内置变量

内置语言变量

一些操作发生在着色器功能之外,需要向着色器可执行程序提供值或接收来自着色器可执行程序的值。着色器通过使用内置的输入和输出变量与固定功能管线阶段进行通信,并可选择与其他的着色器可执行程序进行通信。

顶点着色器特殊变量

内置的顶点着色器变量本质上声明如下:

in int gl_VertexID;       // only present when not targeting Vulkan
in int gl_InstanceID;     // only present when not targeting Vulkan
in int gl_VertexIndex;    // only present when targeting Vulkan
in int gl_InstanceIndex;  // only present when targeting Vulkan
in int gl_DrawID;
in int gl_BaseVertex;
in int gl_BaseInstance;

out gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
};

变量gl_Position用于写入齐次顶点位置。它可以在着色器执行期间的任何时间写入。此值将被原始组装、裁剪、剔除和其他固定功能操作(如果存在)使用,这些操作在顶点处理发生后对图元进行操作。如果顶点着色器可执行程序没有写入gl_Position,则顶点处理阶段之后其值是未定义的。

变量gl_PointSize用于着色器写入要栅格化的点的大小。它以像素为单位进行测量。如果未写入gl_PointSize,则其在后续管道阶段中的值是未定义的。

变量gl_ClipDistance用于写入裁剪距离,并提供控制用户裁剪的前向兼容机制。元素gl_ClipDistance[i]为每个半空间i指定裁剪距离。距离 0 表示顶点位于半空间的边界上,正距离表示顶点位于裁剪体内,负距离表示点位于裁剪体外。裁剪距离将在图元上进行线性插值,并且插值距离小于 0 的图元部分将被裁剪。

gl_ClipDistance数组被预先声明为未确定大小的,必须由着色器通过使用大小重新声明它来显式确定大小,或者通过仅使用常量整数表达式对其进行索引来隐式确定大小。这需要确定数组的大小以包括所有通过 API 启用的裁剪半空间;如果大小不包括所有启用的半空间,则结果是未定义的。大小最大可以是gl_MaxClipDistances。无论启用了多少个半空间,gl_ClipDistance消耗的可变分量数量(请参阅gl_MaxVaryingComponents)都将与数组的大小匹配。着色器还必须设置所有已通过 API 启用的gl_ClipDistance中的值,否则结果是未定义的。写入未启用的半空间的gl_ClipDistance的值无效。

变量gl_CullDistance提供了一种控制用户剔除的机制。元素gl_CullDistance[i]为半空间i指定剔除距离。距离 0 表示顶点位于半空间的边界上,正距离表示顶点位于剔除体内,负距离表示点位于剔除体外。顶点对于半空间i都具有负剔除距离的图元将被丢弃。

gl_CullDistance数组被预先声明为未确定大小的,必须由着色器通过使用大小重新声明它来显式确定大小,或者通过仅使用常量整数表达式对其进行索引来隐式确定大小。大小决定了启用剔除距离的数量和集合,并且最大可以是gl_MaxCullDistancesgl_CullDistance消耗的可变分量数量(请参阅gl_MaxVaryingComponents)将与数组的大小匹配。写入gl_CullDistance的着色器必须写入所有已启用的距离,否则剔除结果是未定义的。

作为输出变量,gl_CullDistance提供了着色器写入这些距离的位置。作为除片段语言之外所有语言的输入,它读取在前一个着色器阶段中写入的值。在片段语言中,gl_CullDistance数组包含着色器写入到gl_CullDistance顶点输出变量的顶点值的线性插值。

对于形成程序的着色器集,gl_ClipDistancegl_CullDistance数组的大小之和大于gl_MaxCombinedClipAndCullDistances,这是一个编译时或链接时错误。

变量gl_VertexID是一个顶点着色器输入变量,它保存顶点的整数索引,如OpenGL 规范的第 11.1.3.9 节“着色器输入”中的“着色器输入”下定义的那样。它仅在不以 Vulkan 为目标时存在。即使存在,gl_VertexID的值也并非总是定义的。

变量gl_InstanceID是一个顶点着色器输入变量,它保存实例化绘制调用中当前图元的实例编号(请参阅OpenGL 规范的第 11.1.3.9 节“着色器输入”中的“着色器输入”)。它仅在不以 Vulkan 为目标时存在。如果当前图元不是来自实例化绘制调用,则gl_InstanceID的值为零。

变量gl_VertexIndex是一个顶点语言输入变量,它保存相对于基址的顶点的整数索引。它仅在以 Vulkan 为目标时存在。即使存在,gl_VertexIndex的值也并非总是定义的。

变量gl_InstanceIndex是一个顶点语言输入变量,它保存相对于基址的实例化绘制调用中当前图元的实例编号。它仅在以 Vulkan 为目标时存在。如果当前图元不是来自实例化绘制调用,则 gl_InstanceIndex 的值为零。

变量gl_DrawID是一个顶点着色器输入变量,它保存当前顶点所属的绘图命令的整数索引(请参阅OpenGL 规范的第 11.1.3.9 节中的“着色器输入”)。如果该顶点不是由 Multi* 形式的绘制命令调用的,则 gl_DrawID 的值为零。

变量gl_BaseVertex是一个顶点着色器输入变量,它保存传递给导致当前着色器调用的命令的 baseVertex 参数的整数值(请参阅OpenGL 规范的第 11.1.3.9 节中的“着色器输入”)。

