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

2023-09-19 10:02 更新

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

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

鏈接里有一個單位圓:

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

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

我們將從單位圓上得到任何點的 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 代碼,這樣我們就可以傳遞上面的兩個參數(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);
  }

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

為什么上面的代碼能夠起作用?首先,讓我們看下數(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è)你有一個矩形,并且你想旋轉(zhuǎn)它。在你把它旋轉(zhuǎn)到右上角 (3.0,9.0) 這個位置之前。我們先在單位圓中選擇一個從 12 點鐘的位置順時針偏移 30 度的點。

30 degrees clockwise from 12 o'clock

在圓上那個位置的點的坐標(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

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

rotate rectangle

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

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)我們順時針向右旋轉(zhuǎn)那個點時,X 的值變得更大而 Y 的值在變小。如果接著旋轉(zhuǎn)超過 90 度,X 的值將再次變小而 Y 的值將變得更大。這個形式就能夠達到旋轉(zhuǎn)的目的。

圓環(huán)上的那些點還有另外一個名稱。他們被稱作為 sine 和 cosine。因此,對任意給定的角度,我們就只需查詢它所對應(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 控制臺中,接著輸入 printSineAndCosineForAnyAngle(30),接著你會看到輸出 s = 0.49 c = 0.87(注意:這個數(shù)字是近似值。)

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

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

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


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號