shader入门教程三(常用函数)

本节主要介绍 shader 中一些重要的内置函数用法。

length

length 函数用于计算向量的长度(模长),例如对于一个二维向量vec2(3,4),可以根据勾股定理求得长度

length(vec2(3,4)) == 5

shader入门教程三(常用函数)

利用length函数,我们可以绘制一个简单的圆形

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = length(st-vec2(0,0));
    if(d<0.3){
        gl_FragColor = vec4(0.0,1.0,0.0,1.0);
    } else {
        discard;
    }
}

shader入门教程三(常用函数)

dot

dot 函数用于计算两个向量的点积。
点积是两个向量相同位置的对应分量相乘后相加的结果。两个向量相乘的几何意义可以看成一个向量在另一个向量方向上的投影长度与另一个向量长度相乘。向量相乘具有如下公式

shader入门教程三(常用函数)

也可以表示成:

shader入门教程三(常用函数)

可以看出当两个向量垂直的话,其点积为0。我们可以此特性同样可以绘制一个圆

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = dot(st-vec2(-0.2,0.0),st-vec2(0.2,0.0));
    if(d<=0.0){
        gl_FragColor = vec4(0.0,1.0,0.0,1.0);
    }else{
        discard;
    }
 }

shader入门教程三(常用函数)

abs

取绝对值函数,这个很好理解。

abs(-0.1); // 0.1
abs(1.0); // 1.0

step

step 函数用于生成一个阶梯函数,它将根据阈值条件返回0或1

step(1,2) // 返回1.0,因为2>1
step(2,2) // 返回1.0,因为2=2
step(3,2) // 返回0.0,因为2<3

step函数用于边界过渡,由于只返回0和1的特性,可以使用 step 函数来代替if-else的书写,在shader中我们推荐用 step 来代替if-else,这样可以提高性能。

例如绘制一个距离y轴0.3范围内的区域。

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = dot(st-vec2(-0.2,0.0),st-vec2(0.2,0.0));
    float green = step(abs(st.x),0.3);
    gl_FragColor = vec4(0.0,green,0.0,1.0);
}

shader入门教程三(常用函数)

green 值刚好只能取0 或者 1,为0就是黑色,为1就是绿色。

我们改写一下,再增加一个到x轴0.3范围内的区域。

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = dot(st-vec2(-0.2,0.0),st-vec2(0.2,0.0));
    float green = step(abs(st.x),0.3) + step(abs(st.y),0.3);
    gl_FragColor = vec4(0.0,green,0.0,1.0);
}

shader入门教程三(常用函数)

实际上累加的效果如下图,中间区域同时满足x轴和y轴,所以值为2,只不过片元着色器对于大于1的值自动转换成1了

shader入门教程三(常用函数)

同时我们可以看到两个step叠加之后的效果,那假如相减呢?试试看

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = dot(st-vec2(-0.2,0.0),st-vec2(0.2,0.0));
    float green = step(abs(st.x),0.3) - step(abs(st.y),0.3);
    gl_FragColor = vec4(0.0,green,0.0,1.0);
}

减法减去了第二个区域
shader入门教程三(常用函数)

换成乘法试试,则是两个区域的交集。

shader入门教程三(常用函数)

smoothstep

smoothstep 函数是一个平滑阶梯插值函数,它在两个阈值之间产生平滑的过渡,

smoothstep(起始值,结束值,处在这个区域的某个值) // 返回[0,1]区域内的值

函数图像如下,当值小于起点时全是0,大于终点则全为1,在这之间则按照绿色曲线过渡,有点类似于css中动画效果

shader入门教程三(常用函数)

smoothstep 函数有很大作用,一般用于过渡或者发光效果,还有例如消除锯齿的作用。

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    gl_FragColor = vec4(0.0,smoothstep(-1.0,1.0,st.x),0.0,1.0);
 }

shader入门教程三(常用函数)

绘制一个边缘模糊圆(消除锯齿感觉)

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = length(st);
    float green = 1.0-smoothstep(0.2-0.005,0.2+0.005,d);
    gl_FragColor = vec4(0.0,green,0.0,1.0);
}

shader入门教程三(常用函数)

直观解释就是让d=0.2两边各划出0.005区域作为过渡区域来实现从绿色到黑色的渐变。

shader入门教程三(常用函数)

实现一个日光效果

void main(){
    // 将坐标归一化到[-1,1]
    vec2 st = 2.0*(gl_FragCoord.xy/vec2(1000.0,1000.0)) - vec2(1.0);
    float d = length(st);
    float v = 1.0-smoothstep(0.2,0.6,d);
    gl_FragColor = vec4(vec3(v),1.0);
}

shader入门教程三(常用函数)

mix

mix 函数在GLSL中用于执行线性混合或插值。smoothstep 是陡峭-缓慢-缓慢-陡峭过程,而 mix 函数则波澜不惊,均速上升

shader入门教程三(常用函数)

mix(a,b,x) // 返回a*(1-x)+b*x

当a=0,b=1时刚好有:

mix(0.0,1.0,0.3) // 返回0.3

clamp

clamp函数和mix有点类似,clamp函数用于将一个值限定在某个范围

clamp(x,a,b) // 当x<a时返回a,当x>b时返回b,否则返回本身

函数图像如下:

shader入门教程三(常用函数)

数学函数

当然还有很多关于数学的函数,使用起来比较简单,这里我就不一一举例子了。

函数 描述
abs(x) 返回 x 的绝对值
ceil(x) 返回不小于 x 的最小整数
floor(x) 返回不大于 x 的最大整数
round(x) 返回最接近 x 的整数
fract(x) 返回 x 的小数部分
sqrt(x) 返回 x 的平方根
pow(x, y) 返回 xy 次方
exp(x) 返回自然数e的x次方
log(x) 返回 x 的自然对数
sin(x) 正弦函数
cos(x) 余弦函数
tan(x) 正切函数
asin(x) 反正弦函数
acos(x) 反余弦函数
atan(x) 反正切函数
sin(x) 正弦函数
cos(x) 余弦函数
tan(x) 正切函数
asin(x) 反正弦函数
acos(x) 反余弦函数
atan(x) 反正切函数

下一节将使用这些函数结合距离场法来实现一些绘图

原文链接:https://juejin.cn/post/7332647780207280165 作者:Sam哥

(0)
上一篇 2024年2月8日 上午10:41
下一篇 2024年2月8日 上午10:51

相关推荐

发表回复

登录后才能评论