如何在片段着色器中应用我自己的颜色图?

How to apply my own colormap in the fragment shader?

我有一个给定的图像 img(16 位灰度图像,其值范围从 0 到 65535)和一个颜色图 colormap_file,它是 8位RGB 256*256像素图像。

因此,多亏了这样一个颜色图,我能够为 valueImage 中的所有像素分配一个 (R, G, B) 三元组。

目前,它是通过这个函数在纯 Python 中完成的:

def transcodeThroughColormap(img, colormap_file):
    colormap = np.array(Image.open(colormap_file))
    flat_colormap = colormap.flatten()

    idx = img
    i = np.floor(idx / 256)
    j = idx - (i * 256)
    R = flat_colormap[(3 * (i * 256 + j)).astype('int')]
    G = flat_colormap[(3 * (i * 256 + j) + 1).astype('int')]
    B = flat_colormap[(3 * (i * 256 + j) + 2).astype('int')]


    rgbArray = np.zeros(shape=(img.shape[0], img.shape[1], 3))
    rgbArray[..., 0] = R
    rgbArray[..., 1] = G
    rgbArray[..., 2] = B


    return rgbArray

但是,我想在我的片段着色器中应用这样的颜色图。

因此,我想知道我是否必须在我的片段着色器中使用两个 sampler2D,但我不知道如何获得与 Python 中相同的结果。

我通过了从 OpenGL 论坛得到的答案: 一个选项:

uniform usampler2D image_tex;
uniform sampler2D color_map;

in vec2 texcoord;

void main()
{
    uint value = texture(image_tex, texcoords).x;
    uvec2 uv = uvec2(value / 0x100, value % 0x100);
    vec4 color = texelFetch(color_map, uv, 0);
    gl_FragColor = color;
}

注意图片纹理需要是无符号整数类型,即GL_R16UI。放大和缩小过滤器需要 GL_NEAREST(线性插值对整数值没有意义)。

如果图像纹理中的值表示连续范围并且颜色图是连续的,那么您可以对图像纹理使用归一化格式(即 GL_R16)并使用一维纹理颜色图(但是不能保证支持 65536 的大小,因此您可能需要对颜色图进行下采样)。例如

uniform sampler2D image_tex;
uniform sampler1D color_map;

in vec2 texcoord;

void main()
{
    float value = texture(image_tex, texcoords).x;
    vec4 color = texture(color_map, value);
    gl_FragColor = color;
}

或者您可以为颜色图使用缓冲纹理(保证支持 65536 大小),这样就无需将值拆分为行和列。例如

uniform sampler2D image_tex;
uniform samplerBuffer color_map;

in vec2 texcoord;

void main()
{
    float value = texture(image_tex, texcoords).x;
    int idx = int(round(value * 0xFFFF));
    vec4 color = texelFetch(color_map, idx, 0);
    gl_FragColor = color;
}

Link to the topic on OpenGL