成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一起學 WebGL:感受三維世界之視圖矩陣

開發 前端
對于一個立方體來說,我們從它的正前方看,不管距離它多遠,也只能看到一個二維的正方形。因此我們需要引入 視圖矩陣(view matrix)。它的作用就像是一個在特定位置的攝像頭。

大家好,我是前端西瓜哥。之前繪制的圖形都是在 XY 軸所在的平面上,這次我們來加入一點深度信息 z,帶你走入三維的世界。

視圖矩陣

對于一個立方體來說,我們從它的正前方看,不管距離它多遠,也只能看到一個二維的正方形。因此我們需要引入 視圖矩陣(view matrix)。它的作用就像是一個在特定位置的攝像頭。

視圖矩陣需要三個信息:

  1. 視點位置;
  2. 觀察點位置;
  3. 上方向;

就好比我們站在某個位置看一個模型,眼睛的位置就是觀察點,目光落在的點就是視點。我們站著看,上方向 就是朝上(y 正軸方向),躺著看就是水平方向,倒立著看就是朝下(y 負半軸方向)。

實際上我們并沒有一個真正的視口,我們的世界坐標的正中心永遠是原點,z 負半軸指向觀察者。

但我們可以利用相對運動的原理,給圖形做一個相反的操作,比如我往右邊走 1 個單位去看模型,其實等價于我不懂,模型向左移動 1 個單位,它們的效果是一樣的。

視圖矩陣的算法實現如下:

function createViewMatrix(eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ) {
  const normalize = (v) => {
    const length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    return [v[0] / length, v[1] / length, v[2] / length];
  };
  const subtract = (v1, v2) => {
    return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]];
  };
  const cross = (v1, v2) => {
    return [
      v1[1] * v2[2] - v1[2] * v2[1],
      v1[2] * v2[0] - v1[0] * v2[2],
      v1[0] * v2[1] - v1[1] * v2[0]
    ];
  };

  const zAxis = normalize(subtract([eyeX, eyeY, eyeZ], [atX, atY, atZ]));
  const xAxis = normalize(cross([upX, upY, upZ], zAxis));
  const yAxis = normalize(cross(zAxis, xAxis));

  return new Float32Array([
    xAxis[0],
    yAxis[0],
    zAxis[0],
    0,
    xAxis[1],
    yAxis[1],
    zAxis[1],
    0,
    xAxis[2],
    yAxis[2],
    zAxis[2],
    0,
    -(xAxis[0] * eyeX + xAxis[1] * eyeY + xAxis[2] * eyeZ),
    -(yAxis[0] * eyeX + yAxis[1] * eyeY + yAxis[2] * eyeZ),
    -(zAxis[0] * eyeX + zAxis[1] * eyeY + zAxis[2] * eyeZ),
    1
  ]);
}

視圖坐標的實現細節不講,不重要。(順帶一提,上面的算法由 Github Copilot 生成)

通過這個方法計算出矩陣,傳入到頂點著色器的矩陣變量中,和頂點位置計算即可。

const viewMatrix = createViewMatrix(0.2, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
const u_ViewMatrix = gl.getUniformLocation(gl.program, "u_ViewMatrix");
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix);

其他的創建緩沖區的邏輯就不講了,之前的文章都講過了。

完整代碼

貼一下完整代碼:

/** @type {HTMLCanvasElement} */
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");

const vertexShaderSrc = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
varying vec4 v_Color;
void main() {
 gl_Position = u_ViewMatrix * a_Position;
 v_Color = a_Color;
}
`;

const fragmentShaderSrc = `
precision mediump float;
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}
`;

/**** 渲染器生成處理 ****/
// 創建頂點渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 創建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序對象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;

// prettier-ignore
const verticesColors = new Float32Array([
  // 下方的紅色三角形
  0, 0.2, -0.2, 1, 0, 0,  // 位置和顏色信息
  -0.2, -0.2, -0.2, 1, 0, 0,  
  0.2, -0.2, -0.2, 1, 0, 0,  
  // 上方的黃色三角形
  0, 0.2, 0, 1, 1, 0,  // 點 1 的位置和顏色信息
  -0.2, -0.2, 0, 1, 1, 0,  // 點 2
  0.2, -0.2, 0, 1, 1, 0,  // 點 3
]);
// 每個數組元素的字節數
const SIZE = verticesColors.BYTES_PER_ELEMENT;

// 創建緩存對象
const vertexColorBuffer = gl.createBuffer();
// 綁定緩存對象到上下文
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
// 向緩存區寫入數據
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, SIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);

const a_Color = gl.getAttribLocation(gl.program, "a_Color");
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, SIZE * 6, SIZE * 3);
gl.enableVertexAttribArray(a_Color);

/****** 視圖矩陣 ****/
// prettier-ignore
// 取消下面一行注釋,并注釋下下一行代碼,可觀察沒有使用視圖矩陣的原始效果
// const viewMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,0,0,1]);
const viewMatrix = createViewMatrix(0.2, 0.25, 0.25, 0, 0, 0, 0, 1, 0);
const u_ViewMatrix = gl.getUniformLocation(gl.program, "u_ViewMatrix");
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix);

/*** 繪制 ***/
// 清空畫布,并指定顏色
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// 繪制三角形
gl.drawArrays(gl.TRIANGLES, 0, 6);

function createViewMatrix(eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ) {
  const normalize = (v) => {
    const length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    return [v[0] / length, v[1] / length, v[2] / length];
  };
  const subtract = (v1, v2) => {
    return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]];
  };
  const cross = (v1, v2) => {
    return [
      v1[1] * v2[2] - v1[2] * v2[1],
      v1[2] * v2[0] - v1[0] * v2[2],
      v1[0] * v2[1] - v1[1] * v2[0]
    ];
  };

  const zAxis = normalize(subtract([eyeX, eyeY, eyeZ], [atX, atY, atZ]));
  const xAxis = normalize(cross([upX, upY, upZ], zAxis));
  const yAxis = normalize(cross(zAxis, xAxis));

  return new Float32Array([
    xAxis[0],
    yAxis[0],
    zAxis[0],
    0,
    xAxis[1],
    yAxis[1],
    zAxis[1],
    0,
    xAxis[2],
    yAxis[2],
    zAxis[2],
    0,
    -(xAxis[0] * eyeX + xAxis[1] * eyeY + xAxis[2] * eyeZ),
    -(yAxis[0] * eyeX + yAxis[1] * eyeY + yAxis[2] * eyeZ),
    -(zAxis[0] * eyeX + zAxis[1] * eyeY + zAxis[2] * eyeZ),
    1
  ]);
}

demo 地址:

https://codesandbox.io/s/ijxwu2?file=/index.js。

這里我繪制了紅色和黃色兩個三角形,紅色在更下邊,z 為 -0.2,黃色在上面一點,z 為 0。

應用視圖矩陣前的效果。因為兩者大小相同,黃色三角形完全蓋住了紅色。

圖片

應用視圖矩陣后:

圖片

結尾

今天簡單講了下讓我們指定一個位置觀察模型的方法:視圖矩陣。

之前我們也講了一個叫做模型矩陣的玩意,模型矩陣就好比一個三維軟件,我們將一個模型導入到場景中,移動它的位置、縮放它的尺寸,旋轉一下之類的。視圖矩陣就好比通過一個攝像機的視角看到的世界。

不知道你發現沒有,這里的兩個三角形并沒有近大遠小的透視效果。此外,當我們的觀察點位置非常靠右或靠左的時候,三角形會缺失部分。

關于這點,我會在下節講解 可視空間,解答這些問題。

責任編輯:姜華 來源: 前端西瓜哥
相關推薦

2023-05-04 08:48:42

WebGL復合矩陣

2023-04-27 08:27:29

WebGL變形矩陣

2023-05-17 08:28:55

2023-06-26 15:14:19

WebGL紋理對象學習

2023-04-26 07:42:16

WebGL圖元的類型

2023-04-12 07:46:24

JavaScriptWebGL

2023-03-29 07:31:09

WebGL坐標系

2023-04-17 09:01:01

WebGL繪制三角形

2023-05-31 20:10:03

WebGL繪制立方體

2023-05-16 07:44:03

紋理映射WebGL

2023-04-13 07:45:15

WebGL片元著色器

2023-04-11 07:48:32

WebGLCanvas

2023-02-28 07:28:50

Spritepixijs

2023-05-06 07:23:57

2022-02-08 14:35:36

分片集群數據庫mongo

2022-12-02 14:20:09

Tetris鴻蒙

2022-11-29 16:35:02

Tetris鴻蒙

2023-03-30 09:32:27

2022-11-14 17:01:34

游戲開發畫布功能

2022-10-18 07:33:57

Maven構建工具
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清在线观看 | 亚洲va欧美va人人爽午夜 | 91色视频在线观看 | 欧美精品成人一区二区三区四区 | 自拍视频精品 | 欧美一区二区三区日韩 | 国产亚洲一区在线 | 国产一级视频免费播放 | 成人网视频 | 黄色片免费看视频 | 日本中文字幕一区 | 国产免费福利在线 | 国产精品久久久久久久午夜片 | 国产精品日韩一区 | 久久中文字幕一区 | 国产成人免费视频 | 亚洲精品乱码久久久久久按摩观 | 成人av高清在线观看 | 精品一区二区三区91 | 国产精品成人一区二区三区 | 日韩av啪啪网站大全免费观看 | 美女黄色在线观看 | 国产中的精品av涩差av | 国内精品99 | 97免费视频在线观看 | 亚洲欧美一区二区三区1000 | 色视频网站在线观看 | 亚洲精品中文字幕 | 欧美久久久久久久久 | 天天爱爱网| 国产精品色 | 亚洲国产成人av好男人在线观看 | 久久久久久久久久久久一区二区 | av国产在线观看 | 精品一区二区久久 | 一区影视| 男女免费在线观看视频 | 久久五月婷 | 中文字幕日本一区二区 | 午夜国产一级 | 久久精品色欧美aⅴ一区二区 |