Blender中对于骨骼的各种Matrix表示
0 前导知识
Armature
Blender中,Armature的概念等价于Graphics中的Skeleton,一个Armature由若干个Bone组成,不同Bone之间可以建立父子关系,形成层级结构。父骨骼移动时,子骨骼会跟随。Bone可以通过变换(Transform)驱动物体变形。关于Skeletal Animation更多技术细节请参见这里的class 11, 12, 13。
Interaction Mode
Object Mode: 管理/移动场景中整个对象
Edit Mode:用于修改骨骼结构,如添加/删除骨骼、调整层级;
Pose Mode: 该模式下允许调整骨骼姿势,如旋转骨骼、添加关键帧动画;
Pose Bone vs Data Bone
Pose Bone | Data Bone | |
---|---|---|
模式 | Pose Mode | Edit Mode |
作用 | 控制动画、添加约束、插入关键帧 | 定义骨骼结构、名称、父子关系 |
是否影响动画 | ✅ 是,会影响最终动画 | ❌ 否,仅用于骨骼结构 |
是否可变形 | ✅ 是,可用于角色变形 | ❌ 否,不影响角色变形 |
是否存储关键帧 | ✅ 是,存储关键帧动画数据 | ❌ 否,不存储动画数据 |
可否添加约束 | ✅ 可以(如 IK、Track To) | ❌ 不能 |
Space Types
Blender中,骨骼的变换涉及多个坐标空间,不同的空间用于不同的计算方式和约束规则,因此衍生出了一系列space[1],本质上分为local space和world space两种。object/armature/bone space是local space的特例。
- World Space
- 骨骼的变换参考世界坐标系,即:位置相对于世界原点,旋转/缩放相对于世界坐标轴;
- 所有父骨骼的变换都会影响当前骨骼的最终 World Space 位置;
- 骨骼在world space下使用的是global coordinates。
- Local Space
- 仅考虑对骨骼自身施加的Transform,不受parent bone影响,但rest pose仍然是基准;
- 骨骼在local space下使用的是local coordinates;
- 对于骨骼而言,local space相当于bone space,bone space是特定于骨骼的local space定义方式。
接下来是特化space:
Pose Space
Bone transform相对于rest pose,表示骨骼在pose mode下的变换。每个bone transform是基于它在rest pose下的位置和朝向计算的,与armature的 object transform无关。
pose space是pose mode使用的主要space,也是关键帧存储bone transform的space。
Local with Parent
bone transform相对于parent bone的transform。参考的是parent bone的local coordinates,也就是说,bone transform受parent bone影响。
如果parent bone是root bone,那么local with parent等价于pose space。
Object Space
Object(Mesh、Armature等)的local space。对armature而言,object space就是armature space。如果armature在object mode下有transform,它的骨骼变换也会受到影响。
Bone Space
bone的local space,即bone的origin是它本身的head,坐标轴沿着bone direction。
Armature Space
等同于object space,但特指armature这个object的local space。整个Armature相对于世界坐标的变换发生在这个空间里。
1 Matrix
该章节大篇幅参考了[3]。
Bone.matrix_local
: bone在armature space下的无pose矩阵,Bone.matrix_local
等价于rest pose状态下的PoseBone.matrix
armature = bpy.data.objects['Armature']
data_bone = armature.data.bones["Bone"]
matrix_local = data_bone.matrix_local
Bone.matrix
:在rest position下,将bone从bone space变换到parent bone的bone space下的3x3矩阵。
armature = bpy.data.objects['Armature']
armature.data.bones["Root"].matrix
PoseBone.matrix_basis
: bone在bone space的变换矩阵,不受父骨骼影响
armature = bpy.data.objects['Armature']
pose_bone = armature.pose.bones["Bone"]
matrix_basis = pose_bone.matrix_basis
PoseBone.matrix
: bone在armature space的pose矩阵。
子骨骼的matrix_basis与父骨骼的matrix复合可得到子骨骼在pose space下的变换矩阵。
armature = bpy.data.objects['Armature']
pose_bone = armature.pose.bones["Bone"]
# bone有parent
pose_bone.matrix == pose_bone.parent.matrix @ pose_bone.matrix_basis
# bone无parent
pose_bone.matrix == pose_bone.bone.matrix_local @ pose_bone.matrix_basis
PoseBone.matrix_channel
: 在armature space中,是bone从rest pose状态变换到pose space的矩阵
armature = bpy.data.objects['Armature']
pose_bone = armature.pose.bones["Bone"]
pose_bone.matrix == pose_bone.matrix_channel @ pose_bone.bone.matrix_local
Object.matrix_world
: object在world space下的变换矩阵。
armature = bpy.data.objects['Armature']
matrix_world = armature.matrix_world
获取armature space下的变换矩阵:
def matrix_armature(armature: bpy.types.Object, bone_name: str):
matrix_local = armature.data.bones[bone_name].matrix_local
matrix_basis = armature.pose.bones[bone_name].matrix_basis
parent_bone = armature.pose.bones[bone_name].parent
if parent_bone is None:
return matrix_local @ matrix_basis
else:
parent_matrix_local = armature.data.bones[parent_bone.name].matrix_local
return matrix_armature(armature, parent_bone.name) @ (parent_matrix_local.inverted() @ matrix_local) @ matrix_basis
从bone space逐级变换到parent的bone space,最终达到root bone的bone space即为armature space。
-
matrix_basis: 当前bone在bone space中的transform;
-
matrix_local @ matrix_basis: 所有parent bone在rest pose下,当前bone在armature space中的transform;
-
parent_matrix_local.inverted() @ matrix_local @ matrix_basis:parent bone在rest pose状态下时,当前bone在parent bone的bone space中的transform;
-
parent_matrix_basis @ parent_matrix_local.inverted() @ matrix_local @ matrix_basis: 当前bone在parent bone的bone space中的transform;
-
parent_matrix_local @ parent_matrix_basis @ parent_matrix_local.inverted() @ matrix_local @ matrix_basis: 考虑了parent bone的pose后,parent bone以上的bone都在rest pose状态下,当前bone在armature space中的transform。
References
[1] https://docs.blender.org/manual/en/latest/animation/constraints/interface/common.html#space-types
[2] https://blenderartists.org/t/what-is-different-local-space-and-pose-space/578162/5
[3] https://maoxyzt.github.io/Notes/Software-Specific/Blender/blender%E4%B8%AD%E5%90%84%E7%A7%8DMatrix%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB.html#_1-matrix