WebGL:浏览器中的3D图形
WebGL:浏览器中的3D图形
你是否曾想过现代网站如何能在浏览器中显示流畅的3D图形,而无需任何插件?答案是WebGL——一种让网页利用计算机显卡(GPU)实时绘制3D场景的技术。
什么是WebGL,为什么它很重要?
WebGL代表Web图形库。它是一个JavaScript API,让Web开发者可以直接访问计算机或手机中的图形硬件。在WebGL之前,如果你想在网页上使用3D,你需要像Flash或Java小程序这样的插件——还记得吗?WebGL通过将3D图形作为Web平台的原生部分,在所有现代浏览器和所有设备上工作,从而改变了这一切。
把WebGL看作是JavaScript和GPU之间的桥梁。JavaScript擅长逻辑和用户界面,但不适合繁重的数字运算。而你的显卡则设计用于并行执行数百万次计算——非常适合每秒60次确定数百万个三角形在屏幕上的位置。
WebGL在底层是如何工作的
WebGL的核心是通过绘制三角形来工作。很多很多的三角形。你看到的每个3D对象——角色、汽车、建筑——都是由连接在一起的三角形组成的。WebGL为你提供了定义这些三角形并告诉GPU如何给它们上色的工具。
这个过程分为两个主要阶段,由直接在GPU上运行的小程序(称为着色器)处理:
首先,顶点着色器获取每个三角形的每个角(称为顶点),并计算出它应该在屏幕上的位置。它通过应用一系列变换——移动、旋转和缩放对象,然后将其从3D空间投影到2D屏幕上来完成。
其次,片段着色器(有时称为像素着色器)针对这些三角形覆盖的每个像素运行。它的工作是决定每个像素的颜色。在这里,你应用纹理、光照、阴影以及所有使场景看起来真实的视觉细节。
这些着色器是用一种叫做GLSL(OpenGL着色语言)的语言编写的,看起来有点像C语言。它们在数千个GPU核心上并行运行,这就是为什么它们如此之快。
WebGL 1和WebGL 2:有什么区别?
你经常会听到WebGL 1和WebGL 2。可以把它们想象成游戏主机的版本——WebGL 2是更新、更强大的版本。WebGL 1自2011年就已存在,并且在任何地方都能工作。它提供了基础功能:绘制三角形、应用纹理和简单着色。
WebGL 2后来出现,带来了以前只在桌面图形API中可用的功能。比如实例化绘制(用单个命令绘制同一个对象数千次)、变换反馈(捕获GPU输出以供重用)以及更多的纹理格式。所有现代浏览器现在都支持WebGL 2,因此它是新项目的默认选择。
为什么几乎没人写原生WebGL
编写原生WebGL代码……非常冗长。非常非常冗长。绘制一个三角形就需要几十行代码:创建缓冲区、编译着色器、链接程序、设置属性、绑定纹理,最后发出绘制调用。对于带有灯光、摄像机、动画和多个对象的复杂场景来说,这样做将极其繁琐且容易出错。
这就是为什么几乎每个人都使用库。最流行的是Three.js。它为你处理所有样板代码——设置渲染器、管理场景图(对象的层次结构)、提供摄像机、灯光、材质以及常见3D文件格式的加载器。使用Three.js,你可以在大约20行代码中创建一个旋转的3D立方体,而不是200行。
其他很好的选择也存在。Babylon.js更像是一个完整的游戏引擎,内置物理引擎、可视化编辑器和优秀的TypeScript支持。PlayCanvas在云端运行,带有协作编辑器。如果你需要轻量级的东西,OGL非常小巧精悍。而如果你真的想要最大程度的控制,原生WebGL始终可用——但大多数项目不需要那种级别的控制。
渲染管线:从3D场景到屏幕上的像素
当你在浏览器中查看3D场景时,在帧之间的几毫秒内会发生很多事情。以下是整个过程:
你的3D对象从它们自己的局部坐标系开始——模型空间,其中(0,0,0)是对象的中心。顶点着色器将它们转换为世界空间(它们在场景中的位置),然后转换为视图空间(相对于摄像机),然后转换为裁剪空间(一个标准化的立方体,GPU可以轻松判断什么是可见的),最后转换为屏幕空间(显示器上的实际像素)。
接下来是光栅化——GPU确定每个三角形覆盖哪些像素。对于这些像素中的每一个,片段着色器都会运行以确定最终颜色。这就是纹理采样、光照计算以及透明度或发光等效果应用的地方。
GPU还会自动进行深度测试——它维护一个深度缓冲区(z-buffer),以便较近的对象正确地隐藏较远的对象。它还处理透明对象的混合,根据不透明度组合颜色。
加速:性能提示
GPU非常快,但它有一个瓶颈:与CPU的通信。每次JavaScript告诉GPU绘制某些东西(一次绘制调用)时,都会产生开销。绘制调用太多,帧率就会下降。性能的关键是尽量减少这种通信。
常见的技巧包括实例化(用一次调用绘制同一几何体的多个副本)、批处理(将多个对象合并到一次绘制调用中)以及使用纹理图集(将许多小纹理打包到一个大纹理中,这样就不必不断切换纹理)。
细节层次(LOD)是另一个经典技巧:近距离使用高细节模型,但为远处的对象切换为更简单的版本。视锥体剔除则完全跳过绘制摄像机视野之外的任何东西。并且始终使用requestAnimationFrame作为你的渲染循环——它会与显示器的刷新率同步,并在标签页隐藏时暂停。
对于性能分析,浏览器开发者工具已经变得非常出色。Chrome DevTools有一个WebGL选项卡,像Spector.js这样的工具可以捕获并重放整个帧,这样你就可以看到发生了哪些绘制调用以及每个调用花费了多长时间。
WebGPU:下一代
WebGL已经为我们服务了十多年,但它是为旧时代的图形硬件设计的。WebGPU是现代继任者——一个更低级的API,为开发者提供对GPU更直接的控制,类似于原生平台上的Vulkan、Metal或DirectX 12。
WebGPU带来了计算着色器(在GPU上运行通用计算,而不仅仅是图形)、更好的多线程支持以及更可预测的性能。它已经在Chrome和Edge中可用,在Firefox中通过标志启用,在Safari Technology Preview中也可用。Three.js和Babylon.js等库正在添加WebGPU渲染器,这样你就可以用最少的代码更改进行切换。
WebGPU不会一夜之间取代WebGL——WebGL不会消失——但对于新的高性能项目来说,它是未来。
你能用它构建什么?
可能性非常广泛。数据可视化通过3D图表和交互式地球仪变得生动。产品配置器让客户可以实时定制汽车、家具或运动鞋。从休闲谜题到完整AAA体验的游戏都在浏览器中运行。科学可视化帮助研究人员探索分子结构或气候模型。创意编码和演示场景推动了艺术边界。AR和VR体验通过WebXR实现。数字孪生让工厂可以监控和模拟现实世界系统。而CAD/BIM查看器将专业工程工具带到了浏览器中。
网络已成为一个合法的3D平台。无论你是在构建产品展示、数据仪表板还是游戏,WebGL(以及越来越多的WebGPU)都为你提供了实现它的工具——无需插件,无需安装,只需一个URL。
