查看原文
其他

Shader 入门:GLSL ES(运算符和限定符)

文弱书生陈皮皮 菜鸟小栈 2022-06-10


前言

在上一篇文章中我们学习了 GLSL ES 的数据类型,那么本章节学习的是 GLSL ES 中运算符和限定符的内容。

上一篇:《Shader 入门: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范围和精度介于 highplowp 之间(通常用于储存高范围的颜色数据和低精度的几何数据)。
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/




更多分享


为什么选择使用 TypeScript ?


高斯模糊 Shader


一文看懂 YAML




公众号

菜鸟小栈

我是陈皮皮,这是我的个人公众号,专注但不仅限于游戏开发、前端和后端技术记录与分享。

每一篇原创都非常用心,你的关注就是我原创的动力!

Input and output.

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存