Unity进阶

247 阅读21分钟

导航系统

Nav Mesh寻航网格

  • Nav Mesh导航网格是3D游戏中,用于实现动态物体自动寻路的 技术。
  • 它将游戏场景中复杂的对象结构组织,简化为带有一定信息的网 格。
  • 在这些网格的基础上,通过一系列的计算实现自动寻路 Unity能自动生成Nav Mesh导航网格。

Nav Mesh Agent导航代理组件

  • Unity的Nav Mesh Agent是配合导航网格使用的导航代理组件
  • 给物体添加导航代理组件后,物体会自行根据目标位置和导航网格,寻找合适的路线,沿着找到的路线移动到目标位置。
  • 导航物体移动过程中,会避开障碍物,以及其它添加了导航 代理组件的导航物体。

以圆柱体为例

  • Agent Size 导航代理尺寸
    • Unity导航代理组件使用一个圆柱体,代表导航物体。Unity导航系统会根据该圆柱体的尺寸,避免导航物体与障碍物或其他导航物体,发生碰撞。
    • Radius是导航代理的半径。
    • Height是导航代理的高度。
    • Base Offset是导航物体相对于圆柱体导航代理的垂直偏移量。
  • 导航代理组件的可设置属性包括:
    • 导航代理的尺寸;
    • 导航代理的运动属性;
    • 闪避,寻路等行为的属性。需要脚本控制。
  • Steering控制属性
    • Speed:最大移动速度。
    • Angular Speed:最大转向速度。
    • Acceleration: 最大加速度。
    • Stopping Distance:停止距离。
    • Auto Braking:自动刹车,到达目标前会逐渐减速。
    • Stopping Distance:停止距离,导航代理距离目标位置小于等于它时会停止移动。
  • Obstacle Avoidance躲避属性
    • 导航代理组件中Obstacle Avoidance标签下的属性,和导航代理的躲避行为有关。
    • Quality表示躲避的质量,如果场景中存在大量导航代理,降低质量可以减小CPU的使用率。
    • 如果Quality属性设置为None,导航代理不会躲避其它导航代理和障碍物。
    • Priority属性表示导航代理的优先级,范围从0到99,值越小优先级越高;导航代理只会躲避比自己优先级高的其余导航代理。

生成导航网格

  • 第一步:标记用于生成导航网格的物体。
  • 第二步:在Navigation视图中点击bake按钮生成导航网格。
  • 依次选择菜单栏中的Window->Navigation->打开Navigation视图

烘焙代理参数

以圆柱体烘培代理为例。

  • Agent Radius:圆柱体烘焙代理的半径。道路宽度必须比它大。
  • Agent Height:圆柱体烘焙代理的高度。
  • Max Slope:圆柱体烘焙代理的最大爬坡角度。斜坡要小于它才可以爬过。
  • Step Height:圆柱体烘焙代理的脚步高度。平台要小于才可以让它迈上去
  • Drop Height:跳落高度。平台到地面的距离小于它,表示可以跳下去。
  • Jump Distance:跳跃距离。平台之前的距离要小于它,表示可以跳过去。
  • Off Mesh Link:允许开发者在不相连的导航区域间创建路径。类似传送门。

Nav Mesh Obstacle 障碍物组件

  • 添加了Nav Mesh Obstacle 障碍物组件的游戏对象会成为障碍物。
  • 添加了导航代理组件的物体,遇到障碍物,会绕开障碍物。

AI 基础

  • 基本行为操控:
    • 靠近,远离,追逐,逃 ..
  • 寻路能力:
    • 从游戏场景中的一个位置移动到另一个位置。
  • 感知能力:
    • 自身状态,听觉和视觉等感知能力。
    • 模拟AI的听觉和视觉的方法:
      • 触发器(Trigger)。
      • 向量计算(Vector)。
  • 自主决策能力:
    • 根据自身状态和外部环境条件,做出合理的反应。
    • 有限状态机 (Finite State Machine)实现自主决策能力。

使用触发器Trigger感知的缺点

  • 我们需要使用三维建模软件,制作出椎体网格来模拟可视区域 这种方式较为麻烦,且不易维护。
  • 物理计算,尤其是MeshCollider网格碰撞体的碰撞计算,开销较大,会降低游戏性能。

