玩网页游戏的时候突然提醒我 初始化图形卡初始化设备失败(创建WebGL上下文失败)

WebGL 是 Web 3D 图形卡初始化的标准 API它使得運行在浏览器中的 JavaScript 程序也可以充分利用 3D 渲染硬件的强大能力。在 WebGL 出现之前为提供硬件加速的 3D 体验,开发者只能借助浏览器插件或编写需偠用户下载***的本地软件

尽管 WebGL 不属于 HTML5 官方标准,但绝大多数支持 HTML5 的浏览器都支持 WebGL——正如支持 Web Workers、WebSockets 等并未被 W3C 官方作为标准采纳的技术一樣要想将浏览器打造成一流的应用平台,3D 是不可或缺的部分这是

主流的桌面浏览器和绝大多数手机浏览器都支持 WebGL1。WebGL 已经可以运行在类姒于你的家用机器和办公机器的数百万台设备上包括游戏、数据可视化、计算机辅助设备、3D 打印和零售行业在内的许多使用了 WebGL 技术的网站也在蓬勃发展。

1在本书写作时iOS 上的 Mobile Safari 还不支持 WebGL,这是个很严重的问题所幸利用某些适配工具包,我们可以将基于 HTML5 和 WebGL 的程序打包成本地應用在 iOS 平台上运行、研究关于这个问题,在第 12 章中会有详细的说明

WebGL 是一套底层绘图 API:它通过解析数据和着色器阵列 2 来进行绘制。它不潒 2D Canvas API 那样具有高度封装的结构这可能会令习惯 2D 图形卡初始化接口的人感到困惑。不过很多开源的 JavaScript 工具包都提供了更加高级的封装方法这些工具包让开发者可以用与操作传统图形卡初始化库更为接近的方式来操作 WebGL 的 API。虽然有了这些工具包3D 开发也还是有一定的难度,但至少利用它们对 3D 开发没什么经验的人可以比较方便地入门,而有经验的 3D 开发者也可以节省大量时间

2阵列,指排成行和列的数学元素矩阵僦是一种典型的阵列形式,此处姑且可以简单理解为一个数据 / 着色器二维数组——译者注

为了让读者对 WebGL 有个基本印象,本章将简单介绍 WebGL 嘚底层基础虽然我们在本书中使用的工具包可以让你不必去关注这些底层细节,但了解这些工具包是基于什么构建的也非常重要所以,让我们从 WebGL 的核心概念和 API 开始学习

 正如不支持许多 HTML5 新特性一样,你的电脑可能也不支持 WebGL主流桌面浏览器中,一部分浏览器只有比较噺的版本才支持 WebGL(例如 IE 只有 IE11 及其之后的版本才支持 WebGL)还有一些老机器的图形卡初始化处理器不支持 3D 硬件加速,在这些老机器上浏览器會直接关闭 WebGL。如果你想了解你的目标机器、设备或浏览器是否支持 WebGL请访问 ,键入“WebGL”关键字进行搜索或直接访问这个链接:。

" // 返回经過投影和变换的顶点值\n" + " // 返回像素点的颜色:始终输出白色\n" +

 GLSL 代码由存储在全局变量中的 JavaScript 字符串提供这有点讨厌,因为我们不得不用加号來连接不同行来保证代码格式。作为替代方案我们可以采用先在外部文本文件中定义着色器,然后用 Ajax 的方式来加载这个文件或者我們也可以创建隐藏的 DOM 节点,然后把代码写在 DOM 节点的文本内容中为了便于说明,我们在示例代码中使用了这种最简单的形式当真正编写玳码的时候,你可以选择其他更优雅的方式

6这里描述的是将 GLSL 中的变量转换为 JavaScript 变量的过程,从而使得 JavaScript 可以向 GLSL 的变量注入一些配置参数——译者注

// 加载并编译片段和顶点着色器 // 将它们链接到一段新的程序中 // 获取指向着色器参数的指针

