2

我正在尝试弄清楚如何使用片段着色器实现调色板交换(查看这篇文章https://gamedev.stackexchange.com/questions/43294/creating-a-retro-style-palette-swapping-effect-in -opengl ) 我是 open 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]是索引纹理(我要着色的那个)

索引纹理

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

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

在此处输入图像描述

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

但我得到的不是画图:

结果

实际上,如果我明确设置 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) 处的像素的颜色值”?

4

1 回答 1

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)。

除非您使用整数或浮点纹理(而您没有使用),否则您的颜色将存储为标准化浮点值。因此,当您从着色器中获取“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

于 2013-01-29T01:25:27.770 回答