template<typename ElementType, typename OctreeSemantics> class TOctree;ElementType可以視為跟STL容器的value type是一樣的東西,至於OctreeSemantics則是用來設定八分樹的參數,或是提供八分樹類別操作ElementType物件的方法。其實就是所謂的traits。
OctreeSemantics需要提供的成員如下:
- MaxElementsPerLeaf:每個葉節點的最大能容納的元素。當新增元素會超過此上限時,會分割葉節點。
- MaxNodeDepth:最大樹深。
- GetBoundingBox:傳回元素的邊界盒。
- SetElementId:TOctree會給予元素一個ID。移除元素時會用到這個ID。
TOctree提供TConstIterator用來巡曳節點,以及TConstElementBoxIterator用來在指定區域巡曳元素。
跟一般的八分樹比較不一樣的地方是,TOctree的卦限大小會膨漲八分之一邊長,同一個父節點的卦限間會有互相重疊的區域,但不同分支下的卦限不會重疊。
範例
以下程式碼展示如何為自訂的Actor建立自己的八分樹。先列出自訂的Actor:
class MyActor extends Actor native placeable; var() DrawBoxComponent BoxComponent; var const native OctreeElementId OctreeId{FOctreeElementId}; cpptext { void AddToOctree(); void RemoveFromOctree(); // UObject interface virtual void BeginDestroy(); // AActor interface virtual void UpdateComponentsInternal(UBOOL bCollisionUpdate = FALSE); } defaultpropeties { bStatic=true begin object class=DrawBoxComponent name=BoxComp BoxColor=(R=128,G=0,B=128,A=255) BoxExtent=(X=100.0,Y=100.0,Z=50.0) bDrawWireBox=true HiddenGame=false end object BoxComponent=BoxComp Components.Add(BoxComp) }MyActor是靜態Actor,利用DrawBoxComponent的方塊大小當成它所佔的空間。建立時會自動加入八分樹,消失時會自動從八分樹中移除。
以下是自訂的OctreeSemantics:
struct FMyOctreeSemantics { enum { MaxElementsPerLeaf = 16 }; enum { MaxNodeDepth = 10 }; typedef TInlineAllocator<MaxElementsPerLeaf> ElementAllocator; static FBoxCenterAndExtent GetBoundingBox(AMyActor* Actor); { return FBoxCenterAndExtent(Actor->Location, Actor->BoxComponent->BoxExtent); } static void SetElementId(AMyActor* Actor, FOctreeElementId Id) { Actor->OctreeId = Id; } };利用自訂的OctreeSemantics定義客製八分樹:
class FMyOctreeType : public TOctree<AMyActor*, FMyOctreeSemantics> { public: FMyOctreeType(const FVector& InOrigin, FLOAT InExtent) : TOctree(InOrigin, InExtent) , RootNodeBounds(InOrigin, InExtent) { } void Draw(FPrimitiveDrawInterface* PDI, FColor DrawColor); protected: FOctreeNodeBounds RootNodeBounds; }; void FMyOctreeType::Draw(FPrimitiveDrawInterface* PDI, FColor DrawColor) { TConstIterator<DefaultStackAllocator> It(*this); while( It.HasPendingNodes() ) { const FNode& CurrNode = It.GetCurrentNode(); const FOctreeNodeContext& CurrContext = It.GetCurrentContext(); DrawWireBox(PDI, CurrContext.Bounds.GetBox(), DrawColor, SDPG_World); FOREACH_OCTREE_CHILD_NODE(ChildRef) { if( CurrNode.HasChild(ChildRef) ) { It.PushChild(ChildRef); } It.Advance(); } } } FMyOctreeType GMyOctree( FVector::ZeroVector, HALF_WORLD_MAX );上一行中定義一個全域的八分樹以供MyActor加入之用。FMyOctreeType中另外加了一個Draw函式示範如何使用八分樹的迭代子。
最後列出MyActor的函式實作部分:
void AMyActor::BeginDestroy() { RemoveFromOctree(); Super::BeginDestroy(); } void AMyActor::UpdateComponentsInternal(UBOOL bCollisionUpdate) { if( GIsEdtor && !GIsCooking && !GIsPlayInEditorWorld && !GIsUCC ) { AddToOctree(); } Super::UpdateComponentsInternal(bCollisionUpdate); } void AMyActor::AddToOctree() { if( OctreeId.IsValidId() ) { GMyOctree.RemoveElment(OctreeId); OctreeId = FOctreeElementId(); } GMyOctree.AddElement(this); } void AMyActor::RemoveFromOctree() { if( OctreeId.IsValidId() ) { GMyOctree.RemoveElment(OctreeId); } OctreeId = FOctreeElementId(); }
沒有留言:
張貼留言