You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:29:24