使用Vector模拟AI的听觉

  • AI的听觉范围可以视为一个球体,该球体的球心是AI 只要玩家位于该球体内部,我们就认为AI可以感知到玩家。
  • 如果玩家与AI的距离小于AI的听觉距离,说明AI可以感知 到玩家。

视觉模拟

  • AI的视觉范围使用AI眼睛正前方的一个圆锥体来模拟,只要玩家位于这个圆锥内部,且不被遮挡,我们就认为AI看见了玩家。

逆向动力学

  • Inverse Kinematic 逆向动力学
  • 如,实现玩家换枪功能。

前向动力学

  • 大多数角色动画都是通过将骨骼的关节角度旋转到预定值来实现的。
  • 一个子关节的位置由它的父节点的旋转角度来决定。
  • 节点链末端的节点位置,是由节点链上各个节点的旋转角度和相对位置决定的。

逆向动力学

  • 给定未端节点的位置,从而逆推出节点链上所有其他节点的合理位置的方法称为逆向动力学Inverse Kinematic,简称IK。
  • 如,让角色对象的手臂去触碰一个特定的物体。

Unity动画系统中的IK

  • Unity的Mecanim动画系统,允许开发者通过脚本,实现角色模 型的逆向动力学,涉及的函数和字段包括:
    • SetIKPosition();
    • SetIKRotation();
    • SetLookAtPosition();
    • SetIKPositionWeight();
    • SetIKRotationWeight();
    • bodyPosition/bodyRotation;
  • 如,实现玩家持枪动作的基本步骤
    1. 在玩家动画控制器Animator中开启IK功能。
    2. 创建球体游戏对象,作为IK标记物。
    3. 通过IK控制脚本,把IK标记物的Position和Rotation属性,赋值给角色模型头部、手部和躯干等骨骼节点相应的IK属性。
    4. 在预览状态下,调整IK标记物的位置和朝向,使玩家头部,手部,躯干等骨骼节点,具有合适的位置和朝向,实现玩家的持枪动作。

光照

光源类型

  • 点光源(Point Light)
    • 从光源位置向所有方向发射出强度相等的光线;
    • 在传输过程中不断的衰减,当传输距离达到预设的极限距离range时,光线强度衰减为0。
    • 适合模拟灯笼,火把等局部光源。
  • 方向光(Directional Light)
    • 不会衰减,它以相同的强度和方向,照亮空间中的所有物体位置信息没有任何意义。
    • 常用来模拟那些体积较大,距离游戏场景非常远的光源,比如日光和月光。
  • 聚光灯(Spot Light)
    • 聚光灯从光源位置开始向某个特定方向照射,照亮一个圆锥体的空间区域,在传播过程中不断衰减。
    • 通常适用于模拟人造光源,比如手电,车灯,探照灯等。
  • 面光源(Area Light)
    • 使用一个矩形来定义,光线将从矩形的正面出发,照亮矩形前的一片区域。
    • 适用于模拟广告灯箱等光源。
    • 不能作为实时光源

光源属性

  • 类型以及与类型相关的属性。
  • Baking:烘焙属性。
    • 实时(Realtime)
    • 烘焙(Baked)
    • 混合(Mixed)
  • Color:光源的颜色。
  • Intensity:光源的强度。
    • 调节直接照射区域的光强。
  • Bounce Intensity :间接光照的强度。
    • 间接照射区域的光强。比如影子的亮度。
  • Shadow Type:光源产生的阴影类型
    • 无阴影(No Shadows )
    • 硬阴影(Hard Shadows )
    • 软阴影( Soft Shadows )
  • Render Mode:光源的渲染方式
    • 自动(Auto)
    • 重要(Important)
      • 逐像素渲染。
    • 不重要(NotImportant)
  • Cookie:通过纹理,给光源添加一层遮罩,改变光斑形状。
  • Halo:勾选Halo属性,Unity会在光源所在位置绘制一个球形的光晕。
  • Flare:设置光源产生的镜头光晕效果。
  • Culling Mask:设置光源所能照射到的物体类型,可选项为 当前项目中的Layer。

