OpenGL sRGB实验 [已结束]

OpenGL sRGB experiment [closed]

提问人:tuket 提问时间:10/25/2022 最后编辑:genpfaulttuket 更新时间:10/25/2022 访问量:78

问:


这个问题是由一个错别字或一个无法再重现的问题引起的。虽然类似的问题可能在这里成为主题,但这个问题的解决方式不太可能帮助未来的读者。

去年关闭。

我在 OpenGL 中做了一个简单的演示,以更好地理解伽马校正。我已经意识到它打破了我的一些假设,所以我希望有人可以帮助我理解。

作为参考,我用 GIMP 制作了这张图片。它以 10% 的步长显示整个黑-灰-白光谱。这些是可见光谱(伽马)。

在此处输入图像描述

我的 OpenGL 演示执行以下操作:

  1. 清除 50% 灰色的屏幕
  2. 使用输出 50% 灰色的着色器绘制一个大矩形(在着色器中硬编码)
  3. 绘制一个较小的矩形,对单像素、50% 灰色、sRGB 纹理进行采样。

在此处输入图像描述

现在,我将更详细地介绍如何执行这 3 个步骤中的每一个

1)清除屏幕

我只是做:

glClearColor(0.5, 0.5, 0.5, 0);
glClear(GL_COLOR_BUFFER_BIT);

2)画大矩形

我用这个像素着色器画了一个矩形:

layout(location = 0) out vec4 o_color;

void main()
{
    o_color = vec4(vec3(0.5), 1);
}

3)画小矩形

我创建了一个 50% 灰色、sRGB、单像素纹理:

u32 tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
const glm::u8vec3 pixelColor(127);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelColor[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

并用这个着色器绘制:

layout(location = 0) out vec4 o_color;

in vec2 v_tc;

uniform sampler2D u_tex;

void main()
{
    o_color = vec4(texture(u_tex, v_tc).rgb, 1);
}

结果

这是生成的渲染。

在此处输入图像描述

解释结果

这不是我所期望的结果。我会试着解释为什么。希望你能帮我弄清楚我的推理有什么问题。

我的后台缓冲区有 sRGB 格式(我已经用 RenderDoc 验证了这一点)。据我所知,您应该在着色器中使用线性值。当您在片段着色器中写入线性颜色时,它将自动“压缩”到 gamma 空间(大约 x^(1/2.2))。

当您对 sRGB 纹理进行采样时,情况正好相反。颜色存储在伽马空间中,采样时,该值会自动“解压缩”为线性空间(大约 x^2.2)。

1)清除屏幕

对于颜色清晰,我不确定会发生什么。 有两种选择:

  • 它可能表现得像写入线性值的片段着色器。在这种情况下,颜色将自动转换为sRGB,因此我会看到较浅的灰色。
  • 它只是将原始数据写入帧缓冲区。在这种情况下,我会看到一个感知的 50% 灰色。

从生成的图像中,我看到感知到的 50% 是灰色的。但令我困扰的是,它与大矩形的灰色阴影相同。

2)大矩形

我看到感知 50% 灰色。这怎么可能?

我在片段着色器中写入 0.5 线性值。这应该对应于伽马(感知)光谱中的~73%灰色。

3) Small rectagle

I see a dark grey (I think it's around ~20% perceptual grey). I wasn't expecting this at all.

What I expected is that the 50% sRGB grey texel would be brought into the fragment shader as ~21.7% linear-scale grey (decompress). When storing that value, the opposite operation be performed (compress), resulting in 50% grey again.


I'm quite confused. And a bit ashamed that after many years working with OpenGL I still haven't grasped the topic. Hopefully you can help me out.

This is the whole code for the demo: https://gist.github.com/tuket/034101ef4132dad7005bbb5d6259ab1f

C++ OpenGL GLSL GLFW 伽玛

评论

2赞 genpfault 10/25/2022
Where's your GLFW_SRGB_CAPABLE window hint and corresponding call?glEnable(GL_FRAMEBUFFER_SRGB)
0赞 genpfault 10/25/2022
Also, edit in a minimal reproducible example.
0赞 tuket 10/25/2022
@genpfault I wasn't aware of those flags. The GLFW flag didn't work, but fixed the problem! Thanks!glEnable(GL_FRAMEBUFFER_SRGB);
0赞 tuket 10/25/2022
@genpfault About the "minimal reproducible example"... I'm not sure if you missed the gist link, or that doesn't qualify as "minimal reproducible example" ?
1赞 genpfault 10/25/2022
That is a MCVE but it isn't in the question itself. Pastebins die but SO is forever :)

答: 暂无答案