在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

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

WebGL 3D 攝像機(jī)

在過去的章節(jié)里我們將 F 移動到截錐的前面,因?yàn)?makePerspective 函數(shù)從原點(diǎn)(0,0,0)度量它,并且截錐的對象從 -zNear 到 -zFar 都在它前面。

視點(diǎn)前面移動的物體似乎沒有正確的方式去做嗎?在現(xiàn)實(shí)世界中,你通常會移動你的相機(jī)來給建筑物拍照。

將攝像機(jī)移動到對象前

http://wiki.jikexueyuan.com/project/webgl/images/4.png" alt="" />

你通常不會將建筑移動到攝像機(jī)前。

將對象移動到攝像機(jī)前

http://wiki.jikexueyuan.com/project/webgl/images/5.png" alt="" />

但在我們最后一篇文章中,我們提出了一個投影,這就需要物體在 Z 軸的原點(diǎn)前面。為了實(shí)現(xiàn)它,我們想做的是把攝像機(jī)移動到原點(diǎn),然后把所有的其它物體都移動恰當(dāng)?shù)木嚯x,所以它相對于攝像機(jī)仍然是在同一個地方。

將對象移動到視圖

http://wiki.jikexueyuan.com/project/webgl/images/6.png" alt="" />

我們需要有效地將現(xiàn)實(shí)中的物體移動到攝像機(jī)的前面。能達(dá)到這個目的的最簡單的方法是使用“逆”矩陣。一般情況下的逆矩陣的計算是復(fù)雜的,但從概念上講,它是容易的。逆是你用來作為其他數(shù)值的對立的值。例如,123 的是相反數(shù)是 -123??s放比例為5的規(guī)模矩陣的逆是 1/5 或 0.2。在 X 域旋轉(zhuǎn) 30° 的矩陣的逆是一個在 X 域旋轉(zhuǎn) -30° 的矩陣。

直到現(xiàn)在我們已經(jīng)使用了平移,旋轉(zhuǎn)和縮放來影響我們的 'F' 的位置和方向。把所有的矩陣相乘后,我們有一個單一的矩陣,表示如何將 “F” 以我們希望的大小和方向從原點(diǎn)移動到相應(yīng)位置。使用攝像機(jī)我們可以做相同的事情。一旦我們的矩陣告訴我們?nèi)绾螐脑c(diǎn)到我們想要的位置移動和旋轉(zhuǎn)攝像機(jī),我們就可以計算它的逆,它將給我們一個矩陣來告訴我們?nèi)绾我苿雍托D(zhuǎn)其它一切物體的相對數(shù)量,這將有效地使攝像機(jī)在點(diǎn)(0,0,0),并且我們已經(jīng)將一切物體移動到它的前面。

讓我們做一個有一圈 'F' 的三維場景,就像上面的圖表那樣。

下面是實(shí)現(xiàn)代碼。

  var numFs = 5;
  var radius = 200;

  // Compute the projection matrix
  var aspect = canvas.clientWidth / canvas.clientHeight;
  var projectionMatrix =
      makePerspective(fieldOfViewRadians, aspect, 1, 2000);

  // Draw 'F's in a circle
  for (var ii = 0; ii < numFs; ++ii) {
    var angle = ii * Math.PI * 2 / numFs;

    var x = Math.cos(angle) * radius;
    var z = Math.sin(angle) * radius;
    var translationMatrix = makeTranslation(x, 0, z);

    // Multiply the matrices.
    var matrix = translationMatrix;
    matrix = matrixMultiply(matrix, projectionMatrix);

    // Set the matrix.
    gl.uniformMatrix4fv(matrixLocation, false, matrix);

    // Draw the geometry.
    gl.drawArrays(gl.TRIANGLES, 0, 16 * 6);
  }

