改变片段的颜色

时间:2013-08-14 15:18:21

标签: c++ opengl

我写了一个片段着色器,我想改变片段的颜色。例如,我想如果它收到的颜色是黑色,那么它应该改为蓝色。

这是我使用的着色器:

uniform sampler2D mytex;

layout (pixel_center_integer) in vec4 gl_FragCoord;

uniform sampler2D texture1;

void main ()
{
    ivec2 screenpos = ivec2      (gl_FragCoord.xy);
    vec4  color     = texelFetch (mytex, screenpos, 0);

    if (color == vec4 (0.0,0.0,0.0,1.0)) {
        color = (0.0,0.0,0.0,0.0);
    }

    gl_FragColor = texture2D (texture1, gl_TexCoord[0].st);
}

以下是我从中获取的日志:

  

警告:-1:65535:'GL_ARB_explicit_attrib_location':扩展在当前GLSL版本中不可用

     

警告:0:1:'texelFetch':函数在当前GLSL版本中不可用

我知道这个警告 - 但不应该编译吗? 着色器没有按照我的意愿去做,有人可以解释原因吗?

1 个答案:

答案 0 :(得分:1)

首先,您使用的是GLSL实现中没有的功能。调用这些的结果将是未定义的。

但是,这里的踢球者是gl_FragColor 绝对没有 来处理此着色器中color的值。因此,即使您的texelFetch (...)逻辑确实正常工作,更改color的值也不会对最终输出产生任何影响。智能编译器会将此视为无操作,并有效地剥离着色器:


uniform sampler2D texture1;

void main ()
{
  gl_FragColor = texture2D (texture1, gl_TexCoord[0].st);
}


如果这还不够,则在此着色器中完全不需要texelFetch (...)。如果要查找与着色器中当前片段对应的纹理元素,并且纹理与您要绘制的视口具有相同的尺寸,则实际上可以使用texture2D (texture1, gl_FragCoord.xy);这是因为GLSL中的默认行为是gl_FragCoord提供片段中心的坐标(x + 0.5,y + 0.5) - 这也是纹理中相应纹素的中心(如果它是相同的分辨率),所以你可以进行传统的纹理查找,而不必担心纹理过滤会改变您的采样结果。

texelFetch (...)允许您在不使用标准化坐标的情况下在纹理中获取显式纹理元素,它有点像成熟的"矩形纹理:)如果您使用多重采样纹理并想要特定样本,或者如果您想绕过纹理过滤(包括mipmap级别选择),它通常很有用。在这种情况下,根本不需要它。

这可能就是你真正想要的(OpenGL 3.2):


#version 150

uniform sampler2D mytex;
uniform sampler2D texture1;

layout (location=0) out vec4 frag_color;
layout (location=1) out vec4 mytex_color;

void main ()
{
  mytex_color = texture2D (mytex, gl_FragCoord.xy);

  // This is not black->blue like you explained in your question...
  //   ... This is generally opaque->transparent, assuming 4th component = alpha
  if (mytex_color == vec4 (0.0,0.0,0.0,1.0)) {
    mytex_color = vec4 (0.0);
  }

  frag_color = texture2D (texture1, gl_TexCoord[0].st);
}

在较旧的GLSL版本中,您必须使用glBindFragDataLocation (...)并手动设置数据位置,或使用gl_FragData[n]代替out变量。

现在真正的问题是你似乎想要改变你正在采样的纹理的颜色。这不起作用,最多你将不得不使用两个片段数据输出。写入相同的纹理可以在一些非常受控制的情况下进行采样,但通常你要做的就是纹理之间的乒乓。换句话说,您将从一个纹理中获取,写入另一个纹理,并且所有引用原始纹理的后续渲染过程都应与您刚刚写入的那个交换。

有关多个渲染目标绘图的详细信息,请参阅"Fragment Data Location"