我正在尝试在 OpenGL 中实现到 HDR 图像的色调映射。
以前,我对 HDR 图像进行手动 mip 映射,以获得具有RGBA32F
亮度平均值的 1x1 纹理(格式)。
我找到了一个色调映射函数的示例并将其放在我的片段着色器中。
在我的渲染代码中,我在GL_TEXTURE0
HDR 图像(格式GL_RGBA32F
)上GL_TEXTURE1
具有平均值的 1x1 纹理。
我要渲染的 LDR 纹理(RGBA8
格式)分配在GL_COLOR_ATTACHMENT0
.
我使用 FreeImage 库上传 HDR 图像(OpenEXR 格式)。
这是代码:
void toneMapping(){
glBindFramebuffer(GL_FRAMEBUFFER, fboTN);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set viewport and textures
setMVP();
glActiveTexture(GL_TEXTURE0); HDRtex->bind(); // Source HDR tex
glActiveTexture(GL_TEXTURE1); DSavgTex0->bind(); // 1x1 tex with avgLum
toneMappingShad->bind();
float key = 0.18f, Ywhite = 1e6f, sat = 1.0f;
toneMappingShad->setUniformValue1f("key", key);
toneMappingShad->setUniformValue1f("Ywhite", Ywhite);
toneMappingShad->setUniformValue1f("sat", sat);
toneMappingShad->setUniformValue("width", im->getWidth());
toneMappingShad->setUniformValue("height", im->getHeight());
toneMappingShad->setUniformValue4f("MVP", glm::value_ptr(MVP));
drawQuad(toneMappingShad);
toneMappingShad->unbind();
glActiveTexture(GL_TEXTURE1); DSavgTex0->unbind(); // 1x1 tex with avgLum
glActiveTexture(GL_TEXTURE0); HDRtex->unbind(); // Source HDR tex
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// RENDER CODE
toneMapping();
texShad->bind();
texShad->setUniformValue4f("MVP", glm::value_ptr(MVP));
LDRtex->bind();
drawQuad(texShad);
LDRtex->unbind();
texShad->bind();
我的输出几乎是黑屏(我可以猜到我画的四边形)。
texShad
着色器非常简单;只是在屏幕上绘制纹理。
我将展示色调映射着色器:
这是顶点着色器(简单):
#version 420
in vec2 vUV;
in vec4 vVertex;
uniform int width; // size of texture
uniform int height;
smooth out vec2 vTexCoord;
uniform mat4 MVP;
void main()
{
gl_Position = MVP*vVertex;
vTexCoord = vec2(vUV.x*width,vUV.y*height);
}
和片段:
#version 420
uniform float key;
uniform float Ywhite;
uniform float sat;
layout(binding=0) uniform sampler2D hdrSampler; // HDR texture
layout(binding=1) uniform sampler2D downSampler; // Texture 1x1 with average of luminance
smooth in vec2 vTexCoord;
layout(location=0) out vec4 color; // LDR sample output (tone mapped image)
const mat3 RGB2XYZ = mat3(0.4124, 0.3576, 0.1805,
0.2126, 0.7152, 0.0722,
0.0193, 0.1192, 0.9505);
vec3 tonemap(vec3 RGB, float logAvgLum){
vec3 XYZ = RGB2XYZ * RGB;
float Y = (key / logAvgLum) * XYZ.y;
float Yd = (Y * (1.0 + Y /(Ywhite * Ywhite))) / (1.0 + Y);
return pow(RGB / XYZ.y, vec3(sat,sat,sat)) * Yd;
}
void main(){
vec3 hdr = texture(hdrSampler, vTexCoord).rgb;
float logAvgLum = exp(texture(downSampler,vec2(0.0,0.0)).a);
color.rgb = tonemap(hdr, logAvgLum);
}
如果我放类似color.a = X
输出的东西不会改变。
一个重要的疑问:这个 ( texture(downSampler,vec2(0.0,0.0)).a
) 得到平均值是否正确?我不知道是否0,0
是正确的值坐标,因为它是纹理大小的 1x1。
我花了很多时间在这上面,但我看不出有什么问题。
这是输出: