UE4學習筆記--AI感知系統AIPerception

最近在做遊戲AI感知相關內容,研究了下UE4引擎自帶的感知系統,讀了相關引擎源碼,文章爲本人學習之餘所整理筆記,如有紕漏歡迎指正交流。

一、UE4官方AI感知方案

虛化4官方的AI感知解決方案目前有2套,AIPerceptionComponentPawnSensingComponent
最早用的是PawnSensingComponent,但是該組件現在目前已被Unreal官方棄用(不推薦但仍保留),官方推薦使用的AI感知解決方案爲AIPerceptionComponent。官方解釋爲AIPerceptionComponent在靈活性以及性能開銷方面效果更佳,比如在視覺感知方面對每幀的trace及查詢增加了上限次數等優化處理。與Pawn Sensing最大的區別在於,Pawn Sensing讓每個人工智能都能獨立地進行感知,但是這樣做在性能方面開銷比較大,而AIPerception對智能體則是分批進行處理的。

以下爲Unreal官方人員回答新感知方案的優越性:

 

二、AIPerception使用方法

1.將感知組件AIPerceptionComponent掛到AI智能體的Controller上;
2.在感知組件上選擇AI需要具有的感知能力類型(視覺、聽覺、觸覺、傷害感知等)並設置相關屬性參數;

3.當感知到目標對象時,感知組件會拋出事件AIPerceptionComponent::OnPerceptionUpdated,告知感知到了哪些目標對象Actor

 

三、AIPerception系統架構

AIPerception系統架構UML圖如下:

1.AIPerceptionSystem

AIPerceptionSystem類即世界中AI感知系統的管理者,它的ListenerContainer存放所有具有感知行爲的AI監聽者(其實是監聽者的感知組件)。同時,它也知道當前世界中所有的AI感知類型有哪些(TArray<UAISense*> Senses)。注意,同一種感知類型的AISense在Senses裏只有一份,比如有兩個AI,一個AI有視覺、聽覺的感知能力,另一個AI只有視覺能力,AIPerceptionSystem的Senses中會有一個視覺感知AISense_Sight和一個聽覺感知AISense_Hearing。
那麼,AIPerceptionSystem是如何對其ListenerContainer和Senses進行處理,使整個感知系統生效的呢?我們繼續往下看。


2.AIPerceptionComponent

AIPerceptionComponent即感知組件,掛在有感知能力的AIController上。其SensesConfig即我們對該AI所有感知能力的配置。
另外,它還會保存當前AI所有需要處理的刺激數據(StimuliToProcess),以及所有刺激源Agent的相關信(PerceptualData)。注意,一個刺激源可能會有一系列的刺激信息
AIPerceptionComponent有兩個委託事件:FPerceptionUpdatedDelegateFActorPerceptionUpdatedDelegate。當AI感知有更新(感知到新的刺激源或移除曾感知到刺激源)時,PerceptionUpdatedDelegate會拋出事件,同時,AIController的ActorsPerceptionUpdated()方法會被調用,傳入的參數即爲要更新的刺激源Actor。


3.AISense

AISense爲感知能力類,是虛基類,其子類爲各個類型的感知能力AISense_Sight、AISense_Hearing、AISense_Touch、AISense_Damage等。不同類型感知能力以及感知規則就是在這些類裏實現的,比如視覺感知會在AISense_Sight的Update方法中每幀檢測視野內的所有刺激源,然後把新感知到的刺激源交給AIPerceptionComponent處理(FPerceptionListener::RegisterStimulus)。
每個有感知能力的AI智能體的感知組件上都會有不同的AISense(每種類型最多一個),同時,AIPerceptionSystem會用當前世界所有AI的AISense(每種類型最多也是一個),AIPerceptionSystem會對所有的AISense進行批處理(在其Tick方法中)。


4.AIStimulus

AIStimulus即感知系統中的刺激。注意,刺激和刺激源不一樣,其關係爲多對一,AIStimulus一般會稱其對應的刺激源Actor爲Source或Target,一個刺激源Actor會產生很多刺激,可能是同一時間不同類型的刺激,也可能是不同時間同一類型的刺激。

刺激主要有以下屬性:
a.Age 刺激的時效,(越小說明越接近,刺激一般會過期)
b.ExpirationAge 過期時間
c.Strength 強度
d.StimulusLocation 產生刺激者位置
e.ReceiverLocation 接收刺激者位置

 

四、AIPerception運行機制

我們瞭解了感知系統的設計架構和主要組成部分及其功能,那麼這些組成是如何分工協作,使整個感知系統運行生效的呢?
我根據代碼大概梳理了以下流程:

第一步:感知組件初始化,調用AIPerceptionComponent::OnRegister(),遍歷組件中所有的感知配置SensesConfig,將所有的AISense註冊到AIPerceptionSystem中;同時將自己添加到AIPerceptionSystem的ListenerContainer中。


第二步:AIPerceptionSystem將AIPerceptionComponent初始化時傳來的信息收集起來,當所有感知組件初始化後,AIPerceptionSystem便知道了當前世界所有具有感知行爲的監聽者ListenerContainer和所有需要用到的感知能力Senses。

第三步:AIPerceptionSystem在其Tick方法中統一處理所有的感知能力和監聽者,每幀遍歷Senses和ListenerContainer,更新ListenerContainer位置信息,並執行每個Sense的Tick方法。

第四步:在Sense子類的Update方法中,執行具體的感知能力判斷邏輯,一般會遍歷所有監聽者與刺激源的映射,比如視覺感知的AISightQuery,聽覺感知的ListenersMap,當某一對映射的刺激源能被監聽者的感知條件滿足(感知到)時,便將改刺激源及其刺激註冊到改監聽者的StimulusToProcess中等待監聽者處理。

第五步:AIPerceptionSystem每幀調用ProcessStimuli方法,遍歷上一幀新註冊的所有刺激StimuliToProcess,更新其所有刺激源Agent的相關信息PerceptualData;找出所有需要更新(新感知到或新移除)的刺激源,並拋出事件PerceptionUpdatedDelegate。

同時,AIController的ActorsPerceptionUpdated()方法會被調用,參數即爲要更新的刺激源Actor,通知AI感知系統更新了某一刺激源Actor。

處理完上一幀新註冊的所有刺激後,清空StimuliToProcess,開始下一幀感知刺激的註冊收集。

流程圖如下:

 

五、感知AISense的具體實現:

瞭解了AIPerception感知系統的運行機制後,我們最後深入AIPerception各類感知AISense的具體實現。
上文介紹過,不同類型的感知的實現方式各不相同,邏輯主要在感知子類的Update()方法中。

1.視覺感知AISense_Sight:

1.1 AISightQuery

視覺感知主要通過對其SightQueryQueue進行操作來實現。SightQueryQueue爲視覺查詢數組,裏面的每個成員AISightQuery爲一個視覺查詢的監聽者與目標的映射關係。其結構成員如下:

FPerceptionListenerID ObserverId;  //監聽者
FAISightTarget::FTargetId TargetId;  //目標
float Age;                                          //老化度,用於計算Score
float Score;                                       //排序分數,用於排序遍歷優先級    
float Importance;                              //重要性,用於計算Score    
FVector LastSeenLocation;             //目標位置信息

1.2 初始化SightQueryQueue

AIPerceptionSystem 有數組SourcesToRegister,成員FPerceptionSourceRegistration爲所有感知能力(SenseID)和對應具有改能力的AI(Source)的映射。但不是所有類型的感知能力都會存在這裏,比如視覺感知會,聽覺感知就不會,是否會存在SourcesToRegister中需要看AISense的bAutoRegisterAllPawnsAsSources字段。
AIPerceptionSystem會在PerformSourceRegistration()方法中遍歷SourcesToRegister,執行AISense_Sight::RegisterTarget。
結束後,AISense_Sight的SightQueryQueue視覺查詢數組初始化完畢。

1.3 處理SightQueryQueue

處理SightQueryQueue的邏輯都在AISense_Sight::Update()方法中,流程圖大致如下:


a.遍歷所有SightQueryQueue,對每一個SightQuery進行處理;
b.檢查是否在單幀最大打射線次數內以及單幀最大執行時間範圍內;
c.若條件b不滿足,對當前SightQuery的Age+1,對未處理的查詢進行老化,以便在下一次排序時它們可以在隊列中前進優先進行處理;
d.若條件b滿足,檢查當前SightQuery的Target是否在Listener的視椎體範圍內;
e.若條件d不滿足,Listener拋出事件視覺感知更新改Target,對其進行移除;
f.若條件d滿足,在Listener的視椎體範圍內,進行射線檢測;
g.trace到Target時若阻擋,即看不見,對其進行移除;
h.trace到Target時若無阻擋,即能看見,更新該SightQuery位置信息;
i.對查詢數組SightQueryQueue根據SightQuery的Score進行優先級排序,等待下一次處理。

2.聽覺感知AISense_Hearing:

2.1 AINoiseEvent

聽覺感知主要通過對其NoiseEvents進行操作處理來實現。NoiseEvents存儲了世界中所有的聲音事件,數組成員FAINoiseEvent結構如下:

NoiseLocation //產生聲音事件位置
Loudness //音量
MaxRange //聲音最大傳播距離
Instigator  //聲音事件發出者 
Tag //聲音標識

注意,不僅聲音事件有傳播距離範圍,監聽者自己也有聽覺範圍(HearingRange)。當MaxRange值爲0表示聲音傳播距離沒有範圍限制。

2.2處理NoiseEvents

處理NoiseEvents在AISense_Hearing::Update()方法中。注意,此Update()方法不是每幀都會調用的,當有新的聲音事件產生時,會將新的聲音事件Add到NoiseEvents中(RegisterEvent),並執行Update()方法。

Update()方法中聽覺感知的具體實現邏輯如下:

a.遍歷所有具有聽覺感知能力的Listener;
b.每一個Listener對所有的NoiseEvent進行遍歷;
c.監聽者到聲源距離 <= 監聽者聽覺距離 * 音量
d.監聽者到聲源距離 <= 聲源傳播距離 * 音量
e.滿足c、d,能聽到聲音,拋出事件通知感知組件;否則聽不到;
f.遍歷結束,清空NoiseEvents。

 


後續我會深入AIPerception各類感知AISense的具體實現並持續對本文進行完善和補充。

以上。

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