跳到主要内容

<pc-joint>

<pc-joint> 约束两个刚体,可用于铰链门、链条、抽屉或受力断裂的绳索。

用法

关节所在实体本身不参与约束,其世界变换定义关节坐标系,包括锚点及运动轴。局部 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 阶段

引擎关节仍为 Alpha,行为和 API 可能变化,标签也会随之调整。

属性​

属性类型默认值说明
angular-dampingVector3"1 1 1"各角轴弹簧阻尼,0 到 1,1 无阻尼,越小阻尼越强,仅 6dof
angular-equilibriumVector3"0 0 0"角弹簧静止角度,仅 6dof
angular-limits-xVector2"0 0"绕局部 X 角度上下限,单位为度,仅 6dof
angular-limits-yVector2"0 0"绕局部 Y 角度上下限,单位为度,仅 6dof
angular-limits-zVector2"0 0"绕局部 Z 角度上下限,单位为度,仅 6dof
angular-motion-xEnum"locked"X 角自由度:locked、limited 或 free,仅 6dof
angular-motion-yEnum"locked"Y 角自由度:locked、limited 或 free,仅 6dof
angular-motion-zEnum"locked"Z 角自由度:locked、limited 或 free,仅 6dof
angular-stiffnessVector3"0 0 0"各角轴弹簧刚度,仅 6dof
break-impulseNumber永不断裂超过后断裂的冲量,省略永不断裂
enable-collisionBoolean"false"是否允许两个受约束物体相互碰撞
enable-limitsBoolean"false"启用 hinge、slider 或 ball 限制,不开启则 limits 不生效,仅开启使用默认。6dof 忽略
enabledBoolean"true"组件启用状态
entity-a实体引用-第一个实体,可为 pc-entity、pc-model 或 pc-node,需要 pc-rigid-body
entity-b实体引用-第二个实体,留空将 A 约束到世界固定点
limitsVector2"-45 45"主轴 min max 限制,hinge 用度,slider 用世界单位
linear-dampingVector3"1 1 1"各线性轴弹簧阻尼,0 到 1,1 无阻尼,越小阻尼越强,仅 6dof
linear-equilibriumVector3"0 0 0"线性弹簧静止位置,仅 6dof
linear-limits-xVector2"0 0"局部 X 平移上下限,仅 6dof
linear-limits-yVector2"0 0"局部 Y 平移上下限,仅 6dof
linear-limits-zVector2"0 0"局部 Z 平移上下限,仅 6dof
linear-motion-xEnum"locked"X 平移自由度:locked、limited 或 free,仅 6dof
linear-motion-yEnum"locked"Y 平移自由度:locked、limited 或 free,仅 6dof
linear-motion-zEnum"locked"Z 平移自由度:locked、limited 或 free,仅 6dof
linear-stiffnessVector3"0 0 0"各线性轴弹簧刚度,仅 6dof
max-motor-forceNumber"0"电机最大力矩或力,0 禁用,仅 hinge 和 slider
motor-speedNumber"0"电机目标速度,仅 hinge 和 slider
swing-limit-yNumber"45"主轴向局部 Y 摆动,即绕 Z 的双侧最大角度,单位为度,仅 ball
swing-limit-zNumber"45"主轴向局部 Z 摆动,即绕 Y 的双侧最大角度,单位为度,仅 ball
twist-limitNumber"20"绕主轴最大扭转角,单位为度,仅 ball
typeEnum"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

接受裸实体名称,最近宿主优先,或文档级 # 选择器,详见实体引用。

另请参阅​

示例:物理关节、布娃娃和AR 热狗风暴。