1. 程式人生 > 其它 >three.js載入模型,滑鼠操作模型,點選獲取物件資訊

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