unity3d从入门到精通

davidtwins

贡献于2016-05-25

字数:0 关键词: 游戏开发

内容简介 本书是国内第一本以面向对象和项目流程开发角度,全面系统介绍 Unity3D 的书籍。 本书以具体项目结构开发的角度,结合 Unity3D 层级式的综合开发环境、视觉化编辑、详 细的属性编辑器和动态的游戏预览的特点,在软件界面介绍及功能使用方面以分级、分阶、 分段手法来向大家详尽阐述概念和使用方法,在程序编写方面以以 OOP【面向对象程序设 计】为主轴讲述 Mono 的精髓;以软件系统开发的高度,清楚的讲解 Mono 的 API 的原因、 原理和应用。Unity3D 是主要游戏开发的载体,它就像是一我们日常生活中使用的 Window s 系统那样,链接着各种可以解析并使用的文件和其他软件硬件的使用接口,当你把这些接 口顺利的打通之后,就可以方便快捷的让 Unity3D 在各种平台施展它的能力,这也是学习 U nity3D 的精髓所在,当你把这一点领悟透彻之后,会发现不论你利用 Unity3D 进行何种方 面的开发,都是相互贯通、浑然一体的,从而再进行学习或开发,就会驾轻就熟,如孙悟 空脚踏筋斗云,南北往来比坐喷气式飞机都还要轻松自如。 本书共分 5 个部分。第 1 部分:Unity3D 的界面熟悉极其组件使用;第 2 部分:脚本编 写与项目设计;第 3 部分:Unity3D 的核心类与各平台下的 API;第 4 部分:视觉编程;第 5 部分:组件开发。附书光盘内容为书中实例源文件和本书中重点操作视频演示教程。 前 言 Unity3D 作为一款跨平台的游戏开发引擎,可以开发出运行在网页、客户端、安卓手机、 Iphone 手机,Ipad、Xbox360、PS3、Wii 客户端的游戏。其内置的 Mono 和 ShaderLab 程序 语言体系良好的解决了多系统跨平台直接协同作战的问题。可以说是今年一款十分方便易 用的游戏开发引擎,能够开发出次世代风格的网络游戏。作为学习者来说,现在学习 Unity 3D 来说正是恰逢其时,因为 Unity3D 引擎是一家丹麦的游戏引擎运营商 Union 开发的游戏 引擎,一直以来对中国的市场支持度并不是太高,但今年有所不同。随着 ChinaJoy 在上海 的顺利召开,Union 也获得了丰厚的风险投资在上海成立了办事结构,正准备面向中国市场 一展拳脚。 并且,由于 Unity3D 最早是一款运行在苹果系统下的软件,一直以来对苹果系列都有 着良好的支持度,许多游戏开发商都可以依助苹果商店这一良好的游戏发布平台,来赚取 游戏产品高额回报率。就拿最经典的 Iphone 热销游戏《愤怒的小鸟》来说吧,2011 年 1 月 份的下载量是 7500 万,3 月份是 1 亿,截至到 4 月 27 日已经达到了 1.4 亿的下载量,每个 游戏的按照 0.99 美金来计算的话,开发者也已经靠开发这款简单的游戏赚取了 1.386 亿美 金,而且该开发团队还在继续向前,不断的推出愤怒小鸟的更新版本,愤怒的小鸟也在不 断的续写着传说!所以说,作为 Unity3D 的开发者,很有可能你就会在这场风暴中,一个 不小心的就变为了亿万富豪。笔者也非常愿意看到这一幕的出现,也不枉费笔者的良苦用 心,写了这么一厚本书,o(∩_∩)o 哈哈。 而且,Unity3D 还提供能了对 Web Dom 体系良好的 API 接口,以及个系统平台下的 A PI 通讯端口,使得我们在开发各方面的软件应用、B/S 或 C/S 应用上都游刃有余。这使得 U nity3D 在程序开发界成为了一种文化学习新风尚,指引着大家开创 3D 虚拟现实应用的新明 天。 本书的目标与特色 本书的目标 长久以来,中国的 Unity3D 开发界都缺少一本专门讲述 Unity3D 的开发书籍。依靠网 上的一些教程和资料又很难全面而透析的理解并掌握 Unity3D。更何况大多说比较经典的网 络教程都是一些难啃的鸟文,这大大增加了学习者学习 Unity3D 的难度,也严重打击了一 些初学者的信心。一些少有的意志坚定者,可能在经历了漫长咖啡因过程之后,会学得小 有所成,但毕竟耗费的代价实在是太大了,而且并不一定就能真正的理解和领悟到 Unity3 D 的精髓。可能网上一些朋友会鼓吹你去学习什么英文,也是为了日后的学习更加事半功倍。 但 IT 产业其本身就是一个高速发展的产业,可能会由于你千分之一秒的一个犹豫,一个黄 金时代就在你的身边飘过了。所以笔者还是建议大家来学习中文,这样既支持了我们伟大 的母语,又能让你在短时间之内技术提高的速度非常快,避免了自己错过赚钱的最佳时机。 并且 Union 都已经准备在中国设立研发机构了,我何必又去庸人自扰呢?还是抓紧时间把 技术学到手,做出自己想要做出的东西来,你说对吧? 本书的特色  本书以理论加实例,深浅结合,使得学习者在整个学习过程中能够把理论知识融汇贯 通,在实例中将知识点滴升华。  以 Unity3D 设计的本意和思路,为读者全面透析核心结构和各部分知识要点,尽可能 的使读者在了解 Unity3D 的同时,更好的把握 Unity3D 游戏的制作思想。  在程序上以面向对象思想(OOP)为重点,例子和必须结合。系统的阐述了 OOP 思想及 其在 Unity3D 中的运用。 本书为何而写 长时间以来,国内关于Unity3D方面的教程参差不齐。一直就没有一本深入,全面介绍 和学习Unity3D的书籍。这极大的限制了Unity3D在国内的推广和国内相关游戏开发者水平 的提高。本书作者从事大型Unity3D项目发开已有数年经验,在Unity3D还未移植到Windows 平台的时候就利用苹果笔记本开始了有关Unity3D的研究。在2009三月 Unity2.5加入了对W indows的支持;2009十月 Unity2.6独立版开始免费的时候,笔者已经清晰的意思到Unity3 D未来的发展规划,并充分的意识到了Unity3D所潜在的力量,并开始研究其架构,积累了 丰富的第一手开发笔记。因此,本书的写作可以说是笔者这些年来潜心研究,呕心沥血的 结果。 笔者在电子工业出版社的大力协助下,以严谨的学术态度撰写本书。笔者衷心期望, 本书出版时,不仅是国内第一本深入学习Unity3D的书籍,也能抛砖引玉,加速推动国内Un ity3D的研究开发步伐。 本书面向的读者人群 本书所讲述的知识主要基于在PC的Windows系统进行Unity3D的开发,主要考虑到的第 一,苹果机器高昂的成本并不一定适合所有的人群;第二,PC的Windows系统毕竟还是当下 使用率最广的平台,基于这个平台来推广Unity3D,能够使得Unity3D在中国更快、更好的 发展。 实际上要写一本Unity3D初学者、Unity3D中级爱好者和实际项目开发者都能看的书, 是一件很有野心的事情,事实上也是难以完全做到的。这是由于Unity3D本身涵盖的知识范 围就很广泛的原因造成的。就拿Mono的开源式.Net来说,完全都可以写一本单独的书了。 再加之Shader着色语言的编写,牵涉到了大量的矢量数学知识,要将Unity3D的知识点滴一 网打尽,其工程量可以说是非常浩大。 但根据笔者观察,国内Unity3D的爱好者水平参差不齐。有一部分学习得比较早的开发 者,但更多的是对Unity3D完全茫然的入门者,以及准备从CG Designer(CG建模设计师) 转向Unity3D Programer(Unity3D程序设计师)的新手。更有广大的以前从事图形编程设 计的程序员,这里面包括了Flash 3D、Java 3D、OGRE、虚幻引擎等等的,拥有良好的OOP 设计基础和3D程序开发基础,准备转向Unity3D的人。随着今年Unity3D在中国上海等地成 立了办事机构,在海外蓬勃发展了6年的“黄金”引擎,在中国将会有着无限广阔的明天! 这样的现状促使我努力的朝着这个不可能的任务去做一些力所能及的事。经过分析, 这几类人群都有比较明显的特征,使得我在讲述的时候必须在某些晦涩难懂的细节上多加 注意,对读者循循善诱,以便能够照顾到绝大部分的人群。 对于初学者 如果你是一个刚入门的初学者,你可能喜欢比较浅显的讲解再加上一些具体的案例。有 时候可能运用具体的案例来给你做一套演示,会胜过千言万语的概念解释,让你更快的了解 知识点的根本,清晰的掌握知识的要点。本书正是在参考了大量的文献资料之后,撰写出来 的一本“Based on the project development learning”【基于实例开发学习】书籍,让你对 软件每部分内容的功能和使用方法都能清晰掌握。 如果你以前从未接触过Unity3D,那么恭喜你,你赶上好时候了。Unity3D在进入3.0版 本以后,对之前的许多功能做出了重大升级和性能改善。使得Unity3D能够对开发者提供能 更友好的开发环境和更易用的使用代码,最终的目的就是让开发者把注意力都集中在游戏开 发的逻辑上和创造力上,而不用过多的考虑编程程序的细节。举个小例子吧,C#作为最经典 的OOP语言之一,它的类名必须得和文件名同名。但Unity3D自建的C#文件总是以默认名“N ewBehaviourScript(Number)”命名的,在3.4以前,当你修改了文件名之后,编译器并不 能理解你意思,而是在文件内部保留了原来的类名,这使得许多初学者在学习到这里的时候 感到很疑惑:“为什么添加的代码都是正确的,但就是编译报错?”,但在3.4以后的版本就 不存在这个问题了,当你在编辑器中修改了文件名字之后,它所对应的类名也会随之改变。 另外,3.4的版本还引入了“Gizmos”【 标签显示】的功能,你别小看这么一个小小的功能, 它的来到能让以前Unity3D混乱的场景一下子变得清晰许多,对大项目的开发和管理尤为有 用。 对于有一定建模背景的人群 对于这类人群而言,可能有些初出茅庐,有些则在原先自己的领域中可能已经成为行业 内的佼佼者了。对于那些建模精英们,建模里面的线条、材质、灯光、优化、表现等等早已 经是驾轻就熟了。但他们却不明白自己做的模型如何在引擎里面使用、如何添加物理,自己 搭建的场景如何能够在引擎里面表现出应有的动态效果。 针对这类人群,笔者将会在有关建模的章节中使用“*”号表示。你大可以跳过带有此 类标记的章节,而只学习到你想要学习到的内容,以助于你的快速入门和提高。但对于那些 初出茅庐的建模人员来说,笔者建议大家还是逐章看看,以有助于你更好的理解Unity3D的 精髓。另外对于那些建模高手们,有空时还是建议大家从头详细阅读一下其他的章节,这便 于大家理解如何处理在Unity3D中模型优化等问题。 对于具有 3D 编程基础的人群 恭喜你,笔者绝对有信心你在学习过本书之后,能将自己的作品提升到一个更高的高度 上去。道理很简单,首先Unity3D提供了对大多数建模软件文件格式的支持,这使得原先许 多需要程序控制的复杂任务被解脱出来交给建模人员去完成,这样的好处会使得项目开发更 加高效,效果也会更加理想。其次,Unity3D的编程脚本采用的是Mono的FrameWork环境,这 使得原先关注于前台编写工作的JavaScript程序员和关注于后台编写工作的C#、Java等OOP 程序员都能够驾轻就熟的迅速掌握和使用它;在图形特效方面,Unity3D内置的ShaderLab 还提供了对Cg、GLSL语言编写shader的支持。一个shder可以包含众多变量及一个参数接口, 允许Unity去判定参数是否为当前所支持并适配最适合参数,并自己选择相应的shader类型 以获得广大的兼容性。 本书结构 第1部分:Unity3D软件基础 第2部分:组件使用、脚本编写与项目设计 第3部分:Unity3D的核心类与各平台下的API 第4部分:视觉编程与网络编程 第5部分:组件开发 本书导读: Unity3D是一个用于创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内 容的综合型创作工具。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件其编辑器运行在Windows 和Mac OS X下,可发布游戏至Windows、Mac,Wii或iPhone平台。也可以利用Unity web pla yer插件发布网页游戏,支持Mac 和Windows的网页浏览。它的网页播放器也被Mac widgets 所支持。 在资源导入方面,Unity3D项目中的资源会被自动导入,并根据资源的改动自动更新。 虽然很多主流的三维建模软件为Unity所支持,不过对于3ds Max、Maya、Blender、Cinema 4D和Cheetah3D的支持比较好,并支持一些其他的三维格式,笔者比较推崇FBX1格式的3D 模型格式,因为它很好的解决了跨平台和多软件相互协作的问题。 并且由于它内置了Mono2的FrameWork开发环境,和面向GPU编程的ShaderLab编程环境, 这两种编程环境一个针对于CPU进行编程,一个针对GPU进行编程,并且都是跨平台跨硬件 的编译器,不受开发环境的约束,对第三方API能够良好的融合,所以使得这款软件在产生 之初就得到了很广泛的使用群体。 图形渲染接口主要是Direct3D(仅运行在Windows平台下),OpenGL(能运行在苹果系统M 1 FBX 最早是 FilmBox 这套软件所使用的格式,现在改称 Motionbuilder(这一套比较著名的动作捕捉软件)。 我们把 FilmBox 第一个、中间一个、和最后一个字母提取出来,就成了 FBX。1993 年 KayDara 公司正式成 立,同时发布了 FilmBox 1.0,FBX 技术就此诞生。在 2004 年 Alias 公司将 KayDara 公司收购了,从此 Motionbuilder 与 Maya 成为了最亲密无间的兄弟。在 2005 年 AutoDesk 公司把 Alias 公司收购,从此 AutoDesk 便拥有了 FBX 技术。现在 FBX 有两个研发中心,一个位于加拿大的蒙特利尔,一个位于中国上海。FBX 相比传统的模型格式文件,除了对顶点、片段、材质等信息数据的支持外,它还对骨骼绑定动画有着良好 的支持。现在的 FBX 已经提供了比较良好的软件 I/O,对 Maya、3ds Max、Mudbox、Softimage、Toxik、 Motion Builder 都有着良好的支持。另外 FBX 还提供了一整套跨平台基于 CPP 的 SDK,这使得我们可以轻 松方便的将支持 FBX 文件的 3D 建模软件中的场景文件,通过 FBX SDK 读取到我们自己的游戏引擎中。 另外如果你安装了 Quicktime 的 FBX 插件,那么你就可以用 Quicktime 预览 FBX 了。 2 Mono 是一个由 Novell 公司(先前是 Ximian)主持的项目。该项目的目标是创建一系列符合 ECMA 标准 (Ecma-334 和 Ecma-335)的.NET 工具,包括 C#编译器和共通语言运行平台。与微软的.NET Framework 不同,Mono 项目不仅可以运行于 Windows 系统上,还可以运行于 Linux,FreeBSD,Unix,Mac OS X 和 Solaris。——来自维基百科 ac和Windows平台下)和自有的APIs(游戏机Wii平台下)。 在项目版本控制方面,使用的是自带的The Unity Asset Server,避免了重新学习Svn 等版本控制软件的烦恼,且方便易用。 另外音效系统基于OpenAL程式库,可以播放Ogg Vorbis的压缩音效。视频播放采用The ora编码。内建地型编辑器,支持树木与植被贴片。内建Lightmapping以及Global illumin ation。 多人网络连线采用Raknet。 对于网站客户端编程人员来说,可以用它来开发网页游戏,开创在线数字城市等虚拟S NS社区。 对于PC端程序员来说,可以用它来开发多人在线游戏,圆了中国无数青少年自主开发 网络游戏的梦想。 对于手机开发者来说更是不可多的的一个机会,无数的手机游戏开发公司可以靠它开 发的游戏在苹果商店获得巨额利润。 另外Unity3D相对于其他的3D游戏开发环境的优势是它是即看即所得的,开发者可以在 整个开发过程中实时的查看到自己制作的游戏运行情况,这使得学习它的人更容易上手, 也更愿意来学习。像虚幻三这类似的引擎,如果你改变了场景,还非得你重新编译一遍才 能显示出场景效果来,对于初学者来说,可能学习起来不是太好掌握。 第1部分Unity3D软件基础 第 1 章 Unity3D 的基本入门及功能介绍 本章主要是 Unity3D 的基础快速入门篇,通过本章的学习,能让初学者们快速的掌握和 应用 Unity3D 软件。 本章导读 本章无论对于 Unity3D 初学者、或是以前从事建模工作的设计师、又或者是从事过 3D 编程的人群,在转向 Unity3D 的学习的时候,学习本章内容都极有必要的。通过本章节内容 的学习,你可以迅速的掌握 Unity3D 的软件结构,各个板块具体的功能和作用以及场景制作 流程等等。本章节可以说是全书的根基,只要你能把本章节的内容掌握熟悉,那在今后的日 子里面开发任何的游戏可以说是事半功倍。这就像运动员们在小的时候打好了坚实的基础, 再向今后的专业突破的时候,就感觉游刃有余,几乎不费吹灰之力就拿下任何一个项目。 对于有一定 Unity3D 基础的人群而言,笔者也强力建议在有充足时间的情况下,耐心的 阅读下本章节的内容。因为笔者时常在网上发现一些 Unity3D 早期的开发者,往往对一些 U nity3D 很基础性的功能莫不着头脑。这不能怨这些开发者的水品不够,而是有许多 Unity3D 的功能在长期未被使用的情况下,被他们遗忘了,突然有一天需要使用的时候,就抓了狂, 发了疯。 另外笔者要在这里提醒一下建模设计师,可能你们在原先的行业里面已经将 3DS MA X、Maya 等建模软件摸索得相当熟练了,但游戏场景和影视场景还是存在很大的差异。首 先最大的差异就在于灯效的实时性,游戏讲究的是动态灯光,追求与游戏者视觉互动;而 影 视灯光则是一种静态的逐帧灯光,所有效果都被渲染成一张张静态的连续图片,它们主要倾 向与影迷们的观赏互动;前者比较主动,而后者相对来说比较被动。前者在使用灯效处理的 时候受硬件的局限性大,面对的客户群体需要有所区分;后者在观赏灯效处理的时候,几 乎 不受任何计算机硬件的影响,面对的客户群体也比较广泛。 1.1 界面入门 图 1-1 如图 1-1 所示为 Unity3D 最经典 2 by 3 结构界面,上面呈现了 Unity3D 最为常用的几 个面板,下面为各个面板的详细说明。  Scene【场景面板】:该面板为 Unity3D 的编辑面板;你可以将你所有的模型、灯光、 以及其他材质对象拖放到该场景中。构建游戏中所能呈现景象。  Game【游戏面板】:与场景面板不同,该面板是用来渲染场景面板中景象的。该面 板不能用作编辑,但却可以呈现完整的动画效果。  Hierarchy【层次清单栏】:该面板栏主要功能是显示放在场景面板中所有的物体对 象。  Project【项目文件栏】:该面板栏主要功能是显示该项目文件中的所有资源列表。 除了模型、材质、字体等,还包括该项目的各个场景文件。  Inspector【监视面板】:该面板栏会呈现出任何对象的所固有的属性,包括三维坐 标、旋转量、缩放大小、脚本的变量和对象等等。  【场景调整工具】:可改变你在编辑过程中的场景视角、物体世界坐标和本地坐标 的更换、物体法线中心的位子,以及物体在场景中的坐标位置,缩放大小等等。  【播放、暂停、逐帧按钮】:用于运行游戏,暂停游戏和逐帧调试程序。  【层级显示按钮】:勾选或取消该下拉框中对应层的名字,就能决定该层中所有物 体是否在场景面板中被显示。  【版面布局按钮】:调整该下拉框中的选项,即可改变编辑面板的布局。  【菜单栏】:和其他软件一样,包含了软件几乎所有要用到的工具下拉菜单。 除了 Unity3D 初始化的这些面板而外,你还可以通过“Add Tab”按钮和菜单栏中的“W indow”下拉菜单中,增添其他面板和删减现有面板。特别是“Window”下拉菜单中的“Li ghtmapping”和“Occllusion Culling”面板对游戏的后期优化尤为管用。除此而外还有用 于制作动画文件的 Animation【动画面板】,用于观测性能指数的 profiler【分析器面 板 】, 用于购买产品和发布产品的 Asset Store【资源商店】,用于控制项目版本的 Asset Server 【资源服务器】,用于观测和调试错误的 Console【控制台面板】。 在【菜单栏】中包含有八个菜单选项:分别是 File【文件】、Edit【编辑】、Assets【资 源】、GameObject【游戏对象】、Component【组件】、Terrain【地形】、Window【窗口】、He lp【帮助】。这些是 Unity3D 中最标准的菜单选项卡,其各自又有自己的子菜单,表 1-1 中 列出了各个菜单栏以及它们所包含的下拉菜单及其译名,仅供读者参考。 主菜单 包含的子菜单 File【文件】 New Scene【新建场景】 Open Scene【打开场景】 Save Scene 【保存场景】 Save Scene as…【场景另存为…】 New Project… 【新建工程文件】 Open Project… 【打开工程文件】 Save Project 【保存工程文件】 Build Settings… 【创建设置】(这里可以设置你的游戏将要以 何种方式发布,发布的场景文件又包含那些) Build & Run 【创建并运行】( 这里以“Build Settings”里设 置好的方式,发布并运行游戏) Exit 【退出】 Edit【编辑】 Undo 【撤销上一步操作】 Redo 【恢复被撤销的操作】 Cut 【剪切】 Copy 【拷贝】 Paste 【粘贴】 Duplicate 【复制】 Delete 【删除】 Frame Selected 【在编辑场景中最大化显示被选中的物体】 Select All 【全选编辑面板中的所有物体】 Preferences… 【首选参数设置】 Play 【播放】(如果游戏已经开始播放,点此按钮代表停止播 放) Pause 【暂停】 Step 【逐帧播放游戏】 Load selection 【载入所选】( 与 “ Save selection”【 存储所选】 联合使用,你可以把它理解为一个临时的快捷键,帮你快速的 找到特定的以被存储的物体对象。) Save selection 【存储所选】( 与 “ Load selection”【 载入所选】 联合使用,你可以把它理解为一个临时的快捷键,帮你快速的 找到特定的以被存储的物体对象。) Project Settings 【工程文件设置】(包含了该工程项目的“Inp ut”【 热 键 】、“ Tags”【标签管理】、“ Audio”【 音 频 设 置 】、“ Ti me”【时间设置】、“Player”【播放器设置】、“Physics”【默认仿 真物理设置】、“Quality”【播放质量参数设置】、“NetWork”【 网 络工作参数设置】、“Editor”【编辑器设置】)“Script Execution Order”【脚本编译顺序设置】 Render settings 【渲染设置】(默认渲染参数设置,包括环境光, 周围的雾化程度,环境颜色等等一系列参数的设定) Network emulation 【网络仿真】(由于你制作的游戏将会在不 同的网络环境中工作,所以需要这个参数来模拟不同的网络工 作环境) Graphics emulation 【图形卡仿真】( 由 于 你制作的游戏将会在 不同的图形卡环境中工作,所以将需要这个参数来模拟不同硬 件条件下的游戏显示质量) Snap settings 【捕捉设置】( 和 3Ds Max 的“栅格和捕捉设置” 类似。) Assets 【资源】 Create 【创建】(包含有“Folder”【文件夹】、“JavaScript”【 Ja vaScript 编程脚本】、“C# Script”【 C#编程脚本】、“Boo Script” 【Boo 编程脚本】、“Shader”【着色语言】、“Prefab”【预置物体】、 “Material”【材质】、“Animation”【 动 画 】、“ Cubemap”【立方 体贴图】、“Lens Flare”【 镜 头 光 晕 】、“ Custom Font”【自定义 字 体 】、“ Render Texture”【渲染纹理】、“Physic Material”【 物 理材质】、“GUI Skin”【用户图形界面皮肤】) Show in Explor 【显示项目资源所在的文件夹】 Open【打开选中的资源】 Delete【删除选定资源】 Import New Asset... 【导入新的资源】 Import Package...【导入资源包】 Export Package... 【导出资源包】 Select Dependencies 【选择相关联的文件】 Export compressed audio file... 【导出压缩的音频文件】 Refresh 【刷新】 Reimport 【重新导入选中的资源】 Reimport All 【重新导入所有的资源文件】 Sync MonoDevelop Project 【与 Mono 项目文件同步】 GameObject【游戏项目】 Create Empty【创建空的游戏对象】 Create Other 【创建其他组件】(包含了“Particle System”【 粒 子系统】、“Camera”【摄像机】、“GUI Text”【图形用户界面文 本 】、“ GUI Texture”【图形用户界面图片】、“ 3D Text”【 3D 文 字 】、“Directional Light”【平行光】、“Point Light”【点光源】、 “Spotlight”【聚光灯】、“ Cube”【立方体】、“Sphere”【 球】、“ C apsule”【 胶 囊 】、“ Cylinder”【圆筒】、“Plane”【 平 面 】、“ cloth” 【布料】、“Audio Reverb Zone”【声音回响区域】、“Ragdoll..” 【布娃娃系统】、“Tree”【植被树系统】、“Wind Zone”【风的区 域】) Center On Children 【归位到子物体中心点】 Make Parent 【创建父集】(必须选择两个以上的物体才能使用 该命令,最先被选中的物体为父级对象,其余的对象都为该对 象的子集) Clear Parent 【取消父集】(取消被选中物体与它上一个父级之 间的父子级关系) Apply Changes To Prefab 【改变影响预制物体】(如果你在场 景中编辑的物体是从资源面板拖拽出的预制物体,默认的情况 下,你在场景面板中对物体做出的改变不会影响原先的预制物 体,除非你点击该按钮) Move To View 【移动物体到“Scene”视窗的中心点】 Align With View 【移动物体到“Scene”视窗的中心点,并且 与显示口正对齐,物体中心位于显示口的中心点】 Align View to Selected 【移动“Scene”视窗与物体对齐,并 且显示口的中心点位于物体的中心】 Component【组件】 Mesh 【网格】(“Mesh Filter”【网格填充】、“Text Mesh”【 文 字网格】、“Mesh Renderer”【网格渲染】、“ Combine Children” 【合并子物体】) Particles 【粒子系统】(能打造出非常棒的流体效果,是制作烟 雾、激光、火焰等效果的首选。“ Ellipsoid Particle Emitter”【 椭球粒子发射器】 ,“ Mesh Particle Emitter”【面片粒子发射器】, “Particle Animator”【粒子动画】,“World Particle Collider”【 世 界粒子碰撞机】,“Particle Renderer”【粒子渲染器】,“Trail Re nderer”【蔓延渲染】) Physics 【物理系统】(可使物体带有对应的物理属性) Audio 【音频】(可创建声音源和声音的听者) Rendering 【渲染】 Miscellaneous 【杂项】 Scripts 【脚本】( Unity 内置的一些功能很强大的脚本) Image Effects【图形渲染效果】(仅限专业版) Character【角色控制器】 Camera-Control 【摄像机控制】 Terrain【地形】 Create Terrain 【创建地形】 Import Heightmap - Raw... 【导入高度图】 Export Heightmap - Raw... 【导出高度图】 Set Resolution... 【设置分辨率】 Create Lightmap... 【创建光影图】 Mass Place Trees... 【批量种植树】 Flatten Heightmap... 【展平高度图】 Refresh Tree and Detail Prototypes 【刷新树及细节模型】 Window【窗口】 Next Window 【下个窗口】 Previous Window 【前一个窗口】 Layouts 【布局】 Scene 【场景窗口】 Game 【游戏窗口】 Inspector 【监视窗口】(这里主要指各个对象的属性) Hierarchy 【层次窗口】 Project 【项目文件窗口】 Animation 【动画窗口】(用于创建时间动画的面板) Profiler 【性能探测窗口】 Asset Store 【资源商店】 Asset Server 【源服务器】 Lightmapping 【灯影视图窗口】 Occlusion Culling 【遮挡剔除窗口】 Console 【控制台】 Help【帮助】 About Unity... 【关于 Unity】 Enter serial number... 【输入序列号】 Unity Manual 【Unity 手册】 Reference Manual 【参考手册】 Scripting Manual 【脚本手册】 What’s New 【最新功能】 Unity Forum 【Unity 论坛】 Unity Answers 【Unity 在线答疑】 Unity Feedback 【Unity 使用信息反馈】 Welcome Screen 【欢迎窗口】 Check for Updates 【查看升级】 Release Notes 【发行说明】 Report a bug【软件缺陷反馈】 表 1-1 1.2 Unity3D 的注册 为了保障你能够正常的学习和使用 Unity3D,请在第一次运行 Unity3D 的时候点击菜单 栏中的“Help”——>“Enter serial number”。这并代表真正的要你购买一个 Unity3D 产品, Unity3D 的学习版是完全免费的。在弹出的“Internet Activation”对话框中选择“Internet a ctivation”【互联网激活】或者是“Manual activation”【手动激活】单选项,笔者建议选择“I nternet activation”【互联网激活】方式,这种方式比较简便,然后点击“下一步”按钮。本 地的 Unity3D 会自动与官网的网站进行连接,在完全注册完毕之前请不要关闭图 1-2 所示的 对话框,然后在 Unity3D 的注册页面填写正确的注册邮箱地址、公司名字,然后选择正确的 授权方式。这里的邮箱地址请你务必认真填写,日后你可以凭此帐号购买 Unity3d 相应版本 专业版本,还可以用此帐号到资源商店购买相应的产品资源,以及发布你所开发的资源。在 一切注册工作做完之后,软件将自动关闭图 1-2 所示连接对话框,回到软件的编辑画面。 图 1-2 如果你在对 Unity3D 安装之后,不加以注册,那你的 Unity3D 很有可能只有 30 天的试 用期限。30 天试用完之后你的软件仍然处于未注册状态的话,系统将不允许你再试用 Unit y3D 产品。 1.3 Unity3D 的一个简单预览 每个 Unity3D 版本都会自带一个 demo 源文件。2.5 和 2.6 使用的是 island 的 Demo,在 3.0 到 3.3 的正式版中,自带的 Demo 就是网上展示的那款强大的第一人称射击游戏 Bootca mp,而 3.4 自带的是 AngryBots 次世代风格的射击游戏。在一般情况下,你只要第一次打开 Unity3D 就会看见自带的那个 demo 项目文件。但如果 Unity3D 并没有打开这个项目文件, 你可以在 Unity3D 里的“File”菜单下点击“Open Project…”,在随后弹出的“Unity – Pr oject Wizard”对话框中点击“Open Other…”按钮,在“C:\Documents and Settings\All Us ers\Documents\Unity Projects”这个路径下找到对应版本的 Demo 项目文件夹(下面主要以 3. 1 自带的 Bootcamp Demo 为例),选择并打开它。打开项目之后,在舞台场景面板中依然什 么都没有显示的的话,请在 Project【项目文件栏】双击场景文件 “Bootcamp”。稍等片刻 之后,该舞台场景的所有对象就可导入舞台场景面板中。导入成功之后效果如图 1-3 所示: 图 1-3 点击一下中间的播放按钮 做一下测试(如果你的机器配置不是太高,可能等待的 时间会稍长)。过了不一会,你就可以在 Game【动画面板】中看到一个正在运行的射击游 戏了。在这个游戏场景中,你能看到比其他游戏还要细腻的游戏画面,例如各个物体的实时 阴影如图 1-4 所示。 图 1-4 当然如果你的机器配置比较高,那你还可以点击“ESC”键——>点击“Graphics”按钮 来将画质进一步调高,如图 1-5 所示。 图 1-5 我们将画面质量调高之前,和画面质量调高之后的效果做一下对比,看看河水是不是真实了 许多。图 1-6 为画质调高前的效果,图 1-7 是画质调高后的效果。 图 1-6 画质调高前 图 1-7 画质调高后 1.4 Snap 与场景布置 无论你以前是从事 3D 建模的设计师,或者是 3D 程序的编程人员,在一个项目开始之 初都会遇见布置场景的问题,那么笔者本小节以官方的一个 Demo 为例,引领大家进入到 U nity3D 场景布置的快速学习当中去。 (1)、首先去官方网站的这个链接 http://unity3d.com/support/resources/tutorials/2d-gameplay-t utorial 去把这个 2DGameplayTutorialProject.zip 压缩包给下载下来,并解压缩到当前文件夹。 但笔者并不打算给大家讲述 2D Gameplay Tutorial 的教程,所以大家不需要下载 2DGamepl ayTutorial.pdf 这个文件,当然你也可以有选择性的下载下来学习。 (2)、 打开 Unity3D 软件,它可能会自动载入上一次的官方 Demo 项目文件。不管它,在软 件打开之后点击“File”——>“Open Project…”,在弹出的“Unity – Project Wizard”对 话框中找到“Open Other...”按钮,输入创建项目的文件夹地址,或者找到对应的文件夹之 后点击“选择文件夹”按钮,这时 Unity3D 就会自动载入该项目文件夹内的所有文件信息。 (3)、 载入完毕之后,它可能会自动打开 2D Platformer 游戏场景,你可以点击中间的播放 按钮 试着玩一下这款游戏,但最关键的还是要学着如何去布置场景,所以“File”——> “New Scene”新建一个场景,或者使用快捷键 Ctrl+N 也能够新建一个场景。 (4)、在新建的场景中,我到 Project【项目文件栏】中展开“Level Prefabs”文件夹, 点选预置物体“MovingPlatform”和预置物体“Pre-Assembled Platform”,这样我们可以 在它们的监视面板中的 Preview【预览】窗口中看到该物体的预览画面,并且你可以使用鼠 标随意旋转观测该物体,如图 1-8 所示。 图 1-8 (5)、 将 预置物体“MovingPlatform”和预置物体“Pre-Assembled Platform”拖入 Scene 【场景面板】或是 Hierarchy【层次清单栏】中,即可在游戏中显示这两个对象。但这两个 对象有可能超出了你在场景中可视范围,这时你可以用鼠标选中 Scene【场景面板】之后用 中间的滚轮拉近和推远视野。 (6)、 在确保这两个物体都在 Scene【场景面板】的可视范围内之后,选中物体对象,利用 移动工具 或使用快捷键 W,来移动该物体在场景中的位置。为了确保物体移动精确度, 你可以点击 Scene【场景面板】中的视角切换按钮 绿色 Y 箭头来将视角切换到顶 视图,来调整物体之间水平方向上的距离,以达到你想要得到的效果,如图 1-9 所示。又或 ○1 选中预 置物体 ②在 Preview 【预览】窗口 中观测物体 者点击蓝色的 Z 箭头来调整物体间竖直方向上的距离,以达到你想要得到的效果,如图 1-1 0 所示。 图 1-9 图 1-10 (7)、为了能精确无误的让两个模型进行顶点贴合,我们这里需要使用一个 Snap 的小技巧。 首先在选中要拖动的物体之后,按住 V 键不放,然后将鼠标放置到该物体需要贴合的顶点上 去,这时你会发现改物体的移动点也在随着鼠标移动,如图 1-11 所示。然后按住该顶点, 并拖放物体到另外一个物体的切合点上。你会发现两个物体的顶点会切合又快又精确,如 图 1-12 所示。另外如果你像保持切合点选取状态不变,而又不想总是按住 V 键不放的话,你 可以使用快捷键 Shift+V 的组合,来切换切合点选取状模式。 图 1-11 图 1-12 (8)、 同样的方法在竖直方向上再贴合一次,如图 1-13 所示。 图 1-13 (9)、 我们经常会在游戏里面遇见那种断格的路段,这种断格之间的距离往往呈现一个恒定 的数值,但如果我们要在监视面板里面一个一个的手动输入数字会显得格外的麻烦,所以这 里又要用到我们可爱的 Snap 了,但这里不是设置贴合顶点,而是间距,所以会有所不同。 在菜单栏中找到“Edit”——>“Snap Settings...”打开 Snap Settings【捕捉设置】面 板,这里面大家会看到一个 Move X 输入框、一个 Move Y 输入框、一个 Move Z 输入框、一 个 Scale 输入框和一个 Rotation 输入框,它们分别代表了当你按住 Ctrl 键盘来精确吸附移 动、缩放或旋转物体时的最小吸附单位。另外在最下面还有一排改变物体中心轴的按钮 ,其中的“Snap All Axes”代表改变所有的轴线,X 代表只改变 X 方向上的轴线,Y 代表只改变 Y 方向上的轴线,Z 代表只改变 Z 方向上的轴线。 下面我希望在 X 方向上每个 4 个单位的距离,就添加一个跳板对象“MovingPlatform”,我 们就可以这样来做。首先,将 Move X 输入框内的数字改为 4;其次,在 Scene【场景面板】 或是 Hierarchy【层次清单栏】中选中现有的“MovingPlatform”对象,然后在菜单栏中找 到“Edit”——>“Duplicate”或使用快捷键 Ctrl+D 来复制一个当前选中的对象“Moving Platform”,然后确保复制出来的“MovingPlatform”对象在选中的状态下,按住 Ctrl 键朝 X 方向上拖动,这时你就会发现这时物体的移动总是以 4 个单位的固定值来移动的。使用同 样的方法,你就可以复制出第二个、第三个、第四个……断格物体,如图 1-14 所示。 图 1-14 (10)、使用移动工具 或使用快捷键 W 移动摄像机,使摄像机的视口能观测到整个场景, 如图 1-15 所示。如果发现角度不对,还可以使用场景调整工具中的旋转工具 或使用快 捷键 E 来旋转摄像机到一个合适的角度,如图 1-16 所示。 图 1-15 图 1-16 (11)、 但这时候的场景略显得黑暗了些,我们在菜单栏中点击“Edit”——>“Render Se ttings”,然后去 Inspector【监视面板】将 Ambient Light【环境光】调节为最亮的纯白色, 如图 1-17 所示。 图 1-17 (12)、 到 Project【项目文件栏】中展开“Level Prefabs”文件夹,将预置物体“Charac ter (Lerpz)”拖放到场景中的钢板上面,然后点击运行按钮 ,在 Game【游戏面板】中 按下左右方向键,来回走一走;再按下空格键跳一跳看看,恭喜你的第一个小游戏就这样轻 松的诞生了!如图 1-18 所示。 图 1-18 第 2 章 地形系统与场景漫游 自三维游戏诞生之日起,地形系统就可以说是和游戏场景密不可分的一个部分。一套完 整的三维游戏地形不单单有连绵起伏的山峰、蜿蜒曲折的河流、不同地形所固有的纹理,还 会有种植在该地形上的花草树木等植被,以及影响影响这些植被运动的风力系统。幸运的是, Unity3D 引擎将这些元素都考虑进去了,让你在制作地形时游刃有余。本章主要就是来为你 讲述 Unity3D 的内置地形系统以及相关组件的。 本章导读 本章虽说是以地形系统为主轴,但由于地形上牵涉的东西非常多,所以在本章中也会出 ○1 菜单栏中 点击“Edit” ——>“Rend er Settings” ②在 Inspecto r【监视面板】 将 Ambient L ight【环境光】 调节为最亮 的纯白色 现包括树形系统,风域的使用等等相关联的知识存在。其主要目的就是为了大家能够全面的 搭建出自己理想的地形效果。 除了上述讲到的知识而外,在本章还会牵涉到利用 PhotoShop 通道的来为树木制作树 叶,如何创建并导入外部模型,材质球与 Shader 之间的关系等等方面的知识。由于涉及的 软件比较多,请大家在学习本章之前,将牵涉到的软件先安装好,以方便配备学习使用。 2.1 如何创建地形 (1)、 打开 Unity3D 软件,它可能会自动载入上一次的项目文件。不管它,在软件打开之后 点击“File”——>“New Project…”,在弹出的“Unity – Project Wizard”对话框中找到“P roject Location:”输入创建项目的文件夹地址,或者点击后面的“Browse…”选择一个文件 夹地址(注:已创建 Unity3D 项目的文件夹,不能当作新创建项目的文件夹来使用。并且非 空的文件夹也不能当作新创建项目的文件夹来使用。),然后在“Import the following packa ges:”中选择要导入的项目文件包,每个文件包都带有一些插件功能。由于我们第一次创建 项目文件,所以我们将所有的复选框都打上勾。但这样做会使得 Unity3D 在开始加载的时候 速度偏慢,等以后我们大家对各个包的作用熟悉了,在创建 Unity3D 项目文件的时候,我们 只勾选需要使用到的包就可以了,如图 2-1 所示。全部设置好之后,我们点击“Create”按 钮创建项目。 图 2-1 (2)、 在创建一个新项目之后,我们会看见新项目的各个面板中,只有 Project【项目文件 栏】包含了“Standard Assets”和“Standard Assets(Mobile)”两个文件夹,这两个文件夹里 面装的是之前所导入项目文件包里的所有文件。除此之外,其他版面都是空空如也。不要紧 万丈高楼平地起,咱们马上就利用文件包和系统功能来丰富各个面板。首先选择菜单栏上的 “Terrain”——>“Create Terrain”创建一个带有地形属性的平面,如图 2-2 所示。但我们 发现“Game”【动画面板】中依然没有任何画面。其实道理很简单,就像演唱会的实况直播。 你把场景全部搭建好了,演员请上场了,但没有加上摄像机,电视机前面的观众有如何能够 收到演出的信号呢? 图 2-2 (3)、 点击菜单栏上的“GameObject”——>“Create Other” ——>“Camera”,在场景中 创建一个摄像机,这时你就可以在 Game【动画面板】中观看到摄像机所观察到的景象了, 如图 2-3 所示。 图 2-3 (4)、 点击菜单栏上的“GameObject”——>“Directional Light”创建一个平行光来模拟自 然界中的太阳光。由于平行光是朝一个方向发射出的光芒,所以它往往与位置无关,只与它 的角度有关。使用场景调整工具的旋转按钮 将刚添加进来的“Directional light”调整到 一个合适的角度,如图 2-4 所示。 图 2-4 (5)、 选中刚创建的“Terrain”【地形】,如果你觉得场景中不是很好选择所需要的对象,那 么你还可以在“Hierarchy”【层次清单栏】选中你所需的对象,该栏中包含了所有场景面板 中的物体对象。在菜单栏上点击“Terrain”——>“Set Resolution…”弹出“Set Heightmap resolution”面板来调节地面的大小。在“Terrain Width”的后面将数字改成 500,然后再 在“Terrain Length”的后面将数字改成 500,设置好之后点击“Set Resolution”按钮来将 原来的地形改成 500*500 大小的地形。 (6)、 选中地面对象“Terrain”之后,我们会在“Inspector”【”Inspector”【监视面板】】中 马上发现与之对应的属性,包含有:Position【坐标】、Rotation【旋转量】、Scale【缩放尺寸】、 以及地面对象固有的“Terrain(Script)” 和 “Terrain Collider”。如图 2-5 所示: 图 2-5 (3)、 在“Terrain(Script)” 卷展栏中, 这个像画笔一样的按钮,是用来改变地面材质 的。我们点击它之后,可以在下面找到“Edit Textures…”按钮,点击“Edit Textures…” ——>“Add Texture”来到“Add Terrain Texture”面板,如图 2-6 所示。  “Splat”【材质接口】:添加材质的地方。  “Tile Size X”【X 方向上的展平尺寸】:材质在 X 方向上的展平尺寸。数值越大, 那么材质在 X 方向上的拉伸距离就越大,在 X 方向上的贴图数量就越少。反之数值 越小,那么材质在 X 方向上的拉伸距离就越小,在 X 方向上的贴图数量就越多。  “Tile Size Y”【 Y 方向上的展平尺寸】:材质在 Y 方向上的展平尺寸。数值越大, 那么材质在 Y 方向上的拉伸距离就越大,在 Y 方向上的贴图数量就越小。反之数值 越小,那么材质在 Y 方向上的拉伸距离就越小,在 Y 方向上的贴图数量就越多。  “Tile Offset X”【贴图在 X 方向的平移距离】  “Tile Offset Y”【贴图在 Y 方向的平移距离】 图 2-6 (4)、 单击“Splat”【材质接口】后面的圆圈,就可以为地面添加你所喜欢的材质了。选择 好之后请点击“Add”按钮来填入新材质,添加材质之后的地面如图 2-7 所示。如果你觉得 对贴图效果不满意,可以继续点击“Edit Textures…”——>“Edit Textures…”弹出“Edit Terrain Texture”窗口来继续修整地形贴图。 图 2-7 (5)、 继续点击“Edit Textures…”——>“Add Texture”来为单调的地形添加一个复合材 质。然后在“Brushes”中选择你想要的笔刷形状,在“Textures”中选中刚才添加进来的图 片,然后到“Settings”中设置“Brush Size”【笔刷尺寸】、“ Opacity”【不透明度】以及“T arget Strength”【目标强度】,接着在场景面板中刷出新材质的区域范围,如图 2-8 所示。 图 2-8 (6)、 在笔刷按钮的左边有 这三个按钮。第一个按钮可以刷出任意的高度的 山峰,并且配合“Brushes”中的笔刷形状,可以改变刷出任意形状的山峰,如图 2-9 所示; 第二个按钮可刷出具有高度限制的地形,但事先要对下面的“Settings”【设定】属性框中的 “Height”【高度】进行参数设定,刷出来的效果如图 2-10 所示;第三个按钮可以用来对比 较尖锐的山峰进行柔滑,使山峰看上去更平缓,图 2-11 展示了使用该笔刷对第一个按钮刷 出来的山峰进行平滑处理之后的效果图。如果你觉得现在山峰太高,或者说某处的山峰有些 多余。你可以按住 Shift 键不放,用刚才的笔刷进行反向凹刷,但你会发现当你反向刷到原 来地形水平线的时候,地形将不会继续下凹,这时你就需要确保地形在选中状态下点击菜单 栏上的“Terrain”——>“Flatten Heightmap...”打开“Flatten Heightmap”窗口,设置里面 的 Height 输入框的数字来提升地形系统的水平高度,这对制作沟渠等地形尤为有用,如 图 2 -12 展示了在设置高度后,用 Shift+山峰笔刷刷出来的沟渠地形。 ○1 点 击“ Edit Textures…” ——>“Add Texture”为地 形添加一个 复合材质 ②在“Brus hes”中选择 您想要的 笔刷形状 ③在“ Textures” 中选中刚才添 加进来的图片 ④设置“Brush Size”【笔刷尺 寸 】、“ Opacity”【不透明度】以 及“ Target Strength”【目标强度】 ⑤在场景面板 中刷出新材质 的区域范围 图 2-9 图 2-10 图 2-11 图 2-12 2.2 高度图的导入、导出 在 Unity3D 中除了有上一节制作地形的方法而外,还有一种更为专业的制作方式,这就 是高度图的导入与导出。在现代战争、地质勘探等对地形高度信息要求比较高的专业领域, 是允许我们像之前那样用手去描绘地形高度的。 Unity3D 的高度图只支持一种 Raw 的无损图片格式,而传统的 JGP 等格式的图片都会 在文件在创建的时候有一些数据被遗失,即通过“有损”的压缩方式来建立文件,这就是其 文件小的原因所在了。这样的损失放到较大地形上面作为高度图的时候,问题就会越发突出。 可惜的是 3D Max 制作出来的 HeightMap 并不支持 Raw 的格式,这让我们在为 Unity3D 打 造个性化的地形时,带来了一定困难。但这并不能成为我们继续学习它的障碍。 (1)、 首先我们得获得一个 Unity3D 的 HeightMap 来作为参考,所以根据前面一节所学习 到的知识,我们在新建一个 Terrain 之后,全部该地形在被选中的情况下,点击菜单栏中的 “Terrain”——>“Export Heightmap - Raw...”【导出高度图】,在弹出的“Export Heightm ap”窗口中将“Byte Order”选择为 Win,然后点击“Export”按钮,将其存储为 Terrain.ra w 的文档。 (2)、打开 3Ds Max 软件,在顶视图中创建一个与地形大小一致的平面,如图 2-13 所示: 图 2-13 (3)、 将平面修改为“可编辑多边形”,并使用“软选择”工具来制作地形,如 图 2-14 所示。 图 2-14 ①在基本体中 选中平面按钮 ②在参数卷展 栏中设置长度 和宽度与地形 保持一直,分 段数也和长 度、宽度一致。 ③在顶视图 中,拉出平面。 ①选中平面, 点击鼠标右 键,选择“转 换为:”——> “转换为可编 辑多边形” ②选中顶点 级别按钮 ③将“使用软选 择”复选框激活 (4)、选择需要移动的顶点,然后使用移动工具 或按下快捷键 W 来移动顶点,或者使 用绘制等方法来调整地形的高度,如图 2-15 所示。 图 2-15 (5)、 取消选择,在修改器列表中添加“UVW 展开”修改器,选择面级别,全选地形中的 所有面,同时在投影卷展栏中按下“平面贴图”按钮,对齐方向选择 Y 轴,如图 2-16 所示。 图 2-16 (6)、 点击“打开 UV 编辑器”按钮来修改贴图,为使我们的贴图能完整的和灰度信息对应 上,我们将面片拉伸到整个贴图空间,如图 2-17 所示。然后关闭 UV 编辑器。 ①修改器列表 中添加“UVW 展开”修改器 ②在投影卷展栏 中按下“平面贴 图”按钮,对齐 方向选择 Y 轴 图 2-17 (7)、 打开材质编辑器,选择一个默认的材质球,单机基本参数中的漫反射边上的按钮,在 弹出的列表中选择“渐变”,然后将 Color #1 调成白色,将 Color #3 调成黑色,如图 2-18 所示。设置好渐变颜色后单机返回上一级按钮。 图 2-18 (8)、 在 Blinn 基本参数卷展栏中,找到自发光参数,将其调节为 100,这是为了避免其他 光照影响我们地形渲染出来的灰度信息。 (9)、将材质球赋予我们的地形,确保顶视图在被激活的状态下,点击 F9 渲染我们地形的 高度图,最后得到如图 2-19 的效果。然后点击保存按钮 ,将高度图保存为 JPG 格式。 图 2-19 (10)、用 PhotoShop 同时打开刚才 Untiy3D 导出的 Terrain.raw 文件和 3Ds Max 刚才导出的 JPG 文件。这里需要注意的是,JPG 文件里面虽然只是灰度图,但它依然包含了 RPG 信息, 所以需要我们点击“图像”——>“调整”——>“灰阶”来去掉其他的颜色信息。并且 Ra w 不支持直接从 JPG 文件中直接讲图片拖入,我们必须在 JPG 文件中使用 Ctrl+A 全选图片, 然后才能使用鼠标将其拖入到 Raw 的各个通道中作为高度信息,如图 2-20 所示。 图 2-20 (11)、 将修改后的 Raw 文件保存,回到 Unity3D 中,确保地形 Terrain 在被选中的情况下, 点击菜单栏中的“Terrain”——>“Import Heightmap - Raw...”【导入高度图】,导入刚才我 们所保存的 Raw 文件,如图 2-21 所示。 Ctrl+A 全选图片, 使用鼠标将其拖入 到 Raw 的各个通道 中作为高度信息 图 2-21 (22)、 正如我之前所说,JPG 是一种有损格式的图片文件,当它被用于一些较大场景的地 形信息的时候,就会出现上图所示的问题,这里为了弥补这一缺憾,我们使用地形工具栏的 山峰平滑工具 来对这些不平地形进行处理吧,得到的效果如图 2-22 所示,然后再根据 我们之前学到的知识,将纹理从新铺一遍得到如图 2-23 所示的效果。 图 2-22 图 2-23 2.3 为地形添加树木和草 根据上一节的场景搭建,我们已经不难看到场景中宽阔无比的河道,连绵起伏的山丘, 以及一些特殊的地理纹理。但这样的场景缺乏了植物的生机盎然,本节主要来个大家讲述如 何给 Terrain 添加树木和花草。 (1)、首先确保地形对象 Terrain 在被选中的状态。然后到 Inspector【监视面板】中找到 具体的种草按钮 和种树按钮 。而 它们的设置方法与地形材质的设置方法十分雷同, 我们首先来看如何种树,先点击“Edit Trees..”按钮,在弹出的“Add Tree”面板中有两个 输入框,一个是“Tree”后面的接口用来制定树木模型,一个是“Bend Factor”后面的数字 可以让树在地形中模拟一个受强风吹拂之后弯曲的效果。在选中想要的树木模型之后,并确 定“Bend Factor”弯曲的数字之后,点击“Add”按钮退出“Add Tree”面板。接着你会在 树形按钮下看到如下参数值:  “Brush Size”【 笔刷大小】: 用于设置种树笔刷半径的大小。  “Tree Density”【 树之间的距离】:数值越小,刷出来的树木就越稀疏。数字越大, 刷出来的树木就越浓密。  “Color Variation”【 颜色差异】:数字越小,每棵树之间的颜色差异就越小。数 值越大,每棵树之间的颜色差异就越大。  “Tree Height”【 树木高度】:设置树木高度。  “Variation”【 高度差异】: 数字越小,每棵树之间的高度差异就越小。数值越大, 每棵树之间的高度差异就越大。  “Tree Width”【 树木宽度】:设置树木的宽度。  “Variation”【 宽度差异】:数字越小,每棵树之间的宽度差异就越小。数值越大, 每棵树之间的宽度差异就越大。 设置好适合的参数之后,利用笔刷工具,在场景中适合的位置按住鼠标左键不放来回拖放, 就可以种出树来了,效果如图 2-24 所示。 图 2-24 (2)、 点击种草按钮 ,在这个按钮的下面点击“Edit Details..”按钮,与种树的“Edit Trees..”不同,种草里面有两个添加按钮“Add Grass Texture”和“Add Detail Mesh”,这 是由于软件制作者出于性能优化方面的角度而考虑的,像草这种显示对象往往多而密,而 且 往往只能看到某个单面,所以“Add Grass Texture”以一种面片加一个带透明通道的贴图方 式来呈现,如图 2-25 所示,既大大的节约了资源又呈现除了最优秀的效果。但有些细节物 体,如石头往往不能以一个面呈现出它的 3D 透视感,而且这种物体相对来说也没有草这么 密集,针对这种细节的“Add Detail Mesh”就能很好的综合“Add Grass Texture”这一缺 陷,如图 2-26 所示。(注:在接下来的两个小节中,笔者还要专门为大家谈到这种两种资源 的制作方式) 图 2-25 图 2-26 这里,我们先以“Add Grass Texture”方法来向地形添加一些杂草,具体做法参照上面刷树 的方法,如果有不明白可以直接看看下一节会有详细介绍。但这里大家需要注意一下,Uni ty3D 在编辑模式下为了节约资源,提高游戏开发效率,采取了资源剔除的方法。如果你在 利用笔刷“种草”的过程中,没有看到你所“种”上去的草,这时你只需将画面拉近即可观 察到效果,如图 2-27 所示。 图 2-27 (3)、 地形系统 Terrain 的其他设置,点击 按钮,来设置地形上的风速、阴影等具体参 数,如图 2-28 所示。  “Pixel Error”【 像素错误】:该参数的数字越大,地形就越接进几何形状。反之 越接进你用笔刷的制作出来的形状。  “Base Map Dist”【 基础图形距离】:该参数越高,地形材质就越清晰,反之则越 模糊。  “Cast shadows”【 投射阴影】: 当该复选框打上勾的时候,地形将向周围投射阴影。 反之,如果复选框未打上勾,则无论灯光选用任何一种“Shadow Type”【阴影模式】, 该地形将不会作出阴影的投射。  “Draw”【绘制】:该复选框被勾选的情况,你在地形上构建的树木和草地才能被渲 染出来。反之,你无论绘制了多么精细的树木和草地,渲染器将不做出渲染。  “Detail Distance”【 草地距离】:实际上这里指的是草地在摄像机镜头前,能被 渲染出来的最远距离。  “Detail Density”【草地的密度】:值越大密度就越大,值越小密度也就越小。  “Tree Distance”【树木距离】:实际上这里指的是树木在摄像机镜头前,能被渲 染出来的最远距离。  “Billboard Start”【广告牌朝向 3开始】:在镜头前广告牌朝向的开始距离。  “Fade Length”【渐变长度】:在镜头前,广告牌朝向过渡到物体本身的网格朝向 的渐变长度。  “Max Mesh Trees”【树木被允许的最大网格数量】:超过这个数字的树木,Unity3 D 将对其进行自动的优化处理。 3 广告牌朝向,既是该网格的正面始终朝向摄像机。  “Speed”【风的速度】:经笔者反复测试,“Wind Settings”中的参数只对草坪有效, 对树木无效。并得到了 Unity3D 官方论坛的管理员“aNTeNNa trEE”的确认,将 在未来的版本修正这一问题。  “Size”【风力的大小】  “Bending”【草受到风的影响而扭曲的程度】  “Grass Tint”【 草坪的色调】 图 2-28 (4)、 Unity3D 为了能让开发人员快速的测试场景在游戏中的运行情况,在自带的导入包中 内置了许多组件,这其中就包含了用于场景漫游的第一人称组件“First Person Controller” 和第三人称组件“3rd Person Controller”,如果你对内置的导入包还不怎么熟悉,找不到这 两个组件存放在什么地方,那么你可以通过 Project【项目文件栏】最上面的查找输入框, 输入这两个组件的名字来查找它们,如图 2-29 所示。 图 2-29 (5)、 查找到该组件之后,将它直接拖放进场景点击测试按钮 ,你就可以控制一个手 持扳手的工人在 Game【动画面板】中进行漫游了。使用左右键来旋转方向,用上下键控制 行走,如图 2-30 所示。漫游的过程中,你可以清晰的看见你创建的草随微风缓缓摆动。 图 2-30 (6)、 再次点击测试按钮 ,退出动画模式。 2.4 草坪的制作与具体参数的设置 正如上一节所说的那样,在 Unity3D 中主要有两种方式可以制作草坪、石头等细节。 第一种就是用它自带的 Mesh,加上带“Alpha”通道的 PSD 作为草坪的材质文件,该方法 十分简单,也特别节省资源,是笔者极力推荐的一种方法。第二种方式是用 3Ds Max 或是 Maya 等建模软件,制作出草坪、石头等细节模型,并赋上材质然后拿给 Unity3D 调用,该 方法由于会增加草坪等细节的面片数量,加大计算机的计算负担,笔者建议大家更具具体情 况需求来使用,但尽量少用。下面我先为大家介绍一下第一种方法的详细制作步骤: (1)、 打开 Photoshop 或其他的图形制作软件,新建一个名字为“grassTexture”,大小为 25 6*256 像素大小的一张图片,分辨率设置为 600 像素/每英寸,如图 2-31 所示。当然,这个 设置标准不是唯一的,图像越大显示质量就越高,但计算机的消耗就越大。 图 2-31 (2)、 将你准备好的草坪贴图导入到现在的画布中,并利用 Ctrl+T 的键盘组合调整贴图的 大小和位置,与当前的画布所匹配,如图 2-32 所示。 图 2-32 (3)、 点击“通道”选项栏进入通道面板,在下面点击“创建新通道”按钮,新增加一个“A lpha 1”通道,在舞台面板中用白色的颜料绘制出小草的显示区域,如图 2-33 所示。这里 要切记的是,白色为要显示的区域,而黑色部分将会作为透明区域处理。 图 2-33 (4)、 将制作完成的图像保存为 PSD 格式的文件,放置到 Unity3D 项目文件夹的“Assets” 资源文件夹中。 (5)、 打开 Unity3D,选中地形对象“Terrain”,在监视面板中点选花草按钮 ,然后点 选“Edit Details..”按钮——>“Add Grass Texture”弹出“Add Grass Texture”对话框, 如图 2-34 所示。在“Detail Texture”后面的材质接口中,找到我们刚才保存的“grassTextu re”材质,然后点击“Add”按钮。当然你还可以在“Add Grass Texture”对话框中,对各 项参数进行一些个性设置,每个参数和具体的用法如下:  “Detail Texture”【 草坪的材质】:后面的接口用是用于添加材质的地方。  “Min Width”【 最小宽度】:因为草坪的 Mesh 会产生一定的随机大小,使得每团草 坪看起来有一定的差异,显得更真实,所以需要我们给这种差异设定一定的范围空 间。这里是 Mesh 的最小宽度。  “Max Width”【 最大宽度】:草坪 Mesh 变化范围的最大宽度。  “Min Height”【最小高度】:草坪 Mesh 变化范围的最小高度。  “Max Height”【最大高度】:草坪 Mesh 变化范围的最大高度。  “Noise Spread”【噪波范围】:该项的数值越高,则草坪的差异性变化就越剧烈。 反之值越小,草坪的差异性变化就越不明显。  “Healthy Color”【健康颜色】:草坪中有长势健康的青草,也有长势不良的枯草。 为了凸显这种差异,“Healthy Color”【健康颜色】用来制定健康草的颜色,而“D ry Color”【 干枯颜色】则用来指定枯草的颜色。  “Dry Color”【干枯颜色】 ○1 点击“通道”选项 栏进入通道面板 ○2 在下面点击“创建新通道”按 钮,新增加一个“Alpha 1”通道 ○3 在舞台面板中用 白色的颜料绘制出 小草的显示区域  “Billboard”【广告牌】:如果该复选框被勾选,则地面上草坪 Mesh 的正面始终面 向摄像机,反之则杂乱无章的摆放。 图 2-34 (6)、 这时你已经可以在“Details”下面看到我们刚才所绘制的草坪了,如图 2-35 所示。 为了能更进一步的绘制出你所想要得到的草坪效果,你还可以对“Details”下的滑动条进行 调整,这些滑动条的具体用法和参数如下:  “Brush Size”【 笔刷大小】: 草坪绘制区域的大小。  “Opacity”【 透明度】:这里实际上指的是绘制草团的数量,数值越大草团越多, 数值越小草团越少。  “Target Strength”【目标强度】:实际运用中,指的是草团的密度。数值越高密 度越大,数值越低密度越小。 图 2-35 (7)、 在“Brushes”下选择适合的笔刷,在“Scene”【场景面板】中进行对地面对象“Ter rain”进行草坪绘制,最后的效果如图 2-36 所示。 图 2-36 除了以上的方法而外,大家还可以使用模型制作法,这种方法可以当作场景细节的一 种补充,比方说制作场景的石头这些具有明显几何体外形的物体,具体的制作步骤如下: (1)、 用 3Ds Max 或 Maya 等工具制作出小草的模型,如图 2-37 所示。这里有两点需要注 意一下,第一:由于该模型必须赋予位图材质,才能作为 Unity3D 里面的草坪被渲染出来; 第二:由于 Unity3D 里面的草坪使用的是模型的本地坐标轴,而且在方向上与 3Ds Max 里 面的坐标轴方向不一致,所以在导出之前必须要“层次”面板中去调整模型的本地坐标轴方 向。 图 2-37 (2)、 点击“文件”——>“导出”,导出为 FBX 格式的模型文件到 Unity3D 项目文件夹的 ○1 确保物体在被选 中的情况下,点击 “层次”面板按钮。 ○2 点击“仅影响 轴”,使其高亮。 ○3 选择旋转按钮 ○4 输入数字 90,按 下回车。使得物体 的本地坐标沿着 X 轴旋转 90° “Assets”资源文件夹中。 (3)、 点选地形对象“Terrain”, 在监视面板中点选花草按钮 ,然后点选“Edit Details..” 按钮——>“Add Details Mesh”,弹 出“ Add Details Mesh”对话框,如图 2-38 所示。在“D etail”后面的模型接口中,找到我们刚才保存的小草模型“afsafdfa”,然后点击“Add”按 钮。当然你还可以在“Add Details Mesh”对话框中,对各项参数进行一些个性设置,每个 参数和具体的用法如下:  “Detail”【 小草的模型】:后面的接口用是用于添加模型的地方。  “Noise Spread”【 噪波范围】:该项的数值越高,则草坪的差异性变化就越剧烈。 反之值越小,草坪的差异性变化就越不明显。  “Random Width”【随机宽度】:该项数值越高,小草模型的宽度就越窄,反之越宽。  “Random Height”【随机高度】:该项数值越高,小草模型的高度就矮,反之越高。  “Healthy Color”【健康颜色】:草坪中有长势健康的青草,也有长势不良的枯草。 为了凸显这种差异,“Healthy Color”【健康颜色】用来制定健康草的颜色,而“D ry Color”【干枯颜色】则用来指定枯草的颜色。  “Dry Color”【干枯颜色】  “Render Mode”【渲染模式】:“Grass”模式为草坪模式,模型看起来很像平面, 这种模式的草坪会受到风的影响。“VertexLit”模式为顶点渲染模式,模型看起来 立体感很强,但草坪不会受到风力的影响,就像是一个一个独立的模型栽种在地面 上。 图 2-38 (4)、 这时你已经可以在“Details”下面看到我们刚才所创建的草坪模型了,如图 2-39 所 示。为了能更进一步的绘制出你所想要得到的草坪效果,你还可以对“Details”下的滑动条 进行调整,这些滑动条的具体用法和参数我在上一个方法中已经说过了,这里不再重复。 图 2-39 (5)、 在“Brushes”下选择适合的笔刷,在“Scene”【场景面板】中进行对地面对象“Ter rain”进行草坪绘制,最后的效果如图 2-40 所示。 图 2-40 2.5 树形系统 在 Unity3D 中创建树木也有很多种方式,比方说在利用建模软件给 Unity3D 建立树木 的模型,然后导入资源文件夹里给 Unity3D 直接引用。但这样的模型在 Unity3D 中没有自带 的 LOD(减面优化)功能,还必须有一定 Unity3D 使用基础,因为你在外部创建的模型导 入 Unity3D 之后,必须要对应树的部位设置树干和树叶的材质,比较的麻烦,非高手级别的 人使用这样的模型对 Unity3D 支持会很有限。所以笔者极力推荐大家使用 Unity3D 自 带 的“ T ree”【 树形系统】来创建树木。 (1)、 在菜单栏中找到“GameObject”——>“Creat Other”——>“Tree”创建一个系统自 带的“Tree 1”树到“Scene”【场景面板】的(0,0,0)坐标点,如图 2-41 所示。但这时候创 建的树木只有一个“Tree Root Node”【树根】和一根光秃秃的“Branch Group”【树干】。 图 2-41 (2)选中刚创建的“Tree 1”, 找到右边“Inspector”【监视面板】下的“Tree”卷展栏,默 认是将树根节点选中激活,如图 2-42 所示。 图 2-42 (3)如果不是默认将树根节点激活,请选择“Tree Root Node”【树根】,然后到“Distri bution”卷展栏中将“Tree Seed”【树种类型】设置为你觉得满意的一个数字,剩下的“A rea Spread”【根部区域】是指树木的根的范围,还有“Ground Offest”【接地偏移量】是 指树木插入地面的深度。 (4)、 继 续 在“Geometry”卷展栏中,设置“LOD Quality”【细化质量】为一个较低的数值, 这样树的面片会比较少,节省资源,但 你也可以设置一个较高的数值,那样模型会显得比较 精细。确保“Ambient Occlusion”【环境光遮蔽】4为勾选状态,这样可以提升树的显示效 果,但是如果不勾选的话会提升树木的渲染速度。设置“AO Density”【环境光遮蔽密度】 为一个合理的数字。 (5)、 在“Material”卷展栏中继续设置“Translucency Color”【表面的半透明颜色】, “Trans.View Dep.”【半透明视点依赖】,“Alpha Cutoff”【材质的透明程度】,“Shadow S trength”【阴影强度】,“Shadow Offset”【阴影的偏移量】,“Shadow Caster Res”【Shado w Caster 的分辨率】 (6)、 在 Tree 下面的组织结构视图中,选中“Branch Group”【树干】,接着在下面大家会 看到许多有关的属性,在下面我罗列了各个属性译名和使用方法。 Distribution【分布】  “Group Seed”【 树枝种类】:变化后面的数字,可得到树枝的随机样式。  “Frequency”【 频率】:实际上这后面的数字主要是控制树枝的数量。  “Distribution”【分布类型】:“Random”【随机】树枝会随意长在树干上;“Alter nate”【相互交错】树枝在树干上交错上升;“Opposite”【 对面】在这种方式下树 枝会长在树干对立的两边,像大鹏展翅那样;“Whorled”【 涡旋】在这种方式下树 枝会在某一个水平线上绕着树干生长。(该属性还可以用后面的贝尔赛样条曲线面 板进行调节)  “Twirl”【 旋转量】:只会在“Distribution”【分布类型】的非“Random”【随机】 方式下出现,代表了树枝绕树干旋转的角度。  “Whorled Step”【涡轮梯级】:只会“Distribution”【分布类型】的“Whorled” 【涡旋】方式下出现,代表了树枝涡轮旋转的增量。  “Growth Scale”【 生长的尺寸】:控制树枝的生长程度。(可用数值和后面的贝尔 赛样条曲线面板进行综合调节)  “Growth Angle”【生长的角度】: 控制树枝的生长角度。(可用数值和后面的贝尔 赛样条曲线面板进行综合调节) 4 “Ambient Occlusion”又被译作“环境光散射”、“环境光吸收”,AO 是来描绘物体和物体相交或靠近 的时候遮挡周围漫反射光线的效果,可以解决或改善漏光、飘和阴影不实等问题,解决或改善场 景中缝隙、褶皱与墙角、角线以及细小物体等的表现不清晰问题,综合改善细节尤其是暗部阴影, 增强空间的层次感、真实感,同时加强和改善画面明暗对比,增强画面的艺术性。 Geometry【几何形状】  “LOD Multiplier”【 细节级别参数】: 该参数用于控制树的细节质量。  “Geometry Mode”【 形状模式】:“Branch Only”【 仅 树枝】、“ Branch + Fronds”【树 枝+棕榈树叶的形状体】、“ Fronds Only”【 棕榈树叶的形状体】。  “Branch Material”【树枝的材质】:树枝的主要材质。  “Break Material”【破裂处材质】:树枝顶部断裂地方的材质。  “Frond Material”【棕榈树叶的形状体的材质:】:棕榈树叶的形状体的主要材质。 (仅当“Geometry Mode”【形状模式】为“Branch + Fronds”【树枝+棕榈树叶的 形状体】或“Fronds Only”【棕榈树叶的形状体】时才有效) Shape【具体的形状参数】  “Length”【 长度】: 调节树枝的长度。  “Relative Length”【 相对长度】: 如果勾选此开关,树枝的长度将会受到半径的 制约。  “Radius”【半径】:用于调节树干的半径大小,并且可以用后面的贝尔赛样条曲线 面板调节生长半径的逐步缩放。  “Cap Smoothing”【 顶端平滑度】:调节顶点端的平滑度,根据官方的说法,对制 作仙人掌很有用。  “Crinkliness”【 卷曲】:树枝被卷曲的程度。  “Seek Sun”【 向光性】:数值调节向上或向下弯曲,后面的贝尔赛样条曲线面板调 节树的弯曲细节参数。  “Noise”【 噪波】:树的外面表主要形体噪波,可用后面的贝尔赛样条曲线面板进 行微调。  “Noise Scale U”【水平方向上的噪波值】:越小的数值能让树枝在水平方向上看 上去更平缓,较大的值会让树枝在水平方向上的随机度更高。  “Noise Scale V”【竖直方向上的噪波值】:越小的数值能让树枝在竖直方向上看 上去更平缓,较大的值会让树枝在竖直方向上的随机度更高。  “Flare Radius”【 外张半径】:这是附加到主要半径上的一个树干外张数值。  “Flare Height”【 外张高度】: 定义了从多高开始外张。  “Break Chance”【 树枝断裂的可能性】:0 的话表示没有树枝会断裂,0.5 代表树 枝有一半的可能性会产生断裂,1 代表所有的树枝都会产生断裂。  “Break Location”【断裂位置】:该拖动条的长度与拖动标尺的比列代表断裂的范 围;而拖动条在拖动标尺上的位置,代表了树枝从什么地方开始断裂。 Fronds【棕榈树叶形状体的参数设置】(仅当“Geometry Mode”【形状模式】为“Branch + Fronds”【 树枝+棕榈树叶的形状体】或“Fronds Only”【棕榈树叶的形状体】时才有效)  “Frond Count”【 棕榈树叶的形状体的数量】: 控制树干上树叶的数量。  “Frond Width”【 棕榈树叶的形状体的宽度】: 控制树叶的宽度。  “Frond Range”【 棕榈树叶的形状体的范围】: 该拖动条的长度与拖动标尺的比列 代表树叶的范围;而拖动条在拖动标尺上的位置,代表了树叶从什么地方开始和结 束。  “Frond Crease”【树叶弯折度】:控制树叶向树干两边的弯折程度。 Wind【风】  “Main Wind”【 主风】: 主要风的参数,能让树产生一个摇摆效果。  “Main Turbulence”【 主要湍流】: 可让树枝产生一个随机运动,像蕨类植物和棕 榈树摆动那样的效果。  “Edge Turbulence”【 边沿湍流】: 用做主要湍流的补充。  “Create Wind Zone”【创建风域】:当参数设定完毕之后,点此按钮为该树添加一 个风域。 (7)、继续在 Tree 下面的组织结构视图下,点击增添树枝按钮 ,来为树干增添树枝。 (8)、点选新添加的树枝,在“Branch Group Properties”【树干组属性】的“Distribut ion”卷展栏下,先增大“Frequency”【树枝的数量】,接着调节“Group Seed”【树枝种类】 为你满意的一个数字。如果“Group Seed”【树枝种类】不能将树枝的位置调节到你认为满 意的一个地方,那么请你点亮“Move Branch”【移动树枝】按钮 ,并选中你认为不满意 的树枝进行位置的拖拽。或者点亮“Rotate Branch”【旋转树枝】按钮 ,对树枝进行 一定的角度调整。再或者点亮“Free Hand”【自由控制】按钮 ,来调整树枝的形体。 (9)、 分别选中树干和树枝节点,到“Geometry”卷展栏下找到“Branch Material”接口, 点击后面的圆圈按钮为树干和树枝添加表面材质,最后的效果如图 2-43 所示。 图 2-43 2.6 快速打造游戏树叶 前面我给大家讲过利用 PhotoShop 勾画草坪材质 Alpha 通道边沿的方法来创建草坪材 质,这种方法比较简洁实用。但如果遇到那种图片质量比较差的材质时,就有点力不从心了。 但不要紧,本节课程我就要教大家高效而快捷的打造游戏树叶。 (1)、下载一张你认为比较好看的树叶图片,用 PhotoShop 打开它,并将树叶周围不需要的 部分删除掉,形成一张背景透明的图片,如图 2-44 所示。 ○1 分别选中树 干和树枝节点 ○2 点击“Bra nch Materia l”接口后面 的圆圈按钮 ○3 选择树 干和树枝 所需要的 材质对象 图 2-44 (2)、 快捷键“Alt+F9”打开动作面板,点击右上角的展开按钮,如图 2-55 所示。在列表 中选中“载入动作”,接着去官方网站下载压缩包:http://unity3d.com/support/documen tation/Images/manual/AlphaUtility.atn.zip,解压出 “AlphaUtility.atn”文件,将其 载入进来。载入之后你可以发现多了一个名为“AlphaUtility”的文件夹,证明载入成功了。 图 2-55 (3)、 快捷键“Ctrl+J”复制当前图层,选中下面的原始图层,在菜单栏中找到“图层”— —>“修边”——>“去边”命令,使得图形的边沿得以优化,如图 2-56 所示。去边宽度根 ○1 点 击展 开按 钮 ○2 载入成功之 后,发现多了 一个名 为“ Alp haUtility”的 文件夹 据你具体的树叶图形大小而定。 图 2-56 (4)、 快捷键“Alt+F9”打开动作面板,展开“AlphaUtility”文件夹,在最下面选中“D ilate Many times”然后点击“播放选定的动作”按钮 。你可以多播放几次,已使得图片 能达到理想的效果,如图 2-57 所示。 图 2-57 ○1 复制图层之后,选 中下面的原始图层 ○2 在菜 单栏中 找到“图 层”— —>“修 边”— —>“去 边”命 令,使得 图形的 边沿得 以优化 (5)、 选中全部图层,快捷键“Ctrl+E”将它们全部合并。 (6)、点击“通道”面板,在最下面点击“创建新通道”按钮,增添一个“Alpha”通道, 这里不用对“Alpha”通道做任何的绘制,直接将完成好的 PSD 文件存储在 Unity3D 项目文 件夹的资源文件夹“Assets”中。 (7)、回到 Unity3D 编辑器中,在菜单栏中找到“Assets”——>“Create”——>“Mater ial”,在“Project”【项目文件栏】中新建一个材质球对象,并且在“Project”【项目文件 栏】中选中它,按下 F2 键将其更名为“LeafMaterial”。 (8)、 接着到“Inspector”【监视面板】中,找到 Shader 下拉菜单中的“Nature”——> “Tree Creator Leaves”,然后将我们制作好的树叶文件拖拽到“Base”基础材质接口里面 去,如图 2-58 所示。 图 2-58 (8)、 选中“Tree 1”树对象,然后在“Inspector”【监视面板】中的“Hierarchy”【 层次 结构】卷展栏下选中树枝节点,然后点击增添树叶按钮,如图 2-59 所示。 图 2-59 (9)、 选中新增添的树叶节点,在“Leaf Group Properties”【树叶组属性】中的“Distr ibution”卷展栏中,调节树叶的数量“Frequency”以及树叶的随机形态“Group Seed”。 (10)、继续在“Leaf Group Properties”【树叶组属性】中的“Geometry”卷展栏中,找 到材质接口“Material”, 点击后面的圆圈按钮,将我们之前定义好的“LeafMaterial”树 叶材质球添加进来,如图 2-60 所示。 ○1 选中“Tree 1”树对象 ○2 在 Inspector”【 监 视面板】中的 “Hierarchy”【 层 次结构】卷展栏下 选中树枝节点 ○3 点击增添 树叶按钮 图 2-60 (11)、最后树的效果如图 2-61 所示。 图 2-61 (12)、当然,既然是游戏,在创作的过程中不必拘泥于现实,大家完全可以带着几分童真, ○1 选中新增添的树叶节点 ○2 找到材质接口 “Material”,点击 后面的圆圈按钮 ○3 将我们之前定义好 的“ LeafMaterial”树 叶 材质球添加进来 去环境你童话世界里的树叶的模样,图 2-62 展示了笔者用星形树叶所制作出来的树木。 图 2-62 2.7 Wind Zone【风域】 虽然 Unity3D 地形上设置的风并不对树木产生任何力的影响,但 Unity3D 却为我们提 供了“Wind Zone”【风域】,创建它的具体方法如下: (1)、 在菜单栏下找到“GameObject”——>“Create Other”——>“Wind Zone”,创建完 毕之后会在场景的坐标(0,0,0)点看到一个类似十字箭头的线框,如图 2-63 所示。 图 2-63 (2)、 确保新创建的“WindZone”在被选中的情况下,观察右边的“Inspector”【监视面板】, 发现它具有如下属性:  “Mode”【 风域模式】:这里主要有两种模式:第一种是“Directional”【定向风】, 选择这种模式之后,该“WindZone”会对场景中所有的树模型系统创建的树产生一 个方向上的风,且风力的大小和方向与“WindZone”的位置无关,只与它的旋转角 度有关。第二种是“Spherical”【球形风】,选择该模式之后,“Wind Zone”【风域】 会以一种球体的模拟形态出现,只有在该球体范围之内的树形系统才会受到风力的 影响,越靠近球体的中心,风力就越强。  “Radius”【球形风的半径】:只有“Wind Zone”【风域】选着了“Spherical”【 球 形风】的模式之后才会有效,规定了“WindZone”影响的区域范围。  “Wind Main”【 主要风力】  “Wind Turbulence”【风的湍流】  “Wind Pulse Magnitude”【 风的脉冲大小】  “Wind Pulse Frequency”【风的脉冲频率】 一切工作完成之后,你就可以通过调节“Wind Zone”【风域】的相关参数,来控制树枝 和树叶的风动效果了,但要使“Wind Zone”【风域】对地形系统刷出来的树木有效,必须在 添加树木的时候设置“Bend Factor”参数。 2.8 Physics【物理】 在 Unity3D 中一共有五个物理碰撞器,它们分别是“Box Collider”【盒子碰撞器】,“ S hpere Collider”【球体碰撞器】,“Capsule Collider”【药丸碰撞器】,“ Mesh Collider” 【网格碰撞器】,以及“Terrain Collider”【地形碰撞器】(地形碰撞器为地形系统固有的 碰撞器,比较特殊。)用来模拟物体之间相互的碰撞效应。除此而外,Unity3D 还根据每种 不同的材质体表面具有不同的物理属性,而为碰撞器们设置专有的“Physic Material”【 物理材质】以模拟光滑平面上的摩擦、粗糙平面上的摩擦、刚性物体之间的碰撞、软性物体 之间的碰撞等等。 前面的 2.3 小节中我们已经完成了一个人物在地形场景中的简单漫游,但用心的朋友一 定会发现不少问题。比方说人物在径直走向树木的时候,会从树木的身体上穿过,这就是树 木没有加物理碰撞的所造成的,所以我们要在 Project【项目文件栏】找到树木的预置物体 模型,并为该模型添加一个碰撞器,具体做法如下: (1)、 利用 Project【项目文件栏】的查找工具查找预置物体“palm”,将其拖入 Scene【场 景面板】,选中该物体在菜单栏中点击“Component”——>“Physics”——>“Capsule Col lider”为树添加一个药丸碰撞器。确保树木模型在选中的情况下,在它的 Inspector【监视 面板】中展开“Capsule Collider”组件卷展栏,调节它的“Radius”【半径】大小刚好和树 干一样,调节它的“Height”【高度】刚好和树一样高,“Direction”【方向】为此“Y-Axis” 【Y 轴】不变,“Center”【中心点】和树木中心点一样,如图 2-64 所示。 图 2-64 (2)、选中添加好碰撞器的树木,在它右侧 Inspector【监视面板】下面找到该物体的名字 “palm”, 并 将其重命名为“palm2”,如图 2-65 所示。最后拖放回 Project【项目文件栏】 中,将 Scene【场景面板】中的“palm2”删除掉。选中地形系统“Terrain”,在它的树木 按钮 下点击“Edit Trees...”——>“Edit Tree”,在弹出来的“Edit Tree”窗口中 把“Tree”后面接口中对应的模型改为“palm2”,然后点击“Apply”按钮。 图 2-65 (3)、 点击播放按钮 ,如无意外场景中的人物在碰到树木的时候就不能前进了,如图 2 -66 所示。但如果任然会穿透的话,请您检查“Terrain”地形系统监视面板里面的“Terrain Collider”【地形碰撞器】,看看里面的“Create Tree Colliders”这一项是否打勾了。 ②将找预置物体 “palm”拖入 Sc ene【场景面板】 ○1 利用 Project 【项目文件 栏】的查找工 具查找预置物 体“palm” ③在菜单栏中点 击“Component” ——>“Physics” ——>“Capsule C ollider”为树添加 一个药丸碰撞器 ④展开“Capsule Col lider”组件卷展栏, 调节相应参数,以适 应树木的形态特征。 选中“palm”, 并将其重命 名 为“ palm2” 图 2-66 2.9 Shader 的使用和水平面的制作 上面的课程中给大家讲解的场景,中间的河道一直都是干涸的,在 Unity3D 中会有一些 内置的“Water”预置对象可供用户直接调用,除此而外用户还可以为自己制作的模型添加 水的材质,使得模型的表面具有水纹效果。本节笔者将会为大家先讲述预置物体的使用,然 后再隆重的介绍下怎样利用 Shader 定义的材质球,来让我们的模型具有不一样的水纹效果。 (1)、 在 Project【项目文件栏】的搜索框中输入搜索的关键字节“Water”, 凡是带有这 种 蓝色方框标志的对象,都是有关水的预置物体,可直接拖入场景中使用。但为了能让 它合符我们场景河道的形状和比例,我们必须用场景调整工具来改变预置物体的比例大小, 以及位置甚至是角度。图 2-67 展示了预置物体“Water4Example (Simple)”被拖放进场景 中,利用场景调整工具修改了尺寸和角度之后的效果。 图 2-67 (2)、 上面讲了最简单的一种制作水面效果的方法,但不是所有的水面都会像现在场景中的 河道那样是一条直线的。这里笔者还要给大家介绍另一种为模型添加水面材质的方法。首先 用 3DMAX 制作出河道的面片模型,并导出 FBX 文件到项目目录下的“Assets”文件夹中; 其次用我们之前学到的知识在地形系统上勾画出河道,并将面片模型拖入到场景对应的位置 处,得到的效果大致如图 2-68 所示。再次我们用鼠标右键点击 Project【项目文件栏】的 空白处“Create”——>“Material”新建一个材质球文件,选中它并按下 F2 键为其更名为 “MyWater”,然后到监视面板中将 Shader 后面的下拉框改为“FX/ SimpleWater”。最后我们 将河水的贴图放入“Fallback texture”接口,将河水的法线贴图放入“Normals”接口,得到 了如图 2-69 所示的效果图。 图 2-68 图 2-69 对于初学者在学习本节知识的时候,可能会有许多不理解的地方请直接跳过。因为在我 们后续的章节中会继续为大家讲解这些知识更为详细的部分。 2.10 简述 Shader【着色器】与显卡的发展历程 在PC个人用户电脑出现的早期,所有计算机的数据基本上都是用过CPU来运算,并将 计算的结果传输给对应的硬件进行处理,比方说显示器。但随着计算机图形处理技术的日趋 完善,原先仅仅依靠CPU来作为计算机图形处理的硬件已不能在满足计算机图形技术的发展 了,所以以ATI,NVIDIA为代表的图形显示卡制造商们,纷纷推出了自己带有GPU5功能的 显卡。但有了良好的硬件设备作为基础,还得将对应的软件技术匹配上去才行,在这样的历 史使命的驱使下,开发控制硬件良好运作,并能提供给程序员友好可编程的高级语言,成了 以编写软件见长的微软和专注计算机图形技术的Khronos工作组当仁不让的重任,(现在 还有英伟达公司的CG编程语言也算是GPU高级编程语言之一)。这也成就了当前 3D 计算机领域DirectX6和OpenGL7分庭抗衡的局面。所以DirectX和OpenGL会随着图形卡硬 件的不断升级和调整,而对应的做出不同的改变,以更好的对硬件产品进行操作。(当然现 在英伟达的CG编程也是不可小觑的一股力量,只是它诞生得比较晚,没两位前辈的名气大, 具体应用的例子也不太多) 打一个简单的比方来说,在图形渲染中,GPU 的可编程计算单元被称为着色器(shade r),着色器的性能由 DirectX 中规定的 shader model 来区分。GPU 中最主要的可编程单元是 顶点着色器和像素着色器。为了实现更细腻逼真的画质,GPU 的体系架构从最早的固定功 能流水线到可编程流水线,再到 DirectX 10 时代的以通用的可编程计算单元为主、图形固 定功能单元为辅的形式。在这一过程中,着色器的可编程性也随着架构的发展不断提高。所 5 简单来说 GPU 就是显卡上专门用于进行图形计算的硬件,功能和作用类似于 CPU,但它又区别于 CPU。 因为它主要是以图形计算为主。 6 DirectX,( Direct eXtension,简称 DX)是由微软公司创建的多媒体编程接口。 7 OpenGL,( Open Graphics Library,简称 OpenGL)主要是由 Khronos 小组发布的跨编程语言、跨平台 的编程接口的规格,它用于三维图象(二维的亦可)。是专业的图形程序接口,是一个功能强大,调用方便 的底层图形库。 以能运行比较高版本的图形卡,得到的游戏画面就会越精致,而受硬件限制不能运行高版本 的 Shader Model 的图形卡,在游戏画面的显示上,就会显得比较粗糙一些。你可以打开 Un ity3D,在菜单栏中选中“Edit”——>“Graphics Emulation”,在我的电脑上可以看到“No Emulation”,“ Shader Model 3”,“ Shader Model 2”,“ Shader Model 1”,“ DirectX 7”这几 个选项。默认选中的是“No Emulation”代表着你电脑上所能支持的最高版本的图形卡环境, 但你还可以选着其它的选项,来模拟该游戏在在较低硬件上所显示的图形效果。图 2-70、 图 2-71、图 2-72、图 2-73 分别展示了同一个场景在“Shader Model 3” ,“ Shader Model 2”, “Shader Model 1”,“ DirectX 7”环境中的渲染效果。大家可以看到图 2-70 和图 2-71 上的 阴影清晰可见,而由于“Shader Model 1”与“DirectX 7”所在的硬件并不支持动态阴影 技术“Shadow Map”,所以即便渲染器指定了这样的操作,但在这样的硬件上,只会将它 作为不可识别的忽略成分存在。 图 2-70 图 2-71 图 2-72 图 2-73 2.11 ImageEffects 概述以及水下效果的制作 首先我们先来熟悉和了解一下什么是 ImageEffects 组件。ImageEffects 组件是用于处理 游戏全部屏幕的特效组件,并且一般只用于摄像机对象上,在新改进的 Unity3.4 版本中一共 有 25 个 ImageEffects 组件,如下所示:  Antialiasing (Image Based)【抗锯齿】:可以使渲染出来的画面看着更柔和。  Bloom(supports HDR and Lens flares)【照亮边沿(支持 HDR 和镜头光晕)】:主要 用于增强一些发光体的边沿效果。  Blur【模糊】:使画面变得模糊。  Camera Info【摄像机信息】:对应处理摄像机的一些相关信息。  Color Correction【色彩校正】:修正渲染图像的色彩信息。  Color Correction(Ramp)【色彩校正(基于坡度图)】:使用具有颜色梯度的图片 来综合修正图像色彩信息。  Contrast Enhance(Unsharp Mask)【增强对比度(虚光蒙版)】:以蒙板的方式增 强画质的对比度。  Contrast Stretch【对比度扩展】:调节画质对比度的一个扩展组件。  Crease【折痕】:Crease 是一种常见的 NPR(非真实感绘制),能够增强可见物体的 轮廓线。  Depth of Field 3.4【景深 3.4】:用于体现游戏画面的景深效果。  Edge Detection(Color)【边沿检测(色彩)】:基于画质色彩在边沿画出一道黑色 的边沿线条。  Edge Detection(Geometry)【边沿检测(几何体)】:基于几何体在边沿画出一道 黑色的边沿线条。  Fisheye【鱼眼】:使画面体现出一个鱼眼镜头的画面效果。  Global Fog【全局雾】:为整个场景添加一个迷雾效果,这个新组件很好的弥补了 原来 Render Settings 里面 Fog 对 SkyBox 处理不了的缺陷。  Glow【辉光】:可以有效的提高太阳、光源、强光物体等等的外部光能模糊感。  Grayscale【灰度】:这是一个简单的将画面处理成灰度图的效果。  Motion Blur(Color Accumulation)【运动模糊(色彩积累)】:用于运动物体的一 种特殊动态模糊。  Noise【噪波】:一种类似电视机和录像机的一种雪花效果。  Sepia Tone【褐色调(复古色调)】:将画质调节为一种复古的褐色调。  Screen Space Ambient Occlusion【屏幕空间环境光遮蔽】:这是一种被广泛使用 到游戏引擎的里面的特效,通过采样像素周围的信息,并进行简单的深度值对比来 计算物体身上环境光照无法到达的范围,从而可以近似地表现出物体身上在环境光 照下产生的轮廓阴影。  Sun Shafts【体积光】:这是一个非常强大的技术,模拟了一些强光物体从周围产 生的光束和射线效果。  Tilt shift【移轴镜】:能够很好的模拟相机中聚集和散焦的效果,但对硬件的资 源消耗极大。  Tonemapping【色调映射】:用于映射 HDR【高动态范围】到 LDR【低动态范围】颜 色变化的过程。  Twirl【卷曲】:能将整个图像卷曲起来,就像旋窝一样被陷进去的感觉。  Vignette and Chromatic Aberration【晕映和色像差】:能够模拟一种昏暗,视力 模糊的视觉效果。  Vortex【旋涡】:和 Twirl 的效果很类似,但它扭曲的只是一个区域。 根据上述的一些组件以及它们所描述的功能,要打造水下镜头模糊的效果,我们这里选 择“Blur”【模糊】会非常不错。但又不能一开始就将它添置上去,因为当人在水面上的时 候,镜头应该是清晰的才对,所以得有一定判断才行。 (1)、 在菜单栏中点击“GameObject”——>“Create Other”——>“Cube”为场景添加一 个带“Box Collider”【盒子碰撞器】的立方体,并利用场景修改工具将他调整到和河道等长 宽高,如图 2-74 所示。 图 2-74 (2)、 但根据我们前面所学到的知识,如果为河道添加了这样一个立方体会出现两个问题: 第一,因为碰撞体的原因人物不能穿透立方体而进入河道;第二,整个河道看上去会是白茫 茫的一片。但不要紧,Unity3D 的开发团队早就料到了会有这样问题出现的一天,要使得人 物能够穿越立方体只要确保“Cube”在选中的情况下,来到它的 Inspector【监视面板】将 “Box Collider”中的“Is Trigger”复选框打勾,这样碰撞体就只作为碰撞检测来使用, 而允许任何物体轻松的穿越它。要解决第二个物体,只需要确保“Cube”在选中的情况下, 来到它的 Inspector【监视面板】将“Mesh Renderer”前面的组件启用复选框中的勾点掉 即可。如图 2-75 所示。 图 2-75 (3)、 在资源面板中鼠标右键点击 Project【项目文件栏】的空白处,“Create”——> “Javascript”新建一个 JS 脚本组件,选择它按下 F2 键将其重命名为“WaterEffect”, 并双击它打开脚本编辑器编写代码。 // OnTriggerEnter 是 Unity3D 内置函数,用于判断是否有其他的碰撞对象 Collider 进入该碰 撞体内,除此而外还有相关用于判断其他碰撞对象 Collider 持续呆在碰撞体内部的函数 OnTriggerStay,和判断是否有其他碰撞对象 Collider 离开该碰撞体内部的函数 OnTriggerExit function OnTriggerEnter (hit : Collider) { //判断如果进入碰撞体内部的目标是游戏人物,就为主摄像机“Main Camera”添加模糊效果 if(hit.gameObject.tag=="Player"){ GameObject.Find("Main Camera").AddComponent(BlurEffect); } } function OnTriggerExit (hit : Collider) { //判断如果离开碰撞体内部的目标是游戏人物,就为主摄像机“Main Camera”删除模糊效果 if(hit.gameObject.tag=="Player"){ Destroy(GameObject.Find("Main Camera").GetComponent(BlurEffect)); } } (4)、快 捷 键 Ctrl+S 保存代码,并将该代码拖放给场景中的碰撞检测对象“Cube”,如 图 2-76 所示。 图 2-76 (5)、运行测试一下效果,当人物在水面上行走时得到的效果如图 2-77 所示,当人物移动 到水下的时候得到的画面效果如图 2-78 所示。 将编辑好的碰撞检 测代码“WaterEffect” 拖放给场景中的碰 撞检测对象“Cube” 图 2-77 图 2-78 第 3 章 光 3.1 Unity3D 中的灯与光,几何体的“Mesh”【网格】和“Mesh Renderer”【网格渲染器】 在 Unity3D 中,你可以简单的认为光学是两门学科。第一门为发光物,主要指各种灯 光,当然还有带有光源材质的物体,但带有光源材质的物体需要烘焙。第二门为光的承载对 象,Unity3D 里面所有在场景里面可以看到的物体都可以被认为是光的承载对象。它们通过 自身材质与光的反射信息叠加,形成了在物体表面的色彩信息。在没有光的情况下,物体表 面利用软件内部的“默认渲染设置”来进行材质与光的叠加。 这里我们需要了解到计算机 3D 应用领域中,大部分的立体对象实际上都是由一些三角 面所构成的封闭几何体,然后再在这些几何体的表面上赋予一定的光学材质,便构成了我们 看见的,和现实生活十分类似的计算机立体图形。Unity3D 中也同样如此,我们在 Unity3D 菜单栏中点击“GameObject”——>“Create Other”——>“Cube”在场景中简单的创建一 个立方体对象。点击选中刚创建的“Cube”,在监视面板中我们可以看到,该几何体对象通 过由“Mesh Filter”【网格滤镜】和“Mesh Renderer”【网格渲染器】组成,如图 3-1 所示。 “Box Collider”【盒子碰撞器】主要对该物体的物理力学产生影响,前面简单解释和使用过。 图 3-1 “Mesh Filter”【网格滤镜】告诉计算机该物体的形状是什么样子的,规定了几何体的 表面信息,我们可以通过点击“Mesh Filter”【网格滤镜】卷展栏下“Mesh”接口后面的圆 圈,选择其他的网格来改变该物体的形体样貌。“Mesh Renderer”【网格渲染器】主要告诉 计算机该物体的表面应如何去进行渲染,主要包括“Cast Shadows”【阴影投射开关】如果 复选框勾选,则该物体将接受发光体的信息,对其他可视化的物体进行自身阴影的投射,反 之则不进行阴影投射;“Receive Shadows”【阴影接收开关】如果复选框勾选,则该物体将 接受来自其他物体投射到自身表面的阴影,反之该物体的表面将不接收任何物体投射到自身 表面的阴影信息;“Materials”【材质】,你可以把它看作一个特殊的类,存储了物体表面需 要显示的色泽信息,并且在“Unity3D”中由专门的着色语言“ShaderLab”进行可编程化的 控制,由于 Unity3D 对多维材质有着良好的支持,所以你可以增大“Materials”卷展栏中的 “Size”,为该可视化几何体多添置几个材质元素,然后对该物体的几何表面进行不同材质 球的渲染,如图 3-2 所示。 图 3-2 3.2 默认渲染设置 默认渲染设置是用于 Unity3D 灯光以及迷雾初始化的设定,你可以在菜单栏中点击“E dit”——>“Render Settings”,然后到“Inspector”【监视面板】中可看到如图 3-3 的属性。  “Fog”【 环境雾的开关】:如果被勾选,将在你的场景创建迷雾效果。  “Fog Color”【 环境雾的颜色】:只有开启环境雾的时候,才会有效果。  “Fog Mode”【 环境雾模式】:主要有三种模式“Linear”【线性的迷雾】、“Exponen tial ”【指数形式的迷雾】、“Exp2”【指数乘积的迷雾】,它们控制着迷雾不同的 淡出方式。  “Fog Density”【大雾的密度】:数值越大,密度越高。反之数值越小,密度越小。  “Linear Fog Start”【线性迷雾的初始值】:只有在“Linear”【线性的迷雾】模 式下才有效。  “Linear Fog End”【线性迷雾的结束值】:只有在“Linear”【线性的迷雾】模式 下才有效。  “Ambient Light”【环境光】:设定环境光的颜色,关乎你场景的整体颜色亮度。  “Skybox Material”【天空盒的材质】:当前渲染摄像机没有添加另外的天空盒组 件时,以该接口对应的材质进行天空渲染。  “Halo Strength”【 光晕强度】:设定各种灯光周围的那圈光环范围,只有灯光开 启“Draw Halo”【绘制光晕】开关的时候,才会有效果。  “Flare Strength”【 耀斑强度】:只有灯光添加了“Flare”【耀斑材质】才会有效。  “Halo Texture”【光晕材质】:只有灯光开启“Draw Halo”【绘制光晕】开关的时 候,才会有效果。  “Spot Cookie”【 聚光灯遮罩】:主要用于所有“Spot lights ”【聚光灯】的材质遮 罩,就是聚光灯默认的按照该材质图形样子来投射光影信息。 图 3-3 3.3 灯的各种类型以及属性参数 Unity3D 不像 3Ds Max 那样,有各种各样丰富的灯光。它只有三种基本灯光:“Point l ights”【点光源】、“Directional light”【平行光】、“Spot lights ”【聚光灯】,添加他们的方式 是在菜单栏中点击“Game Object”——>“Create Other”,然后找到对应的光源。创建成功 后,灯光对象将会以一个太阳的小标志呈现在舞台中。其中,“Point lights”【点光源】是一 个向四周发散的球形光,越靠近球体的中心,亮度就越强;“Directional light”【平行光】是 一个固定方向上发射的平行光线,该光源的投射效果与位置无关,只与它的变换角度有关。 “Spot lights ”【聚光灯】是一个类似手电筒效果的光源,它的光沿着一个给定的方向呈圆 台形状扩散,可以设定该光源圆台半径的大小。 专业版的 Unity3D 可以投射实时阴影,并且每一个灯可以调整阴影的属性。有关更多灯 的属性详见如下:  “Type”【 类型】: 当前灯光的类型。主要有三种类型:“Point lights”【点光源】、 “Directional light”【 平 行 光 】、“ Spot lights ”【聚光灯】。  “Range”【 范围】: 灯光的光束最远发射距离,仅对“Point lights”【点光源】和 “Spot lights ”【聚光灯】有效。  “Spot Angle”【 聚光灯角度】: 确定聚光灯的锥形角度,仅对“Spot lights ”【 聚 光灯】有效。  “Color”【颜色】:发出光线的颜色。  “Intensity”【强度】:光的亮度。“Point lights”【点光源】和“Spot lights ” 【聚光灯】默认值是 1,“ Directional light”【平行光】默认值是 0.5.  “Cookie”【遮罩】:用一个带 Alpha 通道的材质贴图来叠加光的明暗信息。如果灯 的类型是 “Directional light”【平行光】和“Spot lights ”【聚光灯】,那使用 的材质贴图必须是一个 2D 的纹理贴图。如果灯光的类型是“Point lights”【点光 源】,那使用的材质贴图必须是一个“Cubemap”【立方体贴图】。  “Cookie Size”【遮罩尺寸】:遮罩的尺寸大小。仅对“Directional light”【 平 行光】有效。  “Shadow Type(Pro Only)”【投影类型(仅对专业版有效)】:主要有三种类型:“N o Shadows”【没有阴影】这种模式将不产生任何实时阴影效果、“Hard Shadows”【硬 阴影】是利用周围像素来直接产生阴影,产生的效果比较生硬、“ Soft Shadows”【 软 阴影】利用周围像素的平均值来产生阴影,对计算资源的消耗极大。在选择投射实 时阴影的情况下,系统还提供了“Strength”【强度】用于调节阴影强度、“Resolu tion”【分辨率】调节阴影的清晰程度、“Bias”【偏移】控制阴影和实物之间的偏 移距离。如果你选择的是“Soft Shadows”【软阴影】那么你还可以进一步选择“S oftness”【柔软程度】和“Softness Fade”【 柔 软 淡出量】。  “Draw Halo”【 绘制光晕】:如果勾选,会在灯光周围产生一种球形光晕。  “Flare”【耀斑】:为灯光添加耀斑材质的地方。  “Render Mode”【渲染模式】:实际上这里主要是让系统判断该灯在整个场景中灯 效照明的重要性,一共有三种类型:“Auto”【 自 动 】、“ Important”【重要】、“Not Important”【不重要】。  “Culling Mask”【剔除选择】:未被勾选层的物体将不会受到该灯照明效果的影响。  “Lightmapping”【 灯光贴图的混合使用方法】:一共有三种类型:“Auto”【自动】 让系统根据摄像机与阴影之间的距离来自动判断该用何种方式显示阴影、“Realtim eOnly”【仅实时阴影】无论何种情况下都以该灯产生的阴影为主、“BakedOnly”【仅 烘焙阴影】如果有烘焙的灯光阴影贴图,以阴影贴图产生的阴影为主。 3.4 为场景添加光源 (1)、 选中场景中的摄像机对象,然后点选菜单栏中的“Component”——>“Rendering” ——>“Skybox”为摄像机添加一个天空盒。添加成功之后,你就能在摄像机的“Inspector” 【监视面板】中找到刚才添加的天空盒了。接着我们去 Project【项目文件栏】找到“Standa rd Assets”文件夹下的“Skyboxes”文件夹。这里面摆放了许多关于天空的材质球,你只需 要选中一个你喜爱的天空材质球,并拖放给摄像机里的天空盒【Skyboxe】的材质属性【Cu stom Skybox】,就可让场景的天空布满这种材质效果,如图 3-4 所示。 图 3-4 (2)、 选中场景中的光照对象“Directional light”,然后在它的“Inspector”【监视面板】中 找到“Flare”,并点选它后面的圆圈。在它弹出的“Select Flare”对话框中选中双击“Sun” 这种光照效果,如图 3-5 所示。这样就可以使得你在动画模式中清楚的看见平行光所在的位 置。 图 3-5 (3)、 为了让场景更加的逼真,我们还可以为场景添加光照阴影效果。具体的做法如下:选 中光照对象“Directional light”,在它的”Inspector”【监视面板】中找 到“ Shadow Type”【阴 ○1 找到“Flare”, 并 点选它后面的圆圈 ○2 在它弹出的“Select Flare”对话框中选中双击 “Sun”这种光照效果 影模式】,它默认的是“No Shadows”【没有阴影】,你可以将它改成“Soft Shadows”【软 渲染阴影】或是“Hard Shadows”【硬件渲染阴影】。“ Soft Shadows”【 软渲染阴影】以消耗 CPU 的计算为代价来产生阴影效果,这种模式运行速度较慢,但对于硬件比较落后的使用 者是唯一的选择。“Hard Shadows”【硬件渲染阴影】可利用新一代 GPU 的显卡加速功能来 为游戏进行阴影效果的渲染处理,其运行速度比较快,渲染效果也比较理想。但无论你选择 哪一个选项,动画场景的物体都会相对于阳光产生阴影效果。如图 3-6 所示: 图 3-6 (4)、 所有的场景效果调试完毕,按下 Ctrl+S 来保存场景文件,取名叫做“terrain”以便日 后调用。如果保存成功,你会在你项目的“Project”【项目文件栏】中看到一个这样的文件 。 3.5“Flare”【耀斑材质】的制作 (1)、 点击菜单栏上的“Assets”——>“Create”——>“Lens Flare”或用鼠标右键点击“P roject”【项目文件栏】——>“Create”——>“Lens Flare”。创建成功以后你会在“Project” 【项目文件栏】中看到一个名为“New Flare”星形状的材质对象。选中它之后,到“Inspe ctor”【监视面板】你可以看到如图 3-7 的属性。  “Flare Texture”【 耀斑材质】: 放置耀斑材质的接口处。  “Texture Layout”【 材质布局】: 一共有“1 Large 4 Small”、“ 1 Large 2 Mediu m 8 Small”、“ 1 Texture”、“ 2x2 grid”、“ 3x3 grid”、“ 4x4 grid”这六种模式。 这六种材质的布局图可详见 Unity3D 的官方网站的说明页面 http://unity3d.com/ support/documentation/Components/class-Flare.html。  “Elements”【 元素】:这里规定了该耀斑材质将会引用到的材质索引的数量以及具 体索引的设置。  “Use Fog”【 迷雾距离开关】:当被开启时,耀斑会受到迷雾的影响。距离远时, 将被迷雾所掩盖。 图 3-7 (2)、 打开 PhotoShop 作图软件,到管网查看一下“1 Large 4 Small”的布局。新建一个 宽度 120 像素、高度 240 像素的图片,背景颜色为黑色。这是由于如果我们以 60 像素作为 一个耀斑元素的大小的话,按照“1 Large 4 Small”的布局相乘下来就正好是宽度 120 像 素、高度 240 像素的图片,而黑色背景是为了在 Unity3D 中做材质的背景透明处理。 (3)、 快捷键“Ctrl+R”打开面板标尺,用鼠标左键按住上方标尺和左方标尺,拖拽出图形 制作的参考线,如图 3-8 所示。接着在对应的区域画出耀斑的贴图,画完之后将 PSD 保存 为到项目文件的资源文件夹“Assets”下。 图 3-8 (4)、 选中前面新建的“New Flare”,“Inspector”【监视面板】中点选“Flare Texture”后 面的圆圈,选中刚才我们保存的“yaoban.psd”文件,如图 3-9 所示。 图 3-9 (5)、 将“Elements”【 元素】卷展栏下的“Size”设置为 5,这时会发现除了原来的“Ele ment”又多了 4 个“Element”卷展栏出来,利用每个“Element”下的“Image Index”可以 对相应的耀斑材质进行索引,就拿我现在这个例子来说吧,如果我这里索引的是 0 那么对应 的元素就是五角星,如图 3-10 所示。“Image Index”为 0 卷展栏下的“Position”规定了五 角星的偏移量,“Size”规定了五角星耀斑的尺寸大小,“ Color”规定了五角星耀斑的颜色, “Use Light Color”规定了五角星耀斑是否需要和灯光的颜色进行叠加,“Rotate”规定了 五角星耀斑是否在镜头前进行旋转,“ Zoom”规定了五角星耀斑的尺寸大小是否随着与镜头 距离的改变而改变,“Fade”规定了五角星耀斑的光照强度是否随着与镜头距离的改变而改 变。其他的耀斑设置与此设置雷同,只是他们对应着不同的索引。 ○1 在“Project”【项目 文件栏】里面,选中前 面新建的“New Flare” ○2 “Inspector”【监视面 板】中点选“ Flare Texture”后面的圆圈 ○3 选中刚才我们保存 的“yaoban.psd”文件 图 3-10 (6)、 选中场景中的光照对象“Directional light”,到“Inspector”【监视面板】中点击“Fl are”后面的圆圈,将耀斑材质换成我们新添加的“New Flare”这个耀斑材质,最后的效果 如图 3-11 所示。 图 3-11 3.6 各种灯光的“Light Cookie”【 灯光遮罩材质】的制作 “Light Cookie”【 遮罩材质】是用一个带 Alpha 通道的材质贴图来叠加光的明暗信息, 制作方式也比较简单。作图时只要用浅白色表示透光的部分,用深黑色表示遮罩住的部分即 可。但制作好的材质图,在导入 Unity3D 之后要作出一定调整才行。 (1)、 现在请你先用 PhotoShop 简单的制作一副遮罩图用于灯光阴影的投射,制作好之后将 其保存到 Unity3D 工程项目的资源文件夹“Assets”里面。 (2)、 打开 Unity3D,在“Project”【项目文件栏】中选中我们刚才保存在这里面的材质文 件,可以在“Inspector”【监视面板】看到如图 3-12 所示的属性。  “Aniso Level”【 参差水平】: 主要调节位图的显示质量,数值越高位图的质量就 越好,但计算机的消耗就越大。  “Filter Mode”【 滤镜模式】: 用于设定材质图片与图片之间的过渡和结合方式。  “Wrap Mode”【 位图的覆盖模式】:这里主要有“Repeat”【平铺】、“Clamp”【拉伸】 两种模式。  “Texture Type”【材质类型】:这里主要有“Texture”【普通材质】、“ Normal Map” 【凹凸材质】、“GUI”【图形用户操作界面材质】、“Reflection”【反光材质】(反光 材质主要用于模拟物体对周围环境光的反射,所以它存在的形式是一个“CubeMap” 【立体盒材质】)、“ Cookie”【遮罩材 质 】、“ Advanced”【 高级材质】。  “Generate Alpha from Greyscale”【图形的透明通道开关】 图 3-12 (3)、 将“Wrap Mode”【位图的覆盖模式】设置为“Clamp”【拉伸】,然后将“Texture Ty pe”【材质类型】设置为“Cookie”【 遮罩材质】,确保“Generate Alpha from Greyscale”【 图 形的透明通道开关】被勾选。 (4)、选中场景中的灯光对象“Directional light”,在“Inspector”【监视面板】点击“Cook ie”【遮罩材质接口】后面的圆圈,选着我们刚才制作好的材质“liStart”,这时你就可以在 场景中看到由灯光投射下来的一个星形阴影了,如图 3-13 所示。 图 3-13 (5)、 在“Project”【项目文件栏】中重新选中“liStart”对象,到“Inspector”【监视面板】 中将“Wrap Mode”【位图的覆盖模式】改为“Repeat”【平铺】,可以看到被重复投射的光 影效果如图 3-14 所示。但这里需要注意一下,由于“Directional light”【平行光】和“Spot light”【聚光灯】都是方向性光源,所以在使用这种“单面”遮罩材质的时候,不会有任何 问题,但“Point light”【点光源】的光线是向四周发撒的,所以在设置材质的类型时,就必 须制定专门的“Cubmap”【立体盒材质】。使得光的四周都能投射出阴影效果。 图 3-14 (6)、 在“Project”【项目文件栏】中重新选中“liStart”对象,到“Inspector”【监视面板】 中将“Light Type”【 灯光类型】改为“Point”【 点光源】,并在“Mapping”【贴图模式】中 选择一个合适的贴图类型。设置完毕之后,点击“Apply”按钮,让 Unity3D 自动将“liStar t”生成对应的材质类型。如果生成成功的话,就可以在“Project”【项目文件栏】看到我们 的材质变为了一个蓝色盒子的样子 。 (7)、 选中场景中的灯光对象“Directional light”,在“Inspector”【监视面板】中将它的“T ype”【灯光模式】改为“Point light”【点光源】,并点击“Cookie”【 遮罩材质接口】后面的 圆圈选择我们刚才生成的遮罩材质“liStart”,最后得到如图 3-15 所示的效果。 图 3-15 3.7 Cubemap 的制作以及“Skybox”【天空盒】 在计算机图形编程中,对于模拟现实生活中的光运算,是最为复杂的计算科学。为了 能简化模拟物体表面反射光和无限远处场景的计算机图形渲染运算,图形卡编程学里面运用 了“Cubemap”的运算方式,这是一种将无限远处的场景想象成 6 张静态图片,围绕成一个 立方体的盒子,而视觉观测者就身处在这个立方体的正中间。这虽然不能达到现实生活中实 时模拟无限远处的场景,但却大大简化了算法,节省了计算机的运算开支。 在 Unity3D 中制作“Cubemap”有好几种方法,你可以用现实生活中的全景相机捕捉到 周围场景的照片后,将它切割成上、下、左、右、前、后六张图片,导入到 Unity3D 中。再 在“Project”【项目文件栏】中新建一个“Cubemap”组件,然后将切割好的图片放入到组 件对应的接口上去就可以了,这是其中的一个方法。或者你的场景是在 3Ds Max 这些软件 里面完成的话,那你可以使用 VRay 360°摄像机渲染的方法输出全景图,然后再用 PhotoS hop 进行切割后放入 Unity3D 的“Cubemap”组件。但这些方法都是笔者不推荐的,在 Unit y3D 中有一个专门的制作“Cubemap”的函数“Camera.RenderToCubemap”,下面大家只需 要跟着笔者的步骤走,就可以在 Unity3D 的场景中制作出一个带反射贴图的小钢球了。 (1)、 点击菜单栏中的“Help”——>“Scripting Reference”打开脚本参考页面,在搜索栏 中输入“RenderToCubemap”然后点击回车,点击超链接关键字“Camera.RenderToCubema p”进入该脚本的详细页面,如图 3-16 所示。 图 3-16 (2)、 将下面这段灰色区域里面的代码全部复制,然后在 Unity3D 中用鼠标右键点击“Proj ect”【项目文件栏】——>“Create”——>“Javascript”新建一个 JS 脚本,将代码复制给新 建的 Javascript 文件保存,并记得将该脚本文件更名为“RenderCubemapWizard”,因为它这 里它用了一个类继承的代码“class RenderCubemapWizard extends ScriptableWizard”。 // Render scene from a given point into a static cube map. // Place this script in Editor folder of your project. // Then use the cubemap with one of Reflective shaders! class RenderCubemapWizard extends ScriptableWizard { var renderFromPosition : Transform; var cubemap : Cubemap; function OnWizardUpdate () { helpString = "Select transform to render from and cubemap to render into"; isValid = (renderFromPosition != null) && (cubemap != null); } function OnWizardCreate () { // create temporary camera for rendering var go = new GameObject( "CubemapCamera", Camera ); // place it on the object go.transform.position = renderFromPosition.position; go.transform.rotation = Quaternion.identity; // render into cubemap go.camera.RenderToCubemap( cubemap ); // destroy temporary camera DestroyImmediate( go ); } @MenuItem("GameObject/Render into Cubemap") static function RenderCubemap () { ScriptableWizard.DisplayWizard.( "Render cubemap", "Render!"); } } (3)、由于该脚本是用在编辑器内使用的编辑器类文件,我们还得鼠标右键点击“Project” 【项目文件栏】——>“Create”——>“Folder”新建一个文件夹,并将其改名为“Editor”。 然后将我们刚才新建的 JS 文件“RenderCubemapWizard”拖放到“Editor”文件夹里面来。 这时你点击菜单栏中的“GameObject”会发现多了一个“Render into Cubemap”选项,这 是上段代码所添加上去的。 (4)、点击菜单栏中的“GameObject”——>“Create Other”——>“Sphere”新建一个球 体,并将其拖放到舞台的正中间。 (5)、 鼠标右键点击“Project”【项目文件栏】——>“Create”——>“Cubemap”新建一个 “Cubemap”组件。 (6)、点击菜单栏中的“GameObject”——>“Render into Cubemap”打开“Render cube map”面板,在“Hierarchy”【层次清单栏】将新建的“Sphere”拖放到“Render From Po sition”后面的接口上,将新建的“New Cubemap”拖放到“Cubemap”后面的接口上,然 后点击“Render!”按钮,即可为小球烘焙出一个用于模拟反射的“Cubemap”贴图。如图 3 -17 所示。 图 3-17 (7)、 鼠标右键点击“Project”【项目文件栏】——>“Create”——>“Material”新建一个 材质球组件。并且选中新建的材质球,到监视面板中将它的 Shader 改为带反射通道的“Ref lective/Diffuse”,然后将渲染好的“New Cubemap”拖入到“Reflection Cubemap”接口, 如图 3-18 所示。 ○1 在“Hierarchy”【层次清单栏】 将新建的“Sphere”拖 放 到“ Render From Position”后面的接口上 ②将新建的“New Cubemap”拖 放到“Cubemap”后面的接口上 ③点击“Render!”按钮 图 3-18 (8)、 将做好带反射的材质球“New Material”拖放给“Hierarchy”【层次清单栏】中的“S phere”,最后得到如图 3-19 的效果。 图 3-19 这种六面贴图的技术除了用于模拟反射光外,还常常用于模拟无限远处的背景。在 Uni ty3D 中用于模拟无限远处的背景的接口被称作“Skybox”,在前面小节我简单讲了运用组件 给摄像机添加“Skybox”方法,下面我来为大家详细说说 Skybox 的制作方法以及利用“Re nder Setings”为场景添置背景。具体步骤如下: (1)、 先准备六张天空盒的材质贴图,放到项目目录的资源文件夹“Assets”内。然后在 U nity3D 内分别选中导入的贴图,到监视面板中将它们的“Wrap Mode”【包裹模式】从原来 “Repeat”【平铺】改为“Clamp”【拉伸】,然后点击“Apply”按钮。如图 3-20 所示: ○1 将它的 Shader 改 为带反射通道的“R eflective/Diffuse” ②将渲染好的“New Cubemap”拖 入到“Reflection Cubemap”接口 图 3-20 (2)、 鼠标右键点击“Project”【项目文件栏】——>“Create”——>“Material”新建一个 材质球组件。并且选中新建的材质球,到监视面板中将它的 Shader 改 为“ RenderFX/Skybox”, 然后将六张准备好的贴图放置到对应的接口“Front(+Z)”【 前 】、“ Back(-Z)”【后】、“Lef t(+X)”【 左 】、“ Right(-X)”【 右 】、“ Up(+Y)”【 上 】、“ down(-Y)”【 下 】。如图 3-21 所 示: 图 3-21 (3)、 点击菜单栏中的“Edit”——>“Render Settings”,到监视面板中找到“Skybox Mat erial”接口,将刚才新建好的材质球拖放到该接口上,最后得到如图 3-22 所示的效果。 图 3-22 使用“Render Settings”【默认渲染设置】设置的天空盒最大的好处就是,它会对场景 中所有的摄像机都起作用。而使用组件设置 Skybox 的好处在于它只针对个别摄像机起作用。 这里由于小球周围的环境发生了改变,建议将 Cubemap 重新渲染一遍。 3.8 自发光物体的烘焙与 LightMapping 在 Unity3D V3.0 以后的版本中,对渲染引擎做了许多的优化,其中就包括非常重要的 “LightMapping”。“LightMapping”主要用于将游戏场景中所有物体的光影信息烘焙成静态 的图片,而不用计算机实时去计算他们,从而大大的提升游戏的运行效率。不但如此,“Li ghtMapping”对烘焙后的图片信息,还会有针对性的进行优化处理,使烘焙的场景更加的唯 美。它还可以对带有自发光材质的物体,进行周围光的真实处理,从而打造出 Unity3D 场景 中的自发光物体。详细的制作步骤如下: (1)、 在 3Ds Max 中将路灯的灯泡单独的分离为一个对象,如图 3-23 所示。 图 3-23 (2)、 将制作好的模型导出成 FBX 格式,到项目目录的资源文件夹“Assets”下。然后打 开 Unity3D,简单搭建一个地形场景之后,再在“Project”【项目文件栏】中选中我们刚导 入的路灯对象,并把它拖入“Scene”【场景面板】。 (3)、 然后在“Hierarchy”【层次清单栏】中找到我们刚才拖入的路灯对象,并点击它左边 的三角箭头,将其展开选中我们刚刚分离出来的灯泡对象“light”,将它拖到整体的外面来, 这时 Unity3D 可能会弹出“Losing prefab”的警告框,提示这样做可能会让场景中的模型 对象与预制对象失去关联,这里我们点击“Continue”按钮。这样做的目的是为了让它的材 质不再和路灯的整体材质关联。 (4)、点击菜单栏上的“Assets”——>“Create”——>“Material”,新建一个材质球“N ew Material”。选中该材质球以后找到“Inspector”【监视面板】中“ Shader”后面的下拉框, 点选“Self-Illumin”——>“Diffuse”,接着调节“Emission(Lightmapper)”【灯照强度】后 面的数值,如图 3-24 所示。 图 3-24 (5)、 将定义好的材质球“New Material”拖放给“Hierarchy”【层次清单栏】当中分离出 来的灯泡对象“light”,如图 3-25 所示。 图 3-25 (6)、将灯泡对象“light”重新拖回到路灯对象的整体中去,并点选路灯对象,在“Inspe ctor”【监视面板】中勾选“Static”复选框,在弹出的提示框中选择“Yes,change children” 【同时改变子对象】,如图 3-26 所示。 图 3-26 (7)、 在菜单栏中点击“Window”——>“Lightmapping”打开“Lightmapping”窗口,你 可以看到“Object”【 对 象 】、“ Bake”【 烘 焙 】、“ Maps”【图形】这三个选项按钮。“Object” 【对象】主要显示你当前在场景中选定的对象与它烘焙时对应的相关参数,“Bake”【烘焙】 主要是设定烘焙时所需要设定的外部参数,“Maps”【图形】烘焙之后的图形信息。除此而 外,下面还有“Clear”【消除已烘焙的图形】、“Bake Selected”【烘焙已选择对象】、“Bake” 【烘焙整体】这三个按钮。下面列出来“Bake”【烘焙】选项栏下面的一些参数设定及其实 际意义。  “Mode”【 烘焙模式】: 主要有“Single Lightmaps”【 单模光照图】、“ Dual Lightm aps”【双模光照图】。“ Single Lightmaps”【单模光照图】被烘焙的物体阴影信息 只受到烘焙出来的光阴贴图的信息影响。“Dual Lightmaps”【双模光照图】物体的 阴影会受到烘焙后的光阴贴图以及实时光的双重影响。  “Quality”【 渲染质量】: 主要有“Low”【低】和“High”【高】两种渲染模式。“L ow”【低】渲染速度快,但效果差。“High”【高】渲染速度慢,但效果好。  “Bounces”【 反射数量】: 光照射在物体上被反射的次数。  “Sky Light Color”【天光颜色】:模拟天空中从四面射向物体的光线颜色。  “Sky Light Intensity”【天光强度】:为 0 时表示禁止使用天光。  “Bounce Boost”【 反射增量】:  “Bounce Intensity”【反射光强度】:  “Final Gather Rays”【 最终聚集射线】:数字越高显示效果越好。  “Contrast Threshold”【 对比值】: 色彩对比阀值。  “Interpolation”【 插值】:  “Interpolation Points”【插值点】:  “Ambient Occlusion”【 环境剔除】:  “Lock Atlas”【图谱锁定开关】: 当开关被打开时,自动地图信息将不被运行  “Resolution”【 分辨率】: (8)、 选中“Bake”【烘焙】选项栏,选择“Mode”【烘焙模式】为“Dual Lightmaps”【 双 模光照图】,“Sky Light Intensity”【天光强度】设为 0.1,“Resolution”【 分辨率】设置 为 1,然后点击“Bake”【烘焙整体】这个按钮,等待右下角的烘焙进度条结束后,你将在 场景中看到如图 3-27 的效果。 1 2 图 3-27 使用灯光烘焙能将游戏物体表面的光影信息存储在静态的图片上,不但能制作出表面 更加细腻的模型材质感觉,还能极大的提升游戏运行速度。在 Unity3D v3.0 以后,对于场 景的优化不但加入了“LightMapping”,另外还加入了“Occlusion Culling”【遮罩剔除】。这 个笔者将会在以后的小节为大家讲述它的具体的意义和使用技巧。 第 4 章 Animation【动画】 动画原本是指由许多连续的图片在人眼前面快速播放,肉眼因视觉残像产生错觉,而误 以为画面活动的作品。但在 Unity3D 中的“Animation”【动画】系统应该这样理解——用于 为游戏者自动播放人物动作或自动演示物体运动路径、色泽、尺 寸 变化,以及事件触发的集 成学。 4.1 Animation 文件 在 Unity3D 中的 Animation 文件是用来记录物体运动信息的文件,你可以用鼠标右键点 击“Project”【项目文件栏】——>“Create”——>“Animation”来创建一个 Animation 文件,创建好之后的文件为一个时钟的小图标 。除此而外,你导入的模型文件如果带有动 画信息,Unity3D 也会将这些动画信息自动的分离为 Animation 文件,如图 4-1 所示。 ○1 选中“Bake” 【烘焙】选项栏 ○2 选择“Mode”【 烘 焙模式】为“Dual Lightmaps”【双模 光照图】 ○3 “Sky Light In tensity”【天光强 度】设为 0.1 ○4“Resolution”【 分 辨率】设置为 1 ○5 点击“Bake”【 烘 焙整体】这个按钮 图 4-1 另外,Unity3D 内置了 Animation 系统,你可以使用 Animation 面板为物体对象制作各 种动画、色泽变换、或事件触发机制。 4.2 Animation 面板 运用 Animation 面板可以为物体添置许多动画效果,打开方式为在菜单栏中点击 “Window”——>“Animation”,快捷键为 Ctrl+6。 打开 Animation 面板之后,选中 Camera、Light、Gameobject 等带有动画属性参数的对 象,就可以在 Animation 面板左侧看到可以被用作制作动画属性,如图 4-2 所示。 图 4-2 点击左上角红色的录制按钮 ,即为该物体创建一个后缀名为“anim”的动画文件, 动画制作完毕之后再点击这个按钮,就退出了该 Animation 文件的编辑模式。下面我简单做 一个物体的颜色渐变动画。 (1)、 在菜单栏中点击“GameObject”——>“Create Other”——>“Cube”,在场景中创建 一个立方体。 (2)、 Ctrl+6 打开 Animation 面板,在“Hierarchy”【 层次清单栏】或是“Scene”【 场景 面板】选中刚创建好的立方体,点击左上角红色的录制按钮 ,为该立方体创建一个动画 文件,取名为“CubeAnim”然后保存。 (3)、 展 开 “ Default-Diffuse(Instance)( Material)”材质球选项,选中“Color.r”后 面的 ——>“Add Curve”为红色属性参数增加变换曲线。 (4)、在时间轴上点击 1:00,接着按下 增加一个关键帧,然后将“Color.r”后面的数 值设置为 0。点击录制按钮 保存退出,如图 4-3 所示。 图 4-3 (5)、点击播放按钮 ,就可以看到立方体的颜色随时间变化的过程。但如果你会觉得效 果不够明显,那么请你在“Project”【 项目文件栏】中选中动画文件 CubeAnim,然后到 “Inspector”【监视面板】中将它的“Wrap Mode”【 包模式】改为“Loop”,这样一来该物 体的动画就能不断的循环播放了。 4.3 Animation 开关门实例 (1)、 首先利用 3Ds Max 或其他建模软件制作一个门和一些墙体的模型,并导出 FBX 到 Unity3D 项目的资源文件夹 Assets 内。 (2)、 将导入的模型拖放到“Scene”【场景面板】,并单独选中门的模型如图 4-4 所示,按 下快捷键 Ctrl+6 打开 Animation 面板,点击左上角红色的录制按钮 ,为该立方体创建 一个动画文件,取名为“DoorAnim”然后保存。 图 4-4 (3)、 展 开 Transform 卷展栏,选中“Rotation.z”后面的 ——>“Add Curve”为 Z 轴旋 转参数增加变换曲线。 (4)、在时间轴上点击 1:00,接着按下 增加一个关键帧,然后将“Rotation.z”后面 的数值设置为-90。点击录制按钮 保存退出,如图 4-5 所示。 图 4-5 (5)、 选择门的模型“Door”,在“Inspector”【监视面板】下找到“Animation”卷展栏下 的“Play Automatically”复选框,将里面的钩去掉,让物体动画在场景运行的时候不自动 播放。 (6)、选择每一个单独模型,在菜单栏中点击“Component”——>“Physics”——>“Mesh Collider”为每一个模型添加面片碰撞器。这是为了保证人物在碰到墙体和门的时候不被穿 越,并能够进行代码的碰撞检测。 (7)、 右键点击“Project”【 项目文件栏】“Create”——>“C# Script”创建一个 C#文件 取名叫做“OpenDoor”, 双击该 C#文件在该文档中打入如下代码: using UnityEngine; using System.Collections; public class OpenDoor : MonoBehaviour { //人物控制器是否与其他碰撞体产生碰撞 void OnControllerColliderHit(ControllerColliderHit hit) { //如果与其碰撞的碰撞体的名字叫做“Door”,那么这个碰撞体执行动画播放 if(hit.gameObject.name=="Door")hit.gameObject.animation.Play(); } } (8)、保存代码之后,将该 C#文件拖放给场景中的人物角色对象,点击播放按钮执行播放 可看到图 4-6 与图 4-7 的效果。 图 4-6 图 4-7 4.4 DIY 游戏人物 在以前的章节中,大家用于测试的游戏人物都是 Unity3D 自带的,这使得我们的游戏大 大减色不少,那要如何制作一个属于我们自己的游戏人物角色呢?下面笔者就为大家一一道 来。 (1)、 利用 3Ds Max 或 Maya 等建模软件,建立人物模型以及模型的贴图,最好带上法线贴 图这样会比较有质感。在为游戏制作模型的时候,为了使游戏运行起来尽可能的顺畅,减 轻 硬件的计算负担,大家一定要尽量使模型的面尽量的少,具体的细节都用纹理贴图和法线贴 图来表现。(注:如果对建模知识不是太熟悉的朋友,可以参阅一些类似的文章和教程。也 可参看《迎接互联网的明天——玩转 3D WEB》里的具体教程) (2)、 利用 Biped 或类似的建模软件里自带的人物骨骼组件,为人物模型赋给相应的人物骨 骼。并调节你所需要的相应动作,制作关键帧动画。 (3)、制作好动画模型之后导出 FBX 的文件,记得在导出设置里面将“Include”【 包含】— —>“Geometry”【几何体】里的“Convert Geometry used as Bones”【将变形虚拟转化为骨骼】 的选项勾上,如图 4-8 所示: 图 4-8 (4)、 在“Project”【项目文件栏】中选中刚导入的模型文件,到监视面板中找到“Split Animations”复选框并勾选它,点击后面的加号对动画进行切割,如图 4-9 所示。下面我为 大家详细解说下这里面的东西。  “Name”【名字】剪裁动画的片段的名字,就拿这个列子来说吧。我根据每个动画 片不同作用,将它们分别命名为“idle”【空闲】、“run”【 跑】、“walk”【 走 】、“Ju mp”【跳跃】。  “Star”【开始时间】该剪裁动画所开始的帧。  “End”【结束时间】该剪裁动画所结束的帧。  “WrapMode”【循环模式】该选择框一共有五种模式“Default”【默认模式】该模 式让影片剪辑播放完之后停在最初的一帧。“Once”【只播放一次】该模式让影片剪 辑播放完之后停在最后一帧。“Loop”【循环播放】该模式可让这段影片剪辑从开始 帧到结束帧,不断的重复循环播放。“PingPong”【乒乓模式】该模式顾名思义就是 让影片剪辑从开始帧到结束帧来回的播放。“ClampForever”【永远的夹钳】让影片 剪辑播放到最后一帧,然后永远停在那一帧,直到下一个动画开始播放。  “Loop”【循环过渡】该复选框一旦被打勾,会自动产生一个从最后一帧到第一帧 平滑过度的帧,对于“Loop”循环模式下的动画尤为有效。 图 4-9 (5)、切割完毕点击“Apply”按钮,然后将人物模型拖放到场景中。选中人物模型,在其 “Inspector”【监视面板】中可以看到一个“Animation”【动画】的卷展栏,如图“4-10” 所示。 图 4-10  “Animation”【初始动画剪辑】用于模型一开始默认播放的动画剪辑。  “Animations”【 动画剪辑列表】可被脚本访问的动画剪辑列表。  “Play Automatically”【 自动播放复选框】模型在场景中加载完毕之后是否自动 播放动画?  “Animate Physics”【 动画物理】动画是否允许物理交互?  “Culling Type”【 剔除模式】一共有四种类型:“AlwaysAnimate”【始终动画】无 论对象在场景外还是在场景内,都执行动画的播放。“BasedOnRenderers”【基于渲 染】如果对象不被渲染的时候,动画失效。“BasedOnClipBounds”【 基于动画剪辑 边界】这是根据模型动画运动范围,由系统自动设定的一个边界范围,当这个范围 在摄像机渲染范围之内的时候,动画将被激活,否则动画失效。“BasedOnUserBoun ds”【基于用户设定的边界】这是根据由用户设定的一个矩形边界范围,当这个范 围在摄像机渲染范围之内的时候,动画将被激活,否则动画失效。 (6)、 点掉”Inspector”【监视面板】中的 “Play Automatically”【自动播放】复选框不让 模型动画在创建之初播放。然后到菜单栏中选中“Component”——>“Character”——“C haracter Motor”给模型添加一个人物控制器,接着到”Inspector”【监视面板】中的“Char acter Controller”卷展栏下调节人物控制器的“Radius”【 半径】、“Height”【 高度】、“ Center” 【中心点】等信息,正好使得角色控制器能够完整的框住模型,如图 4-11 所示。 图 4-11 (5)、 接着到菜单栏中选中“Component”——>“Character”——“FPS Input Controller” 给模型添加一个移动控制器,该控制器可以控制模型的前后左右随键盘的方向键移动。再接 着到菜单栏中选中“Component”——>“Camera- Control”——“Mouse Look” 给模型 添加一个旋转控制器,由于我们只希望模型左右旋转,所以还得请您到模型”Inspector”【 监 视面板】的“Mouse Look”卷展栏中将“Axes”选择为“MouseX”,然后将其他的有关 Y 属性的值都调节为零,如图 4-12 所示: 图 4-12 (6)、 选中摄像机对象“Camera”,并到菜单栏中选中“Component”——>“Camera- Cont rol”——“Smooth Follow”给摄像机添加一个跟随组件,在它的”Inspector”【监视面板】 中找到“Smooth Follow(Script)” 卷展栏,并将我们的模型对象拖拽给 “Target”后面的 “Transform”接口,如图 4-13 所示。 图 4-13 (7)、 点击测试按钮,在播放模式下调节“Smooth Follow(Script)” 卷展栏里的各个属性 值,直到调整到您觉得一个满意的跟随效果为止。记住这个参数,因为播放状态下的场景为 调试模式,当您重新将测试按钮点起之后,所有的参数又会恢复。恢复之后,再将“Smoot h Follow(Script)” 卷展栏里的各个属性值设定为前面记录下的参数值。 (8)、 创建一个 JS 脚本,并且取名为“moveAnimationControl”。用来控制模型在运动中对 应的播放各种运动动画。具体的代码如下所示: function Start () { //将跳跃的动画层级设置为 1,层级越高的动画被触发时,就最先被执行,默认的层级都为 零。在这里意味着只要跳跃动画被触发,它将优先与其他的动画被执行。 animation["Jump"].layer = 1; //初始动画状态为静止。 animation.Stop(); } function Update () { //这段代码的意思是,竖直方向的方向键被按下,就播放 run 动画,否则就还原成站立动画 if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1) animation.CrossFade("run"); else animation.CrossFade("idle"); //当空格键被按下就执行跳跃动画(*注:由于跳跃动画的层级比其他动画要高,所以当同 时按下方向键和空格键的时候,软件会最先播放跳跃动作) if (Input.GetKeyDown ("space")) animation.CrossFade("Jump"); } 代码输入完毕之后,点击保存 ,并将该代码拖拽给舞台中的人物动画模型“moveTest”, 如图 4-14 所示。 图 4-14 (9)、 然后点击测试按钮 测试一下效果,如图 4-15 所示。用键盘的方向键和空格键盘 来控制人物,可以看到我们的人物在里面行走自如,弹跳轻松。是多么的活灵活现啊! 图 4-15 4.5 角色系统“Ragdoll”的概念及其运用 角色系统【Ragdoll】也被一些人称作“布娃娃系统”,由于在 3D 游戏中需要模拟人物 死亡时、无意识的、身体随机倒下而设定的一个特殊游戏系统。 (1)、 回到前一个小节的 Unity3D 的软件环境,将刚才导入的人物动画模型拖放一个到“场 景面板”中。接着点选菜单栏中的“GameObject”——>“Create Other” ——>“Ragdoll..” 为模型创建一个角色系统。这里需要大家注意一下,Unity3D 角色系统的身体部位和它的英 文名称并不对应,比方说它的“Knee”并不是指膝盖,而是膝盖以下的小腿部分。下面我 要重点说下各部位的记忆方法,如图 4-16 所示。  Root <—— 对应骨骼的根 Bip01  下面从左脚掌骨骼 Bip01 L Foot 往上数 3 个骨骼,对应角色系统中 Left Foot 往 上数的 3 个骨骼:Left Hips <—— Bip01 L Thigh,Left Knee <—— Bip01 L C alf,Left Foot<—— Bip01 L Foot。  下面从右脚掌骨骼 Bip01 R Foot 往上数 3 个骨骼,对应角色系统中 Right Foot 往 上数的 3 个骨骼:Right Hips <—— Bip01 R Thigh,Right Knee <—— Bip01 R Calf,Right Foot<—— Bip01 R Foot。  下面从左肩骨骼 Bip01 L UpperArm 往下数 2 个骨骼,对应角色系统中 Left Arm 往 下数的 2 个骨骼:Left Arm <—— Bip01 L UpperArm,Left Elbow <—— Bip01 L Forearm。  下面从左肩骨骼 Bip01 R UpperArm 往下数 2 个骨骼,对应角色系统中 Right Arm 往下数的 2 个骨骼:Right Arm <—— Bip01 R UpperArm,Right Elbow <—— Bi p01 R Forearm。  下面还有两块骨骼比较简单:Middle Spine <—— 第一脊髓骨骼 Bip01 Spine,H ead <—— Bip01 Head。 图 4-16 (2)、 全部对应好之后,将“Total Mass”设置为 4,并点击创建按钮“Create”。为了大家 更便于理解,图 4-17 展示了角色系统人体构造解析。 图 4-17 (3)、 点击测试按钮 测试一下角色系统。大家会发现人体模型在没有添加如何力的情 况下倒在了地上,并且姿势随作用力的方向随机摆放。如图 4-18 所示: 图 4-18 第 5 章 Occlusion Culling【遮罩剔除】 “Occlusion Culling”【 遮罩剔除】是 Unity3D 中一种被用于游戏场景后期优化的一种 有效手段,它具体的作用是只将摄像机能看到的物体渲染出来,而摄像机无法看到的物体, 将会被计算机自动的从场景中除去,而不做渲染。这样一来,便极大的提升了游戏的性能。 这种方法对于像手机和移动终端这样硬件相对比较低的载体来说,是非常有用的。具体的做 法其实非常简单: (1)、 首先选中场景中所有静止不动的物体对象,然后到“Inspector”【监视面板】中勾选 “Static”复选框,将他们全部设定为静态物体对象。如果有提示框弹出,则选择“Yes,cha nge children”【影响到子物体对象】按钮。 (2)、 点击菜单栏中的“Window”——>“Occlusion Culling”打开“Occl. Culling”窗口, 大家会发现这里和“LightMapping”窗口非常的类似,可以看到“Object”【 对 象 】、“ Bake” 【烘焙】、“Visualizatior”【 可视化面板】这三个选项按钮。“Object”【对象】主要显示你当 前在场景中选定的剔除区域与它烘焙时对应的相关参数,“Bake”【烘焙】主要是设定烘焙 时所需要设定的外部参数,“Visualizatior”【 可视化面板】进行遮罩剔除烘焙后,可在该面 板查看烘焙后的效果。除此而外,下面还有“Clear”【消除已烘焙的剔除效果】、“ Bake”【 烘 焙整体】这二个按钮。 (3)、 在“Object”【对象】选项栏下,找到“Quick Select”后面的下拉框,选择“Create New”【新创建一个剔除区域】,然后你将会在“Scene”【场景面板】中的(0,0,0)点看到 一个剔除区域,如图 3-68 所示。用鼠标左键点击剔除区域前面的绿色按钮进行拖拽,将剔 除区域布满整个场景。 图 3-70 (4)、 在确保剔除区域在选中状态下,你会发现“Object”【对象】选项栏中有这几个选项 “Is View Volume”【是否对静态物体进行剔除检测】、“Is Target Volum”【是否对动态物体 进行剔除检测】、“Target Resolutio”【目标分辨率】后面的下拉框从上往下选择分辨率将会 依次增高。分辨率越高计算的精度越高,但计算机的消耗也就越大。分辨率越低计算的精度 越低,但计算机会运行得越快。这里我们就使用它的默认选择。 (5)、 点选“Bake”【烘焙】选项栏,这里有“View Cell Size”【剔除单元格的尺寸】、“Ne ar Clip Plane”【近景面剔除距离】、“ Far Clip Plane”【远景面剔除距离】、“Bake Quality” 【烘焙质量】这里的“Preview”【预览】主要是用在场景编辑的时候使用,它以一个粗略的 计算机计算,来使用户在编辑时更加流畅;“Production”【产品级】是以最终产品发布时的 效果来计算,相比较“Preview”【预览】而言会比较慢一些,但计算的精度会比较高。这里 笔者的电脑不能承载过于精细的场景烘焙,所以将“View Cell Size”【剔除单元格的尺寸】 调得比较大,调到了 8,然后点击“Bake”【烘焙整体】按钮烘焙整个场景,如图 3-69 所示。 图 3-71 (6)、右下角的烘焙进度条完毕之后,我们进入 Visualizatior”【可视化面板】即可看到烘焙 之后的效果了,如图 3-70 所示。大家可以清晰的看到,场景中没有被摄像机看到的物体并 没有被计算机所加载进来。 用鼠标左键点 击剔除区域前 面的绿色按钮 进行拖拽,将 剔除区域布满 整个场景。 ○1 将“View Cell Size”【剔除单元格 的尺寸】调到 8 ○2 点 击“ Bake”【 烘 焙整体】按钮烘焙 整个场景 图 3-72 4.13 Unity3D 的脚本与组件 在 Unity3D 中可以把每一个交互式脚本都做成一个单独的脚本文件,可视化对象要想 调用他们,最简单的方法就是拖拽附加给可视化的物体对象,这种可被赋予可视化对象的脚 本文件,在 Unity3D 中就被称作组件。当然你还可以通过赋给本对象的编程脚本对其他的组 件进行一定的调用或者说是控制。 在“Inspector”【监视面板】中,你可以看到该可视化物体对象的每一个被赋予的组件, 并且可以自由的改变他们组件的开放参数。这种编程思想特别像我在第二章当中给大家说到 的类继承和类的重写,更像 Java 当中接口的概念。下面笔者做一个 Unity3D 中可视化对象 从无到有的简单演示: (1)、 点击菜单栏“GameObject”——>“Create Empty”在场景中创建一个空的显示对象, 这类似与 PV3D 中顶级显示类“DisplayObject”,在“Hierarchy”【层次清单栏】双击刚才新 创建的空显示对象“GameObject”,发现该对象有坐标的移动方向,但无可显示的东西,在 右边的“Inspector”【监视面板】只有一个“Transform”组件,如图 3-73 所示。这个组件是 Unity3D 每个可视化对象必带的一个组件,用于规定该可视化对象的位置坐标、旋转量、缩 放参数。它与“GameObject”组件是平级关系,在代码编写中两者可以相互继承,相互调 用。 图 3-73 (2)、 继续在菜单栏中点击“Component”——>“Mesh”——>“Mesh Filter”前面说过这 个组件是用来设定可视化物体的形体样貌的,在“Inspector”【监视面板】中我们点击“Me sh”后面的圆圈,在弹出来的“Select Mesh”对话框中选择那个胶囊的模型,如图 3-74 所 示。但发现“Scene”【 场景面板】中依然没有任何物体显示出来,这是由于 Unity3D 中不像 PV3D 在没有添加材质之前会用线框材质去描述物体。所以我们还得为“GameObject”对象 添加一个“Mesh Renderer”【网格渲染器】组件。 图 3-74 (3)、 确保“GameObject”在选中的情况下,在菜单栏中点击“Component”——>“Mesh” ——>“Mesh Filter”为该对象添加一个“Mesh Renderer”【网格渲染器】组件,并到“Ins pector”【监视面板】下找到“Mesh Renderer”组件,在“Materials”卷展栏中点击“Eleme nt 0”后面的圆圈接口,在弹出的“Select Material”中为物体选中一个合适的材质球,这 时你便可以在“Scene”【 场景面板】中看到一个绿色胶囊立体图形了,如图 3-75 所示。 图 3-75 4.14 为地形添加水源和各种水流,以及如何运用默认渲染设置来 做出水下的模糊效果 本节所对应的视频教学录像:  第十五讲 使用“Image Effects”打造水下模糊效果 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\4.14\ (1)、 用 Unity3D 软件新创建一个“water&Fog”项目文件,并导入所有自带的包。用地形 系统创建一个带有洼地的山势图,如图 3-76 所示。创建完毕之后,在场景面板中点击 Y 方 向的绿色箭头切换到顶视图,这样可以便于我们很快的找到洼地的所在地方,如图 3-77 所 示。然后用鼠标滚轮迅速的推进观测距离。 ○1 在“Materials”卷 展栏中点击“Element 0”后面的圆圈接口。 ○2 在弹出的“Select Material”中为物体选 中一个合适的材质球 ○3 在“Scene”【 场景 面板】中看到一个绿 色胶囊立体图形 图 3-76 图 3-77 (2)、 接着再到 Project【项目文件栏】找到“Standard Assets”文件夹下的“Water(Pro O nly)”【仅限专业版使用,如果是非专业版请转到‘Water(Basic)’】 文件夹中,拖拽一个 D aylight Water【白天光照效果的水模型】到洼地的中央,并利用场景调整工具中的缩放工具 ,将水模型调整到合适的大小,如图 3-78 所示。再点击场景面板中右上角的白色小方 块,将视角切换到透视图,如图 3-79 所示。然后利用场景调整工具中的位移工具 ,将 水模型调整到合适的高度,如图 3-80 所示。这时你只需在播放时,将摄像机移动到洼地这 个地方就可以看见湖水的效果了。 图 3-78 创建完毕之后,在场景面 板中点击 Y 方向的绿色 箭头切换到顶视图 在顶视图中 找到洼地。 图 3-79 图 3-80 (3)、 但这样的效果略显单调了一些,既然是山中泉水我们还得有一些瀑布和溅起的浪花。 为了节约时间,我们直接在 Project【项目文件栏】上方的搜索框输入字符“water f”,就可 以查出如图 3-81 所示所示的材质和模型。 图 3-81 (4)、 在这里面中,“Water Fountain”是一个喷泉模型,“Water Surface Splash”是一个水 面的飞溅模型,“WaterFall”是一个瀑布模型。我们先拖入一个“WaterFall”到洼地,然后 利用场景调整工具来调整它的位置和角度,如图 3-82 所示。 图 3-82 (5)这时的瀑布略显小了一些,我们可以先选中它,然后到它的”Inspector”【监视面板】 找到“Local Velocity”将 Z 轴的初始速度调整为 8,加大 Z 轴线上的初始喷射速度,然后 可以得到如图 3-83 所示的效果。 图 3-83 (6)、 接着我们在瀑布下的水面上方放置一个水面飞溅模型“Water Surface Splash”。由于 它的高度一定要和水面高度一致,所以我们先点选水平面看看它 Y 轴的数字,然后在点选 “Water Surface Splash”到它的”Inspector”【监视面板】中输入同样的 Y 轴数字,以确保 它浮在水面上。紧接着到它的”Inspector”【监视面板】中调整它的属性,改变模型变成你 想要得到的效果,我这里调节的是它的“Min Size”和““Max Size””,如图 3-84 所示。 ○1 将 Z 轴的 初始速度调 整为 8 ○2 可看到场景 中瀑布的水流 明显加大 ○2 调节“Water Su rface Splash”的 “Min Size”和“ M ax Size”为 3 和 6。 ○3“Water Surface Splash”的水花面 积明显加大。 ○1 拖入“Water Su rface Splash”模型 图 3-84 (7)、 运行一下游戏,然后将镜头移动到泉水的水面下,如图 3-85 所示。大家会发现,水 下的视觉和在平地上的视觉效果是完全一样的。这和我们平时的生活现状是不相符的,所以 我们还得做一下相应的调整。 图 3-85 (8)、“GameObject”——> “Create Other”——> “Cube”创建一个立方体,并运用场景 调整工具将它调整到整个水洼的实体部分,如图 3-86 所示。(注:运用其他形体也可以,其 主要是用来覆盖水洼的实体部分,以用来和摄像机作碰撞检测,让摄像机的镜头变得模糊。) 图 3-86 (9)、 确保你创建的这个 Cube 是被选中状态,到它的”Inspector”【监视面板】中,将“B ox Collider”卷展栏中的“Is Trigger”复选框打上勾(如果这里不打勾,这个立方体将作为 一个实物,当摄像机撞上它时,就像撞上一堵墙,无法通过),如图 3-87 所示。 图 3-87 (10)、 然后再将“Mesh Renderer”卷展栏下的所有复选框全部点掉,使这个立方体只作为 一个形体存在,而不让它在场景中作出任何的显示渲染。 (11)、 在”Inspector”【监视面板】的最上方将它的名字由“Cube”更改为“WaterColler”, 如图 3-87 所示。 图 3-87 (12)、 选中“Tag”的下拉框——>“Add Tag…”新添加一个“WaterColler”的标签分类, 如图 3-88 所示。 图 3-88 (13)、 在“Hierarchy”【层次清单栏】重新选中“WaterColler”水洼碰撞体。到它的“In spector”【监视面板】中,将这个“WaterColler”水洼碰撞体的 Tag 也改成“WaterColler”, 如图 3-89 所示。 图 3-89 这里需要给大家说明一下,Unity3D 里面可以给“Hierarchy”【层次清单栏】下的每一 个可对象进行重新命名,已方便脚本对其调用和交互。但有时候我们需要将一些不同名字的 物体进行归类操作,以方便脚本对某一类物体进行群体的调用和交互,这就引入了“Tag” 【标签】的概念。这里的“WaterColler”水洼碰撞体我们即对其进行了命名,又对其进行了 标签分类,所以我们可以通过两种方式来访问它。 (14)、 在菜单栏中选中“Assets”——>“Create” ——>“JavaScript”新添加一个 JS 脚本。 到“Project”【项目文件栏】找到刚才新建的 JS 脚本“NewBehaviourScript”,按下 F2 键更 改它的名字为“UnderWaterEffect”,并双击编辑它,输入如下代码: //保存迷雾的默认设置 private var defaultFog = RenderSettings.fog; //保存默认的迷雾颜色 private var defaultFogColor = RenderSettings.fogColor; //保存默认的迷雾密度 private var defaultFogDensity = RenderSettings.fogDensity; //保存默认的天空盒材质 private var defaultSkybox = RenderSettings.skybox; //设定一个天空盒材质的接口 var noSkybox : Material; function OnTriggerStay (hit : Collider) { //进行碰撞判定,如果碰撞对象的标签叫做“”"WaterColler",就改变渲染设置 if(hit.gameObject.tag=="WaterColler"){ //将渲染设置的迷雾开关打开 RenderSettings.fog = true; //设置一个偏蓝色迷雾,透明度为 0.6 RenderSettings.fogColor = Color (0, 0.4, 0.7, 0.6); //设置迷雾的密度 RenderSettings.fogDensity = 0.1; //将天空盒材质改为接入的天空盒材质 RenderSettings.skybox = noSkybox; } } function OnTriggerExit (hit : Collider) { //进行碰撞判定,如果离开了标签叫做“”"WaterColler"的碰撞体,就回复成原来的渲染设 定 if(hit.gameObject.tag=="WaterColler"){ RenderSettings.fog = defaultFog; RenderSettings.fogColor = defaultFogColor; RenderSettings.fogDensity = defaultFogDensity; RenderSettings.skybox = defaultSkybox; } } (15)、 输入完毕之后,在编辑里按 Ctrl+S 保存代码并关闭退出。 (16)、 将默认摄像机删除掉,在“Project”【项目文件栏】中找到第一人称游戏对象“Fi rst Person Controller”,该对象是专门用于 Unity3D 的漫游测试的,在游戏运行中可以用 方向键控制该对象移动,用鼠标控制摄像机镜头角度的变换。将其拖放到“WaterColler”水 洼碰撞体的旁边,如图 3-90 所示。 图 3-90 (17)、 将完成好的脚本“UnderWaterEffect”拖放给第一人称游戏对象“First Person Con troller”,并在拖放之后确保该对象在选中的情况下,从“Project”【 项目文件栏】搜索到 天空盒材质对象“MoonShine Skybox”,把它拖放给“Inspector”【监视面板】中的“noSk ybox”天空盒材质接口,如图 3-91 所示。 图 3-91 (18)、 运行一下游戏,将摄像机移动到“WaterColler”水洼碰撞体里面时,就可以看到一 片蓝色迷雾的景象了,并且仰望天空时,天空变成了夜晚,如图 3-92 所示。但当摄像机离 开“WaterColler”水洼碰撞体时,周围的景色又回复成了正常的颜色,如图 3-93 所示。 图 3-92 图 3-93 本节小结: 除了本节中给大家说的这种方法来制造水底效果而外,还有更好的镜头渲染滤镜的方 法来实现更好的水底效果。这里之所以要用默认渲染设置的参数来设定水底效果,主要是帮 助大家一起回顾一下以前学到的知识,二方面让大家能初步的了解 Unity3D 中是如何通过脚 本来控制设置参数设定的。如果大家看到这里,有点记不清楚 Unity3D 默认渲染设定知识的 话,请参看 4.11.1 小节。 4.15 Unity3D 中脚本运行时间片与接口的简单概述 本节重点:  要清晰的掌握 Unity3D 双时间轴执行事件的概念  明确掌握“Coroutine”【 协 同 函数】的作用和使用方法  掌握时间类函数 Time.deltaTime 与 Time.time 的正确使用方法  学会在 Unity3D 中定义组件接口 和前面的所学 3D 软件一样,Unity3D 要在计算机里面显示出游戏的动画画面,就必须 有着良好的时间层级关系。但 Unity3D 的时间层级关系,又不像 Flash 的固定物理时间轴, 也不像 WF 里面的单纯的图形渲染时间轴。它综合了两者各自拥有的优点,并把二者有机的 结合在了一起。在图 3-94 中,笔者画出了 Unity3D 时间运行函数的关系。 图 3-94  图形渲染时间轴:是与计算机硬件紧密结合的一个时间轴。计算机在这个时间轴上 如何调用函数,并不是我们真实现实生活中的固定频率的物理时间。而是根据计算 机自身的硬件情况,比方说 Update()函数会在计算机图形卡新绘制一帧画面的时候 执行,如果计算机的硬件配置比较高,那么你会看到 Update()里面所执行的事件会 非常的快。在图形渲染时间轴上除了 Update()而外,还有 Awake()、Start()、LateUp date()和绝大多数的 On 函数。Awake()是当该物体在场景中进行加载的时候执行;S tart()是该物体第一次被图形卡开始绘制时执行;Update()是每一次图形卡新绘制该 物体时执行、LateUpdate()是每一次图形卡新绘制该物体完毕之后执行。OnGUI()、 OnDrawGizmos()这类函数作为 2D 界面绘制函数,绝大多数时间是在 LateUpdate() 函数之后被调用,但偶尔会运行在 Update()之前。  固定物理时间轴:是与硬件无关的时间轴,它利用硬件的频率模拟来和真实世界的 时间同步。在这个时间轴上的函数,比方说 FixedUpdate()并不会关心硬件是否已将 当前的画面渲染完成,只要是到达了时间频点它就会执行函数里面的代码。默认的 FixedUpdate()是每隔 0.02 秒执行一次,但你可以在菜单栏中点击“Edit”——>“Pr oject Settings”——>“Time”来修改 FixedUpdate()的执行频率。  “Coroutine”【协同函数】:由于固定物理时间轴对物理时间真实性的把握,Unity3 D 将大量的与时间有关的计算函数,比方说刚体受力作用的运动等等,都放置到这 个时间轴上来运行。但有时候图形渲染时间轴上运行的函数,也需要用到物理时间 来帮它计算出某些结果,这时候 Unity3D 就运用到了“Coroutine”【协同函数 】。“ C oroutine”【协同函数】在图形渲染时间轴上调用它时,被抛出到时间轴以外,并通 过 yield 来对物理时间进行计算,在计算之后向图形渲染时间轴上的函数回调结果。 由于固定物理时间轴和图形渲染时间轴不同步的问题,类似 yield WaitForSecond s()这些延迟函数在固定物理时间轴计算完成之后向图形渲染时间轴回调的时候, 总会产生一点点小小的延迟。 下面用 JS 写的一个列子来证明上面的时间轴关系: (1)、 在菜单栏上选中“Assets”——>“Create” ——>“JavaScript”,在“Project”【项 目文件栏】选中新创建的“NewBehaviourScript”,按下 F2 将其重命名为“timeExperimen t”,然后双击该脚本,在编辑器中输入如下代码。 function Awake() { //打印本次距离上次调用 Awake()函数间隔了多少时间 print ("Awake "+Time.deltaTime); } function Start() { //打印本次距离上次调用 Start()函数间隔了多少时间 print ("Start "+Time.deltaTime); } function Update() { //打印本次距离上次调用 Update()函数间隔了多少时间 print ("Update "+Time.deltaTime); } function LateUpdate(){ //打印本次距离上次调用 LateUpdate()函数间隔了多少时间 print ("LateUpdate "+Time.deltaTime); } function FixedUpdate(){ //打印本次距离上次调用 FixedUpdate()函数间隔了多少时间 print ("FixedUpdate "+Time.deltaTime); } function OnGUI () { //打印本次距离上次调用 OnGUI()函数间隔了多少时间 print ("GUI "+ Time.deltaTime); //绘制一个 GUI 按钮,并且在按下该按钮的时候执行 WaitAndPrint ()协同程序 if(GUI.Button(Rect(10,10,100,50),"This is a title")){ StartCoroutine(WaitAndPrint()); } } function WaitAndPrint () { // 存储 WaitAndPrint()函数被调用的初始时刻 var firstTime=Time.time; //等待 2 秒 yield WaitForSeconds (2); //打印出现在的时间与 WaitAndPrint()函数被调用的初始时刻的时间差值 print ("WaitAndPrint "+ (Time.time-firstTime)); } 从这串代码中,不难看出 Time.deltaTime 是一个记录该函数每一次被调用的时间间隔函数, 而 Time.time 是记录该函数从开始被调用起,一直到当前时间的总用时时间函数。 (2)、 将这段代码拖拽给 Hierarchy【层次清单栏】中任意一个对象,你就会在播放器刚开 始播放的时候,就左下方的控制台面板中看到一串串字母和数字正在被反复的打印着,双击 左下角的控制台字符,可将控制台面板完全展开,如图 3-95 所示。 图 3-95 (*注:这个控制台面板以后大家会经常使用到它,因为它可以用作你代码片段的调试,以 及你程序出错了的提示框,详细的提示你出错的原因所在。) Unity3D 中的脚本(或称作组件)除了有着上述良好的时间层级关系,还有着非常强大 的接口处理功能,你可以在代码中为对象制定任意一个空接口用于和对应类型的对象进行交 互,例如下面用 JS 写的一个列子: 在菜单栏上选中“Assets”——>“Create” ——>“JavaScript”新建一个 JavaScript 组件, 并用编辑打开它输入如下的脚本。 var AddSpeed =5; function Update () { transform.Translate(0, 0, AddSpeed); } 该代码为对象添加了一个在 Z 方向上的初始速度,如果在没有其他外力的作用下,物体将 在每一次游戏画面进行渲染的时候,沿着 Z 方向递增 5 的位移。并且当你将这段代码拖拽 给场景中的一个物体对象之后,它的这个初始速度可以作为一个接口在它的”Inspector”【 监 视面板】中进行修改如图 3-96 所示。 图 3-96 除了数字作为接口外,接口还可以是对象,例如下面用 JS 写的一个列子: 在菜单栏上选中“Assets”——>“Create” ——>“JavaScript” 新建一个 JavaScript 组件, 并用编辑打开它输入如下的脚本。 1 2 var AddSpeed=5; //定义一个变换对象 cubeGO var cubeGO:Transform; function Update () { //在逐帧播放的过程当中,一旦按下 G 键 cubeGO 就以 AddSpeed 速度,朝 Z 轴方向运动 if(Input.GetKey(KeyCode.G)){ cubeGO.Translate(0,0,AddSpeed); } } 你可以将这段代码拖放给 Hierarchy【层次清单栏】中任意一个对象,因为它在这里定义了 一个 Transform 类接口对象 cubeGO,所以它几乎与拖拽的对象无关。拖拽成功之后来到该 物体的”Inspector”【监视面板】中,你就可以看到如图 3-97 所示的一个属性卷展栏。 图 3-97 cubeGO 的后面有个很明显未定义对象接口“None(Transform)”,然后我们把想要使之运动 的物体拖拽到这个接口上面来,如图 3-98 所示。当我们运行游戏时,只要按下“G”键就 可以看到 Cube 作为“cubeGO”的指代对象,朝着“Z”轴方向运动了。 图 3-98 4.16 Unity3d 中的 C# Script 编程的注意事项 也许你在学习Unity3D之前,已经是一位C#的编程高手了。但在Unity3D中的C#并像真 正的微软C#那般强大,因为在Unity3D的C#并不是运行在微软.NET上的,而是运行在跨平台 的Mono8上的,并且根据自身引擎的开发特质进行了一定的内核修整。所以在Unity3D中使 用C#必须注意以下事项:  类名必须与文件名完全相同,这一点和传统的 C#保持一致。  所有新建的 C#脚本必须全部继承自 MonoBehaviour,像这样的格式 public class NewBehaviourScript : MonoBehaviour {...}  协同程序一定是 Ienumerator 的返回类型,并且 yield 用 yield return 替代 8 Mono 是一个由 Novell 公司(先前是 Ximian)主持的项目。该项目的目标是创建一系列符合 ECMA 标准 (Ecma-334 和 Ecma-335)的.NET 工具,包括 C#编译器和共通语言运行平台。与微软的.NET Framework 不同,Mono 项目不仅可以运行于 Windows 系统上,还可以运行于 Linux,FreeBSD,Unix,Mac OS X 和 Solaris。——来自维基百科  避免使用面向对象编程语言里面惯用的构造函数,初始化放在 Awake()或 Start ()函数中。  不支持空间命名,但官方说它们很有可能会在以后的版本中支持这一功能。  C#定义的私有的和受保护的变量或对象不会作为接口出现在“Inspector”【监视面 板】中,那怕你将它放置到该脚本的开始处。 下面为一段 Unity3D 中的 C# Script 完整代码: using System.Collections; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // 一个名为 SomeCoroutine 的协同程序,正如注意事项所说的那样协同程序必须是 Ien umerator 的返回类型 IEnumerator SomeCoroutine () { // 等待一帧,这里大家注意观察,相比较 JavaScript 的 yield,C#要使用 yield retur n 替代 yield return 0; // 等待两秒 yield return new WaitForSeconds (2); } } 在 Unity3D 中,JavaScript 和 C# Script 的编程效果近乎一样,但 Mono 的编译效果却有 着一定的差距,这个笔者会在后面为大家讲述。不过这点差异丝毫不妨碍制作人员用 JavaS cript 编写出品质优秀的 Unity3D 小游戏,特别对于一些学编程语言经历不是太久的朋友,J avaScript 编程语言有着更好的灵活性和使用性,能为对编程不是太熟练的朋友提供极大的方 便。 4.17 利用 MonoDevelop 编辑器来和 Unity3D 协同作战 和前几个章节中所学到的软件一样,Unity3D同样有着一个为它提供强大编程支持的脚 本编辑器《MonoDevelop9》。这个软件会在你安装Unity3D的时候自动安装。你可以在计算 机的开始菜单下的Unity3D目录中找到这个软件,如图 3-99 所示: 9 MonoDevelop 是个适用于 Linux、Mac OS X[1]和 Microsoft Windows[2]的开放源代码集成开发环境,主要 用来开发 Mono 与.NET Framework 软件。 图 3-99 打开 MonoDevelop 之后,点击新建按钮 。直接单击“Unity”就可以看到它所对应的几 个编程语言,其中的 Unity Script 指的就是 JavaScript,如图 3-100 所示。 图 3-100 同样的,在里面输入代码就会弹出相应的提示,使用起来比用 Unity3D 中的脚本编辑方便了 许多。如图 3-101 所示。 图 3-101 4.18 修改 MonoDevelop 编辑器为 Unity3D 的默认编辑器 通常情况下 Unity3D 默认的编辑器都是“UniSciTE”,它用起来十分轻巧快捷,就像记 事本一样,如图 3-102 所示。 图 3-102 但如果要开发一些大型的项目,显然“UniSciTE”简单的功能就不足以支撑它的工作了。 但如果你每回在编辑脚本的时候,都去用“MonoDevelop”一个一个的打开,又显得很麻烦。 所以我们就要在 Unity3D 中做一些设置,让“MonoDevelop”成为默认的脚本编辑器。具体 的步骤是:在菜单栏中找到“Edit”——>“Preferences…”,在弹出的“Unity Preferences” 对话框中找到“External Script Editor”并将它后面的下拉框选中为“Browse…” 浏览到我 们“MonoDevelop”可执行文件存放的地方。这个路径一般都和你 Unity3D 文件夹在一起, 比方说你的 Unity3D 安装在 D 盘的 Program Files 文件夹中,那么你可以直接在这个路径“D: \Program Files\Unity\MonoDevelop\bin”找到“MonoDevelop.exe”这个文件。 设置好之后,重新在 Unity3D 中点选下脚本文件,发现已经能用“MonoDevelop”软件 打开了,但第一次打开的时候会稍显慢一点,因为“MonoDevelop”要加载很多东西,效果 如图 3-103 所示: 图 3-103 (注:如果你是一个 C#和 Visual Studio 忠实编程爱好者,你可以用同样的方法来设置 Visu al Studio 编辑器的路径,让 Visual Studio 成为 Unity3D 的脚本默认编辑器。) 4.19 向 Unity3D 中导入外部模型,以及详细参数的设定 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ Unity3D 支持多种外部模型格式,但它并不是对每一种外部模型的属性都支持。具体的 支持参数,你可以对照表 3-2。下面的实例中,我们利用 3D Max 来制作一个完整的动画, 并导出 FBX 的格式给 Unity3D 使用。 网络 材质 动画 骨骼 Maya 的.mb 和.ma1 格式 √ √ √ √ 3D Studio Max 的.max1 格式 √ √ √ √ Cheetah 3D 的.jas1 格式 √ √ √ √ Cinema 4D 的.c4d1 2 格式 √ √ √ √ Blender 的.blend1 格式 √ √ √ √ Carrara1 √ √ √ √ COLLADA √ √ √ √ Lightwave1 √ √ √ √ Autodesk FBX 的.dae 格式 √ √ √ √ XSI 5 的.x1 格式 √ √ √ √ SketchUp Pro1 √ √ Wings 3D1 √ √ 3D Studio 的.3ds 格式 √ Wavefront 的.obj 格式 √ Drawing InterchangeFiles 的.dxf 格 式 √ 表 3-2 (1)、 创建一个名为“Turret”的项目文件夹。然后打开 Unity3D 软件,选择“File”——> “New Project…”创建一个新工程项目,在项目路径中点击“Browse…”选择找到我们刚 才的“Turret”文件夹,并点选我们需要导入的包文件,然后点击“Create”来创建一个新 的工程文件。(注:这个步骤千万不能乱,因为 Unity3D 是无法以非空的文件夹作为工程文 件夹来创建项目的。) (2)、 打开 3Ds Max 软件制作一个炮塔模型,并将制作好的模型保存在“Turret”文件夹中 的“Assets”【资源】文件夹下面。图 3-103 为 3D Max 中的模型样图. 图 3-103 (3)、 为了保障模型在 Unity3D 中的显示效果,我们给模型添加一些光照,并将添加了光照 的模型渲染为烘焙贴图,这样可使得模型本身带有一些明暗纹理效果。其烘焙贴图的方法请 参看第三章的 3.9 小节,烘焙之后的效果图如图 3-104 所示。烘焙完毕之后,按住 Ctrl+S 保 存文件。 图 3-104 (4)、 重新来到 Unity3D 的软件环境中,这时大家已经能在 Project【项目文件栏】看到我 们刚才用 3D Max 导出的模型文件和材质贴图文件了,如图 3-105 所示。 图 3-105 (5)、 接着利用我们前面章节中所学到知识,为场景文件添加地形和阳光。然后在地形图上 找一个合适的位置,将我们的炮塔拖拽上去,如图 3-106 所示。 图 3-106 (6)、 但这样看着,似乎太小了一点。在改变外部模型的尺寸的时候,有一个技巧,你不必 在场景中修改它。而可以到该模型所在的”Inspector”【监视面板】中去修改它的“Scale F actor”大小。它的默认值是 0.01,我们在这里将它改为 0. 1,并在”Inspector”【监视面板】 的最下方找到“Apply”按钮,点击它让模型尺寸在 Unity3D 中得到改变,如图 3-107 所示。 再来看看我们的炮塔,是不是雄壮了许多? 图 3-107 (7)、 但是,笔者并不赞同这样的模型导入方法。因为根据官方的说法,他们建议你将做好 的模型导出成为 FBX 格式的模型文件给 Unity3D 使用。也许这样会使模型在 Unity3D 中的 运行速度得以提高吧。所以说我们还得回到 3D Max 的软件环境下面,做一下导出工作。 在 3D Max 中,点击 File【文件】——>export【导出】,将模型文件导出为 FBX 文件,保存 到 “Turret”文件夹中的“Assets”【资源】文件夹下面。注意一下弹出的“FBX Export” 面板,这里包含了模型动画、骨骼工具、材质等等一系列的导出设置。如果你没有在模型中 添入这些东西,就请你将不必要的复选框点掉,如图 3-108 所示。 1 2 图 3-108 (8)、 回到 Unity3D 的软件环境,在 Hierarchy【层次清单栏】中选中原先的炮塔模型,按 下 Delete 键将其删除。然后在 Project【项目文件栏】中找到刚刚导入 FBX 模型,点击选中 它,用前面修改模型尺寸的方法来修改 FBX 模型的尺寸。然后将其放置在场景中合适的位 置上。 4.20 预制对象 Prefab,及其它的调用方法 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ 还记得我们在第二章中对 Flash 的学习吗?如果你不想让某些物体出现在舞台上,但你 又想通过代码随时的来调用这些物体,就比方说游戏中的炮弹或子弹这类似的物体。那我们 就要先在 flash 的库中创建一个这样的影片剪辑,但并不把它拖放到舞台上显示,然后用鼠 标的右键点击它,并在它的属性面板里面将“为 ActionScript 导出”复选框打上钩,这便可 以随时随刻的用代码将它调入或调出舞台了。 Unity3D 中同样有着类似的功能,但它和 flash 在用法上稍稍不同。具体的做法是:在 菜单栏中点选“Assets”——>“Create” ——>“Prefab”在 Project【项目文件栏】中创建 一个预制类对象“new prefab”,这时你会发现预制类对象前面的小方框是灰色的,这说明 它是一个空对象,如果你现在用代码调用它,你并不能看到任何的东西。但如果你在 Proje ct【项目文件栏】或是“Hierarchy”【层次清单栏】中向它拖入任意物体,那么你立马就可 以在调用“new prefab”的地方看到这个被拖入的物体,并且看见“new prefab”前面的图 标变为了实体的蓝色,如图 3-109 所示。预置类对象“Prefab”就像一个空着的盒子,你可 以为它填充任何的东西,并利用代码在舞台上显示它。 图 3-109 4.21 图形用户界面类 G.U.I 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ 你在玩很多 3D游戏的时候,不知是否注意到在游戏界面中,总有一些图形和文字信息 是不随着 3D视觉的改变而改变的。这也是由于游戏本身的要求所决定的,比方说英雄的生 命值,聊天窗口的文字信息等等。这一些不被改变的界面元素就被称作G.U.I10。GUI在Unit 10GUI 的计算机标准解释是: “Graphical User Interface”【 图形用户界面】又称图形用户接口,是指采用图 形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉 上更易于接受。 y3D中不像Flash那样有一个二维坐标系,它的位置以距离当前位置 X方向和Y方向多少个“P ixel Offset”【像素偏移单位】来进行计算;在代码中,GUI元素则以距离“Rect”【矩形盒】 左边和顶部多少个像素单位来进行计算。下面我们一起在Unity3D中简单做两个G.U.I实例, 来说明它的用法。 (1)、 打开 Unity3D,它会自动导入上一次的工程项目。为了节省篇幅,我们还是使用前面 的“Turret”工程项目来做说明。假设我们就现在的项目来做一个炮弹发射的游戏,想想我 们都需要做写什么工作?是不是应该在画面的一个角落显示炮弹填发的情况?就像大多数 3D 游戏那样,你的魔法值在使用完毕之后需要一定恢复时间。 (2)、 用 PhotoShop 制作弹药的填发时间图。并将它们全部保存为 PNG 文件到工程项目的 “Assets”文件夹内。如图 3-110 所示,为 PhotoShop 制作的填发时间图,一共 5 张。 图 3-110 (3)、 回到 Unity3D 软件环境中,为了归类我们在 Project【项目文件栏】中右键——>“Cr eate” ——>“Folder”新建一个文件夹,并按 F2 将其更名为“shortTime”,再将导入的五 张图片拖入文件夹内。如图 3-111 所示。 图 3-111 (4)、 在菜单栏中选中“GameObject”——>“Create Other” ——>“GUI Texture”创建 一个 GUI 图标,这时大家会在 Scene【场景面板】中看到一个默认 Unity3D 的图标,如图 3 -112 所示: 图 3-112 (5)、 在 Hierarchy【层次清单栏】选中它之后,来到它的”Inspector”【监视面板】中,点 击 Texture 后面的圆圈来改变它的图标为我们刚导入弹药填充图标。再通过”Inspector”【 监 视面板】中其他属性值的更改,得到图标最终的显示大小和显示位置,如图 3-113 所示: 图 3-113 (6)、 在菜单栏中选中“GameObject”——>“Create Other” ——>“GUI Text”创建一 个 GUI 文字在图标的旁边作为说明。其输入的文字、文字大小、文字样式等等也同样在它 的“Inspector”【监视面板】中调节,最后得到如图 3-114 的效果。 ○1 点击 Texture 后面的圆圈 ○2 在弹出来的“Sele ct Texture”对话框中 选择弹药填充图标 ○3 在场景中看 到弹药填充图 标的标志 图 3-114 4.22 怎样自定义 Unity3D 中的中文字体 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ 在上一节当中,大家学习了 G.U.I 图形和文字的使用方法。但细心一点的朋友可能会发 现,在“GUI Text”中并没有中文字体库,但是,这并不能影响我们对中文作品的开发。U nity3D 中可以将任意的字体作为材质文件赋予“GUI Text”,其中就包含中文字体。具体做 法如下: (1)、 将你需要的中文字体拷贝到项目文件中的“Assets”文件夹内。 (2)、 在菜单栏中选中“GameObject”——>“Create Other” ——>“GUI Text”创建一 个 GUI 文字,然后在它的”Inspector”【监视面板】中找到“Font”点选他后面的接口圆圈, 将它的字体类型改为你刚才拷贝进来的那个字体,接着在“Inspector”【监视面板】中找到 “Text”后面的输入框输入你想要的输入的中文字体。最后你就将在你的“Scene”【场景面 板】和“Game” 【动画面板】看到该文字了,如图 3-115 所示。 图 3-115 4.23 制作炮塔的旋转 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ (1)、 给炮塔的上半部分添加一个旋转函数,使得炮塔随着鼠标在 X 方向上的移动而移动。 在 Project【项目文件栏】中右键——>“Create” ——>“JavaScript”新建一个 JavaScript 函数,并按 F2 将其更名为“turretRotate”,然后输入如下代码。 var speed : float = 20.0; //旋转速度 function Update(){ //这里乘以 Time.deltaTime 函数是为了使旋转效果更加的平滑。 transform.Rotate(Vector3(0, 0, Input.GetAxis("Mouse X")) * Time.deltaTime * speed); } (2)、 点选场景面板中的炮塔,点击三角形按钮将炮塔模型展开,找到炮塔上半部分所对应 的对象,接着将刚才的“turretRotate.Js”文件拖拽给这个对象,如图 3-116 所示。 ○1 选 中“GUI Text”在 “Inspector”【监视面 板】中找到“Font”点 选它后面的接口圆圈 ○2 在弹出的“Selec t Font”对话框中, 选择刚才拷贝进来 的那个字体 ○3 输入 中文,看 到效果 图 3-116 (3)、 选中摄像机对象“Camera”,点选菜单栏中的“Component”——>“Camera-Control” ——>“Smooth Follow”为摄像机添加一个平滑的跟随组件,但这里并没有设置跟随对象。 (4)、 继续选中摄像机对象,在它“Inspector”【监视面板】中找到“Smooth Follow(Scri pt)”卷展栏下的“Target”,然后将炮塔上半身对象拖放给它,如图 3-117 所示。 图 3-117 (5)、 点击测试按钮 ,试着移动下鼠标看看炮塔的旋转效果,如图 3-118 所示。摄像机 随着炮塔的旋转而旋转,而 GUI 图标和 GUI 文字一直在左上方,效果很不错。 ○1 点选场景面板中的 炮塔,点击三角形按钮 将炮塔模型展开 ○2 找到炮塔上半部分所对应的 对象,接着将刚才的“turretRo tate.Js”文件拖拽给这个对象 图 3-118 4.24 凹凸材质的制作 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\4.24\ 在我们的时常玩的游戏当中,经常会看见 3D 模型的表面带有一定的凹凸纹理。这些东 西非常琐碎,但却能良好的凸显出 3D 模型的质感。但如果我们完全依赖建模来凸显这种质 感的话,就会给计算机带来沉重的负担。通过我们前面几章学习,相信大家不难理解,如果 一个模型的表面越复杂,那么为它所建立的三角面也就越多,而对应三角面的顶点也就越多。 为了既不给计算机带来沉重的负担,又能为我们模型增添凹凸的纹理质感,聪明的视觉呈像 师们发明了凹凸纹理叠加材质。这种材质能通过基础材质与凹凸材质的明暗色泽进行线性叠 加,从而从视觉上给人们带来一种表面凹凸的感觉,如图 3-119 所示。这里需要大家记住, 凹凸贴图的浅色表示比高度较高的面,深色则表示比高度较低的面。下面笔者带领大家一起 做一个凹凸贴图的小案例。 图 3-119 (1)、 选取一张砖墙的贴图“wall.jpg”,用 PhotoShop 打开。经过观察之后发现这个砖墙的 纹理分别十分明显,我们只要稍加调整即可做成黑白色泽的凹凸贴图。运用快捷键“Ctrl+S hift+U”对图片进行去色处理,只保留图片的黑色和白色,如图 3-120 所示。 图 3-120 (2)、 快捷键“Ctrl+Alt+M”调出曲线面板,选中曲线的中部往下拖拽,使得图片黑白色泽 对比更加的明显,如图 3-121 所示。调节好之后点击“确定”。 图 3-121 (3)、 在菜单栏上点击“图像”——>“调整”——>“亮度/对比度”打开“亮度/对比度” 调节对话框,勾选“使用旧版”复选框。将对比度的数值往右边拉动,使得黑白的对比更进 一步得到加强,如图 3-122 所示。 图 3-122 (4)、 但这时候的图片与我们前面学到知识正好相违背,这里墙体材质高的面成了黑色,而 墙体材质低的面成了白色,所以我们需要运用快捷键“Ctrl+I”来对图片的颜色进行一下翻 转,翻转之后的效果如图 3-123 所示。完成之后运用快捷键“Ctrl+Shift+S”将图片另存为“w allNormal.jpg”文件 图 3-123 (5)、 将原始的墙体贴图“wall.jpg”和新做好的“wallNormal.jpg”一并放入 Unity3D 项目 文件的“Assets”【资源文件夹】下,打开 Unity3D 在“Project”【项目文件栏】中选中我 们刚刚导入进来的“wallNormal.jpg”, 可 在 “Inspector”【监视面板】中看到许多的材质参 数,关于这些参数的介绍可详见 4.11.5 小节。我们这里将“Texture Type”【材质类型】改 为“Normal map”【凹凸贴图】,然后将“Filtering”【 过滤】从“Sharp”【尖锐】改为“S mooth”【平滑】可以有助于高面与低面进行凹凸显示的时候,中间有个平滑的过度。最后设 置完毕点击“Apply”按钮,可看见“Preview”预览面板中的材质变化,如图 3-124 所示。 图 3-124 (6)、 点击菜单栏上的“Assets”——>“Create”——>“Material”创建一个材质球,并按 下 F2 键给材质球重命名为“normalWall”,并确保新创建的“normalWall”材质球在选中的 情况下,到“Inspector”【监视面板】中,将“Shader”后面的下拉框改为“Bumped Diff use”,这时你可以在下面出现了两个材质接口,一个是“Base”、一个是“Normalmap”,他 们分别对应着物体的基础材质和凹凸贴图材质,将我们的“wall”拖放给“Base”再将“no rmalWall”拖放给“Normalmap”,就可得到一个墙面凹凸材质的材质球了,如图 3-125 所示。 1 2 3 图 3-125 (7)、 点击菜单栏上的“GameObject”——>“Create Other”——>“Cube”在场景中创建 一个立方体,并将刚才创建好的“Normalmap”材质球拖放给这个“Cube”,最后你可看到 如图 3-126 所示的效果图。 图 3-126 以此类推,除了物体表面的凹凸质感可以用贴图叠加形成以外,还有物体表面的光影 信息也同样可以使用“Lightmap”这类的贴图来进行叠加显示。这样除去了计算机对物体表 面渲染信息的实时计算,可极大的提高 3D 游戏的运行速度。 4.25 制作炮弹的射击和爆炸效果 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ (1)、 点击菜单栏的“GameObject”——>“Create Other” ——>“Sphere”创建一个球体 模型,并利用场景调整工具将其调整到和炮口差不多的大小,如图 3-127 所示。 图 3-127 (2)、 找张金属材质的贴图,并运用上一节所学到的知识,在原图的基础上做一张凹凸贴图, 如图 3-128、图 3-129 所示。做好之后将它们拷贝到项目文件夹中“Assets”文件夹内。 图 3-128 图 3-129 (3)、 选中刚才的球体模型,在它的”Inspector”【监视面板】中找到材质球下拉选项框“S hader”。将它的渲染模式改为“Bumped Diffuse”,紧接着和上一节一样将深色的材质贴图 拖放给第一个材质框,将浅色的材质贴图拖放给第二个材质框,如图 3-130 所示。得到一个 带有凹凸材质感的炮弹,如图 3-131 所示: 图 3-130 图 3-131 (4)、 在菜单栏中点选“Assets”——>“Create” ——>“Prefab”创建一个预制类对象, 并按下 F2 键更改它的名字为“Shot”,然后将球体模型模型拖入到预制对象中,并删除场景 面板中的炮弹,如图 3-132 所示。 图 3-132 (5)、 但这时的球体模型仅仅是在外观上有了炮弹的样子,我们还得让它有炮弹一样的物理 特性。确保“Shot”在选中的情况下,在菜单栏中点选“Component”——>“Physics” — —>“Rigidbody”为炮弹添加一个刚体属性。 (6)、 在菜单栏中点选“GameObject” ——>“Create Empty”创建一个空对象放置在炮口, 作为一会炮弹发射的起始点。按下 F2 将其更名为“FirePoint”。然后在 Hierarchy【层次清单 栏 】中 ,把“FirePoint”拖到炮塔上半身的旋转对象中去,这样可以使得它和炮塔一起旋转, 如图 3-133 所示。 图 3-133 (7)、 为炮弹创建一个发射函数。在 Project【项目文件栏】中右键——>“Create” ——> “JavaScript”,创建好之后按下 F2 将其更名为“open fire”。然后双击该文件,输入如下代 码: //定义一个变换对象 FirePoint 作为发射点对象的代码的接口 var FirePoint:Transform; //定义一个刚体对象 Bullet 作为炮弹对象的代码接口 var Bullet:Rigidbody; function Update () { //当鼠标左键按下的时候,就在场景中创建一枚炮弹,并发射它 if(Input.GetMouseButtonDown(0)){ var clone:Rigidbody; //重新实例化对象 clone,让它的坐标位置和方向与发射点对象的一致。 clone = Instantiate(Bullet,FirePoint.position,FirePoint.rotation); //实例化完毕,让炮弹以 100 的速度朝前发射。 clone.velocity = transform.TransformDirection(Vector3.forward*100); } } (8)、 输入完毕之后,将该代码拖拽给 Hierarchy【层次清单栏】中的发射点对象“FirePoi nt”,然后我们会在”Inspector”【监视面板】中的“FirePoint”接口和“Bullet”接口对象为 空。所以我们必须得把发射点对象“FirePoint”和炮弹对象“shot”拖到两个对应的接口上, 如图 3-134 所示。 图 3-134 (9)、 按下测试按钮 看看效果,如图 3-135 所示。大家会发现朝前发射的炮弹在碰到山 体之后,都被弹了起来。所以说此时的炮弹顶多只能算得上一个钢弹,它并不会爆炸。接下 来我们还要继续做出它爆炸的效果。 图 3-135 (10)、 在 Project【项目文件栏】的查找框中输入“fireworks”关键字,将查找到的“firew orks”预置对象拖入到场景面板,你会看到一个动态的实时爆炸火花,如图 3-136 所示。 图 3-136 (11)、 接着确保该对象在选中状态,到它的”Inspector”【监视面板】中调节它的各个属性 值,直到达到你想要的效果为止,如图 3-137 所示。 图 3-137 (12)、 在菜单栏中点选“Assets”——>“Create” ——>“Prefab”创建一个预制类对象, 并按下 F2 键更改它的名字为“boomPrefab”, 然 后 将 这个爆炸火花拖入到预制对象中,并删 除场景面板中的火花。 (13)、 添加一段 JavaScript 代码,取名叫做“boom”,这段代码的主要作用是给炮弹添加一 个碰撞检测。如果炮弹碰撞到任何物体,就让炮弹在舞台上消失,并在炮弹碰撞的地点加载 爆炸火花的预制对象。具体代码如下: //为爆炸火花创建一个接口 var boomFire : Transform; //函数判断物体是否与其他物体产生碰撞,一旦碰撞就执行里面的代码 function OnCollisionStay(collision : Collision) { //实例化一个爆炸火花对象,摆放的职位是当前炮弹的位置,角度是炮弹的角度 Instantiate(boomFire,this.transform.position,this.transform.rotation); //删除掉碰撞的炮弹对象 Destroy(gameObject); } 输入完毕之后,保存该代码,并把这段代码拖放给炮弹预制对象“shot”。并点选预制对象 “shot”,在它的”Inspector”【监视面板】中找到刚才拖放给它的“boom”卷展栏,然后将 爆炸火花预制对象“boomPrefab”拖放给它的接口“boomFire”,如图 3-138 所示。 图 3-138 (14)、 然后运行一下游戏,看看效果。如无意外,大家已经很明显能看到爆炸之后产生的 火花已经出来了,但它会一直在那里闪烁,并不会消失。这严重的违背了现实生活景象,所 以我们还得为它加上一段时间限定消失代码。继续的创建 JavaScript 代码,取名叫做“desB oom”,然后输入如下代码: //创建一个时间接口,这个时间接口不设定数值对象,默认以播放器开始起计算 var creationTime = Time.time; // Awake 函数绝大多数被用于预制对象被调用时执行。这里主要意思是,当爆炸火花被场景 载入时,记录该火花的产生时间 function Awake(){ creationTime = Time.time; } //这段代码的意思是:当前的时间大于爆炸火花产生的时间两秒以上,就让爆炸火花对象消 失。 function Update(){ if(Time.time > (creationTime+2)){ Destroy(gameObject); } } 输入完毕之后,将这段代码拖放给爆炸火花预制对象“boomPrefab”。再次运行游戏,火花 在爆炸产生 2 秒之后就自动消失了。 (15)、 为爆炸添加声音。这个过程十分的简单,只需你在网络上找寻一个你认为合适的声 音,并将这段声音文件添加入项目文件夹的“Assets”内。并在 Project【项目文件栏】中, 将其拖放给爆炸火花的预制对象“boomPrefab”,如图 3-139 所示。这样声音文件就可以和 火花同时产生了。 图 3-139 (16)、 如果你觉得声音需要做适当的调节,例如“是否在预制对象产生时播放?”、“声音 是否需要循环播放?还是只播放一次?”等等这些问题。你都可以在选中预制对象之后,在 它的”Inspector”【监视面板】中找到声音的调节卷展栏,对它进行调节,如图 3-140 所示。  “Play On Awake”【在加载完毕之后自动播放】打勾就意味着在预制对象调用之初 进行播放。不打勾的话,就需要你在代码里用 audio.play()函数来激活。  “Loop”【循环】打勾就意味着让声音文件不断的重复播放,不打勾就只播放一次。  “Volume”【 音量大小】  “Pitch”【 音调】0.5 时很低沉,2 就已经算是高音了。  “Min Distance”【 最小距离】  “Max Distance”【 最大距离】  “Rolloff Mode”【 衰减模式】你也可以在它下面的图形面板手动的调节。但一般 如果你选择的是第一种“Logarithmic Rolloff”模式,播放出来的声音都会比较 小。 图 3-140 (17)创建一个名为“explosionPrefab”的预制对象,然后到“Project”【项目文件栏】上的 搜索栏上输入“Small explosion”找到火舌的预置对象“Small explosion”,并向舞台中拖拽 一个该对象。之后点击搜索栏上的 ,还原原来的“Project”【项目文件栏】,并将刚才的“S mall explosion”拖拽给预制对象“explosionPrefab”,并在场景面板中清除“Small explosio n”。 (18)、 在网络上查找一个开炮的声音文件,并将该声音文件拖拽给预制对象“explosionPr efab”。 (19)、 双击“open fire.js”文件,将代码修改成如下的样子。 var FirePoint:Transform; var Bullet:Rigidbody; //为火舌新增一个接口 var explosionPrefab:Transform; function Update () { if(Input.GetMouseButtonDown(0)){ var clone:Rigidbody; clone = Instantiate(Bullet,FirePoint.position,FirePoint.rotation); clone.velocity = transform.TransformDirection(Vector3.forward*100); //实例化一个火舌对象,火舌的位置为发射点的位置,方向为发射点的方向 Instantiate(explosionPrefab,FirePoint.position,FirePoint.rotation); } } 输入完毕,保存代码并退出。 (20)、 在 Hierarchy【层次清单栏】中选中发射点对象“FirePoint”,然后在它的”Inspector” 【监视面板】中找到“Explosion Prefab”接口,并把火舌预制对象“explosionPrefab”拖拽 给这个接口,如图 3-141 所示。 图 3-141 (21)、 在菜单栏中选中“File”——>“Build Settings”或者按下 Ctrl + Shift + B 键的组 合来发布工程文件,如图 3-142 所示。  “Scenes In Build”【被编译的场景文件】这里面是要发布的场景文件列表。如果 你发现有你所需要的场景没有被列入该面板,那你可以点击“Add Current”按钮 来为该列表添入新的场景文件。后面的数值是场景的加载顺序,0 为最先被加载的 主场景文件。  “Platform”【 导出的文件格式】第一种是网页格式,第二种是 Window 下的 exe 文 件格式,第三种是安卓手机操作系统的格式,第四种是 iPhone 使用的操作系统格 式,第五种是 Xbox 格式,第六种是 PS3 格式,第七种是游戏机 Wii 的格式。如果 你没有购买正式的 Unity3D 专业版软件,那么你只能发布前两种格式的文件。如果 你已经购买了 Unity3D 专业版软件,那么你还得注意第四种 IOS 格式的文件,必须 在苹果的 Mac OS X 操作系统下才能发布。每一种发布的格式,又可以选择它们专 属的发布属性,像网页格式就规定了“Streamed”流媒体发布形式、“Offline Dep loyment”离线调度模式、“Debug Build”调试开发模式。这些方法直接决定了网 页以什么形式来加载 Unity3D 文件,以及它们调试方法等等。  “Player Settings…”【播放器设置】如果你对导出的文件,在播放器上有自己的 个性化要求。那么你还可以点击“Plater Settings…”来对播放器的图标、项目 开发的日期、开发者或是公司的名字,等等进行设定。 图 3-142 最后我们一起来欣赏一下,该项目发布为桌面 EXE 游戏后,在 Window 下的表现。 如图 3-143 所示: 图 3-143 本节小结: 本节中炮弹的飞行是通过“Rigidbody”【刚体】在 Update 里面刷新“velocity”【速度】 来完成的。但在 4.15 小节里面,我给大家说过,Update()的刷帧平率并不固定,也就是 说它的时间物理量并不准确。要想准确运用实际物理时间,请使用 FixedUpdate()函数。 并且可以将刚体的速度函数改换成 AddForce()添加力量函数来试试看。 4.26 制作炮塔的填弹时间来限制开炮的时间间隔,并让 GUI 关 联上这个时间 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ 在真实的炮塔射击中,不可能在炮管中一下子装入无限多颗炮弹,让 你没完没了的射击。 一般情况,一个炮塔除了有一个控制射击的瞄准人员,还得有一个负责装配弹药的填弹人员。 当炮塔将一枚炮弹射出之后,接下来必须由填弹人员迅速的为炮管添加一枚新的弹药,射 击 手才能再次射击。由此炮塔在射击过程中就产生了填弹时间。下面我们一起来看看怎么来实 现这个填弹时间,并让 GUI 动态的显示填弹状态图和百分比数字。 (1)、 双击打开“open fire.js”将代码修改一下,新增部分我会用注释解释。 var FirePoint:Transform; var Bullet:Rigidbody; var explosionPrefab:Transform; //创建一个开火的布尔变量,作为一个是否开火的开关使用 var openFireSwith= false; //创建填弹时间变量 var waitFire = Time.time; function Update () { if(Input.GetMouseButtonDown(0)){ //判断是否允许开火 if(openFireSwith){ //记录下开火的初始时间 waitFire = Time.time; var clone:Rigidbody; clone = Instantiate(Bullet,FirePoint.position,FirePoint.rotation); clone.velocity = transform.TransformDirection(Vector3.forward*15*poweCtrl.powerValue); Instantiate(explosionPrefab,FirePoint.position,FirePoint.rotation); //将开火状态关闭 openFireSwith=false; } } //从开火之时算起,四秒钟之后再一次允许开火 if(Time.time > (waitFire+4)){ openFireSwith=true; } } (2)、 将显示百分比数字的 GUI 更名为“zouGUI”,并为它配置一段初始化代码“guipositi on.js”,该代码的完整片段如下所示: function Awake(){ guiText.text="100%"; } 输入完毕之后,直接将代码拖拽给“zouGUI”。 (3)、 将图形 GUI 对象更名为“shotTime_G”。 (4)、 还记得前面我们导入的五种状态图形吗?现在我们为图形 GUI 书写动态加载各种状 态的代码“shotTimeG.js”,完整代码如下所示: //创建各种状态的图形接口 var T00 : Texture2D; var T25 : Texture2D; var T50 : Texture2D; var T75 : Texture2D; var T100 : Texture2D; //初始化填弹时间,注意这里使用的是 static,证明它可以为全局所用 static var shotTime = 100; function Update () { //初始化动态加载图形 GUI 的对象 var shotTime_G=gameObject.Find("shotTime_G"); //图形 GUI 对象根据填弹时间的大小,来加载不同的状态图形 if(shotTime<=0) { shotTime_G.guiTexture.texture = T00; return; } else if(shotTime<50) { shotTime_G.guiTexture.texture = T25; return; } else if(shotTime<75) { shotTime_G.guiTexture.texture = T50; return; } else if(shotTime<99) { shotTime_G.guiTexture.texture = T75; return; } if(shotTime>=99) { shotTime_G.guiTexture.texture = T100; return; } } 输入完毕之后,将该代码拖拽给摄像机对象 Camera。然后点选摄像机对象,在它的状态栏 中找到刚才的 shotTimeG(Script)卷展栏,并将各个状态图形,一一的拖拽给代码上所对 应的接口。如图 3-144 所示: 图 3-144 (5)、 重新打开“open fire.js”修改代码,将这里的填弹时间与 GUI 显示的百分比和状态图 关联上。请注意一下用方框框出来的代码为新增添的代码: var FirePoint:Transform; var Bullet:Rigidbody; var explosionPrefab:Transform; var openFireSwith= false; var waitFire = Time.time; function Update () { if(Input.GetMouseButtonDown(0)){ if(openFireSwith){ waitFire = Time.time; var clone:Rigidbody; clone = Instantiate(Bullet,FirePoint.position,FirePoint.rotation); clone.velocity = transform.TransformDirection(Vector3.forward*15*poweCtrl.powerValue); Instantiate(explosionPrefab,FirePoint.position,FirePoint.rotation); openFireSwith=false; } } //首先判断是否在等待时间内 if(Time.time <= (waitFire+4)){ //计算等待时间的大小,并折算成百分数赋给 shotTimeG 的静态变量 shotTime shotTimeG.shotTime = Mathf.Round((Time.time-waitFire)*25); //计算等待时间的大小,并折算成百分比赋给 zouGUI 的文字参数。 GameObject.Find("zouGUI").guiText.text=Mathf.Round((Time.time-waitFire)*25)+"%"; } if(Time.time > (waitFire+4)){ openFireSwith=true; } } (6)、 点击测试按钮 ,来看看效果,如图 3-145 所示。 图 3-145 本节小结: 还记得我在 4.15 小节为大家画的时间片段图吗?本节很好的利用了 Awake()函数只在 物体加载时只运行一次的优点,对不需要重复调用和重复判断的变量和事件进行初始化。这 样可以大大的优化游戏引擎的运行速度。除了利用 Awake()函数,Start()函数也是在游戏物 体第一次被画面所渲染的时候只运行一次的函数,所以你可以把需要优化的代码放置到 Sta rt()函数里面。 4.27 为炮塔制作假想敌人 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ (1)、 在菜单栏中选中“GameObject”——>“Create Other” ——>“Cube”,在炮塔旁边 创建一个正方体并将其更名为“tankBody”,并用场景调整工具调整它的大小和位置。 (2)、 创建一个 JS 脚本代码,并命名为“TankLife”,然后输入如下代码,来作为“tankBo dy”的生命减少函数。 var tankLife = 4; function OnCollisionStay(collision : Collision) { //查找所有的碰撞体,如果发现有碰撞体的名字是"shot(Clone)",那么生命值减 1 for (var contact : ContactPoint in collision.contacts) { //这里要特别注意一下,判断炮弹的名字不是"shot"而是"shot(Clone)"" if(contact.otherCollider.name == "shot(Clone)") { if(tankLife>0) { tankLife --; } //当生命值小于 1,物体就消失 if(tankLife<1) { Destroy(gameObject); } } } } 输入完毕之后,将这段代码直接拖放给立方体对象“tankBody”,如图 3-146 所示。 图 3-146 (3)、 点击测试按钮 ,用炮塔对准立方体射击,如图 3-147 所示。连中四发炮弹之后, 立方体果然消失了,如图 3-148 所示。 图 3-147 图 3-148 4.28 添加力量滑动条控制炮弹的发射力度 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ (1)、 创建一个名为“poweCtrl”JS 脚本代码,具体代码如下: //这里设置发炮力度变量 powerValue 的数值为 static,方便其他函数调用 static var powerValue = 3.0; function OnGUI () { //这里设置键盘的两个键来控制滑块的滑动 //这里乘以 Time.deltaTime 函数,是为了滑动更平滑 if (Input.GetKeyDown (KeyCode.Q)&&powerValue>1)powerValue-= 1f*Time.deltaTime; if (Input.GetKeyDown (KeyCode.E)&&powerValue<10)powerValue+= 1f*Time.deltaTime; //这里将滑块的数量值付给发炮力度变量 powerValue //这里的 Rect (5, 100, 100, 30)是设置滑块的位置及滑块的大小。 powerValue = GUI.HorizontalSlider (Rect (5, 100, 100, 30), powerValue, 1.0, 10.0); } 创建完毕之后,将其拖拽给摄像机,如图 3-149 所示。 图 3-149 (2)、 双击打开“open fire”的 JS 脚本,然后在炮弹的初始化速度变量框中加入“poweCt rl”的“powerValue”值来调控炮弹的发射力度,代码如下: var FirePoint:Transform; …… function Update () { …… clone.velocity = transform.TransformDirection(Vector3.forward*15*poweCtrl.powerValue); …… } (3)、 点击测试按钮 ,最终效果如图 3-150 所示 图 3-150 4.29 多炮塔的镜头切换 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\Turret\ (1)、 在 Hierarchy【层次清单栏】中选中炮塔对象,按下 Ctrl+D 复制同样的一个炮塔,将 其拖到其它的位置。 (2)在 Hierarchy【层次清单栏】中选中摄像机对象,在它的”Inspector”【监视面板】中找 到“Smooth Follow(Script)”卷展栏,并点击右边的三角箭头展开它,然后双击 “Smoot hFollow”函数接口来快速的打开“SmoothFollow”脚本,将其中的代码完全拷贝出来。随 后用鼠标右键点击“Smooth Follow(Script)”卷展栏——>“Remove Component”将该组 件从摄像机对象上移除。 (3)、 新建一个名为“followTurret”的 JS 脚本,然后将所有的代码粘贴到这里面来,并稍 微做一点修改。下面我贴出完整的代码,并把改动的地方用线框框出来。 //将原来的跟随对象改为三个,其中的 target 是默认跟随对象,target1 和 target2 是指定跟 随对象。如果你有 N 个摄像机跟随对象,那么就请你在这里改为 N+1 个跟随对象。 var target : Transform; var target1 : Transform; var target2 : Transform; var distance = 10.0; var height = 5.0; var heightDamping = 2.0; var rotationDamping = 3.0; function LateUpdate () { //这里设置,当你按下数字 2 键的时候,将跟随目标改为 target2 if (Input.GetKeyDown (KeyCode.Alpha2)) { target=target2; } //这里设置,当你按下数字 1 键的时候,将跟随目标改为 target1 if (Input.GetKeyDown (KeyCode.Alpha1)) { target=target1; } …… } 编辑完成之后,将该代码拖拽给摄像机对象。 (4)、 在“Hierarchy”【层次清单栏】中点选摄像机对象,继续找到刚才添加的“Follow Turret”展开它,然后将第一个炮塔的顶部对象“mesh4”拖拽给“target”作为摄像机的起 始默认跟踪对象,接着再将第一个炮塔的顶部对象“mesh4”拖拽给“target1”作为数字 1 键的选择跟踪对象,然后将第二个炮塔的顶部对象“mesh4”拖拽给“target2”作为数字 2 键的选择跟踪对象,如图 3-151 所示。. 图 3-151 (5)、 最后点击测试按钮 测试一下我们的小游戏。按下数字 1 和 2 键来回的切换两个 炮塔的视角,然后多角度开炮轰击敌人吧。 本节小结: 到这里我要为炮塔游戏做一个小小的总结了,因为本书篇幅的关系,我不可能教大家做 一个完整的多人在线坦克与炮塔攻防大战游戏,但有兴趣的朋友可以到我的论坛或博客里面 给我留言,咱们可以一起来开发这款游戏。 4.30 如何利用 Asset Server【资源服务管理器】来进行项目的版 本控制和多人协作开发 “Asset Server”【资源服务管理器】是 Unity3D 自带的一种项目资源版本控制器,功能 类似于我们之前所使用的 SVN。通过“Asset Server”【资源服务管理器】良好的使用,你 可以把你正在开发的 Unity3D 项目上传到资源服务器进行存储;可以轻松查看该项目以往开 发过程中上传的历史版本,并进行优劣对比,从中找到你认为满意的修改方案,将其替换掉。 同时你也不必在为不能恢复删除操作而苦恼不已了,“Asset Server”【资源服务管理器】可 以轻松恢复你曾今上传的任何一个历史版本文件。并且通过对“Asset Server”【资源服务管 理器】的使用,能使得一个 Unity3D 共同开发团队突破了地域上的限制,协同能力上得到了 更进一步的加强。 (1)、 到 http://unity3d.com/asset-server 下载适合你服务器操作系统的“Asset Server”【资源 服务管理器】安装配置文件,并在下载好之后安装在你的服务器上面。 (2)、 在第一次安装时,它会提示要求你输入一个密码,这是用于以后你对该资源服务器管 理的密码,请认真填写。安装期间可能会被防火墙和杀毒软件阻止,请全部通过。 (3)、 安装完成之后,会在你安装盘符的根目录下产生很多的 dll 文件,请不要将其删除。 接着到程序启动栏找到“Unity Asset Server”下的“AssetServerControl”将其点击打开。或 者在你安装目录的“bin”文件夹内找到“AssetServerControl”将其打开。 (4)、 点击“Start”按钮,看见上面的字符串变为“Server is running”代表着服务器已经 启动,其他的“Stop”按钮为停止服务器,“Restart”为重启服务,“Reset Admin”为重设 管理员密码,“Quit”为退出服务。 (5)、 回到本地电脑上,打开 Unity3D 在菜单栏中点击“Window”——>“Asset Server” 或用快捷键“Ctrl+0”来打开“Server”面板,如图 3-152 所示。在右上角的添置列表按钮 中找到“Server Administration”,打开“Administration”面板。在“Server Address”后面输 入刚才服务器的 IP 地址或域名,“User Name”后面保有原来的“admin”不变,在“Passw ord”后面输入你配置服务器时,所输入的密码,最后点击“Connect”按钮链接到服务器。 图 3-152 (6)、 链接好之后你可以点击右边的“New User”按钮来为服务器添置一个使用用户,特 别是你的项目是分配给多个工作组开发不同区域工作的时候,就需要用到这项功能。在这里 我们直接点击“Create”,在弹出的“Project Name:”后面输入一个项目名称,点击“Creat e Project”来创建一个新项目。 (7)、 在右上角的添置列表按钮中找到“Connection”,打开“Connection”面板。输入服务 器 IP 地址或域名;输入用户名和密码,默认的是管理员用户“admin”,管理员用户可以控 制所有的项目连接,而其他用户只能链接到拥有管理权限的项目中;点击“Show Projects” 按钮,在右边的“Projects on Server”中找到刚才我们所创建的“teacher”项目,选中它点 ○1 在右上角的添置列 表按钮中找到“Server Administration”,打开 “Administration”面 板 ○2 输入服务器地址和密 码之后,点击“Connect” 按钮连接到服务器 击“Connect”按钮,如图 3-153 所示。 图 3-153 (8)、 点选“Commit”面板——>点击“Add All”按钮,在“Commit Message”面板中输 入第一次项目版本的介绍信息,然后点击“Commit”按钮进行上传,如图 3-154 所示。其 中那些前面带有齿轮标志的文件,是关于该项目的设置文件,比方说我们之前学到的“Proj ect Settings”【项目默认设置】、“Time Manager”【默认时间管理设置】等等。 图 3-154 (9)、 待上传完毕之后,回到“Overview”面板,你可以在“Asset Server Actions”面板下 点击“Show History”按钮来查看该项目的历史版本。在“History”面板中,左边的滑动框 ○1 在右上角的添置列表按 钮中找到“Connection”, 打开“Connection”面板 ○2 输入服务器 IP 地址或域 名,输入用户名和密码, 点 击“Show Projects”按钮 ○3 在右边的“Projects on Server”中找到刚才我们 所创建的“teacher”项 目 , 选中它点击“Connect” 按钮 ○1 点选“Commit” 面板——>点 击“ A dd All”按钮 ○2 在“Commit Message”面 板 中 输入第一次项目 版本的介绍信息 ○3 点击“Commit” 按钮进行上传 摆放的是你当前项目的文件,选中相应的文件你就可以在看到它对应上传的历史版本了,如 图 3-155 所示。然后选中对应的历史版本,你可以点击“Compare to Local Version”按钮 来和当前项目下的文件进行对比,然后来判断是否点击“Download Selected File”按钮来 还原该文件的历史版本,又或则点击“Revert Entire Project to 4005”按钮来还原全部的历 史项目。 图 3-155 4.31 角色系统“Ragdoll”的概念及其运用 本节所对应的视频教学录像:  第十五讲 LocomotionSystem【人物移动系统】 本节所对应的随书光盘源文件地址:  光盘目录:\ Book_Source\Unity3D\4.31\ 角色系统【Ragdoll】也被一些人称作“布娃娃系统”,是 3D 制作人员用来模拟真实人 物物理运动状态的一个系统。下面我用一个简单的例子来为大家说明一下。 (1)、 打开 3DMax 创建一个人物模型,并且将整个模型做成一个完整体。如果你的人物模 型是由多个模型拼接而成,那么请你全选所有的模型之后点击鼠标右键“转换为”——>“转 换为可编辑网络”,并到它们的修改面板中,进入顶点层级将相邻的面焊接起来。 (2)、 在创建面板下,点选系统选择面板中的“Biped”来创建一套人物骨骼,如图 3-156 所示。 图 3-156 (3)、 在运动面板中将“体形模式” 点为高亮,随后利用移动工具和缩放工具来调整 骨骼的大小和位置,让骨骼的各个部位和身体完全吻合。如果在对齐的过程中被模型遮住了 骨骼,导致无法看清对位,那么你可以按下 F3 键,将模型改为线条模式,如图 3-157 所示。 骨骼编辑完成之后,不要忘记到运动面板中将“体形模式” 点回原状态。 图 3-157 (4)、 选中人体模型,在“修改面板”中为它添加一个“蒙皮”,接着到“蒙皮”的骨骼面 板中将人体骨骼全部添加进来,如图 3-158 所示。 图 3-158 (5)、 创建一个名为“firstRagdoll”的项目文件夹,然后用 Unity3D 软件在该项目文件夹中 新建一个工程项目。接着利用前面所学到的知识,创建一个你理想中的地形和一个阳光。 (6)、 回到 3DMax 软件中,先将整个模型渲染成纹理,烘焙的贴图一定要同模型一并放在 “firstRagdoll”项目文件夹的“Assets”文件夹中。渲染成纹理的方法参看前面第三章 3.8 小节。导出 FBX 文件到“firstRagdoll”项目文件夹中的“Assets”文件夹中。在导出的过程 中,一定要注意将导出骨骼选项选中,如图 3-159 所示: 图 3-159 (7)、 回到 Unity3D 的软件环境,将刚才导入的模型拖放一个到“场景面板”中。接着点选 菜单栏中的“GameObject”——>“Create Other” ——>“Ragdoll..”为模型创建一个角色 系统。这里需要大家注意一下,Unity3D 角色系统的身体部位和它的英文名称并不对应,比 方说它的“Knee”并不是指膝盖,而是膝盖以下的小腿部分。下面我要重点说下各部位的 记忆方法,如图 3-160 所示。  Root <—— 对应骨骼的根 Bip01  下面从左脚掌骨骼 Bip01 L Foot 往上数 3 个骨骼,对应角色系统中 Left Foot 往 上数的 3 个骨骼:Left Hips <—— Bip01 L Thigh,Left Knee <—— Bip01 L C alf,Left Foot<—— Bip01 L Foot。  下面从右脚掌骨骼 Bip01 R Foot 往上数 3 个骨骼,对应角色系统中 Right Foot 往 上数的 3 个骨骼:Right Hips <—— Bip01 R Thigh,Right Knee <—— Bip01 R Calf,Right Foot<—— Bip01 R Foot。  下面从左肩骨骼 Bip01 L UpperArm 往下数 2 个骨骼,对应角色系统中 Left Arm 往 下数的 2 个骨骼:Left Arm <—— Bip01 L UpperArm,Left Elbow <—— Bip01 L Forearm。  下面从左肩骨骼 Bip01 R UpperArm 往下数 2 个骨骼,对应角色系统中 Right Arm 往下数的 2 个骨骼:Right Arm <—— Bip01 R UpperArm,Right Elbow <—— Bi p01 R Forearm。  下面还有两块骨骼比较简单:Middle Spine <—— 第一脊髓骨骼 Bip01 Spine,H ead <—— Bip01 Head。 图 3-160 (8)、 全部对应好之后,将“Total Mass”设置为 4,并点击创建按钮“Create”。为了大家 更便于理解,图 3-161 展示了角色系统人体构造解析。 图 3-161 (9)、 点击测试按钮 测试一下角色系统。大家会发现人体模型在没有添加如何力的情 况下倒在了地上,并且姿势随作用力的方向随机摆放。如图 3-162 所示: 图 3-162 4.32 怎样在游戏中为人物添加各种运动动画 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.31\firstRogdoll 在我们日常玩的游戏当中。经常会碰见人物在游戏中做出行走、跑步、跳跃等各种动作。 很可惜的是在 Unity3D 中,这些动作并不依赖于角色系统,但在 Unity3D 的官方网站上有一 个高级人物运动系统的源文件“Locomotion_System”,大家有兴趣可以下载下来研究一下。 网址是:http://unity3d.com/support/resources/unity-extensions/locomotion-ik.html。下面我将为 大家简单讲述一下,如何在 Unity3D 中实现人物根据指令来做出各种动作。 (1)、 打开 3DMax 以及我们上次创作出来的人物模型。在时间轴上 0-19 帧制作人物的站立 动画,在 20-60 帧制作人物的行走动画,在 61-100 帧制作人物的跳跃动画。制作完毕之后, 将动画模型导出到“firstRagdoll”项目文件夹的“Assets”文件夹中,并另外取一个名字叫 做“moveTest.fbx”。 (2)、 打开 Unity3D 软件,到 Project【项目文件栏】中选中刚刚导入进来的“moveTest”, 并在它的”Inspector”【监视面板】中找到“Animations”下的分片列表框,如图 3-163 所示。 图 3-163 (3)、 点击后面的加号对动画进行切割,如图 3-164 所示。下面我为大家详细解说下这里面 的东西。  “Name”【名字】剪裁动画的片段的名字,就拿这个列子来说吧。我根据每个动画 片不同作用,将它们分别命名为“idle”【空闲】、“ Go”【 行 走 】、“ Jump”【跳跃】。  “Star”【开始时间】该剪裁动画所开始的帧。  “End”【结束时间】该剪裁动画所结束的帧。  “WrapMode”【 循环模式】该选择框一共有五种模式“Default”【默认模式】默认 模式的效果几乎和“Once”模式的一样。“Once”【只播放一次】该模式让影片剪辑 播放完之后停在最后一帧。“Loop”【循环播放】该模式可让这段影片剪辑从开始帧 到结束帧,不断的重复循环播放。“PingPong”【乒乓模式】该模式顾名思义就是让 影片剪辑从开始帧到结束帧来回的播放。“ClampForever”【永远的夹钳】让影片剪 辑播放到最后一帧,然后永远停在那一帧,直到下一个动画开始播放。  “Loop”【循环过渡】该复选框一旦被打勾,会自动产生一个从最后一帧到第一帧 平滑过度的帧,对于“Loop”循环模式下的动画尤为有效。 图 3-164 (4)、 拖拽一个“moveTest”的模型到舞台中去,点掉”Inspector”【监视面板】中的 “Pl ay Automatically”【 自动播放】复选框不让模型动画在创建之初播放。然后到菜单栏中选中 “Component”——>“Character”——“Character Motor”给模型添加一个人物控制器,接 着到”Inspector”【监视面板】中的“Character Controller”卷展栏下调节人物控制器的轮廓、 高度等信息,正好使得角色控制器能够完整的框住模型,如图 3-165 所示。 图 3-165 (5)、 接着到菜单栏中选中“Component”——>“Character”——“FPS Input Controller” 给模型添加一个移动控制器,该控制器可以控制模型的前后左右随键盘的方向键移动。再接 着到菜单栏中选中“Component”——>“Camera- Control”——“Mouse Look” 给模型 添加一个旋转控制器,由于我们只希望模型左右旋转,所以还得请你到模型”Inspector”【 监 视面板】的“Mouse Look”卷展栏中将“Axes”选择为“MouseX”,然后将其他的有关 Y 属性的值都调节为零,如图 3-166 所示: 图 3-166 (6)、 选中摄像机对象“Camera”,并到菜单栏中选中“Component”——>“Camera- Cont rol”——“Smooth Follow”给摄像机添加一个跟随组件,在它的”Inspector”【监视面板】 中找到“Smooth Follow(Script)” 卷展栏,并将我们的模型对象拖拽给 “Target”后面的 “Transform”接口,如图 3-167 所示。 图 3-167 (7)、 点击测试按钮,在播放模式下调节“Smooth Follow(Script)” 卷展栏里的各个属性 值,直到调整到你觉得一个满意的跟随效果为止。记住这个参数,因为播放状态下的场景为 调试模式,当你重新将测试按钮点起之后,所有的参数又会恢复。恢复之后,再将“Smoot h Follow(Script)” 卷展栏里的各个属性值设定为前面记录下的参数值。 (8)、 创建一个 JS 脚本,并且取名为“moveAnimationControl”。用来控制模型在运动中对 应的播放各种运动动画。具体的代码如下所示: function Start () { //将跳跃的动画层级设置为 1,层级越高的动画被触发时,就最先被执行,默认的层级都为 零。在这里意味着只要跳跃动画被触发,它将优先与其他的动画被执行。 animation["Jump"].layer = 1; //初始动画状态为静止。 animation.Stop(); } function Update () { //这段代码的意思是,竖直方向的方向键被按下,就播放 Go 动画,否则就还原成站立动画 if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1) animation.CrossFade("Go"); else animation.CrossFade("idle"); //当空格键被按下就执行跳跃动画(*注:由于跳跃动画的层级比其他动画要高,所以当同 时按下方向键和空格键的时候,软件会最先播放跳跃动作) if (Input.GetKeyDown ("space")) animation.CrossFade("Jump"); } 代码输入完毕之后,点击保存 ,并将该代码拖拽给舞台中的“moveTest”模型,如图 3- 168 所示。 图 3-168 (9)、 然后点击测试按钮 测试一下效果,如图 3-169 所示。用键盘的方向键和空格键盘 来控制人物,可以看到我们的人物在里面行走自如,弹跳轻松。是多么的活灵活现啊! 图 3-169 4.33 动画粒子系统【Particle System】 粒子系统顾名思义就是由一个一个很小的粒子构成,并带有一定的物理属性。它可以被 广泛的运用在火焰喷射效果,车辆经过沙漠溅起尘埃等效果的实现。其实在 4.25 小节,我 使用的那个爆炸预制对象就使用了粒子系统,只是当时笔者没有详细为大家讲解而已,下面 就让笔者带领大家进入神奇的粒子系统的世界吧。 (1)、 点选菜单栏中的“GameObject”——>“Create Other” ——>“Particle System”向 舞台添加一个粒子系统,然后我们就可以在舞台上看见一个由无数个小点组成粒子球体,且 它们之间不断的相互运动着,效果如图 3-170 所示: 图 3-170 (2)、 请你确保粒子系统在被选中的状态下,在它的”Inspector”【监视面板】中修改“Elli psoid Particle Emitter”卷展栏下的“Max Size”【粒子最大尺寸】为 0.5(默认与粒子最小 尺寸“Min Size”是一致的,都为 0.1),“Max Energy”【最大生命周期】为 6(默认与最小 生命周期“Min Energy”是一致的,都为 3),这样粒子在产生的过程中将会是 0.1 到 0.5 之 间随机大小的颗粒,存在的生命周期将会是一个 3 到 6 的随机数字。并在“Particle Animat or”卷展栏中找到“Force”【力量】,将其中的 Y 值改为 5,为例子在 Y 方向增加一个 5 的 力量,使它有种向上飘舞的感觉。最终的效果如图 3-171 所示: 图 3-171 有关粒子系统所有有关的参数,见表 3-3、表 3-4、表 3-5 所示。(注:粒子说明文稿,由微 澜虚拟(VRLAND)特别提供支持。) Ellipsoid Particle Emitter(椭圆发射器) Emit 勾选即启动 Min Size 粒子最小尺寸 Max Size 粒子最大尺寸 Min Energy 最小生命周期 Max Energy 最大生命周期 Min Emission 最小发射量 Max Emission 最大发射量 World Velocity 世界坐标系发射速度 Local Velocity 自身坐标系发射速度 Rnd Velocity 随机发射速度 Emitter Velocity Scale 发射器缩放值 Tangent Velocity 正切线发射速度(当只设置一个轴时,发射 范围会沿一个轴平面切齐) Simulate in World Space 勾选则会在世界坐标空间中模拟 One Shot 一秒只发射一次 Ellipsoid 椭圆面大小 Min Emitter Range 发射器的最小范围 表 3-3 Particle Animator(粒子动画) Does Animate Color 是否启动颜色动画 Color Animation 颜色变化选择 World Rotation Axis 让粒子以世界坐标系的 XYZ 方向旋转 Local Rotation Axis 让粒子以自身坐标系的 XYZ 方向旋转 Size Grow 让粒子以设定的比例随机变大或增加 Rnd Force 随机在每帧增加一个力看起来更生动。数字 越高,随机变化的程度也就越高。 Force 为粒子增加一个固定的施力方向。数字越大, 粒子所受到的力度也就越大。 Damping 粒子在运动过程中的衰减值。默认为 1,为 无 衰减状态,小于 1 之后便开始产生衰减。 Autodestruce 勾选之后。粒子系统所有的粒子在消失之后, 承载它的 GameObject 对象也跟着消失。 表 3-4 Particle Render(粒子渲染) Cast Shadows 是否产生阴影 Receive Shadows 是否接受阴影 Materials 粒子外观的材质 Camera Velocity Scale 改变这栏的数字,将会使得粒子在摄像机前 的渲染效果有所不同。 Stretch Particles 拉伸粒子,以达到镜头想要得到的效果。 Billboard 当粒子面对镜头时才呈现 Stretched 朝粒子运动的方向去做拉伸延展 Sorted Billboard 当使用混合材质时,粒子会依照距离镜头的 远近做排列 Vertical Billboard 所有粒子沿着竖直方向上拉伸 HorizontalBillboard 所有粒子沿着水平方向上拉伸 Length Scale 粒子被拉伸的程度,必须在 Stretch Particles 中使用了拉伸效果才能起到作用。 UV Animation 使粒子产生 UV 动画效果 X Tile 沿着 X 轴,每帧产生一次位移 Y Tile 沿着 Y 轴,每帧产生一次位移 Cycles 多久循环一次 表 3-5 高级进阶: 可新建一个模型,然后选中这个模型,点击 Component——>Particles——Mesh Patticle Emitter,添加一个以面的顶点为轴心的粒子喷射器,再接着点击 Component——>Particles— —> Particles Animation 为该喷射器添加一个动画,再接着点击 Component——>Particles— —>Particle Renderer 为粒子添加渲染。另外可以点击 Component——>Particles——>World Particle Collider 为例子添加物理碰撞。 4.34 为什么 Unity3D 能使用多种语言脚本进行开发,并且编译脚 本为什么能够跨平台 为什么 Unity3D 能使用多种语言脚本进行开发?这就不得不说一下 Mono 了,还记得我 们上一章节讲到的 Java 夸平台运行机制吗?Mono 也有包含一个虚拟机,且 Mono 虚拟机包 含一个实时编译引擎,该引擎可用于如下处理器:x86,SPARC,PowerPC,ARM,S390(3 2 位模式和 64 位模式),x86-64,IA64 和 64 位模式的 SPARC。该虚拟机可以将代码实时编 译或者预先编译到本地代码。对于那些没有列出来的系统,则使用的是代码解释器。并 且“ C ommon Language Runtime,缩写 CLR”【 公共语言运行时】已由 Mono 实现,该运行时用于 执行已编译的.NET 应用程序。运行在“CLR”【 公共语言运行时】上的代码都不是编译为本 地代码,而是编译成“Common Intermediate Language,缩写为 CIL”【 公共中间语言】它 将由 Mono 的编译器转换成机器代码。另外 Mono 作为在.NET Framework“Common La nguage Specification,缩写 CLS”【 公共语言规范】和“Common Language Runtime, 缩写 CLR”【 公共语言运行时】开发起来的语言对微软封装的大部分类库调用有着良好 的支持,图 3-172 展示了 Mono 的一个基本运行流程图。 图 3-172 但这里需要让大家注意一下,虽然 Mono 上的脚本都是工作在公共语言运行时之上的, 并且最终他们都会被编译为“CIL”【公共中间语言】,所以用 Mono 编辑器编写的 JavaScrip t 调用系统的 API 已经不再成为什么难事。但就 JavaScript 的语法而言,本身就是一种弱语 言,包含了大量隐式,这些隐式在被解释成为“CIL”【公共中间语言】时往往需要让计算 机多做几道转换,这种转换在少量代码开发的时候凸显不出来,但如果开发海量代码的工程 文件时,就会给 CPU 的耗费带来隐患。这也是笔者为什么会在 4.36 小节给大家介绍与“Vi sual Studio”结合高效开发 Hummer 小游戏的主要原因。 4.35 为什么 Unity3D 网页播放器在 Windows 下只有 570KB 的大 小 为什么 Unity3D 网页播放器在 Windows 下只有 570KB 的大小?这个问题这段时间一直 有人在询问我,所以本人觉得很有必要将它单独列出来给大家讲一讲,但本节内容只作为笔 者多年学习的一种揣测,仅供大家参考。用 570KB 的播放器去解析庞大而华丽的 3D 场景, 这在以前似乎是天方夜谭。但随着 DirectX 和 OpenGL 在操作系统上的封装技术日趋完善, 这种播放器技术在今天成为了事实。 为什么 Unity3D 网页播放器在 Windows 下只有 570KB 的大小?其实道理很简单,Dire ctX 和 OpenGL 控制着硬件具体的 3D 图形绘制方法,而每一个方法又被封装在了 Windows 操作系统的共享库里面,比方说 DirectX 对应的封装库路径有“C:\WINDOWS\ServicePackF iles\i386”下的 d3dx9_xx.dll 和 d3dx10_xx.dll 系列文件,又比方说 OpenGL 对应的封装库路 径有“C:\WINDOWS\system32”下的 OPENGL32.DLL 文件,这样游戏引擎在给每个物体添 加阴影材质的时候,就不用去具体的写任何代码,而只用给封装库传达一个指令,然后由硬 件直接进行渲染即可。所以你可以在 Unity3D 的灯光中很容易的找到“Hard Shadows”【硬 件阴影】,这是最理想的阴影制造方法了,通过调用硬件封装好的 API 直接实现,实现速度 快,效果也很理想。但对于那些旧式电脑,电脑的图形卡并不支持这么高端的图形渲染封装, 但你又想实现这种阴影效果,那就只有找到“Soft Shadows”【软件阴影】的方式进行渲染 了,这种方式就必须靠计算机对具体阴影代码的计算而得到,会耗费计算机大量的运行资源。 4.36 与“Visual Studio”结合,高效开发 Hummer 小游戏 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 新建一个名为“Hummer”的文件夹,并打开 Unity3D 制作软件。在 Unity3D 中新建 一个项目,并把刚才建立的“Hummer”作为项目文件夹来使用。 (2)、 为了便于管理,我们在新建项目的 Project【项目文件栏】中点击鼠标右键——>“Cr eate”——>“Folder”新建六个文件夹,并分别命名为“Animation”、“ Audio”、“ Materials”、 “Prefab”“ Script”、“ Stage”用来存放不同用途的文件。 (3)、 Ctrl+S 保存当前场景到“Stage”文件夹中,并取名叫做“Logo”。在菜单栏中找到“E dit”——>“Preferences…”,在弹出的“Unity Preferences”对话框中找到“External Script Editor”并将它后面的下拉框选中为“Browse…” 浏览到我们“Visual Studio”可执行文件 存放的地方。这里我们将代码编辑器改成“Visual Studio”以便利用它和 C#高效的协同开 发游戏。然后我们右键点击 Project【项目文件栏】中的“Script”文件夹——>“Create”— —>“C Sharp Script”新建一个 C#脚本,并将它更名为“Logo”。这时候如果你将它拖到舞 台的上的任意对象上,看见系统报错,如图 3-173 所示。 图 3-173 还记得我前面所学到的面向对象的编程语言吧?C#作为此类语言的一种,严格遵守类名必 须与文件名相同的规则。所以这时候我们必须打开“Logo.cs”这个文件修改其类名为“Lo go”才行。 (4)、 在 Project【项目文件栏】中的“Script”文件夹下找到我们刚才新建的“Logo”脚本 文件并双击打开它。稍等片刻之后可以看到“Logo”脚本已经被“Visual Studio”所打开, 并且我们的“Visual Studio” 会在项目文件夹下自动为 Unity3D 创建了一套项目文件,如 图 3-174 所示: 图 3-174 (5)、 大家会在打开的“Logo”脚本中发现自动添加了“Start”和“Update”两个代码段, 这是 Unity3D 为了方便开发者而做的模块。我们首先将现在的类名改为“Logo”让它同文 件名一致,如图 3-175 所示。 图 3-175 (6)、 紧接着在“Visual Studio”软件中点击“文件”——>“导出模版”,在弹出的对话框 中选择“项模版”,然后点击下一步,如图 3-176 所示。 将现在的类名改 为“Logo”让它 同文件名一致 图 3-176 (7)、 紧接着选中你要导出的模版文件“Logo.cs”然后点击下一步,如图 3-177 所示。 图 3-177 (8)、 在图 3-178 的这个面板中,不选任何的东西,直接点击下一步。 图 3-178 (9)、 在图 3-179 这个窗口中写上模版的名字“Unity3DScript”和模版的说明文字“Unity3 D 脚本专用模版”,然后点击“完成”。 图 3-179 (10)、 这时我们就已经将这套程序作为一个模版保存进了“Visual Studio”里面,如果你 下一次还要在新建一个 C#脚本的时候,就不必在 Unity3D 中去建立了,直接在“Visual St udio”里面创建即可。例如下面我们新建一个“Player”的脚本,在“Visual Studio”的“解 决方案资源管理器”中右键点击“Script”文件夹——>“添加”——>“新建项”,在弹出的 对话框中找到我们刚才新建的模版“Unity3DScript”,然后输入新建的脚本名字“Player”, 然后点击添加,如下图 3-180 所示。 图 3-180 (11)、 这时我们会惊奇的发现,在“Visual Studio”中新添加的脚本连类名都不需要你改 了,实在是很方便,如下图 3-181 所示。 图 3-181 4.37 利用内置动画系统来制作游戏的开场画面 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer 在几乎所有的游戏中,开始运行的时候总会显示一些关于游戏制作者、游戏公司的 Lo go 出现。在 Unity3D 中,大家可以利用它自身的内置动画系统来轻松解决这个事情,下面 我接着上一节的内容就来教授大家如何来制作。 (1)、 将你需要显示的 Logo 图片放入项目文件夹的“Assets”文件夹内的“Materials”里 面 。 (2)、 在“Logo”场景中,选中默认摄像机“Main Camera”,在它的”Inspector”【监视面 板】中将“Projection”【投射】由原来的“Perspective”【透视】11改为“Orthographic”【正 射】12这样可以使得摄像机的视野由棱锥变为长方形,不再有视觉错差的感觉,观看的景象 就像是一个 2D画面,如图 3-182 所示。 图 3-182 (3)、 并接着在“Inspector”【监视面板】中把摄像机的背景颜色“Background”改为黑色。 (4)、 在菜单栏中点击“GameObject”——>“Create Other”——>“Plane”创建一个平面, 然后用旋转工具调整它的正面面向摄像机。这时候大家可以试着用移动调整工具 来拉 近平面和镜头之间的距离,发现平面并没有因为离摄像机近了而改变自己的显示大小,正如 我之前所说的,在摄像机的“Orthographic”【正射】模式下,一切显示物体都已经变为 2D 的成像效果了。为了能显示出一个饱满的 Logo 图像,我们利用缩放工具 将平面拉伸到 和屏幕一样的大小。然后再将事先准备好在 Project【项目文件栏】中的 Logo 图片拖放给这 个平面,如图 3-183 所示。 11 "Perspective Projection"【透视投影】符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远 到极点即为消失,成为灭点。它的视景体类似于一个顶部和底部都被切除掉的棱椎,也就是棱台。这个投 影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。 12 "Orthographic Projection"【正射投影】,又叫平行投影。这种投影的视景体是一个矩形的平行管道,也就 是一个长方体。正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。这种投 影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变, 以便施工或制造时物体比例大小正确。 图 3-183 (5)、 但这时我们会发现 Game【动画面板】中的图像似乎显得非常暗淡,如图 3-184 所示。 图 3-184 这时可能你也许会想到添加灯光以照明图像。这是一个聪明的做法,但为了保证我们的图像 显示的明暗度能达到 100%的均匀,请你点击菜单栏中“Edit”——>“Render Settings”,然 后到“Render Settings”【默认渲染设置】的”Inspector”【监视面板】中找到“Ambient Li ght”【环境灯】,将后面的颜色调节为一个偏白色的颜色,即可增加亮度。 (6)、 确保平面对象“Plane”在选中的情况下,到它的”Inspector”【监视面板】中找到材 质卷展栏,点击它的色彩调节按钮“Main Color”,如图 3-185 红框标出来的部分。 图 3-185 (7)、 在弹出的“Color”【色彩调节面板】中,大家可以在最下面发现 R、G、B、A 四个 调节框,分别代表物体的红色、绿色、蓝色、不透明的调节。但这个时候我们去拨动不透明 度的滑块“A”,或则试图改变不透明的数值时,会发现对物体对象的显示毫无作用。这是 由于默认的材质模式不支持 alpha 通道的缘故,只要我们在材质卷展栏中,将“Shader”后 面的下拉选项选作为“Transparent”——>“Diffuse”就可调节透明度了。 (8)、 在任意一个面板上点击右上角的添置列表按钮 ——>“Add Tab”——>“Animati on”添加一个动画面板;或在菜单栏中点击“Window”——>“Animation”, 打开动画面板, 如图 3-186 所示。 图 3-186 (9)、 在“Hierarchy”【层次清单栏】中选中我们的平面对象“Plane”,到 Animation【动画 面板】中点击录制按钮 ,给平面对象“Plane”添加一个动画,并在弹出的存储窗口中将 该动画取名为“Logo”并存储在我们建立的“Animation”文件夹中。在动画面板中,我可 以看到平面对象的“Plane”的位置、旋转角度、尺寸等等都可以用来做动画,如图 3-187 中的列表。 图 3-187 (10)、 这里我们只做平面的透明度动画,所以请在 Animation【动画面板】中将材质球“L ogo 1(Material)”展开,并在其中找到“Color.a”在最上面点击增加关键帧的按钮 ,然后 将“Color.a”后面的数值改成 0,让 Logo 在场景刚刚出现的时候不显示。紧接着,我们将 时间轴移动到 2 秒的这个位置 ,再点击增加关键帧的按钮 , 然后将“Color.a”后面的数值改成 1,让 Logo 在场景中慢慢的渐变显示出来。 (11)、 接着按住 Ctrl 键不放,滑动鼠标滚轮,以增加时间时间轴的显示长度,然后将时间 轴移动到 3 秒的这个位置 ,再点击增加关键帧的按钮 ,不做 任何设置,让 Logo 在画面中静止 1 秒中的时间。 (12)、 紧接着将时间轴移动到 5 秒的这个位置,再点击增加关键帧的按钮 ,然后将“C olor.a”后面的数值改成 0,让 Logo 在场景中慢慢的淡出画面。 (13)、 双击“Script”文件夹下面的“Logo”脚本,然后在 VS(下面的文章用 VS 来指代 Visual Studio)中将“Logo”脚本改成如下的代码段: using UnityEngine; using System.Collections; public class Logo : MonoBehaviour { void startGame() { Application.LoadLevel(1); } } 输入完毕点击保存。由于 startGame()并不是 Unity3D 中时间轴函数,也不是构造函数,所以 在没有事件对它进行触发的时候,它是不被运行的。接着将这段代码拖放给我们的平面对象 “Plane”。 (14)、 回到 Animation【动画面板】中,确保平面对象“Plane”在选中的情况下,在动画 剪辑选择框中选择我们之前创建的“Logo”动画,如图 3-188 所示: 图 3-188 (15)、 点击录制按钮 ,重新激活该动画剪辑编辑状态,让后将时间滑块拖动到动画结 束的那一帧,并双击时间刻度线下面的那一个横栏,如图 3-189 所示。 图 3-189 (16)、 这时候会弹出一个“Edit Animation Event”【动画事件编辑器】,请将“Function N ame:”后面的下拉框选择为我们的场景切换函数“startGame()”,如图 3-190 所示。编辑完成 之后,Ctrl+S 保存我们的动画。 图 3-190 (17)、 点击运行按钮,运行一下游戏看看。当 Logo 最后消失的时候,控制面板报错:“Le vel couldn’t be loaded because it has not been added to the build settings.”,这是由于我 们的下一个场景还没有创建,所以动画事件 startGame()无法加载一个不存在的场景。所以我 们得 Ctrl+N 创建一个新的场景,并 Ctrl+S 保存该场景名为“start”,将它存储在“Stage”文 件夹的下面。 (18)接着点选菜单栏中的“File”——>“Build Settings…”,在弹出框中将我们的两个场 景“Logo”和“Start”先后拖放入“Scenes In Build”,并确保它们后面的序号“Logo”为 0、 “Start”为 1,这直接决定了它们的加载顺序,startGame 中的加载代码“Application.LoadL evel(1)”就是指加载后面序号为 1 的场景,如图 3-191 所示。 图 3-191 (19)、 重新点击运行按钮看看,当 Logo 播放结束,顺利的加载了场景“start”,如图 3-19 2 所示。 图 3-192 4.38 利用代码绘制 GUI 背景图片和 GUI 按钮 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 接着上一节的内容,我们双击“Stage”文件夹下的“start”场景文件,来到“start” 场景中。 (2)、 创建一个游戏开始时需要展现的图片“humen.jpg”,并保存到“Materials”文件夹中。 (3)、 双击“Script”文件夹下的任意一个 C#脚本来启动 VS 软件。在 VS 的编程环境中, 鼠标右键点击“Script”文件夹——>“添加”——>“新建项”,新建一个名为“startGame. cs”的脚本,然后输入代码: using UnityEngine; using System.Collections; public class startGame : MonoBehaviour { //创建一个材质对象“backGround”,主要用作感应背景图片的接口 public Texture backGround; void OnGUI(){ //绘制一个背景图片,坐标 X 等于、Y 等于、宽度等于场景的宽度、高度等于场景 的高度,绘制的对象是 backGround 所感应进来的材质图片 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), backGround); } } 然后将这段代码拖放给摄像机对象“Main Camera”, 并在“Hierarchy”【层次清单栏】点选 “Main Camera”,到它的“Inspector”【监视面板】中找到刚才添加的“startGame(Script)” 组件卷展栏,将图片“humen.jpg”拖放到“Back Ground”后面的接口上,如图 3-193 所示。 图 3-193 (4)、 Ctrl+N 创建一个新的场景,并 Ctrl+S 保存该场景取名为“gameScreen”,将它存储在 “Stage”文件夹的下面,用它来做为游戏的运行场景。紧接着点选菜单栏中的“File”——> “Build Settings…”,在弹出框中将我们新建的场景“gameScreen”拖放入“Scenes In Buil d”,如图 3-194 所示。 图 3-194 (5)、 双击“Script”文件夹下的“startGame”C#脚本,在其中添加一段跳转到“gameScre en”场景的按钮代码,如下面红框框出来的部分: using UnityEngine; using System.Collections; public class startGame : MonoBehaviour { //创建一个材质对象“backGround”,主要用作感应背景图片的接口 public Texture backGround; void OnGUI(){ //绘制一个背景图片,坐标 X 等于、Y 等于、宽度等于场景的宽度、高度等于场景 的高度,绘制的对象是 backGround 所感应进来的材质图片 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), backGround); //绘制一个跳转到“gameScreen”场景的按钮 if (GUI.Button(new Rect(Screen.width/2 - 100f, Screen.height/2 - 30f, 200f, 60 f), "Start Game")) Application.LoadLevel(2); } } (6)、 紧接着双击“Stage”文件夹下的“start”场景文件,回到“start”场景中,点击一下 测试按钮 ,可以看到如图 3-195 的效果。 图 3-195 (7)点击“Start Game”按钮,就可以跳转到我们新建的场景“gameScreen”中(注:在 “start”场景中的画面,完全由 GUI 代码绘制而成,所以在你未对项目运行的时候,Game 【动画面板】中将不会显示任何东西。)。当然,如果你对现在的字体样式和字体颜色不满意 的话,我们只需要为它附加一个 GUISkin,既可以改变 GUI 的样式。改变后的按钮代码如 下: using UnityEngine; using System.Collections; public class startGame : MonoBehaviour { //创建一个材质对象“backGround”,主要用作感应背景图片的接口 public Texture backGround; //创建一个 GUI 皮肤对象“customSkin”,主要用作感应外部 GUI 的接口 public GUISkin customSkin; void OnGUI(){ //绘制一个背景图片,坐标 X 等于、Y 等于、宽度等于场景的宽度、高度等于场景 的高度,绘制的对象是 backGround 所感应进来的材质图片 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), backGround); //设置 GUI 的皮肤 GUI.skin = customSkin; //绘制一个跳转到“gameScreen”场景的按钮 if (GUI.Button(new Rect(Screen.width / 2 - 100f, Screen.height / 2 - 30f, 200f, 6 0f), "Start Game")) Application.LoadLevel(2); } } (8)、 紧接着点选菜单栏中的 “Assets”——>“Create” ——>“GUI Skin”创建一个皮 肤组件,然后点选这个新创建的皮肤组件,在它的”Inspector”【监视面板】中找到“Butto n”这一项,然后将它里面的字体颜色设置为黄色、字体大小为 20、字体样式为加粗,如图 3-196 中框选出来的部分。 图 3-196 (9)、 接着选中摄像机对象“Main Camera”到它的“Inspector”【监视面板】的“startGam e(Script)” 组件卷展栏下找到新添加的接口“Custom Skin”,然后将将我们新创建的皮肤 组件拖放给这个接口,如图 3-197 所示。 图 3-197 (10)、 我们重新运行一下“start”场景,可以看到按钮的颜色和字体已经改变了,如下图 3 -198 所示。 图 3-198 4.39 创建一个不断重复播放的 2D 背景 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 双击“Stage”文件夹下的“gameScreen”场景文件,来到“gameScreen”场景中。点 选默认摄像机“Main Camera”,在它的“Inspector”【监视面板】中将“Projection”【投射】 由原来的“Perspective”【透视】改为“Orthographic”【正射】。 (2)、 创建一个平面,并旋转这个平面的正面面向摄像机,并缩放这个平面的宽度为舞台宽 度,高度为舞台高度的两倍(注:这里之所以要设置高度为舞台高度的两倍,是因为这样方 便做向下运动的循环动画。),位置为(0,0,0),然后拖放一个长宽比例与之相同的沙土贴 图给这个平面。如图 3-199 下所示。 图 3-199 (3)、 这时的场景颜色显得过于暗淡,为了增强场景亮度,我们点选菜单栏中“GameObje ct”——>“Create Other” ——>“Directional Light”来添加一个定向光源作为阳光。添加 后的太阳光入射角度与我们的平面正好垂直,光照为最充足的状态。如果你发现场景中依然 没有什么光照,那请你自行调整“Directional light”的光照角度。添加阳光后的场景亮度对 比,如图 3-200 所示。 图 3-200 (4)、 为平面添加一段运动代码,让平面从上至下的不断循环滚动。来到 VS 环境下面,鼠 标右键点击“Script”文件夹——>“添加”——>“新建项”,新建一个“rollBg.cs”的脚本, 具体代码如下: using UnityEngine; using System.Collections; public class rollBg : MonoBehaviour { //定义地平面移动的初始速度 public static float bgSpeed = 100; void Update() { transform.Translate(Vector3.down * Time.deltaTime * bgSpeed,Space.World); //如果地平面移动到舞台的最下方,就让它重新回到舞台的最上方,不段的反复滚 动。 if (transform.position.y < -105) transform.position = new Vector3(transform.position.x, 110f, transform.position.z); } } 写完之后,将这段代码拖放给地平面对象“Plane”。 4.40 用代码控制石头随机掉落的位置、形状、和旋转角度,并用 “Horizontal”来控制汽车的运动 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 利用 3D Max 创建一个迎面而来的石头模型。如图 3-201 所示。 图 3-201 (2)、 建好之后,将它导出到“Prefab”文件夹内,并命名为“stone.fbx”。接着再利用 3D Max 创建一个 Hummer 汽车的模型,如图 3-202 所示。由于我们只是从车顶观看整个模型, 所以在材质和模型细节方面可以不用过多的去在意。建好之后,将它导出到“Prefab”文件 夹内,并命名为“hummer.fbx”。 图 3-202 (3)、 将石头模型“stone”拖放到舞台可视范围的最上方,将汽车模型“hummer”拖放到 舞台可视范围的最下方,如图 3-203 所示。 图 3-203 (4)、 但这时候的模型似乎显得过于渺小,请分别点击 Project【项目文件栏】中的源模型 文件“stone”和“hummer”,并在他们“FBXImporter”卷展栏下,将“Scale Factor”数值 调节到你认为可以的模型大小数值(注:在调节过程中,你不会立刻看到模型的大小变化, 请在”Inspector”【监视面板】的最下面点击“Apply”按钮)。然后接着旋转汽车的模型顶 部面向我们的摄像机。最后在 Game【动画面板】观看到的最终效果如图 3-204 所示。 图 3-204 (5)、 来到 VS 的编程环境中,鼠标右键点击“Script”文件夹——>“添加”——>“新建 项”,为石头添加一个运动控制脚本“enemyStone.cs”,具体的代码如下: using UnityEngine; using System.Collections; public class enemyStone : MonoBehaviour { //初始化石头的运动速度 public static float moveSpeed=100f; //初始化石头的活动范围为舞台的宽度范围 private float EmaxWidth = 140f; private float EminWidth = -140f; private float EresetPosition; //初始化石头的角度旋转范围 private float EmaxRotate = 180; private float EminRotate = -180; private float EresetRotate; //初始化石头的大小变化范围 private float EmaxScale = 1.3f; private float EminScale = 0.9f; private float EnewScale; void Start() { //游戏刚开始运行的时候,让石头复位 transform.position = new Vector3(0f, 105f, 0f); } // Update is called once per frame void Update() { //在石头的最大和最小活动范围内,读取一个随机值 EresetPosition = Random.Range(EmaxWidth, EminWidth); //在石头的最大旋转角度和最小旋转角度范围内,读取一个随机值 EresetRotate = Random.Range(EmaxRotate, EminRotate); //在石头的最大缩放值和最小缩放值之间,读取一个随机值 EnewScale = Random.Range(EmaxScale, EminScale); //设置石头向下移动,并且坐标参考是“Space.World”世界坐标 transform.Translate(Vector3.down * moveSpeed * Time.deltaTime,Space.World); //如果石头的坐标值低于舞台可视范围的最低坐标值,就让石头复位,且变换一下 石头的位置、角度和大小 if (transform.position.y < -105f) { transform.position = new Vector3(EresetPosition, 105f, transform.position.z); transform.Rotate(new Vector3(EresetRotate, EresetRotate, EresetRotate)); transform.localScale = new Vector3(EnewScale, EnewScale, EnewScale); } } } 保存脚本之后,回到 Unity3D 环境并将该代码拖放给舞台上的“stone”,然后点击运行一下 游戏。大家会看到石头“落”到舞台的下方之后,又从上方继续的掉落下来,但从新掉落的 石头形状、大小、和位置已经不再相同,如图 3-205 所示。 图 3-205 (6)、 点击菜单栏中的“Edit” ——> “Project Settings”——>“Input”,然后在”Inspec tor”【监视面板】中点开“Axes”卷展栏,大家可以在这里看到系统已经为我们内置了一些 控制对象动画和运动的按钮,再进一步打开“Horizontal”卷展栏,我们可以看到这是一个 专为控制物体在水平轴线方向上运动的内置按钮,且默认的是用“←”键“Negative Butto n Left”和“→”键“Negative Button right”来控制,或是用“A”键“Alt Negative Butt on a”和“D”键“Alt Negative Button d”来控制。且默认的运动轴线是 X 轴 “Axis X axis”。 (7)、 直接双击“Script”文件夹下的“Player”脚本(注:这个脚本是我们之前就已经创建 好了的),然后输入汽车的控制脚本,具体代码如下所示: using UnityEngine; using System.Collections; using UnityEngine; using System.Collections; public class Player : MonoBehaviour { //初始化汽车的运动速度 public static float PlayerSpeed = 50; void Update() { //设置汽车随着键盘的上的“A”和“D”,或者是“←”和“→”键按下来移动 float hummerMove = Input.GetAxis("Horizontal") * PlayerSpeed * Time.deltaTim e; transform.Translate(Vector3.left * hummerMove); //如果汽车超过舞台的显示范围,则设置它从另外的一边出现 if (transform.position.x < -140f) transform.position = new Vector3(140f,transform.p osition.y,transform.position.z); if (transform.position.x > 140f) transform.position = new Vector3(-140f, transform. position.y, transform.position.z); } } 4.41 创建相撞时的爆炸效果,和碰撞测试代码 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 点击菜单栏“GameObject”——>“Create Other” ——>“Particla System”添加一 个粒子系统,并调节粒子系统的属性参数如下,使它呈现一个爆炸的扩散状态。具体参数: Min Size:10(粒子的最小尺寸为 10), Max Size:15(粒子的最大尺寸为 15),Min Energy 0.5(粒子的最小生命周期为 0.5),Max Energy 1(粒子的最小生命周期为 1)将这个周期 调短是由于爆炸之后出现的火光很短,调短之后可以使得画面看上去更有张力。Min Emiss ion 80(最小发射量为 80),Max Emission 100(最大发射量为 100),Tangent Velocity 下 的 X 和 Z 为 30,代表粒子爆炸向四周散发的半径为 30。将“One Shot”复选框勾上,让粒 子呈现出从中心向外炸开的效果,如图 3-206 所示。 图 3-206 (2)、 然后到“Particle Animator”卷展栏下调节颜色,使得粒子更像火焰。并将“Autodes truct”复选框打上勾,使得爆炸效果只进行一次,如图 3-207 所示。 图 3-207 (3)、 在菜单栏中点击“Assets”——>“Create” ——>“Prefab”,创建一个预置对象并取 名叫做“Boom”,将我们刚创建的粒子系统和爆炸的声音文件都拖放给它,如 图 3-208 所示。 然后将“Hierarchy”【层次清单栏】中的“Particle System”删除。 图 3-208 (4)、 双击“Script”下的“Player”脚本,为汽车添加碰撞爆炸脚本,具体代码如下面框出 来的代码部分: using UnityEngine; using System.Collections; public class Player : MonoBehaviour { public static float PlayerSpeed = 50; //初始一个游戏对象“boom”,用它来感应爆炸的预置对象 public GameObject boom; void Update() { float hummerMove = Input.GetAxis("Horizontal") * PlayerSpeed * Time.deltaTim e; transform.Translate(Vector3.left * hummerMove); if (transform.position.x < -140f) transform.position = new Vector3(140f,transform.p osition.y,transform.position.z); if (transform.position.x > 140f) transform.position = new Vector3(-140f, transform. position.y, transform.position.z); } //设定一个碰撞检测函数 void OnTriggerEnter(Collider otherObject) { //如果碰撞对象的标签叫做“stone”那么就 Instantiate(初始化)一个爆炸对象,并 让汽车对象消除 if(otherObject.tag=="stone"){ Instantiate(boom, transform.position, transform.rotation); Destroy(gameObject); } } } 代码改写完毕,在“Hierarchy”【层次清单栏】中选中“stone”,然后到它的“Inspector”【监 视面板】中找到 Tag 后面的下拉框,点选“Add Tag…”添加一个名为“stone”的标签。 (5)、 重新在“Hierarchy”【层次清单栏】中选中“stone”, 在它的“Inspector”【监视面板】 中将 Tag 后面的下拉框改选为刚才添加进来的标签“stone”。 (6)、 紧接着,我们分别点选汽车对象“Hummer”和石头对象“stone”,在菜单栏中“Co mponent”——>“Physics”——>“Rigidbody”分别为汽车对象和石头对象添加一个刚体属 性。然后运行一下程序试试看,大家发现了什么?石头和汽车并未检测到任何的碰撞,这 究 竟是什么原因呢?那是因为碰撞一定要有碰撞边沿才能检测得到,而 Unity3D 中创建的物体 自身就带有碰撞边沿,但从外部加载进来的模型却是没有的。表 3-6 为 Unity3D 中添加内置 物体对象,所对应“Inspector”【监视面板】中内置的碰撞器。从表中不难看出,碰撞器除 了“Is Trigger”【 触 发 器 开 关 】、“ Size”【 尺 寸 大 小 】、“ Center”【中心位置】等系列参数的 调节外,还有一个很重要的“Physic Material”【物理材质接口】,它决定了碰撞体表面的物 体材质特性,关于物理材质笔者会在会面的章节为大家讲述,这里只要让大家了解一下就可 以了。 立方体中的碰撞器。 球体中的碰撞器。 药丸对象中的碰撞器。 圆柱体中的碰撞器和药丸 对象的碰撞器是相同的 平面对象中的网格碰撞器 表 3-6 这一些碰撞器直接决定了该物体,将在什么范围内和其他具有碰撞器的物体产生碰撞效应。 那要怎样为我们外部导入的模型创建这一类的碰撞器呢?其实非常简单,我们首先选中汽车 模型,观察一下整个汽车的边沿呈现出一个立方体的形状。然后点选菜单栏中的“Compon ent”——>“Physics”——>“Box Collider”,为汽车添加一个立方体形状的碰撞器,如图 3-209 所示。 图 3-209 (7)、 如果你发现这个碰撞边沿并没有达到汽车边沿的形状大小,有一个很简单的方法,可 以让它与模型边沿迅速对齐。在模型的”Inspector”【监视面板】中,找到添加进来的碰撞 器“Box Collider”,然后点选它后面的设置按钮 ——>“Reset”,让系统自动重设一下就 可以了。由于石头模型并不是一个规则模型,所以关于添加不规则模型的碰撞器,我下面单 独列出一节来讲。 4.42 网格碰撞体的正确添加方式 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer 本节所对应的视频教学录像  第十七讲 网格碰撞体的正确添加方式 (1)、 在“Hierarchy”【层次清单栏】中选中“stone”,然后点选菜单栏中的“Component” ——>“Physics”——>“Mesh Collider”为石头添加一个网格碰撞器,但这时在 Scene【场 景面板】中我们单凭肉眼是无法碰断几何体的碰撞是否完整的封闭,如图 3-210 所示。如果 几何体表面有缝隙,那我们其他的碰撞物体就会穿透这个碰撞体,而不产生碰撞。 图 3-210 (2)、 为了避免上述问题的产生,在“stone”的“Inspector”【监视面板】中,找到刚才添 加进来的“Mesh Collider”,将“Convex”复选框打上勾。使 Unity3D 自动为“stone”绘制 出凹凸碰撞边沿,如图 3-211 所示。 图 3-211 但大家要注意一下,这里的凹凸碰撞边沿,并不是按照不规则模型边沿 100%绘制的,而是 一个粗略的边沿碰撞线,如下图 3-212 中的模型网络碰撞边。 图 3-212 (3)、 全部设置完毕,点击运行按钮 来运行一下游戏,大家已经可以看到碰撞效果了。 4.43 巧用枚举来设定游戏角色的状态 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer 现在的游戏中,汽车被撞一次就永远的消失了,这很不符合普通游戏的常识。在我们寻 常的游戏当中,游戏主人翁往往会有一定的生命值,在生命值没有消耗完之前,我们的主人 翁是可以复活的,并有一段的时间处于无敌状态。下面我就教大家如何巧用枚举来实现游戏 对象的无敌状态,与非无敌状态切换。 (1)、 双击“Script”文件夹下的“Player”脚本,然后为汽车添加状态选择代码。 using UnityEngine; using System.Collections; public class Player : MonoBehaviour { public static float PlayerSpeed = 50; public GameObject boom; //设定游戏角色的生命值 public int lifeNumber = 3; //设定游戏角色的两种状态 enum State { Playing, Revival } //设定游戏角色的初始状态 private State state = State.Playing; void Update() { //设置汽车随着键盘的上的“A”和“D”,或者是“←”和“→”键按下来移动 float hummerMove = Input.GetAxis("Horizontal") * PlayerSpeed * Time.deltaTim e; transform.Translate(Vector3.left * hummerMove); //如果汽车超过舞台的显示范围,则设置它从另外的一边出现 if (transform.position.x < -140f) transform.position = new Vector3(140f,transform.p osition.y,transform.position.z); if (transform.position.x > 140f) transform.position = new Vector3(-140f, transform. position.y, transform.position.z); } void OnTriggerEnter(Collider otherObject) { //这里多添加一个角色状态的判断,如果游戏状态不是Playing,那么角色将不进 行碰撞检测,即无敌状态 if(otherObject.tag=="stone" && state == State.Playing){ //将游戏角色的状态设置为复活状态,即无敌状态 state = State.Revival; //由于碰撞函数里面不直接支持时间等待函数yield return new WaitForSeconds, 所以要利用StartCoroutine函数做一个调用 StartCoroutine(hitStone()); } } IEnumerator hitStone() { //只要生命值大于,就产生碰撞后的爆炸 if (lifeNumber > 1) { Instantiate(boom, this.transform.position, Quaternion.identity); Destroy(gameObject); lifeNumber--; //在游戏角色等待1秒后,恢复非无敌状态 yield return new WaitForSeconds(1); state = State.Playing } } } 但当你填写完这段代码,并运行它的时候,却发现汽车依然被撞击之后,就不再出现。其实 只要我们细心想想,在碰撞之后的检测代码中有一个“Destroy(gameObject)”函数,已经将 我们的汽车对象消除掉了,而这段代码又是加载在汽车对象上面执行的,难怪看不到后面的 效果。所以我们不能再使用Destroy()函数,但我们又得让汽车确确实实的消失,那么就不让 角色对象进行渲染就好了“transform.renderer.enabled = false”。等到2秒中之后,再让汽车 又重新在场景中渲染出来“transform.renderer.enabled = true”。但在整个复活的过程中,画 面上看不到任何角色对象,又显得太单调了些,所以我们在复活的整个过程中再加上闪烁效 果,相关代码如下所示: IEnumerator hitStone() { if (lifeNumber > 0) { Instantiate(boom, this.transform.position, Quaternion.identity); //这里改为隐藏对汽车的渲染,而不将汽车消除 transform.renderer.enabled = false; lifeNumber--; //汽车被撞以后每0.2秒闪烁一下,一共闪烁十下 int i = 0; while(i<10){ transform.renderer.enabled = !transform.renderer.enabled; if (transform.renderer.enabled == true) i++; yield return new WaitForSeconds(0.2f); } //在游戏角色等待1秒后,恢复非无敌状态 yield return new WaitForSeconds(1f); state = State.Playing; } } 4.44 游戏结束场景的设置 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\Hummer (1)、 快捷键“Ctrl+N”新创建一个场景,并Ctrl+S保存该场景并命名为“gameOver”同样 的将它保存到“Stage”文件夹下面。 (2)、 打开VS编程环境,鼠标右键点击“Script”文件夹——>“添加”——>“新建项”, 为结束场景创建一个名为“gameOver”的脚本,然后输入场景画面的绘制代码以及返回游 戏和退出游戏的代码: using UnityEngine; using System.Collections; public class gameOver : MonoBehaviour { //初始化一个材质对象overBG,主要是作为感应背景图片的接口 public Texture overBG; void OnGUI(){ //绘制背景图片,大小和场景大小一样 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), overBG); //设置返回游戏的按钮 if (GUI.Button(new Rect(10, Screen.height - 50, 100, 30), "ReStart Game!")) Application.LoadLevel(2); //设置退出游戏的按钮 if (GUI.Button(new Rect(Screen.width - 110, Screen.height - 50, 100, 30), "Quit ")) Application.Quit(); } } (3)、 将代码保存之后,拖放给场景“gameOver”中的摄像机“Main Camera”,然后到摄 像机的”Inspector”【监视面板】中,找到我们用代码设置的材质接口“Over BG”,然后将 背景图片拖放给它,如图3-213所示. 图3-213 (4)、 将新创建的场景“gameOver”拖放到“Build Settings”列表中,如图3-214所示。 图3-214 (5)、 双击“Script”文件夹下的“Player”脚本文件,我们这里还需要做一些设置,因为这 时汽车在生命值消耗殆尽之后,没有做下一步的指示,整个画面像死机了一样。所以我们还 得在这段代码中做一些修改,使得汽车在生命值消耗完了之后,跳转到游戏结束场景。 IEnumerator hitStone() { if (lifeNumber > 0) { Instantiate(boom, this.transform.position, Quaternion.identity); transform.renderer.enabled = false; lifeNumber--; int i = 0; while (i < 10) { transform.renderer.enabled = !transform.renderer.enabled; if (transform.renderer.enabled == true) i++; yield return new WaitForSeconds(0.2f); } yield return new WaitForSeconds(1f); state = State.Playing; } //生命值消耗完,跳转到结束场景 else Application.LoadLevel(3); } 本节小结: 这几节中,做的Hummer游戏都比较简单。但我已将带有加分,通关加速等功能完整版 Hummer小游戏制作出来了,源文件在随书光盘内,大家有兴趣的可以打开来研究研究。 4.45 Unity3D 的网页编程 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.45 和其他的第三方浏览器插件一样,Unity3D提供了面对浏览器编程的良好扩展口““A pplication.ExternalEval”,通过这个扩展口,你使用的Unity3D就可以和网站上任意的DOM13进 行交互,从而达到改变网页的布局外观,增强Unity3D和浏览器API的交互性能等等。下面 我用两个实例来为大家说明“Application.ExternalEval”的具体用法。 实例一:调用浏览器的警告窗口 (1)、打开Unity3D软件,新建一个JS脚本文件,用编辑打开它并输入下列代码,并将场景 13 “Document Object Model,缩写为 DOM”【 文档对象模型】,DOM 可以以一种独立于平台和语言的方式 访问和修改一个文档的内容和结构。换句话说,这是表示和处理一个 HTML 或 XML 文档的常用方法。有 一点很重要,DOM 的设计是以对象管理组织(OMG)的规约为基础的,因此可以用于任何编程语言。最 初人们把它认为是一种让 JavaScript 在浏览器间可移植的方法,不过 DOM 的应用已经远远超出这个范围。 Dom 技术使得用户页面可以动态地变化,如可以动态地显示或隐藏一个元素,改变它们的属性,增加一个 元素等,Dom 技术使得页面的交互性大大地增强。 保存为“webUnity3D”的场景文件。 function OnGUI () { if (GUI.Button(Rect(10,70,50,30),"Click")) Application.ExternalEval ("alert('I am an alert box!!')"); } (2)、将这串代码拖放给“Hierarchy”【层次清单栏】摄像机对象“Main Camera”。 (3)、 在菜单中选中“File”——>“Build Settings”,在弹出来的“Build Settings”中,将 刚才保存的“webUnity3D”场景文件拖放到“Scenes In Build”窗口中,或点击“Add Cur rent”按钮来添置刚才的“webUnity3D”场景文件。接着在“Platform”窗口中,选择创建 的执行文件为“Web Player”,如图3-215所示。设置完毕之后,点击“Build”按钮来创建网 页文件。 图3-215 (4)、 找到刚才生成的Html网页文件,用浏览器打开它,然后点击Unity3D中的GUI按钮, 可以看到如图3-216的效果。 ○1 点击“Add Cur- rent”按钮来添置刚 才的“webUnity3D” 场景文件 ○2 在“Platform” 窗口中,选择创 建的执行文件为 “Web Player” ○3 设置完毕之后, 点击“Build”按钮 来创建网页文件 图3-216 实例二:在Unity3D中实现网页地址的浏览器跳转 (1)、 打开Unity3D软件,新建一个JS脚本文件,用编辑打开它并输入下列代码。 //设定输入框的默认字符 var stringToEdit : String = "http://"; function OnGUI () { //添加一个GUI输入框,并把输入框内的字符传递给字符串变量“stringToEdit” stringToEdit = GUI.TextField (Rect (10, 10, 200, 20), stringToEdit, 25); //创建一个“点击跳转”按钮,用来控制浏览器DOM的“"window.location”,使得当前页面 跳转到“stringToEdit”字符串变量的网页中 if (GUI.Button(Rect(10,140,50,30),"Go")) Application.ExternalEval ("window.location='"+stringToEdit+"'"); } (2)、将这串代码拖放给“Hierarchy”【层次清单栏】摄像机对象“Main Camera”。 (3)、用上一个列子的方法导出Web文件。 (4)、找到刚才生成的Html网页文件,用浏览器打开它,然后在输入网址之后点击“Go”, 可以Unity3D里面的输入框,已经能像网页元素那样进行网页的跳转工作了,如图3-217的效 果。 图3-217 关于更多DOM的使用方法,大家可以去w3school14的网站上查看,再倒回来结合着Uni ty3D的“Application.ExternalEval”使用,就能够解决大多数的Unity3D网页编程问题。当然 Unity3D除了能使用“Application.ExternalEval”来控制各种DOM外,还可以使用“Applicat ion.ExternalCall”向网页的JS进行通讯,使用“unity.SendMessage”由网页向Unity3D进行通 讯,使用“GameObject.SendMessage”在Unity3D的各个游戏对象间进行通讯,等等。下面 一节《Unity3D的通讯技术》将会为大家一一解开这些通信技术的使用方法。 4.46 Unity3D 的通讯技术 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.46 4.46.1 Unity3D 与网页的 JS 通讯技术 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.46\U3DJS 14 w3school 的中文网址是:http://www.w3school.com.cn 1 2 JS是JavaScript的缩写,原本网页中的JS使用来实现各种动态交互的。JS短小精悍, 又 是在客户机上执行的,大大提高了网页的浏览速度和交互能力。 同时它又是专门为制作We b网页而量身定做的一种简单的编程语言。(注:这里需要大家注意一下,虽然网页中的Java Script和Unity3D中JavaScript的语法规则完全一样,但由于它们工作在不同的环境,一个是 浏览器,一个是Unity3D,所以对应的翻译器也会不同,请大家不要将二者混淆。)但随着F lash、Unity3D等第三方插件在浏览器中的大量涌入,使得JS得到了新了历史使命——作为 中间语言,在浏览器中为各种插件的信息交互进行桥梁作用。下面我以一个Flash与Unity3D 在网页中的简单例子,来为大家讲述具体的制作方法。 (1)、 新建一个文件夹“U3DJS”,并用Unity3D新建一个项目文件到该文件夹下。 (2)、 新建一个名为“MessageTest”的C#脚本文件,输入完整代码如下所示: using UnityEngine; using System.Collections; public class MessageTest : MonoBehaviour { //用于显示回调的信息变量 public string showMessage; void OnGUI() { //当按下GUI按钮时,向浏览器的“U3DMessage”函数发送"The message come fr om Unity3D!"的消息。 if (GUI.Button(new Rect(10, 10, 100, 30), "SendMessage"))Application.ExternalCal l("U3DMessgae", "The message come from Unity3D!"); //用于显示回调信息的GUI文本框 GUI.TextArea (new Rect(10, 50, 200, 30),showMessage); } //接受网页信息回调的函数 void messageFunction(string arg) { showMessage = arg; } } (3)、输入完毕之后,保存代码。并将该组件拖拽给“Hierarchy”【层次清单栏】上的摄像 机对象“Main Camera”。 (4)、 快捷键“Ctrl+S”保存该场景文件为“WebSendMessage”,并根据上一节学到的知识 导出网页文件。 (5)、找到导出的网页文件,用Dreamweaver或者FrontPage等网页编辑软件将Html文档打开, 在标签的中间,找到如下javascript代码片段: 这里我需要给大家再进一步解释一下这串代码,因为在页面中你可能会像Flash那样绘制许 多的Unity3D元素,为了便于方便的找到和控制这些元素,Unity3D会在绘制的时候要求你输 入一个该元素的ID值,这里的ID就是"unityPlayer"。Unity3D对象一旦被网页所绘制,就可以 用页面标签
去感知它,比方说
这样一组标签就可以在页 面上显示刚才定义的Unity3D对象了。剩下来的就是一些基本的网页编程知识了,你要改变 该
的级联样式,就要用到CSS编程。在Unity3D的默认页面中,你可以找到这对标签里面的页面样式代码,对应的找到“div#unityPlayer”就是关 于刚才所定义Unity3D的
标签的样式了。 (6)、 接着上面的代码,加一些页面与Unity3D交互的代码进去,如下所示: (7)、快捷键“Ctrl+S”保存修改的网页,快捷键F12发布刚才保存的网页,可看到图3-218 所示的理想效果。 图3-218 (8)、接下来的工作就是将页面上显示的Unity3D消息和向Unity3D里面回传的消息改成Flas h传递过来的消息,和向Flash里面回传的消息。打开Flash软件,创建一个按钮元件并将其实 例名取做“SMbtn”,选中时间轴按下快捷键“F9”添加一个按钮的监听代码,如下所示: //给SMbtn按钮设定一个监听函数,一旦该按钮被按下,则执行“SendMessageFunction”函 数 SMbtn.addEventListener(MouseEvent.CLICK,SendMessageFunction); function SendMessageFunction(evt:MouseEvent):void { //向网页中的“SendToU3D”函数发送字符串消息“The Massage come from flash!” ExternalInterface.call("SendToU3D","The Massage come from flash!"); } 然后用快捷键“Ctrl+Enter”来发布完成好的Flash文件。 (9)、 打开前面Html文档,对Unity3D的回发信息代码做一定的修改,如下红框标记出来的 地方所示: (10)、在网页中写下插入Flash的网页代码,如下所示:
红色字体为插入Flash文件的文件名。 (11)、运行网页,一切如果运行正常,点击Flash按钮即可看到图3-219所示的效果。 图3-219 本节小结: 有关 Flash 与网页 JS 通信的用法,请大家参看 ActionScript 帮助文档的“ExternalInterf ace”部分,还有有关 Flash 与 Unity3D 在 C#环境里面的通信,请大家参看以下代码: private void axShockwaveFlash1_Enter(object sender, EventArgs e) { //设置 Flash 源文件的路径 this.axShockwaveFlash1.Movie = Application.StartupPath + "\\123.swf"; this.axShockwaveFlash1.WMode = "Transparent"; //对 Flash 控件上的 FSCommand 命令进行监听,并发送给监听函数“axShockwaveFlash 1_FSCommand” this.axShockwaveFlash1.FSCommand += new AxShockwaveFlashObjects._IShockwaveFl ashEvents_FSCommandEventHandler(axShockwaveFlash1_FSCommand); } private void axShockwaveFlash1_FSCommand(object sender, AxShockwaveFlashObjects._ISh ockwaveFlashEvents_FSCommandEvent e) { //接受 FSCommand 发送过来的信息,并根据该信息变量的判断对 Unity3D 控件发送消 息 if (e.command == "gogo") { this.axUnityWebPlayer1.SendMessage("MyObject", "gogo", "gogo"); } if (e.command == "leftleft") { this.axUnityWebPlayer1.SendMessage("MyObject", "leftleft", "leftleft"); } if (e.command == "rightright") { this.axUnityWebPlayer1.SendMessage("MyObject", "rightright", "rightright"); } if (e.command == "downdown") { this.axUnityWebPlayer1.SendMessage("MyObject", "downdown", "downdown"); } } 在VS环境中,Flash与Unity3D的播放器都是以控件的方式存在的,所以只要把握好控件的I D,对其进行控件的API控制就可以达到交互的目的。 4.46.2 Unity3D 的内部通信 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.46\insiderSendMessage 在使用Unity3D的时候,你除了用会用上面一节的方法来进行Unity3D和网页页面的信 息通信外,还会想到每个游戏物体之间的信息通信,以 及 同一个物体不同组件之间的信息通 信。不 同 游戏物体之间的通信可以通过transform.Find().GetComponent()或是GameObject.Find ().GetComponent()来完成,而同一个物体上各个组件之间的通信则主要依靠SendMessage() 来完成。下面笔者将以例子的形式,为你讲解Unity3D中各种内部通信的使用方式和方法。 (1)、 新建一个“insiderSendMessage”项目文件夹,打开Unity3D在刚才的文件夹里面创建 新的Unity3D项目。 (2)、 在菜单栏中点击“GameObject”——>“Create Other”——>“Cube”创建一个立方 体“A”,再用同样的方法创建一个立方体“B”,并摆放到摄像机前面不同的位置,如图3- 220所示。 图3-220 (3)、 新建一个JavaScript组件,并输入如下的代码带作为接受信息传递的组件。 function changeColor(valueColor:Color) { gameObject.renderer.material.color = valueColor; } 输入完毕之后将该组件保存名为“changeCc”的组件,并将该组件拖放给立方体“A”和立 方体“B”。 (4)、 再新建一个“sendColor”的组件,用于传递信息。打开刚创建的组件之后,输入如 下代码: function OnMouseEnter() { GameObject.Find("B").GetComponent("changeCc").changeColor(Color.red); } function OnMouseExit() { GameObject.Find("B").GetComponent("changeCc").changeColor(Color.white); } 输入完毕,保存该组件并只将该组件拖放给立方体“A”。 (5)、点击测试影片按钮,在“Game”【动画面板】中将鼠标放置到立方体“A”上,会发现 变红的却是立方体“B”。当鼠标移除立方体“A”的范围之后,立方体“B”又回复到原来的 白色。证明Unity3D在游戏物体与物体之间的通信已经完成,接下来我们要做的就是同一个 物体不同组件之间的通信。 (6)、 打开刚才保存的“changeCc”组件,添加下面代码中用红框标记出来的部分: function OnMouseEnter() { GameObject.Find("B").GetComponent("changeCc").changeColor(Color.red); SendMessage("changeColor", Color.green); } function OnMouseExit() { GameObject.Find("B").GetComponent("changeCc").changeColor(Color.white); SendMessage("changeColor", Color.white); } 添加完成之后保存该组件。 (7)、如果一切运行正常,点击测试影片按钮,在“Game”【动画面板】中将鼠标放置到立 方体“A”上,会发现除了立方体“B” 变红以外,立方体“A”也变绿了!这证明同一个游 戏物体上不同组件之间的通信成功,如图3-221所示。 图3-221 本节小结: 除了以上我给大家讲到的“SendMessage”游戏物体内部组件的通信方法而外,还有比 如像“BroadcastMessage”可以影响该游戏物体和该游戏物体所有的子物体的通信方法。更 详细的操作大家可以在 Unity3D 自带的脚本使用手册中,输入“SendMessage”查看与之相 关的通信函数和方法。 4.47 Unity3D 的 shader【着色语言】入门 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.47 Unity3D的shaders编写使用ShaderLab语言,同时支持自有工作流中的编程方式或Cg15、 GLSL16、HLSL17语言编写的shader。一个shder可以包含众多变量及一个参数接口,允许Un ity去判定参数是否为当前所支持并适配最适合参数,并自己选择相应的shader类型以获得广 大的兼容性。可以这么说,在Unity3D中的材质球只是一个抽象化的接口,是为了便于使用 者可视化的制作项目,而具体负责物体表面渲染工作的,正是材质球后面的“Shader”,你 可以随便选取一个材质球,在它的“Inspector”【监视面板】里更换“Shader”后面下拉 15 Cg 语言(C for Graphics)是为 GPU 编程设计的高级着色器语言,由 NVIDIA 公司开发。Cg 极力保留 C 语言的大部分语义,并让开发者从硬件细节中解脱出来,Cg 同时也有一个高级语言的其他好处,如代码的 易重用性,可读性得到提高,编译器代码优化。 16 GLSL - OpenGL Shading Language 也称作 GLslang,是一个以 C 语言为基础的高阶着色语言。它是由 OpenGL ARB 所建立,提供开发者对绘图管线更多的直接控制,而无需使用汇编语言或硬件规格语言。 17高级着色器语言(High Level Shader Language,简称 HLSL),由微软拥有及开发的一种语言,只能供微 软的 Direct3D 以及 XNA 使用。它跟 Nvidia 的 Cg 非常相似。 框中所对应的着色脚本,材质球将以不同的方式对物体进行渲染,如图 3-222 所示。但除了 这些Unity3D为我们写好的着色脚本,咱们还可以为自己量身定做一些着色脚本。下面笔者 通过一个简单的例子,带领大家领略下自定义“Shader”的制作流程。 图 3-222 (1)、 在菜单栏中点击“Assets”——>“Create” ——>“Shader”新建一个着色脚本,并 在“Hierarchy”【层次清单栏】中找到我们刚才新建的着色脚本,双击用编辑打开它。如 无意外,我们将会看到一段类似 C 语言的代码,如下所示: Shader "New Shader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" } 其实这是一段用CG语言编写的着色程序,正如我之前所说的那样,在Unity3D中你可以随意 的使用CG、GLSL、HLSL等语言来进行编程,它以“CGPROGRAM”作为开始,以“END CG”作为结束。但在这里笔者并不打算就各种语言进行深入的讨论,以免给初学者们带来 一定的混乱。在这段代码开始的部分“Shader "New Shader"”定义该着色组件的名字为“N ew Shader”, 在 Unity3D中着色组件的命名不依赖于“Project”【项目文件栏】中的文件名 字,你真正能在材质球编辑器里面看到名字是代码里面命名的名字,该名字支持树状接口 的命名方式,比方说你像对一类着色语言进行归类,可以这样写“Shader "Book/Physics"”、 “Shader "Book/Math"”、“ Shader "Book/Chemistry"”,这相当于在“Book”的文件夹内存 放了“Physics”、“ Math”、“ Chemistry”三个着色组件,以便于你在使用的时候进行查找。 命名块 18“Shader "Book/Physics"{}”的中间存放着“Properties”【属性】块,它主要是显 示该着色组件在“Inspector”【监视面板】中显示的可调节属性,比方说上面这段代码的“_ MainTex ("Base (RGB)", 2D) = "white" {}”将会在“Inspector”【监视面板】中提供给使 用者一个 2D材质接口,如图 3-223 所示。这段代码的结构“_MainTex”你可以把它看作一 个变量名,在ShaderLab中可以随意的调用这个变量;“"Base (RGB)"”是在“Inspector”【监 视面板】中所显示的属性名字,可以为任意;“2D”是该属性的类型;“ "white"”是该属性 的默认参数,后面的块可以定义一些 2D材质的属性参数。 图 3-223 当然除了 2D 的属性参数而外,ShaderLab 还提供了如下的属性参数:  name ("display name", Range (min, max)) = number:定义一个“float”【浮点】 属性,该属性会设定一个最小“float”【浮点】参数和一个最大“float”【浮点】 18“program block struction”【程序块结构】是一种程序结构形式,这种结构将整个程序分成若干个信息块 或子程序块,使程序变得清晰,便于阅读和修改。 参数,然后在“Inspector”【监视面板】用滑动条的形式提供给使用者在该范围内 进行数字设定,如图 3-224 所示。后面的“number”是该滑动条的默认参数。 图 3-224  name ("display name", Color) = (number,number,number,number):定义一个色 彩属性,该属性由四个数的数组组成,分别代表着“Red”【红色】、“Green”【绿色】、 “Blue”【蓝色】、“Alphe”【透明度】,范围由 0 到 1 的浮点数构成,如图 3-225 所 示。 图 3-225  name ("display name", 2D) = "name" { options }:定义一个 2D 材质属性,前 面说过,这里不再重复。  name ("display name", Rect) = "name" { options }:定义一个矩形材质属性, 如图 3-226 所示。 图 3-226  name ("display name", Cube) = "name" { options }:定义一个立方盒材质属 性,比方说我们之前学到的天空盒,如图 3-227 所示。 图 3-227  name ("display name", Float) = number:定义一个浮点属性,如图 3-228 所示。 图 3-228  name ("display name", Vector) = (number,number,number,number):定义一个 四维向量属性,如图 3-229 所示。 图 3-229 由于各种渲染方法的数据类型不同,所以定义的属性必须交给数据类型相同渲染方法才 能够得到正确的执行。“Properties”【属性】块中的变量作为对外可视化的接口,仅仅起到 一个变量的作用,并不会真正的执行。在 Unity3D 中真正执行渲染工作的是的“SubShader” 【子着色语言】程序块,一个“Shader”【着色语言】程序块中可以包含多个“SubShader” 【子着色语言】程序块,如下所示。 Shader "New Shader" { Properties { \\用在“Inspector”【监视面板】中显示的属性 } SubShader { \\为图形卡A所写的渲染代码 } SubShader { \\为图形卡B所写的渲染代码 } SubShader { \\为图形卡C所写的渲染代码 } …… FallBack "Diffuse" } 它用于提供给不同硬件环境的图形卡所用,图形卡在执行着色渲染的时候,会遍历所有的“S ubShader”【子着色语言】,并从中找寻适合自己硬件的一个。如果你害怕自己编写的所有“S ubShader”【子着色语言】都不满足硬件的要求,那么你可以在“Shader”块的末尾加上“F allBack "Diffuse"”来返回一个默认着色组件,这里返回的是“Diffuse”,它会在图形卡 硬件无法找到合适的“SubShader”【子着色语言】时候,去调用“Diffuse”来作为渲染时 的着色组件。 (2)、 现在我们对“New Shader”中的脚本进行如下改动,从而实现一个完整的着色语言例 子。 Shader " New Shader" { Properties { //设置五个可在“Inspector” 【监视面板】看见的属性变量 _Color ("Main Color", Color) = (1,1,1,0.5) _SpecColor ("Spec Color", Color) = (1,1,1,1) _Emission ("Emmisive Color", Color) = (0,0,0,0) _Shininess ("Shininess", Range (0.01, 1)) = 0.7 _MainTex ("Base (RGB)", 2D) = "white" { } } SubShader { Pass { Material { //漫反射光调用“_Color”变量设置的值 Diffuse [_Color] //环境光调用“_Color”变量设置的值 Ambient [_Color] //镜面高光调用“_Shininess”变量设置的值 Shininess [_Shininess] //物体光泽度调用“_Shininess”变量设置的值 Specular [_SpecColor] //发射光颜色调用“_Emission”变量设置的值 Emission [_Emission] } //开启顶点照明 Lighting On //物体平面纹理调用“_MainTex”传递过来的变量 SetTexture [_MainTex] { constantColor [_Color] Combine texture * primary DOUBLE, texture * constant } } } FallBack "Diffuse" } 这里我需要对物体平面光的颜色组成进行进一步的说明,它一般遵循这样一个公式,“Ambi ent”【环境光】* “RenderSettings ambient setting”【默认渲染设置里的环境光】+(“L ight Color”【灯光颜色】* “Diffuse”【漫反射颜色】+“Light Color”【灯光颜色】*“S pecular”【 物体光泽度】)+“Emission”【发射光颜色】,这样渲染出物体表面的所有颜色信 息再来和物体表面的纹理材质的颜色信息进行叠加。在 SetTexture 块里面“Combine”就 是 混合设定命令,“texture”指代当前的材质对象“_MainTex”,“ primary”指代“Material” 里面多种颜色混合之后的所有颜色信息,而“ DOUBLE”是用来加强混合效果的代表两倍的倍 增光照强度,逗号后面的“texture * constant”是用来设定材质的 alpha 与“constantC olor”的倍增效果。这里需要大家注意一下,在 Shader 里面调用变量和直接设定参数,与 我们传统等于号那种方式不太一样,设定参数一般直接在方法的后面跟相应类型的参数数 值,而调用变量则使用的是方括号[]如我们上面的那段代码所示,下面的代码将上面的代码 改为直接设定参数的模式。 Shader " New Shader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" { } } SubShader { Pass { Material { Diffuse (1,1,1,0.5) Ambient (1,1,1,0.5) Shininess 0.7 Specular (1,1,1,1) Emission (0,0,0,0) } Lighting On SetTexture [_MainTex] { constantColor [_Color] Combine texture * primary DOUBLE, texture * constant } } } FallBack "Diffuse" } 设置完毕之后保存该组件。 (3)、在菜单栏中点击“Assets”——>“Create”——>“Material”创建一个材质球,并 确保该材质球在被选中的情况下,到“Inspector”【监视面板】中点选“Shader”后面的下 拉框,就可以看见刚才我们定义的着色脚本“New Shader”了,如图 3-230 所示。 图 3-230 (4)、随便场景创建一个几何体,并将该材质球拖放给它,就可以让该物体的几何表面按照 我们的要求去显示了。 本节小结: 关于 Shader 更深层次的学习,笔者考虑到本书的读者有极大部分人群是初学者,就不 在这里阐述了,这里主要讲解 Unity3D 中 Shader 的一些基本语法和结构,带领大家入下门, 方便大家在使用别的 Shader 的时候,能够看明白是什么意思,懂得如何去修改它。 4.48 Unity3D 基于层的碰撞检测 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.48 本节所对应的视频教学录像:  第十八讲 基于层的碰撞检测 4.49 “Physic Material”物理材质 本节所对应的随书光盘源文件地址:  光盘目录:\Book_Source\Unity3D\4.49 在前面的小节中,我简单给大家提到了一下关于碰撞体的“Physic Material”【物理材 质】,但没有给大家讲述具体的使用方法,本节笔者将带领大家一起来深入学习“Physic M aterial”【物理材质】。“Physic Material”【物理材质】是用于描述物体表面物理材质的组 件,它包括了“Dynamic Friction”【动摩擦力】、“Static Friction”【静摩擦力】、“Boun ciness”【弹力或者你可以认为是反作用力】等等。和默认渲染设置一样,你可以在菜单栏 中点击“Edit”——>“Project Settings”——“Physics”来设定场景中各个物体的默认 物理材质属性,如图 3-231 所示。下面我为大家详解一下这个面板里面的各个参数:  “Gravity”【 重力】: 默认的重力只对 Y 轴方向上有-9.8 的重力加速度。  “Default Material”【 默认物理材质】: 它将作用于所有没有添加物理材质的碰撞 体,后面有一个添加物理材质的接口。  “Bounce Threshold”【 反弹力】: 它将作用于所有没有添加物理材质的相碰物体。  “Sleep Velocity”【物体初始化的线速度】  “Sleep Angular Velocity”【物体初始化的角速度】  “Max Angular Velocity”【最大角速度】: 用于限制像轮胎这样的刚体转弯过快等 问题。  “Min Penetration For Penalty”【最小穿刺深度】:两个碰撞物体被允许的相互 穿透深度。数值越高,穿透的深度就越深,但抖动就相对越小。  “Solver Iteration Count”【解算器重复计数统计】  “Raycasts Hit Triggers”【射线是否在目标物体中得到碰撞触发】  “Layer Collision Matrix”【层级碰撞矩阵】:只有碰撞矩阵中被设定层上的物体 才可以被相互碰撞,没有打勾的则不能进行碰撞。详情请参看上一节。 图 3-231 和渲染材质一样,物理材质也有灵活的独立组件,你可以在菜单栏中点击“Assets”— —>“Create”——>“Physic Material”来创建一个物理材质组件,创建好之后你可以在 “Project”【项目文件栏】看到这样子的一个图标 。确保新创建的物理材质组件在被选 中的情况下来到监视面板,可看到许多的设定参数,如图 3-232 所示。下面我为大家详解一 下这个面板里面的各个参数:  “Dynamic Friction”【 动摩擦力】: 设定该物体动摩擦力的大小。  “Static Friction”【 静摩擦力】: 设定该物体静摩擦力的大小。  “Bounciness”【反弹力】:设置反弹力的大小。  “Friction Combine”【 两个相撞物体的摩擦力结合模式】:一共有四种模式,“Ave rage”【平均】、“Multiply”【乘积】、“ Minimum”【最小量】、“ Maximun”【最大量】。  “Bounce Combine”【两个相撞物体的反弹力结合模式】:一共有四种模式,“Avera ge”【平均】、“ Multiply”【乘积】、“ Minimum”【最小量】、“ Maximun”【最大量】。  “Friction Direction2”【 各个方向上的摩擦差异性】:和“Dynamic Friction2” 还有“Static Friction2”的数值息息相关。 图 3-232 接下来的事情就比较简单了,你只需创建一些碰撞体,并将设定好的物理材质,拖放给 该碰撞体“Inspector”【监视面板】里的碰撞器标签下的“Physic Material”【物理材质】 接口即可了,如图 3-233 所示。 图 3-233 本节小结: 你可以用本小节的方法,给地形系统和各种物体添加不同的“Physic Material”【 物 理 材质】,然后测试一下看看效果。很好的运用“Physic Material”【物理材质】是模拟场景中 不同地形环境很好的手段,比方说官方那个大兵的例子。 你不能不看的结束语: 当今的中国已经有不少Unity3D的爱好者和开发者了,他们都被Unity3D强大的成像功能 和数据功能所吸引,在未来的2、3年内,Unity3D将会成为最热门的软件之一。但在这个时 候,请大家不妨想想,如果用Unity3D来制作3D Web,浏览它的用户常常为了加载一个庞大 的场景而等上2、3个小时,试问有哪一个网页浏览者会选择这样做?所以也请你在学习Uni ty3D的时候,不妨高瞻远瞩,看看只用几十KB就可以浏览到一个格斗游戏的《第五章 统领 未来的3D超级浏览器》,看看它的架构,看看怎么来鉴证下一个比尔盖茨的诞生!

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档

相关文档