4-高级变换和动画基础

一、学习要点

  1. 进一步研究变化矩阵,并在此基础上制作一些简单的动画效果。
  2. 学习矩阵变换库
  3. 实现简单的动画效果。

二、平移然后旋转

本章和后续章节需要使用到一个矩阵库 cuon-matrix.js 可以到我的git项目上去下载

// 修改上一章的旋转矩阵生成方法
// 修改前
    var radian = Math.PI * ANGLE /180.0 ; //转为弧度制
    var cosB = Math.cos(radian);
    var sinB = Math.sin(radian);
    var xformMatrix = new Float32Array([
        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 u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
    gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix);
// 修改后
    var xformMatrix = new Matrix4();
    xformMatrix.setRotate(ANGLE,0,0,1);
    // 将旋转矩阵传入给顶点着色器
    var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
    gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix.elements);

Matrix4 对象支持的方法和属性如下图 微信图片_20190408162601.png

复合变换 将变换矩阵相乘 达到符合变换的效果(这种符合变换又叫模型变换 或者建模变换)

// 顶点着色器 修改了下变量名字
var VSHANER_SOURCE =
    `
     attribute vec4 a_Position;
     uniform mat4 u_ModelMatrix;
     void main() {
        gl_Position = u_ModelMatrix * a_Position;
     }`; 


// 平移+旋转 修改上面的main方法
    var xformMatrix = new Matrix4();
    xformMatrix.setRotate(ANGLE,0,0,1);
    xformMatrix.translate(Tx,0,0);
    // 将旋转矩阵传入给顶点着色器
    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    gl.uniformMatrix4fv(u_ModelMatrix,false,xformMatrix.elements);

三、动画

动画的基础: 需要不断擦除和重绘三角形,并且在每次重绘时轻微的改变其角度。 两个关键机制:

  1. 在 t0,t1,t2,t3时刻反复调用同一个函数来绘制三角形。
  2. 每次绘制之前清除上一次绘制的内容并使三角形旋转。
// 顶点着色器
var VSHANER_SOURCE =
    `
     attribute vec4 a_Position;
     uniform mat4 u_ModelMatrix;
     void main() {
        gl_Position = u_ModelMatrix * a_Position;
     }`;
// 片元着色器程序
var FSHADER_SOURCE =
    `void main() {
        gl_FragColor = vec4(1.0,0.0,0.0,1.0); // 设置颜色
    }`;

// 旋转速度
var ANGLE_STEP = 45.0;
function main() {
    let canvas = document.getElementById('webgl');
    var gl = getWebGLContext(canvas);
    if(!gl){
        console.log('error');
        return;
    }
    // 初始化着色器
    if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
        console.log('error');
        return;
    }

    //******* 设置顶点的位置********
    var n=initVertexBuffers(gl);

    if(n<0){
        console.log("error");
        return;
    }
    // 设置背景色 背景色在动画期间一直起作用
    gl.clearColor(0.0,0.0,0.0,1.0);


    // 将旋转矩阵传入给顶点着色器
    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    // 三角形当前旋转的角度
    var currentAngle = 0.0;
    var modeMatrix = new Matrix4();
    // 开始绘制三角形
    var tick = function () {
        currentAngle = animate(currentAngle); //更新旋转角度
        draw(gl,n,currentAngle,modeMatrix,u_ModelMatrix);
        requestAnimationFrame(tick); //浏览器在适当的时候调用 时间间隔不是固定的
    }
    tick();
}

function initVertexBuffers(gl) {
    var vertices = new Float32Array([
        0.0,0.3,-0.3,-0.3,0.3,-0.3
    ]);
    var n =3 ; // 点的个数
    // 创建缓冲区对象
    var vertexBuffer = gl.createBuffer();
    if(! vertexBuffer){
        console.log("error");
        return -1;
    }
    // 将缓冲区对象绑定到目标
    gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    var a_Position = gl.getAttribLocation(gl.program,'a_Position');
    // 将缓冲区对象分配给 a_Position变量
    gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
    gl.enableVertexAttribArray(a_Position);
    return n;
}


function draw(gl,n,currentAngle,modelMatrix,u_ModelMatrix) {
    modelMatrix.setRotate(currentAngle,0,0,1);
    // 将旋转矩阵传输给顶点着色器
    gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);
    // 清除canvas
    gl.clear(gl.COLOR_BUFFER_BIT);
    // 绘制三角形
    gl.drawArrays(gl.TRIANGLES,0,n);
}
var g_last = Date.now();
function animate(angle) {
    var now = Date.now();
    var elapsed = now - g_last;
    g_last = now;
    // 根据距离上次调用的时间 更新当前旋转的角度
    var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0
    return newAngle %=360;
}

总结: 复杂变换可以通过基础变化你的矩阵相乘得到。 通过反复变换和重绘图形可以生成动画效果

下一章我们学习 颜色与纹理