这篇文章不会是另一个WebGL教程:已经有足够好的教程了(我们在最后列出了一些)。

我们将向Web开发人员的目标受众介绍WebGL 的概念,这些概念基本上只是任何通用的低级图形API(例如OpenGL或Direct3D)的概念。

什么是WebGL?

WebGL是一种允许低级图形编程的Web API。“低级”意味着WebGL命令以相对直接映射到GPU(图形处理单元,即硬件)实际工作方式的术语表示。这意味着WebGL可以让您真正了解图形硬件的功能集和功能。本机游戏使用OpenGL或Direct3D做什么,你也可以使用WebGL。

WebGL是如此低级,以至于它甚至都不是“3D”图形API。就像您的图形硬件并不关心您是在做2D或3D图形一样,WebGL:2D和3D也不仅仅是两种可能的使用模式。当OpenGL 1.0于1992年问世时,它特别是一个3D API,旨在揭示那个时代的3D图形硬件的功能。但随着图形硬件逐渐变得更加通用和可编程,OpenGL也是如此。最终,OpenGL变得如此通用,以至于2D和3D只是两种可能的用例,同时仍然提供了出色的性能。这就是OpenGL 2.0,而WebGL则紧随其后。

当我们说WebGL是低级图形API而不是3D API时,这就是我们的意思。这是本文的主题; 即使您不打算直接使用WebGL,这也是使WebGL非常有价值的原因。学习WebGL意味着学习图形硬件的工作原理。它可以帮助开发直观的任何图形API中的快速或慢速。

WebGL上下文和帧缓冲

在我们正确解释有关WebGL API的任何内容之前,我们必须介绍一些基本概念。WebGL是HTML Canvas元素的渲染上下文。首先获取画布的WebGL上下文:

<span style="color:#110000"><span style="color:#000066"><strong>var</strong></span> gl <span style="color:#339933">; </span>
<span style="color:#000066"><strong>试试</strong></span> <span style="color:#009900">{</span> 
  gl <span style="color:#339933">=</span> canvas。<span style="color:#660066">getContext </span><span style="color:#009900">(</span><span style="color:#3366cc">“experimental-webgl” </span><span style="color:#009900">)</span><span style="color:#339933">; </span>
<span style="color:#009900">} </span> <span style="color:#000066"><strong>catch </strong></span><span style="color:#009900">(</span> e <span style="color:#009900">)</span> <span style="color:#009900">{ </span><span style="color:#009900">}</span></span>

从那里,您通过在那里获得的gl元素上调用WebGL API函数来执行渲染。WebGL永远不会是单缓冲的,这意味着您当前渲染的图像永远不会是当前在Canvas元素中显示的图像。这可确保半渲染帧永远不会出现在浏览器的窗口中。正在渲染的图像称为WebGL帧缓冲后备缓冲。由于WebGL还允许额外的屏幕外帧缓冲,因此讨论帧缓冲区变得更加复杂,但在本文中我们忽略它。当前显示的图像称为前缓冲。当然,后备缓冲区的内容在某些时候会被复制到前缓冲区 - 否则WebGL绘图将没有用户可见的效果!

但是该操作由浏览器自动处理,事实上,WebGL程序员无法正确访问前置缓冲区。这里的关键规则是浏览器可以在任何时候将后备缓冲区复制到前缓冲区,除非在执行JavaScript期间。这意味着您必须在单个JavaScript回调中执行帧的整个WebGL呈现。只要您这样做,就可以确保正确的渲染,浏览器会为您处理多缓冲合成的非常复杂的细节。此外,您应该让您的WebGL渲染回调成为requestAnimationFrame回调:如果您这样做,浏览器还将为您处理动画调度的复杂细节。

WebGL作为一般的低级图形API

我们还没有描述WebGL是一种低级图形API,其中2D和3D只是两种可能的使用模式。事实上,这种通用图形API可能存在的想法并非易事:业界花了很多年才到达这样的API。

WebGL允许绘制线段三角形。后者当然是大多数时候使用的,所以我们将在本文的其余部分完全关注三角形。

WebGL的三角形渲染非常通用:应用程序提供了一个回调,称为像素着色器片段着色器,它将在三角形的每个像素上调用,并将确定应该绘制它的颜色。

所以假设你正在编写一个老式2D游戏。你想要的只是绘制矩形位图图像。由于WebGL只能绘制三角形(下面有更多内容),您可以将矩形分解为两个三角形,如下所示,

WebGL的基本概念[1]]_2d

片段着色器,即确定每个像素颜色的程序非常简单:它只是从位图图像中读取一个像素,并将其用作当前正在渲染的像素的颜色。

现在假设您正在编写3D游戏。您已将3D形状细分为三角形。为什么三角?三角形是最流行的3D绘图基元,因为3D空间中的任何3个点都是三角形的顶点。相比之下,您不能仅仅在3D空间中采用任何4个点来定义四边形 - 它们通常不会完全位于同一平面中。这就是为什么WebGL除了三角形之外不关心任何其他类型的多边形。

所以你的3D游戏只需要能够渲染3D三角形。在3D中,将3D坐标转换为实际画布坐标有点棘手 - 即确定给定3D对象最终要绘制在画布中的哪个位置。那里没有一个通用的公式:例如,你可能想要渲染奇特的水下或玻璃折射效果,这不可避免地需要为每个顶点进行自定义计算。因此,WebGL允许您提供自己的回调,称为顶点着色器,将为您将渲染的每个三角形的每个顶点调用,并将确定应绘制它的画布坐标。

人们自然希望这些画布坐标是2D坐标,因为画布是2D表面; 但它们实际上是3D坐标,其中Z坐标用于深度测试目的。两个像素的区别仅在于它们的Z坐标与屏幕上的相同像素相对应,而Z坐标用于确定哪一个隐藏另一个像素。所有三个轴都从-1.0到+1.0。重要的是要理解这是WebGL本身理解的唯一坐标系:任何其他坐标系统只能由您自己的顶点着色器理解,您可以在其中实现到画布坐标的转换。

WebGL的基本概念[1]]_2d_02

一旦3D三角形的画布坐标已知(感谢您的顶点着色器),您的三角形将被碎片着色器绘制,就像上面讨论的2D示例一样。然而,在3D游戏的情况下,您的片段着色器通常比2D游戏更复杂,因为3D游戏中的有效像素颜色不像静态数据那样容易确定。诸如照明之类的各种效果可能在像素将在屏幕上具有的有效颜色中起作用。在WebGL中,您必须自己实现所有这些效果。好消息是你可以:如上所述,WebGL允许你指定自己的回调,片段着色器,它决定了每个像素的有效颜色。

因此,我们看到WebGL是如何通用的API,以满足2D和3D应用程序的需求。通过让您指定任意顶点着色器,它允许实现任意坐标转换,包括3D游戏需要执行的复杂坐标转换。通过接受任意片段着色器,它允许实现任意像素颜色计算,包括3D游戏中发现的微妙光照效果。但是WebGL API并不是特定于3D图形,可以用来实现几乎任何类型的实时2D或3D图形 - 它可以一直缩放到20世纪80年代的单色位图或线框游戏,如果这就是你想要的。WebGL唯一无法实现的是最密集的渲染技术,需要利用最近添加的高端图形硬件功能。即使是这样,