现在,我们已经为绘制正方形做好了全部嘚准备工作——我们创建了绘图上下文;设置了视口;顶点缓冲、矩阵和着色器也都已创建和初始化下面我们定义一个函数 draw(),用它来绘淛我们在上文中展示过的那个正方形让我们来通读这个函数。

首先draw() 函数以黑色背景填充的方式清空了整个画布,方法 gl.clearColor() 将黑色设为当前畫布的“清空”颜色这个方法携带四个参数,分别代表 RGBA(Red、Green、Blue、Alpha)颜色的四个分量注意 WebGL 的 RGBA 值是用 0.0 到 1.0 范围的浮点数来表示的(这与用 0~255 的整数表示的 Web 颜色值不一样,例如在 CSS 中)gl.clear() 使用定义的“清空”颜色来“清空”WebGL 颜色缓冲(color buffer),即 GPU 显存中用于渲染屏幕上像素点的区域7[WebGL 使用多种类型的缓冲(buffer)来进行绘制,包括颜色缓冲和用于深度测试的深度缓冲(depth buffer)关于深度缓冲,我们将在下一节予以说明]

7指将顏色缓冲中的所有字节都设为指定的“清空”颜色。——译者注

其次draw() 函数将正方形的顶点缓冲数据绑定到绘图上下文的缓冲,设定了图え绘制过程中将要使用的着色器并建立顶点缓冲数据和矩阵与着色器之间的关联。

最后我们调用 WebGL 的 drawArrays() 函数来绘制这个正方形。WebGL 通过传入嘚图元类型参数和图元的顶点数量参数并结合之前预设的其他属性(顶点、矩阵、着色器)来得到最终的绘制结果。例 2-6 展示了整个流程

// 清空背景(使用黑色填充) // 设置待绘制的顶点缓冲 // 设置待用的着色器 // 建立着色器参数之间的关联:顶点和投影/模型矩阵

终于,我们完成叻整个绘制流程程序执行的结果是一个绘制在黑色背景上的白色正方形,如之前图 2-1 所示的那样

2.5 创建3D几何体

上面绘制的正方形是一个盡可能简单的 WebGL 示例。显然它不怎么能引起你的兴趣甚至还不是 3D 的——尽管为了绘制这个正方形,我们已经编写了将近 200 行代码而实现同樣效果的 2D Canvas 绘制代码顶多只需 30 行左右。在这一点上WebGL 相对其他绘图 API 没有显示出优势。但别着急现在我们来用 WebGL 做一些有趣的事情——真正的 3D 繪图。为了得到一个包含不同颜色的 3D 立方体我们需要在正方形的基础上加一些线条,为此我们将对着色器和绘图函数做一些小改动我們还要为这个立方体加上一个简单的动画,以便从各个角度去观察它图 2-2 展示了一个旋转中立方体的屏幕截图。

图 2-2:一个包含不同颜色的竝方体

为了创建和渲染这个立方体我们将改进之前的示例代码。首先我们将用于创建正方形的缓冲数据改为用于创建立方体的缓冲数據。其次我们将使用与之前不同的 WebGL 函数来执行绘制过程。文件 Chapter 2/example2-2.html 中包含绘制立方体的完整代码

例 2-7 展示了立方体的缓冲设置过程,它比绘淛正方形的代码要复杂一些立方体有更多的顶点,并且我们将为不同的面设置不同的颜色首先,我们创建顶点缓冲数据并将它存储茬变量 vertexBuffer 中。

例 2-7:初始化立方体、颜色和索引缓冲的代码

// 为彩色的立方体构建顶点、颜色和索引数据

其次创建颜色数据,为每个顶点设置┅个四元色并将其存储在变量 colorBuffer 中。faceColors 数组中是一系列定义好的 RGBA 颜色值

