使用shader画直线,正弦波,余弦波
概述
学习一下如何使用shader画直线,正弦波,余弦波,先上代码
绘制直线
let shader = {
vs: `
varying vec2 v_uv;
void main() {
v_uv = uv;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
}
`,
fs: `
varying vec2 v_uv;
uniform float u_time;
// 线的颜色
vec3 lineColor = vec3(0.0,0.0,1.0);
// 线宽度
float lineWidth = 0.01;
// 直线公式 y = ax + b
float line(float x) {
return 1.0 * x + 0.0;
}
// 正弦波函数 y=Asin(ωx+φ)+k
// A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
// (ωx+φ)——相位,反映变量y所处的状态。
// φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
// k——偏距,反映在坐标系上则为图像的上移或下移。
// ω——角速度, 控制正弦周期(单位弧度内震动的次数)。
float sinWave(float x) {
//频率
float frequency = 20.0;
//震幅
float amplitude = 0.2;
return sin(x * frequency + u_time) * amplitude + 0.5;
}
// 余弦波函数 y=Acos(ωx+φ)+k
float cosWave(float x) {
//频率
float frequency = 20.0;
//震幅
float amplitude = 0.2;
return cos(x * frequency + u_time) * amplitude + 0.5;
}
void main() {
float y = line(v_uv.x);
// step(a, b) 等价于 b >= a ? 1.0 : 0.0;
// 可以推导出若不等于0 则不是在这条直线上
float threshold = step(lineWidth, abs(y - v_uv.y));
if(threshold == 0.0) {
gl_FragColor = vec4(lineColor, 1.0);
}else{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
`,
uniform: {
u_time: {
value: 0.0
}
}
}
let geometry = new THREE.PlaneGeometry(20, 20);
let material = new THREE.ShaderMaterial({
vertexShader: shader.vs,
fragmentShader: shader.fs,
uniforms: shader.uniform,
transparent: true
})
let mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2);
scene.add(mesh);
先看下效果
可以看到我们在plane上画了一条直线,其他区域使用红色填充。
先来分析一下如何获取到这条直线的坐标
// 直线公式 y = ax + b
float line(float x) {
return 1.0 * x + 0.0;
}
我们首先可以定义出绘制直线的函数,然后根据传入的uv值来计算出对应的y值多少
float threshold = step(lineWidth, abs(y - v_uv.y));
这里使用了shader的一个内置函数step(), 此函数的作用是step(a, b) 等价于 b >= a ? 1.0 : 0.0;
我们由此可以推断出那些坐标是在这条直线上的,只要step的返回值是0的都是在这条直线上的坐标,最后我们在根据一个判断就可以画出这条直线了。
绘制正弦波
先来看一下正弦波的函数
// 正弦波函数 y=Asin(ωx+φ)+k
// A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
// (ωx+φ)——相位,反映变量y所处的状态。
// φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
// k——偏距,反映在坐标系上则为图像的上移或下移。
// ω——角速度, 控制正弦周期(单位弧度内震动的次数)。
由此我们只要根据对应的公式来写出代码即可
float sinWave(float x) {
//频率
float frequency = 20.0;
//震幅
float amplitude = 0.2;
return sin(x * frequency + u_time) * amplitude + 0.5;
}
最后我们在动画函数中调用一下u_time就可以得到一个正弦波动画
shader.uniform.u_time.value += 0.05;
来看看效果
余弦波只是替换一些对应的函数好了~