使用shader画直线,正弦波,余弦波

使用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;

来看看效果
在这里插入图片描述
余弦波只是替换一些对应的函数好了~

posted @ 2021-01-30 15:14  爱吃土豆丝嗯  阅读(35)  评论(0编辑  收藏  举报  来源