openGL 将像素亮度转换为颜色贴图纹理会产生不正确的结果
openGL Translating pixel brightness to colormap texture produces incorrect result
查看 RGB 和颜色图之间的 gif 切换:
问题是两张图片不一样
我正在绘制 RGB 白色 (1.0,1.0,1.0) 的点。 Alpha 通道控制像素亮度,从而产生点模糊。这就是您所看到的更明亮的图像。然后我有一个 2 像素的黑白纹理 (0.0,0.0,0.0,1.0) (1.0,1.0,1.0,1.0) 并且在片段着色器中我这样做:
#version 330
precision highp float;
uniform sampler2D originalColor;
uniform sampler1D colorMap;
in vec2 uv;
out vec4 color;
void main()
{
vec4 oldColor = texture(originalColor, uv);
color = texture(colorMap, oldColor.a);
}
非常简单,将原始颜色纹理的 alpha 值从 0 到 1 的片段,并将其转换为具有黑色到白色的 colorMap 纹理的新颜色。 两张图应该没有区别吧!或者……至少,这是我的目标。
这是我对颜色贴图纹理的设置
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &colormap_texture_id); // get texture id
glBindTexture(GL_TEXTURE_1D, colormap_texture_id);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // required: stop texture wrapping
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // required: scale texture with linear sampling
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, colormapColors.size(), 0, GL_RGBA, GL_FLOAT, colormapColors.data()); // setup memory
渲染循环:
GLuint textures[] = { textureIDs[currentTexture], colormap_texture_id };
glBindTextures(0, 2, textures);
colormapShader->use();
colormapShader->setUniform("originalColor", 0);
colormapShader->setUniform("colorMap", 1);
renderFullScreenQuad(colormapShader, "position", "texCoord");
我使用 1D 纹理作为颜色图,因为这似乎是可能将 1000 到 2000 个颜色图值索引存储在 GPU 内存中的唯一方法。如果有更好的方法,请告诉我。我认为问题是两个像素之间的插值数学不适合我的目的。
我应该怎么做才能获得预期的结果?
为了确保没有恶作剧,我尝试遵循着色器代码:
color = texture(colorMap, oldColor.a); //incorrect results
color = texture(colorMap, (oldColor.r + oldColor.g + oldColor.b)/3); //incorrect
color = texture(colorMap, (oldColor.r + oldColor.g + oldColor.b + oldColor.a)/4); //incorrect
color = vec4(oldColor.a); //incorrect
color = oldColor; // CORRECT... obviously...
我认为要更准确,您需要更改:
color = texture(colorMap, oldColor.a);
至
color = texture(colorMap, oldColor.a * 0.5 + 0.25);
或更一般地说
color = texture(colorMap, oldColor.a * (1.0 - (1.0 / texWidth)) + (0.5 / texWidth));
通常情况下,您不会注意到这个错误,这只是因为 texWidth 太小了,所以差异很大。
这是因为纹理只会在您通过第一个纹素的中心(在您的 2 纹素宽纹理中为 0.25)后才开始从黑色到白色的线性过滤。一旦您通过最后一个纹素的中心(0.75),插值就完成了。
如果你有一个 1024 的纹理,就像你提到的那样,你计划结束然后插值从 0.000488 开始,我怀疑你会注意到这个错误。
查看 RGB 和颜色图之间的 gif 切换:
问题是两张图片不一样
我正在绘制 RGB 白色 (1.0,1.0,1.0) 的点。 Alpha 通道控制像素亮度,从而产生点模糊。这就是您所看到的更明亮的图像。然后我有一个 2 像素的黑白纹理 (0.0,0.0,0.0,1.0) (1.0,1.0,1.0,1.0) 并且在片段着色器中我这样做:
#version 330
precision highp float;
uniform sampler2D originalColor;
uniform sampler1D colorMap;
in vec2 uv;
out vec4 color;
void main()
{
vec4 oldColor = texture(originalColor, uv);
color = texture(colorMap, oldColor.a);
}
非常简单,将原始颜色纹理的 alpha 值从 0 到 1 的片段,并将其转换为具有黑色到白色的 colorMap 纹理的新颜色。 两张图应该没有区别吧!或者……至少,这是我的目标。
这是我对颜色贴图纹理的设置
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &colormap_texture_id); // get texture id
glBindTexture(GL_TEXTURE_1D, colormap_texture_id);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // required: stop texture wrapping
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // required: scale texture with linear sampling
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, colormapColors.size(), 0, GL_RGBA, GL_FLOAT, colormapColors.data()); // setup memory
渲染循环:
GLuint textures[] = { textureIDs[currentTexture], colormap_texture_id };
glBindTextures(0, 2, textures);
colormapShader->use();
colormapShader->setUniform("originalColor", 0);
colormapShader->setUniform("colorMap", 1);
renderFullScreenQuad(colormapShader, "position", "texCoord");
我使用 1D 纹理作为颜色图,因为这似乎是可能将 1000 到 2000 个颜色图值索引存储在 GPU 内存中的唯一方法。如果有更好的方法,请告诉我。我认为问题是两个像素之间的插值数学不适合我的目的。
我应该怎么做才能获得预期的结果?
为了确保没有恶作剧,我尝试遵循着色器代码:
color = texture(colorMap, oldColor.a); //incorrect results
color = texture(colorMap, (oldColor.r + oldColor.g + oldColor.b)/3); //incorrect
color = texture(colorMap, (oldColor.r + oldColor.g + oldColor.b + oldColor.a)/4); //incorrect
color = vec4(oldColor.a); //incorrect
color = oldColor; // CORRECT... obviously...
我认为要更准确,您需要更改:
color = texture(colorMap, oldColor.a);
至
color = texture(colorMap, oldColor.a * 0.5 + 0.25);
或更一般地说
color = texture(colorMap, oldColor.a * (1.0 - (1.0 / texWidth)) + (0.5 / texWidth));
通常情况下,您不会注意到这个错误,这只是因为 texWidth 太小了,所以差异很大。
这是因为纹理只会在您通过第一个纹素的中心(在您的 2 纹素宽纹理中为 0.25)后才开始从黑色到白色的线性过滤。一旦您通过最后一个纹素的中心(0.75),插值就完成了。
如果你有一个 1024 的纹理,就像你提到的那样,你计划结束然后插值从 0.000488 开始,我怀疑你会注意到这个错误。