WebGL入门指南

978-7-115-31668-4
作者: 【美】Tony Parisi
译者: 郝稼力
编辑: 杨海玲

图书目录:

详情

本书从WebGL和3D图形学的基础概念讲起,循序渐进,用多个简单的实例直观地讲解了各个知识点,包括从坐标系统到投影矩阵这些数学基础,也包括从纹理贴图到模型动画这些图形效果;随后理论结合实际介绍了在现实开发环境中需要注意的各种问题;最后作者把全书所有讲过的知识综合到一起,制作了一个完整的WebGL游戏,让读者能够基本了解WebGL这一新技术的开发流程,以便读者可以独立开发自己的WebGL应用。

图书摘要

版权信息

书名:WebGL入门指南

ISBN:978-7-115-31668-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著     [美] Tony Parisi

译    郝稼力

责任编辑 杨海玲

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


Copyright ©2012 by O’Reilly Media, Inc.

Simplified Chinese Edition, jointly published by O’Reilly Media, Inc. and Posts & Telecom Press, 2013. Authorized translation of the English edition, 2013 O’Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体版由 O’Reilly Media, Inc.授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


WebGL是一项新的Web 3D图形标准,也是HTML5大家庭中的一员。本书从WebGL和3D图形学的基础概念讲起,循序渐进,用多个简单的实例直观地讲解了各个知识点,包括从坐标系统到投影矩阵这些数学基础,也包括从纹理贴图到模型动画这些图形效果;随后又理论结合实际,介绍了在现实开发环境中需要注意的各种问题,例如,如何挑选WebGL框架以及使用哪种3D内容交换格式;在最后一章,作者把全书所有讲过的知识综合到一起,制作了一个完整的WebGL游戏,让读者能够基本了解WebGL这一新技术的开发流程,以便读者可以独立开发自己的WebGL应用。

除此之外,在多个实例中作者还应用了一些非常便捷有效的图形开发技巧,这些脱胎于作者多年图形经验的小技巧可以节省很多工作量,也让初入图形学门槛的读者可以眼前一亮,领会到图形开发的美妙和乐趣。

本书适合Web开发人员阅读,尤其是对3D开发感兴趣的读者。


O’Reilly Media通过图书、杂志、在线服务、调查研究和会议等方式传播创新知识。自1978年开始,O’Reilly一直都是前沿发展的见证者和推动者。超级极客们正在开创着未来,而我们关注真正重要的技术趋势——通过放大那些“细微的信号”来刺激社会对新科技的应用。作为技术社区中活跃的参与者,O’Reilly的发展充满了对创新的倡导、创造和发扬光大。

O’Reilly为软件开发人员带来革命性的“动物书”;创建第一个商业网站(GNN);组织了影响深远的开放源代码峰会,以至于开源软件运动以此命名;创立了《Make》杂志,从而成为DIY革命的主要先锋;公司一如既往地通过多种形式缔结信息与人的纽带。O’Reilly的会议和峰会集聚了众多超级极客和高瞻远瞩的商业领袖,共同描绘出开创新产业的革命性思想。作为技术人士获取信息的选择,O’Reilly现在还将先锋专家的知识传递给普通的计算机用户。无论是通过书籍出版、在线服务或者面授课程,每一项O’Reilly的产品都反映了公司不可动摇的理念——信息是激发创新的力量。

“O’Reilly Radar博客有口皆碑。”

      ——Wired

“O’Reilly凭借一系列(真希望当初我也想到了)非凡想法建立了数百万美元的业务。”

      ——Business 2.0

“O’Reilly Conference是聚集关键思想领袖的绝对典范。”

      ——CRN

“一本O’Reilly的书就代表一个有用、有前途、需要学习的主题。”

      ——Irish Times

“Tim是位特立独行的商人,他不光放眼于最长远、最广阔的视野并且切实地按照Yogi Berra的建议去做了:‘如果你在路上遇到岔路口,走小路(岔路)。’回顾过去Tim似乎每一次都选择了小路,而且有几次都是一闪即逝的机会,尽管大路也不错。”

      ——Linux Journal


自从互联网诞生以来,如何让网页变得更绚丽、更美观一直是人们在不断追求的目标。为了达到这个目的,我们发明了HTML标记语言来确定网页的结构,发明了CSS层叠式样式表来规范网页的外观,发明了JavaScript来实现各种特效,发明了Flash等插件来嵌入视频和动画效果。但是直到WebGL技术的出现,人们才得以从计算机图形学这一学术根基上解决了这一问题。由于直接和GPU交互,如果愿意的话,设计师可以用WebGL精确控制网页中的每一个像素。这是之前所有的技术都无法企及的高度。

WebGL技术诞生的年代正是Web 2.0时代的后期,人们正在急切地寻找下一代互联网应当前进的方向。HTML5被业界认为是合理的答案之一。使用了Canvas的WebGL正好贴合HTML5,成为这个大家庭中的一分子。与传统的前端技术以及HTML5中其他技术成员不同的是,WebGL是被设计成直接工作在显卡(GPU)端的,所以它比目前其他的典型的Web技术都要更加复杂。总的来说,WebGL的原生API是相当的低等级的。但这也正是它为什么能够如此迅速地完成大量的计算,并实现复杂的实时3D渲染的原因。另外,由于WebGL师承OpenGL ES,而OpenGL ES又脱胎自OpenGL,这一切都离不开计算机图形学,而这门科学对于之前所有的前端工程师来说,都是很少染指的。

于是WebGL的教学和普及陷入了一个两难境地,图形工程师不懂前端,而前端工程师更不懂图形。从这个角度上说,本书很好地解决了这个问题。作者用简单易懂的语言介绍了图形学的基本概念,同时又兼顾Web开发中的疑点和难点,无论读者之前专注于哪个领域,都能够很好地入门WebGL开发。另外,本书最后一章也是全书最大的亮点之一,在这一部分作者综合全书的知识点,一步一步陪着读者搭建了一个完整的WebGL游戏。为读者之后独立搭建自己的WebGL应用奠定了基础。这对于目前WebGL实验性示例频出但完整应用依然匮乏的局面来说,有显著的推动意义。

