概述
笔者在前面的文章主要是针对二维的静态图形进行开发;但有时候我们需要模型动起来,就像真实世界中的一切运动变化一样。场景如果不是动态的,那么可想而知,我们的世界是多么枯燥乏味。为了让我们开发的图形应用看上去更加高大上,这一节笔者将和大家一起做一个动画的例子;本节的内容用到了前面文章提到过的平移、缩放和旋转变换,如果对这方面还不是很熟悉的同学,可以参考这篇文章:原生webgl学习(三) WebGL中的矩阵运算:平移、旋转和缩放。图形动画的根本在于改变图形顶点的位置,打个比方,例如现在的你坐或站在一个位置,咱以这个位置为坐标系原点,下一刻你起身走动,你所处的位置也就发生了变化,跟着组成你身体的顶点位置也相对于坐标系发生了偏移,这种偏移并不是说你身上少了一块肉或者多了一块肉,这只是你在世界坐标系的位置发生了变化而已,如果你持续不断的在走动,就构成了我们所认知的动画,所以动画的本质还是顶点在某个坐标系内位置发生了变化,这种变化是持续不断的。如下图所示:
如果对笔者的博客上的代码编写方式还不是很熟悉请参考笔者其他的博文:原生 WebGL开发文章目录(持续更新),里面的文章对代码有详细注释和原理解释。说到这里,相信大家已经期待看见动画的效果,笔者只做了一个gif图,呈现了本文demo的动画实现过程,忽略上面的网址(一个录屏软件生成的水印)。
接下来我们一起来看一下代码,我们主要看关键功能实现的代码,如果需要完整代码,读者可以自行下载:https://gitee.com/babyogl/learnWebGL,本例代码在文件夹chapter-04中的animate-rotating.html。首先,我们先定义一些与动画相关的变量:
let translate = [100, 400];//初始平移
const TRANSLATE_STEP = 100;//平移幅度
let angle = 0;//旋转角
const ANGLE_STEP = 1.0;//旋转幅度
let scale = [1, 1];//缩放比例
其次,要将定义的平移、旋转和缩放的值传递给着色器:
let tMatrix = m3.translation(translate[0], translate[1]);
let rMatrix = m3.rotation(angle);
let sMatrix = m3.scaling(scale[0],scale[1]);
var matrix = m3.multiply(tMatrix, rMatrix);
matrix = m3.multiply(matrix, sMatrix);
接下来,实现图形旋转、平移和缩放动画的功能:
//实现旋转
let r_last = Date.now();//记录开始时间
function updateAngle(angle) {
let now = Date.now();
let elapsed = now - r_last;
r_last = now;
let newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle %= 360;
}
//实现平移
let t_last = Date.now();//记录开始时间
function updateTranslate(x, y) {
let now = Date.now();
let elapsed = now - t_last;
t_last = now;
let dx = x + elapsed * TRANSLATE_STEP / 1000;
let tx = dx;
if (tx > 800) {
tx = tx - dx;
scale[0] = 1;
scale[1] = 1;
}
let translate =[tx, y];
return translate;
}
//实现缩放
function updateSale(sx, sy) {
sx += Math.random() / 200;
sy += Math.random() / 200;
return [sx, sy];
}
最后我们通过resquestAnimationFrame功能实现持续不断的渲染功能,使场景看起来一直在动:
let animate = function() {
angle = updateAngle(angle);
translate = updateTranslate(translate[0], translate[1]);
scale = updateSale(scale[0], scale[1]);
drawScene(gl, program);
requestAnimationFrame(animate);
};
整个domo代码码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>旋转动画</title>
<style>
body {
margin: 0px;
overflow: hidden;
}
canvas {
border: 3px solid blue;
display: block;
}
</style>
</head>
<body>
<canvas id="rotating" width="1000" height="800"></canvas>
<script type="text/javascript" src="../libs/webgl-utils.js"></script>
<script type="text/javascript" src="../libs/shader.js"></script>
<script id="vShader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform mat3 u_matrix;
varying vec4 v_color;
void main()
{
vec2 position = (u_matrix * vec3(a_position, 1.0)).xy;
vec2 zeroToone = position / u_resolution;
vec2 clipSpace = zeroToone * 2.0 - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_color = vec4(gl_Position.xyz*0.5, 0.6);
}
</script>
<script id="fShader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
void main()
{
gl_FragColor = v_color.gbra;
}
</script>
<script type="text/javascript">
"use strict";
let translate = [100, 400];//初始平移
const TRANSLATE_STEP = 100;//平移幅度
let angle = 0;//旋转角
const ANGLE_STEP = 1.0;//旋转幅度
let scale = [1, 1];//缩放比例
//3*3矩阵运算
let m3 = {
identity: function() {
return [
1, 0, 0,
0, 1, 0,
0, 0, 1
]
},
translation: function(tx, ty) {
return [
1, 0, 0,
0, 1, 0,
tx, ty, 1
]
},
rotation: function(angle) {
let c = Math.cos(angle);
let s = Math.sin(angle);
return [
c, -s, 0,
s, c, 0,
0, 0, 1
]
},
scaling: function(sx, sy) {
return [
sx, 0, 0,
0, sy, 0,
0, 0, 1
]
},
multiply: function(a, b) {
let a00 = a[0 * 3 + 0];
let a01 = a[0 * 3 + 1];
let a02 = a[0 * 3 + 2];
let a10 = a[1 * 3 + 0];
let a11 = a[1 * 3 + 1];
let a12 = a[1 * 3 + 2];
let a20 = a[2 * 3 + 0];
let a21 = a[2 * 3 + 1];
let a22 = a[2 * 3 + 2];
let b00 = b[0 * 3 + 0];
let b01 = b[0 * 3 + 1];
let b02 = b[0 * 3 + 2];
let b10 = b[1 * 3 + 0];
let b11 = b[1 * 3 + 1];
let b12 = b[1 * 3 + 2];
let b20 = b[2 * 3 + 0];
let b21 = b[2 * 3 + 1];
let b22 = b[2 * 3 + 2];
return [
b00 * a00 + b01 * a10 + b02 * a20,
b00 * a01 + b01 * a11 + b02 * a21,
b00 * a02 + b01 * a12 + b02 * a22,
b10 * a00 + b11 * a10 + b12 * a20,
b10 * a01 + b11 * a11 + b12 * a21,
b10 * a02 + b11 * a12 + b12 * a22,
b20 * a00 + b21 * a10 + b22 * a20,
b20 * a01 + b21 * a11 + b22 * a21,
b20 * a02 + b21 * a12 + b22 * a22,
];
}
};//3*3矩阵
let position = [
0, -100,
150, 125,
-175, 100
];//三角形顶点位置
function main() {
//获取canvas元素,并判断浏览器是否支持webgl
let canvas = document.getElementById('rotating');
let gl = canvas.getContext('webgl', {antialias:true, depth: false});
if(!gl) {
alert("您的浏览器不支持WebGL!");
}
//创建、编译并连接着色器
let vShaderText = document.getElementById('vShader').text;
let fShaderText = document.getElementById('fShader').text;
let program = initShader(gl, vShaderText, fShaderText);
//获取着色器中相关变量的位置
program.pLocation = gl.getAttribLocation(program, 'a_position');
program.reLocation = gl.getUniformLocation(program, 'u_resolution');
program.mLocation = gl.getUniformLocation(program, 'u_matrix');
//创建缓冲区,并绑定
program.pBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, program.pBuffer);
//动画
let animate = function() {
angle = updateAngle(angle);
translate = updateTranslate(translate[0], translate[1]);
scale = updateSale(scale[0], scale[1]);
drawScene(gl, program);
requestAnimationFrame(animate);
};
animate();
}
//画图
function drawScene(gl, program) {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
gl.enableVertexAttribArray(program.pLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, program.pBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);
gl.vertexAttribPointer(program.pLocation, 2, gl.FLOAT, false, 0, 0);
gl.uniform2f(program.reLocation, gl.canvas.width, gl.canvas.height);
//平移、旋转、缩放运算
let tMatrix = m3.translation(translate[0], translate[1]);
let rMatrix = m3.rotation(angle);
let sMatrix = m3.scaling(scale[0],scale[1]);
var matrix = m3.multiply(tMatrix, rMatrix);
matrix = m3.multiply(matrix, sMatrix);
gl.uniformMatrix3fv(program.mLocation, false, matrix);
gl.drawArrays(gl.TRIANGLES, 0, position.length / 2);
}
//实现旋转
let r_last = Date.now();//记录开始时间
function updateAngle(angle) {
let now = Date.now();
let elapsed = now - r_last;
r_last = now;
let newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle %= 360;
}
//实现平移
let t_last = Date.now();//记录开始时间
function updateTranslate(x, y) {
let now = Date.now();
let elapsed = now - t_last;
t_last = now;
let dx = x + elapsed * TRANSLATE_STEP / 1000;
let tx = dx;
if (tx > 800) {
tx = tx - dx;
scale[0] = 1;
scale[1] = 1;
}
console.log(tx);
// let ty = y + elapsed * TRANSLATE_STEP / 1000;
let translate =[tx, y];
return translate;
}
//实现缩放
function updateSale(sx, sy) {
sx += Math.random() / 200;
sy += Math.random() / 200;
return [sx, sy];
}
main();
</script>
</body>
</html>
最后
以上就是孝顺西牛为你收集整理的原生webgl学习(八) WebGL实现动画:平移、缩放和旋转的全部内容,希望文章能够帮你解决原生webgl学习(八) WebGL实现动画:平移、缩放和旋转所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复