iOS上的片段着色器中奇怪的GLSL浮点颜色值

时间:2013-08-01 03:39:32

标签: ipad glsl glsles

我正在尝试在iPad2上编写一个简单的GLSL片段着色器,我遇到一个奇怪的问题,就是OpenGL似乎代表一个8位“红色”值,像素值已被转换为浮点数作为一部分纹理上传。我想要做的是传递一个包含大量8位表索引的纹理和一个32bpp的实际像素值表。

我的纹理数据看起来像这样:

  // Lookup table stored in a texture

  const uint32_t pixel_lut_num = 7;
  uint32_t pixel_lut[pixel_lut_num] = {
    // 0 -> 3 = w1 -> w4 (w4 is pure white)
    0xFFA0A0A0,
    0xFFF0F0F0,
    0xFFFAFAFA,
    0xFFFFFFFF,
    // 4 = red
    0xFFFF0000,
    // 5 = green
    0xFF00FF00,
    // 6 = blue
    0xFF0000FF
  };

  uint8_t indexes[4*4] = {
    0, 1, 2, 3,
    4, 4, 4, 4,
    5, 5, 5, 5,
    6, 6, 6, 6
  };

然后绑定每个纹理并上传纹理数据,如下所示:

  GLuint texIndexesName;
  glGenTextures(1, &texIndexesName);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, texIndexesName);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, width, height, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, indexes);

  GLuint texLutName;
  glGenTextures(1, &texLutName);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_2D, texLutName);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixel_lut_num, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixel_lut);

我确信纹理设置和统一值按预期工作,因为片段着色器主要使用以下代码:

varying highp vec2 coordinate;
uniform sampler2D indexes;
uniform sampler2D lut;

void main()
{
  // normalize to (RED * 42.5) then lookup in lut
  highp float val = texture2D(indexes, coordinate.xy).r;
  highp float normalized = val * 42.5;
  highp vec2 lookupCoord = vec2(normalized, 0.0);
  gl_FragColor = texture2D(lut, lookupCoord);
}

上面的代码采用8位索引,并在lut中查找32bpp BGRA像素值。我不理解的部分是在OpenGL中定义这个42.5值的地方。我通过反复试验找到了这个比例值,我已经确认每个像素的输出颜色是正确的(意味着每个lut表查找的索引是正确的),其值为42.5。但是,OpenGL究竟是如何提出这个值的呢?

在查看此OpenGL man page时,我发现在将8位“索引”值转换为OpenGL内部使用的浮点值时,似乎使用了两个颜色常量GL_c_SCALE和GL_c_BIAS。这些常量在哪里定义,如何在运行时或编译时查询值? “索引”表的实际浮点值是真正的问题吗?我无法理解为什么texture2D(索引,...)调用返回这个时髦的值,是否有其他方法来获取适用于iOS的索引的int或float值?我试着看一维纹理,但似乎不支持它们。

1 个答案:

答案 0 :(得分:1)

您的颜色索引值将作为8Bit UNORMs访问,因此范围[0,255]将映射到浮点间隔[0,1]。当您访问LUT纹理时,texcoord范围也是[0,1]。但是目前,你只有7的宽度。所以你的魔法值为42.5,你得到以下结果:

INTEGER INDEX: 0: FP: 0.0 ->  TEXCOORD: 0.0 * 42.5 == 0.0
INTEGER INDEX: 6: FP: 6.0/255.0 ->  TEXCOORD: (6.0/255.0) * 42.5 == 0.9999999...

该映射很接近,但不是100%正确,因为您没有映射到纹素中心。 要获得正确的映射(有关详细信息,请参阅this answer),您需要以下内容:

INTEGER INDEX:   0: FP:         0.0 ->  TEXCOORD: 0.0 + 1.0/(2.0 *n)
INTEGER INDEX: n-1: FP: (n-1)/255.0 ->  TEXCOORD: 1.0 - 1.0/(2.0 *n)

上面的代码npixel_lut_size

因此,单个比例值是不够的,您实际上需要一个额外的偏移量。正确的值将是:

scale=  (255 * (1 - 1/n)) / (n-1)    ==  36.428...
offset= 1/(2.0*n)                    ==  0.0714...

还有一件事:你不能将GL_LINEAR用于LUT缩小纹理过滤器。