就在我們計算出我們的投影矩陣之后,我們就可以計算出一個就像上面的圖表中顯示的那樣圍繞 ‘F’ 旋轉(zhuǎn)的攝像機(jī)。

  // Compute the camera's matrix
  var cameraMatrix = makeTranslation(0, 0, radius * 1.5);
  cameraMatrix = matrixMultiply(
      cameraMatrix, makeYRotation(cameraAngleRadians));

然后,我們根據(jù)相機(jī)矩陣計算“視圖矩陣”?!耙晥D矩陣”是將一切物體移動到攝像機(jī)相反的位置,這有效地使攝像機(jī)相對于一切物體就像在原點(diǎn)(0,0,0)。

  // Make a view matrix from the camera matrix.
  var viewMatrix = makeInverse(cameraMatrix);

最后我們需要應(yīng)用視圖矩陣來計算每個 ‘F’ 的矩陣

    // Multiply the matrices.
    var matrix = translationMatrix;
    matrix = matrixMultiply(matrix, viewMatrix);  // <=-- added
    matrix = matrixMultiply(matrix, projectionMatrix);

一個攝像機(jī)可以繞著一圈 “F”。拖動 cameraAngle 滑塊來移動攝像機(jī)。

這一切都很好,但使用旋轉(zhuǎn)和平移來移動一個攝像頭到你想要的地方,并且指向你想看到的地方并不總是很容易。例如如果我們想要攝像機(jī)總是指向特定的 ‘F’ 就要進(jìn)行一些非常復(fù)雜的數(shù)學(xué)計算來決定當(dāng)攝像機(jī)繞 ‘F’ 圈旋轉(zhuǎn)的時候如何旋轉(zhuǎn)攝像機(jī)來指向那個 ‘F’。

幸運(yùn)的是,有一個更容易的方式。我們可以決定攝像機(jī)在我們想要的地方并且可以決定它指向什么,然后計算矩陣,這個矩陣可以將把攝像機(jī)放到那里?;诰仃嚨墓ぷ髟磉@非常容易實(shí)現(xiàn)。

首先,我們需要知道我們想要攝像機(jī)在什么位置。我們將稱之為 CameraPosition。然后我們需要了解我們看過去或瞄準(zhǔn)的物體的位置。我們將把它稱為 target。如果我們將 CameraPosition 減去 target 我們將得到一個向量,它指向從攝像頭獲取目標(biāo)的方向。讓我們稱它為 zAxis。因?yàn)槲覀冎罃z像機(jī)指向 -Z 方向,我們可以從另一方向做減法 cameraPosition - target。我們將結(jié)果規(guī)范化,并直接復(fù)制到 z 區(qū)域矩陣。

+----+----+----+----+
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
+----+----+----+----+
| Zx | Zy | Zz |    |
+----+----+----+----+
|    |    |    |    |
+----+----+----+----+

這部分矩陣表示的是 Z 軸。在這種情況下,是攝像機(jī)的 Z 軸。一個向量的標(biāo)準(zhǔn)化意味著它代表了 1.0。如果你回到二維旋轉(zhuǎn)的文章,在哪里我們談到了如何與單位圓以及二維旋轉(zhuǎn),在三維中我們需要單位球面和一個歸一化的向量來代表在單位球面上一點(diǎn)。

http://wiki.jikexueyuan.com/project/webgl/images/7.png" alt="" />

雖然沒有足夠的信息。只是一個單一的向量給我們一個點(diǎn)的單位范圍內(nèi),但從這一點(diǎn)到東方的東西?我們需要把矩陣的其他部分填好。特別的 X 軸和 Y 軸類零件。我們知道這 3 個部分是相互垂直的。我們也知道,“一般”我們不把相機(jī)指向。因?yàn)椋绻覀冎滥膫€方向是向上的,在這種情況下(0,1,0),我們可以使用一種叫做“跨產(chǎn)品和“計算 X 軸和 Y 軸的矩陣。

