Shader 入门:GLSL ES(数据类型)

在上一篇文章中我们初步了解了 GLSL ES 的基本语法,那么本篇文章就和大家一起学习 GLSL ES 的数据类型。

Let’s go!!!

上一篇:《Shader 入门:GLSL ES(简介和基本语法)》

在本系列文章中主要针对 GLSL ES 3.0 进行讲解

 

 

正文

 

数据类型

 

标量(Scalar)

标量表示只有大小没有方向的量。

 

关键字

关键字

含义

int

有符号整型(Signed Integer)

uint

无符号整型(Unsigned Integer)

float

单精度浮点型(Single Floating-Point)

bool

布尔型(Boolean)

声明并赋值:

1

2

3

4

int age = 18; // 整型

uint hello = 3u; // 无符号整型,在后面数字加 u

float pi = 3.14; // 浮点型

bool isMe = true; // 布尔型

GLSL

 

类型转换

标量类型之间可以互相转换。

  • float 类型的值转换为 intuint 时小数点后面的值将会被忽略,要注意负的 float 类型的值不能转换为 uint 类型。
  • intuintfloat 类型的值转换为 bool 类型时,00.0 将会被转换为 false,所有非零的值都会被转换为 true
  • bool 类型的值转换为 intuintfloat 类型时,false 将会被转换为 00.0true 会被转换为 11.0

我们可以使用标量类型的构造函数来进行类型转换:

1

2

3

4

5

int a = 1;

float b = float(a); // 1.0

int c = int(b); // 1

uint d = uint(c); // 1u

bool e = bool(d); // true

GLSL

当尝试将非标量值转换为标量值时,实际处理的将会是非标量值的第一个元素:

1

2

vec3 a = vec3(0.1, 0.2, 0.3);

float b = float(a); // 0.1

GLSL

 

 

向量(Vector)

在 GLSL 中向量一般用于储存顶点坐标、颜色或纹理坐标数据。

一个向量可以包含 2 到 4 个分量(Component),分量的类型也可以是以上基础类型中的任意一个,一般情况下我们使用浮点型 vecn 就已经足够了。

 

关键字

下面表格中的 n 为分量的个数

关键字

含义

举例

vecn

包含 n 个 float 类型分量的向量

vec2vec4

ivecn

包含 n 个 int 类型分量的向量

ivec2ivec4

uvecn

包含 n 个 uint 类型分量的向量

uvec2uvec4

bvecn

包含 n 个 bool 类型分量的向量

bvec2bvec4

 

创建向量

我们可以使用不同的构造函数来创建相应的向量:

1

2

3

vec2 coord = vec2(0.5, 0.5); // 含有 2 个 float 类型分量的向量

ivec3 police = ivec3(1, 1, 0); // 含有 3 个 int 类型分量的向量

bvec4 hello = bvec4(true, false, true, false); // 含有 4 个 bool 类型分量的向量

GLSL

只传入一个参数的情况下会自动将其他值也设为第一个参数:

1

vec3 three = vec3(0.1); // 等同于 vec3(0.1, 0.1, 0.1)

GLSL

也可以使用一个向量作为参数传给另一个向量构造函数:

1

2

vec2 two = vec2(0.1, 0.2);

vec3 three = vec3(two, 0.3); // vec3(0.1, 0.2, 0.3)

GLSL

而将“大”向量作为参数来创建“小”向量(降维)会自动抛弃多余的值:

1

2

vec4 four = vec4(0.1, 0.2, 0.3, 0.4);

vec3 three = vec3(four); // 等同于 vec3(0.1, 0.2, 0.3),抛弃了 0.4

GLSL

 

获取分量

通过分量名来获取向量中的第 1 到第 4 个分量,包括:

实际上所有向量都可以使用 rgbargbastpq 分量名,但是为了代码的严谨性和可读性,建议使用相应的分量名

分量名(对应第 1 - 4 个分量)

使用场景

x, y, z, w

顶点坐标向量

r, g, b, a

颜色向量