变量 gl_BaseInstance 是一个顶点着色器输入变量,它保存传递给命令的 baseInstance 参数的整数值,该命令导致了当前着色器调用(请参阅OpenGL 规范的 11.1.3.9 节中的“着色器输入”)。

细分控制着色器特殊变量

在细分控制着色器中,内置变量被内在声明为

in gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
} gl_in[gl_MaxPatchVertices];

in int gl_PatchVerticesIn;
in int gl_PrimitiveID;
in int gl_InvocationID;

out gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
} gl_out[];

patch out float gl_TessLevelOuter[4];
patch out float gl_TessLevelInner[2];

细分控制输入变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 包含在前一个着色器阶段写入到相应输出的值。

gl_PatchVerticesIn 包含着色器正在处理的输入面片中的顶点数。单个着色器可以读取不同大小的面片,因此 gl_PatchVerticesIn 的值在不同面片之间可能会有所不同。

gl_PrimitiveID 包含自当前渲染图元集开始以来着色器处理的图元数量。

gl_InvocationID 包含分配给细分控制着色器调用的输出面片顶点的数量。它被分配了 [0, N-1] 范围内的整数值,其中 N 是每个图元的输出面片顶点数。

细分控制输出变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 的使用方式与顶点着色器中的相应输出变量相同。

写入到 gl_TessLevelOutergl_TessLevelInner 的值被分配给输出面片的相应外部和内部细分级别。细分图元生成器使用它们来控制图元细分,并且细分评估着色器可以读取它们。

细分评估着色器特殊变量

在细分评估着色器中,内置变量被内在声明为

in gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
} gl_in[gl_MaxPatchVertices];

in int gl_PatchVerticesIn;
in int gl_PrimitiveID;
in vec3 gl_TessCoord;
patch in float gl_TessLevelOuter[4];
patch in float gl_TessLevelInner[2];

out gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
};

细分评估输入变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 包含在前一个着色器阶段写入到相应输出的值。

gl_PatchVerticesIngl_PrimitiveID 的定义方式与细分控制着色器中的相应输入变量相同。

gl_TessCoord 指定一个三组件 (u,v,w) 向量,该向量标识着色器正在处理的顶点相对于正在细分的图元的位置。它的值将遵循以下属性

gl_TessCoord.x == 1.0 - (1.0 - gl_TessCoord.x) // two operations performed
gl_TessCoord.y == 1.0 - (1.0 - gl_TessCoord.y) // two operations performed
gl_TessCoord.z == 1.0 - (1.0 - gl_TessCoord.z) // two operations performed

以帮助复制细分计算。

如果细分控制着色器处于活动状态,则输入变量 gl_TessLevelOutergl_TessLevelInner 将填充细分控制着色器写入的相应输出。否则,它们将被分配在 OpenGL 规范的 11.2.3.3 节“细分评估着色器输入”中指定的默认细分级别。

细分评估输出变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 的使用方式与顶点着色器中的相应输出变量相同。

几何着色器特殊变量

在几何着色器中,内置变量被内在声明为

in gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
} gl_in[];

in int gl_PrimitiveIDIn;
in int gl_InvocationID;

out gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
    float gl_CullDistance[];
};

out int gl_PrimitiveID;
out int gl_Layer;
out int gl_ViewportIndex;

几何着色器输入变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 包含在前一个着色器阶段写入到相应输出的值。

gl_PrimitiveIDIn 包含自当前渲染图元集开始以来着色器处理的图元数量。

gl_InvocationID 包含分配给几何着色器调用的调用编号。它被分配了 [0, N-1] 范围内的整数值,其中 N 是每个图元的几何着色器调用数。

几何着色器输出变量

gl_Positiongl_PointSizegl_ClipDistancegl_CullDistance 的使用方式与顶点着色器中的相应输出变量相同。

gl_PrimitiveID 填充一个整数,作为片段着色器的图元标识符。然后片段着色器可以使用它,它将从正在着色的图元的引发顶点中选择写入的图元 ID。如果使用 gl_PrimitiveID 的片段着色器处于活动状态,并且几何着色器也处于活动状态,则几何着色器必须写入 gl_PrimitiveID,否则片段着色器输入 gl_PrimitiveID 未定义。有关详细信息,请参阅OpenGL 规范的 11.3.4.5 节“几何着色器输出”。

gl_Layer 用于选择多层帧缓冲附件的特定层(或立方体贴图的面和层)。实际使用的层将来自正在着色的图元中的一个顶点。层的来源顶点如 OpenGL 规范的 11.3.4.6 节“层和视口选择”中所述确定,但可能未定义,因此最好为图元的所有顶点写入相同的层值。如果着色器静态地为 gl_Layer 分配一个值,则会启用分层渲染模式。有关详细信息,请参阅 OpenGL 规范的 11.3.4.5 节“几何着色器输出”和 9.4.9 节“分层帧缓冲”。如果着色器静态地为 gl_Layer 分配一个值,并且着色器中存在一个不设置 gl_Layer 的执行路径,则对于执行该路径的着色器,gl_Layer 的值未定义。

