Shader 入门:GLSL ES(运算符和限定符)
前言
在上一篇文章中我们学习了 GLSL ES 的数据类型,那么本章节学习的是 GLSL ES 中运算符和限定符的内容。
在本系列文章中主要针对 GLSL ES 3.0 进行讲解。
正文
运算符(Operators)
使用括号包裹的内容优先级最高!
优先级 | 操作符 | 描述 |
---|---|---|
1 | ++ -- | 后置自增、自减 |
2 | ++ -- | 前置自增、自减 |
2 | + - ~ ! | 一元运算 |
3 | * % / | 乘、取余、除 |
4 | + - | 加、减 |
5 | << >> | 位运算 |
6 | < > <= >= == != | 关系运算 |
7 | & ^ | | 位与、位异或、位同或 |
8 | && ^^ || | 逻辑与、逻辑异或、逻辑同或 |
9 |
| 三目运算 |
10 |
| 赋值 |
10 | += -= *= /= %= <<= >>= &= ^= |= | 算术赋值 |
限定符(Qualifiers)
储存限定符(Storage Qualifiers)
声明变量时可以在类型前面添加一个储存限定符。
限定词 | 含义 |
---|---|
无(默认) | 用于局部作用域。 |
const | 声明为只读的常量。 |
in | 从上一阶段输入到当前着色器。 |
out | 从当前着色器输出到下一阶段。 |
uniform | 在着色器、OpenGL ES 和程序之间共享的变量。 |
const
使用 const
限定符修饰的变量即为常量,常量一但定义就不可再修改。
适用于标量、向量、矩阵、数组和结构体,但不适用于采样器:
// 声明定义常量
const int age = 18;
const vec4 color = vec4(0.5, 0.5, 0.5, 0.5);
// 也可以用于限定函数的参数
void doSomething(const float param) {
param = 0.1; // Error! 不可!
// ...
}
in
in 限定符常用于接收从上一阶段输出的变量:
in vec3 a_position; // 接收一个顶点坐标向量
in vec2 a_uv0; // 接收一个纹理坐标向量
in vec4 a_color; // 接受一个颜色向量
out
out 限定符常用于将当前着色器中的变量输出到下一阶段:
out vec2 v_uv0; // 输出一个纹理坐标向量
out vec4 v_color; // 输出一个颜色向量
uniform
使用 uniform 限定符来表示一个统一且只读的全局变量,该变量为所有着色器所共用。
注意:声明了却没有使用的 uniform 变量会在编译时被静默移除!
uniform sampler2D texture;
另外 uniform
变量只能在程序中使用 OpenGL ES 的一系列 glUniform
API 进行赋值:
// 程序代码
int location = glGetUniformLocation(shaderProgram, "color"); // 查找 color 的位置(索引)
glUniform4f(location, 0.0f, 0.1f, 0.0f, 1.0f); // 给 color 赋值
// 着色器代码
uniform vec4 color; // vec4(0.0, 0.1, 0.0, 1.0)
参数限定符(Parameter Qualifiers)
函数的参数也可以使用限定符。
限定词 | 含义 |
---|---|
无(默认) | 和 in 的作用一致。 |
in | 表示复制进函数体内的参数(值传递,不影响原来的值)。 |
out | 表示函数向外复制的参数,必须是之前未被初始化的变量(引用传递,会影响原来的值)。 |
inout | 表示参数将在函数内外保持一致(引用传递,会影响原来的值)。 |
使用示例:
// in
void doo(in float param) { ... } // 和普通不加限定词的参数一样
// out
void foo(out int param) {
param = 666;
}
int a; // 声明了但是没有初始化
foo(a); // a = 666
// inout
void goo(inout int param) {
param = param++;
}
int b = 1;
goo(b); // b = 2
精度限定符(Precision Qualifiers)
浮点数、整数和采样器类型声明可以添加精度限定词来设置精度范围(精度控制可以扩展至向量和矩阵)。
精度限定符不适用于常量、布尔类型和构造函数!
限定词 | 含义 |
---|---|
highp | 满足顶点语言的最低要求(使用 highp 可以获得最大的范围和精度,但是也有可能会降低运行速度)。 |
mediump | 范围和精度介于 highp 和 lowp 之间(通常用于储存高范围的颜色数据和低精度的几何数据)。 |
lowp | 范围和精度比 meduimp 小,但是足以储存所有 8-bit 颜色数据。 |
// 变量声明
lowp float a;
mediump vec2 p;
highp mat4 m;
// 函数声明(返回值和参数)也适用
highp float foo(highp param);
默认精度限定符(Default Precision Qualifiers)
我们可以用 precision
关键字来声明指定类型的默认精度:
// 声明方式
precision 精度限定符 类型;
// 示例:声明 float 类型的默认精度为 highp
precision highp float;
在「未主动声明精度」的情况下,在顶点着色器中有以下默认精度声明:
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
而在片段着色器中有以下默认精度声明:
precision mediump int;
precision lowp sampler2D;
precision lowp samplerCube;
在片段着色器中浮点类型、浮点向量和浮点矩阵都没有默认的精度,所以使用时就必须声明其精度,或者事先声明默认精度!
另外,上面没有提到的类型都没有默认精度!
相关资料
「OpenGL ES Registry(OpenGL ES 资料页)」
https://www.khronos.org/registry/OpenGL/index_es.php
「OpenGL ES 3 Quick Reference Card(OpenGL ES 3 快速参考卡片)」
https://www.khronos.org/files/opengles3-quick-reference-card.pdf
「GLSL ES Specification 3.00(GLSL ES 规范 3.0)」
https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf
「OpenGL ES 3.0 Online Reference Pages(OpenGL ES 3.0 在线参考页)」
https://www.khronos.org/registry/OpenGL-Refpages/es3.0/
更多分享
公众号
菜鸟小栈
我是陈皮皮,这是我的个人公众号,专注但不仅限于游戏开发、前端和后端技术记录与分享。
每一篇原创都非常用心,你的关注就是我原创的动力!
Input and output.