蓝色系网站设计,网站的开发语言有哪些,做 58 那样的网站,wordpress新增管理员目录
变换矩阵#xff1a;旋转
变换矩阵#xff1a;平移
44的旋转矩阵
示例代码#xff1a;
gl.uniformMatrix4fv#xff08;#xff09;规范 平移#xff1a;相同的策略 变换矩阵#xff1a;缩放 变换矩阵#xff1a;旋转
对于简单的变换#xff0c;你可以使用…目录
变换矩阵旋转
变换矩阵平移
4×4的旋转矩阵
示例代码
gl.uniformMatrix4fv规范 平移相同的策略 变换矩阵缩放 变换矩阵旋转
对于简单的变换你可以使用数学表达式来实现。但是当情形逐渐变得复杂时你很快就会发现利用表达式运算实际上相当繁琐。比如下图显示了一个“旋转后平移”的过程如果使用数学表达式我们就需要两种变换的等式叠加获得一个新的等式然后在顶点着色器中实现。 但是如果这样做每次都需要进行一次新的变换我们就需要重新求取一个新的等式然后实现一个新的着色器这当然很不科学。好在我们可以使用另一个数学工具——变换矩阵来完成这项工作。变换矩阵非常适合操作计算机图形。
如下图所示矩阵是一个矩形的二维数组数字按照行水平方向和列垂直方向排列数字两侧的方括号表示这些数字是一个整体一个矩阵。我们将使用矩阵来表示前面的计算过程。 在解释如何使用变换矩阵来替代数学表达式之前你需要理解矩阵和矢量的乘法。矢量就是由多个分量组成的对象比如顶点的坐标0.00.51.0。
矩阵和矢量的乘法可以写成如下等式一的形式虽然乘号“×”通常被忽略不写但是为了强调本书中我们总是明确地将这个符号写出来。可见将矩阵中间和矢量右边相乘就获得了一个新的矢量左边。注意矩阵的乘法不符合交换律也就是说A×B和B×A并不相等。 上式中的这个矩阵具有3行3列因此又被称为3×3矩阵。矩阵右侧是一个由x、y、z组成的矢量为了与矢量相乘矢量被写成列的形式其仍然表示点的坐标。矢量具有3个分量因此被称为三维矢量。再次说明数字两侧的方括号表示这些数字是一个整体一个矢量。
在本例中矩阵与矢量相乘得到的新矢量其三个分量为x、y、z其值如下等式二所示。注意只有在矩阵的列数与矢量的行数相等时才可以将两者相乘。 xaxbycz ydxeyfz zgxhyiz 现在为了理解矩阵是如何代替数学表达式的下面将矩阵等式与数学表达式如下等式三即WebGL非矩阵变换_山楂树の的博客-CSDN博客 中的等式R4进行比较。 等式三 x x cosβ - y sinβ y x sinβ y cosβ z z 与比较关于x的表达式进行比较 xaxbycz xx cos β-y sin β 这样的话如果设acosβb-sinβc0那么这两个等式就完全相同了。再来看一下y ydxeyfz yx sin βy cos β 这样的话设dsinβecosβf0两个等式也就完全相同了。最后的关于z的等式更简单设g0h0i1即可。 接下来将这些结果代入到等式一中得到等式四 这个矩阵就被称为变换矩阵transformation matrix因为它将右侧的矢量xyz“变换”为了左侧的矢量xyz。上面这个变换矩阵进行的变换是一次旋转所以这个矩阵又可以被称为旋转矩阵
可以看到等式三中矩阵的元素都是等式二中的系数。一旦你熟悉这种矩阵表示法进行变换就变得非常简单了。变换矩阵的概念在三维图形学中非常重要。
变换矩阵在三维计算机图形学中应用得如此广泛以致于着色器本身就实现了矩阵和矢量相乘的功能。但是在我们修改着色器代码以采用矩阵之前先来快速浏览一遍除了旋转矩阵的其他几种变换矩阵。
变换矩阵平移
显然如果我们使用变换矩阵来表示旋转变换我们就也应该使用它来表示其他变换比如平移。比较一下等式二和平移的数学表达式如下所示 这里第二个等式的右侧有常量项Tx第一个等式中没有这意味着我们无法通过使用一个3×3的矩阵来表示平移。为了解决这个问题我们可以使用一个4×4的矩阵以及具有第4个分量通常被设为1.0的矢量。也就是说我们假设点p的坐标为xyz1平移之后的点p的坐标为xyz1如等式等式五所示 该矩阵的乘法的结果如下等式六 xaxbycz d yexfygzh zixjykz l 1mxnyoz p 根据最后一个式子1mxnyozp很容易求算出系数m0n0o0p1。这些方程都有常数项d、h、l和p看上去比较适合平移等式因为平移等式也有常数项。平移等式如下所示我们将它与等式六进行比较 xxTx yyTy zzTz 比较x可知a1b0c0dTx类似地比较y可知e0f1g0hTy比较z可知i0j0k1lTz。这样你就可以写出表示平移的矩阵又称为平移矩阵如等式七所示 4×4的旋转矩阵
至此我们已经成功地创建了一个旋转矩阵和一个平移矩阵这两个矩阵的作用与此前示例程序中的数学表达式的作用是一样的那就是计算变换后的顶点坐标。在“先旋转再平移”的情形下我们需要将两个矩阵组合起来你应该记得这也是我们使用矩阵的初衷然而旋转矩阵3×3矩阵与平移矩阵4×4矩阵的阶数不同。我们不能把两个阶数不一样的矩阵组合起来所以得使用某种手段使这两个矩阵的阶数一致。
将旋转矩阵从一个3×3矩阵转变为一个4×4矩阵只需要将等式三和等式六比较一下即可。 xx cos β-y sin β yx sin βy cos β zz xaxbyczd yexfygzh zixjykzl 1mxnyozp 例如当你通过比较xx cosβ- y sinβ与xaxbyczd时可知acosβb-sinβc0d0。以此类推求得y和z等式中的系数最终得到4×4的旋转矩阵如等式八所示 这样我们就可以使用相同阶数4×4的矩阵来表示平移和旋转实现了最初的目标
示例代码 在创建了4×4的旋转矩阵之后我们使用旋转矩阵来重写之前的示例程序令三角形绕Z轴逆时针旋转90度。例如下显示了本例的代码其运行结果与 WebGL非矩阵变换_山楂树の的博客-CSDN博客 的旋转实例完全一致。
var VSHADER_SOURCE attribute vec4 a_Position;\n uniform mat4 u_xformMatrix;\n void main() {\n gl_Position u_xformMatrix * a_Position;\n }\n;var FSHADER_SOURCE void main() {\n gl_FragColor vec4(1.0, 0.0, 0.0, 1.0);\n }\n;var ANGLE 90.0;
// var tx 0.5, ty 0.5, tz0 平移矩阵所用function main() {var canvas document.getElementById(webgl);var gl getWebGLContext(canvas);if (!gl) {console.log(Failed to get the rendering context for WebGL);return;}if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.log(Failed to intialize shaders.);return;}var n initVertexBuffers(gl);if (n 0) {console.log(Failed to set the positions of the vertices);return;}var radian Math.PI * ANGLE / 180.0; // Convert to radiansvar cosB Math.cos(radian), 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 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 u_xformMatrix gl.getUniformLocation(gl.program, u_xformMatrix);if (!u_xformMatrix) {console.log(Failed to get the storage location of u_xformMatrix);return;}gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);gl.clearColor(0, 0, 0, 1);gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLES, 0, n);
}function initVertexBuffers(gl) {var vertices new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);var n 3; // The number of verticesvar vertexBuffer gl.createBuffer();if (!vertexBuffer) {console.log(Failed to create the buffer object);return false;}gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);var a_Position gl.getAttribLocation(gl.program, a_Position);if (a_Position 0) {console.log(Failed to get the storage location of a_Position);return -1;}gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(a_Position);return n;
}
首先来看看顶点着色器 u_xformMatrix变量表示等式八中的旋转矩阵a_Position变量表示顶点的坐标即等式八中右侧的矢量二者相乘得到变换后的顶点坐标与等式八中相同。
示例程序中你可以在一行代码中完成矢量相加的运算gl_Positiona_Positionu_Translate。同样你也可以在一行代码中完成矩阵与矢量相乘的运算gl_Positionu_xformMatrix a_Position。这时因为着色器内置了常用的矢量和矩阵运算功能这种强大特性正是专为三维计算机图形学而设计的。
由于变换矩阵是4×4的GLSL ES需要知道每个变量的类型所以我们将u_xformMatrix定义为mat4类型。如你所料mat4类型的变量就是4×4的矩阵。
JavaScript按照等式八计算旋转矩阵然后将其传给u_xformMatrix。 这段代码首先计算了90度的正弦值和余弦值这两个值需要被用来构建旋转矩阵之后创建了Float32Array类型的xformMatrix变量表示旋转矩阵。与GLSL ES不同JavaScript并没有专门表示矩阵的类型所以你需要使用类型化数组Float32Array。我们在数组中存储矩阵的每个元素但问题是矩阵是二维的其元素按照行和列进行排列而数组是一维的其元素只是排成一行。这里我们可以按照两种方式在数组中存储矩阵元素按行主序row major oder和按列主序column major order如下图所示。 WebGL和OpenGL一样矩阵元素是按列主序存储在数组中的。比如图3.27所示的矩阵存储在数组中就是这样的a, e, i, m, b, f, j, n, c, g, k, o, d, h, l, p] 。本例中旋转矩阵也是按照这样的顺序存储在Float32Array类型的数组中的。
最后我们使用gl.uniformMatrix4fv函数将刚刚生成的数组传给u_xformMatrix变量。注意函数名的最后一个字母是v表示它可以向着色器传输多个数据值。
gl.uniformMatrix4fv规范 平移相同的策略
如你所见4×4的矩阵不仅可以用来表示平移也可以用来表示旋转。不管是平移还是旋转你都使用如下形式来进行矩阵和矢量的运算以完成变换新坐标变换矩阵 旧坐标比如在着色器中 这意味着如果我们改变数组xformMatrix中的元素使之成为一个平移矩阵那么就可以实现平移操作其效果就和之前使用数学表达式进行的平移操作一样。
因此修改4x4旋转矩阵代码将旋转角度修改为与平移相关的变量 我们还需重写创建矩阵的代码记住矩阵是按列主序存储的。虽然xformMatrix现在是一个平移矩阵了但我们仍使用这个变量名。因为对于着色器而言旋转矩阵和平移矩阵其实是一回事。最后你不会用到ANGLE变量把与旋转相关的代码注释掉 变换矩阵缩放
最后我们来学习缩放变换矩阵。仍然假设最初的点p经过缩放操作之后变成了p。 假设在三个方向X轴Y轴Z轴的缩放因子S xS× x ySy y zSz z 将上式与等式六作比较可知缩放操作的变换矩阵 和之前的例子一样我们只要将缩放矩阵传给xformMatrix变量就可以直接使用4x4旋转矩阵中的着色器对三角形进行缩放操作了。下面这个示例程序会将三角形在垂直方向上拉伸到1.5倍如图所示。