当前位置:众信范文网 >专题范文 > 公文范文 > 浅述基于WebGL的三维动画绘制

浅述基于WebGL的三维动画绘制

时间:2022-10-27 16:40:05 来源:网友投稿

摘 要 在移动web页面应用中,我们可以通过WebGL的上下文对象很轻松地进行3D动画的绘制工作。WebGL的上下文对象使用一个drawScene的函数来绘制图形。在制作动画时,每一次重绘都需要调用该函数,然后使用不同的方法来重绘图形。对于WebGL技术来说,一个不可回避的问题就是浏览器的支持,建议采用渐进式的支持方法。

关键词 WebGL;上下文对象;3D

WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡在浏览器里面更流畅地展示3D场景和模型了。在移动web页面应用中,我们可以通过WebGL的上下文对象很轻松地进行3D动画的绘制工作。在X点出绘制一个图形时,下一次绘制动画时在Y点处重新绘制该图形,再下一次绘制动画时在Z点处重新绘制该图形,以此类推。可能有人会问,为什么重绘的工作原理是每一次都要重新绘制图形呢?其实原因是WebGL的上下文對象使用一个drawScene的函数来绘制图形。在制作动画时,每一次重绘都需要调用该函数,然后使用不同的方法来重绘图形。

接下来,我们通过一个实例来看一下如何使用WebGL的上下文对象来绘制三维动画。在这个实例中,我们主要实现的功能是在网页中分别绘制一个有颜色的并且具有3D效果的三角形和矩形。

1 首先,设置调用WebGL的脚本代码的语句

通过canvas设置一块绘图区域主要的代码如下:

2 接下来编写JavaScript脚本代码

(1)创建WebGL上下文对象,定义函数initGL,并初始化WebGL。

function initGL(canvas)

{

try

{

gl = canvas.getContext(“experimental-webgl”);

gl.viewportWidth = canvas.width;

gl.viewportHeight = canvas.height;

}

catch (e)

{

}

if (!gl)

alert(“抱歉,您不能初始化WebGL。”);

}

(2)编写创建渲染器getShader。

function getShader(gl, id)

{

var shaderScript = document.getElementById(id);

if (!shaderScript)

return null;

var str =””;

var k = shaderScript.firstChild;

while (k)

{

if (k.nodeType==3)

str+= k.textContent;

k = k.nextSibling;

}

var shader;

if (shaderScript.type==”x-shader/x-fragment”)

shader = gl.createShader(gl.FRAGMENT_SHADER);

else if (shaderScript.type==”x-shader/x-vertex”)

shader = gl.createShader(gl.VERTEX_SHADER);

else

return null;

gl.shaderSource(shader,str);

gl.compileShader(shader);

if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS))

{

alert(gl.getShaderInfoLog(shader));

return null;

}

return shader;

}

(3)定义函数mvPushMatrix将视图-模型矩阵保存在堆栈中。

function mvPushMatrix()

{

var copy = mat4.create();

mat4.set(mvMatrix, copy);

mvMatrixStack.push(copy);

}

(4)定义mvPopMatrix取出堆栈中保存的视图。

function mvPopMatrix()

{

if (mvMatrixStack.length == 0)

throw “Invalid popMatrix!”;

mvMatrix = mvMatrixStack.pop();

}

function setMatrixUniforms()

{

gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);

gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);

}

var triangleVertexPositionBuffer;

var triangleVertexColorBuffer;

var squareVertexPositionBuffer;

var squareVertexColorBuffer;

由此可见,函数mvPushMatrix的作用是将当前的视图-模型矩阵保存在堆栈中[1]。

(5)定义函数initBuffers,初始化缓冲区。

function initBuffers()

{

triangleVertexPositionBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

var vertices =

[

0.0, 1.0, 0.0,

-1.0, -1.0, 0.0,

1.0, -1.0, 0.0

];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

triangleVertexPositionBuffer.itemSize = 3;

triangleVertexPositionBuffer.numItems = 3;

triangleVertexColorBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);

var colors =

[

1.0, 0.0, 0.0, 1.0,

0.0, 1.0, 0.0, 1.0,

0.0, 0.0, 1.0, 1.0

];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

triangleVertexColorBuffer.itemSize = 4;

triangleVertexColorBuffer.numItems = 3;

squareVertexPositionBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);

//使用JavaScript列表定义一个矩形的一组顶点信息

vertices =

[

1.0, 1.0, 0.0,

-1.0, 1.0, 0.0,

1.0, -1.0, 0.0,

-1.0, -1.0, 0.0

];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

//緩冲区中存放四个顶点信息,每个顶点由三个数据(三维)构成

squareVertexPositionBuffer.itemSize = 3;

squareVertexPositionBuffer.numItems = 4;

squareVertexColorBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);

colors = []

for (var i=0; i < 4; i++)

{

colors = colors.concat([0.5, 0.5, 1.0, 1.0]);

}

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

squareVertexColorBuffer.itemSize = 4;

squareVertexColorBuffer.numItems = 4;

}

var rTri = 0;

var rSquare = 0;

(6)定义绘制图形的函数drawScene[2]。

function drawScene()

{

gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

mat4.identity(mvMatrix);

mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);

mvPushMatrix();

mat4.rotate(mvMatrix, degToRad(rTri), [0, 1, 0]);

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);

gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

setMatrixUniforms();

gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);

mvPopMatrix();

mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);

mvPushMatrix();

mat4.rotate(mvMatrix, degToRad(rSquare), [1, 0, 0]);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);

/*通知WebGL缓冲区中存放的顶点位置信息将被作为矩形各顶点位置信息来使用,每个矩形使用三个数据(三维信息)*/

gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);

gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

setMatrixUniforms();

gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);

mvPopMatrix();

}

function degToRad(degrees) {

return degrees * Math.PI / 180;

}

在使用WebGL上下文对象进行3D图形的绘制时,需要告诉WebGL上下文对象当前图形的绘制位置及旋转角度,而当前图形的绘制位置及旋转角度都被保存在模型-视图矩阵中,因此,mat4.rotate方法的作用就比较明显了,该方法的书写代码类似于代码:mat4.rotate(mvMatrix,degToRad(rTri),[0,1,0]);

其中mvMatrix表示视图-模型矩阵,该代码的含义为:将视图-模型矩阵中的旋转角度围绕垂直方向(参数为[0,1,0])旋转rTi度。因为在WebGL API中,使用弧度来制定旋转角度,所以使用degToRad函数将角度转变为弧度,该函数代码如下所示:

Function degToRad(degrees) {

Return degrees *Math.PI/180;

}

(7)定义函数webGLStart绘制3D图形,此函数调用了tick函数,在tick函数中调用drawScene函数来绘制图形[3]。

function webGLStart()

{

var canvas = document.getElementById(“canvas1”);

initGL(canvas);

initShaders();

initBuffers();区

gl.clearColor(0.0, 0.0, 0.0, 1.0);

gl.enable(gl.DEPTH_TEST);

tick();}

(8)定义函数tick,在此函数中使用WebGL API中的动画功能,每一次使用不同的方法来绘制图形,同时要在该函数中制定一个每次调用drawScene函数重绘图形的间隔时间。

function tick()

{

requestAnimFrame(tick);

drawScene();

animate();

}

var lastTime = 0;

(9)定义函数animate设置动画参数。

function animate()

{

var timeNow = new Date().getTime();

if (lastTime != 0)

{

var elapsed = timeNow - lastTime;

rTri += (90 * elapsed) / 1000.0;

rSquare += (75 * elapsed) / 1000.0;

}

lastTime = timeNow;

}

到此为止,使用WebGL上下文对象绘制的三维动画制作完毕[4]。效果如下图所示:

3 关于浏览器支持的问题

对于WebGL技术来说,一个不可回避的问题就是浏览器的支持,虽然IE已经开始支持WebGL了,但很多用户的浏览器可能还不支持。所以建议开发者采用渐进式的支持方法,即给不同的浏览器不同的版本,以确保最先进的浏览器用户获得最好体验,而低版本浏览器用户也能获得良好的效果。

参考文献

[1] 于坤,周大庆.JavaScript基础与案例开发详解[M].北京:清华大学出版社,2009:57.

[2] 張亚飞,高红霞.jQuery全能权威指南:JQuery Core+JQuery Plugin+JQuery Ul+Query[M].北京:清华大学出版社,2012:41-55.

[3] 王翠萍.移动Web开发从入门到精通:基于HTML5+jQuery Mobile+PhoneGap[M].北京:中国铁道出版社,2015:78.

[4] Jon Duckett.JavaScript & jQuery交互式Web前端开发[M].北京:清华大学出版社,2014:17.

推荐访问: 绘制 三维动画 WebGL