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

一起學 WebGL:繪制立方體

開發(fā) 前端
現(xiàn)在我們來繪制一個立方體,其實本質(zhì)和繪制二維圖形是一樣,也是繪制三角形,只是繪制很多個,然后組合起來,作為立方體的幾個面,拼在一起就是一個立方體了。

大家好,我是前端西瓜哥。

之前我們繪制三角形,是一個二維的圖形。

現(xiàn)在我們來繪制一個立方體,其實本質(zhì)和繪制二維圖形是一樣,也是繪制三角形,只是繪制很多個,然后組合起來,作為立方體的幾個面,拼在一起就是一個立方體了。

繪制三角形,我們用的 API 是:

gl.drawArrays(gl.TRIANGLES, 0, n);

那畫一個立方體,假設選擇 gl.TRIANGLE_FAN 圖元模式,也就是畫 6 個面,每個面有 4 個點。所以我們需要定義 24 個點。

這其實重復定義了頂點,因為一個立方體也就 8 個點,數(shù)據(jù)是有冗余的。

WebGL 提供了 gl.drawElements() 方法,通過索引值映射的方式來解決這個問題。

首先定義立方體的 8 個頂點(我們命名為 v0 到 v7)的位置和顏色。

const verticesColors = new Float32Array([
  1, 1, 1,     1, 1, 1, // 點 0 白
  -1, 1, 1,    1, 0, 1, // 點 1 品紅
  -1, -1, 1,   1, 0, 0, // 點 2 紅
  1, -1, 1,    1, 1, 0, // 點 3 黃

  1, -1, -1,   0, 1, 0, // 點 4 綠色
  1, 1, -1,    0, 1, 1, // 點 5 青色
  -1, 1, -1,   0, 0, 1, // 點 6 藍色
  -1, -1, -1,  0, 0, 0, // 點 7 黑色
]);

圖片

然后用索引值構造好 6 個面,每個面 2 個三角形:

const indices = new Uint8Array([
  0, 1, 2, 0, 2, 3, // 正面
  0, 3, 4, 0, 4, 5, // 右面
  0, 5, 6, 0, 6, 1, // 上面
  1, 6, 7, 1, 7, 2, // 左面
  7, 4, 3, 7, 3, 2, // 下面
  4, 7, 6, 4, 6, 5, // 背面
]);

和頂點數(shù)據(jù)類似,索引值也要創(chuàng)建一個緩沖區(qū),并進行綁定,綁定目標變成了 gl.ELEMENT_ARRAY_BUFFER 上。

const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

最后調(diào)用 gl.drawElements 方法進行繪制。這里要傳入 indices 數(shù)組的長度,WebGL 就會讀取索引值得到對應的頂點信息去一個個繪制三角形啦。

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);

繪制結果:

圖片

完整代碼:

// Create a cube
//    v6----- v5
//   /|      /|
//  v1------v0|
//  | |     | |
//  | |v7---|-|v4
//  |/      |/
//  v2------v3

/** @type {HTMLCanvasElement} */
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const infoDiv = document.createElement('div');
document.body.appendChild(infoDiv);

