目录
6.6 利用step()、max()、abs()实现小正方形
着色器提供了一系列内置函数,所谓内置函数和内置变量一样,也就是说不用声明,就可以直接调用。比如向量点乘dot()
、向量叉乘cross()
、两点之间距离distance()
等用于数学计算的函数。
1. 和角度相关的函数
下面是一个和角度相关的函数,他们的用法我们度熟悉。
函数 | 参数 | 描述 |
sin(x) | 弧度 | 正弦函数 |
cos(x) | 弧度 | 余弦函数 |
tan(x) | 弧度 | 正切函数 |
asin(x) | 弧度 | 反正弦函数 |
acos(x) | 弧度 | 反余弦函数 |
atan(x) | 弧度 | 反正切函数 |
radians(x) | 角度 | 角度转换为弧度 |
degrees(x) | 弧度 | 弧度转换为角度 |
2. 数学函数
这类主要是对指数对数幂函数的操作。
函数 | 描述 |
pow(x,y) | x的y次方。如果x小于0,结果是未定义的。同样,如果x=0并且y<=0,结果也是未定义的。 |
exp(x) | e的x次方 |
log(x) | 计算满足x等于e的y次方的y的值。如果x的值小于0,结果是未定义的。 |
exp2(x) | 计算2的x次方 |
log2(x) | 计算满足x等于2的y次方的y的值。如果x的值小于0,结果是未定义的。 |
sqrt(x) | 计算x的开方。如果x小于0,结果是未定义的。 |
inversesqrt(x) | 计算x的开方之一的值,如果x小于等于0,结果是未定义的。 |
3. 常用函数
这里是常用函数,和js中的内置函数很像,需要牢记。
函数 | 描述 |
abs(x) | 返回x的绝对值 |
sign(x) | 如果x>0,返回1.0;如果x=0,返回0,如果x<0,返回-1.0 |
floor(x) | 返回小于等于x的最大整数值 |
ceil(x) | 返回大于等于x的最小整数值 |
fract(x) | 返回x-floor(x),即返回x的小数部分 |
mod(x, y) | 返回x和y的模 |
min(x, y) | 返回x和y的值较小的那个值。 |
max(x, y) | 返回x和y的值较大的那个值。 |
clamp(x, minVal, maxVal) | 将x值钳于minVal和maxVal之间,意思就是当x<minVal时返回minVal,当x>maxVal时返回maxVal,当x在minVal和maxVal之间时,返回x |
mix(x, y, a) | 返回线性混合的x和y,如:x*(1−a)+y*a |
step(edge, x) | 如果x < edge,返回0.0,否则返回1.0 |
smoothstep(edge0, edge1, x) | 如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。 |
4. 几何函数
这是与长度、距离、向量等相关的函数。
length(x) | 返回向量x的长度 |
distance(p0,p1) | 计算向量p0,p1之间的距离 |
dot | 向量x,y之间的点积 |
cross(x, y) | 向量x,y之间的叉积 |
normalize(x) | 标准化向量,返回一个方向和x相同但长度为1的向量 |
faceforward(N, I, Nref) | 如果Nref和I的点积小于0,返回N;否则,返回-N; |
reflect(I, N) | 返回反射向量 |
refract(I, N, eta) | 返回折射向量 |
5.内置函数参数常见形式
内置函数参数数据类型常见形式:float
、vec2
、vec3
、vec4
6.使用内置函数实现各种图形
在片元着色器(fragment.glsl)中,通过各种内置函数实现不同效果的图形。
在fragment.glsl的main()函数前声明uv值及数据精度:
precision lowp float;
varying vec2 vUv;
6.1 利用取模函数mod()达到反复渐变效果
float strength = mod(vUv.y * 10.0 , 1.0) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.2 利用step(edge, x)实现斑马线条纹效果
1)该step(edge,x)函数中,如果x < edge,返回0.0,否则返回1.0。
float strength = mod(vUv.y * 10.0 , 1.0) ;
strength = step(0.5,strength);//0.5为边界值
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
2)更改step中边界值为0.8,当strength大于0.8时返回1,否则返回0,因此黑色宽度占80%,白色占20%。代码如下:
float strength = mod(vUv.y * 10.0 , 1.0) ;
strength = step(0.8,strength);
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
3) 同理,当取vUv的x值时,则生成竖向条纹。
float strength = mod(vUv.x * 10.0 , 1.0) ;
strength = step(0.8,strength);
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
4)横竖条纹相加
float strength = step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
strength += step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
5)条纹相乘(相交位置为1,其余为0)
float strength = step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
strength *= step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6)条纹相减
float strength = step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
strength -= step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
7)方块图形
float strength = step(0.2, mod(vUv.x * 10.0 , 1.0)) ;
strength *= step(0.2, mod(vUv.y * 10.0 , 1.0)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
8)炫彩T字
float barX = step(0.4, mod(vUv.x * 10.0 - 0.2 , 1.0))*step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
float barY = step(0.4, mod(vUv.y * 10.0 , 1.0))*step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
float strength = barX+barY;
gl_FragColor = vec4(vUv,1,strength);
实现效果:
6.3 利用绝对值abs()实现中间向两边渐变
float strength = abs(vUv.x - 0.5) ;//|-0.5~0.5|=0.5-0-0.5
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.4 利用取最小值min()实现渐变
float strength =min(abs(vUv.x - 0.5), abs(vUv.y - 0.5)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.5 利用取最大值max()实现渐变效果
float strength =max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.6 利用step()、max()、abs()实现小正方形
float strength =step(0.1,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5))) ;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
反之,若中间正方型为白色,外框为黑色,则:
6.7 利用向下取整函数floor()实现条纹渐变
1)实现纵向条纹(横向渐变)
float strength = floor(vUv.x*10.0)/10.0;//水平 向下取整实现阶段性图形变化
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
2)实现横向条纹(纵向渐变)
float strength = floor(vUv.y*10.0)/10.0;//垂直
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
3)利用条纹相乘实现渐变格子
float strength = floor(vUv.x*10.0)/10.0*floor(vUv.y*10.0)/10.0;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.8 利用向上取整函数ceil()实现渐变格子
float strength = ceil(vUv.x*10.0)/10.0*ceil(vUv.y*10.0)/10.0;
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.9 利用随机函数radom()实现随机效果
随机函数虽然内置函数并未提供,但可以通过算法实现类随机效果:
在main()函数前对随机函数进行声明:
// 随机函数
float random (vec2 st) {
return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}
1)随机效果
在main()函数中对random()函数进行调用:
float strength = random(vUv);
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
2)随机格子效果
float strength = ceil(vUv.x*10.0)/10.0*ceil(vUv.y*10.0)/10.0;
strength = random(vec2(strength,strength));
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.10 使用length返回向量长度(沿半径计算长度)
float strength = length(vUv);
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
6.11 使用distance函数计算两个向量之间的距离
1)计算uv向量与(0.5,0.5)中心点之间的距离
float strength =1.0 - distance(vUv,vec2(0.5,0.5));
gl_FragColor =vec4(strength,strength,strength,1);
实现效果:
2)利用相除,实现光点效果
float strength =0.15 / distance(vUv,vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,strength);
实现效果:
3)实现十字交叉星星效果
float strength = 0.15 / distance(vec2(vUv.x,(vUv.y-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
strength += 0.15 / distance(vec2(vUv.y,(vUv.x-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,strength);
实现效果:
6.12 利用旋转函数rotate()实现旋转飞镖效果
1)同随机函数一样,虽然glsl并未提供内置函数,但可以通过三角函数实现旋转算法,在main()函数前对rotate()函数进行声明:
// 旋转函数
//(uv,旋转度数,旋转中心)
vec2 rotate(vec2 uv, float rotation, vec2 mid)
{
return vec2(
cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
);
}
2)在main()函数前声明uTime:
uniform float uTime;
3)并在main.js中对uTime进行设置:
// 创建着色器材质;
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: deepVertexShader,
fragmentShader: deepFragmentShader,
uniforms: {
// 动画时间
uTime: {
value: 0,
},
},
side: THREE.DoubleSide,
transparent: true,
});
并对uTime的值进行绑定:
const elapsedTime = clock.getElapsedTime();
shaderMaterial.uniforms.uTime.value = elapsedTime;
4) 在main()函数内实现旋转:
vec2 rotateUv = rotate(vUv,-uTime*5.0,vec2(0.5));
float strength = 0.15 / distance(vec2(rotateUv.x,(rotateUv.y-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
strength += 0.15 / distance(vec2(rotateUv.y,(rotateUv.x-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,strength);
实现效果: