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魔法发生的地方。

Hello, WebGL!

在这个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