在 C++ 中使用 GLSL 和 OpenGL 中的 2D PNG 进行 3D 查找 Table

Using a 3D Lookup Table from a 2D PNG in GLSL and OpenGL in C++

我正在尝试为我的颜色分级着色器加载表示颜色查找 table 的 PNG。

这是中性 LUT png 表示:

我不确定如何将其正确加载为 3d 纹理,然后将其传递到我的着色器中。显然,发生了颜色变换,但我最终得到的是嘈杂的彩虹混乱,而不是中性图像。 例如:

下面是我创建纹理的方法

    glGenTextures(1, &lut_texture);
    glBindTexture(GL_TEXTURE_3D, lut_texture);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8, 32, 32, 32, 0, GL_RGB,
        GL_UNSIGNED_BYTE, &lut_image[0]);

以下是我将其传递到着色器的方式:

    glUseProgram(colorGradingProgram);
    glUniform1f(glGetUniformLocation(colorGradingProgram, "tex0"), 0);
    glUniform1f(glGetUniformLocation(colorGradingProgram, "lut"), 1);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, colorBuffers[0]); 
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_3D, lut_texture); 
    drawQuad();
    glBindTexture(GL_TEXTURE_3D, 0); 
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, 0); 
    glUseProgram(0);

这是片段着色器(使用 GLSL 1.x):

uniform sampler2D tex0;
uniform sampler3D lut;

void main(void)
{
  vec4 colorIn = texture2D(tex0, gl_TexCoord[0].st);

  vec4 colorOut;    
  colorOut.rgb = texture3D(lut, colorIn.rgb).rgb;   

  gl_FragColor = colorOut;  
}

我最不清楚的是为调用

指定的维度
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8, 32, 32, 32, 0, GL_RGB,
        GL_UNSIGNED_BYTE, &lut_image[0]);

根据我在这里使用的值,我的结果差异很大。我能得到的最接近中性图像的是使用 (2,2,2) 作为宽度、高度、深度,但这在直觉上并没有引起我的共鸣,也不是完全中性的。我不明白我做错了什么或应该如何实现(将 2d 纹理转换为 3d 体积)

根据我对上述评论的有根据的猜测,您需要

  1. 分别上传每个纹理层。
  2. 指定 GL_RGBA 格式。

下面的代码应该可以做到这一点(免责声明——未经测试):

glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024);
for(int z = 0; z < 32; ++z) {
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 32*z);
    glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, z, 32, 32, 1, GL_RGBA, GL_UNSIGNED_BYTE, &lut_image[0]);
}