【问题标题】:Is this a good way to render multiple lights in OpenGL?这是在 OpenGL 中渲染多个灯光的好方法吗?
【发布时间】:2017-04-26 22:35:13
【问题描述】:

我目前正在按照几个在线教程在 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

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

【问题讨论】:

标签: opengl graphics opengl-es rendering shader


【解决方案1】:

对于在与主要几何处理相同的着色器中处理光照的正向渲染引擎,唯一真正有效的方法是生成大量着色器,这些着色器可以处理光源、光照计数和光照下的材料。

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

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

此处概述的基本思想:

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

【讨论】:

  • learnopengl.com/#!Advanced-Lighting/Deferred-Shading有一个很好的延迟着色教程
  • 我计划在某个时候实现延迟渲染,但我也想先探索前向渲染......所以如果我想拥有 3 种不同类型的光源,最多 4 盏灯每个,我是否需要为每种可能的光源和数量组合制作大量着色器(我认为是 24 个?)?
  • 请注意,ESSL 支持类似 C 的预处理器,因此您可以编写一些大型着色器(例如,每种灯光类型包括 4 个),每个灯光都包含在“#ifdef”块中。然后,创建变体就像更改预处理器选项一样简单,而不必手动创建许多单独的着色器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 2019-09-25
相关资源
最近更新 更多