从零开始的Shadertoy生活_02
02 glsl 语言:内置参数,函数与常量
在上一章中,我们已经充分了解了glsl语言与C语言的异同。这一章将接着上一章的内容,继续补充完善glsl语言的内置函数与常量。在介绍完常量过后,我们将进一步了解内置参数。
内置函数
glsl的内置函数有很多,在此无法一一列举,仅对最常用、最通用的函数进行介绍。(若想全面、深刻了解glsl语言,请参考 OpenGL相关标准 )
数学计算函数
1 | // 三角相关 |
注意事项:
- 以上所有运算均可应用于
vec,效果等同于对每一项分别操作。 - 三角函数、反三角函数默认使用弧度制。
pow函数对于负数的非整数次方返回值不定(这是Undefined Behavior)。mod函数不能用于整数,整数请用a % b计算。mod(x, y) = x - y * floor(x / y),即取模结果与y同号。minmaxclamp会返回更宽的类型,即min(float, int) -> floatmax(vec3, float) -> vec3。
1 | // 向量相关 |
注意事项:
- 叉乘
cross仅适用于vec3。 reflect和refract的I与N参数都需要归一化。reflect(I, N) = I − 2 * (N ⋅ I) * N。- 折射
refract符合斯涅耳定律,全反射时返回反射角方向。
1 | // 矩阵相关 |
注意事项:
- 仅部分高版本(GLSL 3.30+(OpenGL 3.3+))支持非方阵(如
mat2x3),但是计算消耗大于方阵,因此尽可能少使用非方阵。
以上数学函数将贯通整个 Shader 学习过程,请熟记于心(记不住也没关系,多写自然熟练)。
texture 相关纹理函数
由于纹理比较复杂,此处暂且按下不表,后面会单独开一个章节讨论纹理和缓冲(Buffer)。
常量
学过C语言的同学都知道,常量就是 const ,声明必须同时定义,一旦定义就不能修改。如果真的这么简单,那根本没必要单开一节来讨论常量
glsl中大致符合以上标准的“常量”共有3种:const #define 和 uniform , 我们一个个看。
const:真正的“常量”
和C语言中的一样,const常量是真正的“常量”,在作用域内保持值不可变。如果定义在主函数或是其他某个函数内部,那么const常量将在每次调用这个函数的时候被定义,生命周期持续到函数结束;如果定义在全局(即写在所有函数外面),const常量将仅在编译开始后定义一次,每帧不再重新定义。
1 | // 全局 const(全局只定义一次) |
#define:“常”而非“量”
和C语言中的一样,#define 是预处理器指令,在编译之前就直接做文本替换,不消耗空间,几乎不影响运行效率。所以这不是一种“量”,只是一种宏定义的别名。相比于const,#define 不会进行类型检查,也就是不会被编辑器的红色波形曲线发现,但有可能造成 Compile Error。
1 |
|
uniform:“量”而不“常”
uniform是glsl有别于C的一大特性:它用于传输从宿主程序(如 CPU)向着色器传递的运行时不可变的全局数据。换句话说,uniform常量是CPU向GPU传递数据的单向管道。uniform常量将保持在运行时不变,也就是说在同一帧内每个像素点运行主函数时保持不变且不可修改;但是在不同帧运行之前,CPU可以修改传入的uniform的值。因此,uniform常量不是真正的“常”量。一些常见的uniform常量将在下一节:内置参数中给出。
注:由于自定义uniform常量将涉及到OpenGL API在CPU端修改配置(主要是作者不会),本系列暂不考虑,仅讨论Shadertoy内制的uniform参数。
内置参数
新建一个Shadertoy在线着色器,点开代码区顶部的“着色器输入”,你会发现这些内置参数:
1 | uniform vec3 iResolution; // viewport resolution (in pixels) |
根据我们对 uniform 常量的了解,我们知道,这是每一帧CPU将要传递给GPU的数据。
- 标题: 从零开始的Shadertoy生活_02
- 作者: aaaaa
- 创建于 : 2025-06-30 15:00:00
- 更新于 : 2025-06-30 12:10:08
- 链接: https://redefine.ohevan.com/2025/06/30/从零开始的Shadertoy生活_02/
- 版权声明: 版权所有 © aaaaa,禁止转载。