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

Is this a good way to render multiple lights in OpenGL?

我目前正在按照几个在线教程在 OpenGL 中编写图形渲染器。我最终得到了一个引擎,它有一个渲染管道,基本上包括使用简单的 Phong 着色器渲染一个对象。我的 Phong 着色器有一个基本的顶点着色器,它根据变换修改顶点,还有一个片段着色器,看起来像这样:

// 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

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

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

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

另一种常见的方法是延迟照明方案。这些方案将反照率、法线、material 属性等存储到 "Geometry Buffer" 中(例如一组多渲染目标 FBO 附件),然后在事后应用光照作为一组 post-处理操作。复杂的几何图形被发送一次,结果数据作为一组纹理数据存储在 MRT+深度渲染目标中。然后将照明作为一组基本几何体(通常是球体或二维四边形)应用,使用深度纹理作为裁剪和剔除光源的手段,以及其他 MRT 附件来计算照明强度和颜色。对于 SO post 来说,这是一个有点长的话题 - 但在网络上有很多来自 GDC 和 Sigraph 的优秀演示。

此处概述的基本思想:

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