使用片段着色器进行调色板交换

时间:2013-01-28 22:52:19

标签: opengl

我正在尝试理清如何使用片段着色器实现调色板交换(查看此帖https://gamedev.stackexchange.com/questions/43294/creating-a-retro-style-palette-swapping-effect-in-opengl)我是新手来开放gl所以如果有人能解释我的问题,我会很高兴。

以下是我尝试重现的代码段:

http://www.opengl.org/wiki/Common_Mistakes#Paletted_textures

我设置了Open GL环境,这样我就可以创建窗口,加载纹理,着色器并渲染我映射到窗口角落的单个方块(当我调整窗口图像的大小时也会被拉伸)。

我使用顶点着色器将坐标从屏幕空间转换为纹理空间,因此我的纹理也被拉伸

attribute vec2 position;

varying vec2 texcoord;

void main()
{
        gl_Position = vec4(position, 0.0, 1.0);
        texcoord = position * vec2(0.5) + vec2(0.5);
}

片段着色器是

uniform float fade_factor;
uniform sampler2D textures[2];

varying vec2 texcoord;

void main()
{
    vec4 index = texture2D(textures[0], texcoord);
    vec4 texel = texture2D(textures[1], index.xy);
    gl_FragColor = texel;
}

textures[0]是索引纹理(我试图着色的那个)

indexed texture

每个像素的颜色值为(0,0,0,255),(1,0,0,255),(2,0,0,255)......(8,0,0,255) - 总共8种颜色,这就是它看起来几乎是黑色的原因。我想使用存储在“红色通道”中的值对我的颜色进行编码。

textures[1]是颜色表(9x1像素,每个像素都有唯一的颜色,放大到90x10张贴)

enter image description here

因此,您可以从片段着色器摘录中看到,我想从第一个纹理中读取索引值,例如(5,0,0,255),然后从存储在点(x = 5)的像素中查找实际颜色值,y = 0)在第二个纹理中。与在wiki中写的相同。

但是我得到的不是画图像:

result

实际上,如果我明确设置X点,如vec2(1,0),vec2(2,0),vec2(4,0)或vec2(8,0),我看到我无法访问第二个纹理的像素。但是当我使用vec2(0.1,0)或vec2(0.7,0)时,我可以获得颜色。猜测是因为纹理空间从我的9x1像素归一化到(0,0) - >(1,1)。但是,如何“禁用”该功能并简单地加载我的调色板纹理,以便我可以问“给我存储在(x,y)的像素的颜色值,请”?

1 个答案:

答案 0 :(得分:2)

  

每个像素的颜色值为(0,0,0,255),(1,0,0,255),(2,0,0,255)......(8,0,0,255)

错误。每个像素的颜色值为:(0,0,0,1),(0.00392,0,0,1),(0.00784,0,0,1)...(0.0313,0,0,1)。 / p>

除非您使用整数或浮动纹理(并且您不是),否则您的颜色将存储为标准化浮点值。所以当您从着色器中获取它时,您认为“255”实际上只是“1.0”。

处理此问题的正确方法是首先将规范化值转换回非规范化形式。这是通过将值乘以255来完成的。然后通过除以调色板纹理的宽度(-1)将它们转换为纹理坐标。此外,您的调色板纹理不应该是2D:

#version 330 //Always include a version.

uniform float fade_factor;
uniform sampler2D palattedTexture;
uniform sampler1D palette;

in vec2 texcoord;

layout(location = 0) out vec4 outColor;

void main()
{
    float paletteIndex = texture(palattedTexture, texcoord).r * 255.0;
    outColor = texture(palette, paletteIndex / (textureSize(palette).x - 1));
    gl_FragColor = texel;
}

以上代码是为GLSL 3.30编写的。如果您使用的是早期版本,请相应地进行翻译。

此外,您不应该使用RGBA纹理作为调色板纹理。它只是一个频道,因此请使用GL_LUMINANCEGL_R8