片元着色器处理光栅化后的产生片元并输出一系列的颜色和一个深度值。片元着色器是图元光栅化后,OpenGL显示管线的下一阶段,被图元覆盖的像素将产生输出。每一个片元着色器都具有窗口空间的位置和一系列在前一阶段顶点着色器输出的逐顶点插值。
片元着色器将输出一个深度值(depth value 范围 0 - 1),也可能包含一个模版值(看定义的深度缓冲格式是否包含模版 GL_DEPTH_COMPONENT24 ,GL_DEPTH_COMPONENT32, 模版缓存被启用,该值在着色器中不会被修改),零 到 多个 颜色值,这些值将被写入到帧缓存中。
片元着色器是可选阶段,如果不使用片元着色器,颜色输出是未定义的,且不会改变深度、模版缓存值。可以利用这一特性,在顶点着色器中计算深度值, (没有片元着色器,不改变其值)直接刷新深度缓冲区, 实现阴影绘制和 预处理深度通道 等技法。
The following Per-Sample Processing steps can be performed before the fragment shader:
The pixel ownership test
The scissor test
The stencil test
The depth test
Occlusion query updating
Note that with OpenGL 4.2 or ARB_shader_image_load_store, the pixel ownership and scissor tests will always be performed early.
片元着色器的输入是早期固定管线系统输入及图元表面的插值。
1. 系统输入
in bool gl_FrontFacing; //双面光照
in vec2 gl_PointCoord;
in vec4 gl_FragCoord ; //这个输入有用的多,多用在后处理。
gl_FragCoord 在片元着色器阶段很有用, x, y 是窗口空间的值,单位是像素。如果用户没有写入gl_FragDepth, z 值将被写入, gl_FragCoord 是 1/Wclip , Wclip 透视除法 其值是 VclipCoord = PVM_matrix * Vertex 的 w值。
裁剪空间坐标直接用乘上 gl_FragCoord.w 即做了透视除法了。
OpenGL 4.0 加入 的 gl_SampleID,gl_SamplePosition,gl_SampleMaskIn。
-------------------------------------------------------------------------------
gl_ClipDistance,gl_PrimitiveID
OpenGL4.3 加入的
gl_Layer,gl_ViewportIndex。
2. 顶点着色器阶段的输入
out 出的各种属性值。
用户自定义输出,只能是 浮点数 floats, 整数 integers,和向量 vectors, 相同类型可以成组输出,不能输出接口块 interface blocks。
有三种方法可以将输出变量与颜色号关联起来:
1. 在着色器中指定 In-shader specification
layout(location = 3) out vec4 diffuseColor;
2.在shader链接前指定 Pre-link specification
glBindFragDataLocation(GLuint program, GLuint colorNumber, const char * name);
3. 系统自动设置 Automatic assignment
正如顶点属性输入一样,颜色输出的索引号也是连续的, 自动分配输出并不是什么好主意,不同的片元着色器,即使输出名字相同,分配的输出也可能不同,你每次都需要验证其有效性。
1. 在着色器中控制 gl_FragDepth 输出值。
GLSL 4.20 or ARB_conservative_depth 定义输出值
layout (depth_
any
The default. You may freely change the depth, but you lose the most potential performance.
greater
You will only make the depth larger, compared to gl_FragCoord.z.
less
You will only make the depth smaller, compared to gl_FragCoord.z.
unchanged
If you write to gl_FragDepth, you will write exactly gl_FragCoord.z.
2. GLSL 4.00 or ARB_sample_shading 定义多重采样掩码:
out int gl_SampleMask[];
gl_SampleMask
首先指定输出缓存:
const GLenum buffers[] = {GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT2, GL_NONE, GL_COLOR_ATTACHMENT0};
glDrawBuffers(4, buffers);
其次,在shader 中关联输出位置 location 及定义输出格式 int, vec3, vec4...:
layout(location = 1) out int materialID;
layout(location = 4) out vec3 normal;
layout(location = 0) out vec4 diffuseColor;
layout(location = 3) out vec3 position;
layout(location = 2) out vec4 specularColor;
Output name | Color attachment |
---|---|
materialID | GL_COLOR_ATTACHMENT2 |
normal | GL_NONE |
diffuseColor | GL_COLOR_ATTACHMENT4 |
position | GL_COLOR_ATTACHMENT0 |
specularColor | GL_NONE |
当指定的索引号超出范围时,输出无效 GL_NONE 。