这是在OpenGL中渲染多个灯光的好方法吗?

时间:2016-12-12 05:00:04

标签: opengl graphics opengl-es rendering shader

我目前正在通过以下几个在线教程在OpenGL中编程图形渲染器。我最终得到了一个具有渲染管道的引擎,该渲染管道基本上包括使用简单的Phong Shader渲染对象。我的Phong Shader有一个基本的顶点着色器,可以根据变换和片段着色器修改顶点,如下所示:

// PhongFragment.glsl
uniform DirectionalLight dirLight;
...
vec3 calculateDirLight() { /* Calculates Directional Light using the uniform */ }
...
void main() {
    gl_FragColor = calculateDirLight();

我的对象的实际绘图看起来像这样:

// Render a Mesh
bindPhongShader();
setPhongShaderUniform(transform);
setPhongShaderUniform(directionalLight1);
mesh->draw(); // glDrawElements using the Phong Shader

这项技术运作良好,但有一个明显的缺点,即我只能有一个方向灯,除非我使用统一数组。我可以这样做,但我想看看有哪些其他解决方案可用(主要是因为我不想在着色器中制作一些大量灯光的数组,并且大部分都是空的),我偶然发现在这个,这似乎真的很低效,但我不确定。它基本上涉及每次使用新灯重新绘制网格,如下所示:

// New Render
bindBasicShader(); // just transforms vertices, and sets the frag color to white.
setBasicShaderUniform(transform); // Set transformation uniform
mesh->draw();
// Enable Blending so that all light contributions are added up...
bindDirectionalShader();
setDirectionalShaderUniform(transform); // Set transformation uniform
setDirectionalShaderUniform(directionalLight1);
mesh->draw(); // Draw the mesh using the directionalLight1
setDirectionalShaderUniform(directionalLight2);
mesh->draw(); // Draw the mesh using the directionalLight2
setDirectionalShaderUniform(directionalLight3);
mesh->draw(); // Draw the mesh using the directionalLight3

但这对我来说似乎非常低效。 Aren我一遍又一遍地重绘所有网格几何体?我已经实现了它,它确实给了我正在寻找的结果,多个方向灯,但帧速率已大大降低。这是渲染多个灯光的愚蠢方式,还是与使用着色器均匀数组相提并论?

1 个答案:

答案 0 :(得分:2)

对于使用与主要几何处理相同的着色器处理光照的前向渲染引擎,唯一真正有效的方法是生成大量着色器,这些着色器可以应对光源,光数和光源的各种组合。照明下的材料。

在你的情况下,你会有一个用于1个灯的着色器,一个用于2个灯,一个用于3个灯等。这是着色器数量方面的组合噩梦,但你真的不想发送所有的网格多次(特别是如果你正在为移动设备编写游戏 - 几何带宽非常重,并且会耗尽电池电量)。

另一种常见方法是延迟照明方案。这些方案将反照率,法线,材料属性等存储到“几何缓冲区”(例如,一组多渲染目标FBO附件)中,然后在事后将照明应用为一组后处理操作。复杂几何体被发送一次,结果数据存储在MRT +深度渲染目标中作为一组纹理数据。然后将光照应用为一组基本几何体(通常为球体或2D四边形),使用深度纹理作为剪切和剔除光源的手段,使用其他MRT附件来计算光照强度和颜色。对于SO帖子来说这是一个很长的话题 - 但是GDC和Sigraph在网络上有很多很好的演示。

此处概述的基本理念:

https://en.wikipedia.org/wiki/Deferred_shading