碰撞形状
collision 组件为实体提供物理形状。与 rigidbody 配合时,定义刚体形状;单独使用时充当触发体积。形状不必完全匹配外观,通常也不应该:物理引擎每秒反复检测形状,给精细模型包围简单盒体或胶囊,比逐面匹配的网格更快、更稳定。
形状类型
| 类型 | 属性 | 说明 |
|---|---|---|
| Box | Half Extents | 默认类型,表示宽、高、深的一半;0.5, 0.5, 0.5 对应边长一个单位的立方体 |
| Sphere | Radius | 球体 |
| Capsule | Radius、Height、Axis | 两端圆润的圆柱,常用于角色;高度沿所选局部轴从一端顶点量到另一端 |
| Cylinder | Radius、Height、Axis | 圆柱 |
| Cone | Radius、Height、Axis | 圆锥 |
| Mesh | Model Asset 或 Render Asset、Convex Hull | 来自资源的几何体,见网格碰撞体 |
| Compound | 将子实体形状组合为一个刚体,见复合形状 |
基本几何体比网格模拟开销低得多,应使用合理贴合对象的最简单形状。角色通常使用沿 Y 轴站立的胶囊:
- 引擎
- 编辑器
- React
- Web Components
player.addComponent('collision', {
type: 'capsule',
radius: 0.5,
height: 2,
axis: 1 // 0 = X, 1 = Y (the default), 2 = Z
});
在 Collision 的 Type 下拉框选择形状。下方字段随之变化:盒体为 Half Extents,球体为 Radius,胶囊、圆柱和圆锥为 Radius、Height、Axis。
<Collision type="capsule" radius={0.5} height={2} axis={1} />
省略 type 时,组件会采用同级 <Render> 基本几何体的类型,例如盒形渲染组件自动使用盒形碰撞体。
<pc-collision type="capsule" radius="0.5" height="2" axis="1"></pc-collision>
网格碰撞体
网格碰撞体从模型或渲染资源获得几何体,通常与实体显示的资源相同,分两类:
- 三角形网格:默认方式,精确匹配几何体,包括凹陷,只能用于静态、运动学刚体及触发器。
- 凸包:用包含几何体的最小凸形状包裹模型,会丢失碗内部等凹陷,但这是动态刚体唯一支持的网格形状。
从大型模型构建网格形状需要时间和内存。移动对象优先使用基本形状或复合形状,三角形网格主要用于环境。
- 引擎
- 编辑器
- React
- Web Components
// The environment: a static triangle mesh built from the render asset it draws with
ground.addComponent('collision', {
type: 'mesh',
renderAsset: groundAsset
});
// A dynamic prop needs a convex hull
crate.addComponent('collision', {
type: 'mesh',
renderAsset: crateAsset,
convexHull: true
});
将 Type 设为 Mesh,指定 Model Asset 或 Render Asset,后者由 GLB 导入生成。动态刚体需勾选 Convex Hull。
向 renderAsset prop 传入已加载的渲染资源,动态刚体设置 convexHull:
<Collision type="mesh" renderAsset={crateAsset} convexHull />
几何体没有单独特性:type="mesh" 使用实体自身 <pc-render> 的网格,因此很适合加载模型内部的 <pc-node>:
<pc-model asset="car">
<pc-node name="Body">
<pc-collision type="mesh" convex-hull></pc-collision>
<pc-rigid-body type="dynamic" mass="1200"></pc-rigid-body>
</pc-node>
</pc-model>
形状偏移
每种形状都支持 Position Offset 和 Rotation Offset,相对于实体原点移动与旋转。例如角色原点在脚底,胶囊就需要向上偏移半个高度,避免仅为偏移碰撞体而增加子实体。
- 引擎
- 编辑器
- React
- Web Components
// Raise the capsule so that the entity's origin sits at the character's feet
player.addComponent('collision', {
type: 'capsule',
radius: 0.5,
height: 2,
linearOffset: new pc.Vec3(0, 1, 0)
});
// Tilt a box by 45 degrees about the entity's Y axis
crate.collision.angularOffset = new pc.Quat().setFromEulerAngles(0, 45, 0);
在 Collision 中设置 Position Offset 和以度为单位的 Rotation Offset,所有形状类型都支持。
<Collision type="capsule" radius={0.5} height={2} linearOffset={[0, 1, 0]} angularOffset={[0, 45, 0]} />
<pc-collision type="capsule" radius="0.5" height="2" linear-offset="0 1 0" angular-offset="0 45 0"></pc-collision>
复合形状
复合形状将子实体碰撞形状组合为一个刚体,让动态刚体无需网格碰撞体也能具备复杂轮廓。例如椅子由盒形座面、靠背和四条腿组成,仍能与其他动态刚体碰撞,而凹网格不能。复合形状也比网格模拟开销低。
父实体包含 Compound 类型碰撞组件和刚体组件。各子实体包含基本几何碰撞组件,位置与旋转相对于父实体,无需独立刚体。父刚体拥有整个形状;具有自身 rigidbody 的后代视为独立刚体,不加入复合形状。
- 引擎
- 编辑器
- React
- Web Components
// The parent owns the body and combines the children's shapes
const chair = new pc.Entity('chair');
chair.addComponent('collision', { type: 'compound' });
chair.addComponent('rigidbody', { type: pc.BODYTYPE_DYNAMIC, mass: 5 });
// Children carry the shapes, positioned relative to the parent, and need no rigidbody
const seat = new pc.Entity('seat');
seat.addComponent('collision', { type: 'box', halfExtents: new pc.Vec3(0.25, 0.025, 0.25) });
seat.setLocalPosition(0, 0.45, 0);
chair.addChild(seat);
给父实体添加 Type 为 Compound 的 Collision 和 Rigid Body,再为各部分添加子实体及基本形状 Collision,设置相对位置和旋转:

