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

一起學(xué) WebGL:圖形變形以及矩陣變換

開發(fā) 前端
WebGL 用的是按列主序(column major order)規(guī)則,即按列填充矩陣,從左往右,屬于主流。

之前繪制了三角形,我們現(xiàn)在給它做一個(gè)變形操作。

對(duì)一個(gè)三角形進(jìn)行變形,其實(shí)就是重新這個(gè)三角形的三個(gè)頂點(diǎn)的位置,計(jì)算完后再繪制出來,相比原來就發(fā)生了變形。

變形常見的有位移、選擇、縮放。位移,其實(shí)就是給每個(gè)頂點(diǎn)的各個(gè)坐標(biāo)值加上偏移量 dx、dy、dz。旋轉(zhuǎn)稍微復(fù)雜些,用到了三角函數(shù)。最后是縮放,就是簡單地各個(gè)分量乘以縮放比例系數(shù)。

這些變換可以抽象簡化成對(duì)應(yīng)的變換矩陣,方便我們用統(tǒng)一的方式作表達(dá),并配合矩陣乘法的結(jié)合律,將多個(gè)變形矩陣合并成一個(gè)復(fù)合矩陣,減少計(jì)算量。

直接進(jìn)入正題,看看怎么用 WebGL 實(shí)現(xiàn)矩陣變換。

繪制三角形

我們先繪制一個(gè)普通的沒做過變形的三角形。

demo 地址:

https://codesandbox.io/s/gbh1xf。

代碼:

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

const vertexShaderSrc = `
attribute vec4 a_Position;
void main() {
 gl_Position = a_Position;
 gl_PointSize = 10.0;
}
`;

const fragmentShaderSrc = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點(diǎn)渲染器
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;

// 頂點(diǎn)數(shù)據(jù)
const vertices = new Float32Array([
  // 第一個(gè)點(diǎn)
  0,
  0.5,
  // 第二個(gè)點(diǎn)
  -0.5,
  -0.5,
  // 第三個(gè)點(diǎn)
  0.5,
  -0.5
]);

// 創(chuàng)建緩存對(duì)象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對(duì)象到上下文
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 向緩存區(qū)寫入數(shù)據(jù)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
// 將緩沖區(qū)對(duì)象分配給 a_Position 變量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// 允許訪問緩存區(qū)
gl.enableVertexAttribArray(a_Position);

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

渲染效果:

圖片

位移

位移,最簡單的方式是再聲明一個(gè) u_Translation 向量,和 a_Position 相加就完事了:

但還是矩陣比較方便,具有可以統(tǒng)一格式,計(jì)算復(fù)合矩陣等優(yōu)勢(shì)。通常變形都是復(fù)雜的,旋轉(zhuǎn)后平移然后再縮放一套下來,矩陣還是很重要的。

頂點(diǎn)著色器的代碼修改為:

const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main() {
 gl_Position = u_xformMatrix * a_Position;
}
`;

西瓜哥在這里加多了一個(gè) u_xformMatrix 變量。

首先用了 uniform 類型修飾符,表示這個(gè)變量不會(huì)逐頂點(diǎn)發(fā)生變化,是固定的。mat4 表示一個(gè) 4x4 矩陣,一個(gè)有 16 個(gè)浮點(diǎn)數(shù)的一維數(shù)組。

來看看通過矩陣進(jìn)行位移的實(shí)現(xiàn)。位移矩陣如下:

對(duì)應(yīng)的 Float32Array 數(shù)組為:

/****** 位移矩陣 ****/
const dx = 0.5; // 向右移動(dòng)
const dy = -0.3; // 向下移動(dòng)
// z 先不管,沒用到透視矩陣,設(shè)置值也看不到效果

const xformMatrix = new Float32Array([
  1, 0, 0, 0,

  0, 1, 0, 0,

  0, 0, 1, 0,

  dx, dy, 0, 1
]);

WebGL 用的是按列主序(column major order)規(guī)則,即按列填充矩陣,從左往右,屬于主流。

還有一種是按行主序(row major order)的,也就是將遍歷數(shù)組一行行填充到矩陣,從上往下。比較少見。

接著把這個(gè)數(shù)組懟到前面頂點(diǎn)著色器聲明的 u_xformMatrix 變量中。

const u_xformMatrix = gl.getUniformLocation(gl.program, "u_xformMatrix");
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);

這里是用 gl.uniformMatrix4fv 來設(shè)置 4x4 矩陣的值。

完整代碼:

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

const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main() {
 gl_Position = u_xformMatrix * a_Position;
}
`;