s, t, p, q

纹理坐标向量

使用 . 运算符加分量名来获取向量的分量:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 顶点坐标

vec2 coord = vec2(1.0, 0.5);

float x = coord.x; // 1.0

float y = coord.y; // 0.5

float z = coord.z; // Error! 不存在

 

// 颜色

vec4 color = vec4(0.6, 0.8, 1,0, 0.5);

float r = color.r; // 0.6

float a = color.a; // 0.5

// 纹理坐标

vec4 texCoord = vec4(0.2, 0.4, 0.6, 0.8);

float t = texCoord.t; // 0.4

float p = texCoord.p; // 0.6

GLSL

 

重组(Swizzling)

另外,你还可以使用同一组分量名的任意组合来创建一个新的向量,这一行为称作重组:

1

2

3

4

5

6

7

vec4 coord = vec4(0.1, 0.2, 0.3, 0.4);

vec2 one = coord.xx; // vec2(0.1, 0.1)

vec2 two = coord.xy; // vec2(0.1, 0.2)

vec3 three = coord.xzw; // vec3(0.1, 0.3, 0.4)

vec4 four = coord.wzyx; // vec4(0.4, 0.3, 0.2, 0.1)

vec4 boom = coord.xyzw + coord.wzyx; // vec4(0.5, 0.5, 0.5, 0.5)

vec4 hello = vec4(coord.zyx, 0.0); // vec4(0.3, 0.2, 0.1, 0.0)

GLSL

 

 

矩阵(Matrix)

一种类似于表格的复合数据类型,矩阵最多能够支持 4 列 4 行的数据,且其元素只能够为 float 类型。

 

关键字

下面表格中的 nm 皆为 2 到 4 的任意数字

关键字

含义

举例

matnxn / matn(别名)

表示一个 n n 的浮点型矩阵

mat2mat3

mat3x3

matnxm

表示一个 n m 的浮点型矩阵

mat2x3mat4x3

 

创建矩阵

使用不同的构造函数来创建相应的矩阵:

1

2

3

// 创建一个 2x2 的矩阵

mat2 two = mat2(0.1, 0.2, // 第一列

                0.3, 0.4); // 第二列

GLSL

 

 

 

 

(two)

[

0.1

0.3 0.2

0.4

]

1

2

3

4

// 创建一个 3x3 的矩阵

mat3 three = mat3(0.1, 0.2, 0.3, // 第一列

                  0.4, 0.5, 0.6, // 第二列

                  0.7, 0.8, 0.9); // 第三列

GLSL

 

 

 

 

 

 

 

 

(three)

[

0.1

0.4

0.7 0.2

0.5

0.8 0.3

0.6

0.9

]

只传入一个参数的情况下会自动补零:

1

2

mat2 two = mat2(1.0); // 等同于 mat2(1.0, 0.0, 0.0, 0.0)

mat3 three = mat3(1.0); // 等同于 mat3(1.0, 0.0, 0.0, 0.0, 0.0, 0.0)

GLSL

我们也可以向构造函数传入向量来创建矩阵:

1

2

3

4

5

6

vec2 a = vec2(1.0, 0.0);

vec2 b = vec2(0.5, 0.1);

mat2 four = mat2(a, b); // 等同于 mat2(1.0, 0.0, 0.5, 0.1)

// 创建一个 2x3 的矩阵

mat2x3 haha = mat2x3(a, 0.3,

                     b, 0.2); // 等同于 mat2x3(1.0, 0.0, 0.3, 0.5, 0.1, 0.2)

GLSL

降维操作会自动抛弃多余的元素,升维则会自动补零:

1

2

3

// 伪代码

mat3x3(mat4x4); // 保留参数的前 3 列前 3 行的元素

mat2x3(mat4x2); // 保留参数的前 2 列前 2 行的元素,第 3 行补零

GLSL

 

获取元素

可以通过 [] 操作符来获取矩阵的某个元素(下标从 0 开始):

1

2

3

4