<Entity name="chair">
<Collision type="compound" />
<RigidBody type="dynamic" mass={5} />
<Entity name="seat" position={[0, 0.45, 0]}>
<Collision type="box" halfExtents={[0.25, 0.025, 0.25]} />
</Entity>
</Entity>
<pc-entity name="chair">
<pc-collision type="compound"></pc-collision>
<pc-rigid-body type="dynamic" mass="5"></pc-rigid-body>
<pc-entity name="seat" position="0 0.45 0">
<pc-collision type="box" half-extents="0.25 0.025 0.25"></pc-collision>
</pc-entity>
</pc-entity>

动态或运动学复合形状的子实体可以在运行时移动。变换变化会更新形状在复合体中的偏移,并唤醒父刚体。静态复合体与其他静态刚体一样,保留创建时形状。父实体也是质心,应位于形状内部,通常在中心,否则施加力或扭矩时可能产生绕隐形支点旋转等异常。
上面的椅子来自复合物理形状教程。
缩放
基本几何形状忽略缩放。盒体始终使用以世界单位表示的半尺寸,不受实体和父实体缩放影响,因此放大实体不会放大碰撞体。所有刚体类型、触发器、场景设置和运行时缩放均遵循此规则。
原因是物理引擎中的刚体变换只有位置和旋转,没有缩放。尺寸属于碰撞形状,改变尺寸就需要新形状。因此 PlayCanvas 只将实体位置和旋转传给刚体,基本形状按自身属性构建。
调整基本形状尺寸,应修改这些属性。引擎立即重建形状和刚体,动态刚体保留速度:
// Double the size of a one unit box collider
entity.collision.halfExtents = new pc.Vec3(1, 1, 1);
网格例外,因为其几何体按实体缩放显示。网格碰撞形状按实体世界缩放构建,也包括内部模型节点的缩放。实体或祖先导致世界缩放变化时,会在下一物理步开始时重建;仅缩放模型内部节点不会重建。每次重建都会重建刚体,避免逐帧修改网格碰撞体缩放。
按新缩放重建网格,需要 ammo.js 包含 btScaledBvhTriangleMeshShape。引擎仓库从 2.23 起的构建,以及入门中 Web Components 加载的本站文件包含该功能;PlayCanvas React 使用的 sync-ammo 0.1.2 不包含。旧构建会保留首次缩放,共享同一网格但缩放不同的实体也会使用首次创建的三角网格尺寸。调试引擎首次创建缩放网格时会警告。可通过 typeof Ammo.btScaledBvhTriangleMeshShape === 'function' 判断。
复合体子实体的基本形状也保留自身尺寸。上层缩放仍会改变位置,因此复合体各部分会分开,而非变大。建议复合体不缩放,通过各部分的形状属性设置尺寸。
显示形状
编辑器会在视口中勾勒所选实体的碰撞形状,便于检查尺寸和偏移。运行时要显示所有形状,可在任意开发方式下为实体添加 render-physics.js,启用 Draw Shapes,以半透明网格显示碰撞形状。
另请参阅
- 刚体:形状所属的刚体。
- 触发体积:没有刚体的形状。
- Collision 组件:编辑器属性参考。
- CollisionComponent:API 参考。
- 复合物理形状:上方椅子的教程项目。