8

我目前正在开发一个框架,可以方便地渲染大量动画模型。

一个模型被组织为一个简单的骨骼层次结构,根是躯干/骨盆,通常:

我的简单建模层次结构

因此,作为伪代码,我目前正在渲染这样的模型:

RenderBone(Bone b, Mat4x4 currentTransform){
    Mat4x4 pos = currentTransform * b.boneTransform;
    SetUniform("transformation", pos);
    Draw(bone.mesh);
    for each Bone bc in b.children do{
         RenderBone(bc, pos);
    }
}

因此,对于使用具有 n 个骨骼的模型的单个演员,我需要 n 个 SetUniform(不包括设置纹理之类的东西)和 n 个绘制调用。

为了减少开销,并一次使用相同的模型渲染所有演员,我考虑切换到实例渲染。

但是,我能找到的所有信息和教程都是关于绘制立方体、球体或类似的简单对象的。我在任何地方都看不到一些关于如何使用实例绘图来渲染模型的简单易懂的信息,其中每个部分(骨骼)都需要为着色器提供不同的转换矩阵。

所以,问题是:使用glVertexAttribDivisororgl_InstanceID我只能指定一个与实例相关的矩阵,而不是一个与骨骼相关的矩阵。那我该如何应用我的骨骼转换呢?

我能想到的唯一可行的解​​决方案是 - 我可以实例化每个骨骼,而不是实例化整个模型。从而绘制一种骨骼类型的所有实例,然后绘制另一种,等等。但是我仍然需要相对频繁地使用转换矩阵更新缓冲区,而且它是更多的家务代码。

那么这是最好的选择吗?或者,更一般地说,是否有更好的不太复杂的渲染方式?还是实例化渲染仅在与静态几何体一起使用时才真正发挥作用?

4

1 回答 1

18

当您需要绘制同一模型的数千个副本时,您会使用实例化。通常,带有骨骼的网格不是您需要绘制数千个的东西。

实例化是一种优化,但并不总是有回报。除非您知道自己需要它(通过分析并查看您是否达到性能目标),否则您不应该费心尝试使用它。即便如此,它何时是实际的性能改进也可能非常敏感。

有时,它只是无济于事。但这里有一些一般的经验法则:

  1. 除非您要渲染数千个实例,否则实例化是不值得的。
  2. 实例化不应与顶点过多或过少的网格一起使用。100-1,000左右。

请记住,这些是一般规则,而不是绝对规则。它们也依赖于硬件。

所以,问题:使用 glVertexAttribDivisor 或 gl_InstanceID 我只能指定一个与实例相关的矩阵,而不是一个与骨骼相关的矩阵。那我该如何应用我的骨骼转换呢?

就你看到的例子或你看到其他人所做的事情而言,你想的太多了。像程序员一样思考。

gl_InstanceID不是“与实例相关的矩阵”;它是一个索引。您如何使用该索引完全取决于您。您看到的大多数示例都使用此索引来查找矩阵数组,这些矩阵可能存储在统一块缓冲区纹理中。该矩阵是您用于渲染的变换。每个索引代表单个实例的转换。

您的每个实例都有多个矩阵、多个转换。但是每个实例都有相同数量的骨骼(否则它不会被实例化渲染)。假设你有 5 块骨头。

同样,每个索引都是单个实例的转换。您的案例和标准之间的区别在于每个实例需要多少信息。常规情况需要一个矩阵;你需要五个。但无论哪种方式,想法都是一样的。

如果当前实例需要骨骼索引 3,则只需使用以下表达式访问矩阵数组:(gl_InstanceID * 5) + 3,其中 5 是每个实例的骨骼数。

剩下的就是使用每个顶点属性来传递用于变换每个顶点的骨骼索引的简单问题。

于 2012-08-15T16:45:48.517 回答