# 二维平移

在学习三维之前让我们先看一看二维

平移就是普通意义的“移动”物体。

首先我们来定义一些变量存储矩形的平移,宽,高和颜色。

const translation = [0, 0];
const width = 100;
const height = 30;
const color = [Math.random(), Math.random(), Math.random(), 1];
setRectangle(gl, translation[0], translation[1], width, height);

然后定义一个方法重绘所有东西,我们可以在更新变换之后调用这个方法。

const drawScene = () => {
  const translation = this.translation; // if change call this function
  setRectangle(gl, translation[0], translation[1], width, height); // always
  gl.drawArrays(gl.TRIANGLES, 0, 6);
};

在下方的例子中,我添加了一对滑块,当它们值改变时会更新translation[0] 和 translation[1] 并且调用drawScene方法。拖动滑块来平移矩形。

# 渲染结果1

到目前为止还不错!但是想象一下如果对一个更复杂的图形做类似操作怎么办。

假设我们想绘制一个由六个三角形组成的 ‘F’ ,像这样

接着当前的代码我们需要修改setRectangle,像这样

DETAILS
function setGeometry(gl, x, y) {
  var width = 100;
  var height = 150;
  var thickness = 30;
  gl.bufferData(
      gl.ARRAY_BUFFER,
      new Float32Array([
          // 左竖
          x, y,
          x + thickness, y,
          x, y + height,
          x, y + height,
          x + thickness, y,
          x + thickness, y + height,
 
          // 上横
          x + thickness, y,
          x + width, y,
          x + thickness, y + thickness,
          x + thickness, y + thickness,
          x + width, y,
          x + width, y + thickness,
 
          // 中横
          x + thickness, y + thickness * 2,
          x + width * 2 / 3, y + thickness * 2,
          x + thickness, y + thickness * 3,
          x + thickness, y + thickness * 3,
          x + width * 2 / 3, y + thickness * 2,
          x + width * 2 / 3, y + thickness * 3,
      ]),
      gl.STATIC_DRAW);
}

你可能发现这样做可能并不好,如果我们想绘制一个含有成百上千个线条的几何图形, 将会有很复杂的代码。最重要的是,每次绘制JavaScript都要更新所有点。

这里有个简单的方式,上传几何体然后在顶点着色器中进行平移。




 



 









attribute vec2 a_position;

uniform vec2 u_resolution;
uniform vec2 u_translation;

void main() {
   // Add in the translation.
   vec2 position = a_position + u_translation;
   // convert the position from pixels to 0.0 to 1.0
   vec2 zeroToOne = position / u_resolution;
   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;
   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;
   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}

重构一下代码,首先我们只需要设置一次几何体。

// 在缓冲存储构成 'F' 的值
function setGeometry(gl) {
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
      // 左竖
      0, 0, 30, 0, 0, 150, 0, 150, 30, 0, 30, 150,
      // 上横
      30, 0, 100, 0, 30, 30, 30, 30, 100, 0, 100, 30,
      // 中横
      30, 60, 67, 60, 30, 90, 30, 90, 67, 60, 67, 90
    ]),
    gl.STATIC_DRAW
  );
}
const translationLocation = gl.getUniformLocation(program, "u_translation");
// 顶点缓冲区
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // 1
// 设置矩形参数
setGeometry(gl); // once
// ... 
// use program
// use program
// ...
// set color
const setColor = () => {
  const color = [Math.random(), Math.random(), Math.random(), 1];
  gl.uniform4fv(colorLocation, color);
};
setColor();
this.setColor = setColor;

// set translation
const setTranslation = () => {
  const translation = this.translation;
  gl.uniform2fv(translationLocation, translation);
};
setTranslation();
this.setTranslation = setTranslation;

// draw arrays
const drawScene = () => {
  gl.drawArrays(gl.TRIANGLES, 0, 18);
};
drawScene();
this.drawScene = drawScene;

# 渲染结果2

现在当我们绘制时,WebGL几乎做了所有事情,我们做的仅仅是设置平移然后让它绘制, 即使我们的几何体有成千上万个点,主要的代码还是保持不变。

TIP

大量的运算还是得交给GPU来进行哦