HTML5-WebGL-入门指南-二-

76 阅读1小时+

HTML5 WebGL 入门指南(二)

原文:Beginning WebGL for HTML5

协议:CC BY-NC-SA 4.0

六、分形,高度图,粒子系统

这一章介绍了我们可以用数学达到的各种效果。我们将涉及的主题包括:

  • 直接用 GPU 绘画
  • 分形和 Mandelbrot 集简介
  • 高度图和地形生成
  • 用鼠标旋转摄像机
  • 粒子系统

因为我长久以来一直迷恋于数学和它所产生的美丽意象的强烈交集,所以这一章对我来说写起来特别有趣。即使你不是特别喜欢数学,你也可以跳过大部分细节/技术解释,直接用代码进行实验。我确信这里展示的例子和技术会让你感兴趣,并且可以被修改用于任何 WebGL 程序。

用 GPU 直接绘画

在讨论分形图像和 Mandelbrot 集合之前,我们将展示如何用纯粹包含在着色器程序中的逻辑来绘制图像。我们的 WebGL 应用将使用的唯一几何图形是来自五个顶点的四个三角形,它们将形成一个平面。然后,我们将使用图形处理单元(GPU) 的片段着色器,以编程方式设置平面上每个单独的像素颜色。不会对视图进行任何操作。方形平面的设置如清单 6-1 所示。

*清单 6-1 。*功能在 xy 平面上创建一个由两个三角形组成的正方形

函数 createSquare(size){

size = (typeof size !== 'undefined') ?大小 : 2.0;

var vertexPositionData = [

0.0, 0.0, 0.0,

-尺寸/2.0,-尺寸/2.0,0.0,

尺寸/2.0,-尺寸/2.0,0.0,

尺码/2.0,尺码/2.0,0.0,

-尺寸/2.0,尺寸/2.0,0.0,

];

凡指数数据= [0,1,2,2,3,3,4,4,1];

triangle deployment buffer = GL . create buffer();

gl.bindBuffer(gl)。ARRAY_BUFFER,三角形分布缓冲区:

gl.bufferData(gl。ARRAY_BUFFER,new float 32 ARRAY(vertexPositionData),

gl。STATIC _ DRAW);

三角形分布缓冲区。item size = 3;

triangle deployment buffer . num items = vertexposition data . length/3:

vertxinindexbuffer = GL . create buffer();

bindBuffer(gl。ELEMENT_ARRAY_BUFFER,vertexindex BUFFER);

gl.bufferData(gl。ELEMENT_ARRAY_BUFFER,new Uint16Array(indexData),gl。STREAM _ DRAW);

vertexIndexBuffer.itemSize = 3;

vertxinindexbuffer . num items = index ATA . length:

}

清单 6-1 中平面的默认尺寸是 2.0 x 2.0。

我们的顶点着色器获取 x,y 输入坐标,并将它们传递给片段着色器。z 值固定为 0.0。

七、Three.js 框架

有许多 WebGL 框架可用于抽象出我们在本书前六章中提到的低级应用编程接口(API)调用。这种抽象有助于使 WebGL 开发更加容易和高效。我们将在下一章讨论几个 WebGL 框架。在这一章中,我们将集中讨论最广泛使用的框架之一——three . js。我们将涵盖以下内容:

  • 图书馆的背景
  • 如何用 Three.js 开始开发
  • 如果不支持 WebGL,则退回到 2D 画布上下文进行渲染
  • Three.js API 调用来轻松创建相机、对象和使用光照模型
  • 展示与前面章节中的一些例子等价的 Three.js 代码,这些例子使用了直接的低级 WebGL API 调用
  • 介绍 tQuery,这是一个将 Three.js 与 jQuery 选择器结合在一起的库

背景

Three.js 由 Ricardo Cabello(又名 Doob 先生)创建,自 2010 年以来一直在 gitHub 上。从那时起,它得到了许多贡献者的额外帮助,它的用户群已经发展到一个很大的规模。

Three.js 提供了几种不同的绘制模式,如果不支持 WebGL,可以退回到 2D 渲染上下文。Three.js 是一个设计良好的库,使用起来相当直观。默认设置减少了所需的初始工作或“样板文件”的数量。设置可以作为对象构造时传入的参数来重写,也可以通过随后调用适当的对象方法来重写。

image 注意从 WebGL 开始的人可能会有一个错误的观念认为 Three.js 和 WebGL 开发是一回事。就像 JavaScript 框架 jQuery 和 JavaScript 不一样,Three.js(或者其他任何框架)和纯 WebGL 开发也不一样。

如果你精通一门底层语言,你通常可以理解它的框架代码。反之则不然。了解一个框架并不能保证你了解一门语言,所以学习低级语言是非常有益的。

特征

以下是 Three.js 框架众多特性中的一些:

  • 当不支持 WebGL 时,优雅地退回到 2D 上下文
  • 内置向量和矩阵运算符
  • 摄影机、灯光、材质、着色器、对象和常见几何体的 API 包装实现
  • 导入和导出实用程序
  • 良好的文档和示例

设置

我们现在将讨论如何获得 Three.js 库代码、它的目录结构和核心对象。

获得库

three . js 项目在 github.com/mrdoob/thre…github 上托管。最新版本可以从github.com/mrdoob/three.js/downloads下载。或者,如果您熟悉 git,您可以克隆存储库:

git clonehttps://github . com/mrdoob/3 . js . git。

该库正在积极开发中,对 API 的更改并不少见。最新的完整 API 文档可以在 URL mrdoob.github.com/three.js/docs/latest/,找到,它将重定向到当前版本。在github.com/mrdoob/three.js/wiki/有一个 wiki 页面,网上也不乏使用 Three.js 的演示或关于 Three.js 开发的文章。一些较好的文章列在附录 D 中。

目录结构

一旦您下载或克隆了存储库,您就可以将文件放在您的活动开发文件夹中。目录结构显示如下文件夹布局:

/生成源文件的压缩版本

/docs API 文档

/示例示例

/导出 Three.js 源代码的阿桂拖放式 gui 生成器

/src 源代码,包括中央的 Three.js 文件

/utils 实用程序脚本,如导出程序

在 src 目录中,组件被很好地分成以下子文件夹:

/src

/相机相机对象

/core 核心功能,如颜色、顶点、面、矢量、矩阵、数学定义等

/额外的实用程序、助手方法、内置效果、功能和插件

/灯光灯光对象

/材质网格和粒子材质对象,如 Lambert 和 Phong

/objects 物理对象

/renderers 呈现模式对象

/scenes 场景图形对象和雾函数

/textures 纹理对象

Three.js 中心文件

基本要素

Three.js 中有几个核心对象类型(见表 7-1 )。

表 7-1 。Three.js 中的核心对象

基础对象描述
三个。渲染器实际渲染场景的对象。实现可以是 CanvasRenderer、DOMRenderer、SVGRenderer 或 WebGLRenderer。
三个。事件存储场景中包含的对象和灯光的场景图。
三个。照相机虚拟相机;可以是透视照相机或正投影照相机。
三个。对象 3D许多对象类型,包括网格,线,粒子,骨骼和精灵。
三个。光轻型模型。类型可以是环境光、方向光、点光或聚光灯

关于对象层次的另外两个注意事项:三。网格对象有一个相关的三个。几何和三。物质对象,依次各三个。几何包含三个。顶点和三。面部物体。

基本用法

现在我们已经获得了 Three.js 库,我们准备开始使用它。我们需要包含来自本地资源的脚本,如下所示:

或者从 github 远程访问,例如:

你好世界 !

使用 Three.js 与我们到目前为止所做的底层编码相比是非常容易的。虽然已经学习了基本的 WebGL API 调用,但是我们可以在了解(或者至少在不实际检查库代码的情况下假设了解)surface Three.js API 调用下面发生了什么的同时,充分体会到框架的加速。

在我们的第一个例子中,如图 7-1 所示,我们将用 Three.js 渲染一个没有照明的长方体。

9781430239963_Fig07-01.jpg

图 7-1 。用 Three.js 渲染的矩形长方体。没有光线会使长方体显得扁平

与纯 WebGL 相比,该示例的完整代码相当短(参见清单 7-1 )。我们将在清单之后详细讨论代码的每一部分。

清单 7-1。 渲染一个未点亮的长方形长方体

Three.js 立方体测试

八、生产力工具

在前一章中,我们看到了优秀的 Three.js WebGL 框架,并展示了它如何抽象低级 WebGL API 调用。这种抽象简化并加速了开发。这一章介绍了一些额外的工具,可以帮助你的开发更有效率和更愉快。我们将在本章中讨论的主题如下:

  • 使用 WebGL 框架的优点和学习核心 WebGL 的好处
  • 目前可用的框架
  • 基本的“Hello World”philoGL 和 GLGE 框架示例
  • 加载现有网格和模型
  • 文件格式和导入/导出工具
  • 查找和修改现有着色器和纹理
  • JavaScript 物理框架
  • 使用 Three.js 的 physi.js 库的物理演示

框架

一个框架 抽象了底层 API 调用,也扩展了内置功能。WebGL 框架让您开始使用较少的初始设置和样板代码。这使得开始编程更快,开发复杂的应用更容易。框架可以抽象顶点缓冲对象(VBO)和着色器处理,简化相机操作,执行矩阵数学运算,加载网格等。

使用框架的代价是对底层细节的抽象可能会限制可配置性和性能(不需要修改框架源代码)。不过,通常节省的时间超过了可配置性的损失。

然而,不要依附于任何一个框架,先学习基本的 WebGL API 是有益的。这样做的基本原理是,了解核心 WebGL 的工作方式应该能够相当容易地在框架之间切换。相反不成立。如果你首先学习一个框架(不管它有多好),然后需要使用基本的 WebGL API 或切换框架,你可能会很迷茫。此外,如果您了解核心 WebGL 并希望了解特定框架的细微差别,您可以查看源代码并了解基本的 WebGL API 调用。

许多选择

WebGL 有很多很多可用的框架。根据 www.khronos.org/webgl/wiki/… 的说法,目前有 25 个可用的框架。你应该使用哪一个?

为了脱颖而出,构建了几个框架来提供特定的利基用途,如一般用途、游戏开发、数据可视化、地球仪和地图以及高性能。除了关注点不同,还有哪些因素决定了使用哪个框架?和其他软件项目一样,这里有一些评估标准:

  • 力量和功能 :它可以工作,让你快速创建使用高级技术的场景。代码写得很好,可扩展,很少崩溃,也没有很多严重的错误。
  • 可用性 :清晰的 API 和好的文档,wiki,FAQ 等等。
  • 支持和活动 :作者和社区积极参与。Bug 修复相当快,新的特性需求也在增加(代码库不会无限期地停滞)。要问的一些问题是:项目已经提交了多少次?有多少贡献者?这个项目已经存在多久了?最后一次提交是什么时候?释放?稳定发布?有论坛或者用户群吗?
  • 受欢迎程度 :这更适用于低端和高端人群。如果没有人使用某样东西,就很难获得对图书馆的支持。该框架也更有可能失效并被抛弃。另一方面,如果某个东西广受欢迎,那么资源很容易获得,并且你可以确信这个框架将会有一个光明的未来。
  • 个人喜好 :你就是更喜欢。当所有其他事情都差不多的时候,你自己的直觉偏好很重要。

比较活动的一些项目度量的一个地方是在www.ohloh.net/p/compare,在那里你可以一次比较多达三个项目的统计数据。

可用框架

在这里,我选择了几个最有前途的框架(对我来说),并附有概要和网站地址。之后,我们将给出一个基本的“你好,世界!”两个框架的例子:GLGE 和 philoGL。

image 注意我看不出列出所有当前的框架有多大价值,因为许多框架缺乏之前指定的必要标准(支持、特性、用户),而这些标准是长期存在所必需的。当你试图选择一个来使用时,把它们都展示出来只会把水搅浑。在撰写本文时,这个列表包含了一些顶级的框架。这个列表有些主观,所以如果我遗漏了一个你认为有价值的框架,我很抱歉。

C3DL

C3DL 代表 C anvas 3D L 库。该库旨在提供“一组数学、场景和 3d 对象类,使 WebGL 对于那些希望在浏览器中开发 3D 内容但不想深入处理 3D 数学的开发人员来说更容易访问。”

C3DL 网页有几个教程和很好的文档。你可以在这里找到它:www.c3dl.org/

铜光〔??〕〔??〕??〕

CopperLicht 可用于 3D 应用和游戏。特性包括快速渲染、世界编辑器和许多模型格式的导入。你可以在这里找到更多关于它的信息:www.ambiera.com/copperlicht/index.html

GLGE

