鍍金池/ 教程/ HTML/ WebGL 2D 圖像旋轉(zhuǎn)
WebGL 文本 HTML
WebGL 文本 Canvas 2D
WebGL 2D 圖像旋轉(zhuǎn)
WebGL 圖像處理(續(xù))
WebGL 2D 矩陣
WebGL 繪制多個(gè)東西
WebGL 圖像處理
WebGL 2D 圖像轉(zhuǎn)換
WebGL 3D 透視
WebGL 是如何工作的
WebGL 文本 紋理
WebGL 2D 圖像伸縮
WebGL 場(chǎng)景圖
WebGL 3D 攝像機(jī)
WebGL 文本 使用字符紋理
WebGL 正交 3D
WebGL 基本原理
WebGL - 更少的代碼,更多的樂(lè)趣
WebGL 著色器和 GLSL

WebGL 2D 圖像旋轉(zhuǎn)

首先我要承認(rèn)下我不是很清楚如何講解這個(gè)讓它看起來(lái)更容易理解,但是,不管怎么樣,我想盡力嘗試下。首先,我想介紹下什么叫做“單位圓”。你如果還記得高中數(shù)學(xué)中(不要睡著了!)一個(gè)圓又一個(gè)半徑。半徑指的是從圓心到圓的圓邊的距離。單位圓指的是它的半徑是 1.0。

如下是一個(gè)單位圓:

打開(kāi)上面的鏈接之后,你可以拖動(dòng)圓環(huán)上面的小圓,接著 X 和 Y 的值也會(huì)隨之發(fā)生變化。這個(gè)左邊值表示的是圓環(huán)上的點(diǎn)。在圓上的最高點(diǎn)處,Y 為 1 和 X 為 0。在最右的位置時(shí) X 為 1 和 Y 為 0。

如果你還記得基礎(chǔ)的三年級(jí)數(shù)學(xué),把某個(gè)數(shù)乘以 1 以后結(jié)果仍然是該數(shù)。那么 123*1 = 123。相當(dāng)基礎(chǔ)對(duì)吧?那么半徑為 1.0 的單位圓也是一種形式的 1。它是一種旋轉(zhuǎn)的 1。因此你可以將這個(gè)單位圓與某物相乘,它執(zhí)行的操作和乘以 1 類(lèi)似,除了一些奇異的事情發(fā)生改變這種方式。

我們將從單位圓上得到任何點(diǎn)的 X 和 Y 值,接著將他們乘以上一節(jié)示例中的幾何圖形。

如下是更新渲染器:

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;

uniform vec2 u_resolution;
uniform vec2 u_translation;
uniform vec2 u_rotation;

void main() {
 // Rotate the position
vec2 rotatedPosition = vec2(
 a_position.x * u_rotation.y + a_position.y * u_rotation.x,
 a_position.y * u_rotation.y - a_position.x * u_rotation.x);

// Add in the translation.
vec2 position = rotatedPosition + u_translation;

接著修改 JavaScript 代碼,這樣我們就可以傳遞上面的兩個(gè)參數(shù):

...
  var rotationLocation = gl.getUniformLocation(program, "u_rotation");
  ...
  var rotation = [0, 1];
  ..
  // Draw the scene.
  function drawScene() {
    // Clear the canvas.
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Set the translation.
    gl.uniform2fv(translationLocation, translation);

    // Set the rotation.
    gl.uniform2fv(rotationLocation, rotation);

    // Draw the rectangle.
    gl.drawArrays(gl.TRIANGLES, 0, 18);
  }

如下是代碼運(yùn)行的結(jié)果。拖動(dòng)單位圓上的小環(huán)使圖形進(jìn)行旋轉(zhuǎn)或者拖動(dòng)滑動(dòng)條使圖形進(jìn)行移動(dòng)。

為什么上面的代碼能夠起作用?首先,讓我們看下數(shù)學(xué)公式:

rotatedX = a_position.x * u_rotation.y + a_position.y * u_rotation.x;
rotatedY = a_position.y * u_rotation.y - a_position.x * u_rotation.x;

假設(shè)你有一個(gè)矩形,并且你想旋轉(zhuǎn)它。在你把它旋轉(zhuǎn)到右上角 (3.0,9.0) 這個(gè)位置之前。我們先在單位圓中選擇一個(gè)從 12 點(diǎn)鐘的位置順時(shí)針偏移 30 度的點(diǎn)。

http://wiki.jikexueyuan.com/project/webgl/images/clockwise_30_degree.png" alt="30 degrees clockwise from 12 o'clock " />

在圓上那個(gè)位置的點(diǎn)的坐標(biāo)為 0.50 和 0.87:

3.0 * 0.87 + 9.0 * 0.50 = 7.1
9.0 * 0.87 - 3.0 * 0.50 = 6.3

那剛剛好是我們需要的位置:

http://wiki.jikexueyuan.com/project/webgl/images/rotate_rectangle.png" alt="rotate rectangle" />

旋轉(zhuǎn) 60 度和上面的操作一樣:

http://wiki.jikexueyuan.com/project/webgl/images/clockwise_60_degree.png" alt="rotate 60 degrees" />

圓上面的位置的坐標(biāo)是 0.87 和 0.50:

3.0 * 0.50 + 9.0 * 0.87 = 9.3
9.0 * 0.50 - 3.0 * 0.87 = 1.9

你可以發(fā)現(xiàn)當(dāng)我們順時(shí)針向右旋轉(zhuǎn)那個(gè)點(diǎn)時(shí),X 的值變得更大而 Y 的值在變小。如果接著旋轉(zhuǎn)超過(guò) 90 度,X 的值將再次變小而 Y 的值將變得更大。這個(gè)形式就能夠達(dá)到旋轉(zhuǎn)的目的。

圓環(huán)上的那些點(diǎn)還有另外一個(gè)名稱(chēng)。他們被稱(chēng)作為 sine 和 cosine。因此,對(duì)任意給定的角度,我們就只需查詢(xún)它所對(duì)應(yīng)的 sine 和 cosine 值:

function printSineAndCosineForAnyAngle(angleInDegrees) {
  var angleInRadians = angleInDegrees * Math.PI / 180;
  var s = Math.sin(angleInRadians);
  var c = Math.cos(angleInRadians);
  console.log("s = " + s + " c = " + c);
}

如果你把上面的代碼復(fù)制粘貼到 JavaScript 控制臺(tái)中,接著輸入 printSineAndCosineForAnyAngle(30),接著你會(huì)看到輸出 s = 0.49 c = 0.87(注意:這個(gè)數(shù)字是近似值。)

如果你把上面的代碼整合在一起的話,你就可以將你的幾何體按照你想要的任何角度進(jìn)行旋轉(zhuǎn)。僅僅只需要將你需要旋轉(zhuǎn)的角度值傳給 sine 和 cosine 就可以了。

 ...
  var angleInRadians = angleInDegrees * Math.PI / 180;
  rotation[0] = Math.sin(angleInRadians);
  rotation[1] = Math.cos(angleInRadians);

如下是設(shè)置一個(gè)角度旋轉(zhuǎn)的版本。拖動(dòng)滑動(dòng)條旋轉(zhuǎn)或者移動(dòng)。