本书中文版翻译之时,发生了两件事。一是Google Chrome浏览器移除了WebGL上下文关键字中的“实验性”描述,二是微软Internet Explorer 11被发现开始支持WebGL。前者标志着WebGL已经离开实验阶段,正式扬帆起航;后者或许意味着WebGL难得地作为一项前沿先锋技术即将实现所有浏览器厂商的大一统局面。也许未来,WebGL会像今天的CSS一样普遍,真真切切地改变着互联网的外观,改变我们的生活!


郝稼力 国内最大的WebGL技术社区及资讯站HiWebGL.com的创始人,首次把业界知名度最高的WebGL教程《LearningWebGL》翻译为中文,受到众多WebGL学习者的好评;致力于推动WebGL技术在国内的普及,曾在北京、上海等多地举办WebGL技术宣讲和讨论会。目前,正和伙伴走在创业的道路上,运营着国内首个WebGL网站—捞3D网站(Lao3D.com)。


1996年夏天,我曾在Silicon Graphic公司的Cosmo Software部门做暑期实习生,这家公司正在开发用于Web浏览器中的VRML(Virtual Reality Markup Language)播放器。VRML第一次将交互式的3D图形带入万维网中。当时的Web还很稚嫩,在如此早期的时候,能在浏览器中看到整合的3D体验还是相当令人激动的。

遗憾的是,VRML并没有获得原本想象中的那么多的支持和使用。从纯技术角度讲,有两个原因:首先,VRML的可编程性受到性能孱弱的脚本语言虚拟机的限制,也就是说,人们不可能编写出用于整个3D场景的通用代码,这也就从根本上限制了VRML的应用领域;其次,VRML的渲染模型是基于原始的OpenGL API的固化图形管线的。这意味着除了内置于系统中的视觉效果之外,人们无法添加新的自定义效果。

在随后的16年中,图形技术和编程语言获得了翻天覆地的发展。3D图形管线也变成了完全可编程的,这意味着美术人员和设计师可以凭借他们的想象力创造出无穷的光影着色效果。另外,JavaScript的虚拟机的性能也得到了巨大提升,流畅地改变3D场景的外观成为可能,甚至可以完全改变三角形的每个顶点。这样的灵活性第一次让在浏览器中自由地编写3D应用成为可能。

随着近几年来 OpenGL ES 2.0 API 的发展,计算机图形学的研发工作达到了顶峰;WebGL API正是基于OpenGL ES 2.0 API的。后者是一个轻量级的纯基于着色器的图形库,广泛应用于目前几乎所有的新的智能手机和移动设备。WebGL工作组和开发社区希望将3D图形处理器的威力以健壮和安全的方式释放到Web上,掀起新的激动人心的3D Web应用的浪潮,覆盖每一种操作系统和每一种计算设备。

Tony的这本书通俗易懂,涵盖了在Web上开发3D应用的大部分实用知识。这本书既能帮助初学者快速入门,也包含了相当多的高级开发技巧,这部分信息即使对于资深的3D图形专家来说,也会眼前一亮。Tony从显示基本的3D网格开始,不断介绍一些很有趣的内容,如视觉效果、动画、交互、创作3D内容等,这些内容组合在一起形成了一个3D游戏的原型。这本书非常好看,我非常喜欢,希望你也同样喜欢。

——Ken Russell

科纳斯组织(Khronos Group)WebGL工作组主席


Tony Parisi是一位企业家和职业CTO/ 架构师。他之前创立过国际规范和协议,也开发过优秀的软件产品,作为创业者他出售了自己的技术公司。Tony充盈着对创新的激情,迫切渴望将最酷最有趣的技术传播给普罗大众。

Tony的众多工作中最被人称道的大概就是创建了Web3D的先锋规范。他是VRML和Web 3D图形的ISO标准X3D语言的联合创建者。他同时参与了SWMP的开发,这是一个用于多用户虚拟世界的实时信息协议。Tony至今仍然作为WebGL聚会和Rest3D工作组的创始人,在继续围绕3D图形创新维护着各种社区。

Tony目前是一个保密的在线游戏创业公司的创始人,正在为旧金山湾区的用户开发社交游戏、提供虚拟现实和基于位置的服务。


本书封面上是一只金水母(chrysaora)。金水母属是钵口水母纲(scyphozoa)的一属,广布于世界各地的温带及热带海洋。金水母属中有很多类,其中最常见的一种被称为太平洋海荨麻水母(Pacific sea nettle)。这种水母常见于俄勒冈州和加利福尼亚州的海岸。“Chrysaora”这个单词来自于希腊神话。克律萨俄耳(Chrysaor)是波塞冬和美杜莎的儿子,珀伽索斯的兄弟。他的名字的意思是“拥有黄金装备的人”。

金水母是一种优雅的生物,因它那拖在伞后的24只长而纤细的触手而被人关注。巨大的伞不断脉动以帮助金水母向前推进,在水中游弋。金水母的触手可以长到超过3英尺长,用于捕获各种浮游生物。尽管人们对金水母的触手敬而远之,但其毒素只对微小生物才会致命。金水母同样也是雌雄同体,无性繁殖,一只金水母的生命通常是一年左右。另外,不同种类的金水母的颜色和体积相差巨大,这也正是为什么它如此受到水族馆的欢迎的原因。

事实上WebGL开发和金水母还是有一些关系的。Chrysaora.com是一个杰出的WebGL示例站点,其中模拟了水母在水下翩翩游弋的情景,并且是实时3D渲染的。这个示例由Aleksandar Rodic开发,使用了多种编程语言,包括JavaScript、CSS和Python等。用户可以自由地调整示例参数,控制阴影、速度和水母的数量。

封面题图取自Beauties of Land and Sea


早在1994年,Tim Berners-Lee[1]就提出了一个倡议,呼吁创建一个用于网络虚拟现实的行业规范;Mark Pesce和我做出了回应。因为当时我们只能负担得起一张飞机票,所以我们就派Mark去了日内瓦,并在全球第一次万维网开发者大会上展示我们的Labyrinth原型。在会上,Mark对所有与会人员宣称我们已经完成了这样的一个规范。我们的演示非常简单,但是却直击要点——点击之后,在浏览器窗口中打开并点击超链接,然后显示一个可以旋转的3D物体。几周之内,我们创建了一个邮件列表,并拥有了虚拟现实标记语言(Virtual Reality Markup Language,VRML)——这一致力于将3D内容推向网络世界的开创性努力正式起航了。

