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......注意顺序;

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

猜你喜欢

转载自www.cnblogs.com/eco-just/p/10680025.html