admin管理员组

文章数量:1130349

骨骼原理笔记

一. 骨架: 树状结构, 关节点组成
二. 关节:

  1. 关节名
  2. 父关节索引(根关节的父关节索引为-1,为无效索引)
  3. 关节绑定姿势的逆变换矩阵(offset矩阵)
	struct Joint{Matrix4x4 m_inverseBindPose;const char* m_name;U8 m_iParent;};struct Skeleton{U32 m_jointCount; // 关节数Joint* m_aJoint;  // 关节数组};

三. 姿态(本质是矩阵, 位置信息)

  1. 绑定姿态: Mesh默认的姿态(静止状态? 制作模型的那个姿态? TPose?)

  2. 局部姿态: 关节相对于父关节来指定的。局部姿势存储为TQS的格式,表示相对与父关节的位置、朝向、缩放, 根关节的父节点可以认为是世界坐标系原点。

  3. 全局姿态: 全局姿势是相对于局部姿势而言的,它是关节相对于模型空间或者世界空间的姿势(局部姿势是相对于父关节的姿势), 从该关节左乘局部姿态矩阵一直到根关节

  4. 全局姿态逆矩阵OffsetTransform: 全局姿态矩阵的逆, 将世界空间坐标转为关节局部空间坐标下, 它在模型绑定后一直保持不变

    局部, 全局姿态, 全局姿态逆矩阵只是绑定姿态(静止状态)

  5. 实时姿态

  6. GlobalTransform矩阵 (也叫Combine矩阵), 属于实时姿态(根据动画每帧不同?), 对应静态下的全局姿态, 将局部转为世界空间.

  7. 最终变换矩阵 FinalTransform矩阵 (也称蒙皮矩阵),这个矩阵表示了骨架最终的变换
    , 其中 FinalTransform = GlobalTransform · OffsetTransform. 蒙皮矩阵就是把顶点从绑定姿势变换到骨骼的当前姿势的矩阵. 蒙皮矩阵和前面的基变更矩阵不同,它只是把顶点变换到新的位置,顶点变换前后都在世界空间中(或模型空间中).

四. 蒙皮原理
所谓蒙皮就是计算骨架在某一状态下网格顶点的位置。每个顶点可以绑定到一个至多个骨骼(unity里面是最多4个),动画播放时,顶点随着关节运动,顶点的最终变换就等于它所绑定的骨架变换的加权和。对于每个顶点,我们需要有以下信息:

  • 该顶点绑定到的骨骼索引
  • 该顶点的每个绑定骨骼的权重,他表示了骨架对顶点的影响力。

加权平均的计算时,顶点绑定的所有骨架的权重和为1。通常设每个顶点最多绑定到4个骨架,程序存储如下

	struct SkinnedVertex{float m_position[3]; // 顶点位置(x,y,z)float m_normal[3];   // 顶点法向量 (Nx,Ny,Nz)float m_u, m_v;      // 纹理坐标U8 m_jointIndex[4];  // 关节的索引float m_jointWeight[4]; // 关节权重};

和上面一样用 Fj 表示关节 j 的蒙皮矩阵,假设某个顶点V受到上面关节14、18、15、25的影响,对应点权重分别为W1,W2,W3,W4,则顶点v的最终变换位置为 V’ = W1F14V + W2F18V + W3F15V + W4F25V
。实际上,在内存中,一般存储关节的两个矩阵,一个是局部姿势矩阵Pj(也可以叫节点矩阵,Node矩阵),一个是全局姿势的逆矩阵Offset矩阵,通过前面的知识我们知道,其实Offset矩阵可以通过局部姿势矩阵计算得到,为什么我们还要存一个呢?因为Offset矩阵用的非常频繁,每次使用都去计算一次没有必要,世界开销略大。

蒙皮矩阵的计算过程可以理解为先将点通过Offset矩阵变换到关节空间,再通过GlobalTransform矩阵变换到全局空间。这里需要提一点,unity和C++中存储的模型顶点坐标是一开始就确定的,动画过程中不会变,也就是每一帧不会去更新顶点坐标,只是会通过蒙皮计算得到顶点最终位置,然后渲染到屏幕上。

链接: .html

骨骼原理笔记

一. 骨架: 树状结构, 关节点组成
二. 关节:

  1. 关节名
  2. 父关节索引(根关节的父关节索引为-1,为无效索引)
  3. 关节绑定姿势的逆变换矩阵(offset矩阵)
	struct Joint{Matrix4x4 m_inverseBindPose;const char* m_name;U8 m_iParent;};struct Skeleton{U32 m_jointCount; // 关节数Joint* m_aJoint;  // 关节数组};

三. 姿态(本质是矩阵, 位置信息)

  1. 绑定姿态: Mesh默认的姿态(静止状态? 制作模型的那个姿态? TPose?)

  2. 局部姿态: 关节相对于父关节来指定的。局部姿势存储为TQS的格式,表示相对与父关节的位置、朝向、缩放, 根关节的父节点可以认为是世界坐标系原点。

  3. 全局姿态: 全局姿势是相对于局部姿势而言的,它是关节相对于模型空间或者世界空间的姿势(局部姿势是相对于父关节的姿势), 从该关节左乘局部姿态矩阵一直到根关节

  4. 全局姿态逆矩阵OffsetTransform: 全局姿态矩阵的逆, 将世界空间坐标转为关节局部空间坐标下, 它在模型绑定后一直保持不变

    局部, 全局姿态, 全局姿态逆矩阵只是绑定姿态(静止状态)

  5. 实时姿态

  6. GlobalTransform矩阵 (也叫Combine矩阵), 属于实时姿态(根据动画每帧不同?), 对应静态下的全局姿态, 将局部转为世界空间.

  7. 最终变换矩阵 FinalTransform矩阵 (也称蒙皮矩阵),这个矩阵表示了骨架最终的变换
    , 其中 FinalTransform = GlobalTransform · OffsetTransform. 蒙皮矩阵就是把顶点从绑定姿势变换到骨骼的当前姿势的矩阵. 蒙皮矩阵和前面的基变更矩阵不同,它只是把顶点变换到新的位置,顶点变换前后都在世界空间中(或模型空间中).

四. 蒙皮原理
所谓蒙皮就是计算骨架在某一状态下网格顶点的位置。每个顶点可以绑定到一个至多个骨骼(unity里面是最多4个),动画播放时,顶点随着关节运动,顶点的最终变换就等于它所绑定的骨架变换的加权和。对于每个顶点,我们需要有以下信息:

  • 该顶点绑定到的骨骼索引
  • 该顶点的每个绑定骨骼的权重,他表示了骨架对顶点的影响力。

加权平均的计算时,顶点绑定的所有骨架的权重和为1。通常设每个顶点最多绑定到4个骨架,程序存储如下

	struct SkinnedVertex{float m_position[3]; // 顶点位置(x,y,z)float m_normal[3];   // 顶点法向量 (Nx,Ny,Nz)float m_u, m_v;      // 纹理坐标U8 m_jointIndex[4];  // 关节的索引float m_jointWeight[4]; // 关节权重};

和上面一样用 Fj 表示关节 j 的蒙皮矩阵,假设某个顶点V受到上面关节14、18、15、25的影响,对应点权重分别为W1,W2,W3,W4,则顶点v的最终变换位置为 V’ = W1F14V + W2F18V + W3F15V + W4F25V
。实际上,在内存中,一般存储关节的两个矩阵,一个是局部姿势矩阵Pj(也可以叫节点矩阵,Node矩阵),一个是全局姿势的逆矩阵Offset矩阵,通过前面的知识我们知道,其实Offset矩阵可以通过局部姿势矩阵计算得到,为什么我们还要存一个呢?因为Offset矩阵用的非常频繁,每次使用都去计算一次没有必要,世界开销略大。

蒙皮矩阵的计算过程可以理解为先将点通过Offset矩阵变换到关节空间,再通过GlobalTransform矩阵变换到全局空间。这里需要提一点,unity和C++中存储的模型顶点坐标是一开始就确定的,动画过程中不会变,也就是每一帧不会去更新顶点坐标,只是会通过蒙皮计算得到顶点最终位置,然后渲染到屏幕上。

链接: .html

本文标签: 骨骼原理笔记