我正在将我的 webgl 延迟渲染器转换为使用高动态范围的渲染器。我从网上的各种来源阅读了很多关于这个主题的内容,我有一些问题希望能得到澄清。我阅读的大部分内容都涉及 HDR 图像渲染,但我的问题与渲染器可能必须如何更改以支持 HDR 有关。
据我了解,HDR 本质上是在尝试捕捉更高的光照范围,以便我们可以在极亮或极暗的场景中看到细节。通常在游戏中,我们使用强度 1 表示白光,使用 0 表示黑光。但在 HDR / 现实世界中,范围要多样化得多。即引擎中的太阳可能比 10 的灯泡亮 10000 倍。
为了应对这些更大的范围,您必须将渲染器转换为使用浮点渲染目标(或者理想情况下是半浮点,因为它们使用较少的内存)进行光通道。
我的第一个问题是关于照明的。除了浮点渲染目标之外,这是否仅仅意味着如果以前我有一个代表太阳的光,它的强度为 1,它现在可以/应该表示为 10000?IE
float spec = calcSpec();
vec4 diff = texture2D( sampler, uv );
vec4 color = diff * max(0.0, dot( N, L )) * lightIntensity + spec; //Where lightIntensity is now 10000?
return color;
照明系统是否有任何其他基本变化(除了浮动纹理和更高范围)?
在此之后,我们现在有一个浮动渲染目标,它累加了所有的光照值(如所描述的在较高范围内)。在这一点上,我可能会对渲染目标进行一些后期处理,比如绽放。完成后,现在需要对其进行色调映射,然后才能将其发送到屏幕上。这是因为光线范围必须转换回我们显示器的范围。
所以对于色调映射阶段,我大概会使用后期处理,然后使用色调映射公式将 HDR 照明转换为低动态范围。我选择的技术是来自 Uncharted 2 的 John Hables:
const float A = 0.15;
const float B = 0.50;
const float C = 0.10;
const float D = 0.20;
const float E = 0.02;
const float F = 0.30;
const float W = 11.2;
vec3 Uncharted2Tonemap(vec3 x)
{
return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}
... // in main pixel shader
vec4 texColor = texture2D(lightSample, texCoord );
texColor *= 16; // Hardcoded Exposure Adjustment
float ExposureBias = 2.0;
vec3 curr = Uncharted2Tonemap( ExposureBias * texColor.xyz );
vec3 whiteScale = 1.0 / Uncharted2Tonemap(W);
vec3 color = curr * whiteScale;
// Gama correction
color.x = pow( color.x, 1.0 /2.2 );
color.y = pow( color.y, 1.0 /2.2 );
color.z = pow( color.z, 1.0 /2.2 );
return vec4( color, 1.0 );
我的第二个问题与这个色调映射阶段有关。除了这种技术之外,还有更多的东西吗?只是简单地使用更高的光强度并调整曝光所有这些都需要被视为 HDR - 还是还有更多?我知道有些游戏有自动曝光功能来计算平均发光量,但最基本的需要这个吗?大概你可以使用手动调整曝光?
许多文档中讨论的其他内容是伽马校正。伽马校正似乎在两个方面进行。首先是在读取纹理时,然后在将它们发送到屏幕时再次。当读取纹理时,它们必须简单地更改为如下内容:
vec4 diff = pow( texture2D( sampler, uv), 2.2 );
然后在上述色调映射技术中,输出校正通过以下方式完成:
pow(color,1/2.2);
从 John Hables 的介绍中,他说并非所有纹理都必须像这样进行校正。漫反射纹理必须如此,但法线贴图之类的东西不一定必须如此。
我的第三个问题是关于这个伽马校正。为了让它工作,这是必要的吗?这是否意味着我必须在所有读取漫反射贴图的地方更换引擎?
这就是我目前对这种转换所涉及的内容的理解。它是否正确,我有什么误解或错误吗?