GLGE 的主要目标是简化。“懒人的 WebGL”和“GLGE 的目的是向 web 开发者掩盖 WebGL 的复杂本质,然后他们可以花时间为 web 创造更丰富的内容。”在本章的后面我们将展示一个 GLGE 的例子。你可以在这里找到 GLGE:【www.glge.org/】??

Jax

Jax 的设计考虑到了快速开发。它是“快速构建健壮、高质量 WebGL 应用的一站式商店”Jax 使用 Ruby 语言和模型-视图-控制器(MVC)模式来分离组件。一些内置功能包括键盘和鼠标输入处理,以及单元测试功能。你可以在 jaxgl.com/的[找到 Jax 网站,在 github.com/sinisterchi… 的](jaxgl.com/)[找到 github 的源代码](github.com/sinisterchi…)

kicks

KickJS 专注于用 WebGL 进行游戏开发。KickJS 还提供了一个在线交互式 GLSL 编辑器,如第二章中展示的那样,还有一个在线编辑器(目前处于测试阶段)。你可以在这里找到 KickJS 网站:【www.kickjs.org/】??,在 github 上托管的源代码在这里:【github.com/mortennobel…??

PhiloGL

PhiloGL 专注于数据可视化和游戏开发。该框架的目标是在编写时考虑到最佳的 JavaScript 实践,并对基本的 WebGL 调用进行抽象。在本章的后面我们将展示一个 philoGL 的例子。你可以在这里找到更多关于它的信息:www.senchalabs.org/philogl/

场景 ??

SceneJS 擅长渲染大量可拾取的对象,如工程和医疗应用中使用的对象。这是可能的,因为该框架(顾名思义)提供了一个场景图引擎,它在内部使用了一个高效的优化绘制列表,并且是基于 JSON 的。你可以在这里找到更多关于它的信息:www.scenejs.com/

TDL

Threedlibrary (TDL)专注于低水平的使用和性能,而不是易用性。谷歌身体和许多高性能的演示使用 TDL。你可以在这里找到更多关于它的信息:code.google.com/p/threedlibrary/

三. js

如前一章所述,Three.js 是一个通用的 3D 引擎,它抽象出了许多细节,使得开发 WebGL 更加容易。Three.js 是目前最流行的 WebGL 框架,有人认为 WebGL 和 Three.js 是一回事。事实并非如此,但正如前一章所展示的,这是一个很好的尝试框架。你可以在这里找到 github 上的 Three.js 库:github.com/mrdoob/three.js

在这一章,我们将展示如何导入网格和使用 Three.js 的物理引擎。

一句“你好,世界!”例子

philoGL 是来自 Sencha 实验室的一个框架,该项目的主要开发者是尼古拉斯·加西亚·贝尔蒙特。框架网站在www.senchalabs.org/philogl/,源代码在 github 上:github.com/senchalabs/philogl

首先,下载这个库,并将其包含在本地

,或从远程位置如

philoGL 库的\examples 文件夹展示了 Giles Thomas 在learningwebgl.com/blog/?page_id=1217的热门网站“学习 WebGL”的核心 WebGL 课程的 philoGL 版本。该库分为核心和模块。文件可在 www.senchalabs.org/philogl/doc…](www.senchalabs.org/philogl/doc…)

清单 8-1 显示了库包含的移植的“学习 WebGL”第 4 课示例的修改版本,供我们进一步分析。从清单中可以看出,philoGL 对 JavaScript 使用了非常面向对象的方法。为简洁起见,省略了网格数据,但可以在/08/01_philogl_cube.html 中找到完整的联机文件

清单 8-1 。 代码用 philoGL 旋转一个立方体

Philo cube 试验

九、调试和性能

在本章中,我们将展示如何排除错误并提高应用性能。我们将:

  • 展示用于调试 WebGL 代码和着色器的有用工具
  • 复习一些常见错误及其解决方法
  • 展示如何通过优化我们的代码来消除常见的瓶颈,从而提高 WebGL 的性能
  • 确定 WebGL 最佳实践

排除故障

当我们的程序产生错误的结果时,作为计算机程序员,我们说程序中有个错误或者表现出个错误 。识别 bug 错误来源并修复它们的过程被称为调试

为什么要以精通调试代码为目标?尽管调试通常是编程中最耗时和最令人沮丧的部分,但它也是开发中很自然的一部分。使用能够查明错误来源的工具和技术,以及对常见错误的了解,对于最小化我们花费在调试上的时间是至关重要的。

集成开发环境

我们应该寻求帮助的第一个地方是我们编码的地方。虽然我们可以使用没有语法高亮或代码智能的纯文本编辑器,但是我们为什么要这样做呢?大多数现代的 ide 会通过颜色和/或其他语法高亮显示提供近乎即时的反馈,并显示警告或通知。有很多很多的 ide 和文本编辑器可用,每一个都有各种各样的特性。有些是轻量级的,而有些是内存密集型的,有些是开箱即用的,而有些有插件或模块来添加功能。ide 的价格也从免费到非常昂贵不等。一些适合 JavaScript 和 web 开发的文本编辑器和 ide 包括 Sublime、Notepad++、Netbeans、Eclipse、WebStorm、Zend Studio、Aptana、Cloud9 和 Komodo。其中,有趣的是,Cloud9,顾名思义,是托管在云中的。没有本地安装,当然有利有弊。

至少,您的 IDE 或文本编辑器应该能够检测 JavaScript 和 HTML 语法,有一些颜色编码,可视化地匹配大括号和圆括号,有行号和搜索/替换支持。另一方面,ide 可以有内置的版本控制和远程文件支持、单元测试、重构、代码完成、API 智能等等。你可以在图 9-1 中看到一个 IDE 运行的例子。

9781430239963_Fig09-01.jpg

图 9-1 。Webstorm IDE 中的 jQuery 库自动完成功能

我不会试图说服您使用特定的 IDE 或文本编辑器。选择权在你,最终应该是你觉得最舒服和最有效率的使用方式。需要考虑的一些因素包括:

  • 积极发展和社区基础:不要花时间去学习那些很快就会过时或没人用的东西。
  • 能力和生产力:你能通过几个按键/宏做一些令人惊奇的事情吗?或者 IDE 的巨大实际上阻碍了你的生产力吗?请记住,IDE 的目的是通过提供有助于开发的工具来提高生产率和易用性。
  • 可扩展性:IDE 有插件、模块和第三方集成支持吗?
  • 直观性:IDE 是否设计良好,易于导航?
  • 可配置性:如果初始设置不符合您的要求,编辑器/IDE 中有多少是可定制的?
  • 资源使用和稳定性:加载 IDE 需要几秒钟还是几分钟;是否有求必应;是否占用过多内存;经常死机吗?
  • 焦点:IDE 是针对一种语言还是多种语言定制的?一个特定的任务还是很多?这些都有利弊。通常,如果一个 IDE 是为一种语言定制的,它会比为多种语言设计的软件更时尚、更优化,而且可能还拥有高级工具。然而,一个面向多种语言的 IDE 意味着如果你经常用多种语言编码,你只需要学习一个 GUI 。

浏览器开发工具

WebGL 在浏览器内部运行,使用的 API 是用 JavaScript 编写的。调试时我们应该寻求帮助的下一个地方是浏览器内部,因为每个主流浏览器都有自己内置的开发工具。这些开发人员工具的可用性和功能各不相同,但都具有相同的功能:查看和操作文档对象模型(DOM)、资源、网络流量的能力,以及输出 JavaScript 调试和错误信息的交互式控制台。

Chrome/Safari 都提供了开发者工具。Firefox 有 Firebug 和开发者扩展,Internet Explorer 有开发者工具栏,Opera 有蜻蜓。就内置支持而言,Internet Explorer 开发工具在版本 8 和版本 9 之间有了很大的改进。然而,在我看来,Chrome 和 Firefox 仍然是功能最丰富的浏览器工具。

默认情况下,Safari 禁用了他们的开发者工具。要启用它们,您需要转到首选项> >高级选项卡,然后单击“在菜单栏中显示开发菜单”复选框。火狐扩展可以在 getfirebug.com/和 ?? 获得。

在图 9-2 中,我们演示了如何通过 Chrome 开发者工具控制台标签交互地找到一个 DOM 元素。

9781430239963_Fig09-02.jpg

图 9-2 。使用 Chrome 开发者工具中的控制台搜索<标题>标签

在图 9-3 中,我们展示了 Opera 的蜻蜓开发者工具的网络流量标签。此标签显示网页已载入和正在载入的资源的时间线。

9781430239963_Fig09-03.jpg

图 9-3 。用蜻蜓歌剧院观看网络统计

在图 9-4 中,我们展示了 Firefox 的一个很酷的新特性:以三维方式可视化 DOM 的能力。WebGL 使这个工具成为可能。

9781430239963_Fig09-04.jpg

图 9-4 。火狐中 DOM 元素的 3D 可视化,由 WebGL 实现

另外两个特定的浏览器工具是:在 Firefox 的地址栏中输入“about:config”和搜索“webgl”可以让你调整 Firefox 的 webgl 设置。在 Chrome 中输入地址“about:tracing ”,就可以在浏览器中对 WebGL 应用进行分析。

发送到控制台的调试消息

为了向我们自己或其他开发人员输出关于程序状态的信息,或者如果有我们应该知道的警告或错误,我们可以将消息打印到 JavaScript 控制台屏幕上,而不是显示可能令人讨厌的非严重错误的警告框,或者用我们的状态更新来混淆 DOM 文档。如前所述,所有的浏览器都有开发者工具,包括用于输入和输出命令和消息的控制台屏幕。JavaScript 中还有一个控制台对象,它有向开发人员控制台输出消息的方法。

例如,我们可以用 JavaScript 代码将日志消息和错误消息写到开发人员控制台,如下所示:

var myvar = 42

console.log("只是一些有帮助的信息");//只是一些有用的信息

console.error("更严重的东西:"+myVar);//更严重的东西:42

控制台中显示的这两条消息的主要区别在于,错误消息通常是红色字体,而日志消息是黑色的。控制台对象有更多的方法,Firebug 控制台的应用编程接口(API)可在getfirebug.com/wiki/index.php/Console_API获得。尽管控制台对象的具体实现是依赖于浏览器的,但是其他的(比如基于 WebKit 的)支持 Firebug 使用的大部分实现。

查看别人的代码

因为 WebGL 使用的是 JavaScript 编写的客户端 API,所以我们可以很容易的查看别人的代码。这样做可以洞察我们以前可能没有考虑过的技术。查看 JavaScript 代码有两种方法:右键单击并访问菜单项“查看页面源代码”或“查看源代码”,或者查看开发人员工具的资源选项卡。对于着色器源,我们也可以查看原始源。然而,正如我们在第七章中所展示的,框架可以修改最终的着色器源。因此,使用像 WebGL inspector 这样的工具会更有用,我们将在本章的后面介绍。

在线沙盒

沙箱 是一个安全的环境,众所周知,孩子们可以在里面玩耍,发挥他们的想象力。用开发术语来说,沙箱是一个隔离的测试环境,我们可以在不损害生产代码的情况下摆弄我们的代码。

网上有很多地方我们可以快速安全地修改 JavaScript 代码。jsfiddle.net/的 jsFiddle 允许你运行 JavaScript 代码(可选 HTML 和 CSS)并查看输出。它提供了一个简单的选择框来切换普通 JavaScript 库的包含,并集成了 JSLint 支持来检查代码的有效性。与 jsFiddle 类似的站点是 JS Bin 及其位于 jsbin.com[的站点](jsbin.com)。

着色器可以在几个网站上在线修改,如 KickJS(可以在www . KickJS . org/example/shader _ editor/shader _ editor . html找到)。我们在第二章中介绍了在线着色器工具,一些额外的站点在附录 D 中列出。

在线沙盒的主要用途是能够在为您配置的大部分环境中快速测试少量代码,并且能够安全地将您的代码作为链接共享给其他开发人员查看、调整和协作。

通用 WebGL 错误代码

WebGL 的一个问题使得调试相当困难,那就是只有五个主要的错误代码(包括表示没有错误的代码)。这些代码是数字常量。WebGL 规范的一个例子是:

const glen um INVALID _ ENUM = 0x 0500;

主要错误代码有:

  • 没有错误- 我们准备好了
  • INVALID_ENUM- 为枚举参数指定了不可接受的值
  • INVALID_VALUE- 数值参数超出范围(例如试图指定着色器位置-1)
  • INVALID_OPERATION- 指定的操作在当前状态下是不允许的(比如试图生成一个没有绑定纹理的纹理贴图)
  • 内存不足- 应用已耗尽内存

WebGL 的许多函数调用都存在主要错误。这使得我们能够准确地触发和检测错误发生的位置和时间变得至关重要。有关每个函数可能抛出的错误代码的完整列表,请参考 WebGL 规范。