const vertexShaderSrc = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;  // 視圖矩陣
uniform mat4 u_ProjMatrix; // 正射投影矩陣
mat4 u_MvpMatrix = u_ProjMatrix * u_ViewMatrix;
varying vec4 v_Color;
void main() {
 gl_Position = u_MvpMatrix * a_Position;
 v_Color = a_Color;
}
`;

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

/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 創(chuàng)建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序?qū)ο?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([
  1, 1, 1,     1, 1, 1, // 點 0 白
  -1, 1, 1,    1, 0, 1, // 點 1 品紅
  -1, -1, 1,   1, 0, 0, // 點 2 紅
  1, -1, 1,    1, 1, 0, // 點 3 黃

  1, -1, -1,   0, 1, 0, // 點 4 綠色
  1, 1, -1,    0, 1, 1, // 點 5 青色
  -1, 1, -1,   0, 0, 1, // 點 6 藍色
  -1, -1, -1,  0, 0, 0, // 點 7 黑色
]);

// prettier-ignore
const indices = new Uint8Array([
  0, 1, 2, 0, 2, 3, // 正面
  0, 3, 4, 0, 4, 5, // 右面
  0, 5, 6, 0, 6, 1, // 上面
  1, 6, 7, 1, 7, 2, // 左面
  7, 4, 3, 7, 3, 2, // 下面
  4, 7, 6, 4, 6, 5, // 背面
]);

// 每個數(shù)組元素的字節(jié)數(shù)
const SIZE = verticesColors.BYTES_PER_ELEMENT;
// 創(chuàng)建緩存對象
const vertexColorBuffer = gl.createBuffer();
const indexBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
const a_Color = gl.getAttribLocation(gl.program, 'a_Color');
/****** 正射投影 ******/
const u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');

// prettier-ignore
const viewMatrix = createViewMatrix(
  3, 4, 8, // 觀察點
  0, 0, 0, // 視點
  0, 1, 0 // 上方向
)
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix);

/****** 正射投影 ******/
const u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
// prettier-ignore
const projMatrix = createPerspective(
  30, canvas.width / canvas.height, 1, 100
)
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix);

gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, SIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);

gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, SIZE * 6, SIZE * 3);
gl.enableVertexAttribArray(a_Color);

/*** 繪制 ***/
// 清空畫布,并指定顏色
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST); // 啟動深度檢測,處理錯誤的像素覆蓋問題

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// 繪制三角形
// gl.drawArrays(gl.TRIANGLES, 0, 8);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);

/************ 后面都是一些工具類方法 ******/

/**** 構造視圖矩陣 ****/
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,
  ]);
}

function angleToRadian(angle) {
  return (Math.PI * angle) / 180;
}

/***** 構建透視矩陣 *****/
function createPerspective(fov, aspect, near, far) {
  fov = angleToRadian(fov); // 角度轉(zhuǎn)弧度
  const f = 1.0 / Math.tan(fov / 2);
  const nf = 1 / (near - far);
  // prettier-ignore
  return new Float32Array([
    f / aspect, 0, 0, 0,
    0, f, 0, 0,
    0, 0, (far + near) * nf, -1,
    0, 0, 2 * far * near * nf, 0,
  ]);
}

線上體驗 demo:

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

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

2023-04-12 07:46:24

JavaScriptWebGL

2023-05-16 07:44:03

紋理映射WebGL

2023-04-11 07:48:32

WebGLCanvas

2023-04-17 09:01:01

WebGL繪制三角形

2023-03-29 07:31:09

WebGL坐標系

2023-05-04 08:48:42

WebGL復合矩陣

2023-06-26 15:14:19

WebGL紋理對象學習

2023-04-26 07:42:16

WebGL圖元的類型

2023-04-13 07:45:15

WebGL片元著色器

2023-05-17 08:28:55

2023-04-27 08:27:29

WebGL變形矩陣

2023-03-02 07:44:39

pixijsWebGL

2023-02-22 09:27:31

CanvasWebGL

2023-05-08 07:29:48

WebGL視圖矩陣

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

游戲開發(fā)畫布功能

2019-07-16 16:05:51

PythonScribusRGB

2023-05-06 07:23:57

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品国产欧美日韩不卡在线观看 | 精品国产一区二区国模嫣然 | 久久久久久国产精品 | 男女羞羞视频在线免费观看 | 97精品一区二区 | 国产三级在线观看播放 | 一区视频 | 欧美成人影院 | 亚洲精品一区二区 | 波多野吉衣久久 | 久久久久国产精品 | 超碰国产在线 | 国产精品片aa在线观看 | 国产精品免费播放 | 日韩精品一区二区三区中文在线 | 欧美影院 | 一区二区久久 | 国产精品性做久久久久久 | 久久久久久久久久性 | 亚洲国产一区在线 | 综合久久综合久久 | 中文字幕视频在线看 | 91精品国产91久久综合桃花 | 亚洲国产aⅴ成人精品无吗 亚洲精品久久久一区二区三区 | 国产一区二区免费 | 精品一区国产 | 欧美aaaaaa| 午夜精品久久久久久不卡欧美一级 | 亚洲成网站 | 91精品国产自产精品男人的天堂 | 91久久精品一区二区二区 | 国产综合在线视频 | 自拍 亚洲 欧美 老师 丝袜 | 天天爽夜夜骑 | 欧美精品日韩精品国产精品 | 在线免费观看视频你懂的 | 国产精品精品视频一区二区三区 | 久久成人一区 | 久久久久亚洲 | 午夜黄色影院 | 91久久综合亚洲鲁鲁五月天 |