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

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

相关推荐
小彭努力中2 天前
20. gui调试3-下拉菜单、单选框
前端·3d·webgl
还是大剑师兰特2 天前
webGL 综合教程100+【目录】
webgl·webgl教程·webgl 示例
战术摸鱼大师2 天前
OpenGL(四) 纹理贴图
贴图·opengl
ansondroider3 天前
Android MediaPlayer + GLSurfaceView 播放视频
android·opengl·mediaplayer·glsurfaceview
xiangshangdemayi5 天前
WebGL系列教程八(GLSL着色器基础语法)
webgl·基础·shader·着色器·语法·glsl
wjs04065 天前
WebGL入门:将3D世界带入网页的魔法
javascript·3d·webgl·前端开发
xiangshangdemayi5 天前
WebGL系列教程六(纹理映射与立方体贴图)
webgl·贴图·uv·立方体·纹理坐标·纹理映射
玫瑰花店6 天前
OpengGL教程(三)---使用VAO和VBO方式绘制三角形
c++·ubuntu·计算机视觉·cmake·opengl
刘好念8 天前
[OpenGL]使用OpenGL绘制三角形
c++·opengl
refineiks8 天前
three.js使用3DTilesRendererJS加载3d tiles数据
前端·3d·图形渲染·webgl