在UE4 Editor繪製除錯用的元件
簡介
在遊戲中,我們都知道可以使用Blueprint的DrawDebug系列的功能,用來繪製圓球,膠囊體等物件提供除錯。
但是如果想在編輯器的View視窗用DrawDebug是做不到的(註1),至少UE4引擎內部並不是這樣用。
註1.我有試過在ConstructorScript呼叫DrawDebugSphere,結果是會畫出來,但是永遠不會消失了。
不過引擎是有提供編輯器除錯用的顯示功能的,我們可以在幾個地方看到:
1. Visual Logger
2. EQS Testing Pawn
3. NavigationTestingActor
使用Visual Logger可以在編輯器看到AI角色的位置資訊被記錄下來,也可以自己透過API紀錄想要的資訊,如圖所示。
EQS Testing Pawn則是可以隨著編輯過程的狀況不同,顯示/更新Query的結果,如圖所示。
NavigationTestingActor是比較罕見的功能,可以在編輯器就預覽路徑搜尋的結果。
有個時候專案也會需要這方面的功能,如果沒有心理準備就直接看上面三個系統的實作,通常會被複雜的程式碼勸退。
這次我硬著頭皮研究並試著實作了一輪,簡單的做個筆記與分享。
最主要是去除複雜的程式碼,只列出最基本要實作的項目。有需要改進的部分再從上面提到的系統抽取出來即可。
本篇文章的內容以NavigationTestingActor為出發點作分析,雖然比較少見,但似乎是這幾個系統裡面相對簡單的部份。
架構組成
以下實際用TestActor, TestRenderComponent, TestSceneProxy分別做為案例。
TestActor要實作的項目
UPROPERTY()
class UTestRenderComponent* TestRenderComp;
#if WITH_EDITORONLY_DATA
#endif
TestRenderComp = CreateDefaultSubobject<UTestRenderComponent>(TEXT("TestRenderComp"));
TestRenderComp->PostPhysicsComponentTick.bCanEverTick = false;
TestRenderComp->MarkRenderStateDirty();
TestRenderComponent要實作的項目
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
virtual FBoxSphereBounds CalcBounds(const FTransform &LocalToWorld) const override;
FPrimitiveSceneProxy* UTestRenderComponent::CreateSceneProxy()
{
FTestSceneProxy* newSceneProxy = new FTestSceneProxy(this);
return newSceneProxy;
}
FBoxSphereBounds UTestRenderComponent::CalcBounds(const FTransform &LocalToWorld) const
{
FBox BoundingBox(ForceInit);
AActor* TestActor = GetOwner();
if (TestActor)
{
BoundingBox = TestActor->GetComponentsBoundingBox(true);
}
return FBoxSphereBounds(BoundingBox);
}
TestSceneProxy要實作的項目
TestSceneProxy反而是最複雜的項目,要實作的函式比較多,實際上要繪製的程式碼也寫在這。
GetTypeHash()
Constructor(const UTestRenderingComponent* inComponent);
Destructor
GetDynamicMeshElements()
GetViewRelevance()
GetAllocatedSize()
其中GetTypeHash,Constructor, Destructor, GetViewRelevance, GetAllocatedSize建議直接參考
Engine/Source/Runtime/NavigationSystem/Private/NavMesh/NavTestRenderingComponent.cpp
就好,GetTypeHash, Destructor, GetViewRelevance我是直接照抄。
Constructor目的是要透過TestRenderingComponent拿到TestActor的資料,存入自定義的資料結構。在GetDynamicMeshElements會使用這些資料結構做繪製。
GetAllocatedSize要回傳TestSceneProxy額外使用到的記憶體大小,請參考NavTestRenderingComponent。
GetDynamicMeshElements是主要繪製的程式碼入口,請參考以下的範例程式碼:
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (!(VisibilityMap & (1 << ViewIndex)))
{
continue;
}
// Write your codes here!!
}
在Engine/Source/Runtime/Engine/Public/SceneManagement.h內提供了許多繪製形狀的函式,所以從Constructor拿到的資料在這裡傳入繪圖函式就可以了。
繪製的函式基本上又可以分為兩大類,一類是以Get為開頭的函式;另一類則是Draw開頭的函式。
Get系列要傳入Material,所以需要產生FMaterialRenderProxy後傳入。
Draw系列需要FPrimitiveDrawInterface (引擎縮寫PDI),可以呼叫Collector.GetPDI(ViewIndex)取得。
以上兩個系列的程式碼在FNavTestSceneProxy::GetDynamicMeshElements內挖的到,請直接參考就好。
下圖 為分別使用DrawWireSphereAutoSides與GetSphereMesh的範例結果。
結論
這次的範例是精簡過後的程式碼結果,如果想要往後鑽研的話,參考GameplayDebuggerCategory裡面的使用方法是最好的。
在實作這些功能之前,最好是先在遊戲中輸入'開啟debug模式預覽結果。
在融會貫通之後,就可以針對專案開發出獨特的工具。
例如在Unreal Fest Europe 2019的演講中提到,該Studio會在編輯器內顯示被選擇的Actor,以連線的方式顯示參照的對象與被參照的對象。如圖 所示。
用來輕易地理解場景物件彼此的相關性, 如果場景物件關係複雜的話,這個功能會特別有用。
留言
張貼留言