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

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

length

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

c 复制代码
length(vec2(3,4)) == 5

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

c 复制代码
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;
    }
}

dot

dot 函数用于计算两个向量的点积。

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

也可以表示成:

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

c 复制代码
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;
    }
 }

abs

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

c 复制代码
abs(-0.1); // 0.1
abs(1.0); // 1.0

step

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

c 复制代码
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范围内的区域。

c 复制代码
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);
}

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

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

c 复制代码
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);
}

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

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

c 复制代码
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);
}

减法减去了第二个区域

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

smoothstep

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

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

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

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

c 复制代码
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);
 }

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

c 复制代码
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);
}

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

实现一个日光效果

c 复制代码
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);
}

mix

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

c 复制代码
mix(a,b,x) // 返回a*(1-x)+b*x

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

c 复制代码
mix(0.0,1.0,0.3) // 返回0.3

clamp

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

c 复制代码
clamp(x,a,b) // 当x<a时返回a,当x>b时返回b,否则返回本身

函数图像如下:

数学函数

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

函数 描述
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) 反正切函数

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

相关推荐
魂断蓝桥66610 小时前
如何基于three.js(webgl)引擎架构,实现3D微信小游戏(第一课)
webgl·three.js·微信小游戏·three.js路径规划、三维a*算法、javascript三维导航,·three.js小游戏
康康的幸福生活19 小时前
webgl2 方法解析: getContext()
webgl
哈市雪花2 天前
相机:Camera原理讲解(使用OpenGL+QT开发三维CAD)
qt·3d·交互·相机·图形学·opengl·视角
庖丁解牛2 天前
3. Babylonjs 中获取相机方向相关
前端·webgl·游戏开发
康康的幸福生活2 天前
webgl2 方法解析: createBuffer()
前端·javascript·webgl
Cang_Wang3 天前
Android opengles深入渲染优化
opengl
康康的幸福生活3 天前
webgl2 方法解析: shaderSource()
webgl
魂断蓝桥6663 天前
如何基于three.js(webgl)引擎架构,实现3D医院、3D园区导航,3D科室路径导航
webgl·数字孪生·threejs·3d定位、三维室内定位、3d建筑·three.js路径规划、三维a*算法、javascript三维导航,·3d医院·3d导航·园区导航
康康的幸福生活13 天前
webgl2 方法解析: SCISSOR_TEST
javascript·webgl
魂断蓝桥66614 天前
如何基于three.js(webgl)引擎架构,实现3D机房园区,数据中心消防系统
webgl·数字孪生·three.js·物联网3d·3d机房·、3d工厂、3d工业园区、智慧制造、智慧工业、智慧工厂·bim管理系·3d消防·消防演习模拟