webgl變換:深刻圖形平移

1. 圖形平移

首先咱們來看如何實現圖形的平移操做。javascript

平移的操做就是將圖形的原始座標加上對應的移動距離。首先來看下平移的實現html

const vertexShaderSource = "" + "attribute vec4 apos;" + // 定義一個座標 "uniform float x;" + // 處理 x 軸移動 "uniform float y;" + // 處理 y 軸移動 "void main(){" + " gl_Position.x = apos.x + x;" + " gl_Position.y = apos.y + y;" + " gl_Position.z = 0.0;" + // z軸固定 " gl_Position.w = 1.0;" + "}"; const fragmentShaderSource = "" + "void main(){" + " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" + "}"; // initShader已經實現了不少次,本次就再也不贅述了 const program = initShader(gl,vertexShaderSource,fragmentShaderSource); const buffer = gl.createBuffer(); const data = new Float32Array([ 0.0,0.0, -0.5,-0.5, 0.5,-0.5, ]); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW); const aposlocation = gl.getAttribLocation(program,'apos'); const xlocation = gl.getUniformLocation(program,'x'); const ylocation = gl.getUniformLocation(program,'y'); gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0); gl.enableVertexAttribArray(aposlocation); let x = 0.0; let y = 0.0; function run () { gl.uniform1f(xlocation,x += 0.01); gl.uniform1f(ylocation,y += 0.01); gl.drawArrays(gl.TRIANGLES,0,3); // 使用此方法實現一個動畫 requestAnimationFrame(run) } run() 

解釋:java

  • 首先聲明一個變量 x 和變量 y ,用來處理 x軸 和 y軸 的座標。這裏使用的是 uniform 變量,由於平移的操做對於圖形上的全部頂點都有影響。
  • 經過 gl_Position.[xyzw] 來分別設置 x、y、z、w 的值。用於改變圖形位置。
  • 使用 gl.uniform1f 來爲 x 和 y 賦值
  • 使用 requestAnimationFrame 實現一個緩動動畫。方便觀察效果。
  • 其餘的操做,緩衝區,繪製,賦值,激活,

能夠看到,這樣處理圖形移動的話很好理解,可是由於一個移動,咱們聲明瞭兩個 uniform 變量來實現。而且分開設置的 xyz 座標,很是的不方便。web

因此,在處理webgl變換(平移、縮放、旋轉)的時候,一般使用矩陣來實現。接下來就來看看,如何使用矩陣實現圖形的平移。canvas

 

2. 平移矩陣

推導平移矩陣的步驟:動畫

  • 獲取平移先後的圖形座標(三維)
  • 計算平移先後的差值
  • 帶入到平移矩陣
  • 處理圖形頂點
  • 得到平移後的圖形

2.1 平移矩陣的推導

首先讓咱們來看一幅圖片。webgl

這幅圖片的意義就是咱們將橙色的三角形移動到藍色虛線三角形處。ui

移動以後的藍色虛線三角形的三個座標分別爲spa

  • x’ = x + x1
  • y' = y + y1
  • z' = z + z1
  • w=1 齊次座標爲1

2.2 得到平移矩陣

在 webgl 中,一般使用矩陣來實現圖形變換。下面咱們來看看矩陣如何表示。code

左側是平移以前的原始座標,中間的是一個平移矩陣,通過二者相乘,能夠獲得一個平移以後的座標。

如今咱們來看下平移矩陣如何計算得出

首先經過上述圖片中的矩陣咱們來獲得幾個方程式。用左側的列分別乘矩陣的行,能夠獲得一下公式

  • ax + by + cz + w = x'
  • ex + fy + gz + h = y'
  • ix + jy + kz + l = z'
  • mx + ny + oz + p = w'

公式合併:

第一節 裏的四個方程式和第二節裏的四個方程式合併,能夠獲得以下結果:

  • ax + by + cz + w = x + x1':只有當 a = 1,b = c = 0, w = x1 的時候,等式左右兩邊成立
  • ex + fy + gz + h = y + y1':只有當 f = 1, e = g = 0, h = y1 的時候,等式左右兩邊成立
  • ix + jy + kz + l = z + z1':只有當 k = 1,i = j = 0, l = z1 的時候,等式左右兩邊成立
  • mx + ny + oz + p = 1':只有當 m = n = o = 0, p = 1 的時候,等式左右兩邊成立

