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

如何在Ammo.js中偏移刚体的质心(结合Three.js)

在Ammo.js中偏移刚体质心的正确方法

核心问题

你之前用setCenterOfMassTransform的思路是错的——这个方法是修改刚体在世界空间的整体位置,而非调整质心相对于物体几何中心的局部偏移。要实现质心偏移(让物体某部位"更重"),需要在形状层面或刚体初始化阶段处理。

方法一:使用复合形状(btCompoundShape)偏移质心

Bullet中单个基础形状(如btBoxShape)的质心固定在其几何中心,要偏移质心,最可靠的方式是将基础形状作为子形状添加到btCompoundShape,并给子形状设置局部偏移变换。复合形状的质心会自动根据子形状的位置和质量计算,从而实现质心偏移效果。

Ammo.js 代码示例

// 1. 创建基础碰撞形状(比如一个立方体)
const boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));

// 2. 创建复合形状
const compoundShape = new Ammo.btCompoundShape();

// 3. 定义质心偏移的局部坐标(比如沿X轴偏移1单位)
const centerOffset = new Ammo.btTransform();
centerOffset.setIdentity();
centerOffset.setOrigin(new Ammo.btVector3(1, 0, 0)); // 这里的偏移是局部空间的

// 4. 将基础形状添加到复合形状,传入偏移变换
compoundShape.addChildShape(centerOffset, boxShape);

// 5. 计算质量和局部惯性
const mass = 10;
const localInertia = new Ammo.btVector3(0, 0, 0);
compoundShape.calculateLocalInertia(mass, localInertia);

// 6. 创建刚体构造信息和刚体
const motionState = new Ammo.btDefaultMotionState(new Ammo.btTransform().setIdentity());
const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, compoundShape, localInertia);
const body = new Ammo.btRigidBody(rbInfo);

方法二:手动调整刚体的质心与惯性张量

如果已经创建了刚体,也可以通过setMassProps手动更新质心位置和对应的惯性张量。需要注意:质心偏移后,惯性张量需要用平行轴定理重新计算。

Ammo.js 代码示例

// 假设已经有一个创建好的刚体body,以及基础形状shape
const mass = 10;
const localInertia = new Ammo.btVector3(0, 0, 0);
shape.calculateLocalInertia(mass, localInertia);

// 定义质心偏移的局部坐标
const centerOffset = new Ammo.btVector3(1, 0, 0);

// 计算偏移后的惯性张量(平行轴定理)
const offsetSq = centerOffset.length2();
const inertiaX = localInertia.x() + mass * (offsetSq - centerOffset.x() * centerOffset.x());
const inertiaY = localInertia.y() + mass * (offsetSq - centerOffset.y() * centerOffset.y());
const inertiaZ = localInertia.z() + mass * (offsetSq - centerOffset.z() * centerOffset.z());
const newInertia = new Ammo.btVector3(inertiaX, inertiaY, inertiaZ);

// 设置新的质量、质心偏移和惯性张量
body.setMassProps(mass, newInertia);
body.setCenterOfMassOffset(centerOffset);

C++ 对应参考代码

如果需要参考原生Bullet的实现,以下是C++版本的复合形状示例:

// 创建基础形状
btBoxShape* boxShape = new btBoxShape(btVector3(1,1,1));

// 创建复合形状
btCompoundShape* compoundShape = new btCompoundShape();

// 设置质心偏移
btTransform centerOffset;
centerOffset.setIdentity();
centerOffset.setOrigin(btVector3(1,0,0));
compoundShape->addChildShape(centerOffset, boxShape);

// 计算惯性
btVector3 localInertia(0,0,0);
compoundShape->calculateLocalInertia(10, localInertia);

// 创建刚体
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform::getIdentity());
btRigidBody::btRigidBodyConstructionInfo rbInfo(10, motionState, compoundShape, localInertia);
btRigidBody* body = new btRigidBody(rbInfo);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:52:46