阴影

  • 设置光源的Shadow Type为Hard Shadows或者Soft Shadows。
  • 设置Shadow的相关属性
  • 设置光源的Render Mode为Auto 或者Important。
  • 对于遮挡光线并在其它物体上产生阴影的对象,设置其Mesh Renderer组件的Cast Shadows为On。
  • 对于接收阴影的物体(遮挡光线的物体后面的物体),在Mesh Renderer组件中,勾选其Receive Shadows属性。
  • 阴影缺失的原因
    • 显卡过于古老,不支持阴影的渲染。
    • 项目质量(Quality)设置中关闭了阴影。
    • 产生阴影的光源Rendering Mode为Auto,但是被Unity自动判定为非Important类型的光源。
    • 产生阴影的物体是透明物体。
    • 接收阴影的物体使用了Standard Shader,并且Rendering Mode为Transparent。
    • 接收阴影的物体使用了其它逐顶点的着色器。

全局光照

局部光照(local illumination)

  • 概念:在计算物体光照时,孤立的看待物体,不考虑物体之间的相互影响,每次只考虑:
    • 一个光源
    • 一个物体表面
    • 一个观察者
  • 特点:
    • 简单、快速
    • 与真实世界差异较大

全局光照(Global Illumination)

  • 概念:在计算物体光照时,既考虑光源直接照射所产生的影响,也考虑间接光照,也就是物体之间的反射光线和折射光线,产生的影响.
  • 特点:
    • 效果接近真实世界
    • 算法复杂,计算量大
    • 难以用于实时图形程序

Unity全局光照 - Baked GI

  • 需要预计算(烘焙),只对静态物体有效
  • 编辑阶段
    • 标记出场景中不会运动的静态物体,
    • 烘焙:预先计算静态物体的全局光照效果;
    • 结果保存为光照纹理Lightmap。
  • 游戏运行阶段
    • 直接从Lightmap中获取光照信息

Unity全局光照- Precomputed Realtime

  • Unity5.0之后的版本支持预计算实时GI。
  • 需要预计算(烘焙),只对静态对象有效。
  • 烘焙结果中保存和Baked GI不同的信息。
  • 运行时实时计算全局光照。
  • 优点:可以在运行时动态改变光源的数量,位置,朝向,以及物体的材质。

Unity全局光照的局限性

  • 需要花费较长的时间预计算。
  • 只对静态物体有效。
  • 非静态物体反射的光线无法影响其它物体。
  • 非静态物体也无法直接受到烘焙光源和静态物体反射光线的影响。

Unity全局光照设置

  • 选中需要应用全局光照的游戏对象;
  • 在Inspector视图中,勾选Static下的Lightmap Static。
    • Lightmap Static flag renamed to Contribute GI
  • 点击Window菜单下的Lighting打开Lighting设置窗口。
  • 点击Lighting窗口顶端中部的Scene按钮,打开场景配置页;
  • 根据需要勾选Precomputed Realtime GI或者Baked GI,也可以二者都勾选;
  • 勾选窗口底端Build按钮左侧的Auto复选框。
  • 光源的Baking属性有三个可选项:
    • Baked
    • Realtime
    • Mixed
  • 在Baked GI模式下,每当我们增删静态物体或者修改静态物体的属性,修改Baked或者Mixed光源的属性后,Unity都会自动重新烘焙,并在烘焙结束后自动应用全局光照效果。
  • 面光源(Area Light)只能在Baked GI模式下使用。

光照探头的使用方法

  • 游戏运行时,非静态物体无法直接受到烘焙光源和静态物体反射光线的影响。
  • Light Probes光照探头技术用于解决全局光照模式下非静态物体与静态场景之间光照不协调问题。
  • 基本思想
    • 编辑阶段:在场景中放置光照探头,并在探头的位置对光照进行采样,然后保存采样数据
    • 运行阶段:选择非静态物体附近的几个光照探头,使用这些探头的采样数据,插值获得静态物体应当受到的光照。
  • Light Probe Group对象由若干个Light Probe组成。
  • 就是将非static物体变成Light Probe。

shader

着色器的定义

  • 着色器本质上是一种运行在显卡GPU上的程序,用于控制显卡的图形渲染过程