const fragmentShaderSrc = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點(diǎn)渲染器
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;

// 頂點(diǎn)數(shù)據(jù)
const vertices = new Float32Array([
  // 第一個(gè)點(diǎn)
  0,
  0.5,
  // 第二個(gè)點(diǎn)
  -0.5,
  -0.5,
  // 第三個(gè)點(diǎn)
  0.5,
  -0.5
]);

// 創(chuàng)建緩存對(duì)象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對(duì)象到上下文
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 向緩存區(qū)寫入數(shù)據(jù)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
// 將緩沖區(qū)對(duì)象分配給 a_Position 變量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// 允許訪問緩存區(qū)
gl.enableVertexAttribArray(a_Position);

/****** 位移矩陣 ****/
const dx = 0.5; // 向右移動(dòng)
const dy = -0.3; // 向下移動(dòng)
// z 先不管,沒用到透視矩陣,設(shè)置值也看不到效果

const xformMatrix = new Float32Array([
  1,
  0,
  0,
  0,

  0,
  1,
  0,
  0,

  0,
  0,
  1,
  0,

  dx,
  dy,
  0,
  1
]);
const u_xformMatrix = gl.getUniformLocation(gl.program, "u_xformMatrix");
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);

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

demo 地址:

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

看看效果:

圖片

成功向右并向下移動(dòng)了一段距離。

旋轉(zhuǎn)

頂點(diǎn)著色器的代碼不用改,這次我們傳一個(gè)旋轉(zhuǎn)矩陣進(jìn)去,就逆時(shí)針旋轉(zhuǎn) 90 度吧,沿著 z 軸作旋轉(zhuǎn)。

公式為:

這個(gè)公示是幾何數(shù)學(xué)推導(dǎo)出來的。

數(shù)組數(shù)據(jù)為:

/****** 旋轉(zhuǎn)矩陣 ****/
const angle = 90;
const radian = (angle * Math.PI) / 180;
const cos = Math.cos(radian);
const sin = Math.sin(radian);

const xformMatrix = new Float32Array([
  cos, sin, 0, 0,

  -sin, cos, 0, 0,

  0, 0, 1, 0,

  0, 0, 0, 1
]);

因?yàn)楹芏?API 只支持弧度制,所以我們需要將角度轉(zhuǎn)弧度。

然后是旋轉(zhuǎn)方向,提供一個(gè)正數(shù),WebGL 是沿著逆時(shí)針旋轉(zhuǎn)的。順帶一提, Canvas 2D 是順時(shí)針旋轉(zhuǎn)的。

完整代碼:

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