最后,我们要创建一类新型的缓冲——索引缓冲(index buffer)用于存储顶點数据的索引。我们将这些数据存储在变量 cubeIndexBuffer 中之所以这里样做,是因为我们将在更新过的 draw() 函数中使用顶点集索引而非顶点本身来定义所囿的三角形这样做的理由是:3D 几何图形卡初始化往往代表了连续封闭的区域,单个顶点常常由多个三角形共享而索引缓冲能够避免数據重复,令数据存储更加紧凑

 // 索引数据(定义待绘制的三角形)

为了绘制立方体的颜色,这些颜色必须被传递给着色器例 2-8 展示了改进後的着色器代 码。注意加粗的代码行:我们声明了一个代表顶点颜色的属性此外我们还需要声明一个

GLSL 中的 varying 变量——vColor,它用于将每个顶点嘚颜色信息从顶点着色器传递到 片段着色器与之前出现过的并不逐个更改顶点数据的 uniform 变量(例如我们早先讨论 的矩阵)不同,varying 变量代表著色器会为每个顶点逐个输出不同的值在这个示例中, 我们将存储在 vertexColor 变量中的颜色缓冲数据输入到变量 vColor 中片段着色器直接 输出 vColor 中的原始颜色值。

例 2-8:用于渲染带颜色正方体的着色器代码

" // 返回经过变换和投影的顶点值\n" + " // 返回像素点颜色:始终输出白色\n" +

 如果仅仅用于设置单┅的颜色这段代码看起来也许有点过于复杂。但一个复杂的着色器——例如一个实现了光照模型的着色器或者一个实现了草地、水面動态纹理的着色器,等等——在输出最终色彩之前会对 vColor 进行许多额外的运算处理。无疑着色器提供了强大的视觉能力,但是正如 Ben Parker 的名訁所述——能力越大责任越大。

现在我们开始编写用于绘制的代码如例 2-9 所示。为了绘制比正方形更为复杂的立方体我们需要做一些鈈同的事。示例代码中加粗的部分标明了这些改动首先,我们要开启深度测试使得 WebGL 可以按深度排序来绘制 3D 物体。否则WebGL 将无法保证将“在前方”的面按照我们的预期绘制在其他面的前方,“前方”和“后方”的面会混淆在一起(如果想看看关闭深度测试会发生什么事,只需注释掉那行代码你仍然会看到立方体的部分面,但不完整)

其次,我们要将之前已经在 createCube() 函数中创建好的颜色和索引缓冲绑定到繪图上下文的缓冲最后,我们调用 WebGL 方法 gl.drawElements() 而不是 gl.drawArray() 来绘制用索引缓冲来表示的图元信息

例 2-9:更改后的立方体绘制代码

// 清空背景(使用黑色填充) // 设置待用的着色器 // 建立着色器参数之间的关联:顶点和投影/模型矩阵

如果希望看到立方体的 3D 效果而不是一个静止的 2D 图像,我们需要讓它动起来现在,我们来为这个立方体添加一个绕坐标轴旋转的简单动画动画的代码如例 2-10 所示。在函数 animate() 中立方体以五秒钟为周期围繞预先定义的旋转轴 rotationAxis 旋转。

animate() 由另一个函数 run() 循环调用它调用一个新的浏览器函数 requestAnimationFrame() 来持续驱动动画。这个函数在每次浏览器重绘页面的时候調取一个回调函数(关于这个函数以及其他动画相关的技术,后续的章节里有更详细的说明)每次 animate() 函数被调用的时候,它都会计算当湔时间和上一次调用该函数的时间之间的差值并将其存储在变量 deltat 中,然后根据它计算出作用于矩阵变量 modelViewMatrix 的旋转角度代码执行的结果是竝方体以每五秒一圈的速度绕 rotationAxis 旋转。

例 2-10:为立方体添加动画

纹理映射是我们在本章要学习的最后一个 WebGL API 特性纹理映射(texture map),或简称纹理昰指覆盖几何体表面显示的位图。WebGL 中使用 Image DOM 元素作为纹理数据的源这表示,只需简单地更改 Image 元素的

 WebGL 纹理并不一定要以图像文件为源来构建2D canvas 元素也可以作为纹理的源,利用这个特性我们可以使用 2D Canvas 绘图 API 在 3D 物体的表面绘制图案;纹理甚至还可以以 Vedio 元素作为源来构建,因此你鈳以在一个 3D 物体的表面播放视频关于动态纹理的能力,在第 11 章有更详细的说明

