|
| 1 | +--- |
| 2 | +editLink: false |
| 3 | +outline: deep |
| 4 | +outlineText: "33" |
| 5 | +--- |
| 6 | + |
| 7 | +# 高级变换与动画基础 |
| 8 | + |
| 9 | +1. 学习使用一个矩阵变换库,该库封装了矩阵运算的数学细节 |
| 10 | +2. 快速上手使用矩阵库,对图形进行复合变换 |
| 11 | +3. 在该矩阵库的帮助下,实现简单的动画效果 |
| 12 | + |
| 13 | +## 平移 然后旋转 |
| 14 | + |
| 15 | +平移、旋转、缩放等变换操作都可以用一个 4x4的矩阵表示。使用矩阵库可以简化编程(手动计算每个矩阵很耗费时间) |
| 16 | + |
| 17 | +`Matrix4`对象表示一个4x4的矩阵。该对象内部使用类型化数组`Float32Array`来存储矩阵的元素 |
| 18 | + |
| 19 | +**WebGL和OpenGL一样,矩阵元素是按列主序存储在数组中的** |
| 20 | + |
| 21 | +`mat4` 和 `vec4` 的区别: |
| 22 | + |
| 23 | +1. 定义和结构 |
| 24 | + - mat4: |
| 25 | + - 表示一个**4x4的矩阵**,用于进行各种线性变换,如平移、旋转、缩放和透视投影 |
| 26 | + - 包含16个元素(4行4列),通常以列优先的方式储存 |
| 27 | + - 如: |
| 28 | + ```smalltalk |
| 29 | + | m00 m01 m02 m03 | |
| 30 | + | m10 m11 m12 m13 | |
| 31 | + | m20 m21 m22 m23 | |
| 32 | + | m30 m31 m32 m33 | |
| 33 | + ``` |
| 34 | + - vec4: |
| 35 | + - 表示一个**4维向量**,通常用于表示点、方向或颜色 |
| 36 | + - 包含4个元素,通常是x,y,z,w |
| 37 | + - 如: |
| 38 | + ``` |
| 39 | + | x | |
| 40 | + | y | |
| 41 | + | z | |
| 42 | + | w | |
| 43 | + ``` |
| 44 | +2. 用途 |
| 45 | + - mat4 |
| 46 | + - 用于处理变换和投影。在图形渲染中,模型变换、视图变换和投影变换通常都会用到mat4 |
| 47 | + - 可以与vec4进行相乘,以应用变换 |
| 48 | + ```glsl |
| 49 | + vec4 transformedPositon = modelMatrix * originalPosition |
| 50 | + ``` |
| 51 | + - vec4 |
| 52 | + - 用于表示物体的位置、颜色或光照等特征。 |
| 53 | + - 位置:在3D空间中的点(通常w分量用于齐次坐标) |
| 54 | + - 颜色:RGBA颜色值(红、绿、蓝、透明度) |
| 55 | + - 也可以与其他向量进行运算 |
| 56 | + ```glsl |
| 57 | + vec4 color = vec4(1.0, 0.5, 0,0, 1.0) |
| 58 | + ``` |
| 59 | +3. 运算 |
| 60 | + - 矩阵和向量的运算: |
| 61 | + mat4和vec4可以结合使用,通过矩阵和向量的乘法进行变换。矩阵乘法会改变向量的坐标,应用变换效果 |
| 62 | + - 向量运算: |
| 63 | + vec4之间可以进行加减、点积、叉积等运算 |
| 64 | +
|
| 65 | +**mat4是一种用于表示和操作4x4矩阵的类型,主要用于变换** |
| 66 | +**vec4是一种表示4维向量的类型,主要用于表示颜色、位置和方向** |
| 67 | +
|
| 68 | +
|
| 69 | +**`gl.uniformMatrix4fv(location, transpose, array)`** |
| 70 | +
|
| 71 | +将*array*表示的4x4矩阵分配给由`location`指定的`uniform`变量 |
| 72 | +
|
| 73 | +| 参数 | 描述 | |
| 74 | +|-------------------|------------------------------| |
| 75 | +| location | uniform变量的存储位置 | |
| 76 | +| Transpose | 在WebGL中必须指定为false | |
| 77 | +| array | 带传输的类型化数组,4x4矩阵按列主序存储在其中 | |
| 78 | +| 返回值 | 无 | |
| 79 | +| 错误 | 描述 | |
| 80 | +| INVALID_OPERATION | 不存在当前程序对象 | |
| 81 | +| INVALID_VALUE | transpose不为false,或者数组的长度小于16 | |
| 82 | +
|
| 83 | +```js |
| 84 | +const VSHADER_SOURCE = |
| 85 | + 'attribute vec4 a_Position;\n' + |
| 86 | + 'uniform float u_CosB, u_SinB;\n' + // [!code --] |
| 87 | + 'uniform mat4 u_xformMatrix;\n' + // [!code ++] |
| 88 | + 'void main() {\n' + |
| 89 | + 'gl_Position.x = a_Position.x * u_CosB - a_Position.y * u_SinB;\n' + // [!code --] |
| 90 | + 'gl_Position.y = a_Position.x * u_SinB + a_Position.y * u_CosB;\n' + // [!code --] |
| 91 | + 'gl_Position.z = a_Position.z;\n' + // [!code --] |
| 92 | + 'gl_Position.w = 1.0;\n' + // [!code --] |
| 93 | + 'gl_Position = u_xformMatrix * a_Position;\n' + // [!code ++] |
| 94 | + '}\n' |
| 95 | +const FSHADER_SOURCE = |
| 96 | + ' void main() {\n' + |
| 97 | + 'gl_FragColor = vec4(1.0, 1.0, 0.0,1.0);\n' + |
| 98 | + '}\n' |
| 99 | +
|
| 100 | +
|
| 101 | +var ANGLE = 90.0 |
| 102 | +
|
| 103 | +function main() { |
| 104 | + var canvas = document.getElementById('webgl') |
| 105 | + var gl = getWebGLContext(canvas) |
| 106 | + if (!gl) { |
| 107 | + console.error('Failed to get the rendering context for WebGL') |
| 108 | + return; |
| 109 | + } |
| 110 | +
|
| 111 | + // 初始化着色器 |
| 112 | + if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { |
| 113 | + console.error('Failed to initialize shaders.') |
| 114 | + return; |
| 115 | + } |
| 116 | +
|
| 117 | + // 设置顶点着色器 |
| 118 | + var n = initVertexBuffers(gl); |
| 119 | +
|
| 120 | + if (n < 0) { |
| 121 | + console.error('Failed to set the positions of the vertices') |
| 122 | + return; |
| 123 | + } |
| 124 | +
|
| 125 | + var radian = Math.PI * ANGLE / 180.0; // [!code --] |
| 126 | + var conB = Math.cos(radian); // [!code --] |
| 127 | + var sinB = Math.sin(radian); // [!code --] |
| 128 | +
|
| 129 | + var u_CosB = gl.getUniformLocation(gl.program, 'u_CosB'); // [!code --] |
| 130 | + var u_SinB = gl.getUniformLocation(gl.program, 'u_SinB'); // [!code --] |
| 131 | +
|
| 132 | + gl.uniform1f(u_CosB, conB) // [!code --] |
| 133 | + gl.uniform1f(u_SinB, sinB) // [!code --] |
| 134 | +
|
| 135 | + var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix') // [!code ++] |
| 136 | +
|
| 137 | + var xformMatrix = new Matrix4() // [!code ++] |
| 138 | + xformMatrix.setRotate(ANGLE, 0, 0, 1) // [!code ++] |
| 139 | +
|
| 140 | + gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements) // [!code ++] |
| 141 | +
|
| 142 | +
|
| 143 | +
|
| 144 | + // // 获取attribut变量的存储位置 |
| 145 | + var a_Position = gl.getAttribLocation(gl.program, 'a_Position') |
| 146 | + // |
| 147 | + // var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor') |
| 148 | + if (a_Position < 0) { |
| 149 | + console.error('Failed to get the storage location of a_Position') |
| 150 | + return; |
| 151 | + } |
| 152 | +
|
| 153 | + // 设置canvas背景色 |
| 154 | + gl.clearColor(0.0, 0.0, 0.0, 1.0) |
| 155 | +
|
| 156 | + // 清空canvas |
| 157 | + gl.clear(gl.COLOR_BUFFER_BIT); |
| 158 | +
|
| 159 | + // 绘制三个点 |
| 160 | + gl.drawArrays(gl.TRIANGLE_FAN, 0, n) |
| 161 | +
|
| 162 | +} |
| 163 | +
|
| 164 | +function initVertexBuffers(gl) { |
| 165 | + var vertices = new Float32Array([ |
| 166 | + -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 |
| 167 | + ]) |
| 168 | + var n = 4 // 点的个数 |
| 169 | +
|
| 170 | + // 创建缓冲区对象 |
| 171 | + var vertexBuffer = gl.createBuffer(); |
| 172 | + if (!vertexBuffer) { |
| 173 | + console.error('Failed to create the buffer object') |
| 174 | + return -1; |
| 175 | + } |
| 176 | +
|
| 177 | + // 将缓冲区对象绑定到目标 |
| 178 | + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer) |
| 179 | +
|
| 180 | + // 向缓冲区对象中写入数据 |
| 181 | + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); |
| 182 | +
|
| 183 | + var a_Position = gl.getAttribLocation(gl.program, 'a_Position'); |
| 184 | +
|
| 185 | + // 将缓冲区对象分配给a_Position变量 |
| 186 | + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0) |
| 187 | +
|
| 188 | + // 连接a_Position变量与分配给它的缓冲对象 |
| 189 | + gl.enableVertexAttribArray(a_Position) |
| 190 | + return n |
| 191 | +} |
| 192 | +
|
| 193 | +``` |
| 194 | + |
| 195 | +`Matrix4` 对象所支持的方法和属性 |
| 196 | + |
| 197 | +| 方法和属性名称 | 描述 | |
| 198 | +|--------------------------------|-------------------------------------------------------------------------------------------| |
| 199 | +| Matrix4.setIdentity() | 将Matrix4实例初始化为单位阵 | |
| 200 | +| Matrix4.setTranslate(x,y,z) | 将Matrix4实例设置为平移变换矩阵,在x轴上平移的距离为x,在y轴<br/>上平移的距离为y,在z轴上平移的距离为在 | |
| 201 | +| Matrix4.setRotate(angle,x,y,z) | 将Matrix4实例设置为旋转变换矩阵,旋转的角度为angle,旋转轴为(x,y,z)。<br/>旋转轴(x,y,z)无须归一化 | |
| 202 | +| Matrix4.setScale(x,y,z) | 将Matrix4实例设置为缩放变换矩阵,在三个轴上的缩放因子分别为x,y和z | |
| 203 | +| Matrix4.translate(x,y,z) | 将Matrix4实例乘以一个平移变换矩阵(该平移矩阵在x轴上平移的距离为x,在y轴<br/>上平移的距离为y,在z轴上平移的距离为z),所得的结果还储存在Matrix4中 | |
| 204 | +| Matrix4.rotate(angle,x,y,z) | 将Matrix4实例乘以一个旋转变换矩阵(该旋转矩阵旋转的角度为angle,旋转轴为<br/>(x,y,z)。旋转轴(x,y,z)无须归一化),所得的结果还存储在Matrix4中 | |
| 205 | +| Matrix4.scale(x,y,z) | 将Matrix4实例乘以一个缩放变换矩阵(该缩放矩阵在三个轴上的缩放因子分别为x,y和z),所得的结果还储存在Matrix4中 | |
| 206 | +| Matrix4.set(m) | 将Matrix4实例设置为m,m必须也是一个Matrix4实例 | |
| 207 | +| Matrix4.elements | 类型化数组(Float32Array)包含了Matrix4 实例的矩阵元素 | |
0 commit comments