Three.js之Raycaster cube邊角碰撞檢測
阿新 • • 發佈:2021-08-19
網上包括很多API 的參考文件都是根據攝像機和滑鼠操控來測試碰撞效果的,利用了 raycaster.setFromCamera( ) 函式
但是,如果物體運動的過程中,並不涉及滑鼠的操作,需要直接呼叫 raycaster.set(from, toVecNormalize) 函式,以下做簡要案例測試,暫沒有對多邊形的邊界進行細微調整。
有幾點需要注意:
1 構造THREE.BoxGeometry() 函式中,構建的cude的八個邊角座標通過 cube.geometry.attributes.position.array; 函式獲取到有序列座標的陣列,通過對 3取餘即可獲取x, y, z座標
2 rcaster.set(dcubevertices[vi], dirv.clone().normalize()); 第一個引數是基準點,一般會和當前計算的邊角座標點函式同樣的數值,設定的點在哪裡,碰撞的基準點就在哪裡。
完整程式碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>物體碰撞檢測</title> </head> <body> <script src="../build/three.js"></script> <script src="../build/OrbitControls.js"></script> <script src="../build/MTLLoader.js"></script> <script src="../build/OBJLoader.js"></script> </body> <script type="text/javascript"> const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500); camera.position.set(50, 10, 100); const scene = new THREE.Scene(); var ambient = new THREE.AmbientLight( 0xffffff ); // 增加光源 scene.add( ambient ); let collLst = []; //create a blue LineBasicMaterial const material = new THREE.LineBasicMaterial({color: 0x0000ff}); const points = []; points.push(new THREE.Vector3(-10, 0, 0)); points.push(new THREE.Vector3(0, 10, 0)); points.push( new THREE.Vector3( 10, 0, 0 ) ); const geometry = new THREE.BufferGeometry().setFromPoints( points ); const line = new THREE.Line( geometry, material ); scene.add(line); // 構造等腰三角形 let geom = new THREE.BufferGeometry(); const vertices = []; vertices.push(0, 0, 0); vertices.push(4, 1, 0); vertices.push(4, -1, 0); geom.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); let args = {color: 0xFF00FF, side: THREE.DoubleSide}; let mat = new THREE.MeshBasicMaterial(args); let mesh = new THREE.Mesh(geom, mat); mesh.position.set(30, 10, 0); mesh.name = "cbb"; scene.add(mesh); // General box mesh data var boxGeometry = new THREE.BoxGeometry(40, 40, 20, 1, 1, 1); var boxMaterial = new THREE.MeshBasicMaterial({color: 0x8888ff, wireframe: true}); var dcube = new THREE.Mesh(boxGeometry, boxMaterial); scene.add(dcube); // 獲取矩形的 8個邊角座標,geometry 是通過四個點組成面的,所以有12個點座標 var posArr = dcube.geometry.attributes.position.array; var dcubevertices = []; for (let i =0; i < posArr.length; i = i+ 3){ let x = posArr[i]; let y = posArr[i + 1]; let z = posArr[i + 2]; let ppt = new THREE.Vector3(x, y, z); dcubevertices.push(ppt); const getemp = new THREE.BoxGeometry(1, 1, 1); const mattemp = new THREE.MeshBasicMaterial( { color: 0xFFA9F2 } ); let cbetemp = new THREE.Mesh( getemp, mattemp ); cbetemp.position.set(x, y, z); scene.add(cbetemp ); } // 通過鍵盤碼,根據cube.name 控制移動 setupKeyControls(); function setupKeyControls() { var cube = scene.getObjectByName('cbb'); document.onkeydown = function(e) { switch (e.keyCode) { case 37: cube.position.x -= 1; break; case 38: cube.position.y += 1; break; case 39: cube.position.x += 1; break; case 40: cube.position.y -= 1; break; case 104: cube.position.z += 0.21; break; case 98: cube.position.z -= 0.21; break; } }; } // Create ray caster var rcaster = new THREE.Raycaster(); const animate = function () { requestAnimationFrame(animate); renderer.render(scene, camera); // 把每個角點座標都設定為碰撞點檢測點 for(var vi = 0, l = dcubevertices.length; vi < l; vi++){ var glovert = dcubevertices[vi].clone().applyMatrix4(dcube.matrix); // 檢測方向向量 var dirv = glovert.sub(dcube.position); // set函式 參1:從當前點開始檢測的基準點,參2:檢測方向 rcaster.set(dcubevertices[vi], dirv.clone().normalize()); // 獲取碰撞結果 var hitResult = rcaster.intersectObject(mesh); // 判斷是否碰撞 if(hitResult.length && hitResult[0].distance < dirv.length()){ console.log("接觸"); } } } animate(); var controls = new THREE.OrbitControls(camera, renderer.domElement);//建立控制元件物件 controls.addEventListener('change', renderer);//監聽滑鼠、鍵盤事件 // // 加入座標系幫助 // var axes = new THREE.AxesHelper(20); // scene.add(axes); </script> </html>
執行效果圖:
有用就推薦下吧?