15年之后,3D内容终于可以融入浏览器之中,尽管并不是采用Mark和我当年设想的方式。VRML是一个很好的尝试,但是却过于超前——当时宽带连接和专用的图形硬件都还没有成为主流。VRML启发了后来者和一些模仿者,但他们又都半途而废了。技术大潮起起伏伏,人们却未曾停止过对这一问题的钻研。最终,在2009年,我们终于迎来转折点:整个业界都被一个称为WebGL的新规范凝聚在一起。到现在,2012年,看起来WebGL已经稳稳地扎根于整个行业。

WebGL将3D内容带入浏览器之中,通过JavaScript与电脑中的图形硬件进行交互。基于OpenGL ES(同样的图形内容可以运行于你的智能手机和平板电脑中)的特性,使得WebGL得到了发展并且得到了主流桌面和移动浏览器厂商的广泛支持。有了WebGL,任何一个程序员都可以通过网络创造出震撼的图形效果,并传播给数以百万计的用户,如无须下载的游戏、大数据的可视化、产品展示、模拟训练等众多应用。

尽管目前关于WebGL的网络资源已经非常丰富,而且许多框架和工具都开始支持WebGL,但是WebGL的信息却依然散乱不堪,覆盖面非常有限。WebGL的原生API是相当低等级的,对于大部分传统程序员来说都是不可及的,只有有经验的3D程序员才能驾驭它的原始形式。然而,原本WebGL的前提和愿景就是让3D内容可以走近每一个人,这其中既包括那些拥有当前电脑硬件配置并安装了当前浏览器的消费者,也包括任何一个有文本编辑器和产品设想的开发人员。我们需要找到一种方式,在WebGL的强大和其基础知识、使用工具之间搭起一座桥梁,使得人们可以练习编写WebGL应用。

这就是我写这本书的原因。

如果你是一位Web程序员或设计师,这本书可以教会你使用WebGL。本书假设你已经拥有了HTML、CSS、JavaScript的开发经验,并且熟悉jQuery和Ajax。你不需要任何3D图形学经验,本书的第1章会简短介绍3D图形学的基础知识;此外,你不必是一位专家级的游戏开发者。

本书共分三个部分,总计8章,另外还有一个附录。

大部分章节都遵循同一个套路:先解释概念,然后再深入代码当中举例说明,然后再返回来总结一下,接着再继续下一个话题。有时候我会花时间来写一些我内心的东西,或者对一些最佳实践或其他内容写一些豪言壮语。我希望我在传授知识和理论布道之间取得平衡,非常欢迎你联系我,并让我知道我做的到底怎么样。

如果你卡在了某个示例代码,那么请暂时略过并回头再看。你可以一直只读那些概念章节,然后在全部读完并做好准备之后,再开始看代码。另外,请不要犹豫,一定要在你最喜欢的支持WebGL的浏览器中打开这些示例,并用调试器查看代码,这通常是最好的学习方法。

大部分示例都使用了一个叫Three.js的工具集,它是一个杰出的基于WebGL的开源引擎。之前,我一直在考虑是给读者详细介绍很多低级别的WebGL API——这是一个极其灵活、超级强大但是毫无疑问对用户相当不友好的图形绘制系统,还是教给读者如何利用最少的基础知识就可以快速开始构建应用。显然,我做出的最终决定非常明了,那就是让你迅速入门!如果你非常想要知道WebGL的底层工作原理和更多底层知识,有许多学习资源可以供你参考。我们在附录A中列出了一部分。

WebGL的开发者已经创立了一个独一无二和不可思议的东西——运行于浏览器中的3D内容,在页面中与其他内容一同无缝渲染,整合全球任何地方的数据内容,于是就呈现在你面前一个调色板,用这个调色板你可以构建任何你能够想象到的东西。这并不是零零散散的各个部分的简单组合,而是一个全新的媒介,将会创造一个新的业界局面。WebGL编程也许一开始并不容易,但我可以承诺,如果你付出了努力,那么一个精彩的全新世界就在等着你。

本书使用如下排版约定。

 

 提示

这个图标表示一个提示、建议或者一般的注记。

 

你可以从GitHub上下载本书的所有示例代码,网址是:

http://github.com/tparisi/WebGLBook

在示例文件中,你可以找到本书中构建的所有应用的完整版,其中包含运行这些应用必需的所有代码。在运行其中的某几个示例之前,你需要下载一些额外的内容,如 3D模型等,详情请参考根目录中的README文件。

本书的目标是帮助你完成工作。一般来说,你可以在自己的程序和文档中使用本书中的代码,如果你要复制的不是核心代码,则无须取得我们的许可。例如,你可以在程序中使用本书中的多个代码块,无须获取我们许可。但是,要销售或分发来源于O’Reilly图书中的示例的光盘则需要取得我们的许可。通过引用本书中的示例代码来回答问题时,不需要事先获得我们的许可。但是,如果你的产品文档中融合了本书中的大量示例代码,则需要取得我们的许可。

在引用本书中的代码示例时,如果能列出本书的属性信息是最好不过了。属性信息通常包括书名、作者、出版社和ISBN。例如:“WebGL: Up and Running by Tony Parisi (O’Reilly). Copyright 2012 Tony Parisi, 978-1-449-32357-8.”

在使用书中的代码时,如果不确定是否属于合理使用,或是否超出了我们的许可,请通过permissions@oreilly.com与我们联系。

如果你想就本书发表评论或有任何疑问,敬请联系出版社。

美国:

O’Reilly Media Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

我们还为本书建立了一个网页,其中包含了勘误表、示例和其他额外的信息。你可以通过如下地址访问该网页:

http://oreil.ly/WebGL_UR

关于本书的技术性问题或建议,请发邮件到:

bookquestions@oreilly.com

