Shader 函数可视化

10,007 阅读5分钟

一、正弦余弦

正弦运动y = sin(x)

余弦运动y = cos(x)

动画演示:

通过给sin()cos()添加一些处理,可以制作出更多有趣的效果:

二、smoothstep

在两个值之间取埃尔米特插值(Hermite interpolation)link,它的值永远是 0~1。

描述:在edge0edge1之间取一个平缓的差值,在我们需要一个平滑的渐变的时候特别有用。当前值小于edge0,取值为0。当前值大于edge1,取值1。在这个区间内,取edge0edge1的差值。

适用场景1:由于它的值永远介于 0~1,edge0 和 edge1 的差值只会决定曲线的陡或平缓,所以我们可以控制他们的差值来做一些动画速度的变化。比如:

zoom(uv, smoothstep(0.0, nQuick, progress));

上面通过控制 nQuick 的值来决定 zoom 缩放速度了。

适用场景2smoothstepedge0,edge10的时候,相当于step

smoothstep(0.0, 0.0, x);

那我们怎么实现类似 step(edge, x) 的 edge 移动的效果呢,只需要这么做就一样了:

smoothstep(0.0, 0.0, x-edge);

smoothstep() 的运算同样可以制作出一些不同的变体曲线:

y = smoothstep(0.0,1.0,x) - smoothstep(1.0,  2.0, x); 

使用

float smoothstep(float edge0, float edge1, float x)  
vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x)  
vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x)  
vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x)

vec2 smoothstep(float edge0, float edge1, vec2 x)  
vec3 smoothstep(float edge0, float edge1, vec3 x)  
vec4 smoothstep(float edge0, float edge1, vec4 x)

它等同于:

genType t;  /* Or genDType t; */
t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);

可视化呈现:y = smoothstep(0.0,1.0,x);

三、clamp

将值限制在两个其他值之间。link

说明clamp()返回minValmaxVal范围内的值。返回值计算:min(max(x, minVal), maxVal)。

使用

float clamp(float x, float minVal, float maxVal)  
vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal)  
vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal)  
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)

vec2 clamp(vec2 x, float minVal, float maxVal)  
vec3 clamp(vec3 x, float minVal, float maxVal)  
vec4 clamp(vec4 x, float minVal, float maxVal)

可视化呈现:y = clamp(x,0.,1.);

四、step

通过比较两个值生成步进函数。link

说明step()通过将xedge进行比较来生成步进函数。对于返回值i,如果x[i] < edge[i]则返回0.0,否则返回1.0

适用场景step()有着一个最大的特征,那就是非黑即白。edge 表示非黑即白的边界,小于edge就是黑(0),大于edge就是白(1)。当我们这么使用时,可以判断像素点是否存在归一化坐标系里:

step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)

当它为 0 时,表示像素点在水平或垂直方向超出了边界;当它为 1 时,表示在坐标系内。当我我们把它和mix(texture2D_1, texture2D_2, step())函数一起用时,就可以得到非黑即白的两张相连的纹理图(纹理图超过边界的部分会用纹理图2取代)。

使用

float step(float edge, float x)  
vec2 step(vec2 edge, vec2 x)  
vec3 step(vec3 edge, vec3 x)  
vec4 step(vec4 edge, vec4 x)

vec2 step(float edge, vec2 x)  
vec3 step(float edge, vec3 x)  
vec4 step(float edge, vec4 x)

可视化呈现:y = step(0.5,x);

五、mod

以第二个模数计算第一个参数的值。

说明x指定要求模的值,y指定要获取模数的值。计算公式为:x - y * floor(x / y)

使用

float mod(float x, float y)  
vec2 mod(vec2 x, vec2 y)  
vec3 mod(vec3 x, vec3 y)  
vec4 mod(vec4 x, vec4 y)

vec2 mod(vec2 x, float y)  
vec3 mod(vec3 x, float y)  
vec4 mod(vec4 x, float y)

可视化呈现:y = mod(x,1.)

六、fract

计算参数的小数部分。

说明fract()返回x的小数部分。计算公式为x - floor(x)

适用场景:假如我们在一个归一化的坐标系里,fract(uv) 能够让像素点永远都在坐标系里不会超出边界。以从上往下平移作为例子,fract()可以让从上往下的平移无限循环,且首尾相连。

使用

float fract(float x)  
vec2 fract(vec2 x)  
vec3 fract(vec3 x)  
vec4 fract(vec4 x)

可视化呈现:y = fract(x)

七、floor

找到小于或等于参数的最接近的整数

说明floor()返回一个等于最小整数的值,该整数小于或等于x

使用

float floor(float x)  
vec2 floor(vec2 x)  
vec3 floor(vec3 x)  
vec4 floor(vec4 x)

可视化呈现:y = floor(x)

八、ceil

找到大于或等于参数的最近整数

说明ceil()返回一个等于最接近的整数的值,该整数大于或等于x

使用

float ceil(float x)  
vec2 ceil(vec2 x)  
vec3 ceil(vec3 x)  
vec4 ceil(vec4 x)

可视化呈现:y = ceil(x);

九、sign

提取参数的符号。

说明:如果x小于0.0,则sign()返回-1.0,如果x等于0.0,则返回0.0,如果x大于0.0,则返回+1.0

适用场景sign()用来判断运动方向非常高效,因为它的值只有 -1,0,1,所以我们可以通过

vec2 direction = vec2(0.0, 1.0);   // x, y 代表方向
sign(direction)

来判断水平和垂直的方向,正数为正方向,负数为反方向,也不用担心用户传了超出长度为1的值。

使用

float sign(float x)  
vec2 sign(vec2 x)  
vec3 sign(vec3 x)  
vec4 sign(vec4 x)

可视化呈现:y = sign(x);

十、mix

将值限制在两个其他值之间并做融合,常用于颜色混合:

说明mix()xy之间执行线性插值,使用它们之间的权重。返回值计算为x*(1-a)+y*a。可以这么理解,a决定了x,y所占的比重,比如a < 0.5,那么x的比重更大,a > 0.5y的比重更大。当 a = 0.5时,xy的比重各一半。

使用场景:我们经常会有一些动画,需要在单位时间内往返一次,比如先放大后缩小。通过以下公式可以轻松做到(scale 表示放大的倍数):

mix(scale, 1.0, 2.0 * abs(progress - 0.5))

上面的公式即可做到先放大到scale(当进度为0.5时达到最大),然后再缩小到1

使用

float mix(float x, float y, float a)  
vec2 mix(vec2 x, vec2 y, vec2 a)  
vec3 mix(vec3 x, vec3 y, vec3 a)  
vec4 mix(vec4 x, vec4 y, vec4 a)

vec2 mix(vec2 x, vec2 y, float a)  
vec3 mix(vec3 x, vec3 y, float a)  
vec4 mix(vec4 x, vec4 y, float a)

可视化呈现:y = mix(0.,1.,x);