片段着色器如何知道用于像素颜色的变量?

mpe*_*pen 76 opengl glsl

我看到很多不同的片段着色器,

#version 130

out vec4 flatColor;

void main(void)
{
    flatColor = vec4(0.0,1.0,0.0,0.5);
}
Run Code Online (Sandbox Code Playgroud)

并且它们都使用不同的变量来表示"颜色"(在这种情况下flatColor).那么OpenGL如何知道你想要做什么?

我猜这个有效,因为flatColor它是唯一定义为的变量out,但是你被允许添加更多out变量不是吗?或者那会崩溃吗?


实际上,作为一个测试,我只是运行这个:

#version 330

in vec2 TexCoord0;

uniform sampler2D TexSampler;

out vec4 x;
out vec4 y;

void main()
{
    y = texture2D(TexSampler, TexCoord0.xy);
}
Run Code Online (Sandbox Code Playgroud)

无论我使用x还是使用它都很好y.


此外,我们有一个预定义的gl_FragColor.有什么区别,为什么人们通常坚持使用他们自己的变量?

Nic*_*las 135

此外,我们有一个预定义的gl_FragColor.

让我们从这开始吧.不,您没有预定义的gl_FragColor.这已从核心OpenGL 3.1及更高版本中删除.除非你使用兼容性(在这种情况下,你的3.30着色器应该#version 330 compatibility在顶部说),你永远不应该使用它.

现在,返回用户定义的片段着色器输出.但首先,快速类比.

还记得在顶点着色器中你有输入吗?而这些投入表示顶点属性索引,你传递给数字glVertexAttribPointerglEnableVertexAttribArray等等?您可以设置哪个输入来自哪个属性.在GLSL 3.30中,您使用以下语法:

layout(location = 2) in color;
Run Code Online (Sandbox Code Playgroud)

这将color顶点着色器输入设置为来自属性位置2.在3.30之前(或没有ARB_explicit_attrib_location),您必须glBindAttrbLocation在链接或查询属性索引的程序之前显式设置它glGetAttribLocation.如果您没有明确提供属性位置,GLSL将任意分配一个位置(即:以实现定义的方式).

在着色器中设置它几乎总是更好的选择.

在任何情况下,片段着色器输出的工作方式几乎完全相同.片段着色器可以写入多种输出颜色,这些颜色本身会映射到帧缓冲区中的多个缓冲区.因此,您需要指明哪个输出转到哪个片段输出颜色.

此过程从片段输出位置值开始.它的设置与顶点着色器输入位置非常相似:

layout(location = 1) out secColor;
Run Code Online (Sandbox Code Playgroud)

还有一些API函数glBindFragDataLocationglGetFragDataLocation,这是类似于glBindAttribLocationglGetAttribLocation.

如果您不进行任何显式赋值,则实现通常会将您的一个输出变量分配给位置0.但是,OpenGL标准不需要此行为,因此您也不应该依赖它.

现在公平地说,当你使用两个没有得到不同输出位置的输出时,你的程序应该无法链接.可能发生的事情是你的编译器优化了你没有写出来的那个,所以在检查链接器错误的时候忘了它.

  • 希望我能给出超过+1.壮观的答案.我想知道片段输出位置是如何工作的.:) (3认同)
  • @Mark:"弃用"意味着"你仍然可以使用它,但它可能会在以后的版本中删除." "已删除"表示*已删除*.它们是有区别的.在GL 3.0中被标记为已弃用的那个在3.1中被删除**(除了几件事). (3认同)
  • @NicolBolas:"GL 3.3及以上版本(这是对先前版本的更改)将全部分配到位置0".我想知道规格保证在哪里.3.3说"当一个程序被链接时,没有指定绑定或在着色器文本中明确设置的任何变化的变量将自动被GL的碎片颜色和索引绑定.所有这些赋值将使用颜色索引零.".3.2中没有最后一句.但是,index不是指color _number_,而是仅指双源混合索引(在3.3中添加). (3认同)
  • 谢谢@NicolBolas,很好的答案!所以我还没有完全理解它,只想让它“毫无疑问”。在我们的着色器中,当绘制到任何绑定的内容(通常是“屏幕”而不是 FBO)时,我们总是指定“layout (location = 0) out vec4 outColor”。因此,默认情况下,如果我们没有使用 glDrawBuffers 绑定 FBO(或其他缓冲区),并且我们指定 `location = 0`,它总是会正确绘制到屏幕上? (2认同)

Lor*_*lli 8

我想为使用GLSL_ES_3.10 链接的 OpenGLES 3.1指定这个:

§4.4.2

如果[片段着色器]中只有一个输出,则不需要指定位置,在这种情况下,它默认为零.