着色器语言

  • CPU运行的程序通常用汇编语言,或者C++、Java等高级语言编 写。
  • GPU采用的是不同于CPU的并行计算结构,需要一种适用于GPU 的编程语言,于是就有了着色器语言。
  • 着色器语言: HLSL,GLSL,Cg。

Unity与着色器

  • Unity中所有的渲染都需要通过Shader来完成。
  • Unity内建超过80种着色器,开发人员可以使用内建着色器实现 各种画面效果,还可以方便的对其进行扩展。
  • Unity允许开发者编写自己的着色器。
  • Unity使用自定义ShaderLab开发语言来组织着色器,针对不同平台进行编译。

材质与着色器

  • 材质定义了物体表面的显示效果,每个材质必须绑定一个着色器
  • 材质绑定的着色器决定了该材质的渲染方式,以及可配置属性的类型和数量。

着色器的使用

  • 新建一个材质后,我们首先要做的就是为这个材质选择一个着色器。
  • 选中材质,可在Inspector视图的Shader下拉列表中选择着色器。
  • 指定好着色器后,需要配置材质的各个属性,并在检视视图下方预览材质效果。

Unity内建着色器

  • Standard 和 Standard (Specular setup):标准着色器。
    • Unity5.0新加入的标准着色器,有选择的吸收了许多其他不同着色器的特色功能,能满足大部分的着色器需求,并显著地简化工作流程。
  • FX:光照,水与玻璃效果着色器。
    • Distortion:玻璃的投射畸变
    • Tint Color (RGB):玻璃的颜色
    • Normalmap:玻璃的法向量
  • GUI和UI:用户界面着色器。
  • Mobile:移动平台使用的简单着色器。
  • Nature:植被和地形着色器。
  • Particles:粒子系统使用的着色器。
  • ·SkyBox:天空盒等背景环境着色器
  • Sprites:2D精灵系统着色器。
  • Unlit:忽略一切光照和阴影效果的着色器。
  • Legacy:过时着色器。

图像特效 Image Effect

  • Image Effect图像特效技术,对游戏染出的画面进行后期处理 可以为游戏带来丰富的视觉效果。

图像特效资源

  • 图像特效资源通常是一个脚本文件,该脚本包含一个继承了 MonoBehaviour的类,实现了OnRenderImage函数。
  • 我们把图像特效脚本添加到游戏的Camera摄像机对象上,获得相应的特效。
  • 图像特效分类介绍
    • Bloom and Glow:泛光特效
    • Blur:模糊特效
    • Camera:相机特效
    • Color Adjustments:颜色调整特效
    • Edge Detection:边缘检测特效
    • Displacement:位移特效
    • Rendering:渲染特效
    • Noise:噪点特效
    • Other: 其他特效

Unity Profiler 介绍

  • Profiler能以直观的方式,显示游戏运行时,各种资源的占用情况,包括CPU、GPU、染、内存、音频以及物理等方面。
  • 依次选择菜单栏中的Window -> Profiler,打开Profiler视图。
  • 在Profiler视图中,单击Record按钮,打开录制功能。
  • 打开Profiler录制功能,点击Play按钮,执行游戏预览。Profiler会自动记录游戏运行时的性能数据,并显示在分析器时间轴上。

分析器时间轴

  • 每条分析器时间轴用不同的颜色显示不同的信息,可以在时间轴头部看到对应关系表。
  • CPU使用率分析器记录了染,脚本,物理系统,垃圾回收等操 作的CPU使用情况。

性能优化

