WebGL: 3D浏览器图形入门指南
你好,未来的3D图形魔法师们!我很高兴能成为你们探索WebGL世界的向导。作为一个教授计算机图形学多年的老师,我可以告诉你,WebGL就像是你的浏览器中的一根魔法棒。它允许你在网页中直接创建令人惊叹的3D图形和动画。这难道不酷吗?让我们开始吧!
WebGL是什么?
WebGL,全称为Web图形库,是一个JavaScript API,允许你在任何兼容的浏览器中渲染交互式的2D和3D图形,而无需安装插件。这就相当于给你的浏览器赋予了超能力,以创造惊人的视觉体验!
简史
WebGL首次在2011年推出,从那时起,它彻底改变了我们对网页上图形的看法。在WebGL之前,如果你想在一个浏览器中创建3D图形,你需要依赖于如Flash或Java小程序这样的插件。现在,有了WebGL,我们可以在浏览器中原生地做所有这些事情。这就好像我们从自行车升级到了跑车!
准备工作
在我们开始WebGL冒险之前,让我们确保我们的背包里有正确的工具:
- 一个现代的网页浏览器(Chrome、Firefox、Safari或Edge)
- 一个文本编辑器(我推荐Visual Studio Code,但任何一个都可以)
- HTML和JavaScript的基础知识(如果你不太熟悉,不用担心,我们会在学习过程中复习)
WebGL入门
让我们创建我们的第一个WebGL程序!我们将从一个简单的“Hello, WebGL!”示例开始,它在屏幕上显示一个彩色的三角形。
第1步:设置HTML
首先,我们需要创建一个包含canvas元素的HTML文件。这个canvas就是我们WebGL魔法发生的地方。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Hello, WebGL!</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script src="webgl-demo.js"></script>
</body>
</html>
在这个HTML中,我们创建了一个ID为"glCanvas"的canvas元素,并将其尺寸设置为640x480像素。我们还链接了一个名为"webgl-demo.js"的JavaScript文件,我们将在其中编写WebGL代码。
第2步:初始化WebGL
现在,让我们创建我们的"webgl-demo.js"文件,并开始编写一些JavaScript代码来初始化WebGL:
function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) {
alert("无法初始化WebGL。您的浏览器或机器可能不支持它。");
return;
}
// 设置清空画布的颜色为黑色,完全不透明
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 使用指定的清空颜色清空颜色缓冲区
gl.clear(gl.COLOR_BUFFER_BIT);
}
window.onload = main;
让我们分解一下:
- 我们获取对canvas元素的引用。
- 我们尝试从canvas获取一个WebGL上下文。如果失败,意味着WebGL不支持,我们显示一个错误消息。
- 如果成功,我们设置清空颜色(背景颜色)为黑色,并清空画布。
第3步:创建着色器
着色器是运行在GPU上的特殊程序。它们是用一种叫做GLSL(OpenGL着色语言)的语言编写的。我们需要两种类型的着色器:顶点着色器和片段着色器。
// 顶点着色器程序
const vsSource = `
attribute vec4 aVertexPosition;
void main() {
gl_Position = aVertexPosition;
}
`;
// 片段着色器程序
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
顶点着色器定位我们的顶点,而片段着色器为我们的像素着色(在这个例子中是红色)。
第4步:初始化着色器程序
现在我们需要编译和链接这些着色器到一个着色器程序中:
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
const 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));
return null;
}
return shaderProgram;
}
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('编译着色器时发生错误: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
这段代码编译我们的着色器,将它们链接成一个程序,并检查是否有任何错误。
第5步:创建三角形
现在,让我们创建我们的三角形数据:
function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
-1.0, 1.0,
1.0, 1.0,
-1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
return {
position: positionBuffer,
};
}
这创建了一个缓冲区并填充了我们的三角形顶点的位置。
第6步:绘制场景
最后,让我们把所有东西放在一起并绘制我们的三角形:
function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(programInfo.program);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
2, // 每个迭代2个组件
gl.FLOAT, // 数据是32位浮点数
false, // 不标准化
0, // 步长(0 = 自动)
0 // 缓冲区中的偏移量
);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
这个函数清空画布,设置我们的着色器程序,连接我们的缓冲区数据,并最终绘制我们的三角形。
把所有东西放在一起
现在,让我们更新我们的main
函数以使用所有这些片段:
function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) {
alert("无法初始化WebGL。您的浏览器或机器可能不支持它。");
return;
}
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
},
};
const buffers = initBuffers(gl);
drawScene(gl, programInfo, buffers);
}
window.onload = main;
就这样!你的第一个WebGL程序。当你在一个浏览器中打开你的HTML文件时,你应该会看到一个黑色背景上的红色三角形。恭喜你!
常见的WebGL方法
下面是我们使用过的一些常见的WebGL方法和它们的目的:
方法 | 目的 |
---|---|
gl.createBuffer() |
创建一个新的缓冲区对象 |
gl.bindBuffer() |
将一个缓冲区对象绑定到一个目标 |
gl.bufferData() |
初始化并创建缓冲区对象的数据存储 |
gl.createShader() |
创建一个着色器对象 |
gl.shaderSource() |
设置着色器对象的源代码 |
gl.compileShader() |
编译一个着色器对象 |
gl.createProgram() |
创建一个程序对象 |
gl.attachShader() |
将一个着色器对象附加到一个程序对象 |
gl.linkProgram() |
链接一个程序对象 |
gl.useProgram() |
将指定的程序设置为当前渲染状态的一部分 |
gl.getAttribLocation() |
返回一个属性变量的位置 |
gl.enableVertexAttribArray() |
启用一个顶点属性数组 |
gl.vertexAttribPointer() |
指定顶点属性数据的布局 |
gl.drawArrays() |
从数组数据渲染基本图形 |
结论
哇,我们今天涵盖了很多内容!我们学习了WebGL是什么,设置了我们的开发环境,并创建了我们的第一个WebGL程序。记住,学习WebGL就像学习骑自行车一样——一开始可能有点摇晃,但经过练习,你很快就能自如地骑行!
在未来的课程中,我们将探索更复杂的形状,增加交互性,甚至深入到3D图形。WebGL的世界是广阔和令人兴奋的,我迫不及待想和你一起探索更多。下次见,快乐编码!
Credits: Image by storyset