如何获取片段的当前颜色?

问题描述:

我试图在GLSL中将我的头包裹在着色器中,并且我找到了一些有用的资源和教程,但是我一直跑到墙上寻找应该是基本和琐碎的东西:我的片段着色器如何检索当前片段的颜色?如何获取片段的当前颜色?

您通过设置gl_FragColor = whatever来设置最终颜色,但显然这是仅输出值。如何获得输入的原始颜色,以便您可以对其进行计算?这在某个地方应该是一个变量,但如果有人知道它的名字,那么他们似乎没有将它记录到我迄今为止所遇到的任何教程或文档中,并且它将我推上了墙。

+0

“原始颜色的输入”:你的意思是分配给你的片段(纹理,diffusecolor ..)的材料属性? – DamienD 2010-04-30 11:49:07

片段着色器接收gl_Colorgl_SecondaryColor作为顶点属性。它还得到四个变量:gl_FrontColorgl_FrontSecondaryColor,gl_BackColorgl_BackSecondaryColor它可以写入值。如果您想直接通过传递原来的颜色,你会做这样的事情:

gl_FrontColor = gl_Color; 
gl_FrontSecondaryColor = gl_SecondaryColor; 
gl_BackColor = gl_Color; 
gl_BackSecondaryColor = gl_SecondaryColor; 
在管道下面的顶点着色器,然后将这些夹在区间[0,1],图

固定功能确定顶点是前向还是后向。然后,它会像往常一样插入选定的(正面或背面)颜色。然后片段着色器将接收所选的,被夹住的内插颜色,如gl_Colorgl_SecondaryColor

例如,如果你画了标准的 “死亡三角”,如:

glBegin(GL_TRIANGLES); 
    glColor3f(0.0f, 0.0f, 1.0f); 
    glVertex3f(-1.0f, 0.0f, -1.0f); 
    glColor3f(0.0f, 1.0f, 0.0f); 
    glVertex3f(1.0f, 0.0f, -1.0f); 
    glColor3f(1.0f, 0.0f, 0.0f); 
    glVertex3d(0.0, -1.0, -1.0); 
glEnd(); 

然后,顶点着色器是这样的:

void main(void) { 
    gl_Position = ftransform(); 
    gl_FrontColor = gl_Color; 
} 

与片段着色器是这样的:

void main() { 
    gl_FragColor = gl_Color; 
} 

将传输颜色,就像使用固定功能流水线一样。

+25

大部分你正在做的所有事情都是在版本120之后弃用的。实际上,不仅是警告,还有错误。也不会使用OpenGL ES 2.0(也会在4.x版本中消失) – user697111 2011-04-26 02:54:25

您的片段着色器的整个点是决定输出颜色。你怎么做取决于你想做什么。

您可能会选择设置,以便根据顶点着色器的输出获得插值颜色,但更常见的方法是使用片段着色器中的纹理坐标执行纹理查找顶点着色器插补。然后,根据您选择的光照计算以及您的着色器所要执行的操作,然后将其写入gl_FragColor中,然后修改纹理查找的结果。

如果您称之为“片段的当前值”是片段着色器运行之前渲染目标中的像素颜色值,则no,它不可用。

这样做的主要原因是潜在的,当你的片段着色器运行时,它还不知道。片段着色器并行运行,可能(取决于哪个硬件)影响同一像素,而单独的块从某种FIFO中读取,通常有责任将这些合并在一起。这种合并被称为“混合”,并且不属于可编程流水线的一部分。它是固定的函数,但它有许多不同的方法可以将您的片段着色器生成的像素与之前的像素颜色值进行组合。

如果你想做多次渲染,即如果你已经渲染到帧缓冲区,并希望到您使用以前的呈现比回答第二渲染过程是:

  1. 渲染第一遍纹理
  2. 绑定这个纹理,第二道
  3. 访问着色器中的privously渲染像素

着色器代码3.2:

uniform sampler2D mytex; // texture with the previous render pass 

layout(pixel_center_integer) in vec4 gl_FragCoord; 
// will give the screen position of the current fragment 

void main() 
{ 
    // convert fragment position to integers 
    ivec2 screenpos = ivec2(gl_FragCoord.xy); 
    // look up result from previous render pass in the texture 
    vec4 color = texelFetch(mytex, screenpos, 0); 
    // now use the value from the previous render pass ... 
} 

处理渲染图像的另一种方法是使用OpenGL - > OpenCL interop的OpenCL。这允许更多CPU像计算。

您需要在当前像素坐标样本纹理,这样的事情

vec4 pixel_color = texture2D(tex, gl_TexCoord[0].xy);

注意, - 因为我见过的Texture2D在GLSL 4.00不赞成使用说明书 - 只是寻找类似的纹理...取功能。

有时也最好是提供自己的像素坐标,而不是gl_TexCoord [0]某个.XY - 在这种情况下写的顶点着色器一样的东西:

varying vec2 texCoord; 

void main(void) 
{ 
    gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); 
    texCoord = 0.5 * gl_Position.xy + vec2(0.5);  
}

而在片段着色器使用该texCoord变量代替gl_TexCoord [0]某个.XY。

祝你好运。

怎么办-I-得到最电流颜色的-A-片段

有人说这不能做,但是我说这个工作对我来说:

//Toggle blending in one sense, while always disabling it in the other. 
void enableColorPassing(BOOL enable) { 
//This will toggle blending - and what gl_FragColor is set to upon shader execution 
    enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND); 
    //Tells gl - "When blending, change nothing" 
    glBlendFunc(GL_ONE, GL_ZERO); 
} 

调用之后,gl_FragColor将在着色器首次在每个像素上运行时等于颜色缓冲区的清除颜色,每次连续运行时,每次运行的输出将是新输入。

那么,至少它适合我。

+5

-1:对于“它适用于我”废话,甚至无法说出您实际使用的硬件。此外,为了支持未定义的行为,而不必烦恼地说出你正在使用的硬件是否这样做。 – 2012-11-09 05:18:00

着色器运行后,GPU管线立即可以访问底层像素信息。如果您的材料是透明的,则管道的混合阶段将合并所有片段。

一般情况下,对象按照它们被添加到场景的顺序进行混合,除非它们已经被z缓冲算法命令。你应该首先添加你的不透明物体,然后仔细添加你的透明物体的顺序进行混合。例如,如果您想在场景中使用HUD叠加层,则应该使用合适的透明纹理创建屏幕四边形对象,并最后将其添加到场景中。

为透明对象设置SRC和DST混合功能可让您以多种不同方式访问以前的混合。

您可以在这里使用输出颜色的alpha属性来进行真正的混合效果。这是访问帧缓冲输出(像素)的最有效方法,因为它在GPU流水线的单通道(图1)中工作。

enter image description here
图1 - 单通道

如果你真的需要multi pass(图2),那么你就必须针对帧缓冲区输出到一个额外的纹理单元,而不是屏幕,将此目标纹理复制到下一个传球,依此类推,最终传球中的目标为屏幕。每次传递至少需要两次上下文切换。

额外的复制和上下文切换将严重降低渲染性能。请注意,多线程GPU管道在这里没有多大帮助,因为多路径本质上是序列化的。

enter image description here
图2 - 多通

我都使出与管道图口头描述以避免弃用,由于着色语言(俚语/ GLSL)是可能会改变。