我们还可以检查许多 WebGL 状态,例如当我们使用以下命令检查帧缓冲区状态时:

GLenum checkFramebufferStatus(GLenum 目标);

在其他可能的返回值中,我们可能会收到以下内容:

frame buffer _ INCOMPLETE _ ATTACHMENT//0x8cd 6

上下文错误

与 HTMLCanvasElement 关联的 WebGL 呈现上下文在创建时或在应用的整个生命周期中可能会有错误。我们现在将展示如何检查这些错误,并在遇到错误时适当地处理它们。

上下文创建

如果在我们尝试获取 WebGL 上下文时请求失败,浏览器需要向画布触发一个名为“webglcontextcreationerror”的 WebGL 上下文事件。为了监听这个事件,我们可以添加一个监听器,如 WebGL 规范示例 VII 所示,如清单 9-1 所示。

清单 9-1。 检查上下文创建错误

是 errorInfo = '。

函数 onContextCreationError(事件){

帆布. removeEventListener(

" webglcontextcreationerror ",

onContextCreationError, false);

error info = e . status message | " unknown ";

}

canvas.addEventListener(

" webglcontextcreationerror ",

onContextCreationError, false);

var GL = canvas . get context(" experimental-web GL ");

if(!gl) {

alert("无法创建 WebGL 上下文。\ n 原因:"+

errorInfo(错误信息):

}

清单 9-1 中的代码创建了一个错误监听器,试图获取一个 WebGL 上下文,如果有错误将显示原因,然后移除错误事件监听器。添加侦听器的好处是,我们可以深入了解无法创建上下文的原因。

上下文丢失和恢复

如果浏览器丢失了 WebGL 的上下文,我们可以检测到并恢复它。然而,任何资源,如纹理或缓冲区,将需要重新创建。上下文可能会因为移动电源事件、GPU 重置、客户端放弃背景标签或资源不足而丢失。来自 WebGL 规范的示例 VI 的一部分显示在清单 9-2 中,并演示了如何监听“webglcontextlost”和“webglcontextrestored”事件。

清单 9-2。 倾听失去的语境,还原语境

canvas.addEventListener(

" webglcontextlost ",函数(事件){

//通知 WebGL 我们处理上下文恢复

event.preventDefault();

//停止渲染

window.cancelAnimationFrame(必需):

},假);

canvas.addEventListener(

" webglcontextrestored ",函数(事件){

initialize resources();

},假);

在清单 9-2 中,我们注册了上下文丢失和恢复的监听器。如果上下文丢失了,我们就停止制作动画。在恢复时,我们重新装载我们的资源。

image 注意上下文丢失是 WebGL 的主要安全问题之一,OpessnGL GL_ARB_robustness 扩展旨在为应用添加检测丢失上下文的能力。这将有助于显卡“监视”拒绝服务等恶意攻击。

持续检查错误

在开发过程中,我们可以使用由 Khronos 集团(监督 webgl 的联盟)创建的 webgl-debug.js 库,该库可从CVS . Khronos . org/SVN/repos/registry/trunk/public/web GL/SDK/debug/web GL-debug . js获得。www.khronos.org/webgl/wiki/…概述了使用方法。这个库将在每次 WebGL 调用之间调用 getError,并将错误结果输出到控制台。我们可以通过调用以下命令将错误号转换成可读性更好的字符串:

webldbugutils . glenumosting(GL . get error());

调用 getError 的开销很大,因为它会轮询 GPU,从而有效地阻止 WebGL API 和 GPU 之间的进一步通信,直到返回结果。因此,该库不应用于生产代码中。

在本地下载 webgl-debug.js 文件。从第三章的 03/texture_and_lighting.html 文件开始,我们会稍微修改一下代码来利用这个库。首先,我们包括新的脚本文件:

现在让我们产生一个错误,这样我们就可以演示这个库了。在 setupWebGL 函数中,将深度测试的启用从 gl.enable(gl。DEPTH_TEST)到 gl.enable(gl。DEPTH_TEST_FOOBAR)。如果我们运行这个程序,它看起来很奇怪,但是我们在控制台中没有得到任何指示,表明有一个 WebGL 错误,如图 9-5 所示。

9781430239963_Fig09-05.jpg

图 9-5 。我们的控制台没有产生错误

现在,我们将在 initWebGL 函数的 webgl-debug.js 库中包装我们的 WebGL 上下文:

如果(总帐)

{ GL = webldbugutils . make debug context(GL);

结果(在 09/texture _ and _ lighting _ debug . html 文件中找到)是不产生图像,但是有用的调试信息被输出到控制台。它准确地告诉我们哪个函数和行是错误的 setupWebGL 函数中的第 132 行——如图 9-6 所示。

9781430239963_Fig09-06.jpg

图 9-6 。来自 webgl-debug.js 的调试信息

WebGL 检查器

目前可用的最好的浏览器内调试工具是 WebGL Inspector,它是一个有用的工具,可以查看视图着色器程序信息、加载的纹理、应用的当前状态、缓冲区的内容、捕捉快照以及帧的完整跟踪数据等等。WebGL inspector 由 Ben Vanik 和 James Darpinian 编写,可从benvanik.github.com/WebGL-Inspector/获得。它被宣传为

“一个高级 WebGL 调试工具包…受 gDEBugger 和 PIX 的启发,目标是使高级 WebGL 应用的开发更容易。就像 Firebug 和开发者工具之于 HTML/JS,WebGL Inspector 之于 WebGL。”

WebGL inspector 可以通过在网页中嵌入脚本或安装 Chrome 扩展来使用。安装完成后,带有 WebGL 内容的页面会在地址栏显示一个 GL 图标,并在网页上显示两个按钮,“捕获”和“UI”,如图图 9-7 所示。

9781430239963_Fig09-07.jpg

图 9-7 。WebGL 检查器的缓冲区标签

在图 9-7 中,显示了缓冲区选项卡,显示了我们的顶点缓冲对象(VBOs)的内容。我们可以使用纹理选项卡来确保我们的纹理已经正确加载,查看过滤器和夹紧参数,以及其他关于纹理的信息(见图 9-8 )。

9781430239963_Fig09-08.jpg

图 9-8 。WebGL 检查器的纹理数据

“程序”标签将显示我们程序的状态,以及属性和制服以及我们的顶点和片段着色器源代码,如图 9-9 所示。

9781430239963_Fig09-09.jpg

图 9-9 。WebGL 检查器的“程序”标签

状态选项卡显示了我们所有可调整的状态设置,如是否启用混合、混合颜色、透明颜色、多边形正面的方向等等,如图 9-10 所示。

9781430239963_Fig09-10.jpg

图 9-10 。WebGL 检查器的“状态”选项卡中显示的 WebGL 状态设置

时间轴选项卡将显示各种指标的实时数据,如帧时间、图元/帧和缓冲存储器。时间线是这个非常有用的程序的一个方面,它可以使用一些工作来产生更可扩展和可读的结果(见图 9-11 )。

9781430239963_Fig09-11.jpg

图 9-11 。WebGL 检查器的时间线指标

到目前为止,我们还没有讨论捕获按钮。在我看来,这是 WebGL inspector 最有用的功能。当您点击该按钮时,WebGL inspector 将捕获屏幕,并生成一个完整的帧轨迹,如图 9-12 中的轨迹选项卡所示。我们的示例程序很小,只有 19 行,但是复杂的 WebGL 应用可以有数千行,我们将在后面演示。突出显示为黄色的行是多余的。这是帮助提高性能的重要信息,如下一节所示。您可以选择不突出显示多余的电话,但可能会发现反馈很有用。WebGL inspector 还可以让我们减慢或暂停帧的推进。

9781430239963_Fig09-12.jpg

图 9-12 。“跟踪”选项卡显示使用 WebGL 检查器捕获的帧

在图 9-12 的第 19 行,右边有两个图标。第一个带有向右的箭头,让我们从单个 draw 命令运行独立的输出。在我们的示例应用中,这是整个场景。然而,在有几个绘制调用的更复杂的应用中,显示场景的特定部分被渲染是非常有用的。当第二个链接(看起来像一个 i )被点击时,一个新的窗口将弹出完整的绘图信息。该弹出窗口很大,首先显示了绘制的元素的网格,可以用鼠标滚轮放大和缩小,并在按住鼠标按钮的同时旋转。这个网格对于视觉上确认我们的顶点已经以正确的顺序渲染是有用的,这样我们也可以确保我们的多边形面的一致缠绕;红色在顺时针和逆时针方向的亮度是不同的。我们还可以显示使用的纹理坐标网格。接下来,显示程序统一和当前值的列表,后跟属性。最后,我们看到了 WebGL 设置的状态:顶点,片段,深度/模板和输出。该弹出窗口的第一部分如图 9-13 所示。

9781430239963_Fig09-13.jpg

图 9-13 。有关 WebGL 检查器中特定绘图调用的信息

如果我们点击显示在轨迹日志右侧的图像像素(未在图 9-12 中显示),我们将在一个新的弹出窗口中获得关于颜色成分以及如何获得最终像素颜色的所有信息。我们的例子没有混合,所以最终的颜色计算很简单,如图图 9-14 所示。但是,当与非透明 alpha 值混合时,此信息可能非常有用。

9781430239963_Fig09-14.jpg

图 9-14 。WebGL 检查器的像素历史

最后,WebGL inspector 对于指出错误也很有用。重新添加 gl.enable(gl。DEPTH_TEST_FOOBAR)线使轨迹的错误线以红色高亮显示,如图图 9-15 所示。

9781430239963_Fig09-15.jpg

图 9-15 。无效关键字导致的 WebGL 检查器错误

如果我们试图获得一个不存在的属性位置(例如,试图获得错误输入的属性 aVertexPosition2 而不是 aVertexPosition),getAttribLocation 返回(-1),这是一个无效值(参见图 9-16 )。

9781430239963_Fig09-16.jpg

图 9-16 。属性位置值无效导致的 WebGL 检查器错误

image 注意如果一个变量确实存在于你的顶点着色器中,但你从未使用过它,编译器会将其标记为未使用,并在编译和链接你的程序时将其移除。如果您稍后尝试获取它的位置,您将收到(-1)并产生相同的错误。

最后,假设我们调用了 gl.bindBuffer,将 null 值绑定到 WebGLBuffer 参数。这很容易发生,例如,在从文件中生成或读取数据时将数据写入变量,但在绑定已经初始化为 null 且从未写入的时使用不同的变量。突出显示的错误如图 9-17 所示。

9781430239963_Fig09-17.jpg

图 9-17 。将 VBO 绑定到 null 导致 WebGL 检查器错误

正如您所看到的,WebGL inspector 是一个具有多种用途的工具,我敦促读者熟悉它——您会感谢自己的。

使用 glsl 装置进行测试

单元测试代码——将程序的各个部分隔离成小单元,并在每个单元上运行自动化测试——是一种有价值的方法,可以确保程序按照预期的方式运行,并在重构时检测代码中的错误(对代码进行结构性而非行为性的更改,以改进代码设计和质量)。

code.google.com/p/glsl-unit… GLSL 单元测试框架。要克隆 git 存储库,您可以使用:

git clone

code.google.com/p/glsl-unit/

常见陷阱

使用 WebGL 编程时,有一些错误比其他错误更容易遇到。这里有一些要避免的陷阱。

缓存内容

没有使用文件更改。浏览器仍然在使用旧版本。使用 Shift-F5 进行硬浏览器刷新,或者通过重命名资源文件或故意向着色器程序或 javascript 文件添加错误(临时)来引起浏览器的注意。

为不兼容的上下文重用画布

“2D”和“webgl”上下文不兼容。尝试使用一个然后用另一个调用 canvas.getContext 将返回 null,而不是获得有效的上下文。

移动设备碎片精确支持

WebGL 只要求片段着色器浮点值支持 mediump。许多手机和移动设备只支持这种精度。如果您的目标是移动用户,请不要使用 highp。我们还可以通过调用 getShaderPrecisionFormat 函数来轮询设备支持的精度。这可以让您根据设备功能提供不同的着色器。

摄像机视角朝向错误的方向

确保虚拟摄像机指向场景的正确方向,并且顶点位于剪辑空间和视口内。

质地问题

尝试生成纹理贴图时使用非 2 次方(NPOT)纹理是一个致命错误。可用的纹理单元的数量也有限制。如果你运行图 9-18 所示的 webglreport,你可以很容易地看到你当前的浏览器和 GPU 支持的确切数字。

9781430239963_Fig09-18.jpg

图 9-18 。使用 webglreport 查看您的浏览器 WebGL 支持

性能因 GPU 而异

GPU 有不同的硬件设置和优化。在一个 GPU 上优化的东西在另一个 GPU 上可能非常慢。

加载错误的资源

检查是否加载了正确的文件,无论是纹理图像、网格还是着色器文件。还要确保没有违反跨原始资源共享规则。

浏览器差异

建议在调试时在不同的浏览器中尝试您的代码,因为结果可能会有所不同,或者只在某些浏览器中有效。原因是一些 WebGL 规范是依赖于客户端的。有最低要求,但不是所有的实现都是一样的。也不是所有的扩展都受支持。要轮询浏览器支持的可用扩展列表,您可以使用以下函数:

domstring[]getsupportxtenderextensions()

对象 getExtension(DOMString 名称)

getSupportedExtensions 函数返回一组受支持的扩展名。返回的数组中的每个字符串都将从 getExtension 返回一个有效的对象,而不在受支持的数组中的任何字符串名将返回 null。返回的对象表示扩展已被正确启用,但不需要包含任何函数或常数。

我们还可以使用函数 getParameter(GLenum pname)来查找其他浏览器支持信息,例如使用以下命令检查支持的最大纹理大小:

GL . get parameters(GL)。MAX_TEXTURE_SIZE)。

即使没有 WebGL 浏览器差异,也有 JavaScript 浏览器差异需要测试。例如,JavaScript 对象或数组中的尾随逗号在大多数浏览器中是正确的,但在 Internet Explorer 中是错误的。

ie) [1,2,3,]在 ie 中是不好的,而[1,2,3]在所有浏览器中都是好的。

