Three.js 如何显示坐标系、碰撞体和质心
前面几篇讲交互。这一篇回到模型本身 —— URDF 里除了 <visual> 描述的外观,还有三样渲染用不到、调模型时离不开的东西:关节坐标系、碰撞体、<inertial>。
它们默认都不显示,需要时再打开。

1. 关节坐标系:一个三色十字
1 | import { BufferGeometry, Float32BufferAttribute, LineBasicMaterial, LineSegments } from "three"; |
几条值得注意的:
- 继承
LineSegments,每两个顶点画一段。所以每根轴写了两次0, 0, 0—— 线段不共享起点,没有索引可用。 - 颜色写在顶点上,靠材质的
vertexColors: true生效。每根轴从纯色渐变到浅色(红→橙、绿→黄绿、蓝→浅蓝),比单色更容易分清方向。 dispose()成对释放:geometry和material都要,和上次讲高亮材质是同一个道理 —— 不释放就是泄漏。
用的时候在解析 joint 的过程中挂上去:
1 | const axesMat = new LineBasicMaterial({ |
材质上那五个参数各管一件事:
| 参数 | 作用 |
|---|---|
vertexColors: true |
用顶点色,而不是材质自己的颜色 |
toneMapped: false |
不被色调映射改色,红就是正红 |
depthTest: false + depthWrite: false |
穿透模型显示 |
fog: false |
不受雾影响 |
depthTest: false 是关键一条。不关掉的话,轴会被大腿、外壳挡住,只剩下露在外面的一小截。关掉之后整个十字永远画在模型上面 —— 代价是失去前后关系,看不见的那半截也画出来。
另外两行看着不起眼,其实是配套的:
visible = false—— 默认隐藏。坐标系全部打开会很乱,所以按名字存进jointAxisMap,想调试哪个再取出来打开。userData.isURDFHelper = true—— 给射线拾取用的。拖动那篇的traverseMeshInLink遇到isURDFHelper就停止下钻,所以这个十字不会被选中。没有这个标记,鼠标扫过去会挑中辅助线而不是零件。
size 给 0.2(米)是轴长,比关节本身略大一点,够看清又不至于盖住模型。
2. 碰撞体:只可视化,不做碰撞检测
<collision> 描述”碰撞时算成什么”。Web 前端一般不会真拿它跑碰撞检测 —— 物理仿真在服务端或专门的引擎里做 —— 而是只把它画出来,用来检查简化模型摆得对不对。
读懂一个碰撞体,看两件事:形状尺寸,和 <origin> 把它放在哪。
| 项 | 值 | 含义 |
|---|---|---|
| 形状 | 圆柱 | — |
| 半径 | 0.02 m | 直径 4 cm,比较细 |
| 长度 | 0.2 m | 20 cm |
| origin | xyz="0 0 -0.2" |
圆柱中心相对 link 坐标系向下偏移 0.2 m |
| rpy | 0 0 0 |
无旋转 |
有一个容易看错的地方:URDF 的圆柱沿自身 Z 轴延伸,origin 给的是中心,不是底面。 所以这个圆柱在 link 坐标系下覆盖的是 z 从 -0.3 到 -0.1(中心 -0.2,上下各 0.1),不是从 -0.2 往下 0.2。
大腿和小腿用的就是这根:它们的下一个关节在 z = -0.4,整段长约 0.4 m,而 0.2 m 的细圆柱大致盖住中下部。用简单几何体代替几万个三角形的外观 mesh,碰撞计算的开销小得多,代价是它只是个近似。
3. 质心:<inertial> 的 <origin>
<inertial> 里是三样:<mass>、<origin>、<inertia>。其中 origin 就是这个 link 的惯性坐标系原点,也就是质心。
注意 <link> 里三套 <origin> 各管各的,互不相干:<visual> 的管外观摆在哪儿,<collision> 的管碰撞体摆在哪儿,<inertial> 的管质心在哪儿。
看一个例子:mass = 4.962 kg,质心在 z = -0.1945。这个 link 长约 0.4 m,质心落在 -0.1945 说明质量集中在下半段(靠近膝关节那侧)—— 髋部电机加上大腿上段结构比较重,这个位置是合理的。
4. 惯性张量:六个数字怎么读
<inertia> 是一个 3×3 对称矩阵,只有六个独立分量,单位是 kg·m²:
| 参数 | 值 | 含义 |
|---|---|---|
ixx |
4553.605E-06 | 绕 X 轴的转动惯量 |
iyy |
5688.730E-06 | 绕 Y 轴的转动惯量 |
izz |
3548.907E-06 | 绕 Z 轴的转动惯量 |
ixy |
0.005E-06 | X-Y 惯性积(几乎为 0) |
ixz |
0.817E-06 | X-Z 惯性积(几乎为 0) |
iyz |
-345.157E-06 | Y-Z 惯性积 |
换算成直观的数:Ixx ≈ 0.004554、Iyy ≈ 0.005689、Izz ≈ 0.003549、Iyz ≈ -0.000345,其余交叉项基本为 0。
- 对角线(
ixx/iyy/izz)是绕三个轴各自的转动惯量,数值越大,绕那根轴转起来越”沉”。 - 交叉项(
ixy/ixz/iyz)是惯性积,反映质量分布相对主轴偏了多少。
这组数里交叉项都接近 0,说明这个 link 的质量分布已经比较接近主轴对齐,没有明显偏斜;Iyy 最大,说明绕 Y 轴旋转时惯性最大。
可以用一句话记:质量告诉你”有多重”,惯性张量告诉你”转的时候有多难转”。 它不只跟质量有关,还跟质量离旋转轴的分布有关 —— 同样是 1 kg,摊成一根长杆就比缩成一个球难转得多,这就是”距离平方加权”的意思。
这些数是给物理引擎算力矩用的,渲染完全用不到。但画出来是有价值的:质心位置和惯量分布合不合理,一眼能看出来。
参考
- URDF XML 规范(ROS 官方文档):https://wiki.ros.org/urdf/XML
- Three.js
LineSegments:https://threejs.org/docs/#api/en/objects/LineSegments - Three.js
BufferGeometry.setAttribute:https://threejs.org/docs/#api/en/core/BufferGeometry <collision>和<inertial>的语义:https://wywzixin.github.io/threejs/urdf-parsing/- 上一篇:Three.js 如何实现悬停高亮与提示框 —— https://wywzixin.github.io/threejs/urdf-hover-tip/
- 下一篇:Three.js 实时机器人动画:时间戳插值与缓冲 —— https://wywzixin.github.io/threejs/urdf-animation-buffer/
Three.js 如何显示坐标系、碰撞体和质心