CPU

  • 将引用缓存
    • 在Unity脚本中使用GameObject.Find这类函数获取游戏对象;使用GetComponent这类函数以及transform这类内置访问器获取组件,会产生较多开销。
    • 我们可以在Awake或者Start函数中,获取一次组件引用把引用缓存在当前class的字段中,供Update等函数使用。这样可以减少每次获取组件带来的开销。
  • 删除空的回调函数
    • 脚本中,空的回调函数也会消耗CPU时间。应当删除空回调函数而不是留空
    • 注意:Unity创建脚本时,会自动添加Start和Update两个回调函数。如果不用,最好手动删除。
  • 使用对象池Objects Pool
    • 频繁的使用Instantiate函数和Destroy函数,创建和销毁游戏对象会为脚本执行和垃圾回收带来很大的性能开销。
    • 对象池技术
      • 创建一个数组或者链表,作为对象池。实例化一组对象,把它们设置为未激活状态,放入对象池。
      • 如果需要创建对象,我们直接从对象池中取出一个未激活对象,激活该对象,设置相关属性,然后直接使用即可。
      • 需要销毁对象时,禁用该对象,然后把它放回对象池即可。
  • 避免集中实例化对象造成CPU峰值
    • 短时间内创建大量游戏对象会造成CPU峰值,引起游戏卡顿。
    • 我们可以使用Coroutine协程函数以一定的时间间隔创建多个游戏对象。
  • 优化渲染系统
    • 染系统不止消耗GPU时间,也会消耗CPU时间
    • 优化
      • 减少模型的顶点个数和面片个数;
      • 合并物体,或者使用相同的材质;
      • 减少粒子系统的使用,或者降低粒子的发射速度;
      • 关闭远处的粒子系统。
  • 优化物理系统
    • 频繁的物理系统计算会消耗较多CPU时间
    • 物理系统的计算频率超过画面渲染的帧率是没有意义的。
    • 可以设置Fixed Timestep和Maximum Allowed Timestep,调节物理系统的计算时间间隔。
    • 使用多个简单的Collider组成近似形状,避免使用Mesh Collider
    • 避免使用Wheel Collider
    • 优化物理系统:在精度和性能之间找到平衡点
  • 合理地进行垃圾回收
    • 及时调用Destroy函数释放不用的资源,避免短时间内释放过多资源;
    • 按照一定频率手动进行垃圾回收:System.GCCollect()
    • 选择合适的垃圾回收点,比如页面切换时。

渲染

  • 渲染优化的目的
    • 提高渲染的效率(提高率)。
    • 保证渲染的质量。
  • 减少渲染的工作量
    • 控制渲染的工作量是保证帧率的根本
    • 每帧染的顶点个数是渲染工作量最直观的衡量标准之一
      • 每可染的顶点数量主要取决于设备的GPU
      • PC游戏每帧渲染的顶点数量不宜超过几百万个
      • 移动端每帧渲染顶点的数量不宜超过十万个
  • 使用Stats快速查看渲染顶点的个数。
  • 在效果允许的前提下,使用顶点个数少的物体替代顶点个数多的物体。
  • 查看物体网格的顶点数量
    • 通过对象Mesh Filter组件的Mesh属性,查看该对象使用的模型资源。单击Mesh属性值,Project项目视图会高亮显示该模型资源
    • 在Project项目视图中单击该模型资源,可以在检视视图下方,查看模型网格的顶点和三角形面片数量。
  • 控制每帧渲染的顶点数量
    • 减小摄像机对象的远平面的距离( Clipping Planes - Far )
    • 减小摄像机对象的视角(Field ofView )
    • 降低物体摆放的密集程度。
  • 使用遮挡剔除技术( Occlusion Culling )
    • 摄像机视域内很多被遮挡的物体,没有渲染的必要
    • 我们可以通过“Occlusion Culling”遮挡剔除技术,剔除摄像机视域内被遮挡的物体,提高渲染效率。
    • 选中要参与遮挡剔除的静态物体,然后在Inspector视图右上角,点击Static右侧的黑色小三角,在弹出的列表中,勾选Occluder Static和Occludee Static.
    • 注意:对于足够小,不太容易遮挡其它物体的对象,应当只勾选Occludee Static。
    • 在遮挡剔除窗口中,点击Bake按钮可以设置遮挡剔除的烘焙参数。
    • 通常,点击Set default parameters按钮,使用unity提供的默认参数即可。
    • 点击Occlusion Culling视图右下角的Bake按钮,开始烘焙遮挡剔除数据。
    • 烘焙完毕后,点击Visualization按钮进行预览。
  • LOD技术(Level Of Details)
    • 基本思想:为同一个物体准备多个精度不同的模型,如果物体距离摄像机较近,使用高精度模型绘制物体,展现细节。如果物体距离摄像机较远,使用低精度模型绘制物体,提高渲染效率。
  • Draw Call
    • Unity中,“引擎准备渲染数据,通知GPU进行渲染”的过程称为一次Draw Call;
    • 一个Draw call通常只绘制一个物体,每次Draw Call都需要准备Shader和材质,比较耗时;
    • 每的Draw Call数量是一项非常重要的性能指标。
  • Draw Call合并
    • Draw Call合并技术把具有相同材质的多个物体合并为一个物体在一个Draw Call中完成绘制,从而提高性能
    • 两种Draw Call合并技术:动态合并和静态合并。
    • 启用静态合并和动态合并:我们可以在项目构建窗口中,点击Player Settings在打开的Player Settings视图的OtherSettings标签下,勾选Static Batching和Dynamic Batching
    • 对于要开启Draw Call合并的静态物体我们需要在其Inspector检视视图中,勾选Static下的Batching Static。
  • 减少Pixel Light的使用
    • 尽量减少Pixel Light的使用。不要将光源的
    • Render Mode属性设置为Important。
    • Unity建议:最多只让一个光源采用逐像素渲染模式,该光源的类型最好是方向光。
  • 使用“全局光照+光照探头”替代实时局部光照。
  • 避免使用实时阴影
    • 实现实时阴影,需要对场景进行多次渲染开销非常巨大。应该尽量避免使用实时阴影效果。
    • 可以使用Projector组件模拟阴影效果

