3

位置重建

我想验证这是一个有效的方法,我没有忽略一些东西。

我正在使用一个球形网格,我只使用它来渲染屏幕中光线重叠的部分。如果深度大于或等于此处建议的深度缓冲区,我只渲染背面。

为了重建片段的相机空间位置,我从光体积上的相机空间片段中获取矢量,对其进行归一化,并按我的 gbuffer(存储为32 位 float)的线性深度对其进行缩放。这是此处讨论的方法(使用线性深度)此处(球形光量)的混合。

位置重建


绑扎

我问的原因是因为我从延迟和向前获得的光衰减结果是不同的。

延期 延期

向前 向前

当我按如下方式计算衰减时,衰减与我的相机空间位置相关联:

vec3 light_dir_to = curr_light.camera_space_position - surface_pos_cam;
float light_dist_sq = dot(light_dir_to, light_dir_to);

float light_attenuation_factor = 1.0f - ((1.0f / (curr_light.radius * curr_light.radius)) * light_dist_sq);
light_attenuation_factor = clamp(light_attenuation_factor, 0.0f, 1.0f);
light_attenuation_factor = pow(light_attenuation_factor, curr_light.falloff);

在这些实例中差异并不是特别明显,但是在我尝试缩放光的实例(例如,将其提高到一个功率以使其更快地淡出),效果立即变得明显。

light_atten = pow(light_atten, 2.0f)

attenpow2

我的问题可能出在其他地方,但我想验证我的位置重建方法在我忽略的某些方面没有缺陷。


编辑

按要求发布我的 gbuffer 设置。

enum render_targets { e_dist_32f = 0, e_diffuse_rgb8, e_norm_xyz10, e_spec_intens_b8_spec_pow_a8, e_light_rgb8, num_rt };
//...
GLint internal_formats[num_rt] = {  GL_R32F, GL_RGBA8, GL_RGB10_A2, GL_RGBA8, GL_RGBA8 };
GLint formats[num_rt]          = {   GL_RED,  GL_RGBA,     GL_RGBA,  GL_RGBA,  GL_RGBA };
GLint types[num_rt]            = { GL_FLOAT, GL_FLOAT,    GL_FLOAT, GL_FLOAT, GL_FLOAT };
for(uint i = 0; i < num_rt; ++i)
{
  glBindTexture(GL_TEXTURE_2D, _render_targets[i]);
  glTexImage2D(GL_TEXTURE_2D, 0, internal_formats[i], _width, _height, 0, formats[i], types[i], nullptr);
}
// Separate non-linear depth buffer used for depth testing
glBindTexture(GL_TEXTURE_2D, _depth_tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, _width, _height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);

注意:此问题发生在对整个表面具有一条法线的平面表面上,因此这不会是法线精度的损失。


最终编辑 - 解决方案

看起来这种方法实际上是有效的(正如 GuyRT 所提到的)。条带问题似乎来自我如何进行伽马校正。

对于我的前向渲染器,我只有一个循环超过 8 个灯(我不进行多次传递,仅 1 次传递),并且我在光照计算后立即应用伽马校正。

对于我的延迟渲染器,我会进行所有光照计算、后处理等,然后转换为 gamma。这里的问题是我:

  1. 在线性 RGB 空间中进行光照计算
  2. 将其存储在 RGB 空间中的纹理中(只有 8 位精度)
  3. 光照完成后,伽玛校正值并将其复制到后台缓冲区。

例如,假设两个片段的光照计算在 sRGB 空间中具有最终值 1/255 (~0.003) 和 2/255 (~0.007)(如最后所示)。RGB 空间中的这些值是 (1/255)^2.2 = ~0.000006 和 (2/255)^2.2 = ~0.00002。当这些值存储到我的光照累积纹理时,它们都存储为相同的值,0。这就是条带的原因。

将我的光照累积纹理转换为GL_R11F_G11F_B10F所产生的结果与我的前向渲染器非常接近。一旦我发现 gamma 是问题所在:sRGB 纹理,这两个问题的答案就对我有所帮助。它是否正确?以及何时调用 glEnable(GL_FRAMEBUFFER_SRGB)?.

“衰减”为 4.0 的最终结果

最后结果


额外资源

我刚刚发现这种效果被称为“Gamma Banding”,这是有道理的。这个网站有一些有用的图表这个视频有一个很好的数字演练

4

1 回答 1

3

通过一些调整,我认为你的方法是有效和可行的。

这看起来很像这里讨论的同一人工制品。这是由于 g-buffer 法线的精度损失引起的。这种情况下的解决方案是使用该GL_RGB10_A2格式来存储法线。

如果您有兴趣,这里对 g-buffer normals 的替代表示进行了相当彻底的讨论:http: //aras-p.info/texts/CompactNormalStorage.html,虽然有点旧,所以 ALU/bandwidth今天的权衡可能会有所不同。另外,我认为他在讨论视图空间法线时犯了一个(很常见的)错误,其中的 z 分量可能是负数。

于 2014-03-18T10:05:16.730 回答