<pc-joint>
<pc-joint> 约束两个刚体,可用于铰链门、链条、抽屉或受力断裂的绳索。
- 必须直接位于
<pc-entity>、<pc-model>或<pc-node>下。 - 两实体均需
<pc-rigid-body>,还需通过<pc-wasm>加载 Ammo。
关节所在实体本身不参与约束,其世界变换定义关节坐标系,包括锚点及运动轴。局部 X 为主轴:铰链绕它转,滑动沿它移动,球形绕它扭转。被约束对象由 entity-a 和 entity-b 指定。
因此通常用第三个实体放在轴心处,朝向期望运动方向:
<pc-entity name="hinge-anchor" position="0 2 0">
<pc-collision half-extents="0.25 0.25 0.25"></pc-collision>
<pc-rigid-body></pc-rigid-body>
</pc-entity>
<pc-entity name="hinge-arm" position="1 2 0">
<pc-collision half-extents="1 0.1 0.1"></pc-collision>
<pc-rigid-body type="dynamic"></pc-rigid-body>
</pc-entity>
<!-- The joint sits at the pivot, not on either body -->
<pc-entity name="hinge" position="0 2 0" rotation="0 90 0">
<pc-joint type="hinge" entity-a="hinge-arm" entity-b="hinge-anchor"
enable-limits limits="-100 100"></pc-joint>
</pc-entity>
entity-b 留空时,将 A 约束到世界固定点。常将关节实体作为 A 的子项放在轴心,便于保持所属关系。
引擎关节仍为 Alpha,行为和 API 可能变化,标签也会随之调整。
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
angular-damping | Vector3 | "1 1 1" | 各角轴弹簧阻尼,0 到 1,1 无阻尼,越小阻尼越强,仅 6dof |
angular-equilibrium | Vector3 | "0 0 0" | 角弹簧静止角度,仅 6dof |
angular-limits-x | Vector2 | "0 0" | 绕局部 X 角度上下限,单位为度,仅 6dof |
angular-limits-y | Vector2 | "0 0" | 绕局部 Y 角度上下限,单位为度,仅 6dof |
angular-limits-z | Vector2 | "0 0" | 绕局部 Z 角度上下限,单位为度,仅 6dof |
angular-motion-x | Enum | "locked" | X 角自由度:locked、limited 或 free,仅 6dof |
angular-motion-y | Enum | "locked" | Y 角自由度:locked、limited 或 free,仅 6dof |
angular-motion-z | Enum | "locked" | Z 角自由度:locked、limited 或 free,仅 6dof |
angular-stiffness | Vector3 | "0 0 0" | 各角轴弹簧刚度,仅 6dof |
break-impulse | Number | 永不断裂 | 超过后断裂的冲量,省略永不断裂 |
enable-collision | Boolean | "false" | 是否允许两个受约束物体相互碰撞 |
enable-limits | Boolean | "false" | 启用 hinge、slider 或 ball 限制,不开启则 limits 不生效,仅开启使用默认。6dof 忽略 |
enabled | Boolean | "true" | 组件启用状态 |
entity-a | 实体引用 | - | 第一个实体,可为 pc-entity、pc-model 或 pc-node,需要 pc-rigid-body |
entity-b | 实体引用 | - | 第二个实体,留空将 A 约束到世界固定点 |
limits | Vector2 | "-45 45" | 主轴 min max 限制,hinge 用度,slider 用世界单位 |
linear-damping | Vector3 | "1 1 1" | 各线性轴弹簧阻尼,0 到 1,1 无阻尼,越小阻尼越强,仅 6dof |
linear-equilibrium | Vector3 | "0 0 0" | 线性弹簧静止位置,仅 6dof |
linear-limits-x | Vector2 | "0 0" | 局部 X 平移上下限,仅 6dof |
linear-limits-y | Vector2 | "0 0" | 局部 Y 平移上下限,仅 6dof |
linear-limits-z | Vector2 | "0 0" | 局部 Z 平移上下限,仅 6dof |
linear-motion-x | Enum | "locked" | X 平移自由度:locked、limited 或 free,仅 6dof |
linear-motion-y | Enum | "locked" | Y 平移自由度:locked、limited 或 free,仅 6dof |
linear-motion-z | Enum | "locked" | Z 平移自由度:locked、limited 或 free,仅 6dof |
linear-stiffness | Vector3 | "0 0 0" | 各线性轴弹簧刚度,仅 6dof |
max-motor-force | Number | "0" | 电机最大力矩或力,0 禁用,仅 hinge 和 slider |
motor-speed | Number | "0" | 电机目标速度,仅 hinge 和 slider |
swing-limit-y | Number | "45" | 主轴向局部 Y 摆动,即绕 Z 的双侧最大角度,单位为度,仅 ball |
swing-limit-z | Number | "45" | 主轴向局部 Z 摆动,即绕 Y 的双侧最大角度,单位为度,仅 ball |
twist-limit | Number | "20" | 绕主轴最大扭转角,单位为度,仅 ball |
type | Enum | "fixed" | fixed、ball、hinge、slider 或 6dof |
关节类型
type 决定哪些属性生效。表中多数是 6dof 专用,其余四类忽略,因此应先选类型再看对应项:
| 类型 | 约束 | 使用属性 |
|---|---|---|
fixed | 刚性锁定两物体 | — |
ball | 绕锚点自由旋转,可选摆动与扭转限制 | swing-limit-y, swing-limit-z, twist-limit |
hinge | 绕局部 X 旋转,可选限制与电机 | limits, max-motor-force, motor-speed |
slider | 沿局部 X 平移,可选限制与电机 | limits, max-motor-force, motor-speed |
6dof | 各线性和角轴独立锁定、受限或自由,可选弹簧 | linear-* 与 angular-* 系列 |
所有类型都使用 entity-a、entity-b、enable-collision 和 break-impulse。
限制需要显式启用。铰链只有 limits="-100 100" 而无 enable-limits 时仍自由摆动。只开限制则使用默认:铰链 ±45 度、滑动 ±45 单位、球形摆动 45 度与扭转 20 度。应同时配置期望值。6dof 不使用此开关,各轴通过 motion=limited 启用。
坐标系与限制
以下两点不能仅从属性表推断:
限制相对初始姿态。 约束创建时两坐标系重合,各自由度读数为零。因此铰链 limits="0 110" 表示从当前初始姿态到旋转 110 度,不是某绝对角区间。equilibrium 同理。
坐标系只捕获一次。 通常在组件启用且两刚体进入模拟时捕获,之后移动关节实体不生效。可调用底层 refreshFrames() 按当前变换重新捕获。全程忽略实体缩放,与刚体一致。
正负号规则:线性以 B 相对 A 沿坐标系正轴移动为正,B 为空时以世界锚点代替;角度反向,以从正轴端观察时 A 相对 B 逆时针为正。限制方向反了通常源于此。
6dof 各轴默认 locked,因此不设置时相当于固定关节。通过 linear-motion-* 和 angular-motion-* 开放所需轴,再用对应 limits 设置受限轴。
事件
通过 addEventListener() 监听:
| 事件 | 说明 |
|---|---|
break | 冲量超过 break-impulse 后约束断裂,检测时机见下文 |
break 支持冒泡和跨 Shadow DOM 传播,可在祖先统一监听:
document.addEventListener('break', (event) => {
console.log(`${event.target.getAttribute('entity-a')} came loose`);
});
物理引擎超冲量时立即断裂,但本指南采用的标准 ammo.js 无法直接报告。元素需等两锚点分离超过 0.2 单位后才察觉,6dof 断裂则不会报告。
断裂后不再约束且不会自动恢复。调用 refreshFrames()、切换 enabled,或修改 type、entity-a、entity-b 均可重启。
const joint = document.querySelector('pc-joint');
joint.component.refreshFrames(); // re-armed, frames re-captured from the current transforms
示例
电机铰链绕静态轮毂转叶片。关节位于轴心,旋转 0 90 0 使局部 X 指向屏幕内,正 motor-speed 在观察方向呈顺时针。负值反转,可添加 enable-limits limits="-60 60" 观察电机到限位后停止:
<pc-app>
<pc-wasm name="Ammo" glue="https://developer.playcanvas.com/assets/modules/ammo/ammo.wasm.js" wasm="https://developer.playcanvas.com/assets/modules/ammo/ammo.wasm.wasm" fallback="https://developer.playcanvas.com/assets/modules/ammo/ammo.js"></pc-wasm>
<pc-scene>
<pc-entity name="camera" position="0 2 6">
<pc-camera clear-color="#1d1f2b"></pc-camera>
</pc-entity>
<pc-entity name="light" rotation="45 30 0">
<pc-light></pc-light>
</pc-entity>
<!-- Static hub -->
<pc-entity id="hub" position="0 2 0" rotation="90 0 0" scale="0.5 0.3 0.5">
<pc-render type="cylinder"></pc-render>
<pc-collision type="cylinder" radius="0.25" height="0.3"></pc-collision>
<pc-rigid-body></pc-rigid-body>
</pc-entity>
<!-- Dynamic blade -->
<pc-entity id="blade" position="0 2 0" scale="4 0.3 0.2">
<pc-render type="box"></pc-render>
<pc-collision half-extents="2 0.15 0.1"></pc-collision>
<pc-rigid-body type="dynamic"></pc-rigid-body>
</pc-entity>
<!-- The joint sits at the pivot; its frame's X axis is the hinge axis -->
<pc-entity name="hinge" position="0 2 0" rotation="0 90 0">
<pc-joint type="hinge" entity-a="#blade" entity-b="#hub"
motor-speed="90" max-motor-force="1000"></pc-joint>
</pc-entity>
</pc-scene>
</pc-app>
物理关节示例包含各类型,也展示被坠落重物拉断的固定关节。
JavaScript 接口
可以通过 JointComponentElement API创建和操作元素。
component 是底层 JointComponent,就绪前为 null,其余功能可通过它访问。
entity-a 与 entity-b 在赋值时解析,不自动发现之后创建的实体,应在目标存在后再次设置:
const joint = document.querySelector('pc-joint');
joint.entityA = '#link-3'; // re-resolves now
接受裸实体名称,最近宿主优先,或文档级 # 选择器,详见实体引用。
另请参阅
<pc-rigid-body>:双方必需。<pc-collision>:定义形状。<pc-wasm>:加载 Ammo。