内存优化与其它优化

  • CPU优化和渲染优化的很多方法,通过牺牲“空间”来换取“时间”
    • 对象池技术,通过占用更多的内存空间来节省CPU时间
    • MipMaps技术,通过占用更多的存储空间来提高渲染效率
    • 如果内存资源更为稀缺,我们应该减少使用某些CPU和渲染的优化方法。
  • 导入时压缩资源。
  • 使用压缩的音频
    • 使用MP3压缩格式保存游戏背景音乐等长时间播放的音频,可以节省内存空间
    • 注意:为了减少解码带来的性能损失,我们应该使用WAV等非压缩格式,保存“枪声”等短促的游戏音效。
  • 调整光照贴图的大小。
  • 及时释放资源
    • 及时调用Destroy函数释放不用的资源。
    • 定期调用GC.Collect函数,手动进行垃圾回收。

Unity Quality质量设置

  • 在画面质量和帧率之间找到一个平衡点。质量越高帧率越低,反之亦然。
  • 依次点击菜单栏的Edit->Project Settings->Quality,就能在Inspector检视视图中,打开Quality质量设置窗口。
  • Rendering渲染设置
    • Pixel Light Count:场景中逐像素光源的最大个数
    • Pixel Light Count值越大,场景的光照效果越好,染效率(帧率)越低。
    • Anisotropic Textures:各向异性纹理该技术用来处理,当视角变化导致3D物体表面倾斜时,造成的纹理错误
      • 开启后,画面质量提高,帧率降低。
    • Anti Aliasing:反走样技术
      • 图形硬件渲染出的多边形边缘通常会有锯齿。反走样技术能够平滑这些锯齿,提供更好的视觉效果
      • 开启后画面质量提高,渲染效率降低
  • Shadows 阴影设置
    • Shadows阴影的种类
      • 禁用:节省非常多的开销
      • 硬阴影:边缘锐利,需要一定开销
      • 软阴影:边缘柔和,计算开销更大。
    • Shadows Resolution 阴影分辨率:
      • 阴影分辨率越高,场景中的阴影效果越好计算开销越大。
    • Shadows Projection 方向光产生阴影的方法
      • Close Fit:产生的阴影分辨率较高,但相机移动时,阴影可能会有抖动现象;
      • Stable Fit:能够避免抖动,但是分辨率相对较低。
    • Shadow Distance 阴影的最大距离
      • 到摄像机的距离超过该值的阴影,都不会被渲染。
    • Shadow Cascades阴影层叠技术,能够使近处的阴影在ShadowMap中具有较高的分辨率,远处阴影在ShadowMap中具有较低的分辨率降低近处阴影的锯齿感.
  • Other其它设置
    • V Sync Count: 垂直同步。开启后,每画面的刷新时间将与显示设备的刷新时间保持同步,可以避免画面的撕裂.