700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > WebGL编程指南四:利用矩阵进行平移旋转缩放变换

WebGL编程指南四:利用矩阵进行平移旋转缩放变换

时间:2022-09-02 07:24:54

相关推荐

WebGL编程指南四:利用矩阵进行平移旋转缩放变换

目标:掌握利用矩阵位移,旋转,缩放基本图形

准备

引入cuon-matrix.js矩阵库

基本概念

Matrix4类 cuon-matrix.js中为我们提供了Matrix4类,Matrix4对象(实例)表示一个4*4的矩阵,该对象内部使用类型化数组Floated32Array来存储矩阵的元素旋转

为描述一个旋转,你必须指明1.旋转轴(图形将围绕旋转轴旋转); 2.旋转方向(方向:顺时针或逆时针); 3.旋转角度(图形旋转经过的角度)。

在旋转中,关于“逆时针”的约定是:如果β是正值,观察者在Z轴正半轴某处,视线沿着Z轴负方向进行观察,那个看到的物体就是逆时针的,这种情况又可称为正旋转。我们也可以使用右手来确定旋转方向:右手握拳,大拇指伸直并指向旋转轴正方向,那么右手其余几个手指就指明了旋转的方向,因此正方向又可以称为右手法则旋转。本文默认使用右手法则旋转

本文旋转中这样描述旋转:绕Z轴,逆时针旋转β角度;必须掌握的方法

Matrix4对象所支持的方法和属性

上边的表格中,Matrix4对象有两种方法,一种方法名称中含有前缀set,这一种会根据参数计算出变换矩阵,然后将矩阵写入自身中,另一种不含set,这种会先根据参数计算出变换矩阵,然后将自身与刚刚计算得到的变换矩阵相乘,然后把最终得到的结果写入Matrix4对象中

单位阵在矩阵乘法中的行为,就像数字1在乘法中的行为一样,将一个矩阵乘以单位阵,得到的结果和原矩阵完全相同。在单位阵中,对角线上的元素为1.0,其余元素为0.0

变换等式

旋转后 的坐标 = 旋转矩阵 * 原始坐标(矢量)

缩放后 的坐标 = 缩放矩阵 * 原始坐标(矢量)

平移后 的坐标 = 平移矩阵 * 原始坐标(矢量)

平移后旋转 的坐标 = 旋转矩阵 * 平移后的坐标(矢量)

= 旋转矩阵 * (平移矩阵 * 原始坐标)

= (旋转矩阵 * 平移矩阵)* 原始坐标新坐标 = 变换矩阵 * 原始坐标

gl_Position = u_xformMatrix * a_Position;

一个模型可能经过了多次变换,将这些变换全部复合成一个等效的变换,就得到了模型变换,模型变换的矩阵称为模型矩阵。上式中(旋转矩阵*平移矩阵)就称为模型矩阵

方法

gl.uniformMatrix4fv(location, transpose, array)将array表示的4*4矩阵分配给location指定的uniform变量。transpose在WebGL中必须指定为false

示例程序

// 示例一(利用矩阵方法平移旋转三角形)var VSHADER_SOURCE = `attribute vec4 a_Position;\nuniform mat4 u_ModelMatrix;\nvoid main(){\ngl_Position = u_ModelMatrix * a_Position;\n}\n`var FSHADER_SOURCE = `void main(){\ngl_FragColor = vec4(1.0,0.0,0.0,1.0);\n}`var ANGLE = 60.0;// 旋转角度var Tx = 0.5;//平移function main () {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);gl.clearColor(0.0,0.0,0.0,1.0);if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)) {return;}var n = initVertexBuffers(gl);gl.clear(gl.COLOR_BUFFER_BIT);// 清空缓存区gl.drawArrays(gl.LINE_LOOP,0,n);// 绘制三角形}main();function initVertexBuffers(gl) {var vertices = new Float32Array([0.0,0.5,-0.5,-0.5,0.5,-0.5]); // 三个顶点坐标数据var n = 3; //顶点个数为3var vertexBuffer = gl.createBuffer();if (!vertexBuffer) {console.log('Failed to create the buffer object');return -1;}// 将顶点数据写入缓存区gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);var a_Position = gl.getAttribLocation(gl.program,'a_Position');gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(a_Position);//模型矩阵var modelMatrix = new Matrix4();/* 先平移后旋转modelMatrix.setRotate(ANGLE,0,0,1);modelMatrix.translate(Tx,0,0);*//* 先旋转后平移 */modelMatrix.setTranslate(Tx,0,0);modelMatrix.rotate(ANGLE,0,0,1);// 将模型矩阵传给attribute变量var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);return n;}

