網頁版
https://yekdniwue.blogspot.com/2020/06/ue4-editor.html
簡介
在遊戲中,我們都知道可以使用Blueprint的DrawDebug系列的功能,
用來繪製圓球,膠囊體等物件提供除錯。
但是如果想在編輯器的View視窗用DrawDebug是做不到的(註1),
至少UE4引擎內部並不是這樣用。
註1.我有試過在ConstructorScript呼叫DrawDebugSphere,結果是會畫出來,
但是永遠不會消失了。
不過引擎是有提供編輯器除錯用的顯示功能的,我們可以在幾個地方看到:
1. Visual Logger
2. EQS Testing Pawn
3. NavigationTestingActor
使用Visual Logger可以在編輯器看到AI角色的位置資訊被記錄下來,
也可以自己透過API紀錄想要的資訊,如圖所示。
[圖1.]
EQS Testing Pawn則是可以隨著編輯過程的狀況不同,顯示/更新Query的結果,
如圖所示。
[圖2.]
NavigationTestingActor是比較罕見的功能,可以在編輯器就預覽路徑搜尋的結果。
有個時候專案也會需要這方面的功能,如果沒有心理準備,
就直接看上面三個系統的實作,通常會被複雜的程式碼勸退。
這次我硬著頭皮研究並試著實作了一輪,簡單的做個筆記與分享。
最主要是去除複雜的程式碼,只列出最基本要實作的項目。有需要改進的部分再從上面提
到的系統抽取出來即可。
本篇文章的內容以NavigationTestingActor為出發點作分析,雖然比較少見,但似乎是這
幾個系統裡面相對簡單的部份。
架構組成
1. AActor
2. URenderComponent
3. FSceneProxy
要完成這個功能,首先要有三個class,一個就是顯示項目要依附在的Actor。
然後要為這個Actor新增自定義的RenderComponent,作為顯示用。
在RenderComponent內會創出自定義的SceneProxy,
你要繪製的項目要實作在SceneProxy的函式內。
以下實際用TestActor, TestRenderComponent, TestSceneProxy分別做為案例。
TestActor要實作的項目
在TestActor的member加上
UPROPERTY()
class UTestRenderComponent* TestRenderComp;
如果只想讓這個功能在Editor中出現,可以使用macro
#if WITH_EDITORONLY_DATA
#endif
將所有使用到TestRenderComponent的地方夾起來。
TestActor的Constructor加上
TestRenderComp =
CreateDefaultSubobject<UTestRenderComponent>(TEXT("TestRenderComp"));
TestRenderComp->PostPhysicsComponentTick.bCanEverTick = false;
根據需求,Override PreEditChange或PostEditChangeProperty或PostEditMove。
在有資料變動的時候呼叫MarkRenderStateDirty。
TestRenderComp->MarkRenderStateDirty();
PostEditChangeProperty內可以實作property內容變動後該做的事;
PostEditMove則是Actor在編輯器內被拖拉移動的時會進入的事件;
TestRenderComponent要實作的項目
首先TestRenderComponent要繼承UPrimitiveComponent,然後實作下面兩個函式。
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
virtual FBoxSphereBounds CalcBounds(const FTransform &LocalToWorld)
const override;
CreateSceneProxy就是new出SceneProxy,並且把component自己傳入SceneProxy的
constructor,說這麼多其實直接看程式碼比較快。
FPrimitiveSceneProxy* UTestRenderComponent::CreateSceneProxy()
{
FTestSceneProxy* newSceneProxy = new FTestSceneProxy(this);
return newSceneProxy;
}
CalcBounds比較簡單,就是決定這個component的bounding box範圍,用來決定這個
component會不會進rendering。
可以從GetOwner拿到TestActor,然後直接回傳Actor的BoundingBox即可。
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的範例結果。
[圖3.]
[圖4.]
結論
這次的範例是精簡過後的程式碼結果,如果想要往後鑽研的話,參考
GameplayDebuggerCategory裡面的使用方法是最好的。
在實作這些功能之前,最好是先在遊戲中輸入'開啟debug模式預覽結果。
在融會貫通之後,就可以針對專案開發出獨特的工具。
例如在Unreal Fest Europe 2019的演講中提到,
該Studio會在編輯器內顯示被選擇的Actor,
以連線的方式顯示參照的對象與被參照的對象。如圖 所示。
用來輕易地理解場景物件彼此的相關性, 如果場景物件關係複雜的話,這個功能會特別
有用。
[圖5.]
參考資料
https://docs.unrealengine.com/en-US/Gameplay/Tools/VisualLogger/index.html
Visual Logger
https://docs.unrealengine.com/en-US/Engine/AI/EnvironmentQuerySystem/EQSPawn/index.html
EQS Testing Pawn
https://www.unrealengine.com/zh-CN/events/unreal-fest-europe-2019/blueprints-blending-system-architecture-and-creativity
Blueprints: Blending System Architecture and Creativity
Deep Silver Dambuster Studios