Nor*_*der 4 c++ opengl renderer c++11
我正在使用XNA/MonoGame界面在OpenGL中制作2D批量渲染器,但我遇到了一个小设计问题,我正在寻找一些输入.目前,您可以通过以下四种方式提交顶点数据:
void Render(const Sprite& sprite);
void Render(const Shape& shape);
void Render(const Vertex* vertices, unsigned int length);
void Render(const Vertex* vertices, unsigned int length, const Texture* texture);
Run Code Online (Sandbox Code Playgroud)
精灵包含四个顶点,颜色和纹理坐标,而其他三个顶点可以包含任意数字(精灵和形状具有唯一的变换).一切都可以纹理或无纹理.我想批量处理所有内容以减少状态更改和OpenGL绘制调用的次数.我觉得合理地假设大多数提交都有共享顶点,这样我就可以使用glDrawElements而不是glDrawArrays,但是我很难弄清楚如何按照上面描述的方法正确地批量处理.
XNA/MonoGame sprite batchers的工作原理是它们只使用纹理四边形/三角形而不是任意形状.或者,我可以像SFML渲染器一样为每个可绘制对象发出一个绘制调用,但这会破坏批渲染的目的.
我觉得我的渲染器正试图"做所有事情",这是我想要避免的事情,因为在我的经历中它通常会变得过于复杂.
我问的是:我怎样才能重新设计我的渲染器?我可以为不同的提交保留单独的批次列表吗?我可以以某种方式模块化我的渲染器吗?我应该只允许在XNA/MonoGame中完成纹理对象吗?
好吧,所以我们需要最小化状态变化和绘制调用的次数.我假设你正在使用现代OpenGL,包括顶点缓冲对象和着色器.
一种方法是确保所有顶点数据具有相同的格式.例如,每个顶点都有一个位置,颜色和纹理坐标(xyz,rgba,uv).如果我们在VBO中交错我们的顶点数据,我们在渲染之前只需要一次调用glVertexAttribPointer和glEnableVertexAttribArray.
这意味着无纹理对象的一些冗余数据,但我们将所有内容都塞进一个批处理中,这很好.
要处理无纹理对象,您可以绑定空白白色纹理并将其视为纹理对象.或者,您可以在片段着色器中使用统一变量(0到1之间的浮点数),并使用该mix函数在纹理颜色和顶点颜色之间进行混合.
要批量精灵和形状,我们应该首先处理CPU上的转换,这样我们总是将"世界" - 坐标上传到GPU.这使我们不必为每个精灵设置变换均匀,每个精灵都需要单独的绘制调用.
此外,我们需要尽可能按纹理排序,因为纹理绑定是您可以执行的更昂贵的操作之一.
我们的方法基本归结为以下几点:
将数据从CPU获取到GPU内存可以通过不同方式完成.例如,首先在GPU上分配足够大的空内存缓冲区,并使用glBufferSubData上传顶点/索引数据的子集,每当您执行一次Render调用时.
在进行此类工作时进行性能分析非常重要.例如,比较批处理和单个绘制调用之间的性能,或glDrawArrays与glDrawElements之间的性能.我建议使用gDebugger,它是一个免费且非常好的OpenGL探查器.
另请注意,太大的VBO会损害您的性能.所以保持一个合理的大小,并在它填满时用一个绘制调用冲洗它.