mat3 three = mat3(0.1, 0.2, 0.3, // 第一列

                  0.4, 0.5, 0.6, // 第二列

                  0.7, 0.8, 0.9); // 第三列

float el = three[0][2]; // 获取第一列第三行的元素:0.3

GLSL

也可以通过分量名来获取元素:

1

float el = three[0].z; // 同上,获取第一列第三行的元素:0.3

GLSL

 

 

采样器(Sampler)

在 GLSL 中我们需要通过采样器来获取纹理的信息。

采样器只能在 Shader 外部的宿主语言中通过 OpenGL 的 API 来进行赋值。

 

关键字

采样器的类型较多,这里只列出了常见的几个

关键字

含义

sampler2D

用来访问 2D 纹理的句柄

sampler3D

用来访问 3D 纹理的句柄

samplerCube

用来访问立方体映射纹理的句柄

sampler2DArray

用来访问 2D 纹理数组的句柄

剩下不常用的还有 samplerCubeShadowsampler2DShadowsampler2DArrayShadowisampler2Disampler3DisamplerCubeisampler2DArrayusampler2Dusampler3DusamplerCubeusampler2DArray

采样器必须使用 uniform 关键字来修饰(关于 uniform 我们后面会说到):

1

uniform sampler2D texture;

GLSL

通过内置的 texture 函数获取颜色:

1

2

3

uniform sampler2D myTexture;

// 通过内置的 texture 函数获取 myTexture 纹理 uv_0 坐标处的颜色

vec4 color = texture(myTexture, uv_0);

GLSL

 

 

结构体(Structure)

GLSL 允许你使用 struct 关键字来自定义一个新的类型,新的自定义类型可以包含其他已经定义的类型:

1

2

3

4

5

6

7

8

9

// 定义一个名为 circle 的类型,包含一个浮点型成员和一个四维向量成员

struct circle {

    float radius;

    vec4 color;

};

// 创建一个 circle 类型的变量

circle myCircle;

// 单独给 radius 赋值

myCircle.radius = 0.5;

GLSL

定义新的结构体时可以包含已经定义的结构体,但是不能够在结构体中定义新的结构体:

1

2

3

4

5

6

7

8

9

10

// 结构体 A

struct A {

    float f;

};

// 结构体 B

struct B {

    A a; // 可

    A; // Error! 禁止匿名成员

    struct { ... }; // Error! 不可

}

GLSL

 

 

数组(Array)

GLSL 支持一维数组,只需要在变量名称后面接上一对方括号[]

数组的长度必须大于 0,可以使用字面量或者整型常量:

1

2

3

4

5

// 字面量

float values[3];

// 整型常量

const int COUNT = 3;

float values2[COUNT];

GLSL

作为函数的返回值或参数的类型:

1

2

3

4

// 返回值类型

float[5] getValues() { ... }

// 参数类型

void setValues(float[2] values) { ... }

GLSL

使用相应的构造函数初始化数组:

1

2

3

4

5

6

float a[2] = float[2](0.1, 0.2);

// 另外下面这 4 种方式是一样的

float b[3] = float[3](0.1, 0.2, 0.3);

float b[] = float[3](0.1, 0.2, 0.3);

float b[3] = float[](0.1, 0.2, 0.3);

float b[] = float[](0.1, 0.2, 0.3);

GLSL

同样通过 [] 运算符来获取数组中的元素(下标从0 开始):

1

2

float a[3] = float[3](0.1, 0.2, 0.3);

float b = a[1]; // 0.2

GLSL

通过数组的 length 函数可以获取数组的长度(int 类型):

1

2

int a[3] = int[3](1, 2, 3);

int b = a.length(); // 3

GLSL

 

 

空(void)

1

2

3

4

5

 

```glsl

void main() {

    // ...

}

VOID```

 

 

相关资料

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 Cocos 游戏开发工具包

 

https://chenpipi.cn/post/shader-quickstart-glsles-2/

 

posted @ 2023-03-11 11:12  imxiangzi  阅读(167)  评论(0编辑  收藏  举报