點(diǎn)擊和碰撞都需要使用光線投射
Raycaster( origin : Vector3, direction : Vector3, near : Float, far : Float )
origin —— 光線投射的原點(diǎn)向量究驴。
direction —— 向射線提供方向的方向向量秃踩,應(yīng)當(dāng)被標(biāo)準(zhǔn)化。
near —— 返回的所有結(jié)果比near遠(yuǎn)启具。near不能為負(fù)值,其默認(rèn)值為0。
far —— 返回的所有結(jié)果都比far近侯勉。far不能小于near,其默認(rèn)值為Infinity(正無窮铝阐。)
使用光線投射實(shí)例的intersectObject
或intersectObjects
方法檢查光線和物體的相交關(guān)系
點(diǎn)擊
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects([sphere, cylinder, cube]);
if (intersects.length > 0) {
console.log(intersects[0]);
intersects[0].object.material.transparent = true;
intersects[0].object.material.opacity = 0.1;
}
}
當(dāng)點(diǎn)擊鼠標(biāo)時(shí)址貌,上述代碼會(huì)發(fā)生以下處理:
- 基于屏幕上的點(diǎn)擊位置創(chuàng)建一個(gè) THREE.Vector3 向量。
使用 vector.unproject 方法將屏幕上的點(diǎn)擊位置轉(zhuǎn)換成 Three.js 場(chǎng)景中的坐標(biāo)徘键。換句話說练对,就是將屏幕坐標(biāo)轉(zhuǎn)換成三維場(chǎng)景中的坐標(biāo)。 - 創(chuàng)建 THREE.Raycaster吹害。使用 THREE.Raycaster 可以向場(chǎng)景中發(fā)射光線螟凭。在下述案例中,從攝像機(jī)的位置(camera.position)向場(chǎng)景中鼠標(biāo)的點(diǎn)擊位置發(fā)射光線它呀。
- 使用 raycaster.intersectObjects 方法來判斷指定的對(duì)象中哪些被該光線照射到的螺男,并返回包含了所有被光線照射到的對(duì)象信息的數(shù)組(根據(jù)距離攝像機(jī)距離,由短到長(zhǎng)排序)纵穿。
碰撞
我們以物體中心為起點(diǎn)下隧,向各個(gè)頂點(diǎn)(vertices)發(fā)出射線,然后檢查射線是否與其它的物體相交谓媒。如果出現(xiàn)了相交的情況淆院,檢查最近的一個(gè)交點(diǎn)與射線起點(diǎn)間的距離,如果這個(gè)距離比射線起點(diǎn)至物體頂點(diǎn)間的距離要小句惯,則說明發(fā)生了碰撞土辩。
當(dāng)物體的中心在另一個(gè)物體內(nèi)部時(shí),該方法會(huì)失效
/**
* 功能:檢測(cè) movingCube 是否與數(shù)組 collideMeshList 中的元素發(fā)生了碰撞
*
*/
var originPoint = movingCube.position.clone();
for (var vertexIndex = 0; vertexIndex < movingCube.geometry.vertices.length; vertexIndex++) {
// 頂點(diǎn)原始坐標(biāo)
var localVertex = movingCube.geometry.vertices[vertexIndex].clone();
// 頂點(diǎn)經(jīng)過變換后的坐標(biāo)
var globalVertex = localVertex.applyMatrix4(movingCube.matrix);
// 獲得由中心指向頂點(diǎn)的向量
var directionVector = globalVertex.sub(movingCube.position);
// 將方向向量初始化
var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
// 檢測(cè)射線與多個(gè)物體的相交情況
var collisionResults = ray.intersectObjects(collideMeshList);
// 如果返回結(jié)果不為空宗弯,且交點(diǎn)與射線起點(diǎn)的距離小于物體中心至頂點(diǎn)的距離脯燃,則發(fā)生了碰撞
if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
crash = true; // crash 是一個(gè)標(biāo)記變量
}
}