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

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

相关推荐
凌云行者13 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者13 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
_oP_i1 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
新中地GIS开发老师2 天前
WebGIS和WebGL的基本概念介绍和差异对比
学习·arcgis·webgl
_oP_i3 天前
Unity 中使用 WebGL 构建并运行时使用的图片必须使用web服务器上的
前端·unity·webgl
凌云行者3 天前
OpenGL入门004——使用EBO绘制矩形
c++·cmake·opengl
闲暇部落4 天前
Android OpenGL ES详解——模板Stencil
android·kotlin·opengl·模板测试·stencil·模板缓冲·物体轮廓
flying robot5 天前
Three.js简化 WebGL 的使用
webgl
小彭努力中6 天前
114. 精灵模型标注场景(贴图)
前端·3d·webgl·贴图
小彭努力中6 天前
109. 工厂光源(环境贴图和环境光)
前端·深度学习·3d·webgl·贴图