import * as THREE from "three";
// 定义照相机、场景、渲染器
let camera, scene, renderer;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
2000
);
camera.position.set(0, 6, 5);
camera.lookAt(0, 0, 0);
// 渲染器
renderer = new THREE.WebGLRenderer({
// 抗锯齿
antialias: true,
// 设置对数深度缓冲区
logarithmicDepthBuffer: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0xeeeeee));
document.body.appendChild(renderer.domElement);
// 灯光
var spotLight = new THREE.SpotLight();
spotLight.position.set(30, 30, 30);
spotLight.castShadow = true;
scene.add(spotLight);
// 创建立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshPhongMaterial({
color: 0x6688aa,
})
const cube = new THREE.Mesh(geometry, material);
cube.position.x = -1;
scene.add(cube);
// 创建立方体2
const material2 = new THREE.MeshPhongMaterial({
color: 0x6688aa,
})
const cube2 = new THREE.Mesh(geometry, material2);
cube2.position.x = 1;
scene.add(cube2);
// 为第一个cube绑定移动事件
document.addEventListener(
'keydown',
(e) => {
var ev = e || window.event;
switch (ev.code) {
case 'ArrowLeft':
case 'KeyA':
cube.position.x -= 0.05;
break;
case 'ArrowRight':
case 'KeyD':
cube.position.x += 0.05;
break;
default:
break;
}
},
false
)
// 碰撞检测 之 射线检测法
function onIntersect() {
// 声明一个变量来表示是否碰撞
let isCollide = false;
// 获取物体的中心坐标、网格中心、世界坐标
const centerCoord = cube.position.clone();
// 获取网格中,几何对象的顶点对象
const position = cube.geometry.attributes.position;
// 顶点三维向量
const vertices = [];
for (let i = 0; i < position.count; i++) {
vertices.push(new THREE.Vector3(position.getX(i), position.getY(i), position.getZ(i)));
}
for (let i = 0; i < vertices.length; i++) {
// cube.matrixWorld 物体的世界坐标变换 -- 是一个记录物体旋转、位移的四维矩阵
// .applyMatrix4() 将vertices[i]向量乘以四维矩阵,获取世界坐标下,网格变换之后的新的三维向量
let vertexWorldCoord = vertices[i].clone().applyMatrix4(cube.matrixWorld);
// 然后,将变换后的三维向量,减去物体的中心坐标,获得由中心指向几何对象顶点的向量
var dir = vertexWorldCoord.clone().sub(centerCoord);
// 发射光线
// Raycaster的四个参数介绍
// origin - 光线投射的原点向量
// direction - 射线的方向向量,应该归一化.normalize()
// near - 所有返回的结果,要比near远。near不能为负数,默认值是0
// far - 所有返回的结果,要比far近。far不能小于near,默认值为无穷大
let raycaster = new THREE.Raycaster(centerCoord, dir.clone().normalize());
// 放入要检测的物体cube2,返回相交物体
let intersects = raycaster.intersectObjects([cube2], true);
// 如果存在相交物体
if (intersects.length > 0) {
// 如果和相交物体的距离,小于,网格中心到顶点的距离,则代表发生了碰撞
if (intersects[0].distance < dir.length()) {
isCollide = true;
}
}
}
return isCollide;
}
// 请求动画帧渲染
function render() {
requestAnimationFrame(render);
if (onIntersect()) {
cube.material.color.set('yellow')
} else {
cube.material.color.set(0x6688aa)
}
renderer.render(scene, camera);
}
requestAnimationFrame(render);
// 这样还是存在许多的问题,比如说如果cube在一个很大的物体内部,那么就无法进行碰撞检测了。
// 当两个物体能够互相穿过,且有较大部分重合时,检测效果也不理想。
// 涉及到物理引擎这方面还是建议使用ammo.js