而{"a":"1 "," b":"2 ",}在 IE 中是不好的而{"a":"1 "," b":"2"}在所有浏览器中都是好的。

analyticalgraphicsinc.github.com/webglreport/有一个很好的查看浏览器 WebGL 常量的实用程序,Chrome 输出示例如图图 9-18 所示。

外部着色器解析错误

当从外部文件加载着色器时,您可能会注意到一个似乎有效的语句,如以下任一项:

if(a < b){;}

if(a & & b){;}

每一行都会导致着色器无法加载,因为 XML 实体“

if(a<b){;}

if(a&&b){;}

或者,您可以调整从对 HTML 的 Ajax 调用返回的数据类型,然后用 jQuery 解析出脚本标记:

$.ajax({

异步:假,

url: './my_shader.fs ',

成功:函数(数据){

fs_source = $(数据)。html();

},

数据类型: 'html'

});

性能

对于简单的应用,遵循 WebGL 最佳优化实践并不重要。浏览器和 GPU 可以非常快速地执行计算,因此少量的绘制调用将快速渲染,并以良好的帧速率出现,无论我们的代码是否经过优化。然而,随着我们的应用变得越来越复杂,并涉及更多的 WebGL 和 GPU 交互,它们将很快变慢,其影响范围从轻微的明显到令人虚弱的使用。对我们来说幸运的是,有已知的方法来获取现有的代码并优化它。

测量帧速率

为了查看我们所做的是否真的改善了处理,我们需要测量我们正在渲染的帧率 (每秒的帧数)。较低的帧速率会显得起伏不定,而较高的帧速率会显得平滑自然。帧速率通常以每秒帧数(fps)来衡量。由于相机是手摇的,无声电影的帧速率可变,约为 14-26 fps。早期的投影仪将 fps 设置为恒定的 24 fps,这当然显得更加平滑。一些较新的电影使用 48 fps,计算机显示器的刷新率通常为 60 赫兹(Hz,赫兹,是每秒的周期数),尽管现在更大的数字显示器超过 100 赫兹。所以你能达到的帧率越高越好。

为了测量帧率,我们将使用位于 github.com/mrdoob/stat… 的 Github 上的 stats.js 库。这个库是 three.js 框架的作者写的,这个框架在第七章中有介绍。下载 stats.js 文件,并将其包含在代码中,如下所示:

接下来,我们需要将 stats

附加到我们的文档,并每次通过 requestAnimationFrame 循环调用它的 update 方法。请注意,如果我们的场景暂停,则不会调用 update 方法。这是个人偏好,否则当应用暂停时,fps 将会波动到一个更高但不相关的值。使用 stats.js 库的代码如清单 9-3 所示。

清单 9-3。 向我们的应用添加统计计算器

var Stats = new Stats();

函数 initWebGL()

{

attach stats();

(函数 animLoop(){

如果(!暂停){

setupwbgl();

setMatrixUniforms();

draw scene();

stats . update();

}

requestimationframe(aniloop,canvas);

})();

}否则{

alert("错误:您的浏览器似乎不支持 WebGL。");

}

}

函数 attachStats()

{

stats . getdomelement()style . position = ' absolute ';

stats . getdomelement()style . left = ' 0px ';

stats . get item(). style . top = ' 0px ';

document . body . appendchild(stats . getdocument());

}

image **注意:**你可以通过使用 setMode 方法查看渲染帧而不是 fps 所用的毫秒数:

stats.setMode(1);0: 满分频, 1: 毫秒

统计部件显示在图 9-19 的左上角。

9781430239963_Fig09-19.jpg

图 9-19 。显示 stats.js 的 fps 指标

当我们使用 stats.js 并打开多个浏览器选项卡时,如果我们切换到不同的选项卡,然后返回,当我们返回时,帧速率会急剧下降。这很好,因为它表明 requestAnimationFrame 正在如承诺的那样工作,并且没有执行不必要的动画。

优化的复杂性

很难确定如何优化 GPU,因为有许多不同的硬件实现,一些有助于某些 GPU 的优化实际上会影响其他 GPU 的性能。

瓶颈

为了优化代码,您通常需要找到瓶颈——系统性能最受限制的地方——并修复它们。

很多人都熟悉的一个例子是洗衣服和烘干衣服。假设你有三台洗衣机和一台烘干机。每台洗衣机每次洗衣需要 30 分钟,烘干机需要两倍的时间:每次洗衣需要 60 分钟。洗衣机和烘干机的容量是一样的。我们需要等待干燥机完成,并受到所用时间的限制;这是我们系统的瓶颈。

假设我们有三车衣服要洗。进行 3 次洗涤的总时间为 210 分钟(并行洗涤 30 分钟+每次干燥 60*3)。我们可以通过以下方式限制或消除瓶颈来提高系统性能:

  • 减少干燥时间
  • 增加机器的生产能力
  • 购买更多干衣机

有了第一个改进,假设你可以摆弄机器,把烘干时间缩短到 45 分钟。3 次装载的总时间为 165 分钟(30 + 45*3)。

对于第二个改进(但没有速度改进),假设您可以修改烘干机,以处理两个完整的负载,而不是一个。您仍然需要进行 2 次完整的干燥机循环(1 次半容量= 1 台洗衣机负载,然后 1 次全容量= 2 台洗衣机负载),但总时间减少到 150 分钟(30 + 60*2)。

对于第三个选项,如果您可以购买两台额外的机器,您的总时间将减少到 90 分钟(30 + 60)。

在洗衣机/干衣机的例子中,购买更多的硬件(类似于拥有更多的计算能力或 RAM)会带来最大的改进。然而,在其他情况下,瓶颈可以通过更有效的算法来改善。

例如,如果您有一个需要 1000 个数字的计算,并且该计算的当前复杂度以 n 3 的顺序增加,则需要 10 亿个计算单元才能完成。如果您购买 4 台机器并在它们之间分配计算,每台机器仍需要 250,000,000 次计算。然而,如果你可以在不购买任何新东西的情况下,将算法的复杂度降低到 n 2 ,你就减少了 1000 到 1000000 的计算成本。

WebGL 瓶颈

虽然优化不是绝对的,但是有一些通用的最佳实践指南,可以最大限度地提高性能并限制瓶颈。昂贵的操作包括阻止浏览器和 GPU 的通信以及不必要的计算和查找。片段着色器要执行的计算最多,因为它对场景中的每个像素都进行操作。由于这个原因,片段着色器也经常成为应用中的瓶颈。

片段着色器

片段着色器作用于每个像素。因此,这是计算瓶颈和性能损失的可能来源。判断片段着色器实际上是否是瓶颈的一种方法是减小画布的大小并比较帧速率。如果有显著的性能改进,那是因为需要计算的像素更少了,所以您应该尝试优化片段着色器。

一个技巧是做相反的事情:片段着色器完成后,将画布拉伸到更大的尺寸。这不需要更多的 GPU 计算,应该是一个相对便宜的客户端操作。当然,这只有在拉伸产生可接受数量的伪像或锯齿标记时才是可行的(也就是说,它看起来仍然很好)。

浏览器资源

甚至在我们开始渲染我们的场景之前,我们需要加载资源。有几种方法可以减少资源的物理大小,从而缩短网页的初始加载时间。

缩小 JavaScript 文件

当我们的代码为生产做好准备时,我们可以将多个文件组合起来并缩小成一个压缩文件。有很多工具可以做到这一点,从直接剪切/粘贴源文件到上传文件:

www.minifyjavascript.com/

jscompress.com/

要使用命令行:

html5boilerplate.com/docs/Build-script/

developer.yahoo.com/yui/compressor/

纹理

我们应该保持纹理尺寸尽可能的小。如果一个较小的 128 x 128 的纹理看起来和一个较大的 512 x 512 的几乎一样,我们应该使用它。内存会小 16 倍。其次,我们应该选择一个合适的图像格式。BMP 图像通常比 png 大,png 比 JPEGss 大,JPEG 比 WEBPs 大。您选择哪种格式还取决于您是否需要 alpha 通道,以及您可以承受多少图像数据丢失,同时仍能获得令人满意的图像质量。

浏览器与 GPU 能力的对比

GPU 的计算速度比客户端的 JavaScript 快几个数量级。在 GPU 上,许多许多操作可以并行完成,并使用编译后的本机代码。因此,如果可能的话,任何“重担”都应该由 GPU 来承担。

阻塞 GPU

GPU 从与顶点属性相关联的应用获取数据流。这些流然后到达顶点处理器,然后到达片段处理器。GPU 并行计算,但 JavaScript API 和 GPU 之间的通信更串行。自然,我们不希望尽可能地阻止这个浏览器与 GPU 的通信。这样做将导致我们的程序似乎停滞不前,帧速率下降。那么我们能做些什么来限制不必要的浏览器与 GPU 通信呢?

批量提取调用

我们应该尽可能地限制 draw 调用(drawArrays,drawElements ),方法是将它们批处理在一起。GPU 可以轻松地同时处理数百或数千个三角形。但是,单个 VBO 的大小也有上限。

image 注意: Three.js 有一个工具可以合并不相交的几何图形,以减少所需的单独绘制调用的数量。详细信息在/src/extras/GeometryUtils.js 文件和函数 THREE.GeometryUtils.merge 中。

减少缓冲切换

我们应该将顶点属性(如颜色、法线和位置)组合成交错数组,而不是使用单独的 vbo。我们将在本章的后面讨论交错阵列。

减少着色器程序切换

如果我们有几个正在使用的着色器程序和几个对象,如果可能的话,我们希望对使用每个着色器的元素进行分组,以便我们可以限制我们需要更改活动着色器程序的频率。

缓存状态变化(gl.getX/gl.readX)

每次需要轮询 WebGL 的一个状态组件时,浏览器都需要中断 GPU 获取信息。要尽量避免的一些调用有 getAttachedShaders、getProgramParameter、getProgramInfoLog、getShaderParameter、getShaderInfoLog、getShaderSource、getTexParameter、getParameter、getError、getActiveAttrib、getActiveUniform、getattrib、getUniformLocation、getVertexAttrib、getVertexAttribOffset、getTexParameter、getRenderbufferParameter、getFramebufferAttachmentParameter、getBufferParameter parameter 以及关联的 set X 调用。如果可能的话,我们应该用 JavaScript 存储这些信息的缓存版本。我们还希望限制统一更改,因为它们需要与 GPU 进行交互。要限制的其他 WebGL 调用是 readPixel 和 finish。

不要在生产中使用 getError

如上所述,使用 getError 查询昂贵的 GPU。在开发过程中持续使用它,但不要在代码进入生产环境后使用它。

移除多余的呼叫

我们已经展示了 WebGL inspector 如何非常有助于向您展示不必要的 API 调用。不必要调用的一个例子是在没有任何改变的情况下每帧设置一个状态。这可以通过将特定的状态设置代码移动到呈现循环之外的初始化函数中来补救。

另一个不必要冗余的例子是通过重新计算每个球体的顶点来生成 1000 个球体,然后在场景中置换它们。相反,计算一次单位长度(1 = x² + y² + z²)球体的顶点并存储它们。然后对于其他球体,缩放和变换所有生成的点以产生方差。这大大减少了所需的三角运算的数量,并用成本低得多的乘法和加法的初等运算来代替它们。

限制活动纹理更改

