three.js加載模型,鼠標操作模型,點擊獲取對象信息


<style>
            body {
                margin: 0;
                overflow: hidden;
            }

            #label {
                position: absolute;
                padding: 10px;
                background: rgba(255, 255, 255, 0.6);
                line-height: 1;
                border-radius: 5px;
            }

            #display {
                height: 600px;
                width: 1200px;
            }
        </style>
<script src="js/three.js"></script>
        <script src="js/GLTFLoader.js"></script>
        <script src="js/OrbitControls.js"></script>
        <div id="WebGL-output"></div>
        <div id="Stats-output"></div>
        <div id="label"></div>
        <div>
            <canvas id="display"></canvas>
        </div>
        <script src="js/stats.min.js"></script>
        <script src="js/dat.gui.min.js"></script>
        <script type="module">
            //性能優化插件
            let stats = initStats();
            let scene, camera, renderer, controls, light, selectObject, canvas;
            //加載器
            let gltfLoader;
            //用來存外部引入的模型
            let group = new THREE.Group();

            //場景
            function initScene() {
                scene = new THREE.Scene();
            }

            //相機
            function initCamera() {
                //與視點坐標系聯動
                camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10000);
                camera.position.set(-1, 0.5, 0);
                camera.lookAt(new THREE.Vector3(0, 0, 0));
            }

            //渲染器
            function initRenderer() {
                canvas = document.querySelector('#display');
                renderer = new THREE.WebGLRenderer({
                    canvas,
                    antialias: true //抗鋸齒
                });
                renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
                renderer.setClearColor(0xFDE7CA);
            }

            //初始化模型
            function initContent() {
                let helper = new THREE.GridHelper(100, 50, 0xCD3700, 0x4A4A4A);//網格線
                scene.add(helper);

                gltfLoader = new THREE.GLTFLoader();
                gltfLoader.load('model/c1.glb', (gltf) => {

                    let model = gltf.scene;

                    //遍歷模型的每一部分
                    //traverse這個方法可以遍歷調用者和調用者的所有后代
                    //所以這里的o就是模型的每一部分
                    model.traverse((o) => {
                        //將圖片作為紋理加載
                        //let explosionTexture = new THREE.TextureLoader().load(
                        //    'static/seraphine/textures/Mat_cwfyfr1_userboy17.bmp_diffuse.png'
                        //);
                        ////調整紋理方向,默認為真。翻轉圖像的Y軸以匹配WebGL紋理坐標空間。
                        ////此處不需要反轉,當然也可以試試反轉以后什么效果
                        //explosionTexture.flipY = false;
                        ////將紋理圖生成基礎網格材質(meshBasicMaterial)
                        //const material = new THREE.MeshBasicMaterial({
                        //    map: explosionTexture
                        //});
                        ////給模型每部分上材質
                        //o.material = material;

                    });
                    //加載外部模型時候基本上都是一個組合對象.

                    group.add(model)
                    scene.add(group);
                });

            }

            //函數:重新設置渲染器的展示大小
            function resizeRendererToDisplaySize(renderer) {
                //這里沒看明白往上翻
                const canvas = renderer.domElement;
                let width = window.innerWidth;
                let height = window.innerHeight;
                //判斷css像素分辨率就和物理像素分辨率是否統一
                let canvasPixelWidth = canvas.width / window.devicePixelRatio;
                let canvasPixelHeight = canvas.height / window.devicePixelRatio;
                //判斷是否需要調整
                const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height;
                if (needResize) {
                    renderer.setSize(width, height, false);
                }
                return needResize;
            }


            //鼠標雙擊觸發的方法
            function onMouseDblclick(event) {
                //alert("a");
                //獲取raycaster和所有模型相交的數組,其中的元素按照距離排序,越近的越靠前
                let intersects = getIntersects(event);
                 console.log(intersects);
                // console.log(intersects[0].object);

                //獲取選中最近的Mesh對象
                //instance坐標是對象,右邊是類,判斷對象是不是屬於這個類的
                if (intersects.length !== 0 && intersects[0].object.type === 'Mesh') {
                    intersects[0].object.material.color.set(0x00FF00);
                    //console.log(intersects[0].object.material.color);
                    selectObject = intersects[0].object;
                    //changeMaterial(selectObject)
                } else {
                    console.log('未選中 Mesh!');
                }
            }

            //獲取與射線相交的對象數組
            function getIntersects(event) {
                event.preventDefault();// 阻止默認的點擊事件執行, https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault
                //console.log("event.clientX:" + event.clientX);
                //console.log("event.clientY:" + event.clientY);

                //聲明 rayCaster 和 mouse 變量
                let rayCaster = new THREE.Raycaster();
                let mouse = new THREE.Vector2();

                //通過鼠標點擊位置,計算出raycaster所需點的位置,以屏幕為中心點,范圍-1到1
                mouse.x = ((event.clientX - canvas.getBoundingClientRect().left) / canvas.offsetWidth) * 2 - 1;
                mouse.y = -((event.clientY - canvas.getBoundingClientRect().top) / canvas.offsetHeight) * 2 + 1; //這里為什么是-號,沒有就無法點中

                //通過鼠標點擊的位置(二維坐標)和當前相機的矩陣計算出射線位置
                rayCaster.setFromCamera(mouse, camera);

                //獲取與射線相交的對象數組, 其中的元素按照距離排序,越近的越靠前。
                //+true,是對其后代進行查找,這個在這里必須加,因為模型是由很多部分組成的,后代非常多。
                let intersects = rayCaster.intersectObjects(group.children, true);

                //返回選中的對象
                return intersects;
            }

            // 窗口變動觸發的方法
            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            }

            //鍵盤按下觸發的方法
            function onKeyDown(event) {
                switch (event.keyCode) {
                    case 13:
                        initCamera();
                        initControls();
                        break;
                }
            }

            //改變對象材質屬性
            function changeMaterial(object) {
                let material = new THREE.MeshLambertMaterial({
                    color: 0xffffff * Math.random(),
                    transparent: object.material.transparent ? false : true,
                    opacity: 0.8
                });
                object.material = material;
            }

            //初始化軌道控制器
            function initControls() {
                controls = new THREE.OrbitControls(camera, renderer.domElement);
                //controls.enableDamping = true;
            }

            // 初始化燈光
            function initLight() {
                light = new THREE.SpotLight(0xffffff);
                light.position.set(-300, 600, -400);
                light.castShadow = true;

                scene.add(light);
                scene.add(new THREE.AmbientLight(0x5C5C5C));
            }

            //初始化 dat.GUI
            function initGui() {
                //保存需要修改相關數據的對象
                let gui = new function () {

                }
                //屬性添加到控件
                let guiControls = new dat.GUI();
            }

            //初始化性能插件
            function initStats() {
                let stats = new Stats();

                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';

                document.body.appendChild(stats.domElement);
                return stats;
            }

            //更新div的位置
            // function renderDiv(object) {
            //     //獲取窗口的一半高度和寬度
            //     let halfWidth = window.innerWidth / 2;
            //     let halfHeight = window.innerHeight / 2;
            //
            //     //逆轉相機求出二維坐標
            //     let vector = object.position.clone().project(camera);
            //
            //     //修改div的位置
            //     $("#label").css({
            //         left: vector.x * halfWidth + halfWidth,
            //         top: -vector.y * halfHeight + halfHeight - object.position.y
            //     });
            //
            //     //顯示模型信息
            //     $("#label").text("name:" + object.name);
            // }

            //更新控件
            function update() {
                stats.update();
                controls.update();
            }

            //初始化
            function init() {
                initScene();
                initCamera();
                initRenderer();
                initContent();
                initLight();
                initControls();
                initGui();//顯示隱藏右上角的控制器開關
                addEventListener('click', onMouseDblclick, false);
                addEventListener('resize', onWindowResize, false);
                addEventListener('keydown', onKeyDown, false);
            }

            function animate() {
                if (selectObject != undefined && selectObject != null) {
                    //renderDiv(selectObject);
                }
                requestAnimationFrame(animate);
                renderer.render(scene, camera);
                update();
                //判斷渲染器是否調整,若調整,相機也需要調整aspect
                if (resizeRendererToDisplaySize(renderer)) {
                    const canvas = renderer.domElement;
                    //重新設置攝像機看視錐體的橫縱比,橫縱比一般為屏幕寬高比,不然會擠壓變形
                    camera.aspect = canvas.clientWidth / canvas.clientHeight;
                    camera.updateProjectionMatrix();
                }
            }

            init();
            animate();
        </script>

 用到的一些JS:https://github.com/ThisCabbage/CabbageGarden/blob/58cedeb52eed245fbbe349f21a5cfaf6905b794f/threeJs.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM