拖拽自助建站系统源码,个人网站建立内容,郑州seo网站管理,中企动力做的电梯网站GLSL 着色器语言 1. 着色器语言基础1.1 数据类型1.2 数据类型的基本使用1.3 运算符1.4 各个数据类型的构造函数1.5 类型转换1.6 存储限定符1.7 插值限定符1.8 一致块1.9 layout 限定符1.10 流程控制1.11 函数的声明和使用1.12 片元着色器中浮点及整型变量精度的指定1.13 程序的… GLSL 着色器语言 1. 着色器语言基础1.1 数据类型1.2 数据类型的基本使用1.3 运算符1.4 各个数据类型的构造函数1.5 类型转换1.6 存储限定符1.7 插值限定符1.8 一致块1.9 layout 限定符1.10 流程控制1.11 函数的声明和使用1.12 片元着色器中浮点及整型变量精度的指定1.13 程序的基本结构 2. 内建变量2.1 顶点着色器中的内建变量2.2 片元着色器中的内建变量2.3 内建常量 3. 内置函数3.1 角度转换与三角函数3.2 指数函数3.3 常见函数3.4 几何函数3.5 矩阵函数3.6 向量关系函数3.7 纹理采样函数3.8 微分函数3.9 浮点数打包与解包函数 4. invariant 修饰符避免值变问题5. 预处理器 笔记总结自 《Vulkan 开发实战详解》第三章 GLSL 着色语言是一种易于实现、功能强大、便于使用并且可以高度并行处理、性能优良的高级图形编辑语言。 特性 - 高级的过程语言 - 对顶点着色器、片元着色器、曲面细分着色器、几何着色器以及计算着色器使用相同的语言不做区分 - 基于C/C 的基本语法及流程控制 - 支持向量及矩阵的各种操作 - 通过特定限定符来管理输入与输出 - 拥有大量的内置函数来提供丰富的功能
1. 着色器语言基础
1.1 数据类型
1 标量 标量的值只有大小没有方向。着色器语言支持的标量类型有 bool、int、uint 与 float 。
布尔类型——bool
bool b; // 声明一个布尔类型的值 true/false有符号整型/无符号整型——int/uint
// 着色器语言支持32位精度超出范围会导致溢出问题。
// 一般情况使用有符号整型
// 无符号整型不能用负数来声明int a 15; // 十进制
uint b 3u; // 无符号十进制声明无符号整型字面常量时需要在数字后添加后缀u或 U否则该字面常量的类型为有符号整型。
int c 036; // 八进制
int d 0x3D; // 十六进制浮点类型——float
// 浮点类型可以用十进制形式和指数形式两种方式表示
float f; // 声明float变量
float g 2.0; // 声明变量并赋值
float h, i ; // 声明多个变量
float j, k 2.56, 1; // 声明多个变量并赋值
flaot s 3e2; // 声明变量并赋予指数形式的初值表示3 乘以 10 的平方2 向量 向量可以看作由同样类型的标量组成基本类型也分为 bool、int、uint 及 float。每个向量可以由 2 个、3 个或者 4 个相同的标量组成。
C语言中也可以自定义结构体来支持向量但进行向量运算必须由CPU 将每个分量依次顺序计算效率不高。着色器中的向量由硬件原生支持进行向量的运算时是各分量并行一次完成的n个分量只需要一次计算。
向量在着色器中可以很方便的存储及操作颜色、位置、纹理坐标等不仅包含一个组成部分的量。 vec 包含浮点数的向量 vec2 、vec3、vec4 ivec 包含整数的向量 ivec2、ivec3、ivec4 uvec 包含无符号整数的向量 uvec2、uvec3、uvec4 bvec 包含布尔数的向量 bvec2、bvec3、bvec4 向量的声明
vec2 v2;
ivec3 v3;
uvec3 vu3;
bvec4 v4;将向量看作颜色时可以使用r、g、b、a 等4个分量名分别代表 红、绿、蓝、透明度 4 个颜色通道。
aColor.r 0.6; // 给向量aColor 的红色通道分量赋值
aColor.a 0.8; // 给向量aColor 的透明通道分量赋值将向量看作位置时可以使用x、y、z、w 等4个分量名分别代表x轴、y轴、z轴分量及W值。
aPosition.x 108.5; // 给向量aPosition的x轴分量赋值
aPosition.z 2422; // 给向量aPosition的z轴分量赋值将向量看作纹理坐标时可以使用s、t、p、q 等4个分量名分别代表纹理坐标的不同分量。
aTexColor.s 0.65; // 给向量aTexColor的 s 分量赋值
aTexColor.t 0.82; // 给向量aTexColor的 t 分量赋值访问向量中的各个分量不仅可以采用“.” 加上不同的分量名还可以将向量看作一个数组用数组下表来访问
aColor[0] 0.6; // 给向量aColor 的红色通道分量赋值
aColor[3] 0.8; // 给向量aColor 的透明通道分量赋值3矩阵
矩阵的值为浮点数。3D 场景中的移位、旋转、缩放等变换都是由矩阵的运算来实现的故着色器提供了对矩阵类型的支持。矩阵按尺寸分为 2 × 2 矩阵、2 × 3 矩阵、2 × 4 矩阵、3 × 2 矩阵、3 × 3 矩阵、3 × 4 矩阵、4 × 2 矩阵、4 × 3 矩阵、4 × 4 矩阵。矩阵第一个数字表示矩阵的列数第二个数字表示矩阵的列数。
着色器语言中可以将一个矩阵看作几个列向量组成比如 mat3 可以看作3个 vec3 组成。可以将矩阵作为列向量的数组来访问比如mat4 的 matrix[2] 表示第三列值为 vec4 也可以使用 matrix[[2][[2] 表示第三列向量的第三个分量值为float
mat2 m2; // 声明一个mat2 类型矩阵
mat3 m3; // 声明一个mat3 类型矩阵
mat4 m4; // 声明一个mat4 类型矩阵
mat3×2 m5; // 声明一个 mat3×2 类型的矩阵4采样器 着色器语言中不同于C语言的一种特殊基本数据类型专门用来进行纹理采样的相关操作。 一般情况下一个采样器变量代表一幅或者一套纹理贴图。 采样器变量不能在着色器中进行初始化。 一般情况下采样器变量都用uniform 限定符来修饰从宿主语言如 C接收传递进着色器的值。 采样器变量也可以用作函数的参数但是作为函数时不可以使用out 或 inout 修饰符来修饰。 采样器基本类型 sampler2D 用于浮点型的二维纹理sampler3D 用于浮点类型三维纹理samplerCube 用于访问浮点型的立方贴图纹理samplerCubeShadow 用于访问浮点型的立方阴影纹理smapler2DShaodow 用于访问浮点型的二维阴影纹理sampler2DArray 用于访问浮点型的二维纹理数组sampler2DArrayShadow 用于访问浮点型的二维阴影纹理数组isampler2D 用于访问整型的二维纹理isampler3D 用于访问整型的三维纹理isamplerCube 用于访问整型的立方贴图纹理isampler2DArray 用于访问整型的二维纹理数组usampler2D 用于访问无符号整型的二维纹理usampler3D 用于访问无符号整型的三维纹理usamplerCube 用于访问无符号整型的立方贴图纹理usampler2DArray 用于访问无符号整型的二维纹理数组
5 结构体
类似于C语言的自定义结构体同样使用 struct 关键字进行声明。
struct info { // 声明结构体 infovec3 color; // 颜色成员vec3 position; // 位置成员vec2 textureColor; // 纹理坐标成员
}// 使用结构体
info CubeInfo; // 声明info 类型的变量 CubeInfo6 数组
着色语言支持自定义数组着色器语言只支持一维数组不支持二维数组。
// 方式一 在声明数组的同时指定数组大小
vec3 position[20]; // 声明了一个包含20个 vec3 的数组// 方式二 在声明数组并初始化的同时可以不指定数组的大小
float x[] float[2](1.0, 2.0); // 数组的长度为2
float y[] float[](1.0, 2.0, 3.0); // 数组的长度为37 空类型
空类型使用 void 表示仅用来表明不返回任何值的函数。 如在顶点着色器以及片元着色器中必须存在的 main 函数是一个返回值为空类型的函数。
void main() {// ...
}1.2 数据类型的基本使用
1 声明、作用域及初始化
变量声明及作用域 与 C/C 语言类似可以在任何需要的位置声明变量。作用域与C/C 语言类似分为局部变量与全局变量。
int a, b; // 声明全局变量 a、 b 作用域为整个着色器
vec3 aPosition vec3(1.0, 2.0, 3.3); // 声明全局变量 aPosition 并赋值
void myFunction() { int c 14; // 声明局部变量c 并赋值 作用域为 myFunction 函数内a 4; // 给全局变量a 赋值b a * c; // 给全局变量b 赋值
}变量命名规则 由字母、数字、下划线组成且必须以字母或者下划线开头。系统很多内建变量以“gl_”开头自定义变量不允许使用“gl_” 作为开头建议。取名尽量采用有意义的拼写多个单词组合时第一个字母小写其余采用驼峰命名建议。
// 向量各分量值相同可以简化写法
vec4 vc vec4(0.2);矩阵初始化的技巧 初始化矩阵的各个元素可以i使用字面常量也可以使用变量还可以从其他向量直接获取。初始化时若矩阵只有对角线上有值且相同可以通过给出1个字面常量初始化矩阵。初始化时矩阵M1 的行列数N × N 小于构造器中矩阵 M2 的行列数M × M时N M矩阵 M1 的元素值为 矩阵 M2 左上角 N × N 子阵的元素值。初始化时矩阵 M1 的行列数N × M与构造器中矩阵 M2 的行列数P × Q 不同且 P 和 Q 之间的最大值大于N 和M 之间的最大值时假设 M1 为 mat2 × 3 M2 为 mat 4 × 2矩阵 M1 和左上角 N × N 的元素值为矩阵 M2 左上角 N × N 元素的值矩阵 M1 的其他行的元素值为 0。初始化时矩阵 M1 的行列数N × N大于构造器中矩阵 M2 的行列数M × M时即 N M矩阵M1 左上角 M × M 的元素值为矩阵M2 的元素值矩阵M1 右下角的元素值为 1 矩阵M1 剩余其他的元素值为0。
float a 6.3;
float b 11.4;
float c 12.5;
vec3 va vec3(2.3, 2.5, 3.8);
vec3 vb vec3(a, b, c);
vec3 vc vec3(vb.x, va.y, 14.4);
mat3 ma mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, c); // 通过给出9个字面常量初始化 3 × 3 矩阵
mat3 mb mat3(va, vb, vc); //通过给出3个向量初始化 3 × 3 的矩阵
mat3 mc mat3(va, vb, 1.0, 2.0, 3.0); // 通过给出2个向量和3个字面常量初始化 3 × 3 的矩阵
mat3 md mat3(2.0); // 通过给出 1 个字面常量初始化 3 × 3 的矩阵
mat4×4 me mat4×4(3.0); // 等价于(3.0, 0, 0, 0, 0, 3.0, 0, 0, 0, 0, 3.0, 0, 0, 0, 0, 3.0);
mat3×3 mf mat3×3(me); // 等价于(3.0, 0, 0, 0, 3.0, 0, 0, 0, 3.0);
vec2 vd vec2(a, b);
mat4×2 mg mat4×2(vd, vd, vd, vd);
mat2×3 mh mat2×3(mg); // 等价于 mat2×3(6.3, 11.4, 0.0, 6.3, 11.4, 0.0)
mat4×4 mj mat4×4(mf); // 等价于 mat4×4(3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0 )2 变量初始化的规则
为了防止重复计算着色器中应少用字面长两个而用常量代替如有多个1.0、0.0可以声明常量重复使用。常用初始化方式为变量可以在声明的时候就进行初始化
int a 2, b 3, c;用 const 限定符修饰的变量必须在声明的时候进行初始化
const float k 1.0;全局的输入变量、一致变量以及输出变量在声明的时候一定不能进行初始化
int float angleSpan; // 不可对输入变量进行初始化
uniform int k; // 不可对一致变量进行初始化
out vec3 position; // 不可对输出变量进行初始化1.3 运算符
运算符列表按优先级排列从左到右、从上到下
运算符说明运算符说明()括号分组[]数组下标()函数调用和构造函数结构.用于成员选择与混合 –自增自减前缀 - -自增自减前缀 - ~ !一元运算符* / %乘法、除法、取余 -加法减法 逐位左移和逐位右移 关系运算符 !等于 不等于逐位与^逐位异或|逐位或逐位与^^逻辑异或||逐位或?:选择 - * /赋值运算符% ^ |赋值运算符,按顺序排列
1 索引 用在对数组、向量或者矩阵的操作中获取数组、向量或者矩阵的元素。
float array[10];2 混合选择 运算符“.”进行混合选择操作。
vec4 color vec4(0.7, 0.1, 0.5, 1.0);
vec3 temp color.agb; // 相当于拿到一个向量1.0, 1.0, 0.5 并赋值给temp
vec4 tempL color.aabb; // 相当于拿到一个向量 (1.0, 1.0, 0.5, 0.5) 并赋值给 tempL
vec3 tempL;
tempLL.grb color.aab; // 对向量 tempLL 的三个分量赋值一次混合最多只能列出4个分量名称且一次出西安的各部分的分量名称必须时来自同一名称组各分量的名称在进行混合时可以改变顺序以进行重新排列以赋值表达式中的“” 为界做测成为L 值右侧成为R 值。进行混合时R值可以使用一个向量的各个分量任意地组合以及重复。
3 算数运算符
对标量而言算数运算符与C 语言相同。矩阵运算进行的是线性代数的相关运算。
4 其他运算符
关系运算符只能用在浮点数或整数标量的操作中。 如果想要得到两个向量中的每一个元素比较大小的结果则可调用内置函数 lessThan、lessThanEqual、 greaterThan、greaterThanEqual 实现。等于运算符可以用在任意类型数据的操作中。如果想要得到向量中的每一个元素是否相等可以调用内置函数 equal 和 noEqual。逻辑运算符 用在类型为布尔标量的表达式中不可以用在矩阵中。选择运算符的使用与 C 相同可以用在除数组之外的任何类型中。但是要注意的式 第二个和第三个表达式必须是相同的类型。位运算符 只适用于有符号或者无符号的整型标量 或者整型向量的类型。赋值运算符最常用的 “” 在操作时要求符号两边的操作数必须类型完全相同。 着色器语言的赋值没有自动类型转换或提升功能。
1.4 各个数据类型的构造函数
构造函数的使用可以看作函数调用函数名称是某一数据类型的名称结果是得到的指定类型的实例。构造函数还可以用来进行数据类型的转换。 1 向量的构造函数
向量的构造函数可以用来创建指定类型向量的实例其入口参数一般可以为基本类型的字面常量、变量或其他向量。 如果向量构造函数内只有一个标量那么该向量的所有分量都等于该值如果向量的构造函数内有多个标量或者向量参数那么向量的分量则由左向右一次被赋值。在这种情况下参数的分量和向量的分量至少要一样多。如果向量构造函数的参数与对应的向量类型不相符则会选择数据类型转换的方式转换参数类型与向量类型匹配。
vec4 myVec4 vec4(1.0); // 每一个分量值都是1.0
vec3 myVec3 vec3(1.0, 0.0, 0.5); // 分量分别为1.0 0.0 0.52 矩阵的构造函数
矩阵构造函数的基本形式 如果矩阵的构造函数内只有一个标量值那么矩阵的对角线上的分量都等于该值其余值为0。举着可以由许多向量构造而成。矩阵可以由大量的标量构成矩阵的分量由左向右依次被赋值。
3 结构体的构造函数 如果一个结构体被定义并且赋予了一个类型名即可用该类型名去构造该结构体的实例。
struct {float intensity;vec3 position;
};
light lightVar light(2.0, vec3(1.0, 2.0, 3.0));4 数组的构造函数
数组类型同样可以作为构造函数的名称该构造函数同样适用于初始化或者表达式。使用数组的构造函数时需要保证参数的个数与定义的数组长度相同。
const float i[3] float[3](1.0, 2.0, 3.0);
const float j[3] float[](1.0, 2.0, 3.0);
float k 1.0;
float m[3];
m - float[3](k, k_1.0, k2.0);1.5 类型转换
着色器没有提供类型的自动提升功能着色器没有提供数据类型强转的功能只能通过构造函数来完成类型转换
float f 1.0;
bool b bool(f); // 非0 为true 0 为false
float f1 float(b); // true 为 0.1 false 为 0.0
int c - int(f1); // 去掉小数点着色器语言的设计可以避免类型转换带来的性能、复杂性缺陷简化了对硬件实现
// 以下声明会导致编译错误
float f0 1;1.6 存储限定符
1 in/centroid in 限定符
in/centrol in 限定修饰符修饰的全局变量又称 输入变量其形成当前着色器与渲染管线前一阶段的动态输入接口。输入变量的值实在着色器开始执行时由渲染管线的前一阶段送入。在着色器程序执行过程中变量不可以被重复赋值。使用情况 顶点着色器的输入变量只能使用in来修饰全局变量 用来接收渲染管线传递进顶点着色器的当前待处理顶点的各种属性值。属性值每个顶点各自拥有独立的副本用于描述顶点的各项特性如顶点坐标、法向量、颜色、纹理坐标等。修饰的变量的值 实质是由宿主程序批量传入渲染管线管线进行i基本处理后再传递给顶点着色器。数据有多少顶点就调用多少次顶点着色器每次将一个顶点的各种属性传递给in变量。因此顶点着色器每次执行将完成对一个顶点各项属性数据的处理。顶点着色器的in限定符只能用来修饰浮点数标量、浮点数向量、矩阵变量以及有符号合伙则会无符号的整型标量或者整型向量。 // 顶点着色器中使用 in 限定符layout (location 0) in vec3 aPosition; // 顶点位置layout (location 1) in vec3 aNormal; // 顶点法向量片元着色器的输入变量in/ centroid in 用来接收来自前一阶段着色器一般是顶点着色器的相关数据最典型的是接收根据顶点着色器的顶点数据插值产生的片元数据。可以修饰的类型包括有符号或者无符号的整型标量或整型向量、浮点数标量、浮点数向量、矩阵变量、数组变量以及结构体变量。当类型为有符号和或无符号整型标量或整型向量时变量也必须使用flat限定符来修饰。 layout (location 0) in vec3 vPosition; // 接收从顶点着色器传递过来的顶点数据centroid layout (location 1) in vec2 vTexCoord; // 接收从顶点着色器传递过来的纹理坐标flat layout (location 2) in vec3 vColor; // 接收从顶点着色器传递过来的颜色数据2 uniform 限定符
一致变量限定符。 一致变量指对于同一组顶点组成的单个3D物体中所有顶点都相同的量。可以使用在顶点着色器或片元着色器中其支持用来修饰所有的基本数据类型。一致变量的值也是从宿主程序传入。 unform mat4 uMVPMatrix; // 总变换矩阵uniform mat4 uMatrix; // 变换矩阵uniform vec3 uLightLocation; //光源位置uniform vec3 uCamera; // 摄像机位置3 out/centroid out 限定符
限定的变量又称输出变量其形成当前着色器与渲染管线后继阶段的动态输出接口。通常在当前着色器程序执行完毕时输出变量的值才被送入后继阶段进行处理。不能在着色器中声明同时起到输入和输出作用的inout 全局变量使用情况 顶点着色器的输出变量 用out/centrioid out 修饰全局变量被修饰的全局变量用于向渲染管线后继阶段传递当前顶点的数据可以用来修饰浮点型标量、浮点型向量、矩阵变量、有符号或无符号的整型标量或整型向量、数组变量及结构体变量。当顶点类型为有符号或无符号整型标量或整型向量时变量必须使用flat限定符来修饰。顶点着色器out变量的工作原理 首先顶点着色器在每个顶点中都对out 变量 vPosition 进行赋值。接着在片元着色器中接收in 变量 vPosition 的值时得到的并不是某个顶点赋的特定值而是根据图元所在位置及图元中各个顶点的位置进行插值计算产生的值。 光栅化后产生了多少个片元就会插值计算出多少套 in 变量。同时渲染管线就会调用多少次片元着色器。一般情况下对一个3D 物体的渲染中片元着色器执行的次数会大大超出顶点着色器。GPU 硬件中配置的片元着色器硬件数量往往多余顶点着色器硬件数量通过这些硬件单元的并行执行提高渲染速度。顶点着色器的后继阶段一般是片元着色器但也有可能是曲面系分着色器或几何着色器。 片元器着色器的输出变量 只能用 out 限定符来修饰全局变量片元着色器的out 输出变量一般指的是由片元着色器写入计算完成后片元颜色值的变量一般在片元着色器的最后都需要对其进行赋值然后将其送入渲染管线的后继阶段进行处理。out 限定符只能用来修饰浮点型标量、浮点型向量、有符号或无符号的整型标量或整型向量以及数组变量。 // 片元着色器中使用 out 限定符out vec4 outColor; // 输出的片元颜色值out vec4 outWorldPos; // 输出的片元世界坐标系坐标4 const 限定符
只读变量值是不变的也就是常量又称编译时常量。声明时必须初始化。在着色器外部是完全不可见的。 // 声明整型常量const int tempx 1;1.7 插值限定符
主要用于控制顶点着色器传到片元着色器数据的插值方式。顶点着色器的 out 和 片元着色器的 in。默认的插值方式为 smooth。无论顶点着色器中的out 全局变量被哪种插值限定符修饰后继 片元着色器中都必须含有与之对应的修饰符修饰的 in 全局变量。
1 smooth 限定符
顶点着色器传到片元着色器数据 参数的默认限定符是在光栅化阶段由管线根据片元所属图元各个顶点对应的顶点着色器对 out 变量的赋值情况及片元与个顶点的位置关系插值产生 smooth out vec3 normal; // 顶点着色器 out 变量smooth in vec3 normal; // 片元着色器 in 变量2 flat 限定符
如果顶点着色器中out 变量之前含有 flat 限定符 则传递到后继片元着色器中对应的in 的值不是在光栅化阶段插值产生的一般是由图元的最后一个顶点对应的顶点着色器对此 out 变量所赋的值决定。此时图元中每个片元的此项值都相同。若顶点着色器中的out 类型为整型标量或整型向量则变量必须使用 flat 限定符修饰。若片元着色器中的输入变量的类型为整型标量或整型向量变量必须使用 flat 限定符修饰。 flat out vec4 vColor; // 顶点着色器 out 变量flat in vec4 vColor; // 片元着色器 in 变量1.8 一致块
多个一致变量的声明可以通过类似结构体形式的接口块实现该接口块又称 一致块。一致块的数据是通过缓冲对象送入渲染管线的以一致块的形式批量传送数据比单个传送效率高。一致块内不允许声明in 或 out 变量、采样器类型的变量也不能定义结构体类型。内建变量、数组变量及已定义结构体类型的变量可以作为一致块的成员变量。创建一致块时可以声明实例名也可以不声明。 // 基本语法// uniform 为一致块的修饰关键字声明时必须使用// 应用程序通过一致块名称识别一致块// 成员变量列表可以包含多个变量的声明 与普通结构体内成员变量的声明类似// 实例名是一致块的实例名称命名规则与一致块名称相同。[layout 限定符] uniform 一致块名称 {成员变量列表} [实例名]// 例如uniform Transform {float radius;mat4 modelViewMatrix;uniform mat3 normalMatrix;} block_Transform;未声明实例名 一致块内的成怨怒变量与在块外一样名称作用域时全局的开发时可以直接通过一致块的成员变量名称访问对应变量。 声明实例名 一致块内成员变量的作用域为从声明开始到一致块结束变成时通过实例名 .成员变量 在块外访问成员变量 uniform MatrixBlock {mat4 uMVPMatrix; // 块成员变量总变换矩阵} mb; // 实例名 mbgl_Position mb.uMVPMatrix * vec4(aPosition, 1); // 根据总变换矩阵计算此次绘制此顶点的位置1.9 layout 限定符
主要用于设置变量的存储索引即 引用值。可以作为接口块的一部分也可以单独修饰接口块中的成怨怒。可以用于修饰被接口限定修饰符的单独变量 // 语法// 接口限定符有 in out uniform 三种选择layout 限定符 接口限定符 变量声明1 layout 输入限定符
与 in 限定符 配合使用用在顶点着色器中 layout (location 0) in vec3 aPosition; //aPosition 输入变量的引用索引为0layout (location 1) in vec4 aColor; // aColor 输入变量的引用索引为12 layout 输出限定符
与 out 限定符 配合使用用在片元卓i瑟琪中 // location 的值是有范围的范围为 [0, MAX_DRAW_BUFFERS - 1]MAX_DRAW_BUFFERS 为目标硬件支持的最大绘制用缓冲数layout (location 0) out vec4 outColor; // 第一个输出layout (location 1) out vec4 outColorR; // 第二个输出layout (location 2) out vec4 outColorG; // 第三个输出layout (location 3) out vec4 outColorB; // 第四个输出3 一致块 layout 限定符
一致块可以用layout限定符一般还需要给出所需的属性设置std140 表示一致块的内存布局基于 std140 标准 row_major 表示一致块中的矩阵元素在内存中将按照行优先的顺序存放 column_major 表示一致块中的矩阵元素在内存中将按照列优先的顺序存放 layout (std140, row_major) uniform MatrixBlock { // 块布局时std140矩阵行优先mat4 M1;layout (column_major) mat4 uMVPMatrrix; // 该变量布局是列优先mat4 M2;}1.10 流程控制
1 if-else 条件语句 if(表达式) { // 执行逻辑处理}else { // 执行逻辑处理}2 switch-case-default 条件语句 // 初始表达式必须是整型标量switch(初始表达式) { // 语句序列case 0: break;...default:break;}3 while/do-while 循环 while (条件表达式) { // 语句序列}do { // 语句序列 } while (条件表达式7)4 for 循环 for(初始化表达式; 条件表达式; 更新语句列表) { // 语句序列 }5 break 与 continue 循环控制
break 在循环中中断循环continue 在循环中跳过本次进入下一次循环
1.11 函数的声明和使用
着色器语言中可以开发自定义函数 // 精度限定符可以选择 highp、 mediump、 lowp 这三种之一// 返回类型为数组式必须指定数组的长度// 返回类型可以是采样器之外的任意类型// 参数序列的参数除了可以指定类型外还可以指定用途。常用用途如下// in 修饰的参数为输入参数进攻函数接收外界传入的值若某个参数没有明确给出用途修饰符等同于使用in 修饰符// out 修饰符修饰的参数为输出参数在函数中对输出参数赋值可以将值传递到哦调用其的外界变量中。需要注意的是在调用时不可以使用字面常量const// inout 修饰的参数为输入输出参数具有输入输出两种参数的功能。输入输出参数在调用时也不可以使用字面常量const。[精度限定符] 返回类型 函数名称 ([参数序列]) { //函数体 }// 例(注意 着色器内只能重载用户自定义的函数)void pointLight(int vec4 x, out vec4 y) {}void pointLight(int vec4 x, out ivec4 y) {}void pointLight(int vec4 x, out vec4 y, out vec4 z) {}1.12 片元着色器中浮点及整型变量精度的指定
在片元着色器中可以指定精度 // 精度有3种选择 lowp、 mediump、 highp分别代表 低、 中、高 3种精度等级不通一ing吉安种实现可能会有所不同// 一般情况下使用 highp 精度// 浮点或整型相关类型不仅包含 float int 还包含 与之对应的向量类型以及与之对应的矩阵类型。lowp float color;in mediump vec2 Coord;highp mat4 m;highp ivec22 k;在同一个片元着色器种浮点或整型相关类型的变量都选用同一精度则可以指定整个着色器中相关类型的默认精度 precision 精度 类型;precision mediump int;1.13 程序的基本结构
#version 400 // 声明使用着色器语言版本
#extension GL_ARB_separate_shader_objects : enable // 启动GL_ARB_separate_shader_objects 必要扩展
#extension GL_ARB_shading_language_420pack : enable // 启动GL_ARB_shading_language_420pack 必要扩展
layout (std140, set 0, binding 0) uniform bufferVals { // 一致块mat4 mvp; // 总变换矩阵
} myBufferVals; // 实例名为 myBufferValslayout (location 0) in vec3 pos; // 传入的物体坐标系顶点位置
layout (location 1) in vec3 color; // 传入如的顶点颜色
layout (location 0) in vec3 vcolor; // 传到片元着色器的顶点颜色// 自定义函数不可以递归调用
out gl_PerVertex { // 计算顶点位置的方法gl_Position myBufferVals.mvp * vec4(pos, 1.0); // 计算最终顶点位置
} void main() { // 主函数positionShift(); // 调用计算顶点位置的方法必须先声明vcolor color; // 传递顶点颜色给片元着色器
}2. 内建变量
着色器中提供的用来满足特定需求的内建变量内建变量不需要声明一般用来实现渲染管线固定功能部分与可编辑着色器顶点、片元、几何、曲面系分着色器之间的信息交互可分为两类 输入变量与输出变量 输入变量 负责将渲染管线中固定功能部分产生的信息传递进着色器输出变量 负责将着色器中产涩会给你的信息传递给渲染管线中的固定功能部分。
2.1 顶点着色器中的内建变量
1 内建输入变量
主要有 gl_VertexID 和 gl_InstanceID分别为当前处理顶点的整数索引以及当前处理实例的整数索引以及当前处理实例的整数索引。gl_VertexID 类型为 “heighp int” 用来将当前被处理顶点的索引传递给顶点着色器。 gl_instanceID 类型为 “heighp int” 用来将当前被处理实例的索引传递给顶点着色器。 若不是在多实例渲染的情况下此内建变量的值一直为0。
2 内建输出变量
主要由 gl_Position 以及 gl_PointSize。 这两个变量分别用来存放处理后顶点的位置和顶点的尺寸。gl_Position 顶点着色器从渲染管线中获得原始的顶点位置数据这些原始的顶点位置数据在顶点着色器中经过平移、旋转、缩放、摄像机观察、摄影等数学变换后生成新的顶点位置。 新的顶点位置通过在顶点着色器中写入 gl_Position 内建变量传递到渲染管线的后继阶段继续处理。类型是 vec4 写入的顶点位置数据爷必须与其类型一致。几乎在所有的顶点着色器中都必须对gl_Position 写入适当的值否则后继阶段的处理结果将是不确定的。 gl_PointSize 顶点着色器中可以计算一个点的大小单位为像素并将其赋值给 gl_PointSize标量 float 类型以传递给渲染管线。如果没有明确赋值的化采用默认值 1.0。gl_PointSize 的值一般只有在采用了点绘制方式之后才有意义。
2.2 片元着色器中的内建变量
也分为输入变量和输出变量输入变量包括 gl_FragCoord、 gl_FrontFacing 和 gl_PointCoord。输出变量包括 gl_FragDepth值为 片元深度值可以对其赋值然后送进深度缓冲参与后继计算。gl_FragCoord 内建变量gl_FragCoordvec4 类型含有当前片元相对于窗口位置的坐标值 x、y、z 与 1/w。 其中 x y 为片元相对窗口的二维坐标z 为片元的深度值。 gl_FrontFacing gl_FrontFacing 是一个布尔型的内建变量通过读取该值可以判断正在处理的片元是否数与在光栅阶段生成此片元的对应图元的正面。如果属于正面值为true反之 false。一般用于开发双面光照功能相关的程序中。对于点、线没有正反面的图元默认正面。对于三角形图元来说正反面取决于应用程序中对卷绕的设置以及图元中顶点的具体卷绕情况。 gl_PointCoord vec2 类型的内建变量当启用 点精灵时 gl_PointCoord 的值表示当前图元中片元的纹理坐标 值范围是 0.0 到 1.0。如果当前图元不是一个点或者未启用点精灵gl_PointCoord 的值是不确定的。
2.3 内建常量
内建常量适用于所有的着色器用来限制每种属性高变量的数量。也就是用来规定每种自定义变量数量的最大值。不同品牌、不同型号的设备内建常量的默认值不同。下表的默认值为可能默认值的最小值。
内建常量默认值说明const mediump int gl_MaxVertexAttribs16顶点着色器in 变量数量的最大值const mediump int gl_MaxVertexUniformComponents1024顶点着色器 uniform 修饰的 vec4 变量数量的最大值const mediump int gl_MaxVertexOutputComponents64顶点着色器 out 修饰的 vec4 变量数量的最大值const mediump int gl_MaxVertexTextureImageUnits16顶点着色器中科利用的纹理单元数量的最大值const mediump int gl_MaxCombinedTextureImageUnits80顶点着色器和片元着色器中可利用的纹理单元数量的最大值的总和const mediump int gl_MaxTextureImageUnits16片元着色器中可利用的纹理图像单元数量的最大值const mediump int gl_MaxFragmentInputComponents128片元着色器 in 变量数量的最大值const mediump int gl_MaxFragmentUniformComponents1024片元着色器 uniform 修饰的vec4 变量数量的最大值const mediump int gl_MaxDrawBuffers8片元着色器中多重渲染目标数量的最大值
3. 内置函数
着色器提供了很多内置函数这些函数大多已经被重载一般四种变体分别用来接收和返回 genTypegenITypegenUType 以及 genBType 类型的值。
变体类型说明变体类型说明genType浮点flloat, vec2, vec3, vec4genUType无符号整型uint, uvec2, uvec3, uvec4genIType整型int, ivec2, ivec3, ivec4genBType布尔类型bool, bvec2, bvec3, bvec4
内置函数通常以最有方式实现有部分函数甚至由硬件直接支持。大部分内置函数同时适用于顶点、片元、集合、曲面细分等着色器也有部分只适用于顶点或者片元着色器内置函数按照设计目的可以分为3个类别 提供独特硬件功能的访问接口如纹理采样系列函数用户无法自行开发。简单的数学函数内置函数相比自己开发效率更高是厂商根据硬件的特点用最高效的方式实现的。一些复杂的函数如三角函数等用户可以自己编写编写过程繁琐。主流硬件往往都有将进行这些计算的专用指令更高效。
3.1 角度转换与三角函数
适用于多种着色器且每个角度转换与三角函数都有4种重载变体
内置函数签名说明genType radians(genType degrees)将角度转为弧度, result Π / 180) * degreesgenType degrees(genType radians)将弧度转换为角度, result (Π / 180) * radiansgenType sin(genType angle)求正弦值返回 [-1, 1] angle 以弧度为单位genType cos(genType angle)求余弦值genType tan(genType angle)求正切值genType asin(genType x)求反正弦值 [-Π/2, Π/2]x取值[-1, 1] x 绝对值大于1 结果不确定genType acos(genType x)求反余弦值 [0, Π] x 绝对值大于1 结果不确定genType atan(genType y, genType x)求反正切函值 [-Π, Π] x y 全为0 返回值不确定genType atan(genType y_over_x)求反正切值 [-Π/2, Π/2] , y_over_x 不存在范围限制genType sinh(genType x)双曲正弦函数返回 ( e x − e − x ) / 2 ( e^x - e^{-x} )/2 (ex−e−x)/2 x不存在范围限制genType cosh(genType x)双曲余弦函数返回 ( e x e − x ) / 2 (e^x e^{-x}) / 2 (exe−x)/2 x不存在范围限制genType tanh(genType x)双曲正切函数 返回 sinh(x)/consh(x) 双曲正切函数由双曲正弦函数和双曲余弦函数推出genType asinh(genType x)反双曲正先函数双曲正弦函数的反函数genType acosh(genType x)反双曲余弦函数。返回值为其非负部分 x 1 返回值不确定genType atanh(genType x)反双曲正切函数 若 |x| ≥ 1返回值不确定
3.2 指数函数
适用于多种着色器
内置函数签名说明genType pow(genType x, genType y)返回x 的y 次方x 小于0返回值不确定x值等于0 并且y值小于等于0返回值不确定 x y x^y xygenType exp(genType x)返回e(约等于2.718281828) 的 x 次方即 e x e^x exgenType log(genType x)返回e 为底的x 的对数x 小于0返回值不确定即 l o g e ( x ) log_e(x) loge(x) 如果返回值为y那么也满足方程 x e y x e^y xeygenType exp2(genType x)返回 2 的 x 次方即 2 x 2^x 2xgenType log2(genType x)返回 2 为底的x 的对数即 l o g 2 ( x ) log_2(x) log2(x)genType sqrt(genType x)返回x 的平方根 x \sqrt{x} x genType inversesqrt(genType x)返回x 正平方根的倒数 1 x \cfrac 1 {\sqrt{x}} x 1
3.3 常见函数
内置函数签名说明genType abs(genType x)求绝对值genType sign(genType x)与0 进行比较返回 1.0 、0 、 -1.0genType floor(genType x)返回小于或者等于x 的最大整数值genType trunc(genType x)截取并返回x 整数部分genType round(genType x)四舍五入genType roundEven(genType x)偶四舍五入例如 3.5 和 4.5 都返回 4.0genType ceil(genType x)返回大于等于x的最小整数genType fract(genType x)返回 x - floor(x)genType mod(genType x, float y)取模运算genType mode(genTypex x, genType y)取模运算genType modf(genType x, out genType i)返回x 的小数部分并将x 的整数部分存入输出变量i。同时返回值以及输出变量i的符号与x相同genType min(genType x, genType y)获得x 和y 中的最小值genType miiiiin(genType x, float y)获得 x 和y 中的最小值genType clamp(genType x, genType minVal, genType maxVal)返回 min(max (x, minVal), maxVal)genType clamp(genType x, float minVal, float maxVal)返回 min(max (x, minVal), maxVal)genType mix(genType x, genType y, genType a)使用因子 a 对 x 与 y 执行西安行混合即 返回 x ∗ ( 1 − a ) y ∗ a x^*(1 - a) y^*a x∗(1−a)y∗agenType mix(genType x, genType y, float a)使用因子 a 对 x 与 y 执行西安行混合即 返回 x ∗ ( 1 − a ) y ∗ a x^*(1 - a) y^*a x∗(1−a)y∗agenType mix(genType x,genType y, genBType a)使用参数 a 的布尔值选择返回参数 x 或 y 的值genType step(genType edge, genType x)通过 x 与 edge 比较返回相应的值genType step(float edge, genType x)通过x 与 edge 比较返回相应的值genType smoothstep(genType edge0, genType edge1, genType x)通过 x 与 edge0、edge1 比较返回相应的值genType smoothstep(float edge0, float edge1, genType x)通过 x 与 edge0、edge1 比较返回相应的值genBType isnan(genType x)判断参数 x 是否为NaN是返回 truegenBType isinf(genType x)判断x 是否为正无穷或负无穷genType floatBitsToInt(genType value)将表示浮点的比特序列看作表示整数的比特序列并将对应的整数返回genUType floatBitsToUint(genType value)将表示浮点的比特序列看作表示整数的比特序列并将对应的整数返回genType intBitsToFloat(genType value)将表示整数的比特序列看昨表示附带念书的比特序列genType uintBitsToFloat(genUType value)将表示整数的比特序列看昨表示附带念书的比特序列 float t; // 声明变量用来存储平滑过渡中的值t clamp ( ( x - edge0 ) / (edge1 - edge0 ), 0.0, 1.0); // 计算x位置对edge1 与 edge0 之间的线性插值return t*t*(3.0 - 2.0*t); // 产生对应此x 位置的平滑过渡值3.4 几何函数
内置函数签名说明float length(genType x)返回 向量x 的长度 x [ 0 ] ∗ x [ 0 ] x [ 1 ] ∗ x [ 1 ] . . . \sqrt{ x[0]^*x[0] x[1]^*x[1] ... } x[0]∗x[0]x[1]∗x[1]... float distance(genType p0, genType p1)返回 p0 与 p1 之间的距离 即 length(p0 - p1)float dot(genType x, genType y)返回向量x 与y 的点积 即 x [ 0 ] ∗ y [ 0 ] x [ 1 ] ∗ y [ 1 ] x [ 2 ] ∗ y [ 2 ] . . . x[0]^*y[0] x[1]^*y[1] x[2]^*y[2] ... x[0]∗y[0]x[1]∗y[1]x[2]∗y[2]...vec3 cross(vec3 x, vec3 y)返回向量 x 与 y 的叉积即 [ x [ 1 ] ∗ y [ 2 ] − y [ 1 ] ∗ x [ 2 ] x [ 2 ] ∗ y [ 0 ] − y [ 2 ] ∗ x [ 0 ] x [ 0 ] ∗ y [ 1 ] − y [ 0 ] ∗ x [ 1 ] ] \begin{bmatrix} x[1]^*y[2] - y[1]^*x[2] \\ x[2]^*y[0] - y[2]^*x[0] \\ x[0]^*y[1] - y[0]^*x[1] \end{bmatrix} x[1]∗y[2]−y[1]∗x[2]x[2]∗y[0]−y[2]∗x[0]x[0]∗y[1]−y[0]∗x[1] genType normalize(genType x)返回与向量 x 方向相同并且长度为 1 的向量对向量进行规格化genType faceforward(genType N, genType I, genType Nref)根据 dot(Nref, I) 的值返回相应的值如果 do(Nref, I) 0, 则返回N否则返回 -NgenType reflect(genType I, genType N)根据传入的入射向量I 以及表面法向量 N , 返回反射方向的向量genType refract(genType I, genType N, float eta)根据传入的入射向量I 、 表面法向量 N 以及折射系数 eta 返回折射向量。
3.5 矩阵函数
主要包括生成矩阵、矩阵转置 、求矩阵行列式、求逆矩阵
内置函数签名说明mat matrixCompMult( mat x, mat y)按各个部分将矩阵 x 与 矩阵 y 相乘即 返回值 result[i][j] 是 x[i][j] 与 y[i][j]标量的乘积mat2 outerProduct(vec2 c, vec2 r) mat3 outerProduct(vec3 c, vec3 r) mat4 outerProduct(vec4 c, vec4 r) mat2x3 outerProduct(vec3 c, vec2 r) mat3x2 outerProduct(vec2 c, vec3 r) mat2x4 outerProduct(vec4 c, vec2 r) mat4x2 outerProduct(vec2 c, vec4 r) mat3x4 outerProduct(vec4 c, vec3 r) mat4x3 outerProduct(vec3 c, vec4 r)将参数c 和参数r 分别看成只有一列的矩阵和只有一行的矩阵并将其进行线性矩阵乘积产生一个新的矩阵mt2 transpose(mat2 m) mat3 transpose(mat3 m) mat4 transpose(mat4 m) mat2x3 transpose(mat3x2 m) mat3x2 transpose(mat2x3 m) mat2x4 transpose(mat4x2 m) mat4x2 transpose(mat2x4 m) mat3x4 transpose(mat4x3 m) mat4x3 transpose(mat3x4 m)返回参数矩阵 m 的转置矩阵原始m矩阵不变float determinant(mat2 m) float determinant(mat3 m) float determinant(mat4 m)返回参数矩阵m 的行列式mat2 inverse(mat2 m) mat3 inverse(mat3 m) mat4 inverse(mat4 m)返回矩阵 m 的逆矩阵 原始矩阵 m 不变
3.6 向量关系函数
内置函数签名说明bvec lessThan(vec x, vec y) bvec lessThan(ivec x, ivec y) bvec lessThan(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量 执行 x y 的结果bvec lessThanEqual(vec x, vec y) bvec lessThanEqual(ivec x, ivec y) bvec lessThanEqual(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量执行 x y 的结果bvec greaterThan(vec x, vec y) bvec greaterThanEqual(ivec x, ivec y) bvec greaterThanEqual(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量执行 x y 的结果bvec greaterThanEqual(vec x, vec y) bvec greaterThanEqual(ivec x, ivec y) bvec greaterThanEqual(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量执行 x y 的结果bvec equal(vec x, vec y) bvec equal(ivec x, ivec y) bvec equal(bvec x, bvec y) bvec equal(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量 执行 x y 的结果bvec notEqual(vec x, vec y) bvec notEqual(ivec x, ivec y) bvec notEqual(bvec x, bvec y) bvec notEqual(uvec x, uvec y)返回向量 x 与向量 y 中的各个分量 执行 x ! y 的结果bool any(bvec x)如果x 中任何一个分量为 true 返回 truebool all(bvec x)x 中所有组成元素都为 true 返回 truebool not(bvec x)对于 x 中各个分量执行的逻辑非运算
3.7 纹理采样函数
sampler 为指定纹理的采样器P 为纹理坐标lod 为细节级别bias 为偏移值gvec4 中的 g 表示占位符可以表示 vec4、ivec4、uvec4投影采样相关功能与函数 textureProj 相同偏移采样相关功能与函数textureOffset 相同dPdx 为 P 对窗口 x 坐标的偏导数dPdy 为 P 对窗口 y 坐标的偏导数渐变采样相关功能与函数 textureGrad 相同
内置函数签名说明highp ivec2 textureSize(gsampler2D sampler, int lod) highp ivec2 textureSize(gsampler3D sampler, int lod) highp ivec2 textureSize(gsamplerCube sampler, int lod) highp ivec2 textureSize(sampler2DShadow sampler, int lod) highp ivec2 textureSize(gsamplerCubeShadow sampler, int lod) highp ivec3 textureSize(gsampler2DArray sampler, int lod) highp ivec3 textureSize(gsampler2DArrayShadow sampler, int lod)根据参数smapler 的细节级别按顺序返回纹理的宽度高度以及深度。对于 Array 格式返回值的最后一个元素为纹理数组的层数。gvec4 texture(gsampler2D sampler, vec2 P[, float bias]) gvec4 texture(gsampler3D sampler, vec3 P[, float bias]) gvec4 texture(gsamplerCube sampler, vec3 P[, float bias]) gvec4 texture(gsampler2DArray sampler, vec3 P[, float bias])纹理坐标 P 在 sampler 参数指定的纹理坐标执行纹理采样float texture(sampler2DShadow sampler, vec3 P[, float bias] float texture(samplerCubeShadow sampler, vec4 P[, float bias] float texture(sampler2DArrayShadow sampler, vec4 P[, float bias]执行阴影类纹理采样gvec4 textureProj(gsampler2D sampler, vec3 P[,float bias] gvec4 textureProj(gsampler2D sampler, vec4 P[,float bias] gvec4 textureProj(gsampler3D sampler, vec4 P[,float bias] float textureProj(sampler2DShadow sampler, vec3 P[,float bias]执行投影纹理采样。采样时的纹理坐标为 P 参数的前几个分量不含最后一个分别除以最后一个分量所得gvec4 textureOffset(gsampler2D sampler, vec2 P, ivec2 offset [, float bias]) gvec4 textureOffset(gsampler3D sampler, vec3 P, ivec3 offset [, float bias]) gvec4 textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset [, float bias]) gvec4 textureOffset(gsampler2DArray sampler, vec3 P, ivec2 offset [, float bias])使用偏移纹理坐标进行纹理采样gvec4 texelFetch(gsampler2D sampler, ivec2 P, int lod) gvec4 texelFetch(gsampler3D sampler, ivec3 P, int lod) gvec4 texelFetch(gsampler2DArray sampler, ivec3 P, int lod)使用整型纹理坐标 P 在 sampler 参数 指定的纹理中执行纹理采样gvec4 texelFetchOffset(gsampler2D sampler, ivec2 P, int lod, ivec2 offset) gvec4 texelFetchOffset(gsampler3D sampler, ivec3 P, int lod, ivec3 offset) gvec4 texelFetchOffset(gsampler2DArray sampler, ivec3 P, int lod, ivec2 offset)使用整型偏移纹理坐标在 sampler 参数 指定的纹理中获取对应坐标处的纹素。gvec4 textureProjOffset(gsampler2D sampler, vec3 P, ivec2 offset [, float bias]) gvec4 textureProjOffset(gsampler2D sampler, vec4 P, ivec2 offset [, float bias]) gvec4 textureProjOffset(gsampler3D sampler, vec4 P, ivec2 offset [, float bias]) float textureProjOffset(sampler2DShadow sampler, vec4 P, ivec2 offset [, float bias])执行投影偏移纹理采样gvec4 textureLodOffset(gsampler2D sampler, vec2 P, float lod, ivec2 offset) gvec4 textureProjOffset(gsampler3D sampler, vec3 P, float lod, ivec3 offset) float textureLodOffset(sampler2DShadow sampler, vec3 P, float lod, ivec2 offset) float textureProjOffset(gsampler2DArray sampler, vec3 P,float lod, ivec2 offset)执行投影偏移纹理采样gvec4 textureProjLod(gsampler2D sampler, vec2 P, float lod) gvec4 textureProjLodtextureProjLod(gsampler2D sampler, vec4 P, float lod) float textureProjLod(gsampler3D sampler, vec4 P, float lod) float textureProjLod(sampler2DShadow sampler, vec4 P, float lod)执行投影偏移纹理采样gvec4 textureProjLodOffset(gsampler2D sampler, vec3 P, float lod, ivec2 offset) gvec4 textureProjLodOffset(gsampler2D sampler, vec4 P, float lod, ivec2 offset) gvec4 textureProjLodOffset(gsampler3D sampler, vec4 P, float lod, ivec3 offset) float textureProjLodOffset(sampler2DShadow sampler, vec4 P, float lod, ivec2 offset)执行指定细节级别的投影偏移纹理采样gvec4 textureGrad(gsampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy) gvec4 textureGrad(gsampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy) gvec4 textureGrad(gsamplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy) gvec4 textureGrad(gsampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy)执行纹理渐变采样float textureGrad(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy) float textureGrad(samplerCubeShadow sampler, vec4 P, vec3 dPdx, vec3 dPdy) float textureGrad(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy)执行纹理阴影类型纹理渐变采样gvec4 textureGradOffset(gsampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy, ivec2 offset) gvec4 textureGradOffset(gsampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy, ivec3 offset) float textureGradOffset(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy, ivec2 offset) gvec4 textureGradOffset(gsampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy, ivec2 offset) gvec4 textureGradOffset(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset)执行纹理渐变偏移采样gvec4 textureProjGrad(gsampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy) gvec4 textureProjGrad(gsampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy) gvec4 textureProjGrad(gsampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy) float textureProjGrad(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy)执行投影纹理渐变采样gvec4 textureProjGradOffset(gsampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy, ivec2 offset) gvec4 textureProjGradOffset(gsampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset) gvec4 textureProjGradOffset(gsampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy, ivec3 offset) gvec4 textureProjGradOffset(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy, ivec2 offset)执行投影纹理渐变偏移采样
3.8 微分函数
仅能用于 片元着色器主要包括 dFdxz 方法、dFdy 方法以及 fwidth 方法
内置函数签名说明genType dFdx(genType p)返回参数 p 在 x 方向的偏导数genType dFdx(genType p)返回参数 p 在 y 方向的偏导数genType fwidth(genType p)返回参数 p 在 x 与 y 方向偏导数的绝对值之和 abs (dFdx ( p) abs(dFdy (p))x
3.9 浮点数打包与解包函数
内置函数签名说明highp uint packUnorm2x16(vec2 v)首先将二维向量 v 中的每个规格化浮点数分量转换为 16 比特的整数然后两个 16 比特的整数被打包城一个 32 比特的无符号整数返回。 r o u n d ( c l a m p ( c , 0 , 1 ) ∗ 65535.0 round(clamp(c, 0, 1) * 65535.0 round(clamp(c,0,1)∗65535.0highp vec2 unpackUnorm2x16(highp uint p)将一个32位无符号的整数 p 解包成一对 16 位的无符号整数并将每一个分量转换成规格化的浮点值生成一个 vec2 并返回highp uint packUnorm4x8(highp uint p)首先将四维向量 v 中的每个规格化浮点数分量转换成 8 比特的整数然后四个8比特的整数被打包成一个32 比特的无符号整数返回。 r o u n d ( c l a m p ( c , 0 , 1 ) ∗ 255.0 ) round(clamp(c, 0, 1 ) * 255.0) round(clamp(c,0,1)∗255.0)highp vec4 unpackUnorm4x8(highp uint p)将一个 32 位无符号的整数 p 解包成四个 8 位的无符号整数并将每一个分量转换成规格化的浮点数生成一个 vec4 并返回。 可以理解位packUnorm4x8 函数的逆操作highp uint packSnorm4x8(vec4 v)首先将四维向量 v 中的每个规格化浮点数分量转为 8 比特的整数然后四个 8 比特的整数被打包成一个32 比特的无符号整数返回。 r o u n d ( c l a m p ( c , − 1 , 1 ) ∗ 127.0 ) round(clamp(c, -1, 1 ) * 127.0) round(clamp(c,−1,1)∗127.0)highp vec4 unpackSnorm4x8(highp uint p)将一个32 位无符号的整数 p 解包成四个 8 位的无符号整数并将每一个分量转换成规格化的浮点值生成一个 vec4 并返回highp double packDouble2x32(uvec2 v)首先将二维向量 v 中的每个规格化浮点数分量转换为 32 比特的浮点数然后两个32 比特的浮点数被打包成一个 64 比特的浮点数返回。highp uvec2 unpackDouble2x32(double p)将一个 64 比特的浮点数 p 解包成两个 32 位的浮点数并将每一个分量转换成规格化的浮点值生成一个 uvec2 并返回。
4. invariant 修饰符避免值变问题
值变问题是指 在同样的着色器程序多次运行时同一个表达式在同样输入值的情况下多次运行结果不精确一致的情况。大部分情况下值变不影响最终效果的正确性。以下几种情况可以使用 invariant 顶点着色器中的内建输出变量如 gl_Position顶点着色器中声明的以 out 修饰符修饰的变量片元着色器中内奸的输出变量片怨怒着色器中声明的以 out 修饰符修饰的变量 某些特殊情况需要避免值变问题很少主要有两种方式 在声明便力量时加上 invariant 修饰符对已经声明的变量补充使用 invariant 修饰符进行修饰 // 此部分代码只能位于着色器程序的前面且不能在片元着色器中使用// 方式一invariant out vec3 color; // 方式二out vec3 color;invariant color;// 所有的输出变量都是 invariant#pragma STDGL invariant (all)5. 预处理器
在真正的编译开始之前由编译器调用的独立程序处理编译过程中所需的源字符串遵循 C/C 语言预处理器的规则宏定义和条件测试等可以通过预处理指令执行。
预处理器说明#预处理#define定义宏#define删除事先定义的宏#if条件测试#ifdef条件测试是否定义#ifndef条件测试是否未定义#else条件测试#elif条件测试#endif条件测试结束编译块的控制#error将诊断信息保存到着色器对象的信息日志中#pragma允许依赖于实现的编译控制。如默认情况下 开启着色器优化 #pragram optimize(off)#extension激活指令的扩展行为#line#line后面是整型常量表达式表示从其开始的起始行号
着色器还定义了一些可以直接使用的宏所有以 GL_ 为前缀的宏名和包含两个连续下划线 __ 的宏名称都是着色器语言保留的。重定义内建宏名和预定义宏名是错误的
预定义宏说明__LINE__当前按被编译代码行的行号十进制整数__FILE__当前被处理的源代码字符串符号十进制整数__VERSION__用来替代着色器语言的版本号
与C 类似如果定义了宏没有给出其替代表达式并不会默认其替代表达式为“0”预定义表达式在编译时执行可操作符如下
优先级操作符类型操作符结合性1最高()NA2一元操作符define - ~ !从右到左3乘、除、取余 * / %从左到右4加、减 -从左到右5比特左/右移 从左到右6比较操作符 从左到右7等于/不等于操作符 ! 从左到右8比特与从左到右9比特异或^从左到右10比特或|从左到右11逻辑与从左到右12(最低)逻辑或||从左到右
着色器语言的编译器必须反馈不符合规范的编译时词法和语法错误同时任何扩展行为必须先启用才能使用控制编译器使用的扩展行为 通过 #extension 指令实现 #extension 扩展名:扩展行为扩展名为各个硬件厂商提供的特殊功能扩展的名称使用时查阅厂商提供资料编译器的初始状态为 #extension all:disable意味着编译器关闭任何扩展主要包含以下类型
扩展行为主要的扩展行为require说明需要指定扩展名的扩展如果编译器不支持指定扩展名对应的扩展或扩展名为 all则反馈错误enable启用指定扩展名的扩展如果编译器不支持扩展名对应的扩展 则给出警告。如果扩展名为all 则反馈错误warn检测是否使用了指定名称的扩展如果使用了则给出警告。如果为all 则检测是否使用了任何扩展若使用了给出警告。如果编译器不支持此扩展则给出警告disable金庸指定扩展名的扩展如果编译器不支持指定扩展名则给出警告。如果为all则禁用所有使用的扩展回复到默认核心版本