虚拟世界的构成
基于Unigine引擎构建的虚拟世界场景包含了一系列具有不同特定属性的内置对象。 几乎所有的对象在虚拟世界中都是可见的。 不过其中有一些是伪对象,它们不能在正常模式中显现(像Physicals(物理),Occluders(遮挡器)等等)。
通常情况下,虚拟世界的构建包含如下内容:
- 要有被称为Nodes(节点)的内置对象,它们可以依次调用其它节点(*.node),网格(*.mesh),音频文件(*.oga),路径(*.path)或脚本(*.h)。
虚拟世界既能只存储节点或是那些放置在外部*.node文件中的References(引用),又能将它们一并存储其中。 反过来,*.node文件同样可以存储节点以及其它外部*.node文件中的引用。
- 要有以库的形式组织的Materials(材质)和Properties(属性)。
- 材质库需调用Shaders(着色器)和Textures(纹理)。
- 一般渲染,物理,音效和游戏设置。
新世界的创建可以通过UnigineEditor的菜单栏完成,或是在创建新项目时通过Unigine SDK Browser来完成。
每个虚拟世界都采用XML格式的单个文件形式存储在磁盘上,其文件扩展名为.world。
- 未启用世界脚本。 这种情况下,虚拟世界的内容就通过UnigineEditor来创建和管理。
- .world文件为空。 这种情况下,虚拟世界的内容就通过世界脚本来生成和管理。
由于Unigine引擎支持数据流技术,且所需资源 — 网格,纹理,动画,音效 — 都在Runtime(运行时)中被动态加载,因此虚拟世界可以被设计成游戏关卡设计师所希望的规模。 且资源也无需从内存中释放。
为了便于超大虚拟世界的设计和编辑,我们可以将其划分为多个部分。
Coordinate System坐标系#
Unigine引擎中的三维空间采用右手笛卡尔坐标系表示:X轴和Y轴构成水平面,Z轴垂直指向该平面。 当从三维编辑应用中输出动画时,Y轴指向被认定为正向。
正旋转角代表旋转方向为逆时针。 它对应右手定则:伸平手掌,如果将您的右手拇指指向任一坐标轴的正向,那么其余四指合拢的方向即为该坐标轴的旋转方向。
Built-in Objects内置对象#
nigine引擎提供有一系列内置对象,这使得您几乎可以将现实生活中存在的所有物体都添加进虚拟世界中。 为方便起见,它们被划分为了多个组来负责不同类型的操作。
虚拟世界既能只存储节点或是那些被放置在扩展名为.node的外部文件中的References(引用),又能将它们一并存储其中。
节点中与对象相关的类型还包括有Surfaces(节点表面)和Physical Bodies(物理实体)(包括与Joints(连接器)相连的碰撞Shapes(形状))。 节点表面包含有特殊材质的引用以及其所对应库的属性。 当您为节点表面分配材质或属性时这类节点的引用将会被自动创建。
- 对象的一部分,需拥有属于它自己的单独材质。
- 不同的细节层次(LOD)(包括Reflection(反射)的LOD和Shadow(阴影)的LOD)。 这种情况下,它们用或多或少的细节变化(高密度多边形和低密度多边形模型)来代表相同的对象或对象的一部分。 在任何特定的时间,哪些表面可见是由节点表面的属性决定的。
综合以上给出的信息,虚拟世界的主要组成的工作原理可以拓展为下图所示:
Nodes Hierarchy节点层级#
所有节点都以Hierarchy(层级)的形式被组织。 每个节点可以有多个子节点。
通常,一级节点的坐标和方位按【全球(世界)】坐标系定义,而它们子节点的坐标和方位则按各自父节点的【本地】坐标系来定义(前提是未选择其它选项)。 这就使得我们只需变换和旋转根节点就可以轻松完成整个层级树分支的变换和旋转。
【全球(世界)】坐标系的原点被设置在Scene Center(场景中心)。 而本地坐标系的原点就是父节点的【The Pivot Point(轴心点)】。
Surfaces节点表面层级#
上面提到了,节点中与对象相关的类型还包括有节点表面。 默认情况下,通过UnigineEditor添加的节点拥有1种节点表面,并且它会作为该表面的根节点。
节点表面的【数量】取决于网格是如何从三维编辑应用中被导出的,并且该数量不能在Runtime(运行时)中被动态更改。 每个节点表面都可以添加单独的DIP来调用GPU。
当节点表面被前景中的其它对象遮挡时它也会执行对象不可见部分的Culling(剔除)。 此外,剔除操作也被用来计算带有物理仿真对象的碰撞检测。
节点与它们的节点表面共享常用选项。 如有所需,每个节点表面都可以选择Enabled(启用)或Disabled(禁用)渲染。
节点表面使用的是单独的材质和属性,两者都需要从对应的库中加载。
点击 图标可当场编辑【Instanced(实例化)】的材质或属性。 也就是说,这种操作创建了子材质/子属性,并且只更改了该实例存储在虚拟世界文件中的参数(相较父材质/父属性而言)。
节点表面通常代表了同一项目的LOD。 要了解有关Min parent(最小父级数),Max parent(最大父级数),Visible(能见度)和Fade(渐隐/渐显)距离参数的详细介绍,请查阅细节层次(LOD)章节。
Physical Simulation of Objects对象的物理仿真#
对象除了构成非交互环境之外,它也参与Physical Simulation(物理仿真)。 仿真既要行之有效,同时又要保持整体高帧速,并且其物理还总要与真实世界中的非常接近。 这样要求的目的就是为了能在对象之间进行Collision Detection(碰撞检测)。
为此,对象应该被分配Body(物理实体),由它来描述对象的行为以及其所有具有的物理属性。 例如,它既可以是能一直保持固体形态的未变形Rigid Body(刚体),也可以是能被折叠和撕裂的Cloth(布料)。
不过,这种对象实体还不能满足对象进行交互。 我们需要能估计出对象实体体积的某种基本物理实体(或一组实体) — 【Shape(形状)】。 Unigine引擎提供有这么几类基本物理实体:Box(盒体),Sphere(球体),Capsule(胶囊),Cylinder(缸体),Convex Hull(凸包),或任意的网格形状。 这些形状被用来计算对象之间的碰撞。
一对形状可以由这些Joints(连接器)中的任意一种来连接: Fixed(固定型),Ball(球窝型),Hinge(铰链型),Prismatic(移动型),Cylindrical(柱筒型),Wheel(滚轮型)或Suspension(悬接型)。 它们描述了两个形状彼此间可能出现的移动方式。
Materials材质#
节点自身在场景中是不可见的。 节点如何被渲染的信息数据是存储在材质中的,而这些信息会被分配到特定的节点表面上。 材质是根据被渲染节点表面的种类所作的一组属性(状态,选项,参数)和资源(2D,3D纹理)组合,即:
- Options(选项)。 选项集合都是预定义好的,并且供所有材质选择的选项值也都是一样的。 每种选项都可以选择启用或禁用某种表现。 基本材质的选项值,默认包含在Unigine引擎的材质库中,它们采用的是硬编码,不允许被更改;所有其它材质的选项值都可以被更改。
- States(状态)。 它们负责确定条件,在此基础上Unigine引擎会为所有确定好的条件选择适当的着色器,纹理和参数。 例如,我们可以定义状态来开启和关闭水体仿真中泡沫的绘图,并且为两种状态(有泡沫和无泡沫)提供不同的着色器。
-
Textures(纹理)。 通常情况下,材质可以定义数种纹理。 常见的理由如下:
- 着色器需要处理的纹理可能不止一种。
- 一般情况下,不同的纹理会使用不同的渲染通道。
- 状态同样影响着纹理的数量,例如,每种状态都可以有它自己的纹理。
- Parameters(参数)。 如有所需,它们会将自身作为参数传给着色器。
- Shaders(着色器)。 它们是材质的最核心部分。 根据不同条件来真正绘制材质的就是着色器。 每种材质通常配有数种着色器,引擎会根据当前的渲染通道和状态选择最适合的一种。
Material Hierarchy材质层级#
在Unigine引擎中,【材质】以层级形式组织,就像节点一样;不过它们是完全独立于节点层级的。
默认情况下,Unigine引擎提供了一系列Base Materials(基本材质),它们永远位于材质层级的最顶端。 如果您需要扩展基本材质的属性或对其修改,那可以通过从必需的基本材质Inheriting(继承)来创建新材质:基本材质会将自身的所有属性都传给所继承的材质。 之后您可以添加新属性或置换已有属性。
分配有【mesh_base】材质的原始立方体 |
拥有从【mesh_base】继承来的材质的原始立方体 |
左侧立方体使用标准Unigine材质库中的一种基本材质来渲染。 右侧立方体继承了左侧立方体所使用的基本材质并简单更改了2种纹理(Diffuse(漫反射)和Normal(法线)纹理)。 这里无需您再设置其它属性,因为它材质的所有属性都是继承来的。 不过,如有所需,它们也可以被更改为任意属性,就像我们为立方体更换纹理那样。
所有的材质属性(除了着色器的)都可以在UnigineEditor中被轻松置换。 不过,如果您需要扩展一系列已有属性或置换着色器,那就需要手动编辑写有您的材质定义的XML文件。 这种情况下,请参考材质文件格式一章,里面对使用XML格式作材质声明进行了详尽描述。
材质库#
要在虚拟世界中使用材质,那一系列材质就要以库的形式组织,反过来,材质库的引用就应该被包含在.world文件中。 位于虚拟世界中的节点表面会直接调用该库的材质。
如果您通过UnigineEditor的【 Materials(材质)】窗口添加材质库,那么该库的引用会被自动添加进.world文件。
材质库是一种具有.mat扩展名的XML文件,它里面简单列出了含有属性的必需材质。 默认情况下,Unigine SDK包含的一系列材质库都位于data/core/materials/default目录下。
材质库中的所有材质都应该是从基本材质继承来的。 如果出于某种原因您不能找到可继承的材质或是您需要特殊后处理,那么我们也提供有创建全新材质的方法。
保持材质的正确加载顺序是非常重要的。 如果某个库中的材质是由另一个库中的材质继承而来,那么这里的【另一个库】应该被首先包含。 例如,您有两个材质库 - custom1.mat和custom2.mat。 如果custom2.mat(下图中的F)中的材质由custom1.mat(下图中的C)中的材质继承而来,那么材质库custom1.mat应该被首先加载。
Properties属性#
要想将对象正确地融入虚拟世界中,光是确定其方位,固有特性和外观还不够。 属性指明了对象的行为表现以及它与其它对象和场景环境间的交互方式。 例如,属性指定对象是否能交互以及是否属于开关。 对于游戏角色,属性可以指定其生命值或金币值。 因此,属性能使节点遵从游戏/应用的逻辑。
属性就像材质一样,也以层级形式组织。
Property Hierarchy属性层级#
属性层级由按层次结构组织的属性列表表示,这些属性可以分配给在场景中使用的节点。 属性层级独立于节点和材质层级。
默认情况下,Unigine引擎提供有2种属性,它们位于层级的最顶端且不能被更改。 如果您需要为属性更改特殊设置,那可以通过从默认属性继承来创建新属性:父属性会将自身的所有设置都传给子属性。 如果父属性之后被修改了,那所有继承的属性也将会被自动更新。
层级能以人性化的方式被轻松编辑:您只需通过拖拽就可以更改继承关系,只需一键操作就可以复制,分配或移除属性。 除了能一次复制整个属性,层级操作同样允许您单独复制它的每一项设置;您也可以选择其它属性,将这些设置应用其中,操作很简单,只需粘贴它们到属性即可。
属性库#
要在虚拟世界中使用属性,那一系列属性就要以库的形式组织。 属性库描述了属性的状态,参数以及父-子关系。 它们存储在具有.prop扩展名的XML文件中;为了能预加载库,属性库都应该在.world文件中作出声明。
如果您通过UnigineEditor的【Properties(属性)】窗口添加属性库,那么该库的引用会被自动添加进.world文件。
默认情况下,Unigine SDK包含的一系列属性库都位于data/core/properties目录下。