[FreedomAI]第五週——AI的LOD

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章