我不知道一個跨產(chǎn)品意味著在數(shù)學(xué)方面。我所知道的是,如果你有 2 個單位向量和你計算的交叉產(chǎn)品,你會得到一個向量,是垂直于這 2 個向量。換句話說,如果你有一個向量指向東南方,和一個向量指向上,和你計算交叉產(chǎn)品,你會得到一個向量指向北西或北東自這2個向量,purpendicular 到東南亞和。根據(jù)你計算交叉產(chǎn)品的順序,你會得到相反的答案。

http://wiki.jikexueyuan.com/project/webgl/images/8.png" alt="" />

現(xiàn)在,我們有 xAxis,我們可以通過 zAxisxAxis 得到攝像機(jī)的 yAxis

http://wiki.jikexueyuan.com/project/webgl/images/9.png" alt="" />

現(xiàn)在我們所要做的就是將 3 個軸插入一個矩陣。這使得矩陣可以指向物體,從 cameraPosition 指向 target。我們只需要添加 position

+----+----+----+----+
| Xx | Xy | Xz |  0 |  <- x axis
+----+----+----+----+
| Yx | Yy | Yz |  0 |  <- y axis
+----+----+----+----+
| Zx | Zy | Zz |  0 |  <- z axis
+----+----+----+----+
| Tx | Ty | Tz |  1 |  <- camera position
+----+----+----+----+

下面是用來計算 2 個向量的交叉乘積的代碼。

function cross(a, b) {
  return [a[1] * b[2] - a[2] * b[1],
          a[2] * b[0] - a[0] * b[2],
          a[0] * b[1] - a[1] * b[0]];
}

這是減去兩個向量的代碼。

function subtractVectors(a, b) {
  return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
}

這里是規(guī)范化一個向量(使其成為一個單位向量)的代碼。

function normalize(v) {
  var length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  // make sure we don't divide by 0.
  if (length > 0.00001) {
    return [v[0] / length, v[1] / length, v[2] / length];
  } else {
    return [0, 0, 0];
  }
}

下面是計算一個 "lookAt" 矩陣的代碼。

function makeLookAt(cameraPosition, target, up) {
  var zAxis = normalize(
      subtractVectors(cameraPosition, target));
  var xAxis = cross(up, zAxis);
  var yAxis = cross(zAxis, xAxis);

  return [
     xAxis[0], xAxis[1], xAxis[2], 0,
     yAxis[0], yAxis[1], yAxis[2], 0,
     zAxis[0], zAxis[1], zAxis[2], 0,
     cameraPosition[0],
     cameraPosition[1],
     cameraPosition[2],
     1];
}

這是我們?nèi)绾问褂盟鼇硎瓜鄼C(jī)隨著我們移動它指向在一個特定的 ‘F’ 的。

  ...

  // Compute the position of the first F
  var fPosition = [radius, 0, 0];

  // Use matrix math to compute a position on the circle.
  var cameraMatrix = makeTranslation(0, 50, radius * 1.5);
  cameraMatrix = matrixMultiply(
      cameraMatrix, makeYRotation(cameraAngleRadians));

  // Get the camera's postion from the matrix we computed
  cameraPosition = [
      cameraMatrix[12],
      cameraMatrix[13],
      cameraMatrix[14]];

  var up = [0, 1, 0];

  // Compute the camera's matrix using look at.
  var cameraMatrix = makeLookAt(cameraPosition, fPosition, up);

  // Make a view matrix from the camera matrix.
  var viewMatrix = makeInverse(cameraMatrix);

  ...

下面是結(jié)果。

拖動滑塊,注意到相機(jī)追蹤一個 ‘F’。

請注意,您可以不只對攝像機(jī)使用 “l(fā)ookAt” 函數(shù)。共同的用途是使一個人物的頭跟著某人。使小塔瞄準(zhǔn)一個目標(biāo)。使對象遵循一個路徑。你計算目標(biāo)的路徑。然后你計算出目標(biāo)在未來幾分鐘在路徑的什么地方。把這兩個值放進(jìn)你的 lookAt 函數(shù),你會得到一個矩陣,使你的對象跟著路徑并且朝向路徑。