0

考虑以下代码。imageDataf 是一个浮点数*。事实上,正如代码所示,它由光线追踪器创建的 float4 值组成。当然,颜色值在线性空间中,我需要对它们进行伽玛校正以在屏幕上输出。所以我能做的是一个简单的 for 循环,伽马校正为 2.2(参见 for 循环)。此外,我可以使用 GL_FRAMEBUFFER_SRGB_EXT,它几乎可以正常工作,但存在“条带”问题。

图像

左边是使用 GL_FRAMEBUFFER_SRGB_EXT,右边是手动伽玛校正。右图看起来很完美。在某些显示器上发现它可能会有一些困难。有谁知道如何解决这个问题?我想“免费”进行伽玛校正,因为 CPU 版本使 GUI 有点滞后。请注意,实际的光线追踪是在另一个线程中使用 GPU(optix) 完成的,因此实际上它的渲染性能几乎一样快。

GLboolean sRGB = GL_FALSE;
glGetBooleanv( GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &sRGB );
if (sRGB) {
    //glEnable(GL_FRAMEBUFFER_SRGB_EXT);
}

for(int i = 0; i < 768*768*4; i++)
{
    imageDataf[i] = (float)powf(imageDataf[i], 1.0f/2.2f);
}

glPixelStorei(GL_UNPACK_ALIGNMENT, 8);

glDrawPixels( static_cast<GLsizei>( buffer_width ), static_cast<GLsizei>( buffer_height ),
    GL_RGBA, GL_FLOAT, (GLvoid*)imageDataf);

//glDisable(GL_FRAMEBUFFER_SRGB_EXT);
4

1 回答 1

3

启用时GL_FRAMEBUFFER_SRGB,这意味着 OpenGL 将假定片段的颜色在线性颜色空间中。因此,当它将它们写入 sRGB 格式的图像时,它会在内部将它们从线性转换为 sRGB。除了......你的像素不是线性的。您已经将它们转换为非线性色彩空间。

但是,我假设您只是忘记了其中的if声明。我假设如果帧缓冲区支持 sRGB,则跳过循环并直接上传数据。所以相反,我会解释为什么你会被绑起来。

因为您要求的 OpenGL 操作执行以下操作,所以您得到了条带化。对于您指定的每种颜色:

  1. 将浮点数限制在 [0, 1] 范围内。
  2. 将浮点数转换为无符号、标准化的 8 位整数。
  3. 生成一个无符号、标准化、8 位颜色的片段。
  4. 将无符号、标准化、8 位片段颜色从线性 RGB 空间转换为 sRGB 空间并存储。

步骤 1-3 都来自使用glDrawPixels. 您的问题是第 2 步。您希望将浮点值保留为floats。然而,您坚持使用固定功能管道(即:)glDrawPixels,它强制将浮点数转换为无符号标准化整数。

如果您将数据上传到浮动纹理并使用适当的片段着色器来渲染此纹理(即使只是一个简单的gl_FragColor = texture(tex, texCoord);着色器),您就可以了。着色器管道使用浮点数学,而不是整数数学。所以不会发生这样的转换。

简而言之:停止使用glDrawPixels.

于 2013-04-01T13:57:32.857 回答