4-高级变换和动画基础
一、学习要点
- 进一步研究变化矩阵,并在此基础上制作一些简单的动画效果。
- 学习矩阵变换库
- 实现简单的动画效果。
二、平移然后旋转
本章和后续章节需要使用到一个矩阵库 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 对象支持的方法和属性如下图
复合变换 将变换矩阵相乘 达到符合变换的效果(这种符合变换又叫模型变换 或者建模变换)
// 顶点着色器 修改了下变量名字
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);
三、动画
动画的基础: 需要不断擦除和重绘三角形,并且在每次重绘时轻微的改变其角度。 两个关键机制:
- 在 t0,t1,t2,t3时刻反复调用同一个函数来绘制三角形。
- 每次绘制之前清除上一次绘制的内容并使三角形旋转。
// 顶点着色器
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;
}
总结: 复杂变换可以通过基础变化你的矩阵相乘得到。 通过反复变换和重绘图形可以生成动画效果
下一章我们学习 颜色与纹理