我们可以通过将小纹理合并成一个更大的纹理来减少改变活动纹理的频率。这个合成图像被称为纹理图谱 。一些行星、太阳和月亮的纹理图谱如图 9-20 中的所示。

9781430239963_Fig09-20.jpg

图 9-20 。月球、太阳和一些行星的纹理图谱

我们将在本章的后面使用这个纹理贴图来优化性能。为了提高性能,还应确保生成第三章中概述的 mipmaps。

用进废退

如果您没有使用混合或深度测试等功能,请禁用它们。例如,如果您只渲染到二维而没有 MVP 变换,或者如果您正在渲染 2D 对象,而您知道这些对象是按照从最远到最近的顺序绘制的,那么您可以安全地禁用深度测试。

更快的阵列

WebGL 数组自然比传统的 JavaScript 数组快,因为它们利用了新的 JavaScript 类型化数组。将此与交叉存取数组的使用相结合将提高 VBO 和属性性能,我们现在将对此进行解释。

类型化数组

传统上,JavaScript 中传输的原始数据被视为字符串。由于 WebGL 将大量数据传递给 GPU,因此使用类型化数组来提高性能。类型化数组使用原始二进制数据,并具有固定的字节大小和类型,这提高了流效率。

WebGL 使用原始大小:

gl .字节- 1 字节

gl。SHORT - 2 字节

gl。浮点型- 4 字节

JavaScript 中可用的类型化数组有以下几种:

ArrayBuffer, ArrayBufferView, DataView

浮动 32 阵列,浮动 64 阵列

int 16 阵列,int 32 阵列,int 8 阵列

Uint16Array, Uint32Array, Uint8Array

WebGL 中需要类型化数组。你可以在 developer.mozilla.org/en/JavaScri… 查看更多关于他们的信息。

交错数组

切换 VBOs 是昂贵的。为了简单起见,属性数据通常是分开的。然而,我们可以将部分或全部数据合并到一个交错数组中,而不是使用单独的颜色、纹理、位置和法线数组。这在性能方面会好得多,因为阻碍性能的不是一次传递给我们 GPU 的数据量,而是所需的单独绘制调用的数量。

交错数组只是在每个顶点将数据混合在一起。在图 9-21 中,数组数据的每一行都有 RGBA 颜色数据,后面是 XYZ 位置数据(W 被省略)。每行的元素总数是 7:RGB axyz。当我们告诉 WebGL 如何解释我们的数据时,将需要大小和顺序。WebGL 不关心数据的实际内容,由我们来提供数据的适当上下文。我们可以按照 XYZRGBA 的顺序有效地交错数组。

9781430239963_Fig09-21.jpg

图 9-21 。使用单独的数据阵列与交叉存取阵列

让我们看看使用交错数组所需的实际代码。在清单 9-4 中,我们展示了两个属性数组的数组声明,以及它下面的一个交错数组的声明。

清单 9-4。 分离位置和颜色数组和交错数组

//带有分隔数组的正方形

var vertexPositionArray = [

        10.0, 10.0, 0.0,

        10.0, -10.0, 0.0,

        -10.0, -10.0, 0.0,

        -10.0, 10.0, 0.0

];

var verticalarray =[

        1.0, 0.0, 0.0,

        0.0, 1.0, 0.0,

        0.0, 1.0, 1.0,

0.0, 0.0, 1.0

];

//带有交错数组数据的正方形

var vertexInterleavedArray = [

//x,y,z,r,g,b

10.0, 10.0, 0.0, 1.0, 0.0, 0.0,

        10.0, -10.0, 0.0, 0.0, 1.0, 0.0,

        -10.0, -10.0, 0.0, 0.0, 1.0, 1.0,

-10.0, 10.0, 0.0, 0.0, 0.0, 1.0

];

现在我们有了数据,我们可以将它绑定到一个缓冲区,然后在稍后绘制场景时将我们的属性指向缓冲区。清单 9-5 中的显示了单独的缓冲器。

清单 9-5。 绑定单独的缓冲区并稍后指向属性

//用于位置和颜色数据的两个缓冲区

var vertexpositionbuffer = GL . create buffer();

gl.bindBuffer(gl)。ARRAY_BUFFER,vertexPositionBuffer:

gl.bufferData(gl。ARRAY_BUFFER,new float 32 ARRAY(vertexPositionArray),gl。STATIC _ DRAW);

var verticalrbbuffer = GL . create buffer();

gl.bindBuffer(gl.ARRAY_BUFFER,顶点颜色缓冲区);

gl.bufferData(gl。ARRAY_BUFFER,new float 32 ARRAY(vertexcoloraray),gl。STATIC _ DRAW);

gl.bindBuffer(gl)。ARRAY_BUFFER,vertexPositionBuffer:

gl . verticalpointer(vertexplicationattributes,3,GL)。浮点,false,0,0;

gl.bindBuffer(gl.ARRAY_BUFFER,顶点颜色缓冲区);

gl . verticalpointer(verticalcolor 属性,3,GL)。浮点,false,0,0;

vertexAttribPointer 的最后两个参数是步幅偏移。这些以字节为单位,默认值都是 0。

进展

stride 让 WebGL 知道数组中每行顶点数据相隔多远。所以对于 vertexPositionArray,这是 3 *Float32Array。字节每元素= 12。以下语句将产生与使用默认步幅 0 相同的结果。

gl . verticalpointer(vertexplicationattributes,3,GL)。浮点值,false,12.0;

对于我们的交错阵列,我们的跨距为 6 * float 32 阵列。每元素字节数= 24。请注意,我们还可以使用一个包含“垃圾数据”的数组,这些数据是我们在每行中没有使用或稍后使用的,例如://[r,g,b,x,y,z,some _ extra _ value]在这种情况下,跨距将是 7 * Float32Array。BYTES_PER_ELEMENT = 28,即使我们仍然只使用每行的 24 个字节。

抵消

偏移量告诉 WebGL 从哪个字节开始读取数据。对于清单 9-4 中的 vertexPositionArray,如果我们想要丢弃前两个数字并从第三个开始,我们将使用偏移量 2 * Float32Array。每元素字节数= 8。我们的前三个顶点是:

(0.0,10.0,-10.0)

(0.0,-10.0,-10.0)

(0.0,-10.0,10.0)

当我们需要指向交错数组中的特定数据属性时,stride 和 offset 真正派上了用场。使用相同的缓冲区,我们可以将属性的偏移量设置为不同的适当值。对于清单 9-4 中的交错数据,位置数据没有偏移,而颜色数据是 3 * Float32Array。BYTES_PER_ELEMENT = 12 字节,所以我们将其偏移量设置为这个值,如清单 9-6 所示。

清单 9-6。 使用单个缓冲器进行数据间插

//使用单个缓冲区的交错数据

var vertxinterleave dbuser = GL . create buffer();

bindBuffer(gl。ARRAY_BUFFER,vertexInterleavedBuffer);

gl.bufferData(gl。ARRAY_BUFFER,new float 32 ARRAY(vertexInterleavedArray),gl。STATIC _ DRAW);

bindBuffer(gl。ARRAY_BUFFER,vertexInterleavedBuffer);

gl . verticalpointer(vertexplicationattributes,3,GL)。浮点值,false,24.0;

gl . verticalpointer(verticalcolor 属性,3,GL)。浮点,false,24,12;

索引缓冲区

如果可能的话,使用索引缓冲区,因为 GPU 针对它们的使用进行了优化。索引缓冲区允许我们重用顶点,因此需要在 CPU 和 GPU 之间传输更少的数据。

早期估算计算

您不会在每次需要使用圆周率时都计算到小数点后 100 位,而是使用预先计算的值。此外,圆周率精确到 100 位小数很可能是不必要的,并且不会在最终结果中产生任何差异。这展示了计算中的两个重要概念:

  • 最快的计算是不需要进行的计算。
  • 如果(视觉)结果大致相等,估计和简化往往比精确更好。

重用预先计算的值比多次执行计算要好。例如,如果每个顶点计算 cos(时间),在我们的 JavaScript 中每帧计算一次这个值,并作为统一值传递给顶点着色器,这比每个顶点都计算一次要好得多。

按照从最便宜到最贵的顺序:

  • 在代码内部设置为常量的外部计算
  • 应用设置期间完成的计算
  • 计算重做了应用的每一帧
  • 在顶点着色器中对每个顶点进行计算
  • 对片段着色器中的每个像素进行计算

当然,我们还必须考虑到 GPU 比 JavaScript 强大得多,所以在有些情况下,早期用 JavaScript 进行复杂的计算与在 GPU 中多次进行计算一样糟糕,如果不是更糟糕的话。

最佳实践总结

以下是被广泛认为是 WebGL 最佳实践用法的技术:

  • 尽可能批量,减少抽签调用的次数
  • 交错属性数据
  • 减少状态变化查询
  • 不要在生产中调用 getError
  • 保持纹理尺寸尽可能小;使用纹理贴图和批纹理
  • 将尽可能多的计算从浏览器转移到 GPU,这样速度会大大提高
  • 确保片段着色器得到优化,因为它是最常用的
  • 使用 requestanimationframe

更多资源可在附录 D 中找到。

捏造的例子

我们往往会忘记(或不完全理解)我们所学的东西,除非我们深入研究并亲自尝试。因此,我们现在将编造一个例子,让许多对象在场景中随机移动,以使 WebGL 足够慢,以注意到优化的改进。我们将增加对象的数量,直到我们获得一个差的帧速率,然后我们将使用我们已经获得的调试和性能知识来优化它。

我已经创建了一个例子,09/spheres_original.html,它使用了六个纹理(太阳、地球、月亮、火星、木星和土星)以及一个基本的光照模型和随机运动。最初,每个球形对象将有一个单独的绘制调用,并使用非交错数据。通过调整渲染对象的数量,我们可以降低帧率。在我的机器上,6 个对象以 60 fps 运行,50 个以大约 35 fps 运行,100 个以大约 30 fps 运行,这还可以。一千个对象将帧速率降低到大约 4 fps。我尝试了 10,000,但是我的浏览器只是挂了一会儿。你可以在图 9-22 左边看到 50 个物体,右边看到 1000 个。您可以通过更改以下行来调整在您的计算机上渲染的对象的数量,并且可以通过使用显示在画布左上角的 stats.js 小部件来观察帧速率:

9781430239963_Fig09-22.jpg

图 9-22 。左边五十个物体;右边 1000

var num _ spheres = 1000

较低的-4 fps 是一个很好的起点,可以看到性能的改善。打开 WebGL Inspector,我们可以捕捉到一帧,在 Trace 选项卡中看到每帧执行了 18000 多行;以及如图图 9-23 所示的 1000 次总抽取呼叫;“缓冲区”选项卡中有 4,000 个独立的缓冲区;并且使用了超过 40 MB 的缓冲数据。

9781430239963_Fig09-23.jpg

图 9-23 。跟踪捕获显示超过 18,000 条线路,并突出显示冗余调用

捕捉一帧并使用跟踪来为我们识别冗余,我们可以看到正在设置视口,并且每帧都在重新计算透视矩阵。我们的视角不会改变,我们的相机也不会移动,所以这是一种浪费。我们可以将下面几行移动到渲染循环之前:

gl.viewport(0,0,canvas.width,canvas . height);

mat4.perspective(45,canvas.width / canvas.height,0.1,100.0,p matrix);

gl .统一矩阵 4 Fv(glprogram . pmatrixuniiform,false,pmatrix);

这个改变稍微提高了 fps。我们将通过跟踪工作,直到我们尽可能多地消除冗余。接下来,我们可以看到,每次渲染对象时,我们都在重新启用顶点数组属性。我们也可以将这些线移动到渲染循环之前。

vertexpositionattributes = GL . getaftlocation(glprogram," warning explication ");

vertxnormalattribel = GL . getattriblocation(glprogram," warning xnormal ");

vertxtxcoordattributel = GL . getattriblocation(glprogram," avertextxcoord ");

GL . enableverticalscribarray(vertexpositionattributes);

GL . enablevertexattribarray(vertexNormalAttribute);

GL . enablevertxattribarray(vertxtxcoordattribute);

令人惊讶的是,这段代码将帧速率一直提高到了 50 fps!跟踪中不再标记冗余,调用总数从 18,000 减少到 11,000。现在让我们看看我们可以推动这个应用显示多少个对象。增加渲染对象的数量,直到帧速率降低到 15 以下。去除冗余的完整代码在 09/optimized _ 1 _ removed _ redundances . html 文件中,输出如图图 9-24 所示。

9781430239963_Fig09-24.jpg

图 9-24 。每秒 16 帧的三千个物体

image **注意:**使用太多的缓冲液可能会导致错误的结果。对于 100,000 个对象,我获得了很高的帧速率,但是在 WebGL 检查器中查看后,只有 12,000 个 vbo,而不是应该有的 400,000 个。痕迹中也只有 33,000 行;我们需要至少 100,000 英镑来分别跟注。我们实际上没有 100,000 个对象的最大证据是 3,000 个对象的结果看起来与 100,000 个相同。

稍后在交错我的顶点属性后,我可以看到 20,000 个 vbo 和更完整的图像,如图 9-25 所示。

除了对 VBO 总数的限制之外,对每个 VBO 的元素数量也有限制。最大索引数是 2¹⁶ = 66536。

优化时,如果一个结果看起来好得不像真的,用你的直觉判断是否达到了浏览器的上限,或者结果是否被缓存在某个地方。

9781430239963_Fig09-25.jpg

图 9-25 。交错阵列出错。这些物体不是很圆

我们的下一个优化是将顶点位置、纹理坐标和法向数组交织成一个数组,这样我们就可以绘制更多的元素,因为我们为每个对象使用的缓冲区数量从 4 个减少到了 2 个(1 个缓冲区用于索引数组)。交错数组很好地清理了 drawScene 函数。清单 9-7 显示了我们使用交织数据的代码(生成的数据没有显示,但可以在 09/optimized _ 2 _ interleaved . html 文件中查看)并将其发送到 GPU。

清单 9-7。 交错数组属性指向

函数 drawScene()

{

for(var I = 0;I

setMvMatrix(球体位置[i])

setMatrixUniforms();

var active _ num = I % textures . length;

gl.activeTexture(gl)。纹理 0 + active_num:

GL . uniform 1 I(GL program . sampleruniform,active _ num);

bindBuffer(gl。ARRAY_BUFFER,triangles interleavedbuffers[I]);

gl . verticalpointer(vertexplicationattributes,3,GL)。浮点型,false,

8 * float 32 阵列。BYTES_PER_ELEMENT,0);

gl . verticalpointer(vertxnormplatform 属性,3,GL)。浮点型,false,

8 * float 32 阵列。每元素字节数,

3 *浮动 32 阵列。字节每元素);

gl . vertxtexcoordattribute,2,GL。浮点型,false,

8 * float 32 阵列。每元素字节数,

6 * float 32 阵列。字节每元素);

gl.drawElements(gl)。三角形,vertxinindexbuffer[I]。numItems(项目编号),

gl。UNSIGNED_SHORT,0);

}

}

现在,如果你输入了错误的步幅,比如 8 *而不是 8 * Float32Array。BYTES_PER_ELEMENT(总字节数)在前面的代码中,你会得到意想不到的结果,如图图 9-25 所示。

然而,使用正确的步幅值会产生如图 9-26 所示的预期结果。

9781430239963_Fig09-26.jpg

图 9-26 。交错阵列走向正确;10,000 个对象,但帧率较低

接下来,我们将把六个 256 x 256 的纹理合并成一个 512 x 512 的纹理图谱。你会记得纹理图谱图像之前在图 9-20 中显示过。使用纹理贴图集意味着我们不需要改变每个物体的活动纹理,我们永远不需要改变统一的采样值!

使用纹理地图最困难的部分是生成坐标。这对于每个内部图像的维度也是 2 的幂的纹理图谱来说实际上是相当容易的,尽管宽度和高度不必相等。我们跟踪每个图像的 x 和 y 偏移,以及图像长度相对于整体纹理的比例(从 0 到 1)图集尺寸,如下所示:

//x_offset,y_offset,x_scale,y_scale

var textureAtlasAreas = [

[0.0,0.0,0.5,0.5],//月亮

[0.5,0.0,0.5,0.5],//孙

[0.0,0.5,0.25,0.25],//土星

[0.0,0.75,0.25,0.25],//木星

[0.5,0.5,0.25,0.25],//地球

[0.5,0.75,0.25,0.25]//火星

];

然后,当我们设置我们的球体数据时,我们可以像这样访问这些信息:

var num _ textures = textureatlasareas . length;

for(var I = 0;I

var active _ num = i % num _ textures

var tex _ start _ x = texture atlasareas[active _ num][0],

tex _ start _ y = texture atlasareas[active _ num][1],

tex _ scale _ x = texture atlasareas[active _ num][2],

tex _ scale _ y = texture atlasareas[active _ num][3];

//纹理坐标

interleaveddata . push(u * tex _ scale _ x+tex _ start _ x);

interleaveddata . push(v * tex _ scale _ y+tex _ start _ y);

}

image 注意纹理图谱的一个潜在缺点是纹理边界可能会有颜色渗色。

我们将通过调用 gl.generateMipmap(gl。质感 _ 2D);我们要做的最后一个优化,也是最重要的一个优化是批量抽取调用。

当我们在示例的 setupSphereData 方法中生成网格,然后在 drawScene 方法中使用批的数量时,我们将执行批和每批球体的双循环,而不是循环通过我们要绘制的所有球体。

然而,我们现在至少面临一个问题。之前,我们更改了每个球体对象的模型视图矩阵。然而,现在我们将几个对象绘制批处理在一起,并且仍然每批只调整一次模型视图矩阵。这意味着一批中的每个球体都将在同一位置绘制。我们将只看到每批中最大的球体,较小的球体将隐藏在其中。例如,一次将 10,000 个球体批处理为 40 个,我们将渲染所有 10,000 个球体,但只看到 250 个。我们需要能够设置每个球体的模型视图。我们也不想不必要地更新制服。我们可以将这种计算转移到 GPU,而不是在 JavaScript 中为每个对象计算模型视图。这实际上是一种性能提升,因为 GPU 速度快得多。我们还必须在每次绘制时更新一次平移和旋转量的统一值,而不是针对每个对象。我们计算每个对象模型视图矩阵的原始 JavaScript 代码如清单 9-8 所示。

清单 9-8。 JavaScript 代码用于计算每个对象模型的视图矩阵值

函数集矩阵

{

mat 4 . identity(mv matrix);

mat4.identity(法线矩阵);

mat4.translate(mvMatrix,[sp.x_offset,sp.y_offset,sp . z _ offset]);

mat4.rotate(mvMatrix,sp.angle,[sp.x_angle,sp.y_angle,sp . z _ angle]);

mat4 .反向(mvMatrix,法向矩阵);

sp . x _ angle+= math . random();

sp . y _ angle+= math . random();

sp . z _ angle+= math . random();

sp . x _ offset =(math . cos(sp . angle)* sp . x _ offset _ orig);

sp . y _ offset =(math . sin(sp . angle)* sp . y _ offset _ orig);

sp . z _ offset =-25.0+12.0 * math . sin(sp . angle);

sp . angle+= 0.005;

}

我们可以创建统一的变量来存储这些值,并在我们的顶点着色器中使用它们,而不是重新计算在所有球体中保持不变的余弦和正弦值:

均匀浮动 uCosTime

统一浮动使用时间;

我们现在也将只计算一次球体几何图形,并将其存储,如清单 9-9 所示。

清单 9-9。 计算单位球面上的点

var unit _ sphere = null

函数 calculateUnitSpherePoints(纬度带,经度带)

{

//O(n²)三角运算-代价高昂!

unit_sphere = {

【顶点】:[],

"紫外线":[]

};

的(订单编号= 0;纬度,经度++)

var theta = latNumber * Math。PI/latitude bands;

var sinet = math . sin(theta):

var cosTheta = math . cos(theta);

for(var long number = 0;longNumber < = longitudeBandslongNumber++) {

var phi = longNumber * 2 * Math。PI/longitude bands;

var sinphi = math . sin(phi);

var cos phi = math . cos(phi);

var x = cosPhi * sinTheta

var y = cosTheta

var z = sinPhi *语法;

var u = 1-(long number/longitude bands);

其中 v =分数字/纬度带;

//位置

unit _ sphere . vertices . push({ " x ":x," y": y," z ":z });

//纹理坐标

unit_sphere.uvs.push({"u": u," v ":v });

}

}

}

我们可以使用存储的坐标来生成场景中的所有其他球体:

//位置

interleaveddata . push(radius * vertex . x+spherePositions[mesh _ number])。x _ offset _ orig);

interleaveddata . push(radius * vertex . y+spherePositions[mesh _ number])。y _ offset _ orig);

interleaveddata . push(radius * vertex . z+spherePositions[mesh _ number])。z _ offset _ orig);

//正常

interleaveddata . push(vertex . x);

interleaveddata . push(vertex . y);

interleaveddata . push(vertex . z);

//纹理坐标

interleaveddata . push(uv . u * tex _ scale _ x+tex _ start _ x);

interleaveddata . push(uv . v * tex _ scale _ y+tex _ start _ y);

这允许我们不改变 MVP 矩阵,也不需要在生成后使用 spherePositions 数组数据。我们现在可以用清单 9-10 中的代码批量绘制我们的对象。

清单 9-10。 批量绘制我们的对象

var num _ spheres = 15000

var num _ per _ batch = 250

var batches = num _ spheres/num _ per _ batch;

函数 drawScene()

{

GL . uniform 1 f(GL program . costime uniform,math . cos(current time));

GL . uniform 1f(GL program . sin time uniform,math . sin(current time));

for(var I = 0;I

bindBuffer(gl。ARRAY_BUFFER,triangles interleavedbuffers[I]);

gl . verticalpointer(vertexplicationattributes,3,GL)。浮点型,false,

8 * float 32 阵列。BYTES_PER_ELEMENT,0);

gl . verticalpointer(vertxnormplatform 属性,3,GL)。浮点型,false,

8 * float 32 阵列。每元素字节数,

3 *浮动 32 阵列。字节每元素);

gl . vertxtexcoordattribute,2,GL。浮点型,false,

8 * float 32 阵列。每元素字节数,

6 * float 32 阵列。字节每元素);

gl.drawElements(gl)。三角形,vertxinindexbuffer[I]。numItems(项目编号),

gl。UNSIGNED_SHORT,0);

}

current time+= 0.01;

}

由于我们受限于单个 VBO 可以有多大,我们将使用 10 个分区的球体(每个球体 600 个索引)而不是 30 个分区(每个球体 5400 个索引)来演示批处理的加速。一次渲染 15,000 个这样的球体会产生 3 fps 的效果。渲染 15,000 但一次批处理 250 会产生更好的 45 fps,如图 9-27 所示。

9781430239963_Fig09-27.jpg

图 9-27 。左图:批量大小为 1 以 3 fps 渲染;右图:-批量大小为 250 以 47 fps 渲染

摘要

本章讨论了如何调试 WebGL 应用并提高性能。这是两个重要的主题,将有利于您的 WebGL 开发和用户对您的应用的享受。一个以 3 fps 爬行的复杂场景和一个以 40 fps 移动的场景之间的差别是显著的,这可能是用户喜欢你的应用还是放弃它的差别。WebGL 可能很难调试,因为有许多因素在起作用:特定的浏览器、计算机和使用的 GPUJavaScript API 着色器程序;以及纹理等资源。其中每一个都可能是误差的来源。幸运的是,有强大的工具可以帮助我们,从我们使用的 IDE 到浏览器开发工具,以及使用 WebGL inspector。

在下一章,也是最后一章,我们将介绍各种各样的效果、技巧和窍门——图像处理、非真实感着色器,以及使用 framebuffer 对象来确定我们场景中的哪个元素当前被鼠标选中并实现阴影贴图。

十、效果、提示和技巧

在本章中,我们将介绍各种 WebGL 效果、提示和技巧,例如:

  • 基本图像处理
  • 使用卷积滤波器的图像处理
  • 反混淆
  • 非真实感着色器
  • 帧缓冲和渲染缓冲
  • 从画布中拾取对象
  • 阴影贴图实现

效果

通过图像处理和卷积滤波器可以实现各种各样的效果,如锐化、模糊、灰度、棕褐色调、颜色调整和边缘检测。

为了应用这些效果,我们将从加载纹理图像开始。然后,我们将在片段着色器中改变纹理中每个像素的原始颜色值。对于这些例子,设置类似于第六章中的一些例子,其中算法被用于纯粹在片段着色器中创建图像。这一次,我们有一个开始改变纹理图像。实际上,纹理图像可能来自 HTMLVideoElement 对象,因此我们可以使用这些相同的技术动态地改变视频流。我们将专注于静态图像处理。

基本图像操作

我们的第一个图像处理示例 将显示灰度、反转颜色值和原始纹理图像旁边的绿色图像。为此,我们首先设置一些效果常数和一个变量来存储一个统一的值,该值将通知我们的着色器使用哪个效果:

var NO_EFFECT = 0,

灰度 _ 效果= 1,

负 _ 效= 2,

GREEN _ TINT _ EFFECT = 3;

var effectUniform = null;

