上节给房屋内加上了电脑,并且靠近后可以打电脑:

但是这个房子还没有门,这节来加一下。
改下 house.js

// === 门 ===
const doorWidth = 1.2;
const doorHeight = 2;
const doorThickness = 0.08;
// 门的铰链在左侧门框边缘
const hingeX = houseOffsetX + (-doorOpeningWidth / 2);
const doorCenterX = hingeX + doorWidth / 2;
const doorY = houseOffsetY + doorHeight / 2;
// 门放在墙框内侧(+Z方向),这样可以向两边完全打开
const doorZ = houseOffsetZ + (wallThickness / 2 + doorThickness / 2 + 0.02);
const doorGeo = new THREE.BoxGeometry(doorWidth, doorHeight, doorThickness);
const doorMat = new THREE.MeshPhongMaterial({ color: 0x8b4513 });
const doorMesh = new THREE.Mesh(doorGeo, doorMat);
doorMesh.position.set(doorCenterX, doorY, doorZ);
doorMesh.castShadow = true;
doorMesh.receiveShadow = true;
group.add(doorMesh);
const doorBody = new CANNON.Body({
mass: 10,
position: new CANNON.Vec3(doorCenterX, doorY, doorZ),
angularDamping: 0.5,
linearDamping: 0.05
});
doorBody.addShape(new CANNON.Box(new CANNON.Vec3(doorWidth / 2, doorHeight / 2, doorThickness / 2)));
world.addBody(doorBody);
// 门框柱子(固定铰链的位置)- 放在门框内侧
const doorFrameRadius = 0.08;
const doorFrameGeo = new THREE.CylinderGeometry(doorFrameRadius, doorFrameRadius, doorHeight, 8);
const doorFrameMat = new THREE.MeshPhongMaterial({ color: 0x6d4c41 });
const doorFrameMesh = new THREE.Mesh(doorFrameGeo, doorFrameMat);
doorFrameMesh.position.set(hingeX, doorY, doorZ);
doorFrameMesh.castShadow = true;
group.add(doorFrameMesh);
const doorFrameBody = new CANNON.Body({
mass: 0,
position: new CANNON.Vec3(hingeX, doorY, doorZ)
});
// 使用极小的碰撞体,几乎不影响门的旋转
doorFrameBody.addShape(new CANNON.Cylinder(0.02, 0.02, doorHeight, 8));
world.addBody(doorFrameBody);
// 铰链约束
const hinge = new CANNON.HingeConstraint(doorFrameBody, doorBody, {
pivotA: new CANNON.Vec3(0, 0, 0),
pivotB: new CANNON.Vec3(-doorWidth / 2, 0, 0),
axisA: new CANNON.Vec3(0, 1, 0),
axisB: new CANNON.Vec3(0, 1, 0),
collideConnected: false,
maxForce: 1e8
});
world.addConstraint(hinge);
export default group;
export { doorMesh, doorBody };
首先,我们画了一个立方体的门:

门柱是圆柱形:

大概是这样:

分别加上对应的物理刚体:


前面我们学过铰链约束,就是这样:

这里的门显然也是用这种:

把门柱和门用铰链的方式连起来,这样就可以转动了。
main.js 里引入下:

import house, { doorMesh, doorBody } from './house.js';
function render() {
renderer.render(scene, camera);
css3Renderer.render(scene, camera);
updateViewTip();
// 同步门的视觉和物理状态(保留物理效果)
if (doorMesh && doorBody) {
doorMesh.position.copy(doorBody.position);
doorMesh.quaternion.copy(doorBody.quaternion);
}
requestAnimationFrame(render);
}
渲染循环里去更新物理世界的位置、旋转角度到 threejs 场景。
试下效果:

可以看到,门可以被推开,而且是围绕门柱转动的。
另一个方向也是一样:

这样,房子的门就完成了。
案例代码上传了小册仓库
总结
这节我们把门画了出来,并加上了物理效果。
门就是一个圆柱 + 一个立方体。
然后对应的物理刚体也是这个形状,只不过需要在两者之间加上铰链约束。
这样,一个真实的门的效果就完成了。