溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

three.js如何利用射線Raycaster進行碰撞檢測

發(fā)布時間:2021-06-17 15:44:33 來源:億速云 閱讀:800 作者:小新 欄目:web開發(fā)

這篇文章主要為大家展示了“three.js如何利用射線Raycaster進行碰撞檢測”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“three.js如何利用射線Raycaster進行碰撞檢測”這篇文章吧。

本文實例為大家分享了利用射線Raycaster進行碰撞檢測的具體代碼,供大家參考,具體內容如下

學習碰撞檢測之前,我們先了解一下Raycaster類

Raycaster 應該翻譯為“光線投射”,顧名思義,就是投射出去的一束光線。 

Raycaster的構造函數(shù)如下

Raycaster( origin, direction, near, far ) {
origin — 射線的起點向量。
direction — 射線的方向向量,應該歸一化。
near — 所有返回的結果應該比 near 遠。Near不能為負,默認值為0。
far — 所有返回的結果應該比 far 近。Far 不能小于 near,默認值為無窮大。

使用Raycaster進行碰撞檢測

用Raycaster來檢測碰撞的原理很簡單,我們需要以物體的中心為起點,向各個頂點(vertices)發(fā)出射線,然后檢查射線是否與其它的物體相交。如果出現(xiàn)了相交的情況,檢查最近的一個交點與射線起點間的距離,如果這個距離比射線起點至物體頂點間的距離要小,則說明發(fā)生了碰撞。

這個方法有一個  缺點 ,當物體的中心在另一個物體內部時,是不能夠檢測到碰撞的。而且當兩個物體能夠互相穿過,且有較大部分重合時,檢測效果也不理想。 

還有需要  注意 的一點是:在Three.js中創(chuàng)建物體時,它的頂點(veritces)數(shù)目是與它的分段數(shù)目相關的,分段越多,頂點數(shù)目越多。為了檢測過程中的準確度考慮,需要適當增加物體的分段。 

檢測光線是否與物體相交使用的是  intersectObject 或  intersectObjects 方法: 

.intersectObject ( object, recursive )
 
//object — 檢測該物體是否與射線相交。
//recursive — 如果設置,則會檢測物體所有的子代。

相交的結果會以一個數(shù)組的形式返回,其中的元素依照距離排序,越近的排在越前.

這樣通過對數(shù)組中的元素進行處理,就能得出想要的結果。

intersectObjects 與  intersectObject 類似,除了傳入的參數(shù)是一個數(shù)組之外,并無大的差別。

/**
 * 功能:檢測 movingCube 是否與數(shù)組 collideMeshList 中的元素發(fā)生了碰撞
 * 
 */
var originPoint = movingCube.position.clone();
 
for (var vertexIndex = 0; vertexIndex < movingCube.geometry.vertices.length; vertexIndex++) {
 // 頂點原始坐標
 var localVertex = movingCube.geometry.vertices[vertexIndex].clone();
 // 頂點經過變換后的坐標
 var globalVertex = localVertex.applyMatrix4(movingCube.matrix);
 // 獲得由中心指向頂點的向量
 var directionVector = globalVertex.sub(movingCube.position);
 
 // 將方向向量初始化
 var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
 // 檢測射線與多個物體的相交情況
 var collisionResults = ray.intersectObjects(collideMeshList);
 // 如果返回結果不為空,且交點與射線起點的距離小于物體中心至頂點的距離,則發(fā)生了碰撞
 if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
  crash = true; // crash 是一個標記變量
 }
}

在Three.js中是使用矩陣來記錄3D轉換的,每一個Object3D的實例都有一個矩陣,存儲了位置position,旋轉rotation和伸縮scale。

var globalVertex = localVertex.applyMatrix4(movingCube.matrix);

這一句代碼將物體的本地坐標乘以變換矩陣,得到了這個物體在世界坐標系中的值,處理之后的值才是我們所需要的。

下面是一個測試的完整實例:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <script src="../js/three.js"></script>
 
 <script src="../js/controls/DragControls.js"></script>
 <script src="../js/controls/TrackballControls.js"></script>
 
 <script src="../js/stats.min.js"></script>
 <script src="Main.js"></script>
 <title>Document</title>
</head>
<body οnlοad="initThree();">
 <div id="canvas-frame"></div>
 
</body>
</html>

Main.js