我们将前面的旋转立方体示例改为使用纹理映射而非表媔色彩。如图 2-3 所示

图 2-3:一个使用了纹理映射的立方体

这里需要提醒各位读者,如果你直接在文件系统里双击打开纹理映射的代码示例页媔它是无法正常运行的。它需要用一个 Web 服务器来加载因为我们从一个 JPEG 文件中载入纹理,这是由于 WebGL 安全模型中的跨域访问安全限制我們需要运行一个 Web 服务器而非直接通过 file:// URL 来访问这个文件。总的来说本书中的大多数例子都需要通过 Web 服务器来访问。

我在 MacBook 上运行了一个标准夲地版 LAMP 环境不过你需要用到的仅仅是 LAMP 的一部分功能——像 Apache 这样的 Web 服务。或者如果你的机器上装了 Python你也可以利用 Python 内置的 SimpleHTTPServer 模块来启动一个 Web 垺务,使用命令行窗口定位到 examples 目录然后输入:

这样你就可以通过 http://localhost:8000/ 这个地址来访问本书的示例了。如果希望获取更多关于这方面的技术支歭请访问 Linux Journal 网站()。

Image 对象的 src 属性设为一个 JPEG 文件的路径——在这个示例中我们加载了一个 256×256 的正方形 WebGL 官方 LOGO——不过首先我们要为图像的 onload 倳件注册一个事件处理程序,以便在图像加载完毕的时候对 WebGL 纹理对象做一些处理

例 2-11:从图像创建一个纹理映射

onload 事件的回调函数 handleTextureLoaded() 中,我們做了下面这些事情首先,我们调用 gl.bindTexture() 函数来指定 WebGL 在后续绘制过程中将要使用的纹理被指定的纹理将在后续的整个绘制过程中生效,直箌 gl.bindTexture() 再次被调用——在函数的末尾我们将绑定纹理设置为空,以防止在后续操作中意外更改纹理存储区域的内容

其次,我们调用 gl.pixelStorei() 函数来翻转所有纹理像素点的 y 坐标值之所以需要进行这个操作,是因为在 WebGL 中纹理坐标系的 y 轴是垂直向上的,而在 Web 图像本身的坐标系中y 轴是垂直向下的。

OpenGL通常以一个字母后缀来标识函数参数的类型。图像以整型数组的方式存储(RGB 或 RGBA 颜色)因此被标识为 i。

现在我们调用 texImage2D() 方法來将加载好的图像数据复制到 WebGL 纹理对象中这个方法支持几种不同类型的参数,你可以查阅 WebGL 规范了解如何使用它创建不同类型的纹理在這个示例中,我们在第 0 层创建了一个 2D 纹理——一个纹理中可以包含不同层级的纹理这个技术被称为 mip-mapping,我们将在后面进行介绍——这个纹悝采用了 RGBA 颜色模式存储在一个无符号字节(unsigned byte)数组中。

我们还需要设置纹理过滤选项这些选项用于控制图像随远近位置放大缩小时的紋理像素颜色计算。在我们的示例中我们使用了最简单的过滤设置——gl.NEAREST,这个设置的策略是通过缩放图像本身来得出纹理像素点的颜色在这个设置下,纹理在没有被过度缩放的前提下看起来效果还不错但过近处(放大)会呈现块状和像素化效果,而过远处(缩小)会呈现锯齿和不平滑效果WebGL 提供了另外两种纹理过滤能力:gl.LINEAR 是使用线性插值的方法来处理放大,使得放大后纹理的视觉效果更加平滑;gl.LINEAR_MIPMAP_NEAREST 用于添加 mip-map 过滤使得远处物体的纹理看起来更平滑。

想要感受 gl.NEAREST 过滤的缺点可以尝试调整立方体的位置。修改源文件 Chapter 2/example2-3.html 的第 47 行修改立方体 z 坐标嘚值(当前为 -8),调整立方体的远近

尝试将 -8 改为 ?4。当立方体更加靠近观察点你可以观察到立方体的纹理明显变得像素化了(图 2-4)。

图 2-4:gl.NEAREST 过滤——近处物体上的纹理变得像素化

现在再尝试将 -8 改成 -32当立方体远离观察点时候,可以看到纹理出现了明显的锯齿(图 2-5)

图 2-5:gl.NEAREST 过濾——较远物体的纹理出现锯齿

现在,我们已经设置好了全部的纹理选项并调用 gl.bindTexture() 方法来清空当前绑定的纹理。最后我们将全局变量 okToRun 的徝设为 true,以此通知 run() 函数纹理已经准备就绪绘图程序可以开始运行了。

像往常一样我们还需要对代码的其他部分进行更改:缓冲的创建玳码,着色器代码以及着色值的设置代码。首先我们将创建颜色缓冲的代码替换为创建纹理缓冲的代码。纹理坐标(texture coordinate)用随顶点数据┅同定义的、[0, 1] 范围内的一对浮点数来表示这对浮点数对应位图上的 xy 偏移量,正如下面着色器的代码中所展现的那样对我们的立方体來说,纹理坐标值非常简单:我们把整张纹理分别贴到立方体的每个表面上因此立方体每个面的转角坐标恰好对应纹理图像的转角坐标,如 [0, 0]、[0, 1]、[1, 0] 或 [1, 1]

注意,这些纹理坐标值的顺序与顶点缓冲中的顶点顺序是相对应的例 2-12 展示了创建纹理坐标缓冲的代码。

例 2-12:纹理映射立方體的缓冲创建代码

我们还要将使用色彩的着色器更改为使用纹理的着色器在顶点着色器中,我们定义了一个名为 texCoord 的顶点属性变量顶点數据通过这个变量传入,以及一个 varying 类型的输出变量 vTexCoord用于向片段着色器输出各个顶点的信息。片段着色器使用纹理坐标作为纹理映射数据嘚索引纹理坐标通过

例 2-13:纹理映射立方体的着色器代码

" // 返回经过变换和投影的顶点值\n" + " // 返回像素点的颜色:始终输出白色\n" +

为了将纹理贴到峩们的立方体上,我们最后还要对绘制函数做一些小修改例 2-14 展示了修改后的代码。我们将设置颜色缓冲的代码替换为设置纹理缓冲的代碼并将该纹理设为当前纹理,绑定到绘图上下文

例 2-14:初始化绘制所需的纹理映射数据

本章讲述了如何使用 WebGL API 进行图形卡初始化渲染。我們了解了编写一个 WebGL 应用的基本流程包括创建绘图上下文、视口、缓冲、矩阵、着色器和图元的绘制。我们学习了如何创建 2D 和 3D 几何图形卡初始化并用颜色和纹理来填充它们我们还稍微借助了开源库 glMatrix 和 RequestAnimationFrame.js,它们都是 WebGL 开发的常用基本库

显然,到目前为止我们接触到的 WebGL 底层编程昰非常繁琐的在读完本章之后,我们已经可以编写一些稍微复杂的、包括颜色和纹理的几何图形卡初始化尽管为此可能需要编写数百荇代码。这提供了强大的能力——你可以精细地操作屏幕上的每一个顶点和像素以令人炫目的硬件加速的速度进行。然而使用 WebGL 底层接口來编写代码需要大量繁重的工作标准的设计者们采用了牺牲代码尺寸来换取更强大能力的思路。WebGL 的 API 小而简单这就使得更多工作落在了應用开发者身上。

如果你是一名经验丰富的游戏或图形卡初始化开发者并且希望更好地掌控应用的性能和特性,那么直接使用 WebGL API 对你来说吔许是最好的选择如果你正在开发的应用对渲染有特别的需求,例如图像处理应用或 3D 建模工具那么你应该深入地研究 WebGL 中的 metal 技术。又或許你需要开发一些更顶层的应用,例如谁也不希望为了创建一个立方体而重复写那四十行相同的代码在这个层次上你得完全靠自己,伱需要理解和控制每一行代码

尽管如此,如果你和大多数人一样对 3D 并不是特别熟悉那么你应该以一种比 WebGL API 本身更高级的封装方式来编写應用,例如使用一些现成的工具事实上这些工具已经存在:有许多基于 WebGL 的优秀开源库可供使用。我们将在后面的几章一一介绍它们

类型化数组也是数组只不过其え素被设置为特定类型的值。

类型化数组的核心就是一个名为

  • ArrayBuffer的类型每个ArrayBuffer对象表示的只是内存中指定的字节数,但不会指定这些字节用於保存什么类型的数据通过ArrayBuffer能做的,就是为了将来使用而分配一定数量的字节

使用ArrayBuffer(数组缓冲器类型)的一种特别的方式就是用它来創建数组缓冲器视图。其中最常见的视图是

  • DataView,通过它可以选择ArrayBuffer中的一小段字节为此,可在创建DataView实例的时候传入一个ArrayBuffer、一个可选的字节偏移量(从该字节开始选择)和一个可选的要选择的字节数

DataView对象会把字节偏移量以及字符长度信息保存在

buffer属性也可以取得数组缓冲器;

讀取和写入DataView的时候,要根据实际操作的数据类型选择相应的

如下,列出了DataView支持的数据类型以及相应的读写方法:

类型化视图在读写数组緩冲器中更加便利:

类型化视图(类型化数组)

类型化视图一般也被称为类型化数组因为它们除了元素必须是某种特定的数据类型外,與常规的数组无异类型化视图也分几种,而且它们都继承了DataView

需要三个参数,只有第一个是必须的:ArrayBuffer对象、字节偏移量、要包含的字节數如:

能够指定缓冲器中可用的字节段,意味着能在同一个缓冲器中保存不同类型的数值如下面的代码就是在缓冲器的开头保存8位整數,而在其他字节中保存16位整数:


另外每个视图构造函数都有一个名为

表示类型化数组的每个元素需要多少字节:

这样就可以利用这个屬性来辅助初始化:

另外,还可以不用首先创建ArrayBuffer对象只要传入希望数组保存的元素数,相应的构造函数就可以自动创建一个包含足够字節数的ArrayBuffer对象:

另外还可以把常规数组转换为类型化视图:

也可以使用方括号语法为类型化视图的元素赋值:

  • subarray()方法基于底层数组缓冲器的子集创建一个新视图接收两个参数:开始元素的索引,可选的结束元素的索引:


目前在支持的浏览器中,WebGL的名字叫做“experimental-webgl”这是因为WebGL规范仍然未制定完成。制定完成后这个上下文的名字就会变成简单的“webgl”。如果浏览器不支持WebGL那么取得该上下文时会返回null。

通过给getContext()传递苐二个参数可以为WebGL上下文设置一些选项。这个参数本身是一个对象可以包含下列属性:

* `alpha`:值为true,表示为上下文创建一个Alpha通道缓冲区;默認值为true;
* `depth`:值为true表示可以使用16位深缓冲区;默认值为true;
* `stencil`:值为true,表示可以使用8位模板缓冲区;默认值为false;
* `antialias`:值为true表示将使用默认机制執行抗锯齿操作;默认值为true。

传递这个选项对象的方式如下:

大多数情况下不用开启因为可能影响到性能,而且默认值一般都能满足我們需求

如果getContext()无法创建WebGL上下文,浏览器可能会报错所以应该把它封装到try-catch块中:

在WebGL中,保存在上下文对象中的这些常量都没有GL_前缀

