在OpenGL中实例化动态模型 [英] Instanced drawing of dynamic models in OpenGL

查看:360
本文介绍了在OpenGL中实例化动态模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发一个框架,让我可以方便地呈现更多的动画模型。



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





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

  RenderBone(Bone b,Mat4x4 currentTransform){
Mat4x4 pos = currentTransform * b.boneTransform;
SetUniform(transformation,pos);
Draw(bone.mesh);
每个Bone bc在b.children做{
RenderBone(bc,pos);
}
}

所以对于一个使用n我需要n SetUniform(不包括像设置纹理的东西)和n个绘图调用。



尝试减少这种开销,并且同时渲染所有actor使用相同的模型,我想到了切换到实例化渲染。



但是,我可以找到的所有信息和教程是关于绘制立方体,球体或类似的简单对象。无法在那里看到一些简单的,可理解的信息,关于如何使用实例化绘图来渲染模型,每个部分(骨骼)需要一个不同的变换矩阵给予着色器。



所以,问题:
使用 glVertexAttribDivisor gl_InstanceID 我只能指定一个实例相关的矩阵,不是骨生成矩阵。如何应用我的骨骼变换呢?



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



这是最好的选择吗?或者,更一般地说,有更好的不太复杂的渲染方式?

解决方案

实例化是当你使用静态几何时,需要绘制相同型号的千个副本。一般来说,与骨骼的网格不是你需要绘制成千上万的东西。



Instancing是一个优化,而不是总是付清。除非你知道你需要(通过分析和查看是否达到性能目标),否则不应该尝试使用它。即使这样,对于什么时候是实际的性能改进也是非常敏感的。



有时候,它只是没有帮助。但这里有一些一般的经验法则:


  1. 除非您要呈现数千个执行个体,否则Instancing不值得。

  2. 实例化不应用于具有太多顶点或太少的网格。


  3. 请记住,这些是一般规则,而不是绝对法律。它们也是硬件相关的。


    所以,问题:使用glVertexAttribDivisor或gl_InstanceID我只能指定一个实例相关的矩阵,骨生成矩阵。我如何应用我的骨骼变换呢?


    你看到的例子太多了,你见过其他人在做。像程序员一样。



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



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



    同样,每个索引都是单个实例的变换。您的案例和标准之间的区别是每个实例需要多少信息。常规案例需要一个矩阵;你需要五个。但是这个想法是一样的。



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



    其余的是使用每顶点属性传递要用于变换每个顶点的骨骼索引。


    I am currently developing a framework that allows me to conveniently render a larger number of animated models.

    A model is organized as a simple hierarchy of bones, with the root being the torso/pelvis, generally:

    So, as pseudo code, I am currently rendering a model like this:

    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);
        }
    }
    

    So for a single actor that uses a model with n bones I need n SetUniform (not counting stuff like setting textures) and n draw calls.

    Trying to reduce that overhead, and render all actors using the same model at once, I thought about switching to instanced rendering.

    However, all information and tutorials I could find are about drawing cubes, spheres or similar simple objects. Nowhere I could see some simple, comprehensible information about how to use instanced drawing to render models where each part (bone) requires a different transformation matrix to be given to the shader.

    So, the problem: Using glVertexAttribDivisor or gl_InstanceID I can only specify an instance-related matrix, not a bone-realted matrix. How do I apply my bone transformations then?

    The only feasible solution I could think of is - instead of instancing the entire model - I can instance each bone. Thus drawing all instances of one bone type, then another one, etc. But then I would still have to update the buffer with the transformation matrices relatively often, and it's more housekeeping code.

    So is this best best option? Or, more generally, are there better not-too-complicated ways of rendering? Or does instanced rendering only really shine when using it with static geometry?

    解决方案

    Instancing is something you use when you need to draw thousands of copies of the same model. In general, meshes with bones are not the kinds of things you need to draw thousands of.

    Instancing is an optimization, and one that doesn't always pay off. You shouldn't bother trying to employ it unless you know that you need it (by profiling and seeing if you're hitting performance targets). And even then, it can be very touchy as to when it is an actual performance improvement.

    Sometimes, it just doesn't help. But here are some general rules of thumb:

    1. Instancing is not worthwhile unless you're rendering thousands of instances.
    2. Instancing shouldn't be used with meshes that have too many vertices or too few. 100-1,000 or so.

    Remember that these are general rules, not absolute laws. They're also hardware-dependent.

    So, the problem: Using glVertexAttribDivisor or gl_InstanceID I can only specify an instance-related matrix, not a bone-realted matrix. How do I apply my bone transformations then?

    You're thinking far too much in terms of what examples you've seen or what you've seen other people doing. Think like a programmer.

    gl_InstanceID is not "an instance-related matrix"; it is an index. What you do with that index is entirely up to you. Most examples you've seen use this index to lookup an array of matrices, likely stored in a uniform block or a buffer texture. This matrix is the transform you use for rendering. Each index represents the transform for a single instance.

    Each of your instances has multiple matrices, multiple transforms. But each instance has the same number of bones (otherwise it wouldn't be instanced rendering). Let's say you have 5 bones.

    Again, each index is the transform for a single instance. The difference between your case and the standard is how much information is needed per-instance. The regular case needs one matrix; you need five. But the idea is the same either way.

    If you need bone index 3 for your current instance, you simply access your matrix array with this expression: (gl_InstanceID * 5) + 3, where 5 is the number of bones per instance.

    The rest is a simple matter of using a per-vertex attribute to pass the bone index to be used to transform each vertex.

    这篇关于在OpenGL中实例化动态模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