在OpenGL中实例绘制动态模型

s3r*_*ius 5 c++ opengl opengl-3

我目前正在开发一个框架,允许我方便地渲染大量的动画模型.

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

我简单的建模层次结构

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

试图减少开销,并使所有actor一次使用相同的模型,我想到切换到实例化渲染.

但是,我能找到的所有信息和教程都是关于绘制立方体,球体或类似的简单对象.无处可以看到一些关于如何使用实例化绘制来渲染模型的简单易懂的信息,其中每个部分(骨骼)需要将不同的变换矩阵赋予着色器.

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

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

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

Nic*_*las 14

当您需要绘制相同模型的数千份副本时,就会使用实例化.一般来说,骨骼网格不是你需要绘制成千上万的东西.

实例化是一种优化,并不总是有回报.你不应该费心去尝试使用它,除非你知道你需要它(通过剖析并看看你是否达到了性能目标).即便如此,它在实际性能提升时也会非常敏感.

有时,它没有帮助.但这里有一些一般的经验法则:

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

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

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

从你看过的例子或者你看到别人做过的事情来看,你的想法太多了.像程序员一样思考.

gl_InstanceID不是"与实例相关的矩阵"; 这是一个索引.您对该索引的处理完全取决于您.您见过的大多数示例都使用此索引来查找矩阵数组,可能存储在统一块缓冲区纹理中.此矩阵是用于渲染的变换.每个索引代表单个实例的转换.

每个实例都有多个矩阵,多个变换.但是每个实例具有相同数量的骨骼(否则它将不是实例化渲染).假设你有5个骨头.

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

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

其余的是使用每顶点属性来传递用于变换每个顶点的骨骼索引的简单问题.