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

如何为THREE.js Torus创建Cannon-es物理刚体?

解决Three.js Torus的Cannon-es物理刚体创建问题

由于Cannon-es没有内置的圆环(Torus)形状,你可以通过以下几种方案模拟对应的物理碰撞体:

1. 多圆柱/胶囊体组合成复合形状

这是最常用的近似方案,通过沿圆环路径排列多个小圆柱,组合成复合刚体来模拟圆环的碰撞特性:

// 创建Cannon复合形状
const compoundShape = new CANNON.Compound();

// 匹配Three.js Torus的参数
const torusRadius = 1; // 圆环中心到管中心的距离
const tubeRadius = 0.2; // 圆环管的半径
const segmentCount = 16; // 分段数,越高精度越好但性能消耗越大

// 沿圆环路径添加圆柱
for (let i = 0; i < segmentCount; i++) {
  const angle = (i / segmentCount) * Math.PI * 2;
  const posX = Math.cos(angle) * torusRadius;
  const posZ = Math.sin(angle) * torusRadius;
  
  // 创建适配管半径的圆柱
  const cylinderShape = new CANNON.Cylinder(tubeRadius, tubeRadius, tubeRadius * 2, 8);
  // 旋转圆柱使其贴合圆环切线方向
  const quaternion = new CANNON.Quaternion();
  quaternion.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), angle);
  
  compoundShape.addShape(cylinderShape, new CANNON.Vec3(posX, 0, posZ), quaternion);
}

// 创建物理刚体
const torusBody = new CANNON.Body({
  mass: 1,
  shape: compoundShape
});
world.addBody(torusBody);

2. 基于顶点数据创建凸包形状

如果对碰撞精度要求不高,可以提取Three.js Torus的顶点数据,构建Cannon的凸包形状。注意凸包会忽略圆环的中空部分,碰撞体是包裹圆环的凸几何体:

// 获取Three.js Torus的顶点数据
const torusGeometry = new THREE.TorusGeometry(1, 0.2, 16, 32);
const rawVertices = torusGeometry.attributes.position.array;

// 转换为Cannon需要的Vec3数组
const cannonVertices = [];
for (let i = 0; i < rawVertices.length; i += 3) {
  cannonVertices.push(new CANNON.Vec3(rawVertices[i], rawVertices[i+1], rawVertices[i+2]));
}

// 创建凸包形状
const convexShape = new CANNON.ConvexPolyhedron({ vertices: cannonVertices });

// 创建物理刚体
const torusBody = new CANNON.Body({
  mass: 1,
  shape: convexShape
});
world.addBody(torusBody);

3. 自定义隐式形状(高精度方案)

如果需要完全匹配圆环的碰撞形状,可以通过Cannon的ImplicitShape自定义碰撞检测逻辑,基于圆环的数学方程实现:

// 自定义圆环隐式形状
class TorusShape extends CANNON.ImplicitShape {
  constructor(torusRadius, tubeRadius) {
    super();
    this.torusRadius = torusRadius;
    this.tubeRadius = tubeRadius;
  }

  // 实现隐式函数:返回点到圆环表面的距离
  signedDistanceFunction(point) {
    const r = Math.sqrt(point.x ** 2 + point.z ** 2);
    return Math.sqrt((r - this.torusRadius) ** 2 + point.y ** 2) - this.tubeRadius;
  }
}

// 使用自定义形状创建刚体
const customTorusShape = new TorusShape(1, 0.2);
const torusBody = new CANNON.Body({
  mass: 1,
  shape: customTorusShape
});
world.addBody(torusBody);

内容的提问来源于stack exchange,提问作者Danilo Bassi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:20:22