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

鍍金池/ 教程/ HTML/ WebGL 3D 透視
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 3D 透視

在上一篇文章中,我們就學(xué)習(xí)過(guò)如何做三維,但三維沒(méi)有任何透視。它是利用一個(gè)所謂的“正交”的觀點(diǎn),它固然有其用途,但這通常不是人們說(shuō) “3D” 時(shí)他們想要的。

相反,我們需要補(bǔ)充透視。只不過(guò)什么是透視?它基本上是一種事物越遠(yuǎn)顯得更小的特征。

http://wiki.jikexueyuan.com/project/webgl/images/perspective-example.svg" alt="" />

看上面的例子,我們看到越遠(yuǎn)的東西被畫得越小。鑒于我們目前樣品的一個(gè)讓較遠(yuǎn)的物體顯得更小簡(jiǎn)單的方法就是將 clipspace X 和 Y 除以 Z。

可以這樣想:如果你有一條從(10,15)到 (20,15) 的線段,10個(gè)單位長(zhǎng)。在我們目前的樣本中,它將繪制 10 像素長(zhǎng)。但是如果我們除以 Z,例如例子中如果是 Z 是 1

10 / 1 = 10
20 / 1 = 20
abs(10-20) = 10

這將是 10 像素,如果 Z 是 2,則有

10 / 2 = 5
20 / 2 = 10
abs(5 - 10) = 5

5 像素長(zhǎng)。如果 Z = 3,則有

10 / 3 = 3.333
20 / 3 = 6.666
abs(3.333 - 6.666) = 3.333

你可以看到,隨著 Z 的增加,隨著它變得越來(lái)越遠(yuǎn),我們最終會(huì)把它畫得更小。如果我們?cè)?clipspace 中除,我們可能得到更好的結(jié)果,因?yàn)?Z 將是一個(gè)較小的數(shù)字(-1 到 +1)。如果在除之前我們加一個(gè) fudgeFactor 乘以 Z,對(duì)于一個(gè)給定的距離我們可以調(diào)整事物多小。

讓我們嘗試一下。首先讓我們?cè)诔艘晕覀兊?“fudgefactor” 后改變頂點(diǎn)著色器除以 Z 。

<script id="2d-vertex-shader" type="x-shader/x-vertex">
...
uniform float u_fudgeFactor;
...
void main() {
  // Multiply the position by the matrix.
  vec4 position = u_matrix * a_position;

  // Adjust the z to divide by
  float zToDivideBy = 1.0 + position.z * u_fudgeFactor;

  // Divide x and y by z.
  gl_Position = vec4(position.xy / zToDivideBy, position.zw);
}
</script>

注意,因?yàn)樵?clipspace 中 Z 從 -1 到 +1,我加 1 得到 zToDivideBy 從 0 到 +2 * fudgeFactor

我們也需要更新代碼,讓我們?cè)O(shè)置 fudgeFactor。

  ...
  var fudgeLocation = gl.getUniformLocation(program, "u_fudgeFactor");

  ...
  var fudgeFactor = 1;
  ...
  function drawScene() {
    ...
    // Set the fudgeFactor
    gl.uniform1f(fudgeLocation, fudgeFactor);

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

下面是結(jié)果。

如果沒(méi)有明確的把 “fudgefactor” 從 1 變化到 0 來(lái)看事物看起來(lái)像什么樣子在我們除以 Z 之前。

http://wiki.jikexueyuan.com/project/webgl/images/orthographic-vs-perspective.png" alt="" />

WebGL 在我們的頂點(diǎn)著色器中把 X,Y,Z,W 值分配給 gl_Position 并且自動(dòng)除以 W。

我們可以證明通過(guò)改變著色這很容易實(shí)現(xiàn),而不是自己做除法,在 gl_Position.w 中加 zToDivideBy

<script id="2d-vertex-shader" type="x-shader/x-vertex">
...
uniform float u_fudgeFactor;
...
void main() {
  // Multiply the position by the matrix.
  vec4 position = u_matrix * a_position;

  // Adjust the z to divide by
  float zToDivideBy = 1.0 + position.z * u_fudgeFactor;

  // Divide x, y and z by zToDivideBy
  gl_Position = vec4(position.xyz,  zToDivideBy);
}
</script>

看看這是完全相同的。

為什么有這樣一個(gè)事實(shí): WebGL 自動(dòng)除以 W ?因?yàn)楝F(xiàn)在,使用更多維的矩陣,我們可以使用另一個(gè)矩陣復(fù)制 z 到 w。

矩陣如下

1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 1,
0, 0, 0, 0,

將復(fù)制 z 到 w.你可以看看這些列如下

x_out = x_in * 1 +
        y_in * 0 +
        z_in * 0 +
        w_in * 0 ;

y_out = x_in * 0 +
        y_in * 1 +
        z_in * 0 +
        w_in * 0 ;

z_out = x_in * 0 +
        y_in * 0 +
        z_in * 1 +
        w_in * 0 ;

w_out = x_in * 0 +
        y_in * 0 +
        z_in * 1 +
        w_in * 0 ;

簡(jiǎn)化后如下

x_out = x_in;
y_out = y_in;
z_out = z_in;
w_out = z_in;

我們可以加 1 我們之前用的這個(gè)矩陣,因?yàn)槲覀冎?w_in 總是 1.0。

1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 1,
0, 0, 0, 1,

這將改變 W 計(jì)算如下

w_out = x_in * 0 +
        y_in * 0 +
        z_in * 1 +
        w_in * 1 ;

因?yàn)槲覀冎?w_in = 1.0 所以就有

w_out = z_in + 1;

最后我們可以將 fudgeFactor 加到矩陣,矩陣如下

1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, fudgeFactor,
0, 0, 0, 1,

這意味著

w_out = x_in * 0 +
        y_in * 0 +
        z_in * fudgeFactor +
        w_in * 1 ;

簡(jiǎn)化后如下

w_out = z_in * fudgeFactor + 1;

所以,讓我們?cè)俅涡薷某绦蛑皇褂镁仃?。   ?/p>

首先讓我們放回頂點(diǎn)著色器。這很簡(jiǎn)單

<script id="2d-vertex-shader" type="x-shader/x-vertex">
uniform mat4 u_matrix;

void main() {
  // Multiply the position by the matrix.
  gl_Position = u_matrix * a_position;
  ...
}
</script>

接下來(lái)讓我們做一個(gè)函數(shù)使 Z - > W 矩陣。

function makeZToWMatrix(fudgeFactor) {
  return [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, fudgeFactor,
    0, 0, 0, 1,
  ];
}

我們將更改代碼,以使用它。

    ...
    // Compute the matrices
    var zToWMatrix =
        makeZToWMatrix(fudgeFactor);

    ...

    // Multiply the matrices.
    var matrix = matrixMultiply(scaleMatrix, rotationZMatrix);
    matrix = matrixMultiply(matrix, rotationYMatrix);
    matrix = matrixMultiply(matrix, rotationXMatrix);
    matrix = matrixMultiply(matrix, translationMatrix);
    matrix = matrixMultiply(matrix, projectionMatrix);
    matrix = matrixMultiply(matrix, zToWMatrix);

    ...

注意,這一次也是完全相同的。

以上基本上是向你們展示,除以 Z 給了我們透視圖,WebGL 方便地為我們除以 Z?!   ?/p>

但是仍然有一些問(wèn)題。例如如果你設(shè)置 Z 到 -100 左右,你會(huì)看到類似下面的動(dòng)畫。

http://wiki.jikexueyuan.com/project/webgl/images/z-clipping.gif" alt="" />

發(fā)生了什么事?為什么 F 消失得很早?就像 WebGL 剪輯 X 和 Y 或+ 1 到 - 1 它也剪輯 Z。這里看到的就是 Z<-1 的地方。

我可以詳細(xì)了解如何解決它,但你可以以我們做二維投影相同的方式來(lái)得到它。我們需要利用 Z,添加一些數(shù)量和測(cè)量一定量,我們可以做任何我們想要得到的 -1 到 1 的映射范圍。

真正酷的事情是所有這些步驟可以在 1 個(gè)矩陣內(nèi)完成。甚至更好的,我們來(lái)決定一個(gè) fieldOfView 而不是一個(gè) fudgeFactor,并且計(jì)算正確的值來(lái)做這件事。

這里有一個(gè)函數(shù)來(lái)生成矩陣。

function makePerspective(fieldOfViewInRadians, aspect, near, far) {
  var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians);
  var rangeInv = 1.0 / (near - far);

  return [
    f / aspect, 0, 0, 0,
    0, f, 0, 0,
    0, 0, (near + far) * rangeInv, -1,
    0, 0, near * far * rangeInv * 2, 0
  ];
};

這個(gè)矩陣將為我們做所有的轉(zhuǎn)換。它將調(diào)整單位,所以他們?cè)赾lipspace 中它會(huì)做數(shù)學(xué)運(yùn)算,因此我們可以通過(guò)角度選擇視野,它會(huì)讓我們選擇我們的 z-clipping 空間。它假定有一個(gè) eye 或 camera 在原點(diǎn)(0,0,0)并且給定一個(gè) zNear 和 fieldOfView 計(jì)算它需要什么,因此在 zNear 的物體在 z = - 1 結(jié)束以及在 zNear 的物體它們?cè)谥行囊陨匣蛞韵掳雮€(gè) fieldOfView,分別在 y = - 1 和 y = 1 結(jié)束。計(jì)算 X 所使用的只是乘以傳入的 aspect。我們通常將此設(shè)置為顯示區(qū)域的 width / height。最后,它計(jì)算出在 Z 區(qū)域物體的規(guī)模,因此在 zFar 的物體在 z = 1 處結(jié)束。

下面是動(dòng)作矩陣的圖。

形狀像四面錐的立方體旋轉(zhuǎn)稱為“截錐”。矩陣在截錐內(nèi)占空間并且轉(zhuǎn)換到 clipspace。zNear 定義夾在前面的物體,zfar定義夾在后面的物體。設(shè)置 zNear 為23你會(huì)看到旋轉(zhuǎn)的立方體的前面得到裁剪。設(shè)置 zFar 為24你會(huì)看到立方體的后面得到剪輯。

只剩下一個(gè)問(wèn)題。這個(gè)矩陣假定有一個(gè)視角在 0,0,0 并假定它在Z軸負(fù)方向,Y的正方向。我們的矩陣到目前為止已經(jīng)以不同的方式解決問(wèn)題。為了使它工作,我們需要我們的對(duì)象在前面的視圖。

我們可以通過(guò)移動(dòng)我們的 F 做到。 我們?cè)冢?5,150,0)繪圖。讓我們將它移到(0,150,- 360)

現(xiàn)在,要想使用它,我們只需要用對(duì) makePerspective 的調(diào)用取代對(duì)make2DProjection 舊的調(diào)用

    var aspect = canvas.clientWidth / canvas.clientHeight;
    var projectionMatrix =
        makePerspective(fieldOfViewRadians, aspect, 1, 2000);
    var translationMatrix =
        makeTranslation(translation[0], translation[1], translation[2]);
    var rotationXMatrix = makeXRotation(rotation[0]);
    var rotationYMatrix = makeYRotation(rotation[1]);
    var rotationZMatrix = makeZRotation(rotation[2]);
    var scaleMatrix = makeScale(scale[0], scale[1], scale[2]);

結(jié)果如下

我們回到了一個(gè)矩陣乘法,我們得到兩個(gè)領(lǐng)域的視圖,我們可以選擇我們的 z 空間。受篇幅限制我們沒(méi)有做。下一節(jié),攝像機(jī)