MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

在之前静态的示例中,我们现有的代码已被配置成每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ć之前写的示例。

文档标签和贡献者

标签: 
 此页面的贡献者: Sincoyw, ZhangMenghe
 最后编辑者: Sincoyw,