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 开始,我怀疑你会注意到这个错误。