几十个必备的设计师灵感网站,天津高端网站定制,饰品做商城网站模式,wordpress 分类浏览量学习使用一个矩阵变换库#xff0c;该库封装了矩阵运算的数学细节。快速上手使用该矩阵库#xff0c;对图形进行复合变换。在该矩阵库的帮助下#xff0c;实现简单的动画效果。 矩阵变换库#xff1a;cuon-matrix.js
OpenGL中的函数#xff1a; 书中 cuon-matrix.js 函数… 学习使用一个矩阵变换库该库封装了矩阵运算的数学细节。快速上手使用该矩阵库对图形进行复合变换。在该矩阵库的帮助下实现简单的动画效果。 矩阵变换库cuon-matrix.js
OpenGL中的函数 书中 cuon-matrix.js 函数库中是这样实现的
函数库主要创建了一个Matrix4类构造函数在该类原型函数下绑定了众多方法许多函数之前都留有注释我们主要看一下代码最前面的注释
/** * This is a class treating 4x4 matrix.* This class contains the function that is equivalent to OpenGL matrix stack.* The matrix after conversion is calculated by multiplying a conversion matrix from the right.* The matrix is replaced by the calculated result.*/根据注释可知该函数库主要处理4×4的矩阵对标OpenGL中矩阵处理函数。函数库提供了一个名为Matrix4的对象(构造函数)我们可以通过new方法创建它的实例对象内部挂载了许多关于矩阵计算的方法。
这样使用函数库的方法写起来更加简单
矩阵的创建方式
// RotatedTriangle_Matrix.js
...// 创建旋转矩阵let radian (Math.PI * ANGLE) / 180.0 // 转换为弧度制let cosB Math.cos(radian)let sinB Math.sin(radian)// 注意WebGL中矩阵是列主序的let 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,])...// RotatedTriangle_Matrix4.js
...// 创建旋转矩阵// 为旋转矩阵创建Matrix4对象let xformMatrix new Matrix4()// 将xformMatrix设置为旋转矩阵xformMatrix.setRotate(ANGLE, 0, 0, 1)
...传输矩阵数据
// RotatedTriangle_Matrix.js
...// 将旋转图形所需数据传输给顶点着色器let u_xformMatrix gl.getUniformLocation(gl.program, u_xformMatrix)if (!u_xformMatrix) {console.log(Failed to get the storage location of u_xformMatrix)}gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix)
...// RotatedTriangle_Matrix4.js
...let u_xformMatrix gl.getUniformLocation(gl.program, u_xformMatrix)if (!u_xformMatrix) {console.log(Failed to get the storage location of u_xformMatrix)}gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements)
...Matrix4在不提供数据直接初始化的情况下其挂载的element元素就是一个单位阵之后大部分操作都是对element元素进行的。
从上表可见Matrix4对象有两种方法
一种方法的名称中含有前缀set这一类方法会根据参数计算出变换矩阵然后将变换矩阵写入自身另一种方法的名称中不含set前缀这一类方法在计算出变换矩阵后会将自身与计算出的变换矩阵相乘最终结果写入Matrix4对象。
复合变换RotatedTranslatedTriangle.js 相关内容采用Matirx4对象运用矩阵乘法模拟符合变换。 相关函数Matrix4.setRotate(), Matrix4.translate() 注意矩阵乘法的先后顺序与模型变换的先后顺序有关不能随意变化(矩阵乘法不满足乘法交换律)。 注意是 左乘 一个模型可能经过了多次变换将这些变换全部复合成一个等效的变换就得到了模型变换(model transformation)或称建模变换(modeling transformation)相应的模型变换的矩阵称为模型矩阵(model matrix)。
重写Rotatedtriangle_Matrix4 代码
命名习惯在顶点着色器中命名uniform变量(mat4)为u_ModelMatrix取模型矩阵之意。
// 顶点着色器
var VSHADER_SOURCE attribute vec4 a_Position;\n uniform mat4 u_ModelMatrix;\n void main(){\n gl_Position u_ModelMatrix * a_Position;\n }\n构建矩阵时采用Matrix4对象先设置对象为旋转矩阵再和平移矩阵相乘。 // 创建Matrix4对象let modelMatrix new Matrix4()// 旋转角度let ANGLE 90.0// 平移距离let Tx 0.5// 设置模型矩阵为旋转矩阵modelMatrix.setRotate(ANGLE, 0, 0, 1)// 将模型矩阵乘以平移矩阵modelMatrix.translate(Tx, 0, 0)// 将模型矩阵传输给顶点着色器let u_ModelMatrix gl.getUniformLocation(gl.program, u_ModelMatrix)if (!u_ModelMatrix) {console.log(Failed to get the storage location of u_ModelMatrix)}gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)完整代码
// RotatedTranslatedTriangle.js
// 顶点着色器
var VSHADER_SOURCE attribute vec4 a_Position;\n uniform mat4 u_ModelMatrix;\n void main(){\n gl_Position u_ModelMatrix * a_Position;\n }\n
// 片元着色器
var FSHADER_SOURCE void main(){\n gl_FragColor vec4(1.0, 0.0, 0.0, 1.0);\n }\n// 主函数
function main() {// 获取canvas元素let canvas document.getElementById(webgl)// 获取WebGL上下文let 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 initialize shaders)return}// 设置顶点位置let n initVertexBuffers(gl)if (n 0) {console.log(Failed to set the positions of the vertices)return}// 创建Matrix4对象let modelMatrix new Matrix4()// 旋转角度let ANGLE 90.0// 平移距离let Tx 0.5// 设置模型矩阵为旋转矩阵modelMatrix.setRotate(ANGLE, 0, 0, 1)// 将模型矩阵乘以平移矩阵modelMatrix.translate(Tx, 0, 0)// 将模型矩阵传输给顶点着色器let u_ModelMatrix gl.getUniformLocation(gl.program, u_ModelMatrix)if (!u_ModelMatrix) {console.log(Failed to get the storage location of u_ModelMatrix)}gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}function initVertexBuffers(gl) {// 设置类型化数组和顶点数let vertices new Float32Array([0.0, 0.3, -0.3, -0.3, 0.3, -0.3])let n 3// 创建缓冲区对象let 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.STREAM_DRAW)let 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}// 将缓冲区分配给attribute变量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)// 开启attribute变量(连接)gl.enableVertexAttribArray(a_Position)return n
}动画-RotatingTriangle.js 相关内容通过JavaScript灵活设计WebGL系统通过反复变换和重绘图形生成动画效果setInterval()系列函数和requestAnimationgFrame()系列函数的异同。相关函数setInterval(), requestAnimationFrame(), cancelAnimationFrame() 机制一在t0、t1、t2、t3等时刻反复调用同一个函数来绘制三角形。机制二每次绘制之前清除上次绘制的内容并使三角形旋转相应的角度。
基于此该实例程序与前面的示例有以下三点区别
实现反复调用绘制函数的机制机制一定义绘制函数在绘制函数中包括清空绘图区、向着色器传值、绘制三步由于程序需要反复绘制所以在一开始就指定了背景色。
// RotatedTranslatedTriangle.js
// 顶点着色器
var VSHADER_SOURCE attribute vec4 a_Position;\n uniform mat4 u_ModelMatrix;\n void main(){\n gl_Position u_ModelMatrix * 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_STEP 45.0// 主函数
function main() {// 获取canvas元素let canvas document.getElementById(webgl)// 获取WebGL上下文let 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 initialize shaders)return}// 设置顶点位置let n initVertexBuffers(gl)if (n 0) {console.log(Failed to set the positions of the vertices)return}// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 获取u_ModelMatrix变量存储位置let u_ModelMatrix gl.getUniformLocation(gl.program, u_ModelMatrix)if (!u_ModelMatrix) {console.log(Failed to get the storage location of u_ModelMatrix)}// 三角形当前旋转角度let currentAngle 0.0// 模型矩阵Matrix4对象let modelMatrix new Matrix4()// 开始绘制三角形let tick function () {currentAngle animate(currentAngle) // 更新旋转角draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix)requestAnimationFrame(tick) // 请求浏览器调用tick}tick()
}function initVertexBuffers(gl) {// 设置类型化数组和顶点数let vertices new Float32Array([0.0, 0.3, -0.3, -0.3, 0.3, -0.3])let n 3// 创建缓冲区对象let 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.STREAM_DRAW)let 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}// 将缓冲区分配给attribute变量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)// 开启attribute变量(连接)gl.enableVertexAttribArray(a_Position)return n
}
function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {// 设置旋转矩阵modelMatrix.setRotate(currentAngle, 0, 0, 1)// 旋转前加个平移// modelMatrix.translate(0.5, 0, 0)// 将旋转矩阵传输给顶点着色器gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}// 记录上一次调用函数的时刻
var g_last Date.now()
// 更新旋转角
function animate(angle) {// 计算距离上次调用经过多长时间let now Date.now()let elapsed now - g_last // 毫秒g_last now// 根据上次调用的时间更新当前旋转角度let newAngle angle (ANGLE_STEP * elapsed) / 1000.0return (newAngle % 360)
}重复调用函数的方法 // 开始绘制三角形let tick function () {currentAngle animate(currentAngle) // 更新旋转角draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) // 绘制三角形requestAnimationFrame(tick) // 请求浏览器调用tick}tick()该方法是一个诞生较早的方法其出现时浏览器还没有支持多标签页所以在现代浏览器中不论标签页是否被激活该方法都会反复调用func如果标签页较多就会增加浏览器的负荷。 这一方法只有当标签页处于激活状态时才会生效基于此也无法指定重复调用的时间间隔。 更新旋转角度
...
// 旋转速度(度/秒)
var ANGLE_STEP 45.0
...
// 记录上一次调用函数的时刻
var g_last Date.now()
// 更新旋转角
function animate(angle) {// 计算距离上次调用经过多长时间let now Date.now()let elapsed now - g_last // 毫秒g_last now// 根据上次调用的时间更新当前旋转角度let newAngle angle (ANGLE_STEP * elapsed) / 1000.0return (newAngle % 360)
}animate()是更新旋转角的主要部分该函数配合当前旋转角currentAngle变量、全局变量ANGLE_STEP变量(旋转速度)和g_last(上一次调用函数的时刻)使用基本思路是根据本次调用与上次调用之间的时间间隔来决定这一帧的旋转角度比上一帧大出多少
绘制函数的设计
/*** 绘制三角形* param {WebGLRenderingContext} gl 上下文对象* param {number} n 顶点数量 int* param {number} currentAngle 当前旋转角度 float* param {Martix4} modelMatrix 根据当前的旋转角度计算出的旋转矩阵存储在Martix4对象中* param {number} u_ModelMatrix 顶点着色器中同名的uniform变量的存储位置 uint*/
function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {// 设置旋转矩阵modelMatrix.setRotate(currentAngle, 0, 0, 1)// 将旋转矩阵传输给顶点着色器gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}参考【《WebGL编程指南》读书笔记-高级变换与动画基础】_webgl高级-CSDN博客