const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main() {
 gl_Position = u_xformMatrix * a_Position;
}
`;

const fragmentShaderSrc = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點(diǎn)渲染器
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;

// 頂點(diǎn)數(shù)據(jù)
const vertices = new Float32Array([
  // 第一個(gè)點(diǎn)
  0,
  0.5,
  // 第二個(gè)點(diǎn)
  -0.5,
  -0.5,
  // 第三個(gè)點(diǎn)
  0.5,
  -0.5
]);

// 創(chuàng)建緩存對(duì)象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對(duì)象到上下文
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 向緩存區(qū)寫入數(shù)據(jù)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
// 將緩沖區(qū)對(duì)象分配給 a_Position 變量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// 允許訪問緩存區(qū)
gl.enableVertexAttribArray(a_Position);

/****** 旋轉(zhuǎn)矩陣 ****/
const angle = 90;
const radian = (angle * Math.PI) / 180;
const cos = Math.cos(radian);
const sin = Math.sin(radian);

const xformMatrix = new Float32Array([
  cos,
  sin,
  0,
  0,

  -sin,
  cos,
  0,
  0,

  0,
  0,
  1,
  0,

  0,
  0,
  0,
  1
]);
const u_xformMatrix = gl.getUniformLocation(gl.program, "u_xformMatrix");
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);

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

demo 地址:

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

渲染效果:

圖片

縮放

縮放公式為:

數(shù)組為:

/****** 縮放矩陣 ****/
const sx = 2;
const sy = 2;
const sz = 1;
// sz 先不管,沒用到透視矩陣,設(shè)置了值也看不到效果

const xformMatrix = new Float32Array([
  sx, 0, 0, 0,

  0, sy, 0, 0,

  0, 0, sz, 0,

  0, 0, 0, 1
]);

完整代碼:

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

const vertexShaderSrc = `
attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main() {
 gl_Position = u_xformMatrix * a_Position;
}
`;

const fragmentShaderSrc = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點(diǎn)渲染器
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;

// 頂點(diǎn)數(shù)據(jù)
const vertices = new Float32Array([
  // 第一個(gè)點(diǎn)
  0,
  0.5,
  // 第二個(gè)點(diǎn)
  -0.5,
  -0.5,
  // 第三個(gè)點(diǎn)
  0.5,
  -0.5
]);

// 創(chuàng)建緩存對(duì)象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對(duì)象到上下文
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 向緩存區(qū)寫入數(shù)據(jù)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 獲取 a_Position 變量地址
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
// 將緩沖區(qū)對(duì)象分配給 a_Position 變量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// 允許訪問緩存區(qū)
gl.enableVertexAttribArray(a_Position);

/****** 縮放矩陣 ****/
const sx = 2;
const sy = 2;
const sz = 2;
// z 先不管,沒用到透視矩陣,設(shè)置了值也看不到效果

const xformMatrix = new Float32Array([
  sx,
  0,
  0,
  0,

  0,
  sy,
  0,
  0,

  0,
  0,
  sz,
  0,

  0,
  0,
  0,
  1
]);
const u_xformMatrix = gl.getUniformLocation(gl.program, "u_xformMatrix");
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);

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

demo 地址:

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

繪制效果:

圖片

結(jié)尾

矩陣變換是 WebGL 非常重要的一部分。

本節(jié)介紹了三種常見的變形矩陣,并展示了各自的效果,下節(jié)我們講多個(gè)矩陣的組合,復(fù)合矩陣。

責(zé)任編輯:姜華 來源: 前端西瓜哥
相關(guān)推薦

2023-05-04 08:48:42

WebGL復(fù)合矩陣

2023-06-26 15:14:19

WebGL紋理對(duì)象學(xué)習(xí)

2023-04-26 07:42:16

WebGL圖元的類型

2023-04-12 07:46:24

JavaScriptWebGL

2023-03-29 07:31:09

WebGL坐標(biāo)系

2023-05-08 07:29:48

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-05-17 08:28:55

2023-04-17 09:01:01

WebGL繪制三角形

2023-02-23 08:40:09

Pixijs修改圖形屬性

2023-02-22 09:27:31

CanvasWebGL

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ā)畫布功能

2023-05-06 07:23:57

2023-02-28 07:28:50

Spritepixijs
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人国产免费观看 | 日韩电影免费在线观看中文字幕 | 久久久久九九九九 | 91亚洲欧美| 欧美操操操 | 一区二区久久 | 久久久久久国产精品免费免费狐狸 | 在线黄av| 国产永久免费 | 欧美成人手机视频 | 久久青视频 | 精品亚洲一区二区三区四区五区高 | 日韩精品一区二区三区中文字幕 | 亚洲情侣视频 | 国产成人综合在线 | 国产精品日产欧美久久久久 | 国产免费福利 | 国产一区二区日韩 | 亚洲一区二区中文字幕 | 久久y| 色www精品视频在线观看 | 国产成人99久久亚洲综合精品 | 欧美a在线 | 亚洲一区二区不卡在线观看 | 毛片网站在线观看视频 | 青青草原综合久久大伊人精品 | 亚洲在线 | av一二三区 | 高清视频一区二区三区 | 国产精品久久久久久久久久久久久 | 一级大片免费 | 99久久婷婷国产综合精品 | 欧美黄视频 | 国产高清一区二区 | 国产高清在线精品一区二区三区 | 最近免费日本视频在线 | 国产精品2 | 午夜精品久久久久久久久久久久久 | www国产成人免费观看视频,深夜成人网 | 成人在线视频免费播放 | 亚洲成色777777在线观看影院 |