当我们渲染到画布上时,我们将实际绘制场景四次,每次使用四分之一的视口并改变效果。效果图如图图 10-1 所示。不幸的是,很难看出黑白印刷有什么不同,所以请访问网站【www.beginningwebgl.com/ 获得全彩色版本。

9781430239963_Fig10-01.jpg

图 10-1 。左上:原图;右上:灰度;右下:反转颜色;左下角:颜色更绿

调整视口和重新渲染可以让我们很容易地一次看到几个变化,这是在同一个场景中使用多个视口的应用,如第一章中所讨论的。视窗设置的代码如清单 10-1 所示。其中,我们在视口的不同区域绘制了四次,并通过更改统一值通知片段着色器每次应用哪个效果。

清单 10-1 。 为视口设置的代码

。。。

//左上角

gl.uniform1i(effectUniform,NO _ EFFECT);

gl.viewport(0,canvas.height/2.0, canvas.height/2.0, canvas . height/2.0);

draw scene();

//左下角

gl.uniform1i(effectUniform,GREEN _ TINT _ EFFECT);

gl.viewport(0,0,canvas.height/2.0,画布.高度/2.0);

draw scene();

//右上角

gl.uniform1i(effectUniform,gray _ EFFECT);

gl.viewport(canvas.height/2.0,0,canvas.height/2.0, canvas . height/2.0);

draw scene();

//右下角

gl.uniform1i(effectUniform,NEGATIVE _ EFFECT);

gl.viewport(canvas.height/2.0,canvas.height/2.0, canvas.height/2.0, canvas . height/2.0);

draw scene();

。。。

完整的代码可以在 10/01_image_processing.html 文件中找到。顶点着色器非常简单,只将原始的 x 和 y 坐标传递给片段着色器:

十一、后记

image

WebGL 的未来

WebGL 的未来会怎样?在这篇后记中,我们将讨论 WebGL 的优点和一些问题,并对它的未来进行推测。

为了让 WebGL 有一个光明的未来,而不是像其他过去的 3D 浏览器尝试(如虚拟现实标记语言(VRML))一样失败,它需要以下几点:

  • 支持
  • 来自开发社区的采用,尤其是游戏开发者
  • 改进和积极发展

支持

这里我们将看看来自浏览器和设备的支持。

浏览器支持

正如书简介中提到的,Chrome 和 Firefox 在支持 WebGL 方面做得非常好。Safari 和 Opera 正在改进,IE 近期没有原生支持 WebGL 的计划。虽然五年前这可能是一场灾难,但 IE 并没有获得它曾经享有的市场份额——Chrome 已经超过了它,Firefox 也紧随其后。

移动设备支持

目前支持 WebGL 的移动设备数量很少,但随着每一款新设备的发布,这一水平将会提高,到 2013 年,这一水平将会大大提高。

目前,有几种支持 WebGL 的移动浏览器:Firefox Mobile、Android 浏览器、Opera Mobile(仅限 Android)、BlackBerry Playbook 和 iOS Mobile Safari(目前仅支持 iAd)。

移动市场份额正在增长,是一个重要的发展领域。由于 Adobe 最近宣布将停止对移动 Flash 的支持,WebGL 有了一个更好的机会来确立自己作为移动 3D 首选技术的地位。

Florian Boesch 的网站webglstats.com/有一些非常有趣的统计数据,关于跨浏览器、设备和操作系统的各种 WebGL 指标的当前支持。

收养

正如本书中提到的,Google 已经将 WebGL 用于其身体、地图和地球应用。

我们在第九章中展示了 Firefox 正在使用 WebGL 对文档对象模型(DOM)进行新的 3D 调试可视化。获得知名公司的支持和使用是很重要的,谷歌、Mozilla、苹果和 Opera 都提供了支持。同样重要的是,要有写得好的框架来降低 3D 编码的门槛。Three.js 这样的框架已经很容易使用了,并且会继续变得更好。

WebGL 有何优势

  • 不需要插件。

  • The timing is right. 3D in the browser is more useful now than back when VRML tried. GPUs are more powerful. WebGL is part of the larger movement of HTML5 and related technologies, which adds many browser enhancements which are making it possible to create applications previously only possible on the desktop.

    “几十年来,网络一直在通过吸管吸取这种能力,但有了 WebGL,当谈到图形处理能力时,就好像吸管被消防水管取代了一样。。."www . tnl . net/blog/2011/10/23/web GL-and-the-future-of-the-web/

  • Web 应用没有平台兼容性问题,也不需要安装。

  • WebGL 框架使得开始使用 WebGL 变得越来越容易。

  • 对于有经验的图形程序员来说,在底层调整 WebGL 的能力是非常有用的。

  • 许多令人敬畏的演示。

  • 规范的透明开发。

  • 经验和现有开发人员。Khronos 还负责 OpenGL 和 Collada。有许多当前的 OpenGL 和 OpenGL ES 开发人员可以相当容易地学会/过渡到 WebGL API。

关系

WebGL 功能强大,非常有前途。然而,它是一种相对较新的语言,存在一些问题,包括:

  • 缺少微软的支持。如前所述,这并不像微软统治浏览器市场时那么重要。究竟是出于安全考虑还是出于对自身 DirectX 技术的兴趣而不支持 WebGL,只有微软能说得准。
  • 安全问题。 GPU 黑名单和安全性更高的新型显卡将有助于解决 GPU 问题。跨来源资源共享等其他网络安全措施将在保持安全性的同时实现灵活性。
  • Flash 或其他用于 3D 的技术。如上所述,Flash 停止移动支持有助于缓解这种担忧。
  • JavaScript 的性能问题。JavaScript 很慢。已经进行了改进,例如类型化数组,并且正在研究更多的优化。
  • 游戏开发者需要加入进来。现在将详述这一点。

游戏开发商

Florian Boesch 在 http://code flow . org/entries/2011/sep/11/webgl-and-html 5-challenges-for-the-future/的一篇出色的博客文章解释了 web GL 如何需要游戏开发者采用它。在条目中,列出了游戏开发人员需要的几个功能,其中与 WebGL 相关的功能特别多:多个渲染目标、几何实例化、顶点着色器中的纹理查找以及浮点纹理。目前浏览器对这些功能的支持可以在这里提到的 webglstats.com 链接中找到。

积极发展

WebGL 规范、未来扩展和浏览器实现都在积极开发中。

扩展

WebGL 语言的核心扩展正在开发中,可以在 www.khronos.org/registry/we…:

  • 各向异性过滤,提高以倾斜角度观看的纹理质量
  • 阴影贴图的深度纹理
  • 压缩纹理

可能很快添加的未来功能包括:

  • 更多扩展,如跨上下文共享或多个呈现目标。

  • web workers 中的多线程。这将允许上传纹理和数据,而不会阻塞主线程。

  • 异步上下文创建和上下文之间的资源共享。

最后一句话

技术领域没有什么是确定的,但我坚信 WebGL 会一直存在下去——否则我不会花时间和精力写这本书。WebGL 是一项非常有前途的技术,它的开发恰逢其时,因为浏览器正处于快速发布周期,并且每天都在支持更多的高级功能。这也是一个越来越多功能强大的计算机被塞进任何地方的移动设备的时代。WebGL 已经是一项非常有用的技术。框架改进将有助于降低新开发人员的门槛,更多的调试和实用工具将被创建,性能将继续提高。

十二、附录 A:基本 HTML5 和 JavaScript

有许多改进和特性是 HTML5 的一部分或与之相关:地理定位、新的输入类型、表单验证、本地存储和 web 套接字(仅举几例)。涵盖所有新的内容既不可行,也不值得在这里讨论——最近有大量书籍深入探讨了这一问题。

基本 HTML5

虽然您不需要了解 HTML5 的所有新的和伟大的内容,但为了最大限度地加深您对代码示例的理解,我们将展示您需要了解的与 HTML 4 的相关差异。

简洁

首先,HTML5 通过标准化开始标记和对脚本和样式的简化,允许更紧凑地编写文档。在 HTML 4 中,你可能会有类似下面的代码列出 A-1 :

清单 A-1 。 一个极简的 HTML 4 文档

例子

十三、附录 B:图形刷新程序

本书假设读者对 3D 图形有一个基本的了解,但是我们将在本附录中刷新一些相关主题的记忆。

像素

当我们在计算机屏幕上以数字方式呈现一幅图像时,它是由一个矩形网格组成的,这个网格由称为像素的单个颜色点组成。这种类型的表示被称为光栅图形位图 。显示图像的真实程度取决于屏幕上的像素数量:分辨率。在图 B-1 中,我们在左边显示了一个输入图像,在中间显示了一个 4 × 4 像素的网格表示,在右边显示了一个 16 × 16 的网格表示。随着分辨率的增加,原始图像与渲染图像之间的差异会减小。

9781430239963_AppB-01.jpg

图 B-1 。左图:输入图像;中心:4 × 4 像素输出;右图:16 × 16 像素输出

基元

图形元素是我们可以用来组成图像和场景的最小构建模块。我们可用的图元取决于所使用的语言,可以是点、线、多边形(如三角形和四边形)或一些高级语言中的立体形状。

彩色

颜色有几个属性,包括色调(色调)、饱和度(暗度)和值(强度)。事实上,颜色可以由色调-饱和度-值(HSV)颜色模型中的这三个属性来表示。然而,呈现颜色的方式不止一种,这取决于我们使用的是加色理论还是减色理论,以及诸如打印图像或在屏幕上显示图像等应用用途。

当我们打印图像时,通常使用减色法 CMYK 模式,它有四个通道,由青色、洋红色、黄色和暗度(K)组成。这就是为什么有些打印机有彩色 CMY 墨盒和黑色墨盒。

在计算机显示器上,颜色值通常使用加色 RGBA 方案来表示,该方案有四个通道,包括红色、绿色、蓝色和 Alpha(透明度)值。每个通道值的范围可以是 0.0 至 1.0 的浮点值、0 至 255 的整数值或 0×000000 至 0×ffffff 的十六进制值。

为了从 CMY 转换到 RGB,我们采用[(1.0,1.0,1.0)-CMY]。所以黄色在 CMY 是(0.0,0.0,1.0),在 RGB 是(1.0,1.0,0.0)。在本书中,我们将专门使用 RGB(A)颜色模型。

image 更多关于 RGBA 彩色格式的信息可以在维基百科上的en.wikipedia.org/wiki/RGBA_color_space找到。

坐标系统

笛卡尔坐标系 以数学家、哲学家和作家勒内·笛卡尔的名字命名,在二维中使用(x,y)对,在三维中使用(x,y,z)三元组。原点是所有轴的交点。在二维中,这是(0,0),在三维中是(0,0,0)。对于每个轴,原点一侧的值增加,另一侧的值减少。有两个独立的三维坐标系方向,如图图 B-2 所示。它们之间的区别是相对于 x 和 y 轴的 z 方向。

9781430239963_AppB-02.jpg

图 B-2 。两种不同的 3D 坐标系方向

变换

初等变换或仿射变换会改变图形的顶点。有三种基本变换:平移、旋转和缩放,如图图 B-3 所示。

9781430239963_AppB-03.jpg

图 B-3 。平移(左)、旋转(中)和缩放(右)的变换

图 B-4 中显示了向右移动 3 个位置和向上移动 2 个位置的着色区域的平移。

9781430239963_AppB-04.jpg

图 B-4 。翻译一张图片

图像子区域围绕其中心像素顺时针旋转 90 度,如图 B-5 所示。

9781430239963_AppB-05.jpg

图 B-5 。图像的旋转

在图 B-6 中显示了两倍于已着色子区域原始尺寸的缩放比例。

9781430239963_AppB-06.jpg

图 B-6 。图像的缩放

图形编程使用了大量的数学知识,尽管库可以抽象掉大量的计算,但是了解一些基本知识还是很有好处的。

数学

我们首先应该知道的是角度、度数、圆周率和弧度。

角度

两条光线相交形成一个角度,如图 B-7 左侧所示。从技术上来说,角度是两条射线的弧长与圆内接半径的商的度量,如图 B-7 右侧所示。圆有 360 度,所以角度有时用度来度量。

9781430239963_AppB-07.jpg

图 B-7 。左图:形成内角的两条射线;右:圆内的角度

圆周率

用π表示的常数π大约是 3.14159,它是圆的周长与直径的比值。圆周率广泛应用于三角学、几何学和其他数学分支。

弧度

除了度,我们还有弧度,它被定义为 360 度= 2π弧度。这意味着 1 弧度约为 57.3 度。图 B-8 ,显示了各种角度和四个象限直角的弧度值。角度 A 看起来大约是 45 度,E 大约是 150 度,这使得角度 B 大约是 30 度。角度 D 看起来是-60 度,这将使角度 C 大约为 30 度。

