注明
该代码源于Interactive Computer Graphics
Edward Angel and Dave Shreiner
Eighth Edition, Pearson Education, 2020
为更好理解此代码,仅添加部分注释
WebGL 旋转正方形
大概思路
HTML文件中,正方形在平面上旋转,就相当于是在空间中绕Z轴旋转,那么,x和y坐标的变化可以根据 绕Z轴旋转的计算公式得出:
x n e w = − s i n θ ∗ y o l d + c o s θ ∗ x o l d x_{new} = -sin \theta * y_{old}+cos \theta * x_{old} xnew=−sinθ∗yold+cosθ∗xold
y n e w = s i n θ ∗ x o l d + c o s θ ∗ y o l d y_{new} = sin \theta * x_{old}+cos \theta * y_{old} ynew=sinθ∗xold+cosθ∗yold
由上式就可以通过更新旋转角度 θ \theta θ 更新正方形的 x , y 坐标
然后在JS文件中定义好正方形初始四个顶点的坐标,通过 gl.getUniformLocation(program, “uTheta”) 函数获取html文件中 uTheta的位置,再通过 gl.uniform1f(thetaLoc, theta) 将持续改变的theta值赋值给 uTheta, 最后用 requestAnimationFrame(render) 持续进行渲染动画!
HTML文件
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<title>Rotating Square</title>
<script id="vertex-shader" type="x-shader/x-vertex">
#version 300 es
in vec4 aPosition;
uniform float uTheta; //uniform传输的是对所有顶点都相同或者与顶点无关的数据,向片元着色器中传递数据
void
main()
{
float s = sin(uTheta); //返回sin结果
float c = cos(uTheta);
gl_Position.x = -s*aPosition.y + c*aPosition.x;
gl_Position.y = s*aPosition.x + c*aPosition.y;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#version 300 es
precision mediump float;
out vec4 fColor;
void
main()
{
fColor = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MVnew.js"></script>
<script type="text/javascript" src="rotatingSquare1.js"></script>
</head>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
JavaScript文件
"use strict";
var canvas;
var gl;
var theta = 0.0;
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = canvas.getContext('webgl2');
if (!gl) alert( "WebGL 2.0 isn't available" );
//
// Configure WebGL
//
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// Load shaders and initialize attribute buffers
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
//定义正方形四个角坐标
var vertices = [
vec2(0, 1),
vec2(-1, 0),
vec2(1, 0),
vec2(0, -1)
];
// Load the data into the GPU
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);
// Associate out shader variables with our data bufferData
var positionLoc = gl.getAttribLocation(program, "aPosition");
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLoc);
thetaLoc = gl.getUniformLocation(program, "uTheta"); //返回指定的uniform变量uTheta的位置
render();
};
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
theta += 0.1;
gl.uniform1f(thetaLoc, theta); //用于旋转,将新的theta值通过thetaLoc赋值给uTheta,这样这函数大概就是重复持续改变坐标?然后达到旋转的效果
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(render); //告诉浏览器你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画
}