方法洺的后缀会包含参数个数(1到4),和接收的数据类型(f为浮点数i为整数),如:gl.uniform4f()意味着要接收4个浮点数;另外还有很多方法接收数组参數而非一个个单独的参数这样的方法中名字包含字母v,如:gl.uniform3iv()可以接收一个包含3个值的整数数组

在实际操作WebGL上下文之前,一般都要使用某种实色清除canvas元素为绘图做好准备。为此首先必须使用:

  • clearColor()方法来指定要使用的颜色值,这个方法接收4个参数:红、绿、蓝和透明度烸个参数必须是一个0到1之间的数值,表示每种分量在最终颜色中的强度

开始绘图之前,通常要先定义WebGL的视口(viewport)默认情况下,视口可鉯使用整个canavs区域要改变视口大小,可以调用

  • viewport()方法并传入4个参数:(视口相对于canvas元素的)x、y坐标、宽度和高度

视口坐标的原点(0,0)在canvas元素的咗下角,x轴和y轴的正方向分别是向右和向上可以定义为(width-1,height-1)。

视口内部的坐标系与定义视口的坐标系也不一样在视口内部,坐标原点(0,0)是视ロ的中心点因此视口左下角坐标为(-1,-1),而右上角坐标为(1,1)

顶点信息保存在JavaScript的类型化数组中,使用之前必须转换到WebGL的缓冲区要创建缓冲区,可以调用

  • gl.bindBuffer()绑定到WebGL上下文这两步做完以后,就可以用数据来填充缓冲区了

  • gl.STATIC_DRAW:数据只加载一次,在多次绘图中使用;

  • gl.STREAM_DRAW:数据只加载一次茬几次绘图中使用;

  • gl.DYNAMIC_DRAW:数据动态改变,在多次绘图中使用;

在包含缓冲区的页面重载之前缓冲区始终保留在内存中。如果你不想要某个緩冲区了可以直接调用

JavaScript与WebGL之间的一个最大区别在于,WebGL操作一般不会抛出错误为了知道是否有错误发生,必须在调用某个可能出错的方法后手工调用

  • gl.getError()方法。这个方法返回一个表示错误类型的常量

  • gl.NO_ERROR:上一次操作没有发生错误(值为0)。

  • gl.INVALID_VALUE:在需要无符号数的地方传入了负徝

着色器(shader)是OpenGL 中的另一个概念。WebGL中有两种着色器:定点着色器和片段(或像素)着色器顶点着色器用于将3D顶点转换为需要渲染的2D点。片段着色器用于准确计算要绘制的每个像素的颜色WebGL的着色器是使用GLSL(OpenGL Shading Language,OpenGL着色器)写的GLSL是一种与C和JavaScript完全不同的语言。

GLSL是一种类C语言專门用于编写OpenGL着色器。因为WebGL是OpenGL ES 2.0的实现所以OpenGL中使用的着色器可以直接在WebGL中使用。

  • main()方法该方法在绘图期间会重复执行。

为着色器传递数据嘚方式有两种:

  • AttributeUniform通过Attribute可以向顶点着色器传入顶点信息,通过Uniform可以向任何着色器传入常量值

又如Uniform片段着色器:

浏览器不能理解GLSL程序,洇此必须准备好字符串形式的GLSL程序以便编译并链接到着色器程序。

前面定义的着色器必须接收一个值才能工作为了给着色器传入这个徝,必须先找到要接收这个值的变量

与着色器的其他操作一样,着色器操作也可能会失败而且也是静默失败。如果你想找到着色器或程序执行中是否发生了错误必须亲自询问WebGL上下文。

WebGL只能绘制三种形状:点、线和三角其他所有形状都是由这三种基本形状合成之后,洅绘制到三维空间中的执行绘图操作要调用gl.drawArrays()或gl.drawElements()方法,前者用于数组缓冲区后置用于元素数组缓冲区。

WebGL的纹理可以使用DOM中的图像要创建一个新纹理,可以调用gl.createTexture()然后再将一副图像绑定到该纹理。如果图像尚未加载到内存中可能需要创建一个Image对象的实例,以便动态加载圖像图像加载完成之前,纹理不会初始化因此,必须在load事件触发后才能设置纹理

与2D上下文类似,通过WebGL上下文也能读取像素值读取潒素值的方法readPixels()与OpenGL中的同名方法只有一点不同,即最后一个参数必须是类型化数组像素信息是从帧缓冲区读取的,然后保存在类型化数组ΦreadPixels()方法的参数有:x、y、宽度、高度、图像格式、数据类型和类型化数组。前4个参数指定读取哪个区域中的像素图像格式参数几乎总是gl.RGBA。数据类型用于指定保存在类型化数组中的数据类型但有以下限制。

它必须在上下文创建的时候创建我们可以提供绘画缓冲区的配置选项参数。否则在使用绘画缓冲区时会按照默认值。在HTML页面合成操作前应立即将绘画缓冲区提交到HTML页媔合成器这一操作仅仅适合在最后一次合成操作以后,绘画缓冲区参数被修改的时候


    第二个参数不是必须的。WebGL的实现并不保证他将会照做了,但应该尽最大的努力来按照参数创建当组合属性不能支持WebGL的实现或图形卡初始化硬件时,是不会导致创建WebGLRenderingContext的失败WebGLRenderingContext中的getContextAttributes() 方法中获取的属性参数才是真正创建上下文中需要的。


    绘图缓冲区是在创建WebGLRenderingContext对象一同创建的下表显示了所有的缓冲区,组成了绘画缓冲区,连同他们嘚最小尺寸和他们是否被定义或不是默认情况下。绘画缓冲区的大小,须由HTMLCanvasElement的属性宽度和高度决定的也显示了当首次创建或大小被修改时需要清理


    如果请求的宽度或高度不能满足,要么当绘画缓冲第一次被创建或这改变HTMLCanvasElement宽度和高度属性,不然绘图缓冲区就会创建与较小的尺寸。實际使用的维度都依赖于实现的,并且不能保证一个缓冲区径比相同的将被创建

    可选的WebGLContextAttributes对象可以用来修改参数不论是否定义了该缓冲区。咜也可以被用来定义颜色缓冲区是否包含alpha通道如果定义了,使用的是alpha通道HTML合成器来结合与其余的页面颜色缓冲区。WebGLContextAttributes的对象仅用在第一次调鼡getContext没有提供修改绘图缓冲区创建后的工具。

    在HTML页面合成操作前应立即将绘画缓冲区提交到HTML页面合成器这一操作仅仅适合在最后一次合荿操作以后,绘画缓冲区参数被修改的时候绘图缓冲区是用于合成实现时应确保所有的渲染操作已经被刷新到绘图缓冲区。默认情况下,匼成后的绘画缓冲区应被还原到默认值

WebGLContextAttributes对象的preserveDrawingBuffer属性。如果这个标志为true,绘图缓冲区予以保留直到我们清除或者覆盖它们的时候为止。如果这个标志为false,尝试执行操作使用这个上下文作为源图像函数返回后呈现可能导致未定义行为,这包括readPixels或toDataURL调用,或者使用这个上下文作为源圖像的另一个上下文的texImage2D或drawImage调用

    OpenGL将管理矩形视口作为本身状态的一部分,矩形视口是为绘图缓冲区的渲染结果提供展现的场地在创建WebGL上丅文时,视口初始化为一个矩形起点(0,0)和宽度和高度相同的(canvas.width、canvas.height)。

   注意:如果一个WebGL程序不包含逻辑来设置窗口在调整canvas大小时,它并不会得箌妥善处理下面的ECMAScript示例说明了如何使用一个WebGL程序可以通过编程调整canvas大小。

   原理阐述: 自动设置视口会干扰手动设置的应用程序应用程序应该使用onresize方法依次处理canvas大小的响应和设置OpenGL视口。

参考资料

 

随机推荐