在此示例中,我们实际上将旋转正方形平面。
使正方形旋转
让我们开始旋转正方形。我们需要的第一件事是创建一个变量,用于跟踪正方形的当前旋转:
var squareRotation = 0.0;
现在我们需要更新drawScene()函数以在绘制正方形时将当前旋转应用于正方形。转换为正方形的初始绘图位置后,我们像这样应用旋转:
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatesquareRotation, // amount to rotate in radians[0, 0, 1],
); // axis to rotate around
这会将 modelViewMatrix 的当前值squareRotation绕 Z 轴旋转。
要进行动画制作,我们需要添加squareRotation随时间更改值的代码。为此,我们可以创建一个新变量来跟踪上次动画播放的时间(我们称之为then),然后将以下代码添加到主函数的末尾
var then = 0;// Draw the scene repeatedly
function render(now) {now *= 0.001; // convert to secondsconst deltaTime = now - then;then = now;drawScene(gl, programInfo, buffers, deltaTime);requestAnimationFrame(render);
}
requestAnimationFrame(render);
该代码用于 requestAnimationFrame 要求浏览器在每一帧上调用函数“render”。requestAnimationFrame 自页面加载以来经过的时间(以毫秒为单位)。我们将其转换为秒,然后从中减去,以计算 deltaTime 自渲染最后一帧以来的秒数。在 drawscene 的结尾,我们添加了要更新的代码 squareRotation。
squareRotation += deltaTime;
源码如下:
// webgl-demo.js
import { initBuffers } from "./init-buffers.js";
import { drawScene } from "./draw-scene.js";let squareRotation = 0.0;
let deltaTime = 0;main();//
// start here
//
function main() {const canvas = document.querySelector("#glcanvas");// Initialize the GL contextconst gl = canvas.getContext("webgl");// Only continue if WebGL is available and workingif (gl === null) {alert("Unable to initialize WebGL. Your browser or machine may not support it.");return;}// Set clear color to black, fully opaquegl.clearColor(0.0, 0.0, 0.0, 1.0);// Clear the color buffer with specified clear colorgl.clear(gl.COLOR_BUFFER_BIT);// Vertex shader programconst vsSource = `attribute vec4 aVertexPosition;attribute vec4 aVertexColor;uniform mat4 uModelViewMatrix;uniform mat4 uProjectionMatrix;varying lowp vec4 vColor;void main(void) {gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;vColor = aVertexColor;}`;// Fragment shader programconst fsSource = `varying lowp vec4 vColor;void main(void) {gl_FragColor = vColor;}`;// Initialize a shader program; this is where all the lighting// for the vertices and so forth is established.const shaderProgram = initShaderProgram(gl, vsSource, fsSource);// Collect all the info needed to use the shader program.// Look up which attributes our shader program is using// for aVertexPosition, aVertexColor and also// look up uniform locations.const programInfo = {program: shaderProgram,attribLocations: {vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),},uniformLocations: {projectionMatrix: gl.getUniformLocation(shaderProgram,"uProjectionMatrix"),modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),},};// Here's where we call the routine that builds all the// objects we'll be drawing.const buffers = initBuffers(gl);let then = 0;// Draw the scene repeatedlyfunction render(now) {now *= 0.001; // convert to secondsdeltaTime = now - then;then = now;drawScene(gl, programInfo, buffers, squareRotation);squareRotation += deltaTime;requestAnimationFrame(render);}requestAnimationFrame(render);
}//
// Initialize a shader program, so WebGL knows how to draw our data
//
function initShaderProgram(gl, vsSource, fsSource) {const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);// Create the shader programconst shaderProgram = gl.createProgram();gl.attachShader(shaderProgram, vertexShader);gl.attachShader(shaderProgram, fragmentShader);gl.linkProgram(shaderProgram);// If creating the shader program failed, alertif (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {alert(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);return null;}return shaderProgram;
}//
// creates a shader of the given type, uploads the source and
// compiles it.
//
function loadShader(gl, type, source) {const shader = gl.createShader(type);// Send the source to the shader objectgl.shaderSource(shader, source);// Compile the shader programgl.compileShader(shader);// See if it compiled successfullyif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`);gl.deleteShader(shader);return null;}return shader;
}
// draw-scene.js
function drawScene(gl, programInfo, buffers, squareRotation) {gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaquegl.clearDepth(1.0); // Clear everythinggl.enable(gl.DEPTH_TEST); // Enable depth testinggl.depthFunc(gl.LEQUAL); // Near things obscure far things// Clear the canvas before we start drawing on it.gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// Create a perspective matrix, a special matrix that is// used to simulate the distortion of perspective in a camera.// Our field of view is 45 degrees, with a width/height// ratio that matches the display size of the canvas// and we only want to see objects between 0.1 units// and 100 units away from the camera.const fieldOfView = (45 * Math.PI) / 180; // in radiansconst aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;const zNear = 0.1;const zFar = 100.0;const projectionMatrix = mat4.create();// note: glmatrix.js always has the first argument// as the destination to receive the result.mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);// Set the drawing position to the "identity" point, which is// the center of the scene.const modelViewMatrix = mat4.create();// Now move the drawing position a bit to where we want to// start drawing the square.mat4.translate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to translate[-0.0, 0.0, -6.0]); // amount to translate// 关键数据mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatesquareRotation, // amount to rotate in radians[0, 0, 1]);// Tell WebGL how to pull out the positions from the position// buffer into the vertexPosition attribute.setPositionAttribute(gl, buffers, programInfo);setColorAttribute(gl, buffers, programInfo);// Tell WebGL to use our program when drawinggl.useProgram(programInfo.program);// Set the shader uniformsgl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix,false,projectionMatrix);gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix,false,modelViewMatrix);{const offset = 0;const vertexCount = 4;gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);}
}// Tell WebGL how to pull out the positions from the position
// buffer into the vertexPosition attribute.
function setPositionAttribute(gl, buffers, programInfo) {const numComponents = 2; // pull out 2 values per iterationconst type = gl.FLOAT; // the data in the buffer is 32bit floatsconst normalize = false; // don't normalizeconst stride = 0; // how many bytes to get from one set of values to the next// 0 = use type and numComponents aboveconst offset = 0; // how many bytes inside the buffer to start fromgl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}// Tell WebGL how to pull out the colors from the color buffer
// into the vertexColor attribute.
function setColorAttribute(gl, buffers, programInfo) {const numComponents = 4;const type = gl.FLOAT;const normalize = false;const stride = 0;const offset = 0;gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);gl.vertexAttribPointer(programInfo.attribLocations.vertexColor,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
}export { drawScene };
WebGL 应用程序中的 mat4.rotate
函数对模型视图矩阵(modelViewMatrix)进行旋转操作。下面是这段代码的详细解释:
mat4.rotate(out, a, rad, axis)
out
:表示结果存储的目标矩阵,即进行旋转操作后的矩阵将存储在这里。a
:表示要进行旋转操作的原始矩阵,即待旋转的矩阵。rad
:表示旋转的角度,以弧度为单位。axis
:表示一个包含 x、y 和 z 分量的数组,指定了旋转的轴向量。
在这段代码中,mat4.rotate
函数的作用是将模型视图矩阵 modelViewMatrix
绕指定的轴进行旋转。具体解释如下:
modelViewMatrix
是一个 4x4 的矩阵,用于表示模型在世界坐标系中的位置和方向。modelViewMatrix
同时作为目标矩阵和原始矩阵,表示结果将存储在这个矩阵中,同时也是待旋转的矩阵。squareRotation
是旋转的角度,以弧度为单位,表示要围绕指定轴旋转的角度。[0, 0, 1]
是一个包含 x、y 和 z 分量的数组,表示绕 z 轴旋转。在这种情况下,表示围绕 z 轴顺时针旋转。
因此,这段代码的作用是将模型视图矩阵 modelViewMatrix
绕世界坐标系中的 z 轴进行顺时针旋转,旋转角度为 squareRotation
所指定的弧度值。