OpenGL
OpenGL(
GLSL
GLSL(Open
文件路径:data/databundles/shaders.zip
后缀名:.ksh(klei shader)
加载类型:SHADER
Asset("SHADER", "shaders/overheat.ksh")
基于WebGL,可直接在浏览器内运行。
https://thebookofshaders.com/edit.php
precision mediump float;
void main() {
vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
gl_FragColor = color;
}
设置浮点数精度,可选:lowp, mediump, highp
main函数
变量声明和赋值
通过gl_FragColor设置颜色
| 类型 | 描述 | 示例 |
|---|---|---|
| int | 整数 | int a = 1; |
| float | 浮点数 | float b = 1.0; | bool | 布尔值 | bool c = true; |
| vec2 | 二维向量 | vec2 d = vec2(1.0, 2.0); |
| vec3 | 三维向量 | vec3 e = vec3(1.0, 2.0, 3.0); |
| vec4 | 四维向量 | vec4 f = vec4(1.0, 2.0, 3.0, 1.0); |
| 类型 | 描述 | 示例 |
|---|---|---|
| mat2 | 2×2矩阵 | mat2 g = mat2(1.0, 2.0, 3.0, 4.0); |
| mat3 | 3×3矩阵 | mat3 h = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0); |
| mat4 | 4×4矩阵 | mat4 i = mat4(1.0, 2.0, 3.0, 4.0, ..., 13.0, 14.0, 15.0, 16.0); |
int number = 10;
float alpha = 0.5;
bool is_red = true;
vec3 red = vec3(1.0, 0.0, 0.0);
vec3 black = vec3(0.0); // 等价于vec3(0.0, 0.0, 0.0)
vec4 color = vec4(red, alpha);
float r = color[0]; // color.r, color.x
float g = color[1]; // color.g, color.y
float b = color[2]; // color.b, color.z
float a = color[3]; // color.a, color.w
vec3 rgb = color.rgb; // color.xyz
vec3 bgr = color.bgr; // color.zyx
mat4 m = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
m[0] = vec4(1.0, 0.0, 0.0, 0.0); // 第一行
m[0][0] = 0.5; // 第一行第一列
mat4 m2 = mat4(
m[0],
m[1],
vec4(0.0, 0.0, 0.0, 1.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
| 类型 | 描述 | 示例 |
|---|---|---|
| bvec2, bvec3, bvec4 | 布尔向量 | bvec2 a = bvec2(true, false); |
| ivec2, ivec3, ivec4 | 整数向量 | ivec3 b = ivec3(1, 2, 3); |
float array[3];
void main() {
array[0] = 1.0;
array[1] = 2.0;
array[2] = 3.0;
gl_FragColor = vec4(array[0], 0.0, 0.0, 1.0);
}
数组成员只能在函数内部赋值。
struct positionInfo {
vec2 coord;
float value;
};
基本用不到。
float a = 1.0;
int b = int(a);
float c = float(b);
单行注释://
多行注释:/* */
一致变量,在所有线程中保持一致 + 只读。
由CPU传给GPU,控制着色器的行为。
uniform float time;
uniform vec2 resolution;
uniform sampler2D texture;
在线编辑器里可以使用的uniform变量:
uniform float u_time; // 时间(加载后的秒数)
uniform vec2 u_resolution; // 画布尺寸(宽,高)1000x1000
uniform vec2 u_mouse; // 鼠标位置(在屏幕上哪个像素)
注意:这些变量的名字是人为指定的,在不同的平台不一致。
vec4 gl_FragCoord: 当前像素的坐标。
vec4(x, y, 0.0, 1.0)
标准坐标:vec2 gl_FragCoord.xy / resolution.xy (范围0.0–1.0)
precision mediump float;
uniform vec2 u_mouse;
void main() {
vec4 color = vec4(1.0);
gl_FragColor = color;
}
&& 与操作
|| 或操作
! 取反
优先级:! > && > ||
precision mediump float;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
vec4 color = vec4(0.0);
gl_FragColor = color;
}
if (条件1) {
// 代码1
} else if (条件2) {
// 代码2
} else {
// 代码3
}
// 如果语句只有一个,可以省略大括号
if (st.x < .5 && st.y < .5)
color = vec4(1.0, 0.0, 0.0, 1.0);
else
color = vec4(0.0, 1.0, 0.0, 1.0);
aaa = bbb; // 这句无论如何都会执行
自带的一些数学计算函数,有硬件加速,性能高。
| abs(x) | 绝对值 |
| sign(x) | 符号,返回-1.0, 0.0, 1.0 |
| min(x, y) | 最小值 |
| max(x, y) | 最大值 |
| clamp(x, minValue, maxValue) | 限制范围,等价于min(max(x, minValue), maxValue) |
| floor(x) | 向下取整 |
| ceil(x) | 向上取整 |
| fract(x) | 小数部分,等价于x - floor(x),总是返回非负值 |
| mod(x, y) | 取模,返回余数 |
| sin(a) | 正弦 |
| cos(a) | 余弦 |
| tan(a) | 正切 |
| asin(x) | 反正弦 |
| acos(x) | 反余弦 |
| atan(y, x) 或者 atan(y_over_x) | 反正切 |
| step(a, x) | 阶梯函数,判断x是否比a大,返回1.0或0.0 |
| smoothstep(a, b, x) | 平滑阶梯函数,返回0.0到1.0之间的值 |
step和smoothstep可以检测是否跨越了某个值。
precision mediump float;
uniform vec2 u_resolution;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
float y = st.x * st.x;
vec3 color = vec3(step(st.y, y));
gl_FragColor = vec4(color, 1.0);
}
部分数学计算函数可以用于vec2、vec3和vec4。
vec2 a = vec2(1.5, 2.5);
vec2 b = fract(a); // vec2(0.5, 0.5)
vec3 c = vec3(0.0, -1.0, 2.0);
vec3 d = sign(c); // vec3(0.0, -1.0, 1.0)
vec2 e = step(
vec2(0.5, 0.5),
vec2(1.0, 0.0)
);
// vec2(1.0, 0.0)
但是,不要使用if语句,<,>x,&&和||
提示1:首先计算像素和中心点的角度
提示2:注意图形的周期性,有什么函数可以处理周期?
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
vec2 offset = st - vec2(0.5);
float angle = atan(offset.y, offset.x) * 180.0 / 3.1416;
float color = step(mod(angle, 90.0), 45.0);
gl_FragColor = vec4(color);
}
返回值类型 函数名(参数) { 函数体 }
precision mediump float;
uniform vec2 u_resolution;
float rect(vec2 st, vec2 center, float size) {
float v = size * 0.5;
vec2 offset = st - center;
return step(abs(offset.x), v) * step(abs(offset.y), v);
}
float circle(vec2 st, vec2 center, float radius) {
return step(length(st - center), radius);
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
float color = 0.0;
color = max(color, rect(st, vec2(0.5, 0.5), 0.1));
color = max(color, rect(st, vec2(0.2, 0.7), 0.3));
color = max(color, circle(st, vec2(0.1, 0.1), 0.1));
color = max(color, circle(st, vec2(0.8, 0.1), 0.2));
gl_FragColor = vec4(color);
}
precision mediump float;
float data[5];
void setup() {
data[0] = 1.0;
data[1] = 2.0;
data[2] = 3.0;
data[3] = 4.0;
data[4] = 5.0;
}
void main() {
setup();
/* ... */
}
有时候,我们需要对已绘制的图形进行移动/缩放/旋转...
试试直接修改st,会发生什么?
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
float test(vec2 st) {
vec2 v = step(vec2(0.01), mod(st, 0.33));
float rect = step(0.0, st.x) * step(st.x, 0.33) * step(0.0, st.y) * step(st.y, 0.33);
return v[0] * v[1] - rect * 0.5;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
gl_FragColor = vec4(test(st));
}