• WebGL编程指南案例解析之平移和旋转的矩阵实现


    手写各种矩阵:

    //矩阵
    var vShader = `
      attribute vec4 a_Position;
      uniform mat4 u_xformMatrix;
      void main(){
        gl_Position = u_xformMatrix * a_Position;
      }
    `;
    var fShader = `
      void main(){
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
      }
    `;
    
    
    
    function main(){
      //获取canvas元素
      var canvas = document.getElementById('webgl');
      //获取webgl上下文
      var gl = getWebGLContext(canvas);
      if(!gl){
        console.log('Failed to get the rendering context for WebGL!');
        return;
      }
      //初始化着色器
      if(!initShaders(gl,vShader,fShader)){
        console.log('Failed to initialize shaders.');
        return;
      }
      var n = initVertexBuffers(gl);
      if(n < 0){
        console.log('Failed to set the positions of the vertices!');
        return;
      }
      //用指定颜色填充webgl容器,就是设置背景
      gl.clearColor(0.4, 0.5, 0.0, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
    
    
    
      /*手动写各种矩阵*/
      var ANGLE = 180.0;
      var radian = Math.PI * ANGLE / 180.0;
      var cosB = Math.cos(radian),sinB = Math.sin(radian);
      //旋转矩阵
      var transform = [
        cosB,-sinB,0.0,0.0,
        sinB,cosB,0.0,0.0,
        0.0,0.0,1.0,0.0,
        0.0,0.0,0.0,1.0
      ];
      //平移矩阵
      var transform = [
        1.0,0.0,0.0,0.5,
        0.0,1.0,0.0,0.5,
        0.0,0.0,1.0,0.0,
        0.0,0.0,0.0,1.0
      ];
      //旋转+平移矩阵
      var transform = [
        cosB,-sinB,0.0,0.5,
        sinB,cosB,0.0,0.5,
        0.0,0.0,1.0,0.0,
        0.0,0.0,0.0,1.0
      ];
      //缩放矩阵
      var Sx = 0.5,Sy = 0.5,Sz = 0.5;
      var transform = [
        Sx,0.0,0.0,0.0,
        0.0,Sy,0.0,0.0,
        0.0,0.0,Sz,0.0,
        0.0,0.0,0.0,1.0
      ];
      //将行主序矩阵转化为列主序矩阵(webgl只支持列主序矩阵)
      var xformMatrix = new Float32Array(rTc(transform));
      //至此,适用于顶点着色器的变化矩阵已经写好
    
    
      /*行主序转为列主序(webgl是列主序的)*/
      function rTc(arr){
          var size = arr.length/4;
          var newarr = [];
          for (var i = 0; i < size; i++) {
            newarr.push(arr[i]);
            newarr.push(arr[4+i]);
            newarr.push(arr[8+i]);
            newarr.push(arr[12+i]);
          }
          return newarr;
      }
    
    
    
    
      var u_xformMatrix = gl.getUniformLocation(gl.program,'u_xformMatrix');
      gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix);
      gl.drawArrays(gl.TRIANGLES,0,n);
    
      function initVertexBuffers(gl){
        var vertices =  new Float32Array([
          0.0,0.5,-0.5,-0.5,0.5,-0.5
        ]);
        var n = 3;//点的个数
    
        //创建缓冲区对象
        var vertexBuffer = gl.createBuffer();
        if(!vertexBuffer){
          console.log('Failed to create the buffer object!');
          return -1;
        }
    
        //将缓冲区对象绑定到目标ARRAY_BUFFER
        gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
        //往ARRAY_BUFFER
        gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    
        //获取shaderProgram中attribute变量‘a_Position’的地址
        var a_Position = gl.getAttribLocation(gl.program,'a_Position');
        if (a_Position < 0) {
            console.log('Failed to get the storage location of a_Position');
            return -1;
        }
        //将缓冲区对象分配给a_Position变量
        gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
        //开启着色器对缓冲区数据的访问
        gl.enableVertexAttribArray(a_Position);
        return n;
      }
    }
    
    
    main();

    利用webgl编程指南作者提供的矩阵库:

    //矩阵
    var vShader = `
      attribute vec4 a_Position;
      uniform mat4 u_xformMatrix;
      void main(){
        gl_Position = u_xformMatrix * a_Position;
      }
    `;
    var fShader = `
      void main(){
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
      }
    `;
    
    
    
    function main(){
      //获取canvas元素
      var canvas = document.getElementById('webgl');
      //获取webgl上下文
      var gl = getWebGLContext(canvas);
      if(!gl){
        console.log('Failed to get the rendering context for WebGL!');
        return;
      }
      //初始化着色器
      if(!initShaders(gl,vShader,fShader)){
        console.log('Failed to initialize shaders.');
        return;
      }
      var n = initVertexBuffers(gl);
      if(n < 0){
        console.log('Failed to set the positions of the vertices!');
        return;
      }
      //用指定颜色填充webgl容器,就是设置背景
      gl.clearColor(0.4, 0.5, 0.0, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
    
    
    
      var ANGLE = 180.0;
     
      var xformMatrix = new Matrix4();
      //设置旋转矩阵,旋转轴为(0,0,1),即Z轴
      xformMatrix.setRotate(ANGLE,0,0,1);
      xformMatrix.translate(0.5,0,0);
      //先设置旋转矩阵,在此基础上乘以平移矩阵
      //最后结果是 旋转矩阵x平移矩阵,就是先平移再旋转
    
    
      // xformMatrix.setTranslate(0.5,0,0);
      // xformMatrix.rotate(ANGLE,0,0,1);
      //先设置平移矩阵,在此基础上乘以旋转矩阵
      //最后结果是 平移矩阵x旋转矩阵,就是先旋转再平移
      gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix.elements);
      gl.drawArrays(gl.TRIANGLES,0,n);
    
    
    
      function initVertexBuffers(gl){
        var vertices =  new Float32Array([
          0.0,0.5,-0.5,-0.5,0.5,-0.5
        ]);
        var n = 3;//点的个数
    
        //创建缓冲区对象
        var vertexBuffer = gl.createBuffer();
        if(!vertexBuffer){
          console.log('Failed to create the buffer object!');
          return -1;
        }
    
        //将缓冲区对象绑定到目标ARRAY_BUFFER
        gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
        //往ARRAY_BUFFER
        gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    
        //获取shaderProgram中attribute变量‘a_Position’的地址
        var a_Position = gl.getAttribLocation(gl.program,'a_Position');
        if (a_Position < 0) {
            console.log('Failed to get the storage location of a_Position');
            return -1;
        }
        //将缓冲区对象分配给a_Position变量
        gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
        //开启着色器对缓冲区数据的访问
        gl.enableVertexAttribArray(a_Position);
        return n;
      }
    }
    
    
    main();

    在顶点着色器中,我们添加了一个矩阵参数,通过变化矩阵来改变顶点的坐标,替代了之前的复杂的运算,关于矩阵:

    矩阵运算:

    平移矩阵:

    旋转矩阵:

    注意:

    ①webGL中矩阵是列主序的,但是我们通常接触的高数中的矩阵都是行主序的,行主序的矩阵看上去也比较符合人的习惯,所以我们在这里,手写矩阵的时候,写成行主序,但是传给webGL的时候,要将其转化为列主序的,文中已经列出了我自己编写的转化函数:

    /*行主序转为列主序(webgl是列主序的)*/
      function rTc(arr){
          var size = arr.length/4;
          var newarr = [];
          for (var i = 0; i < size; i++) {
            newarr.push(arr[i]);
            newarr.push(arr[4+i]);
            newarr.push(arr[8+i]);
            newarr.push(arr[12+i]);
          }
          return newarr;
      }

    ②在矩阵库的帮助下,我们写起矩阵尤为方便,但要注意,关于set***和不加set前缀的方法的区别

    set***为一个矩阵对象初始化一个矩阵M1,多次set***的话,结果只包含最后一次set的矩阵;

    不加set的方法,在原先初始化了矩阵的矩阵基础上M1 x M2,多个的结果是M1 x M2 x M3 x......注意顺序;

    矩阵乘法不适用交换律,所以先后顺序不同的话,最终效果也会不一样,文中注释已说明。

  • 相关阅读:
    体验js之美第八课-面向对象创建和继承终结篇
    从零到一:用Phaser.js写意地开发小游戏(Chapter 3
    HTML5 进阶系列:拖放 API 实现拖放排序
    五款轻量型bug管理工具横向测评
    用原生js写一个"多动症"的简历
    HTML5中新增Javascript特性
    Angular2入门系列(五)———— 路由参数设置
    移动端真机调试实战经验
    Java经典习题44
    Java经典习题43
  • 原文地址:https://www.cnblogs.com/eco-just/p/10680025.html
Copyright © 2020-2023  润新知