网上包括很多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>
运行效果图:
左侧有个推荐,有用就推荐下吧?