日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一起學(xué)WebGL:圖形變形以及矩陣變換

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

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:國際域名空間、虛擬主機、營銷軟件、網(wǎng)站建設(shè)、鎮(zhèn)安網(wǎng)站維護、網(wǎng)站推廣。

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

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

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

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

繪制三角形

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

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)建頂點渲染器
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;

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

// 創(chuàng)建緩存對象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對象到上下文
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ū)對象分配給 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);

渲染效果:

位移

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

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

頂點著色器的代碼修改為:

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

西瓜哥在這里加多了一個 u_xformMatrix 變量。

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

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

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

/****** 位移矩陣 ****/
const dx = 0.5; // 向右移動
const dy = -0.3; // 向下移動
// 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ù)組一行行填充到矩陣,從上往下。比較少見。

接著把這個數(shù)組懟到前面頂點著色器聲明的 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)建頂點渲染器
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;

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

// 創(chuàng)建緩存對象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對象到上下文
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ū)對象分配給 a_Position 變量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

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

/****** 位移矩陣 ****/
const dx = 0.5; // 向右移動
const dy = -0.3; // 向下移動
// 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 地址:

看看效果:

成功向右并向下移動了一段距離。

旋轉(zhuǎn)

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

公式為:

這個公示是幾何數(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
]);

因為很多 API 只支持弧度制,所以我們需要將角度轉(zhuǎn)弧度。

然后是旋轉(zhuǎn)方向,提供一個正數(shù),WebGL 是沿著逆時針旋轉(zhuǎn)的。順帶一提, Canvas 2D 是順時針旋轉(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)建頂點渲染器
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;

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

// 創(chuàng)建緩存對象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對象到上下文
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ū)對象分配給 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 地址:

渲染效果:

縮放

縮放公式為:

數(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)建頂點渲染器
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;

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

// 創(chuàng)建緩存對象
const vertexBuffer = gl.createBuffer();
// 綁定緩存對象到上下文
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ū)對象分配給 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 地址:

繪制效果:

結(jié)尾

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

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


本文名稱:一起學(xué)WebGL:圖形變形以及矩陣變換
分享URL:http://www.5511xx.com/article/cdisggg.html