教学知识文档
背景
-
骨骼动画实际上是一个由两部分组成的过程。第一个由艺术家执行,第二个由程序员(或者更确切地说,你编写的引擎)执行。第一部分发生在建模软件内部,称为索具。这里发生的事情是,艺术家定义了网格下方的骨骼骨架。网格表示对象(无论是人类,怪物还是其他任何东西)的皮肤,并且骨骼用于以模仿现实世界中实际运动的方式移动网格。这是通过将每个顶点分配给一个或多个骨骼来完成的。将顶点分配给骨骼时,将定义一个权重,以确定骨骼移动时对顶点的影响量。通常的做法是使所有权重的总和为1(每个顶点)。例如,如果顶点正好位于两个骨骼之间,我们可能希望为每个骨骼分配 0.5 的权重,因为我们期望骨骼对顶点的影响相等。但是,如果顶点完全在单个骨骼的影响范围内,则权重将为1(这意味着骨骼自主控制顶点的运动)。
-
艺术家将骨骼结构装配在一起,并为每种动画类型(“行走”,“奔跑”,"死亡"等)定义一组关键帧。关键帧包含动画路径上关键点中所有骨骼的变换。图形引擎在关键帧的变换之间进行插值,并在它们之间创建平滑的运动。
-
用于骨骼动画的骨骼结构通常是分层的。这意味着骨骼具有子/父关系,因此会创建骨骼树。除根骨外,每个骨骼都有一个父骨。
-
我们不打算进一步讨论操纵。这是一个复杂的主题,超出了图形程序员的领域。建模软件具有高级工具来帮助艺术家完成这项工作,您需要成为一名优秀的艺术家才能创建好看的网格和骨架。让我们看看图形引擎需要做什么才能制作骨架动画。
-
第一阶段是使用每个顶点骨骼信息预兆顶点缓冲区。有几个选项可用,但我们要做的非常简单。对于每个顶点,我们将添加一个槽数组,其中每个槽都包含骨骼 ID 和权重。为了使我们的生活更简单,我们将使用一个具有四个插槽的数组,这意味着没有顶点可以受到四个以上骨骼的影响。如果您要加载包含更多骨骼的模型,则需要调整数组大小,但对于本教程演示的一部分的Doom 3模型,四个骨骼就足够了。因此,我们的新顶点结构将如下所示:
-
骨 ID 是骨转换数组的索引。这些转换将应用于WVP矩阵之前的位置和法线(即它们将顶点从"骨空间"转换为局部空间)。权重将用于将多个骨骼的转换组合成单个转换,并且在任何情况下,总权重必须正好为1(建模软件的责任)。通常,我们会在动画关键帧之间进行插值,并更新每一帧中的骨骼转换数组。
-
创建骨骼转换阵列的方式通常是棘手的部分。转换设置在继承结构(即树)中,常见的做法是在树中的每个节点中具有缩放向量,旋转四元数和平移向量。实际上,每个节点都包含这些项的数组。数组中的每个条目都必须有一个时间戳。应用程序时间与其中一个时间戳完全匹配的情况可能很少见,因此我们的代码必须能够插值缩放/旋转/平移,以获得应用程序时间点的正确转换。我们对从当前骨骼到根的每个节点执行相同的过程,并将这一转换链相乘以获得最终结果。我们对每个骨骼执行此操作,然后更新着色器。
Assimp骨骼动画
-
到目前为止,我们谈论的所有内容都非常通用。但是这是一个关于使用Assimp的骨架动画的教程,因此我们需要再次深入研究该库,并了解如何使用它进行蒙皮。Assimp的好处是它支持从多种格式加载骨骼信息。坏处是,您仍然需要对它创建的数据结构进行大量工作,以生成着色器所需的骨骼转换。
-
在 Assimp 教程中,所有内容都包含在 aiScene 类中(我们在导入网格文件时获得的对象)。aiScene 包含一个 aiMesh 对象数组。aiMesh 是模型的一部分,包含顶点级别的内容,例如位置、法线、纹理坐标等。现在我们看到 aiMesh 还包含一个 aiBone 对象数组。毫无疑问,aiBone 代表网格骨架中的一个骨骼。
-
每个骨骼都有一个名称,通过该名称可以在骨骼层次结构中找到它(见下文),顶点权重数组和4x4偏移矩阵。我们需要这个矩阵的原因是因为顶点存储在通常的局部空间中。这意味着即使没有骨架动画支持,我们现有的代码库也可以加载模型并正确呈现它。但是,继承权中的骨骼变换在骨骼空间中起作用(每个骨骼都有自己的空间,这就是为什么我们需要将变换相乘)。因此,偏移矩阵的工作是将顶点位置从网格的局部空间移动到该特定骨骼的骨骼空间中。
顶点级别构建骨骼信息
-
在顶点级别构建骨骼信息后,我们需要处理骨骼转换层次结构并生成将加载到着色器中的最终转换。下图显示了相关的数据结构:
-
同样,我们从aiScene开始。aiScene 对象包含一个指向 aiNode 类对象的指针,该对象是节点层次结构(换句话说 - 树)的根。树中的每个节点都有一个返回其父节点的指针和一个指向其子节点的指针数组。这使我们能够方便地来回遍历树。此外,节点携带一个转换矩阵,该矩阵从节点空间转换为其父级空间。最后,节点可能有名称,也可能没有名称。如果节点表示层次结构中的骨骼,则节点名称必须与骨骼名称匹配。但有时节点没有名称(这意味着没有相应的骨骼),它们的工作只是帮助建模者分解模型并在此过程中放置一些中间转换。