WebGL - 立方体旋转
你好,未来的 WebGL 巫师们!今天,我们将踏上一段激动人心的旅程,进入 3D 图形的世界。在本教程结束时,你将能够使用 WebGL 创建一个旋转的立方体。这难道不酷吗?让我们开始吧!
理解基础知识
在我们开始像 DJ 一样旋转立方体之前,让我们先了解一下一些基本概念。
什么是 WebGL?
WebGL(Web 图形库)是一个 JavaScript API,它允许我们在网页浏览器中渲染 3D 图形。它就像给你的浏览器戴上了一副 3D 眼镜!
为什么选择立方体?
你可能想知道,“为什么我们从立方体开始?”亲爱的学生们,立方体就像是 3D 图形的“Hello World”。它足够简单,容易理解,但又足够复杂,可以教给我们重要的概念。而且,谁不喜欢一个好的立方体呢?
设置我们的 WebGL 环境
HTML 画布
首先,我们需要一个舞台,让我们的立方体在上面表演。在 WebGL 中,这个舞台被称为画布。让我们来设置它:
<canvas id="glcanvas" width="640" height="480">
你的浏览器不支持 HTML5 画布
</canvas>
这创建了一个 640x480 像素的画布。如果你看不到它,别担心——它现在就像一个看不见的舞池。
初始化 WebGL
现在,让我们让 WebGL 准备好派对:
var canvas = document.getElementById('glcanvas');
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL 不支持,退回到 experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}
if (!gl) {
alert('你的浏览器不支持 WebGL');
}
这段代码获取我们的 WebGL 上下文。如果你的浏览器不支持 WebGL,就像试图在 VHS 播放器上播放 DVD 一样——它就是不会工作!
创建我们的 3D 立方体
定义顶点
立方体有 8 个角(顶点)。我们需要告诉 WebGL 这些角在哪里:
var vertices = [
// 前面
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// 后面
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// 顶面
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// 底面
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// 右面
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// 左面
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
每组三个数字代表我们立方体在 3D 空间中的一个角。这就像给 WebGL 一个我们立方体的地图!
创建缓冲区
现在我们需要将这些数据发送到 GPU:
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
这就好比把我们的立方体打包进一个行李箱(缓冲区)然后发送给 GPU。
着色器 - WebGL 的魔术师
顶点着色器
顶点着色器定位我们的顶点:
var vertexShaderSource = `
attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}
`;
这个着色器接收每个顶点并应用我们的变换矩阵。就像魔术师移动我们立方体的角落!
片段着色器
片段着色器给我们的立方体上色:
var fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
这个简单的着色器将所有东西都染成白色。就像给我们的立方体上了色!
编译和链接着色器
现在我们需要编译我们的着色器并将它们链接成一个程序:
function getShader(gl, source, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('编译着色器时发生错误:' + gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var vertexShader = getShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
var fragmentShader = getShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('无法初始化着色器程序:' + gl.getProgramInfoLog(shaderProgram));
}
gl.useProgram(shaderProgram);
这就好比教我们的魔术师(着色器)他们的技巧,然后让他们上台表演!
让我们的立方体旋转
设置旋转
要让我们的立方体旋转,我们需要随时间更新它的旋转角度:
var cubeRotation = 0.0;
function render(now) {
now *= 0.001; // 转换为秒
const deltaTime = now - then;
then = now;
cubeRotation += deltaTime;
drawScene();
requestAnimationFrame(render);
}
这个函数会被反复调用,每次更新我们立方体的旋转。
绘制场景
现在让我们把所有东西放在一起,绘制我们的旋转立方体:
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation, [0, 1, 1]);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), false, projectionMatrix);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), false, modelViewMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 36);
}
这个函数清除画布,设置我们的视角,应用旋转,最后绘制我们的立方体。
结论
就这样,朋友们!我们使用 WebGL 创建了一个旋转的 3D 立方体。记住,掌握 WebGL 就像学习杂技——它需要练习,但一旦你掌握了它,你就可以做出惊人的事情!
下面是一个总结我们使用的主要方法的表格:
方法 | 描述 |
---|---|
gl.createBuffer() |
创建一个新的缓冲区对象 |
gl.bindBuffer() |
将缓冲区对象绑定到目标 |
gl.bufferData() |
创建并初始化缓冲区对象的数据存储 |
gl.createShader() |
创建一个着色器对象 |
gl.shaderSource() |
设置着色器对象的源代码 |
gl.compileShader() |
编译着色器对象 |
gl.createProgram() |
创建一个程序对象 |
gl.attachShader() |
将着色器对象附加到程序对象 |
gl.linkProgram() |
链接程序对象 |
gl.useProgram() |
将指定的程序设置为当前渲染状态的一部分 |
gl.clear() |
清除缓冲区到预设值 |
gl.uniformMatrix4fv() |
为当前程序对象指定统一变量的值 |
gl.drawArrays() |
从数组数据渲染图元 |
继续练习,继续编码,很快你就能在浏览器中创建惊人的 3D 图形了。快乐编码!
Credits: Image by storyset