ShaderToy:入门
一、概览
Shadertoy是一个基于WebGL的在线着色器编辑器平台,允许用户在浏览器中实时编写、分享和预览GLSL代码生成的图形效果。里面有好多大佬分享的用着色器写的各种效果,可以参考学习使用。
官网地址:传送门
二、特点
1.着色器语言
ShaderToy提供了片元着色器的代码入口,顶点着色器没有提供,相当于提供了一个画板,可以用数学知识在画板上绘制各种各样好玩的工具,它的顶点着色器大致能推测出来就是绘制了一个全铺满的矩形(画板)
const vertexShaderSource = `attribute vec4 a_Position;void main() {gl_Position = a_Position;}`// 创建覆盖整个canvas的矩形const vertices = new Float32Array([-1.0, 1.0,-1.0, -1.0,1.0, 1.0,1.0, -1.0])// 创建缓冲区const vertexBuffer = gl.createBuffer()gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)// 获取attribute变量的位置const a_Position = gl.getAttribLocation(program, 'a_Position')// 将缓冲区分配给a_Position变量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(a_Position)
2.强数学模式
在绘制过程中非常依赖个人的数学能力,特别是几何知识,不明白函数的曲线长啥样的话理解这个很困难,就像它的名字一样,它往往被那些数学大佬们当成一个“玩具”。
3.渲染效果
由于片元着色器可以自由发挥,大拿们用它做出来的东西都很绚丽,加上动画的话简直是个封神的存在,好多小伙伴都是因为在Shadertoy上看到的各种绚丽效果从而被吸引走上了shader的编程之路
三、入门代码
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from 0 to 1)vec2 uv = fragCoord/iResolution.xy;// Time varying pixel colorvec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));// Output to screenfragColor = vec4(col,1.0);
}
上面代码就是ShaderToy上默认的初始代码,fragColor就是原生webgl代码中的gl_FragCoord,fragCoord 就是原生webgl代码中的gl_FragColor,mainImage就相当于原生片元着色器中的main方案。
1.UV坐标系
因为不同设备的像素不一样,所以一般来说我们会把像素坐标转换成UV(纹理)坐标,不理解UV坐标的话可以看下这篇文章传送门,这样高和宽都会处于[0,1]的范围内
vec2 uv = fragCoord/iResolution.xy;
2.纠正高宽比变形
UV坐标系的范围值统一了就会出现一个新的问题,实际上往往大多数人的电脑的高宽都是不一样的,就以大多数都在用的一个高宽比1920 x 1080,高宽不一致,如果都强行把范围压缩至[0,1]范围内的话,势必会造成绘制的图形变形,所以我们选择把高宽最小的那个的最大值设为1,另外一个根据高宽比给放大(如果宽高比是 1200像素 x 1000像素,那么转换的UV坐标就是宽[0,1.2],高[0,1])。
// 从像素坐标获取归一化的UV坐标[0, 1]
vec2 uvCoord = gl_FragCoord.xy / u_Resolution;
// 计算宽高比
float aspect = u_Resolution.x / u_Resolution.y;
// 修正宽高比
vec2 uvCoord.x *= aspect;
还有一种比较优雅的写法
vec2 uvCoord = gl_FragCoord.xy/min(iResolution.y,iResolution.x);
3.中心化
上面的UV坐标的原点是左下角,但是场景平面坐标系中往往X轴负半轴,和Y轴负半轴也经常用到,所以要做一个中心化处理
vec2 centeredCoords = (2.0*gl_FragCoord.xy-iResolution.xy)/min(iResolution.y,iResolution.x);
四、常用内置方法
名称 | 描述 |
---|---|
mod(a, b) | 计算a除以b的余数,相当于取模操作。 |
step(edge, x) | 如果x小于edge,返回0;否则返回1。常用于代替if else |
smoothstep(edge0, edge1, x) | 在x、y之间进行Hermite插值,返回一个平滑过渡的值 |
min(x, y) | 返回x和y中的较小值 |
max(x, y) | 返回x和y中的较大值 |
mix(x, y, a) | 根据a的值混合x和y,返回x和y的线性插值 |
clamp(x, a, b) | 将x的值限制在a和b之间。 |
abs(x) | 返回x的绝对值 |
fwidth(x) | 计算x的变化率(斜率) |
length(x) | 返回矢量x的长度 |
五、学习资料汇总
1.webglfundamentals
2.冯乐乐博客
3.shadertoy中文教程
4.B站pdcxs
5.掘金寒璃