var scene,camera,controls,renderer,cube,originPoint;
var WIDTH,HEIGHT;
var objects = [];
//創(chuàng)建渲染器
function initRenderer(){
 WIDTH = window.innerWidth;
 HEIGHT = window.innerHeight;
 renderer = new THREE.WebGLRenderer({
  antialias:true,
 });
 renderer.setSize(WIDTH,HEIGHT);
 renderer.setPixelRatio(WIDTH/HEIGHT);
 document.getElementById('canvas-frame').appendChild(renderer.domElement);
 
}
//創(chuàng)建場景
function initScene(){
 scene = new THREE.Scene();
 scene.background = new THREE.Color( 0xf0f0f0 );
}
//創(chuàng)建相機
function initCamera(){
 camera = new THREE.PerspectiveCamera(50,WIDTH/HEIGHT,1,10000);
 camera.position.set(0,0,1000);
 camera.lookAt(0,0,0);
}
//創(chuàng)建光源
function initLight(){
 // 方向光
 var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
 scene.add( directionalLight );
 // 環(huán)境光
 scene.add( new THREE.AmbientLight( 0x505050 ) );
}
//創(chuàng)建對象
function initObject(){
 var geometry = new THREE.BoxBufferGeometry( 40, 40, 40 );
 
 for ( var i = 0; i < 2; i ++ ) {
 
  var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
  //隨機位置
  object.position.x = Math.random() * 1000 - 500;
  object.position.y = Math.random() * 600 - 300;
  object.position.z = Math.random() * 800 - 400;
  //隨機角度
  object.rotation.x = Math.random() * 2 * Math.PI;
  object.rotation.y = Math.random() * 2 * Math.PI;
  object.rotation.z = Math.random() * 2 * Math.PI;
  //隨機大小
  object.scale.x = Math.random() * 2 + 1;
  object.scale.y = Math.random() * 2 + 1;
  object.scale.z = Math.random() * 2 + 1;
  //開啟陰影
  object.castShadow = true;
  object.receiveShadow = true;
 
  scene.add( object );
  // 放入數(shù)組
  objects.push( object );
 
 }
 // 
 var geometry = new THREE.BoxGeometry( 80, 80, 80 );
 var material = new THREE.MeshLambertMaterial( {color: 0xfff000} );
 cube = new THREE.Mesh( geometry, material );
 scene.add( cube );
 /**
  * .clone () : Vector3
  * 返回一個新的Vector3,其具有和當前這個向量相同的x、y和z。
  */
 originPoint = cube.position.clone();
 
}
//創(chuàng)建控制器
function initControls(){
 // TrackballControls 軌跡球控件,最常用的控件,可以使用鼠標輕松的移動、平移,縮放場景。
 controls = new THREE.TrackballControls( camera );
 controls.rotateSpeed = 1.0;// 旋轉速度
 controls.zoomSpeed = 1.2;// 縮放速度
 controls.panSpeed = 0.8;// 平controls
 controls.noZoom = false;
 controls.noPan = false;
 controls.staticMoving = true;// 靜止移動,為 true 則沒有慣性
 controls.dynamicDampingFactor = 0.3;// 阻尼系數(shù) 越小 則滑動越大
 // DragControls 初始化拖拽控件
 var dragControls = new THREE.DragControls( objects, camera, renderer.domElement );
 // 開始拖拽
 dragControls.addEventListener( 'dragstart', function () {
 
  controls.enabled = false;
 
 } );
 // 拖拽結束
 dragControls.addEventListener( 'dragend', function () {
 
  controls.enabled = true;
 
 } );
}
 
function initThree(){
 initRenderer();
 initScene();
 initCamera();
 initLight();
 initObject();
 initControls();
 animation();
}
//循環(huán)
function animation(){
 requestAnimationFrame(animation);
 renderer.render(scene,camera);
 // 更新控制器
 controls.update();
 // 循環(huán)碰撞檢測
 for (var i = 0; i < cube.geometry.vertices.length; i++) {
  // 頂點原始坐標
  var localVertex = cube.geometry.vertices[i].clone();
  // 頂點經過變換后的坐標
  // matrix 局部變換矩陣。 applyMatrix4 并返回新Matrix4(4x4矩陣)對象.
  var globalVertex = localVertex.applyMatrix4(cube.matrix);
  // 獲得由中心指向頂點的向量
  var directionVector = globalVertex.sub(cube.position);
  // 將方向向量初始化
  var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
  // 檢測射線與多個物體的相交情況
  var collisionResults = ray.intersectObjects(objects);
  // 如果返回結果不為空,且交點與射線起點的距離小于物體中心至頂點的距離,則發(fā)生了碰撞
  if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
   console.log('碰撞!');
  }
 }
 
}

以上是“three.js如何利用射線Raycaster進行碰撞檢測”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI