在之前静态的示例中,我们现有的代码已被配置成每15毫秒就重新绘制一次WebGL的场景。但至今为止,每一次所绘制的场景都是相同的。让我们来改变这一点,使我们的正方形动起来。
在这个例子中,我们实际上对2D的正方形进行了三维旋转和移动;这证明即使我们建立的是一个2D的物体,但实际上它也是存在于3D空间中的。
旋转正方形
让我们从旋转正方形开始。首先我们需要一个变量来追踪正方形当前的旋转情况:
var squareRotation = 0.0;
现在我们需要更新 drawScene()
函数将当前的旋转状态应用于绘制正方形。在将正方形移动到初始绘制位置后,使用如下方法进行旋转:
mvPushMatrix(); mvRotate(squareRotation, [1, 0, 1]);
这段代码存储了当前模型视图矩阵,然后按照squareRotation
的值绕X轴和Z轴旋转矩阵。
绘制完成后,需要加载回之前的矩阵:
mvPopMatrix();
存储后再重加载原始矩阵的目的是:避免绘制其它图形时也受到这次旋转的影响。但在此例子中并没有绘制更多物体,所以在此这一步并没有实际意义。
为了让物体动起来,我们需要随时改变squareRotation
的值。我们可以建立一个新的变量来追踪上一次动作的时间(可以称这个变量为 lastSquareUpdateTime
),并将如下代码添加到 drawScene()
函数的末尾:
var currentTime = Date.now(); if (lastSquareUpdateTime) { var delta = currentTime - lastSquareUpdateTime; squareRotation += (30 * delta) / 1000.0; } lastSquareUpdateTime = currentTime;
这段代码用当前时间与上次动作的时间差更新 squareRotation
决定旋转的角度。
移动正方形
在绘制正方形之前,可以先将图形移动到其它位置。下面的例子展示的是非常基础的动作——当然,在实际操作中一般不会用如此奇怪的变换。
让我们用一些新的变量来追踪每个轴的偏移量:
var squareXOffset = 0.0; var squareYOffset = 0.0; var squareZOffset = 0.0;
用如下的变量来表示每个轴上的变化量:
var xIncValue = 0.2; var yIncValue = -0.4; var zIncValue = 0.3;
在之前的旋转代码中加入如下的部分:
squareXOffset += xIncValue * ((30 * delta) / 1000.0); squareYOffset += yIncValue * ((30 * delta) / 1000.0); squareZOffset += zIncValue * ((30 * delta) / 1000.0); if (Math.abs(squareYOffset) > 2.5) { xIncValue = -xIncValue; yIncValue = -yIncValue; zIncValue = -zIncValue; }
最后,将下面的代码加入 drawScene()
函数中:
mvTranslate([squareXOffset, squareYOffset, squareZOffset]);
如下所示,正方形在旋转的过程中会缩放,在画布上随机移动且相对于观测者的位置循环地拉近缩远。它看起来更像一个屏幕保护程序。
更多矩阵操作
这个例子中使用了其他一些矩阵操作,包括两个用于保存矩阵的入栈出栈函数,以及一个将矩阵旋转特定的角度的函数。代码如下:
var mvMatrixStack = []; function mvPushMatrix(m) { if (m) { mvMatrixStack.push(m.dup()); mvMatrix = m.dup(); } else { mvMatrixStack.push(mvMatrix.dup()); } } function mvPopMatrix() { if (!mvMatrixStack.length) { throw("Can't pop from an empty matrix stack."); } mvMatrix = mvMatrixStack.pop(); return mvMatrix; } function mvRotate(angle, v) { var inRadians = angle * Math.PI / 180.0; var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); multMatrix(m); }
这些函数来源于Vlad Vukićević之前写的示例。