通過上述方程式,能夠獲得一個平移的矩陣:

| 1 0 0 x |

 

| 0 1 0 y |

| 0 0 1 z |

| 0 0 0 1 |

以後將平移矩陣和原始座標相乘,就能夠獲得平移以後的座標。

 

3. 矩陣實戰

來看看使用矩陣如何處理圖形的平移。

第一步,建立着色器源代碼
const vertexShaderSource = "" + "attribute vec4 apos;" + "uniform mat4 mat;" + // 建立一個 uniform 變量,表明平移矩陣 "void main(){" + " gl_Position = mat * apos;" + // 矩陣與原始座標相乘 "}"; const fragmentShaderSource = "" + "void main(){" + " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" + "}"; 
第二步,建立平移矩陣
let Tx = 0.1; //x座標的位置 let Ty = 0.1; //y座標的位置 let Tz = 0.0; //z座標的位置 let Tw = 1.0; //差值 const mat = new Float32Array([ 1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, Tx,Ty,Tz,Tw, ]); 

這裏能夠看到,使用的矩陣和咱們推導出來的矩陣不太同樣,推導的平移矩陣裏 xyzw 位於矩陣的右側,如今是位於矩陣的底部,這是爲何呢?

這是由於在 webgl 中,矩陣的使用須要按照 左上右下 的對角線作一次翻轉。因此使用的矩陣,xyzw 位於底部

第三步,繪製一個三角形
const program = initShader(gl,vertexShaderSource,fragmentShaderSource); const aposlocation = gl.getAttribLocation(program,'apos'); const data = new Float32Array([ 0.0,0.0, -.3,-.3, .3,-.3 ]); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW); gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0); gl.enableVertexAttribArray(aposlocation); gl.drawArrays(gl.TRIANGLES,0,3); // 第五步的時候會重寫 
第四步,獲取矩陣變量,給矩陣賦值
const matlocation = gl.getUniformLocation(program,'mat'); gl.uniformMatrix4fv(matlocation,false,mat); 

這裏使用 gl.uniformMatrix4fv 來給矩陣賦值。

第五步,添加緩動動畫
function run () { Tx += 0.01 Ty += 0.01 const mat = new Float32Array([ 1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, Tx,Ty,Tz,Tw, ]); gl.uniformMatrix4fv(matlocation,false,mat); gl.drawArrays(gl.TRIANGLES,0,3); // 使用此方法實現一個動畫 requestAnimationFrame(run) } run()

http://www.ssnd.com.cn 化妝品OEM代加工

4. 完整代碼

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <canvas id="webgl" width="500" height="500"></canvas> <script> const gl = document.getElementById('webgl').getContext('webgl'); const vertexShaderSource = "" + "attribute vec4 apos;" + "uniform mat4 mat;" + "void main(){" + " gl_Position = mat * apos;" + "}"; const fragmentShaderSource = "" + "void main(){" + " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" + "}"; const program = initShader(gl,vertexShaderSource,fragmentShaderSource); const aposlocation = gl.getAttribLocation(program,'apos'); const matlocation = gl.getUniformLocation(program,'mat'); const data = new Float32Array([ 0.0,0.0, -.3,-.3, .3,-.3 ]); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW); gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0); gl.enableVertexAttribArray(aposlocation); let Tx = 0.1; //x座標的位置 let Ty = 0.1; //y座標的位置 let Tz = 0.0; //z座標的位置 let Tw = 1.0; //差值 function run () { Tx += 0.01 Ty += 0.01 const mat = new Float32Array([ 1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, Tx,Ty,Tz,Tw, ]); gl.uniformMatrix4fv(matlocation,false,mat); gl.drawArrays(gl.TRIANGLES,0,3); // 使用此方法實現一個動畫 requestAnimationFrame(run) } run() function initShader(gl,vertexShaderSource,fragmentShaderSource){ const vertexShader = gl.createShader(gl.VERTEX_SHADER); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vertexShader,vertexShaderSource); gl.shaderSource(fragmentShader,fragmentShaderSource); gl.compileShader(vertexShader); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program,vertexShader); gl.attachShader(program,fragmentShader) gl.linkProgram(program); gl.useProgram(program); return program; } </script> </body> </html> 

至此,經過矩陣控制圖形移動就所有實現完成了。

相關文章
相關標籤/搜索