欢迎登录我们的网站(http://www.oreilly.com),查看更多我们的书籍、课程、会议和最新动态等信息。

我们的其他联系方式如下。

Facebook:http://facebook.com/oreilly

Twitter:http://twitter.com/oreillymedia

YouTube:http://www.youtube.com/oreillymedia

就像WebGL本身一样,这本书是很多人努力的成果,其中并不乏许多知名人士的帮助和支持。首先,我想要感谢O’Reilly团队。首先是我的编辑Mary Treseler。新技术书籍一直都很有风险,但Mary全速前进最终使书得以出版。她对主题的丰富理解和不断的鼓励,对于第一次写书的作者来说是非常令人感激的。另外,包括编辑部、发行部和市场营销部门的工作人员,太多的人不能一一列举,他们都非常优秀,让我非常享受写书的过程。

我非常感谢Giles Thomas(LearningWebGL.com创始人)、Mike Korcynski、Ray Camden和Raffaele Cecco做出的一流的技术评议。他们翔实地评论让我在专业术语上保证了正确性,并且帮我精简了示例代码。最重要的是,在我写作遇到困难时,他们对前几章的积极反馈给了我强大的精神动力。

作为一本编程书籍,其中也包含了大量精美的3D图形内容。我想要感谢许多美术设计师授权允许我在本书的示例中使用他们的作品。你可以在每个示例的HTML和JavaScript文件中以及README文件中找到详细的版权信息。我想要特别感谢Christell Gause,TurboSquid的技术支持主管,正是由于他的努力,我才可以从多位TurboSquid的美术设计师那里获得授权。另外,本书中我编写的示例也离不开来自痴迷于数据的Theo Armour、资深3D开发者Don Olmstead和来自Sunglass.io的3D设计师Arefin Mohiuddin的帮助。

WebGL有幸拥有一个强大的开发社区。我想要感谢Three.js的开发者们,包括作者Ricardo Cabello(网名为Mr.doob)、代码贡献者Branislav Ulicny(网名为AlteredQualia)和Tim Knip,感谢他们对于我时常提出的一些幼稚问题的耐心回答以及他们对Three.js的热心。我亏欠Ken Russell一个人情,他是WebGL工作组的主席并在Google领导WebGL的开发。Ken不仅构建了WebGL这个伟大的产品,还欣然同意为本书作序。

最后,我想要感谢我的朋友和家人。感谢我的老伙伴Mark Pesce,一起提出VRML的“罪人”,他是一位老兵级作家。他对于写作的忘我献身和对新技术的激情,成为在这些年中不断启迪我的源泉。非常感谢我的朋友、有时也是生意伙伴的Scott Foe,尽管这本书分散了我在我的创业公司的大部分精力,他还是一直支持我写作。最后但同样重要的是,感谢我的家人长期以来给我的精神支持、耐心和充满爱的环境。另外,他们还成了我的后勤军:我的10岁儿子Lucian,试玩了书中的大部分示例;我的妻子Marina,让我坚持唯美路线,使得这些拼凑起来的示例看起来外观统一并连贯始终。

[1] Tim Berners-Lee是万维网的发明者、互联网之父。1989年3月他正式提出万维网的设想;1990年12月25日,他在日内瓦的欧洲粒子物理实验室里开发出了世界上第一个网页浏览器。


在一个可以交互的栩栩如生的水母森林中,成百条的水母游弋着,阳光穿过海面到达朦胧的水底——这一切都尽在你的掌控。一个网上的人体虚拟模拟演示,包括骨骼、循环系统和其他主要的人体系统——你可以使用鼠标来控制剥离人体的各个层面,在感兴趣的部分留下记号以备将来使用,并用超链接的形式分享给同事和学生。在一个充满沉浸感的宇宙空间中,充满了你和朋友以及粉丝的微博。不,你不是突然换台换到了PBS的《NOVA》!你也不是在看Ridley Scott最新的电影预告片!这就是运行在你浏览器中的互联网的未来——现在,它叫作WebGL。

图1-1 WebGL水母模拟(http://chrysaora.com),经Aleksander Rodic授权使用

WebGL是新的Web上的3D图形规范。有了WebGL,开发者仅仅通过JavaScript、Web浏览器和标准的Web技术的堆叠就可以充分驾驭计算机图形硬件的渲染能力。在WebGL出现之前,开发者必须依靠插件或者本地应用程序,并且要求用户下载并安装软件来实现3D体验。

WebGL是HTML5技术大家族中的一员。虽然没有写在官方的HTML5规范内,但大部分支持HTML5的浏览器都支持WebGL。像Web Workers、WebSocket和其他W3C推荐之外的技术一样,WebGL实质上已经成为把现代浏览器转变为一流的应用平台必备的一部分。

WebGL可以在大部分主流台式机上及增长迅猛的移动浏览器中运行。目前安装了支持WebGL的浏览器的用户已经超过了数百万,如你家中和办公室中的计算机。WebGL正处于一个生机勃勃、茁壮成长的生态系统的中心,将使网络体验在视觉上更加丰富和动人。现在已经有数百个使用了WebGL技术开发的网站、应用和工具,从游戏到数据可视化、计算机辅助设计以及电子商务。

在开始的时候,也许WebGL原生的低等级API会让人望而生畏,但是实际上有很多开源的JavaScript工具集可以大大简化开发工作。我是很小心地来声明这一点的,并不想夸大其词——因为3D图形学依然是一门非常困难的技术。但这些工具至少可以让更多鲜有Web开发经验的普通人也可以涉足WebGL业务。所以,把你梦寐以求想要开发的游戏变成现实的最终时刻正是现在!或者你也可以凭借个人主页上华丽的图形效果让你的老板对你刮目相看。

在本章中,我们将快速浏览一遍WebGL的底层工作原理,为你打一个基础。虽然在书中以后的大部分地方我们都将使用高级别的3D工具集Three.js,它掩盖了很多麻烦的细节,但还是很有必要了解一下这些工具集是构建在什么之上的,那么就让我们赶快开始WebGL的核心概念和原生API之旅吧!

WebGL 标准是由科纳斯组织(Khronos Group)开发和维护的,该组织还是管理着 OpenGL、COLLADA等其他你也许早有耳闻的规范的标准组织。以下是科纳斯组织的网站上对WebGL的官方描述:

WebGL是免授权费的,跨平台的应用程序接口API,它将OpenGL ES 2.0作为在HTML网页内的3D绘图环境,作为低级别文档对象模型接口开放。它使用OpenGL渲染语言GLSL ES,并可被整洁地与其他3D内容上层或下层的网页内容捆绑。它是使用JavaScript编程开发语言开发适合动态3D网页应用的理想工具,并已被主流互联网浏览器集成。

这段定义中包含了好几个核心概念,下面让我们逐条地详细铺开来看。

WebGL是一套API

WebGL是一套JavaScript编程接口,并且JavaScript是WebGL的唯一入口,所以也并不需要任何特殊的HTML标签。WebGL中的3D渲染与使用Canvas元素的2D绘画类似,所有的功能都通过JavaScript API调用。事实上,要想调用WebGL接口,只需要使用已有的Canvas元素,并设置一个特殊的绘制上下文即可。

WebGL是基于OpenGL ES 2.0的

OpenGL ES是历史悠久的3D渲染标准OpenGL的精简版本。“ES”是指“Embedded Systems”,即“嵌入式系统”,也就是说,它是为小型的计算机设备量身定制的,其中最典型的就是智能手机和平板电脑。目前iPhone、iPad、Android手机和平板电脑都使用了OpenGL ES来进行3D渲染。WebGL标准的设计者认为,沿着OpenGL ES的足迹前行,打造一个协调一致、跨平台、跨浏览器的3D Web API会更加切实可行。

WebGL和其他网络内容可以整合在一起

WebGL内容可以放置于其他页面内容之上或者之下。3D(canvas)画布元素可以作为页面的一部分,也可以充满整个页面。并且可以放置于<div>标签中,使用z轴指定堆叠顺序。也就是说,你可以用WebGL来开发自己的3D图形,但是其他的元素都依然可以继续用传统的HTML来制作。浏览器会将包括3D图形在内的页面上的所有图形内容无缝地整合在一起,提供给用户。

WebGL是用于搭建动态Web应用的

WebGL在设计之初就是为Web交付而生的。尽管脱胎于OpenGL ES,但却继承了那些能够更好地和Web浏览器整合、与JavaScript语言协同工作的特性,因此WebGL对于Web交付是非常友好的。

WebGL是跨平台的

WebGL可以运行于任何操作系统,以及从手机、平板电脑到桌面电脑的任何设备。

WebGL是完全免费的

和所有开放的Web规范一样,WebGL是免费使用的。没有人会因为WebGL而向你征收版权费用。

许多浏览器厂商,包括Chrome、Firefox、Safari和Opera,都做出了显著贡献,包括对WebGL的支持以及大量的开发资源,这些浏览器团队中的一些工程师也是WebGL规范工作组里的核心成员。WebGL规范流程是对所有科纳斯组织的成员开放的,同时他们建立了一个公开的邮件列表。你可以在附录A中找到邮件列表的信息和其他关于WebGL规范的资源。

“数学太难了啦!”

——芭比娃娃

也许有点不太好听,但是我必须得说,当我写3D图形的代码的时候,我会和芭比一样,有强烈的欲望想要用疯狂购物来放纵一下自己。因为3D图形编程通常很难,而且需要大量的数学知识。幸运的是,你不需要先成为数学大师再来写WebGL应用;我们会使用各种框架来代替我们去做其中大部分的复杂工作。尽管如此,理解底层的工作原理依然是非常重要的,因此下面我尝试在几页的篇幅内总结出整个3D图形学的基础知识。

毫无疑问,3D绘制是建立在3D坐标系中的。任何一个熟悉2D笛卡儿坐标系(即绘图纸上的和HTML页面中的窗口坐标)的人,都会知道x坐标和y坐标。这种2D坐标可以用于定义页面中<div>标签的位置,或者指定在Canvas元素上进行2D绘制的位置。类似地,3D绘制是建立在3D坐标系统中的,除了x轴和y轴,新增加了一个坐标轴z,用于表示深度(即在离屏幕多深多远的地方绘制一个3D物体)。WebGL使用的坐标系可以查看图1-2,x轴方向是水平的从左到右,y轴的方向是垂直的从下到上,z轴的方向是从屏幕里面指向屏幕外面。

图1-2 一个3D坐标系统(https://commons.wikimedia.org/wiki/File: 3D_coordinate_system.svg; 根据Creative Commons Attribution–Share Alike 3.0 Unported协议授权使用)

如果你已经非常熟悉2D坐标系,那么我想3D坐标系应该也不是很难理解。不过,从现在开始,事情要变得复杂一些了。

有很多种方法来绘制3D图形,最常用的一种方法就是使用网格(Mesh)。网格是由一个或多个多边形组成的物体,各个顶点的坐标(x, y, z)定义了多边形在3D空间中的位置。网格中的多边形通常都是三角形(包含三个顶点)和四边形(包含四个顶点)。3D网格通常也叫作模型(model)。

图1-3举例说明了一个3D网格。由黑线描边的四边形组成了这个网格,形成了一个脸部的形状(当然在最终的渲染图片中你不会看到这些黑线,这里只是为了解释网格的概念)。网格中的各个顶点的x, y, z的坐标分量只是用于定义形状;而网格表面的其他特性,如颜色和着色,都是由其余的属性来定义的,我们稍后会介绍。

图1-3 一个3D网格 (http://upload.wikimedia.org/wikipedia/commons/8/88/Blender3D_UVTexTut1.png; 根据Creative Commons Attribution-Share Alike 3.0 Unported 协议授权使用)

网格表面的其他特性是由除了顶点位置(x, y, z)坐标之外的属性来定义的。网格表面可以简单到只有一种颜色,也可以复杂到是由多个不同的数据来共同决定的,比如说物体如何反射照射到表面上的光,物体的光泽度如何。网格表面同样也可以由一个或多个位图来决定,这就是我们通常所说的纹理映射(texture map),或者简称为纹理。纹理可以定义一个线性表面的外观(就好比把一张图片印在T恤衫上),另外,通过组合多张不同的纹理可以实现更加复杂的效果,例如凹凸效果和辉光效果。在大多数的图形系统中,网格表面的特性被统称为材质(material)。材质通常依赖于一个或多个光源(light)来呈现出外观效果,你也许已经猜到了,这就是我们如何让场景被照亮的。

图1-3中人的头部模型拥有一层紫色的材质,光源则是从模型的左侧照入(注意观察模型右侧脸颊的阴影)。

3D网格的形状是由顶点位置决定的。如果每次你想要移动模型都必须重新设定顶点位置,那将会是一件非常可怕和沉闷的事情,特别是当模型会持续穿过整个场景或做其他的动作的时候。因此,大部分的3D系统都支持变换(transform),这是一种不需要遍历每个顶点就可以移动模型的操作,不需要明确的逐个改变每个顶点的位置。变换包括对渲染模型的缩放、旋转、位移操作,而不必手动设定任何顶点的值。

变换通常是由矩阵来操作的,这是一个包含一组数值的数学模型,用于计算顶点的变换位置。如果你和我一样也是一个线性代数迷,那你应该很适应这个方法。如果不是,也别灰心。本书中使用的Three.js工具集可以让我们以黑箱模式操作矩阵:我们只需要告诉程序位移、旋转或者缩放,那么Three.js就会完成相应的操作。

每一个场景在渲染时都需要有一个视点,用户正是从视点的位置去观察场景。3D图形系统通常使用相机(camera)来定义用户与场景的相对位置和朝向,和我们真实世界中的相机一样,3D世界中的相机也具有类似于视野尺寸等属性。视野尺寸决定了透视关系(例如,远处的物体会看起来小一些)。相机的各个属性组合在一起将最终的3D场景渲染图像传送给2D视口(viewport),视口是由浏览器窗口或Canvas元素决定的。

相机永远是由两个矩阵来控制的。第一个矩阵定义了相机的位置和朝向,类似于用于进行变换操作的矩阵(见前文)。第二个矩阵比较特殊,它用于将相机空间的3D坐标转换为视口中的2D绘制空间中的坐标,这就是所谓的投影矩阵(projection matrix)。唉,我就知道讨厌的数学又来了!但大部分的WebGL框架都可以掩盖相机矩阵的底层细节,所以你要做的只是放置相机然后渲染即可。

图1-4很好地解释了相机、视口和投影的核心概念。在图的左下方,会看到一个眼睛的图标,代表相机的位置。红色的向量指向右侧(在图中被标记为x轴),代表相机的指向。蓝色的方块是3D场景中的物体。绿色和红色的矩形分别代表近裁剪面远裁剪面。这两个平面决定了3D空间的子集的边界,也就是所谓的视锥体(view volume)或视平截头体(view frustum)。只有处于视平截头体内部的物体才可以被渲染到屏幕上。近裁剪面即视口,此平面就是我们最终在屏幕上看到的渲染的2D图像。

图1-4 相机、视口和投影,经授权使用

相机是一个非常强大的工具,它决定了观察者和3D场景之间的关系,造成一种仿真感。在动画兵工厂中相机还是一件威力无比的武器,通过移动相机,你可以创造出神奇的荧幕效果,掌控用户的视觉体验。

这是在总结我们的3D图形学探索旅程之前的最后一个话题:着色器(shader)。为了在最终的图像中渲染模型,开发者必须精确地定义顶点、变换、材质、光源和相机之间的关系和交互。这就是由着色器来完成的。着色器(或称为“可编程着色器”)是一小段程序代码,其中包含了将模型投射到屏幕上的像素算法。着色器通常是由高等级的类C语言编写的,编译并运行在图形处理单元(GPU)中。大部分的现代电脑都配备了GPU,它是一种独立于CPU而专门用于渲染3D图形的处理器。

如果你仔细阅读了我之前提到的WebGL的定义,你也许会注意到我忽略了一部分内容。在科纳斯组织的官方网站上有这么一段话:

它使用OpenGL渲染语言GLSL ES……

在其他许多图形系统中,着色器是一个可选的或比较高级的特性;但与之不同的是,WebGL必须配备着色器。当你编写WebGL程序的时候,必须定义着色器,否则图形是不会显示在屏幕上的。WebGL的实现假定客户端电脑上配备有GPU。GPU可以处理顶点、纹理和其他一点东西;但它对材质、光源和变换却一无所知。把后者这些较高级的信息传递给GPU并最终把它们绘制到屏幕上的转换过程是由着色器来完成的,着色器是由开发者创建的。

所以你现在应该可以理解为什么我不一开始就讨论这个话题:我不想吓到你!着色器编程看起来很吓人,要用类C的语言来写,短时间内看是这样的,而且似乎花这么大的代价来将3D场景转换成最终的2D图像有点得不偿失。但是,请别害怕:许多流行的WebGL框架都内置了着色器,你只需要在代码中嵌入它们即可,这些内置的着色器可以满足你大部分的需求。

 

 

我想我有必要声明一下,着色器带来的并不只是痛苦和煎熬。它的存在是很有必要的。着色器给予图形开发者完全的能力去操控每一个顶点和像素。这种能力可以创作出许多惊艳的视觉效果,从栩栩如生的CG效果(如图1-1所示的水母)到奇幻的卡通风格。但是强大的能力总是需要更强大的控制者。着色器是一个非常高端的话题,我不想让你在一开始就去攀登这座大山,直到我们已经充分理解了各种知识。这也正是为什么本书中所有的示例都使用了相当简单的着色器。

 

计算机图形学中的基本概念在过去的数年中从未发生过变化。但图形技术却不断进化,特别是最近几年,伴随着设备和操作系统的多样化。这些百花齐放的图形技术的根基则是诞生于20世纪80年代末期的OpenGL。OpenGL作为行业规范已经存在了非常长的时间,并且成功经受住了来自微软的DirectX的竞争考验,无可争辩地成为3D图形编程的领衔者。

但是并非所有的OpenGL都是一样的。根据不同平台的不同特征,包括台式电脑、智能电视、手机和平板电脑等,人们开发了不同版本的OpenGL。OpenGL ES(Embedded System,即嵌入式系统)就是其中的一个版本,专门用于运行在较小的设备上,例如智能电视和手机。也许当初OpenGL ES的设计者们并未料到,正是它成了WebGL的理想核心。OpenGL ES小而精悍,这并不只是说它足够小因此可以集成到浏览器中,还意味着不同的浏览器厂商都可以使用这套规范。这样的话,WebGL应用就可以顺利地运行在所有的不同浏览器中。

但所有这些高性能和便携性的背后都有代价。WebGL精悍的本质其实是将责任压在了应用开发者的肩上,他们必须自己去处理所有的模型、场景、显示列表和其他构架;当然,在资深图形开发者看来,这都是理所当然的。最值得关注的是,对于一般的Web开发者,WebGL的学习之路陡峭而崎岖,WebGL看起来好像天书。而好消息则是目前已经有很多开源的WebGL框架,可以大大简化WebGL开发的工作量。说个有些粗糙的比喻,这些框架就好像是jQuery和Prototype.js一样。在本书中我们会花几页的篇幅讨论其中一个框架Three.js。但在这之前,我们还是快速地浏览一下WebGL的底层原理。

从本质上来讲,WebGL只是一个绘制库——一个增强型的绘制库,使用WebGL你可以绘制出惊人的图形,并可以在当前大部分机器上充分利用强大的GPU硬件能力。但也可以把WebGL理解成另一种画布,类似于HTML5浏览器中的2D Canvas。实际上,WebGL也正是使用了HTML5中的<canvas>元素来在浏览器页面中显示3D图形。

想要使用WebGL把图形渲染到页面中,一个应用至少需要执行如下步骤。

1.创建一个画布元素。

2.获取画布的上下文。

3.初始化视口。

4.创建一个或多个包含渲染数据的数组(通常是顶点数组)。

5.创建一个或多个矩阵,将顶点数组变换到屏幕空间中。

6.创建一个或多个着色器来实现绘制算法。

7.使用参数初始化着色器。

8.绘制。

在本小节中我们会详细介绍上述的每一个步骤,各步骤的代码片段来源于一个完整的示例,在这个示例中我们用WebGL绘制了一个白色的正方形。你可以从文件Chapter 1/example1-1.html中找到完整的代码。

所有的WebGL渲染都发生在一个上下文(context)中,这是一个JavaScript DOM对象,可以提供完整的WebGL API。这个结构类似于HTML5中<canvas>元素的2D绘制上下文。想要使用WebGL,只需要创建一个<canvas>元素,然后获取与它关联的DOM对象(使用document.getElementById()),最后再为其获得一个WebGL上下文即可。示例1-1展示了如何从画布的DOM对象中获得WebGL上下文。

示例1-1 从Canvas中获取WebGL上下文

function initWebGL(canvas) {
    var gl;
    try
    {
        gl = canvas.getContext("experimental-webgl");
    }
    catch (e)
    {
        var msg = "Error creating WebGL Context!: " + e.toString();
        alert(msg);
        throw Error(msg);
    }
    return gl;
}

 

 

请注意示例代码中的try/catch这一部分。这一部分非常重要,因为目前一些浏览器依然不支持WebGL,或者即使支持了,但是用户并没有安装包含WebGL支持的最新版本的浏览器。另外,即使浏览器支持WebGL,但因为用户使用的是老旧的硬件,因此并不能成功地获得上下文。所以示例1-1中这一部分的检测代码将会帮助你做一个回滚,比如回滚到2D画布,或者至少能让你的应用礼貌地选择退出。

 

一旦成功地从画布中获得了WebGL的绘制上下文,你就可以告诉它在哪里绘制矩形了。在WebGL中,这被称为视口(viewport),在WebGL中设置视口非常简单,只需要调用上下文的viewport()方法即可(参见示例1-2)。

示例1-2 设置WebGL视口

function initViewport(gl, canvas)
{
    gl.viewport(0, 0, canvas.width, canvas.height);
}

让我们回忆一下,gl对象是在initWebGL()函数中创建的。在这个示例中,我们初始化的WebGL的视口占据了整个画布的显示区域。

现在我们获取到了上下文并设置好了视口,可以准备开始绘制了。这和2D Canvas还是很像的。

WebGL的绘制是由图元(primitive)组成的,图元的种类包括三角形(三角形数组)、三角形带(triangle strip,稍后我们会讲到)、点和线。图元使用的数据数组被称为Buffer,它定义了顶点的位置。示例1-3展示了如何创建一个大小为1×1的正方形的顶点数组。返回的JavaScript对象存储了顶点数组信息、数组中每个顶点所占的尺寸(在这个示例中,包含三个浮点数来存储x, y, z的值)、需要绘制的顶点的数量,以及用于绘制正方形的图元的类型。(在这个示例中,我们使用了三角形带。三角形带是一种基本的渲染图元,它是指使用前三个顶点画出第一个三角形,然后再用这前三个顶点中的后两个与下一个顶点结合再绘制一个三角形,依次类推。)

示例1-3 创建顶点数组

// 创建用于绘制正方形的顶点数据
function createSquare(gl) {
    var vertexBuffer;
    vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    var verts = [
         .5,  .5,  0.0,
         -.5,  .5,  0.0,
         .5, -.5,  0.0,
         -.5, -.5,  0.0
   ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts),
        gl.STATIC_DRAW);
    var square = {buffer:vertexBuffer, vertSize:3, nVerts:4,
        primtype:gl.TRIANGLE_STRIP};
    return square; 
}

请注意我们使用了一个叫Float32Array的数据类型。这是一种为了WebGL而专门引入浏览器中的新数据类型。Float32ArrayArrayBuffer的一种,也被称为类型化数组(typed array),用于在JavaScript中存储二进制数据。在JavaScript中访问类型化数组可以使用与传统数组相同的语法,但是速度更快并且占用更少的内存。在对性能要求很高的场合下,使用它来处理二进制数据是非常理想的选择。类型化数组还可以用于很多其他的场合,但是它最开始是因为WebGL才被引入的。你可以在科纳斯组织的官方网站上找到类型化数组的规范全文(http://www.khronos.org/registry/ typedarray/specs/latest/)。

在绘制正方形之前,我们必须建立两个矩阵。首先,我们需要一个矩阵来定义正方形在3D坐标系中相对于相机的位置。这个矩阵也称为模型视图矩阵(modelview matrix),因为它综合了模型的变换和相机之间的关系。在这个示例中,我们对模型的变换就是将正方形沿着负z轴进行平移(即远离相机-3.333个单位)。

我们需要的第二个矩阵就是投影矩阵(projection matrix),这个矩阵将被用于在着色器中将相机空间中模型的3D坐标转换为绘制的视口的2D坐标。在这个示例中,投影矩阵定义了一个45°的相机视野。投影矩阵非常难以想象,几乎没有人会手动编写计算投影矩阵的代码,而都是由框架来自动完成。在这里我推荐一个非常好用的开源框架,叫作glMatrix,它专门用来在JavaScript中进行矩阵运算。glMatrix是由Brandon Jones编写的,他同时也是一些精彩的WebGL作品的作者,他复刻了Quake和其他几个著名游戏的WebGL版本。

示例1-4 设置模型视图矩阵和投影矩阵

function initMatrices()
{
   // 正方形的变换矩阵——相对于相机沿着z轴稍微后移一些
   modelViewMatrix = new Float32Array(
           [1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, −3.333, 1]);

   // 变换矩阵(45度视野)
       projectionMatrix = new Float32Array(
           [2.41421, 0, 0, 0,
            0, 2.41421, 0, 0,
            0, 0, −1.002002, −1,
            0, 0, −0.2002002, 0]);
}

我们离最终的绘制越来越近了。最后还剩一个非常重要的步骤需要设置:着色器。像我们之前所说的一样,着色器其实就是一小段程序,是由高等级的类C语言编写而成,它定义了如何将3D物体的像素切实地绘制在屏幕上。WebGL要求开发者为每个需要绘制的物体提供着色器。一个着色器可以同时应用于多个物体。所以在实际情况下,我们经常只提供一个着色器来满足整个应用程序,然后每次用不同的参数多次复用这个着色器。

着色器是由两个部分组成的:顶点着色器(vertex shader)和片元着色器(fragment shader),后者也被称为像素着色器(pixel shader)。顶点着色器负责将物体的坐标转换到2D空间;片元着色器负责生成最后的颜色输出到每个转换后的顶点像素,而颜色的输入则可以是纯色、纹理、光源或者材质。在这个简单的示例中,顶点着色器综合了modelViewMatrixprojectionMatrix的值,通过计算转换了每一个顶点;而片元着色器则只是简单的输出了白色。

在WebGL中,设置着色器必须遵循一定的步骤,首先编译着色器的各个部分,然后将它们链接到一起。因为篇幅有限,我们在这里只展示两个简单的着色器代码(使用GLSL ES语言,参考示例1-5),而并不写出所有的设置代码。你可以在完整的示例中看到如何设置着色器。

示例1-5 顶点着色器和片元着色器

var vertexShaderSource =
    "    attribute vec3 vertexPos;\n" +
    "    uniform mat4 modelViewMatrix;\n" +
    "    uniform mat4 projectionMatrix;\n" +
    "    void main(void) {\n" +
    "        // 返回变换并投影后的顶点数据\n" +
    "        gl_Position = projectionMatrix * modelViewMatrix * \n" + 
                    vec4(vertexPos, 1.0);\n" +
    "    }\n";

var fragmentShaderSource =
    "    void main(void) {\n" +
    "    // 返回像素颜色:永远输出白色\n" +
    "    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
    "}\n";

现在我们终于万事俱备,可以开始绘制正方形了(参考示例1-6)。我们建立了上下文,设置了视口,顶点数组、矩阵和着色器也已经设置并初始化完成。我们定义了一个函数draw(),在这个函数中将接管WebGL上下文和我们之前建立的矩形对象。首先,函数会先清理一下画布并用黑色作为背景颜色。然后将顶点数组绑定到上下文中,使用着色器,并把顶点数组和矩阵作为输入传递给着色器。最后我们调用了WebGL的drawArrays()方法来绘制正方形。我们简单地告诉它,图元的类型和图元中有多少顶点;WebGL会自动根据我们在上下文中设置的其他值(顶点、矩阵、着色器)完成绘制。

示例1-6 绘制代码

function draw(gl, obj) {

     // 用黑色清空背景
     gl.clearColor(0.0, 0.0, 0.0, 1.0);
     gl.clear(gl.COLOR_BUFFER_BIT);

     // 设置顶点数组
     gl.bindBuffer(gl.ARRAY_BUFFER, obj.buffer);

     // 设置着色器
     gl.useProgram(shaderProgram);

     // 设置着色器参数:点点坐标、投影矩阵和模型视图矩阵
     gl.vertexAttribPointer(shaderVertexPositionAttribute,
        obj.vertSize, gl.FLOAT, false, 0, 0);
     gl.uniformMatrix4fv(shaderProjectionMatrixUniform, false,
        projectionMatrix);
     gl.uniformMatrix4fv(shaderModelViewMatrixUniform, false,
        modelViewMatrix);

     // 绘制物体
     gl.drawArrays(obj.primtype, 0, obj.nVerts);
}

最终完成绘制的结果如图1-5所示。

图1-5 使用WebGL绘制的正方形

这样我们就结束了WebGL基础知识之旅。噢!东西可真多啊!现在你也许在想,仅仅在屏幕上画一个正方形就如此兴师动众。而且,这还不是一个真正的3D物体!好吧,我部分同意你的意见。WebGL编程,在这个等级上的编程,是相当困难的。标准的设计者做出这样一个决定还是相当清醒的,他们用这样一个既小巧又简单的标准,换取了WebGL强大的能力,而付出的代价是开发者必须要在应用程序端编写大量的代码。

显然,在大部分情况下,我们不会使用WebGL来绘制2D物体。HTML5的2D Canvas在这方面已经做得很好了,并且只需要很少的几行代码。但即使是开发真正的3D应用,你用WebGL原生API来编写代码依然是一件艰巨的工作。你会不由自主的开始写一个自己的构建于WebGL之上的库,或者更好的是,其他程序员也许已经替你完成了这项工作。好吧,我有个好消息:那就是他们的确已经完成了这样的工作。在第2章中,我们将会使用Three.js来开发第一个WebGL应用。让我们开始吧!


相关图书

计算机图形学编程(使用OpenGL和C++)(第2版)
计算机图形学编程(使用OpenGL和C++)(第2版)
计算机图形学入门:3D渲染指南
计算机图形学入门:3D渲染指南
从零开始:数字图像处理的编程基础与应用
从零开始:数字图像处理的编程基础与应用
OpenCV图像处理入门与实践
OpenCV图像处理入门与实践
趣味掌控板编程
趣味掌控板编程
OpenGL超级宝典(第7版)
OpenGL超级宝典(第7版)

相关文章

相关课程