当与立方体贴图纹理数组一起使用时,输出变量 gl_Layer 会采用特殊值。它不仅引用层,还用于选择立方体贴图的面和层。将 gl_Layer 设置为值 layer*6+face 将渲染到层 layer 中定义的立方体的面 face。面值在OpenGL 规范的 9.4.9 节“分层帧缓冲”的表 9.3 中定义,但为了清晰起见,在下面重复。

面值 生成的 目标

0

TEXTURE_CUBE_MAP_POSITIVE_X

1

TEXTURE_CUBE_MAP_NEGATIVE_X

2

TEXTURE_CUBE_MAP_POSITIVE_Y

3

TEXTURE_CUBE_MAP_NEGATIVE_Y

4

TEXTURE_CUBE_MAP_POSITIVE_Z

5

TEXTURE_CUBE_MAP_NEGATIVE_Z

例如,要渲染到立方体贴图数组的第 5 层中的正 y 立方体贴图面,gl_Layer 应设置为 5 * 6 + 2

输出变量 gl_ViewportIndex 提供几何着色器发出的下一个图元应绘制到的视口的索引。几何着色器生成的图元将使用 gl_ViewportIndex 的值选择的视口变换和剪裁矩形进行视口变换和剪裁测试。使用的视口索引将来自正在着色的图元中的一个顶点。但是,视口索引来自哪个顶点是与实现相关的,因此最好对图元的所有顶点使用相同的视口索引。如果几何着色器未为 gl_ViewportIndex 分配值,则将使用视口变换和剪裁矩形零。如果几何着色器静态地为 gl_ViewportIndex 分配一个值,并且着色器中存在一个不为 gl_ViewportIndex 分配值的路径,则对于执行该路径的着色器,gl_ViewportIndex 的值未定义。有关详细信息,请参阅OpenGL 规范的 11.3.4.6 节“层和视口选择”。

片段着色器特殊变量

可以从片段着色器访问的内置特殊变量内在声明如下

in vec4 gl_FragCoord;
in bool gl_FrontFacing;
in float gl_ClipDistance[];
in float gl_CullDistance[];
in vec2 gl_PointCoord;
in int gl_PrimitiveID;
in int gl_SampleID;
in vec2 gl_SamplePosition;
in int gl_SampleMaskIn[];
in int gl_Layer;
in int gl_ViewportIndex;
in bool gl_HelperInvocation;

out float gl_FragDepth;
out int gl_SampleMask[];

片段着色器可执行文件的输出由 API 管道后端的固定功能操作处理。

可以通过读取下面描述的 gl_FragCoord.z 来获得片段的固定功能计算深度。

写入 gl_FragDepth 将为正在处理的片段建立深度值。如果启用了深度缓冲,并且没有着色器写入 gl_FragDepth,则固定功能深度值将用作片段的深度值。如果着色器静态地为 gl_FragDepth 分配一个值,并且着色器中存在一个不设置 gl_FragDepth 的执行路径,则对于执行该路径的着色器,片段的深度值可能未定义。也就是说,如果链接的片段着色器集静态地包含对 gl_FragDepth 的写入,则它负责始终写入它。

如果着色器执行 discard 关键字,则该片段将被丢弃,并且任何用户定义的片段输出、gl_FragDepthgl_SampleMask 的值都变得无关紧要。

变量 gl_FragCoord 在片段着色器中作为输入变量可用,它保存片段的窗口相对坐标 (x, y, z, 1/w) 值。如果启用多重采样,此值可以是像素内的任何位置,或其中一个片段样本的位置。使用 centroid 不会将此值进一步限制在当前图元内部。此值是固定功能的结果,该固定功能在顶点处理后插值图元以生成片段。z 分量是片段深度将使用的深度值,前提是没有着色器写入 gl_FragDepth。如果着色器有条件地计算 gl_FragDepth,但其他情况下需要固定功能的片段深度,则此值对于保持不变性非常有用。

片段着色器可以访问内置输入变量 gl_FrontFacing,如果片段属于正面朝向的图元,则其值为 true。一个用途是通过选择顶点或几何着色器计算的两种颜色之一来模拟双面光照。

当启用点精灵时,gl_PointCoord 中的值是二维坐标,指示当前片段在点图元内的位置。它们在整个点上从 0.0 到 1.0 变化。如果当前图元不是点,或者未启用点精灵,则从 gl_PointCoord 读取的值未定义。

对于输入数组 gl_SampleMaskIn[] 和输出数组 gl_SampleMask[],掩码 M 的位 B (gl_SampleMaskIn[M]gl_SampleMask[M]) 对应于样本 32*M+B。这些数组有 ceil(s/32) 个元素,其中 s 是实现支持的最大颜色样本数。

输入变量 gl_SampleMaskIn 指示在多重采样光栅化期间,生成片段的图元覆盖的样本集。当且仅当样本被认为为此片段着色器调用覆盖时,它才会设置样本位。

输出数组 gl_SampleMask[] 设置正在处理的片段的样本掩码。当前片段的覆盖将成为覆盖掩码和输出 gl_SampleMask 的逻辑与。此数组必须在片段着色器中隐式或显式地调整大小,使其不大于实现相关的最大样本掩码(作为 32 位元素的数组),该掩码由最大样本数确定。如果片段着色器静态地为 gl_SampleMask 赋值,则对于任何未能赋值的片段着色器调用的任何数组元素,样本掩码将未定义。如果着色器未静态地为 gl_SampleMask 赋值,则样本掩码对片段的处理没有影响。

输入变量 gl_SampleID 填充了当前正在处理的样本的样本号。此变量的范围为 0gl_NumSamples-1,其中 gl_NumSamples 是帧缓冲区中的样本总数,如果渲染到非多重采样帧缓冲区,则为 1。在片段着色器中静态使用此变量会导致整个着色器按每个样本进行评估。

输入变量 gl_SamplePosition 包含当前样本在多重采样绘制缓冲区中的位置。gl_SamplePositionxy 分量包含当前样本的子像素坐标,其值将在 0.0 到 1.0 的范围内。在片段着色器中静态使用此变量会导致整个着色器按每个样本进行评估。

如果片段着色器调用被视为辅助调用,则值 gl_HelperInvocationtrue,否则为 false。辅助调用是仅为了评估导数以用于非辅助片段着色器调用而创建的片段着色器调用。此类导数在内置函数 texture() 中隐式计算(请参阅“纹理函数”),并在“导数函数”中的导数函数(例如 dFdx() 和 dFdy())中显式计算。

片段着色器辅助调用执行与非辅助调用相同的着色器代码,但不会产生修改帧缓冲区或其他着色器可访问内存的副作用。特别是

  • 当着色器执行完成时,对应于辅助调用的片段会被丢弃,而不会更新帧缓冲区。

  • 辅助调用执行的对图像和缓冲区变量的存储对底层图像或缓冲区内存没有影响。

  • 辅助调用执行的对图像、缓冲区或原子计数器变量的原子操作对底层图像或缓冲区内存没有影响。此类原子操作返回的值未定义。

可能会为未被正在渲染的图元覆盖的像素生成辅助调用。虽然通常要求用 centroid 修饰的片段着色器输入在像素和图元的交点处进行采样,但对于此类像素,此要求将被忽略,因为像素和图元之间没有交点。

当片段被早期片段测试(使用 early_fragment_tests 限定符)杀死,或者当实现能够确定执行片段着色器除了协助计算其他片段着色器调用的导数之外不会产生任何影响时,也可能会为被正在渲染的图元覆盖的片段生成辅助调用。

在处理任何图元集时生成的辅助调用集是实现相关的。

gl_ClipDistance 包含着色器写入 gl_ClipDistance 输出变量的顶点管道值的线性插值。此数组中只有启用了裁剪的元素才有定义的值。

gl_CullDistance 包含着色器写入 gl_CullDistance 输出变量的顶点管道值的线性插值。

如果存在几何着色器,则输入变量 gl_PrimitiveID 填充写入 gl_PrimitiveID 几何着色器输出的值。否则,它将填充自当前渲染图元集开始以来着色器处理的图元数。

如果存在几何着色器,则输入变量 gl_Layer 填充写入 gl_Layer 几何着色器输出的值。如果几何阶段未动态地为 gl_Layer 赋值,则片段阶段中 gl_Layer 的值将未定义。如果几何阶段未对 gl_Layer 进行任何静态赋值,则片段阶段中的输入值将为零。否则,片段阶段将读取几何阶段写入的相同值,即使该值超出范围。如果片段着色器包含对 gl_Layer 的静态访问,则它将计入片段阶段的最大输入数量的实现定义的限制。

如果存在几何着色器,则输入变量 gl_ViewportIndex 将填充在几何阶段写入到输出变量 gl_ViewportIndex 的值。如果几何阶段没有动态地为 gl_ViewportIndex 赋值,则片段着色器中 gl_ViewportIndex 的值将是未定义的。如果几何阶段没有对 gl_ViewportIndex 进行静态赋值,则片段阶段将读取零。否则,即使该值超出范围,片段阶段也将读取由几何阶段写入的相同值。如果片段着色器包含对 gl_ViewportIndex 的静态访问,它将被计入片段阶段输入的最大数量的实现定义限制中。

计算着色器特殊变量

在计算着色器中,内置变量声明如下:

// workgroup dimensions
in uvec3 gl_NumWorkGroups;
const uvec3 gl_WorkGroupSize;

// workgroup and invocation IDs
in uvec3 gl_WorkGroupID;
in uvec3 gl_LocalInvocationID;

// derived variables
in uvec3 gl_GlobalInvocationID;
in uint gl_LocalInvocationIndex;

内置变量 gl_NumWorkGroups 是一个计算着色器输入变量,包含执行计算着色器的调度中每个维度的工作组数量。它的内容等于传递给 DispatchCompute API入口点的 num_groups_xnum_groups_ynum_groups_z 参数中指定的值。

内置常量 gl_WorkGroupSize 是一个计算着色器常量,包含着色器的工作组大小。工作组在 XYZ 维度的大小分别存储在 xyz 分量中。gl_WorkGroupSize 中的常量值将与当前着色器所需的 local_size_xlocal_size_ylocal_size_z 布局限定符中指定的值匹配。这是一个常量,因此可以用于调整可在工作组内共享的内存数组的大小。在未声明固定工作组大小的着色器中,或在该着色器使用 local_size_xlocal_size_ylocal_size_z 声明固定工作组大小之前使用 gl_WorkGroupSize 是编译时错误。但是,使用其值派生自 gl_WorkGroupSize 的变量不受固定工作组大小声明的约束。

内置变量 gl_WorkGroupID 是一个计算着色器输入变量,包含当前调用正在执行的工作组的三维索引。可能的值范围涵盖传递给 DispatchCompute 的参数,即从 (0, 0, 0) 到 (gl_NumWorkGroups.x - 1, gl_NumWorkGroups.y - 1, gl_NumWorkGroups.z - 1)。

内置变量 gl_LocalInvocationID 是一个计算着色器输入变量,包含当前工作项在工作组内的三维索引。此变量的可能值范围涵盖工作组大小,即从 (0, 0, 0) 到 (gl_WorkGroupSize.x - 1, gl_WorkGroupSize.y - 1, gl_WorkGroupSize.z - 1)。允许在声明 local_size_xlocal_size_ylocal_size_z 之前使用 gl_LocalInvocationID

内置变量 gl_GlobalInvocationID 是一个计算着色器输入变量,包含当前工作项的全局索引。该值唯一标识了当前 DispatchCompute 调用所启动的所有工作组中所有其他调用中的此调用。它计算为:

gl_GlobalInvocationID =
    gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID;

内置变量 gl_LocalInvocationIndex 是一个计算着色器输入变量,其中包含 gl_LocalInvocationID 的一维表示。它计算为:

gl_LocalInvocationIndex =
    gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
    gl_LocalInvocationID.y * gl_WorkGroupSize.x +
    gl_LocalInvocationID.x;

允许在声明 local_size_xlocal_size_ylocal_size_z 之前使用 gl_LocalInvocationIndex

兼容性配置文件内置语言变量

使用兼容性配置文件时,GL 可以为顶点和片段可编程管线阶段提供固定的功能行为。例如,将固定功能顶点阶段与可编程片段阶段混合使用。

以下内置的顶点、细分控制、细分评估和几何输出变量可用于指定后续可编程着色器阶段或固定功能片段阶段的输入。如果相应的片段着色器或固定管线中的任何功能使用它或从中派生的状态,则应写入特定的一个。否则,行为未定义。以下成员被添加到这些语言的输出 gl_PerVertex 块中:

out gl_PerVertex { // part of the gl_PerVertex block described in 7.1
    // in addition to other gl_PerVertex members...
    vec4  gl_ClipVertex;
    vec4  gl_FrontColor;
    vec4  gl_BackColor;
    vec4  gl_FrontSecondaryColor;
    vec4  gl_BackSecondaryColor;
    vec4  gl_TexCoord[];
    float gl_FogFragCoord;
};

输出变量 gl_ClipVertex 为顶点和几何着色器提供了一个写入坐标的位置,该坐标将用于用户裁剪半空间。写入 gl_ClipDistance 是用户裁剪的首选方法。对于构成程序的着色器集,静态读取或写入 gl_ClipVertexgl_ClipDistancegl_CullDistance 之一是编译时或链接时错误。如果既不写入 gl_ClipVertex 也不写入 gl_ClipDistance,则它们的值是未定义的,并且针对用户剪辑半空间的任何剪辑也是未定义的。

与先前为核心配置文件描述的类似,可以在着色器中重新声明 gl_PerVertex 块以显式包含这些附加成员。例如:

out gl_PerVertex {
    vec4 gl_Position;    // will use gl_Position
    vec4 gl_FrontColor;  // will consume gl_color in the fragment shader
    vec4 gl_BackColor;
    vec4 gl_TexCoord[3]; // 3 elements of gl_TexCoord will be used
}; // no other aspects of the fixed interface will be used

用户必须确保剪辑顶点和用户裁剪半空间在同一坐标空间中定义。

输出变量 gl_FrontColorglFrontSecondaryColorgl_BackColorglBackSecondaryColor 为正在处理的顶点的基元的正面和背面分配主要和辅助颜色。输出变量 gl_TexCoord 为正在处理的顶点分配纹理坐标。

对于 gl_FogFragCoord,写入的值将用作 OpenGL 规范的兼容性配置文件的第 16.4 节“雾”中的“c”值,由固定功能管线使用。例如,如果希望将片段在眼睛空间中的 z 坐标作为“c”,那么顶点着色器可执行文件应将其写入 gl_FogFragCoord

与所有数组一样,用于下标 gl_TexCoord 的索引必须是常量整数表达式,否则必须由着色器重新声明此数组的大小。该大小最大可以是 gl_MaxTextureCoords。使用接近 0 的索引可能有助于实现保留可变资源。gl_TexCoord 的重新声明也可以在全局范围内完成,例如:

in vec4 gl_TexCoord[3];
out vec4 gl_TexCoord[4];

(这是对 gl_TexCoord[] 的特殊处理,而不是重新声明块成员的通用方法。)如果在全局范围内重新声明了相应的内置块,则重新声明 gl_TexCoord[] 是编译时错误;只允许在着色器内(因此在阶段内,因为块重新声明必须在所有使用它的着色器中匹配)使用一种重新声明形式。

在细分控制、评估和几何着色器中,上述先前阶段的输出也可以在这些语言的输入 gl_PerVertex 块中使用。

in gl_PerVertex { // part of the gl_PerVertex block described in 7.1
    // in addition to other gl_PerVertex members...
    vec4  gl_ClipVertex;
    vec4  gl_FrontColor;
    vec4  gl_BackColor;
    vec4  gl_FrontSecondaryColor;
    vec4  gl_BackSecondaryColor;
    vec4  gl_TexCoord[];
    float gl_FogFragCoord;
} gl_in[];

可以重新声明这些内容以建立显式管线接口,其方式与上面为输出块 gl_PerVertex 描述的相同,并且输入重新声明必须与先前阶段的输出重新声明匹配。但是,当重新声明带有实例名称的内置接口块(例如,gl_in)时,必须在重新声明中包含实例名称。不包含内置实例名称或更改其名称是编译时错误。例如:

in gl_PerVertex {
    vec4 gl_ClipVertex;
    vec4 gl_FrontColor;
} gl_in[]; // must be present and must be "gl_in[]"

可以使用无大小的语法重新声明预先声明大小的内置块数组。这使其大小等于原始预先声明的大小。

gl_TexCoord[] 重新声明的处理也与为输出块 gl_TexCoord[] 重新声明描述的相同。

当使用兼容性配置文件时,以下片段输入块也可以在片段着色器中使用:

in gl_PerFragment {
    in float gl_FogFragCoord;
    in vec4  gl_TexCoord[];
    in vec4  gl_Color;
    in vec4  gl_SecondaryColor;
};

gl_Colorgl_SecondaryColor 中的值将由系统根据 gl_FrontColorgl_BackColorgl_FrontSecondaryColorgl_BackSecondaryColor 自动推导得出,具体取决于在生成片段的图元中哪个面是可见的。如果顶点处理使用固定功能,那么 gl_FogFragCoord 将是片段在眼睛坐标系中的 z 坐标,或者是由雾坐标插值得到的,如 OpenGL 规范兼容性配置文件的第 16.4 节“雾”中所述。gl_TexCoord[] 值是来自顶点着色器的插值 gl_TexCoord[] 值,或是任何基于固定管线的顶点功能的纹理坐标。

片段着色器 gl_TexCoord 数组的索引如上述顶点着色器文本中所述。

如上文针对输入和输出 gl_PerVertex 块所述,可以重新声明 gl_PerFragment 块,以创建与另一个程序的显式接口。当在单独的程序之间匹配这些接口时,只有当由它们生成的相应片段着色器成员存在于 gl_PerFragment 输入块中时,才必须声明 gl_PerVertex 输出块中的成员。这些匹配的详细信息在 OpenGL 规范 的 7.4.1 节“着色器接口匹配”中描述。如果它们在程序中不匹配,将导致链接时错误。如果两个程序之间不匹配,则在程序之间传递的值是未定义的。与所有其他块匹配不同,gl_PerFragment 中的声明顺序不必跨着色器匹配,也不必与匹配的 gl_PerVertex 重新声明中的声明顺序一致。

以下片段输出变量在使用兼容性配置文件时在片段着色器中可用。

out vec4 gl_FragColor;
out vec4 gl_FragData[gl_MaxDrawBuffers];

写入 gl_FragColor 指定后续固定功能管线将使用的片段颜色。如果后续固定功能消耗片段颜色,并且片段着色器可执行文件的执行没有向 gl_FragColor 写入值,则消耗的片段颜色是未定义的。

变量 gl_FragData 是一个数组。写入 gl_FragData[n] 指定后续固定功能管线将用于数据 *n* 的片段数据。如果后续固定功能消耗片段数据,并且片段着色器可执行文件的执行没有向其写入值,则消耗的片段数据是未定义的。

如果着色器静态地将值赋给 gl_FragColor,则它不能将值赋给 gl_FragData 的任何元素。如果着色器静态地向 gl_FragData 的任何元素写入值,则它不能将值赋给 gl_FragColor。也就是说,着色器可以将值赋给 gl_FragColorgl_FragData,但不能同时赋值。链接在一起的多个着色器也必须始终如一地只写入这些变量中的一个。类似地,如果正在使用用户声明的输出变量(静态赋值),则不能赋值给内置变量 gl_FragColorgl_FragData。这些不正确的用法都会生成编译时或链接时错误。

如果着色器执行 discard 关键字,则会丢弃片段,并且 gl_FragDepthgl_FragColor 的值将变得无关紧要。

兼容性配置文件顶点着色器内置输入

以下预声明的输入名称可以在顶点着色器中使用,以访问在使用兼容性配置文件时 OpenGL 状态的当前值。

in vec4 gl_Color;
in vec4 gl_SecondaryColor;
in vec3 gl_Normal;
in vec4 gl_Vertex;
in vec4 gl_MultiTexCoord0;
in vec4 gl_MultiTexCoord1;
in vec4 gl_MultiTexCoord2;
in vec4 gl_MultiTexCoord3;
in vec4 gl_MultiTexCoord4;
in vec4 gl_MultiTexCoord5;
in vec4 gl_MultiTexCoord6;
in vec4 gl_MultiTexCoord7;
in float gl_FogCoord;

内置常量

以下内置常量在所有着色器中声明。使用的实际值取决于实现,但必须至少为所示的值。

//
// Implementation-dependent constants. The example values below
// are the minimum values allowed for these maximums.
//
const int gl_MaxVertexAttribs = 16;
const int gl_MaxVertexUniformVectors = 256;
const int gl_MaxVertexUniformComponents = 1024;
const int gl_MaxVertexOutputComponents = 64;
const int gl_MaxVaryingComponents = 60;
const int gl_MaxVaryingVectors = 15;
const int gl_MaxVertexTextureImageUnits = 16;
const int gl_MaxVertexImageUniforms = 0;
const int gl_MaxVertexAtomicCounters = 0;
const int gl_MaxVertexAtomicCounterBuffers = 0;

const int gl_MaxTessPatchComponents = 120;
const int gl_MaxPatchVertices = 32;
const int gl_MaxTessGenLevel = 64;

const int gl_MaxTessControlInputComponents = 128;
const int gl_MaxTessControlOutputComponents = 128;
const int gl_MaxTessControlTextureImageUnits = 16;
const int gl_MaxTessControlUniformComponents = 1024;
const int gl_MaxTessControlTotalOutputComponents = 4096;
const int gl_MaxTessControlImageUniforms = 0;
const int gl_MaxTessControlAtomicCounters = 0;
const int gl_MaxTessControlAtomicCounterBuffers = 0;

const int gl_MaxTessEvaluationInputComponents = 128;
const int gl_MaxTessEvaluationOutputComponents = 128;
const int gl_MaxTessEvaluationTextureImageUnits = 16;
const int gl_MaxTessEvaluationUniformComponents = 1024;
const int gl_MaxTessEvaluationImageUniforms = 0;
const int gl_MaxTessEvaluationAtomicCounters = 0;
const int gl_MaxTessEvaluationAtomicCounterBuffers = 0;

const int gl_MaxGeometryInputComponents = 64;
const int gl_MaxGeometryOutputComponents = 128;
const int gl_MaxGeometryImageUniforms = 0;
const int gl_MaxGeometryTextureImageUnits = 16;
const int gl_MaxGeometryOutputVertices = 256;
const int gl_MaxGeometryTotalOutputComponents = 1024;
const int gl_MaxGeometryUniformComponents = 1024;
const int gl_MaxGeometryVaryingComponents = 64;            // deprecated
const int gl_MaxGeometryAtomicCounters = 0;
const int gl_MaxGeometryAtomicCounterBuffers = 0;

const int gl_MaxFragmentImageUniforms = 8;
const int gl_MaxFragmentInputComponents = 128;
const int gl_MaxFragmentUniformVectors = 256;
const int gl_MaxFragmentUniformComponents = 1024;
const int gl_MaxFragmentAtomicCounters = 8;
const int gl_MaxFragmentAtomicCounterBuffers = 1;

const int gl_MaxDrawBuffers = 8;
const int gl_MaxTextureImageUnits = 16;
const int gl_MinProgramTexelOffset = -8;
const int gl_MaxProgramTexelOffset = 7;
const int gl_MaxImageUnits = 8;
const int gl_MaxSamples = 4;
const int gl_MaxImageSamples = 0;
const int gl_MaxClipDistances = 8;
const int gl_MaxCullDistances = 8;
const int gl_MaxViewports = 16;

const int gl_MaxComputeImageUniforms = 8;
const ivec3 gl_MaxComputeWorkGroupCount = { 65535, 65535, 65535 };
const ivec3 gl_MaxComputeWorkGroupSize = { 1024, 1024, 64 };
const int gl_MaxComputeUniformComponents = 1024;
const int gl_MaxComputeTextureImageUnits = 16;
const int gl_MaxComputeAtomicCounters = 8;
const int gl_MaxComputeAtomicCounterBuffers = 8;

const int gl_MaxCombinedTextureImageUnits = 96;
const int gl_MaxCombinedImageUniforms = 48;
const int gl_MaxCombinedImageUnitsAndFragmentOutputs = 8;  // deprecated
const int gl_MaxCombinedShaderOutputResources = 16;
const int gl_MaxCombinedAtomicCounters = 8;
const int gl_MaxCombinedAtomicCounterBuffers = 1;
const int gl_MaxCombinedClipAndCullDistances = 8;
const int gl_MaxAtomicCounterBindings = 1;
const int gl_MaxAtomicCounterBufferSize = 32;

const int gl_MaxTransformFeedbackBuffers = 4;
const int gl_MaxTransformFeedbackInterleavedComponents = 64;

const highp int gl_MaxInputAttachments = 1;  // only present when targeting Vulkan

常量 gl_MaxVaryingFloats 在核心配置文件中被移除,请改用 gl_MaxVaryingComponents

兼容性配置文件内置常量

const int gl_MaxTextureUnits = 2;
const int gl_MaxTextureCoords = 8;
const int gl_MaxClipPlanes = 8;
const int gl_MaxVaryingFloats = 60;

内置统一状态

生成 SPIR-V 时,内置统一状态不可用。否则,作为访问 OpenGL 处理状态的辅助手段,以下统一变量将构建到 OpenGL 着色语言中。

//
// Depth range in window coordinates,
// section 13.6.1 "Controlling the Viewport" in the
// OpenGL Specification.
//
// Note: Depth-range state is only for viewport 0.
//
struct gl_DepthRangeParameters {
    float near; // n
    float far;  // f
    float diff; // f - n
};
uniform gl_DepthRangeParameters gl_DepthRange;
uniform int gl_NumSamples;

这些变量仅保证在片段阶段可用。在其他阶段,它们的存在和功能是实现定义的。

兼容性配置文件状态

这些变量仅存在于兼容性配置文件中。它们不适用于计算着色器,但适用于所有其他着色器。

//
// compatibility profile only
//
uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix;
uniform mat4 gl_ModelViewProjectionMatrix;
uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];

