• WebGL笔记:矩阵的变换之平移的实现


    矩阵的变换

    变换

    • 变换有三种状态:平移旋转缩放
    • 当我们变换一个图形时,实际上就是在移动这个图形的所有顶点。
    • 解释
      • webgl 要绘图的话,它是先定顶点的,就比如说我要画个三角形,那它会先把这三角形的三个顶点定出来。
      • 然后它再考虑以什么样的方式去绘制这个三角形, 就比如说在 gl.drawArrays(gl.TRIANGLES, 0, 3) 这个方法
        • 第一个参数是 TRIANGLES,让它画一个独立三角形,我依次连接这三个点,然后逐片元给它们填充颜色
        • 接下来我就可以对三角形进行变换操作了,比如:旋转,缩放,平移。
        • 我在做这三种操作的时候,实际上就是改变了三角形的顶点位置

    平移

    • 对图形的平移,就是对图形所有顶点的平移

    • 举个简单的例子

      • 就比如说已知点p的位置是(x,y,z)
      • 那我要对它进行一个相对的移动,
      • 移动的三个分量分别是 tx, ty, tz, 那么求它移动完之后的位置 p’ (x’, y’, z’)
      • 只要让它这三个分量做加法就可以了
    • 即,如下图

      x'=x+tx
      y'=y+ty
      z'=z+tz
      
      • 1
      • 2
      • 3

    • 如果上面这个图形中并非只有一个顶点,而是三个顶点或者更多,那么所有的顶点也是按同样的原理去进行位移的
    • 就比如下面这个图这个三角形在位移的时候啊,其实上也就是它的所有顶点去做一个相对的位移

    向量的加法

    • 在实际的编码中,要有一个向量的概念。
    • 就比如说 (x,y,z) 这三个量可以构成一个三维点位
    • 我们可以说它是一个顶点位置,也可以说它是一个向量, 至于这个 (x,y,z) 到底是什么?我们要看它是要做什么的
    • 就比如说我把点p(x,y,z)作为点位的时候,那它就是个点
    • 如果我把p的移动距离 tx, ty, tz 封装成一个对象 pt(tx,ty,tz), 那么 pt 就是一个向量,一个为点p 指明移动方向和距离的向量
    • 那么,点 p 的移动结果 p’ 就可以这么写:p’ = p + pt
    • 由此可知,顶点的位移,就是向量的加法

    编写向量加法代码

    • 在GLSLES语言里,是直接可以进行向量运算的,下面是顶点着色器里的代码:

      attribute vec4 a_Position;
      vec4 translation = vec4(0, 0.2, 0, 0);
      void main() {
          gl_Position = a_Position + translation;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • a_Position 是原始点位,属于attribute 变量
      • translation 是顶点着色器里的私有变量,没有向外部暴露,属于4维向量
      • a_Position + translation 便是着色器内的向量加法,这里是对原始点位进行位移
    • 基于对初始的这个a_Position 点位进行一个位移的话,那我可以直接让它加上一个四维的向量,就比如这里的这个translation,就是我声明的一个个四四维向量,让它直接加上即可

    • 上述 translation 是写死的 ,我们也可以把 translation 变量暴露出去,让js可以修改图形位置:

      <script id="vertexShader" type="x-shader/x-vertex">
          attribute vec4 a_Position;
          uniform vec4 u_Translation;
          void main() {
              gl_Position = a_Position + u_Translation;
          }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 在js 中修改uniform 变量的方法,我们之前已经说过:

      // 获取 uniform 变量
      const u_Translation = gl.getUniformLocation(gl.program, 'u_Translation');
      // 为 uniform 变量赋值
      gl.uniform4f(u_Translation, 0, 0.5, 0, 0);
      
      • 1
      • 2
      • 3
      • 4
    • 之后,可以加一段逐帧动画:

      let y = 0;
      !(function animate() {
          y += 0.02;
          if(y > 1) y = -1;
          gl.uniform4f(u_Translation, 0, y, 0, 0);
          gl.clear(gl.COLOR_BUFFER_BIT);
          gl.drawArrays(gl.TRIANGLES, 0, 3);
          requestAnimationFrame(animate)
      })()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9


    完整代码

    <canvas id="canvas">canvas>
    <script id="vertexShader" type="x-shader/x-vertex">
      attribute vec4 a_Position;
      uniform vec4 u_Translation;
      void main() {
          gl_Position = a_Position + u_Translation;
      }
    script>
    <script id="fragmentShader" type="x-shader/x-fragment">
      void main() {
          gl_FragColor = vec4(1.0,1.0,0.0,1.0);
      }
    script>
    <script type="module">
      // 这里参考之前博文代码
      import { initShaders } from './util.js';
    
      const canvas = document.getElementById('canvas');
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      const gl = canvas.getContext('webgl');
    
      const vsSource = document.getElementById('vertexShader').innerText;
      const fsSource = document.getElementById('fragmentShader').innerText;
      initShaders(gl, vsSource, fsSource);
    
      const vertices = new Float32Array([
        0.0, 0.1,
        -0.1, -0.1,
        0.1, -0.1
      ])
    
      const vertexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
      const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
      gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(a_Position);
    
      //获取uniform 变量
      const u_Translation = gl.getUniformLocation(gl.program, 'u_Translation');
      //为uniform 变量赋值
      gl.uniform4f(u_Translation, 0, 0.5, 0, 0);
    
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
    
      let y = 0
      !(function animate() {
        y += 0.02;
        if (y > 1) y = -1;
        gl.uniform4f(u_Translation, 0, y, 0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, 3);
        requestAnimationFrame(animate);
      })()
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
  • 相关阅读:
    Kafka详解
    Linux | 性能问题排查
    The 19th Zhejiang Provincial Collegiate Programming Contest
    支持券商的量化接口怎么使用python来执行交易过程?
    查找用户账户禁用
    SELinux
    金蝶云星空各种部署架构及适用场景分享
    h264编码流程分析
    JavaWeb学习-监听器
    centos8 安装 时序数据库 TimescaleDB
  • 原文地址:https://blog.csdn.net/Tyro_java/article/details/134043065