使用3D关节坐标在three.js中驱动VRM人形模型动画的技术问题咨询
Three.js VRM动捕常见问题解答
1. 3D关节坐标转骨骼旋转值的方法
1.1 单个关节坐标对应的欧拉角计算逻辑
首先需要先对齐坐标系:你的输入坐标系是y轴向下,three.js默认y轴向上,需要先将输入坐标的y值乘-1完成坐标系转换。
单个关节的坐标无法直接计算旋转,你需要同时获取该关节所属骨骼的根点和末点坐标(比如计算左肩关联的左上臂骨骼旋转,需要同时拿到左肩、左肘两个关节的坐标),计算步骤如下:
- 拿到父骨骼(左上臂的父骨骼为胸腔)的世界坐标,将两个关节坐标转换到父骨骼的局部坐标系下
- 计算骨骼的目标朝向向量:末点局部坐标减去根点局部坐标,做归一化处理
- 调用
THREE.Quaternion的setFromUnitVectors方法,将骨骼初始朝向向量(可以在模型绑定姿势下提前获取存储)转换到目标朝向向量,得到四元数 - 调用四元数的
toEuler方法,传入和模型一致的欧拉角顺序(一般为XYZ)即可得到需要的rotation值
1.2 需要计算旋转的骨骼范围
仅需要对具备可动父子层级、关联肢体运动的骨骼计算旋转,包括脊柱、颈部、头部、肩、上臂、下臂、手腕、髋部、大腿、小腿、脚踝等部位。
左肩的旋转具备实际意义,直接控制整个手臂的抬起、转向角度;鼻子这类属于头部骨骼的子节点,不需要单独计算旋转,头部骨骼旋转后鼻子会自动跟随运动,单独调整其旋转没有常规应用价值。
1.3 不能直接修改骨骼position的原因
核心原因是人形骨骼动画遵循刚体层级绑定规则:
- 正常人体的骨骼长度是固定的,关节仅能做旋转运动,不能随意改变相对父骨骼的位置,直接修改
position相当于将骨骼从父级上扯离,完全不符合人体运动逻辑 - 你给出的代码写法本身也存在语法错误:
Object3D的position是Vector3类型,不能直接赋值元组,需要调用set(10, -2.5, 1)方法赋值,即使语法正确,最终效果也会和预期动作完全不符 - 只有根骨骼(通常是髋部)的
position可以调整,用来实现整个人物的位移,其余骨骼的position在绑定姿势下就已经固定,不需要修改
2. VRM人形骨骼节点的结构与旋转计算逻辑
VRM返回的骨骼节点就是标准的three.js Object3D实例,不是单纯的向量,它包含完整的三维变换属性:局部位置position、局部欧拉角rotation、局部四元数quaternion、缩放scale、局部变换矩阵matrix、世界变换矩阵matrixWorld,以及父节点、子节点的引用关系,完全支持三维空间的旋转、位移、缩放操作。
你拿到左肩的单个三维坐标,不能直接计算三个轴的角度赋值给rotation:
- 单个点的坐标没有方向参考,你必须拿到该骨骼关联的两个端点坐标,才能计算出骨骼的朝向
- 所有旋转计算需要在父骨骼的局部坐标系下完成,不能直接用世界坐标计算角度
- 更推荐直接给
quaternion属性赋值四元数,不需要转欧拉角,可以避免万向锁问题,旋转精度更高
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

