持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
GLSL是什么
前言
上篇文章介绍了GLSL基本语法,然而要通过glsl告诉GPU如何渲染,不仅要用传入的变量进行操作,还要还需要内置变量来计算或告诉GPU渲染需要的参数。本文基于glsl中文手册,做了解释和精简,提供了一个案例。
内置变量
output负责告诉GPU如何渲染,而input则是GPU告诉程序一些信息。
| 变量 | output还是input | 说明 |
|---|---|---|
highp vec4 gl_Position | output | 用在顶点着色器,顶点坐标信息 |
mediump float gl_PointSize | output | 用在顶点着色器,需要绘制点的大小,(只在gl.POINTS模式下有效) |
mediump vec4 gl_FragCoord; | input | 用在片元着色器,当前点的位置 |
bool gl_FrontFacing; | input | 用在片元着色器,是否为正面片元 |
mediump vec2 gl_PointCoord; | input | 用在片元着色器,经过插值计算后的纹理坐标 |
mediump vec4 gl_FragColor; | output | 用在片元着色器,此像素点的颜色 |
mediump vec4 gl_FragData[n] | output | 用在片元着色器,当前片点的颜色,使用glDrawBuffers数据数组 |
内置函数库
glsl提供了非常丰富的函数库,供我们使用,这些功能都是非常有用且会经常用到的. 这些函数按功能区分大改可以分成7类:
通用函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 说明 |
|---|---|
| T abs(T x) | 返回x的绝对值 |
| T sign(T x) | 比较x与0的值,大于,等于,小于 分别返回 1.0 ,0.0,-1.0 |
| T floor(T x) | 返回<=x的最大整数 |
| T ceil(T x) | 返回>=等于x的最小整数 |
| T fract(T x) | 获取x的小数部分 |
| T mod(T x, T y) T mod(T x, float y) | 取x,y的余数 |
| T min(T x, T y) T min(T x, float y) | 取x,y的最小值 |
| T max(T x, T y) T max(T x, float y) | 取x,y的最大值 |
| T clamp(T x, T minVal, T maxVal) T clamp(T x, float minVal,float maxVal) | min(max(x, minVal), maxVal),返回值被限定在 minVal,maxVal之间 |
| T mix(T x, T y, T a) T mix(T x, T y, float a) | 取x,y的线性混合,x*(1-a)+y*a |
| T step(T edge, T x) T step(float edge, T x) | 如果 x<edge 返回 0.0 否则返回1.0 |
| T smoothstep(T edge0, T edge1, T x) T smoothstep(float edge0,float edge1, T x) | 如果x<edge0 返回 0.0 如果x>edge1返回1.0, 否则返回Hermite插值 |
角度&三角函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
cos、acos、tan、atan和sin一样,不再列出
| 方法 | 说明 |
|---|---|
| T radians(T degrees) | 角度转弧度 |
| T degrees(T radians) | 弧度转角度 |
| T sin(T angle) | 正弦函数,角度是弧度 |
| T asin(T x) | 反正弦函数,返回值是弧度 |
指数函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 说明 |
|---|---|
| T pow(T x, T y) | 返回x的y次幂 xy |
| T exp(T x) | 返回x的自然指数幂 ex |
| T log(T x) | 返回x的自然对数 ln |
| T exp2(T x) | 返回2的x次幂 2x |
| T log2(T x) | 返回2为底的对数 log2 |
| T sqrt(T x) | 开根号 |
| T inversesqrt(T x) | 1/√x |
几何函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
| 方法 | 说明 |
|---|---|
| float length(T x) | 返回矢量x的长度 |
| float distance(T p0, T p1) | 返回p0 p1两点的距离 |
| float dot(T x, T y) | 返回x y的点积 |
| vec3 cross(vec3 x, vec3 y) | 返回x y的叉积 |
| T normalize(T x) | 对x进行归一化,保持向量方向不变但长度变为1 |
| T faceforward(T N, T I, T Nref) | 根据 矢量 N 与Nref 调整法向量 |
| T reflect(T I, T N) | 返回 I - 2 * dot(N,I) * N, 结果是入射矢量 I 关于法向量N的 镜面反射矢量 |
| T refract(T I, T N, float eta) | 返回入射矢量I关于法向量N的折射矢量,折射率为eta |
矩阵函数:
mat可以为任意类型矩阵.
| 方法 | 说明 |
|---|---|
| mat matrixCompMult(mat x, mat y) | 将矩阵 x 和 y的元素逐分量相乘 |
向量函数:
下文中的 类型 T可以是 vec2, vec3, vec4, 且可以逐分量操作.
bvec指的是由bool类型组成的一个向量:
vec3 v3= vec3(0.,0.,0.);
vec3 v3_1= vec3(1.,1.,1.);
bvec3 aa= lessThan(v3,v3_1); //bvec3(true,true,true)
| 方法 | 说明 |
|---|---|
| bvec lessThan(T x, T y) | 逐分量比较x < y,将结果写入bvec对应位置 |
| bvec lessThanEqual(T x, T y) | 逐分量比较 x <= y,将结果写入bvec对应位置 |
| bvec greaterThan(T x, T y) | 逐分量比较 x > y,将结果写入bvec对应位置 |
| bvec greaterThanEqual(T x, T y) | 逐分量比较 x >= y,将结果写入bvec对应位置 |
| bvec equal(T x, T y) bvec equal(bvec x, bvec y) | 逐分量比较 x == y,将结果写入bvec对应位置 |
| bvec notEqual(T x, T y) bvec notEqual(bvec x, bvec y) | 逐分量比较 x!= y,将结果写入bvec对应位置 |
| bool any(bvec x) | 如果x的任意一个分量是true,则结果为true |
| bool all(bvec x) | 如果x的所有分量是true,则结果为true |
| bvec not(bvec x) | bool矢量的逐分量取反 |
样例
学习了以上内置函数和变量,我们就可以理解shadertoy的例子
shadertoy提供了如下更多内置变量以供使用
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
uniform float iTimeDelta; // render time (in seconds)
uniform int iFrame; // shader playback frame
uniform float iChannelTime[4]; // channel playback time (in seconds)
uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)
uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
uniform samplerXX iChannel0..3; // input channel. XX = 2D/Cube
uniform vec4 iDate; // (year, month, day, time in seconds)
uniform float iSampleRate; // sound sample rate (i.e., 44100)
我们来解析如下这个例子
void mainImage( out vec4 fragColor, in vec2 fragCoord )//主函数
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;//获取当前点相对位置(0.0~1.0)
// Time varying pixel color
vec3 col = 0.5 + 0.5*cos(uv.xyx+vec3(0,2,4));//根据相对位置设置rgb颜色
// Output to screen
fragColor = vec4(col,1.0);//屏幕颜色变量设置
}
结果如图