//
// compatibility profile only
//
uniform mat3 gl_NormalMatrix; // transpose of the inverse of the
                              // upper leftmost 3x3 of gl_ModelViewMatrix

uniform mat4 gl_ModelViewMatrixInverse;
uniform mat4 gl_ProjectionMatrixInverse;
uniform mat4 gl_ModelViewProjectionMatrixInverse;
uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords];

uniform mat4 gl_ModelViewMatrixTranspose;
uniform mat4 gl_ProjectionMatrixTranspose;
uniform mat4 gl_ModelViewProjectionMatrixTranspose;
uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords];

uniform mat4 gl_ModelViewMatrixInverseTranspose;
uniform mat4 gl_ProjectionMatrixInverseTranspose;
uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose;
uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];

//
// compatibility profile only
//
uniform float gl_NormalScale;

//
// compatibility profile only
//
uniform vec4 gl_ClipPlane[gl_MaxClipPlanes];

//
// compatibility profile only
//
struct gl_PointParameters {
    float size;
    float sizeMin;
    float sizeMax;
    float fadeThresholdSize;
    float distanceConstantAttenuation;
    float distanceLinearAttenuation;
    float distanceQuadraticAttenuation;
};

uniform gl_PointParameters gl_Point;

//
// compatibility profile only
//
struct gl_MaterialParameters {
 vec4 emission;   // Ecm
 vec4 ambient;    // Acm
 vec4 diffuse;    // Dcm
 vec4 specular;   // Scm
 float shininess; // Srm
};
uniform gl_MaterialParameters gl_FrontMaterial;
uniform gl_MaterialParameters gl_BackMaterial;

//
// compatibility profile only
//
struct gl_LightSourceParameters {
    vec4 ambient;               // Acli
    vec4 diffuse;               // Dcli
    vec4 specular;              // Scli
    vec4 position;              // Ppli
    vec4 halfVector;            // Derived: Hi
    vec3 spotDirection;         // Sdli
    float spotExponent;         // Srli
    float spotCutoff;           // Crli
                                // (range: [0.0,90.0], 180.0)
    float spotCosCutoff;        // Derived: cos(Crli)
                                // (range: [1.0,0.0],-1.0)
    float constantAttenuation;  // K0
    float linearAttenuation;    // K1
    float quadraticAttenuation; // K2
};

uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];

struct gl_LightModelParameters {
    vec4 ambient;                  // Acs
};

uniform gl_LightModelParameters gl_LightModel;

//
// compatibility profile only
//
// Derived state from products of light and material.
//

struct gl_LightModelProducts {
    vec4 sceneColor; // Derived. Ecm + Acm * Acs
};

uniform gl_LightModelProducts gl_FrontLightModelProduct;
uniform gl_LightModelProducts gl_BackLightModelProduct;

struct gl_LightProducts {
    vec4 ambient; // Acm * Acli
    vec4 diffuse; // Dcm * Dcli
    vec4 specular; // Scm * Scli
};

uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];
uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];

//
// compatibility profile only
//
uniform vec4 gl_TextureEnvColor[gl_MaxTextureUnits];
uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords];
uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords];
uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords];
uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords];
uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords];
uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords];
uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords];
uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords];

//
// compatibility profile only
//
struct gl_FogParameters {
    vec4 color;
    float density;
    float start;
    float end;
    float scale; // Derived: 1.0 / (end - start)
};

uniform gl_FogParameters gl_Fog;

重新声明内置块

可以在着色器中重新声明 gl_PerVertex 块,以显式指示将使用固定管线接口的哪个子集。这对于在多个程序之间建立接口是必要的。例如

out gl_PerVertex {
    vec4 gl_Position;   // will use gl_Position
    float gl_PointSize; // will use gl_PointSize
    vec4 t;             // error, only gl_PerVertex members allowed
}; // no other members of gl_PerVertex will be used

这建立了着色器将与后续管线阶段使用的输出接口。它必须是 gl_PerVertex 的内置成员的子集。这样的重新声明还可以添加 invariant 限定符、插值限定符和布局限定符 xfb_offsetxfb_bufferxfb_stride。它还可以为无大小数组添加数组大小。例如

out layout(xfb_buffer = 1, xfb_stride = 16) gl_PerVertex {
    vec4 gl_Position;
    layout(xfb_offset = 0) float gl_ClipDistance[4];
};

除非另有明确说明,否则其他布局限定符(如 location)不能添加到这样的重新声明中。

如果重新声明了内置接口块,则它必须出现在着色器中,然后才能使用任何包含在内置声明中的成员,否则将导致编译时错误。多次重新声明块或重新声明内置块,然后使用该内置块中未包含在重新声明中的成员也是编译时错误。此外,如果重新声明了内置接口块,则不能在块重新声明之外重新声明内置声明的任何成员。如果使用属于同一接口的内置块的成员的多个着色器在同一程序中链接在一起,则它们必须以相同的方式重新声明内置块,如“接口块”中所述,以进行接口块匹配,否则将导致链接时错误。如果程序中的某些着色器重新声明了特定的内置接口块,而该程序中的另一个着色器没有重新声明该接口块但仍使用了该接口块的成员,则也会导致链接时错误。如果跨不同程序的着色器形成内置块接口,则着色器必须全部以相同的方式重新声明内置块(如单个程序中所述),否则沿接口传递的值是未定义的。