0%

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

前言

在上一篇文章中我们学习了 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/


传送门

微信推文版本

个人博客:菜鸟小栈

开源主页:陈皮皮

Eazax-CCC 游戏开发脚手架


更多分享

为什么选择使用 TypeScript ?

高斯模糊 Shader

一文看懂 YAML


公众号

菜鸟小栈

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

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

Input and output.

欢迎关注我的其它发布渠道