LOD——Level of Detail,多细节层次,这本身是图形学的一个概念,在图形学中,为了对性能进行加速,我们很正常的会有这样一个想法,对于那些比较远的图元,我们是不是可以不渲染他大量的细节,而只描绘出一个轮廓呢?——而这在视觉效果上其实并不会产生太大差距,因为往往比较远的图元真正体现在图元上仅仅只是几个像素而已。由此,在图形学中,我们往往会对图元设计多个细节层次,每个细节层次都表现出不同的细节程度,比如,第一级,启用阴影,光照模型,法线贴图,全部的Mesh,第二级,启用光照模型,法线贴图,全部Mesh,第三级,不用法线贴图................................
在AI中,其实我们发现,这个概念是可以类比的,玩家当然不会关心过于远的AI是在走在跑,是不是用一些策略有效的组织进攻。所以在AI中,我们同样引用了LOD的概念。
首先对所有的AI增加一个LODComponent的组件,存着AI的LOD级别,然后再用一个系统实时的计算LOD级别。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityECS; using FreedomAI; namespace FreedomAI { public class LODComponent:UComponent { public int mLOD; public static int maxLOD; }; public class LODUpdateSystem:USystem { public static float[] lodDistance; public static GameObject mPlayer; public override void Init () { base.Init (); this.AddRequestComponent (typeof(LODComponent)); } public override void Update (UEntity uEntity) { base.Update (uEntity); if (lodDistance.Length == 0) return; if (mPlayer == null) return; GameObject tObject = getObjectByEntity (uEntity); float dis = Vector3.Distance (mPlayer.transform.position,tObject.transform.position); for (int i = 0; i < lodDistance.Length; i++) { if (dis < lodDistance [i]) { uEntity.GetComponent<LODComponent> ().mLOD = i + 1; return; } } uEntity.GetComponent<LODComponent> ().mLOD = lodDistance.Length + 1; } private GameObject getObjectByEntity(UEntity uEntity) { if (uEntity.GetComponent<BaseAIComponent> ()!=null) return uEntity.GetComponent<BaseAIComponent> ().mAIRT; else return ((SimpleAI)uEntity).mAIRT; } } }; public class AILOD:MonoBehaviour { public float[] LODDistance; void Start() { LODUpdateSystem.lodDistance = LODDistance; LODComponent.maxLOD = LODDistance.Length+1; LODUpdateSystem.mPlayer = GameObject.FindGameObjectWithTag ("Player"); } }
然后光有LOD的计算还是不够的,我们还有要切实的用出来。
在FSM中,我们本来是一秒中轮询一次节点是否发生转化,现在:
int lod = uEntity.GetComponent<LODComponent> ().mLOD; if (uEntity.GetComponent<AIState> ().timer <= 1.0f*lod) { uEntity.GetComponent<AIState> ().timer += Time.deltaTime; return; }
动画系统中:
public override void Update (UEntity uEntity) { int lod = uEntity.GetComponent<LODComponent> ().mLOD; Animator tAnimator = uEntity.GetComponent<AIAnimation> ().mAnimator; if (lod > (LODComponent.maxLOD) / 3 * 2) tAnimator.enabled = false; else tAnimator.enabled = true; if (lod > (LODComponent.maxLOD)/2) return; AnimationPlay tAnim = uEntity.GetComponent<AIAnimation> ().Get (uEntity.GetComponent<AIAnimation>().tempAnim); tAnim (tAnimator); }
在LOD非常高的时候,甚至直接取消了Animator。
在Emotion,FuSM等等系统中也存在着同样思路的优化。同时在逻辑节点中,也可以引用LOD参数,做一些用户级别想要的优化。