首先咱们来看如何实现图形的平移操做。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
能够看到,这样处理图形移动的话很好理解,可是由于一个移动,咱们声明了两个 uniform 变量来实现。而且分开设置的 xyz 坐标,很是的不方便。web
因此,在处理webgl变换(平移、缩放、旋转)的时候,一般使用矩阵来实现。接下来就来看看,如何使用矩阵实现图形的平移。canvas
推导平移矩阵的步骤:动画
首先让咱们来看一幅图片。webgl
这幅图片的意义就是咱们将橙色的三角形移动到蓝色虚线三角形处。ui
移动以后的蓝色虚线三角形的三个坐标分别为spa
在 webgl 中,一般使用矩阵来实现图形变换。下面咱们来看看矩阵如何表示。code
左侧是平移以前的原始坐标,中间的是一个平移矩阵,通过二者相乘,能够获得一个平移以后的坐标。
如今咱们来看下平移矩阵如何计算得出
首先经过上述图片中的矩阵咱们来获得几个方程式。用左侧的列分别乘矩阵的行,能够获得一下公式
公式合并:
将第一节 里的四个方程式和第二节里的四个方程式合并,能够获得以下结果:
通过上述方程式,能够获得一个平移的矩阵:
| 1 0 0 x |
| 0 1 0 y |
| 0 0 1 z |
| 0 0 0 1 |
以后将平移矩阵和原始坐标相乘,就能够获得平移以后的坐标。
来看看使用矩阵如何处理图形的平移。
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代加工
<!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>
至此,经过矩阵控制图形移动就所有实现完成了。