如何用THREE.js创建可穿过的空心圆环?
解决Three.js中空心圆环(可穿过)的物理碰撞问题
你这情况我太熟了!之前做套圈小游戏的时候也踩过一模一样的坑——明明视觉上是空心圆环,结果物理引擎把它当成实心块,根本没法套到圆柱上。给你几个亲测有效的解决方案:
方案1:用THREE.RingGeometry配合Physijs复合碰撞体
你之前用THREE.Shape做的形状,物理引擎默认会生成实心凸包碰撞体,得手动构建空心的碰撞逻辑:
首先创建视觉用的圆环:
const outerRadius = 10; const innerRadius = 9; const height = 1; // 视觉模型:用RingGeometry直接生成空心圆环 const ringGeometry = new THREE.RingGeometry(innerRadius, outerRadius, 32); const ringMaterial = new THREE.MeshStandardMaterial({ color: 0xff6600, side: THREE.DoubleSide }); const ringMesh = new THREE.Mesh(ringGeometry, ringMaterial); ringMesh.rotation.x = Math.PI / 2; // 放平圆环方便套圈 scene.add(ringMesh);
然后给它绑定空心物理碰撞体,核心是用外圆环+内圆环组合出空心区域:
// 外圆环碰撞体:用圆柱模拟 const outerCollision = new Physijs.CylinderMesh( new THREE.CylinderGeometry(outerRadius, outerRadius, height, 32), new Physijs.Material(), 0 // 质量设0表示静态物体 ); outerCollision.rotation.x = Math.PI / 2; // 内圆环碰撞体:设为传感器(只检测碰撞不产生阻挡) const innerCollision = new Physijs.CylinderMesh( new THREE.CylinderGeometry(innerRadius, innerRadius, height + 0.1, 32), new Physijs.Material(), 0 ); innerCollision.rotation.x = Math.PI / 2; innerCollision.collisionFlags = Physijs.CollisionFlags.SENSOR; // 关键:让内圈不挡物体 innerCollision.position.copy(outerCollision.position); // 组合碰撞体,把视觉模型挂载上去 outerCollision.add(innerCollision); ringMesh.parent = outerCollision; scene.add(outerCollision);
方案2:用凹面体碰撞处理自定义Shape
如果你坚持用自己写的THREE.Shape生成圆环,得用Physijs的ConcaveMesh来识别凹面碰撞:
const outerRadius = 10; const innerRadius = 9; const height = 1; // 完整的空心Shape绘制(你之前的代码没写完,补全一下) const arcShape = new THREE.Shape(); arcShape.moveTo(outerRadius * 2, outerRadius); arcShape.absarc(outerRadius, outerRadius, outerRadius, 0, Math.PI * 2); arcShape.absarc(outerRadius, outerRadius, innerRadius, Math.PI * 2, 0, true); // 反向画内圆实现挖空 const extrudeSettings = { depth: height, steps: 1, bevelEnabled: false }; const ringGeometry = new THREE.ExtrudeGeometry(arcShape, extrudeSettings); // 用ConcaveMesh处理凹面碰撞,这才会识别出中间的空心 const ringPhysijs = new Physijs.ConcaveMesh( ringGeometry, new Physijs.Material(), 0 ); ringPhysijs.rotation.x = Math.PI / 2; scene.add(ringPhysijs); // 绑定视觉模型 const ringMesh = new THREE.Mesh(ringGeometry, new THREE.MeshStandardMaterial({ color: 0xff6600 })); ringMesh.parent = ringPhysijs;
关键注意事项
- 物理引擎默认只处理凸面体碰撞,所以普通
Mesh会把空心形状当成实心凸包,必须用ConcaveMesh或复合形状才能实现空心效果。 - 内圈设为传感器是核心技巧:既保留了碰撞检测(方便判断套圈成功),又不会阻挡物体穿过空心区域。
内容的提问来源于stack exchange,提问作者requenaxii
相关产品推荐
相关产品推荐