//示例二(分别平移、旋转、缩放三角形,自己手写矩阵,仅供参考)var VSHADER_SOURCE = `attribute vec4 a_Position;\nuniform mat4 u_xformMatrix;\nvoid main(){\ngl_Position = u_xformMatrix * a_Position;\n}\n`var FSHADER_SOURCE = `void main(){\ngl_FragColor = vec4(1.0,0.0,0.0,1.0);\n}`var ANGLE = 90.0;function main () {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);gl.clearColor(0.0,0.0,0.0,1.0);if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)) {return;}var n = initVertexBuffers(gl);gl.clear(gl.COLOR_BUFFER_BIT);// 清空缓存区gl.drawArrays(gl.LINE_LOOP,0,n); // 绘制三角形}main();function initVertexBuffers(gl) {var vertices = new Float32Array([0.0,0.5,-0.5,-0.5,0.5,-0.5]); // 三个顶点的坐标数据var n = 3;// 顶点个数为3var vertexBuffer = gl.createBuffer();if (!vertexBuffer) {console.log('Failed to create the buffer object');return -1;}// 将顶点数据写入缓存区gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);var a_Position = gl.getAttribLocation(gl.program,'a_Position');gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(a_Position);/* 旋转矩阵var radian = Math.PI * ANGLE / 180.0;var cosB = Math.cos(radian);var sinB = Math.sin(radian);var xformMatrix = new Float32Array([cosB, sinB, 0.0, 0.0,-sinB, cosB, 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0])*//* 平移矩阵var Tx = 0.5,Ty = 0.5,Tz = 0.5;var xformMatrix = 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, 1.0])*/// 缩放矩阵var Sx = 1.0, Sy = 1.5, Sz = 1.0;var xformMatrix = new Float32Array([Sx, 0.0, 0.0, 0.0,0.0, Sy, 0.0, 0.0,0.0, 0.0, Sz, 0.0,0.0, 0.0, 0.0, 1.0])/* 无任何变换的矩阵var xformMatrix = 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,0.0, 0.0, 0.0, 1.0]);*/// 将变换矩阵写入传给attribute变量var u_xformMatrix = gl.getUniformLocation(gl.program,'u_xformMatrix');gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix);return n;}

详解矩阵【矩阵的算法是表达式算法的另一种表达方式】

矩阵和矢量的乘法

矢量就是由多个分量组成的对象,如顶点的坐标(0, 0.5, 1);

矩阵和矢量的乘法可以写成如下形式

可见将矩阵和矢量相乘,就可以获得一个新的矢量。注意矩阵的乘法不符合交换律,A*B不等于B*A

上式中的矩阵为3*3矩阵,矩阵右侧是一个由x,y,z组成的矢量(表示点的坐标)。注意:只有在矩阵的列数和矢量的行数相等时,才可以将两者相乘

矩阵和等式的转换

假设点p的坐标为(x, y, z, 1),平移之后的点p’ 的坐标为(x’, y’, z’, 1);

如下表示:

矩阵的元素都是等式中的系数。平移矩阵必须为4*4矩阵,因为平移是加上一个常量,第四列均为常量。

一旦你熟悉这种矩阵表示法,进行变换就变得非常简单了。如果你不熟悉,你应当花点时间好好的理解它,变换矩阵的概念在三维图形学中非常重要

平移矩阵

缩放矩阵

旋转矩阵

旋转的数学表达式推导:

利用三角函数两角和公式,可得:

旋转矩阵为3*3矩阵,平移矩阵是4*4矩阵,为使他们阶数相同,比较如下等式:

JavaScript表示矩阵

JavaScript并没有专门表示矩阵的类型,你需要使用类型化数组Float32Array 存储矩阵的每个元素,但矩阵是二维的,其元素按照行和列进行排列,而数组是一维的,其元素只能排成一行。我们可以按照两种方式在数组中存储矩阵元素:按行主序(row major order)和按列主序(column major order)

WebGL和OpenGL一样,矩阵元素是按列主序存储在数组中的[a, e, i, m, b, f, j, n, c, …].

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。