HDR,自适应色调映射和GLSL中的MSAA

Nic*_*vre 6 opengl glsl

为了自学OpenGL,我正在通过第五版的Superbible工作.

我目前正在试图弄清楚如何结合HDR和MSAA(如第9章所述).

对于HDR,本书提出了一种自适应色调映射方法,该方法基于计算每个片段的5x5卷积滤波器的平均亮度.

对于MSAA,使用的方法通过从样本距离计算的权重来平均所有样本.

我尝试将两者结合起来,在下面的pastebin中,将色调映射应用于每个样本,然后平均它们以计算最终的片段颜色.

性能是(正如人们应该预期的那样?)可怕:每个样本25个查找,4xMSAA为4次,我猜测GPU花费大部分时间来查找我的FBO纹理.切换到代码中由use_HDR统一控制的代码路径,对于简单的场景,性能会下降400 + fps到10以下.

我的问题是双重的:

  • 这是一种执行色调映射的理智方法吗?如果没有,你会建议什么?

  • MSAA和基于卷积的过滤器应该如何组合?我猜我会再次遇到这个问题需要查找相邻纹素的任何滤镜,即几乎任何像绽放,模糊等等?

码:

#version 330
in Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    vec2 texCoord;
    mat4 mvp;
    mat4 mv;
} gdata;

out vec4 outputColor;
uniform sampler2DMS tex;
uniform sampler1D lum_to_exposure;
uniform samplerBuffer weights;
uniform int samplecount;
uniform bool use_HDR;

vec4 tone_map(vec4 color, float exp)
{
    return 1.0f - exp2(-color * exp);
}

const ivec2 tc_offset[25] = ivec2[](ivec2(-2, -2), ivec2(-1, -2), ivec2(0, -2), ivec2(1, -2), ivec2(2, -2),
                                    ivec2(-2, -1), ivec2(-1, -1), ivec2(0, -1), ivec2(1, -1), ivec2(2, -1),
                                    ivec2(-2,  0), ivec2(-1,  0), ivec2(0,  0), ivec2(1,  0), ivec2(2,  0),
                                    ivec2(-2,  1), ivec2(-1,  1), ivec2(0,  1), ivec2(1,  1), ivec2(2,  1),
                                    ivec2(-2,  2), ivec2(-1,  2), ivec2(0,  2), ivec2(1,  2), ivec2(2,  2));

void main()
{
    ivec2 itexcoords = ivec2(floor(textureSize(tex) * gdata.texCoord));
    float tex_size_x = textureSize(tex).x;
    float tex_size_y = textureSize(tex).y;
    outputColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
    // for each sample in the multi sample buffer...
    for (int i = 0; i < samplecount; i++)
    {
        // ... calculate exposure based on the corresponding sample of nearby texels
        vec4 sample;
        if (use_HDR)
        {
            sample = texelFetch(tex, itexcoords, i);

            // look up a 5x5 area around the current texel
            vec4 hdr_samples[25];
            for (int j = 0; j < 25; ++j)
            {
                ivec2 coords = clamp(itexcoords + tc_offset[j], ivec2(0, 0), ivec2(tex_size_x, tex_size_y));
                hdr_samples[j] = texelFetch(tex, coords, i);
            }
            // average the surrounding texels
            vec4 area_color = (
                     ( 1.0f * (hdr_samples[0] + hdr_samples[4] + hdr_samples[20] + hdr_samples[24])) +
                     ( 4.0f * (hdr_samples[1] + hdr_samples[3] + hdr_samples[5] + hdr_samples[9]
                             + hdr_samples[15] + hdr_samples[19] + hdr_samples[21] + hdr_samples[23])) +
                     ( 7.0f * (hdr_samples[2] + hdr_samples[10] + hdr_samples[14] + hdr_samples[22])) +
                     (16.0f * (hdr_samples[6] + hdr_samples[8] + hdr_samples[16] + hdr_samples[18])) +
                     (26.0f * (hdr_samples[7] + hdr_samples[11] + hdr_samples[13] + hdr_samples[17])) +
                     (41.0f * (hdr_samples[12]))
                     ) / 273.0f;
            // RGB to luminance formula : lum = 0.3R + 0.59G + 0.11B
            float area_luminance = dot(area_color.rgb, vec3(0.3, 0.59, 0.11));
            float exposure = texture(lum_to_exposure, area_luminance/2.0).r;
            exposure = clamp(exposure, 0.02f, 20.0f);


            sample = tone_map(sample, exposure);
        }
        else
            sample = texelFetch(tex, itexcoords, i);

        // weight the sample based on its position
        float weight = texelFetch(weights, i).r;
        outputColor += sample * weight;
    }
}
Run Code Online (Sandbox Code Playgroud)

rot*_*lup 5

我没有Superbible的副本,所以我不知道它们的确切命题,但这种方法看起来非常低效且不精确:你的5x5过滤器只访问每个纹素的'i'样本,并且完全错过了其他样品.

对于过滤阶段,我会像kvark已经建议的那样,使用glBlitFramebuffer在HDR中累积所有样本来解析另一个纹理.之后,使用双线性过滤,在另一个HDR纹理中进行过滤,可能使用可分离的过滤器来获得性能,甚至使用GPU硬件来帮助提高性能.

这将为您提供模糊的纹理,然后您可以在色调映射着色器中进行采样.这应该会大大提高性能,但会占用更多内存.

请注意,存在其他色调映射运算符,并且此域中没有"基本事实".您可以选择使用更高性能的方法,而不使用这种细粒度的光度估计.

你可以看看Matt Pettineo最近关于色调映射的博客文章,这可以给你提示如何改进,也许是通过使用glGenerateMipMaps创建光度纹理.

关于使用MSAA进行色调映射的具体问题,我唯一知道的是,建议在MSAA解析之前对各个样本进行色调映射,以防止出现混叠伪像.