【问题标题】:Palette swap using fragment shaders使用片段着色器交换调色板
【发布时间】:2013-01-12 10:10:07
【问题描述】:

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

这是我试图重现的代码 sn-p:

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里写的一样。

但我得到的不是画图:

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

【问题讨论】:

  • 为什么不通过将坐标除以查找纹理的宽度来进行归一化?
  • 可能这还不够,我的输出仍然很糟糕

标签: opengl


【解决方案1】:

每个像素的颜色值为 (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

【讨论】:

  • 能否解释一下本文中的sn-p(针对110版)? opengl.org/wiki/Common_Mistakes#Paletted_textures 似乎他们只是将纹理用作二维数组。
  • @dig:因为//256 x 1 pixels 这一行,它才有效。看看我上面的等式:我乘以 255.0,然后除以图像的宽度 - 1。即 256 - 1。因此,如果调色板纹理的宽度为 256,则不必乘以或除以。
  • 谢谢!最后我弄清楚发生了什么:)
猜你喜欢
  • 1970-01-01
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 2013-09-17
  • 2021-04-21
  • 2014-11-12
  • 2021-12-25
  • 2021-12-02
相关资源
最近更新 更多