9781430239963_AppB-08.jpg

图 B-8 。各种旋转角度

三角形的角和边的关系是在称为三角学的数学分支中研究的。

三角学

对于直角三角形(一个角正好是 90 度)和三角形中的另一个角 q,我们可以知道边长的比值。图 B-9 显示了直角的斜边(直角的对边)、对边和邻边。

9781430239963_AppB-09.jpg

图 B-9 。直角三角形的边

给定这些边和角度 q,我们可以用边来表示角度如下:

sin θ =对边/斜边

cos θ =邻边/斜边

tan θ =相对/相邻

这些关系常被记忆为 *soh、cah、*和 toa ,它们是关系名和边的首字母缩写。

旋转

在二维中,旋转使用旋转矩阵:

[什么-Sina][x]=[xcosa-ysina]

[sinA 什么] [y] = [xsinA + ycosA]

我们可以用这些方程来计算旋转 A 度后新的 x,y 坐标。

矢量

有了坐标为(x 1 ,y 1 ,z 1 ),(x 2 ,y 2 ,z 2 的两个点,我们现在将定义一些有用的计算。

点积

点积通过返回两个输入向量按分量相乘的和来返回标量值:

x1* x2+y1* y2+y1* z2

交叉乘积

叉积 (x,y,z)返回一个垂直于由两个输入向量形成的平面的向量。因此,我们用它来寻找法向量。叉积的计算方法如下:

x = y1z2–y2 z1

y =-x1* z2+x2* z1

z = x1* y2-x2* y1

长度

两点之间的长度可以计算为每个分量差的平方和的平方根:

平方根((x1-x2)2+(y1-y2)2+(z1-z2)2)

十四、附录 C:WebGL 规格和零碎事项

本附录包含我们提到过但未完全涵盖的规范的某些部分,在此列出以供参考。

webcl 上下文属性

当我们获得我们的 WebGL 上下文时,我们可以有选择地向它传递一个包含以下部分或全部属性的对象:

字典 WebGLContextAttributes {

布尔 alpha =真;

布尔深度= true

布尔模具=假;

boolean 抗锯齿= true

boolean premultiplied alpha = true;

boolean preserveDrawingBuffer = false;

};

我们展示了如何在一个第五章的投射实例中保存绘图缓冲区:

GL = canvas . get context(" webgl " { preserve drawing buffer:true })| |)

canvas . get context(" experimental-web GL ",{ preserveDrawingBuffer:true });

通过保留缓冲区内容而不是自动交换缓冲区,我们可以看到物体运动的轨迹,还可以产生运动模糊等效果。如果性能是关键,并且我们不需要 alpha 或深度测试,我们可以禁用这些属性。如果我们需要模板缓冲区,我们可以启用它。我们在第十章中展示了如何禁用抗锯齿。premultipliedAlpha 值影响画布的 Alpha 组件如何影响图像的整体颜色。将该值设置为 false 会使画布元素的 WebGL 颜色计算与 2D 上下文相同。

纹理属性

在第三章中,我们忽略了一些纹理选项。

立方体贴图目标

对于立方体贴图纹理,目标属性可以是以下之一:

纹理立方体贴图,纹理绑定立方体贴图,

纹理 _ 立方体 _ 贴图 _ 正 X,纹理 _ 立方体 _ 贴图 _ 负 X,

纹理 _ 立方体 _ 贴图 _ 正 _Y,纹理 _ 立方体 _ 贴图 _ 负 _Y,

纹理 _ 立方体 _ 贴图 _ 正 Z,纹理 _ 立方体 _ 贴图 _ 负 Z,

最大立方体贴图纹理大小

泰晤士河 2D

纹理的格式如下:

阿尔法:阿尔法

RGB: R、g、b 颜色

RGBA:红、绿、蓝颜色和阿尔法

亮度:亮度

亮度 _ALPHA:亮度,ALPHA

这些类型可以是:

无符号字节

无符号 _ 短整型 _4_4_4_4

UNSIGNED _ SHORT _ 5 _ 5 _ 5

无符号 _SHORT_5_6_5

以下组合是合法的:

无符号字节/ RGBA,RGB,亮度,亮度阿尔法

UNSIGNED_SHORT_4_4_4_4 / RGBA

UNSIGNED_SHORT_5_5_5_1 / RGBA

UNSIGNED_SHORT_5_6_5 / RGB

帧缓冲区和渲染缓冲区目标和附件

在第十章中,我们介绍了帧缓冲区和渲染缓冲区 。其他合法附件/格式组合如下:

深度 _ 附件/深度 _ 组件 _16

模板 _ 附件/模板 _ 索引 8

深度 _ 模板 _ 附件/深度 _ 模板

颜色附件:COLOR_ATTACHMENT0

附加格式:RGBA、RGBA4、RGB5_A1、RGB565、STENCIL_INDEX

以下并发附件组合是非法的:

深度 _ 附件/深度 _ 模板 _ 附件

模板 _ 附件/深度 _ 模板 _ 附件

深度 _ 附件/模板 _ 附件

十五、附录 D:额外资源

WebGL 是一个新兴的技术,有很多方面。我尽了最大努力在本附录中汇编了良好的补充学习资源。

伙伴网站

您可以在以下地址找到本书的配套网站 :

开始 WebGL

www.beginningwebgl.com/

github page(github 页)

github . com/bdancilla/begin ningtwebgl

由于网络的不稳定性,很快会产生死链、过时的资源或涌现的新资源,请参考配套网站,了解本附录中列出的资源的最新版本。

主题

这里列出了本书中提到的许多技术的更多资源(按字母顺序排列)。

Ajax

XMLHttpRequest 规范

www.w3.org/TR/XMLHttpRequest/

Mozilla XMLHttpRequest 页面

developer . Mozilla . org/En/XMLHttpRequest/Using _ XMLHttpRequest

调试

Khronos 调试 wiki 页

www.khronos.org/webgl/wiki/Debugging

WebGL 检查器

benvanik . github . com/webgl-inspector/

我们给了

尖端的 Chrome WebGL 实验

www.chromeexperiments.com/webgl

Khronos 演示资源库

www.khronos.org/webgl/wiki/Demo_Repository

不错的水演示

madebyevan.com/webgl-water/

HTML

HTML 5 和 4 的区别

www . w3 . org/tr/html 5-diff/

画布元素

www.w3.org/TR/html5/the-canvas-element.html

JavaScript〔??〕〔??〕

道格拉斯·克洛克福特网站

javascript.crockford.com/

框架

jquery.com/

数据

www.json.org/

灯,MAMP ,WAMPT3

马姆普

www.mamp.info/en/index.html

XAMPP(洗发精)

www.apachefriends.org/en/index.html

EasyPHP

www.easyphp.org/

比特南

bitnami.org/

欧佩克

sourceforge.net/projects/opew/

浏览器设置调整

github . com/mrdoob/three . js/wiki/How-to-run-things-locally

库和框架

框架列表

www . khronos . org/webgl/wiki/user _ contributions

GLGE

项目页面

www.glge.org

辅导的

www . rozengain . com/blog/2010/06/23/hands-on-web GL-basic-glge-tutorial/

菲洛勒

项目页面

www.senchalabs.org/philogl/

资源

www . slide share . net/Philo GB/leaving-flatland-getting-started-with-web GL-sxsw-2012

三个。JS

项目页面

mrdoob . github . com/3 . js/

文件

mrdoob.github.com/three.js/docs/latest/

维基网

github . com/mrdoob/3 . js/wiki

学习资源:Paul Lewis

aerotwist.com/tutorials/

学习资源:Jerome Etienne

learninthreejs . com/

整体物体的漂亮图表

ushiroad.com/3j/

www.12devsofxmas.co.uk/2012/01/webgl-and-three-js/

照明

直接照明模型

www . lighthouse 3d . com/tutorials/glsl-tutorial/directional-lights-ii/

www.ozone3d.net/tutorials/glsl_lighting_phong_p3.php

Phong 反射模型

en.wikipedia.org/wiki/Phong_reflection_model

图 3-13 是 http://en . Wikipedia . org/wiki/File:Phong _ components _ version _ 4 . png 的变体,它在 GNU 自由文档许可证下获得许可

全局照明模型

http . developer . NVIDIA . com/gpugems 2/gpugems 2 _ chapter 38 . html

环境遮挡

http . download . NVIDIA . com/developer/GPU _ Gems _ 2/GPU _ Gems 2 _ ch14 . pdf

en.wikipedia.org/wiki/Screen_Space_Ambient_Occlusion

www . game rendering . com/category/lighting/ssao-lighting/

反射和折射

http . developer . NVIDIA . com/gpugems 3/gpugems 3 _ ch17 . html

http . developer . NVIDIA . com/gpugems 2/gpugems 2 _ chapter 19 . html

阴影映射

fabiensangard . net/shadow mapping/index . PHP

数学

Wolfram Mathworld(黑钨矿)

mathworld.wolfram.com

分形

users.erols.com/ziring/mandel.html

66.39.71.195/Derbyshire/manguide.html

davis.wpi.edu/∼matt/courses/fractals/index.htm

www.fractalforums.com/

矩阵和向量库

gl-matrix.js

github.com/toji/gl 矩阵

西尔威斯特

sylvester.jcoglan.com/

webgl mj

code . Google . com/p/webgl-mj/

基准

stepheneb . github . com/web GL-matrix-benchmarks/matrix _ benchmark . html

网格文件格式

波前(obj)格式

en . Wikipedia . org/wiki/wave front _ obj

格式化整理

en . Wikipedia . org/wiki/collada

Three.js 内部 JSON 格式

github . com/mrdoob/three . js/wiki/JSON-Model-format-3.0

性能和最佳实践

Mozilla 开发者网络最佳实践

developer.mozilla.org/en/WebGL/WebGL_best_practices

Gregg Tavares 谷歌 I/O 2011

www . YouTube . com/watch?v=rfQ8rKGTVlg

games . greggman . com/game/web GL-techniques-and-performance/

static . Google user content . com/external _ content/untrusted _ dlcp/www . Google . com/en//events/io/2011/static/notes files/webgltechnizandperformancenotes . pdf

使用关于进行分析:跟踪

www.html5rocks.com/en/tutorials/games/abouttracing/

物理

学问

www.physicsclassroom.com

WebGL 演示

www.ibiblio.org/e-notes/webgl/gpu/contents.htm

Javascript 库:

2D 港口

code.google.com/p/box2dweb/

github . com/kri pke/box 2d . js

子弹港

github . com/kri pke/ammo . js/

大炮

github . com/text PPE/cannon . js

物理学家

chanderprall . github . com/physij/

教程

creative js . com/2011/09/box2d-JavaScript-tutorial-series-by-Seth-ladd/

learning three js . com/blog/2012/06/05/3d-physics-with-three-js-and-physijs/

www . html 5 gamedevs . com/2012/01/18/web GL-bullet-js-experiences-history-programming-slides/

WebGL

当前浏览器支持

caniuse . com/# search = webgl

Khronos 集团维基

www . khronos . org/webgl/wiki/main _ page

www . khronos . org/web GL/wiki/Tutorial # Creating _ the _ Shaders

WebGL 规范

www.khronos.org/registry/webgl/specs/latest/

学习 WebGL

learningwebgl.com/blog/

Mozilla 开发人员区域

developer . Mozilla . org/en/webgl

Opera 开发者区

dev . opera . com/articles/view/porting-3d-graphics-to-the-web-web GL-intro-part-2/

参考卡

www . khronos . org/files/web GL/web GL-reference-card-1 _ 0 . pdf

报告

www.khronos.org/webgl/wiki/Presentations

教程

www.html5rocks.com/en/features/graphics

混合

mrdoob . com/lab/JavaScript/web GL/blending/blend func . html

WebGL 未来

挑战和预测

www.irrlicht3d.org/pivot/entry.php?id=1255

code flow . org/entries/2011/sep/11/web GL-and-html 5-挑战未来/

www . tnl . net/blog/2011/10/23/web GL-and-the-future-of-the-web/

支持统计

www.riastats.com/

weblstat . com/

扩展注册表

www.khronos.org/registry/webgl/extensions/

WebGL SL (OpenGL 是 SL)

OpenGL ES 2.0 着色语言版本 1.0

www . khronos . org/registry/gles/specs/2.0/GLSL _ ES _ Specification _ 1 . 0 . 17 . pdf

提供 WebGL 快速参考卡

www . khronos . org/files/web GL/web GL-reference-card-1 _ 0 . pdf

在线 GLSL 编辑

weblplayground . net/

spidergl.org/meshade/

www . kickjs . org/example/shader _ editor/shader _ editor . html

现有着色器

code . Google . com/p/GL slang-library/source/browse/trunk/trunk/GL slang/shaders/material/