提问人:tuket 提问时间:10/25/2022 最后编辑:genpfaulttuket 更新时间:10/25/2022 访问量:78
OpenGL sRGB实验 [已结束]
OpenGL sRGB experiment [closed]
问:
我在 OpenGL 中做了一个简单的演示,以更好地理解伽马校正。我已经意识到它打破了我的一些假设,所以我希望有人可以帮助我理解。
作为参考,我用 GIMP 制作了这张图片。它以 10% 的步长显示整个黑-灰-白光谱。这些是可见光谱(伽马)。
我的 OpenGL 演示执行以下操作:
- 清除 50% 灰色的屏幕
- 使用输出 50% 灰色的着色器绘制一个大矩形(在着色器中硬编码)
- 绘制一个较小的矩形,对单像素、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
答: 暂无答案
评论
GLFW_SRGB_CAPABLE
window hint and corresponding call?glEnable(GL_FRAMEBUFFER_SRGB)
glEnable(GL_FRAMEBUFFER_SRGB);