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參數,做一些用戶級別想要的優化。