Advertisement
Guest User

Untitled

a guest
May 21st, 2017
2,399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 110.48 KB | None | 0 0
  1. fixed_HI_StaticMeshComponent.h
  2.  
  3. #pragma once
  4.  
  5. //#include "Components/InstancedStaticMeshComponent.h"
  6. #include "CoreMinimal.h"
  7. #include "Stats/Stats.h"
  8. #include "UObject/ObjectMacros.h"
  9. #include "Async/AsyncWork.h"
  10. #include "Components/InstancedStaticMeshComponent.h"
  11. #include "StaticMeshResources.h"
  12.  
  13. //#include "Components/HierarchicalInstancedStaticMeshComponent.h"
  14.  
  15.  
  16. #include "fixed_HI_StaticMeshComponent.generated.h"
  17.  
  18. class FClusterBuilder;
  19. class FStaticLightingTextureMapping_InstancedStaticMesh;
  20. class Ufixed_HI_StaticMeshComponent;
  21.  
  22. USTRUCT()
  23. struct FFixed_ClusterNode
  24. {
  25.     GENERATED_USTRUCT_BODY()
  26.  
  27.         UPROPERTY()
  28.         FVector BoundMin;
  29.     UPROPERTY()
  30.         int32 FirstChild;
  31.     UPROPERTY()
  32.         FVector BoundMax;
  33.     UPROPERTY()
  34.         int32 LastChild;
  35.     UPROPERTY()
  36.         int32 FirstInstance;
  37.     UPROPERTY()
  38.         int32 LastInstance;
  39.  
  40.     FFixed_ClusterNode()
  41.         : BoundMin(MAX_flt, MAX_flt, MAX_flt)
  42.         , FirstChild(-1)
  43.         , BoundMax(MIN_flt, MIN_flt, MIN_flt)
  44.         , LastChild(-1)
  45.         , FirstInstance(-1)
  46.         , LastInstance(-1)
  47.     {
  48.     }
  49.  
  50.     friend FArchive& operator<<(FArchive& Ar, FFixed_ClusterNode& NodeData)
  51.     {
  52.         // @warning BulkSerialize: FFixed_ClusterNode is serialized as memory dump
  53.         // See TArray::BulkSerialize for detailed description of implied limitations.
  54.         Ar << NodeData.BoundMin;
  55.         Ar << NodeData.FirstChild;
  56.         Ar << NodeData.BoundMax;
  57.         Ar << NodeData.LastChild;
  58.         Ar << NodeData.FirstInstance;
  59.         Ar << NodeData.LastInstance;
  60.         return Ar;
  61.     }
  62. };
  63.  
  64. class FFixed_AsyncBuildInstanceBuffer : public FNonAbandonableTask
  65. {
  66. public:
  67.     class Ufixed_HI_StaticMeshComponent* Component;
  68.     class UWorld* World;
  69.  
  70.     FFixed_AsyncBuildInstanceBuffer(class Ufixed_HI_StaticMeshComponent* InComponent, class UWorld* InWorld)
  71.         : Component(InComponent)
  72.         , World(InWorld)
  73.     {
  74.     }
  75.     void DoWork();
  76.     FORCEINLINE TStatId GetStatId() const
  77.     {
  78.         RETURN_QUICK_DECLARE_CYCLE_STAT(FFixed_AsyncBuildInstanceBuffer, STATGROUP_ThreadPoolAsyncTasks);
  79.     }
  80.     static const TCHAR *Name()
  81.     {
  82.         return TEXT("FFixed_AsyncBuildInstanceBuffer");
  83.     }
  84. };
  85. /**
  86.  *
  87.  */
  88. UCLASS(ClassGroup = Rendering, meta = (BlueprintSpawnableComponent))
  89. class HISM_TEST_API Ufixed_HI_StaticMeshComponent : public UInstancedStaticMeshComponent
  90. {
  91.     GENERATED_UCLASS_BODY()
  92.    
  93.    
  94.     ~Ufixed_HI_StaticMeshComponent();
  95.        
  96.     TSharedPtr<TArray<FFixed_ClusterNode>, ESPMode::ThreadSafe> ClusterTreePtr;
  97.        
  98.     // Temp hack, long term we will load data in the right format directly
  99.     FAsyncTask<FFixed_AsyncBuildInstanceBuffer>* AsyncBuildInstanceBufferTask;
  100.        
  101.     // Prebuilt instance buffer, used mostly for grass. Long term instances will be stored directly in the correct format.
  102.     FStaticMeshInstanceData WriteOncePrebuiltInstanceBuffer;
  103.        
  104.     // Table for remaping instances from cluster tree to PerInstanceSMData order
  105.     UPROPERTY()
  106.         TArray<int32> SortedInstances;
  107.        
  108.     // The number of instances in the ClusterTree. Subsequent instances will always be rendered.
  109.     UPROPERTY()
  110.         int32 NumBuiltInstances;
  111.        
  112.     // Normally equal to NumBuiltInstances, but can be lower if density scaling is in effect
  113.     int32 NumBuiltRenderInstances;
  114.        
  115.     // Bounding box of any built instances (cached from the ClusterTree)
  116.     UPROPERTY()
  117.         FBox BuiltInstanceBounds;
  118.        
  119.     // Bounding box of any unbuilt instances
  120.     UPROPERTY()
  121.         FBox UnbuiltInstanceBounds;
  122.        
  123.     // Bounds of each individual unbuilt instance, used for LOD calculation
  124.     UPROPERTY()
  125.         TArray<FBox> UnbuiltInstanceBoundsList;
  126.        
  127.     // Enable for detail meshes that don't really affect the game. Disable for anything important.
  128.     // Typically, this will be enabled for small meshes without collision (e.g. grass) and disabled for large meshes with collision (e.g. trees)
  129.     UPROPERTY()
  130.         uint32 bEnableDensityScaling : 1;
  131.        
  132.     // Which instances have been removed by foliage density scaling?
  133.     TBitArray<> ExcludedDueToDensityScaling;
  134.        
  135.     // The number of nodes in the occlusion layer
  136.     UPROPERTY()
  137.         int32 OcclusionLayerNumNodes;
  138.        
  139.     bool bIsAsyncBuilding;
  140.     bool bDiscardAsyncBuildResults;
  141.     bool bConcurrentRemoval;
  142.        
  143.     UPROPERTY()
  144.         bool bDisableCollision;
  145.        
  146.     // Apply the results of the async build
  147.     void ApplyBuildTreeAsync(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent, TSharedRef<FClusterBuilder, ESPMode::ThreadSafe> Builder, double StartTime);
  148.        
  149.     public:
  150.    
  151.         //Begin UObject Interface
  152.         virtual void Serialize(FArchive& Ar) override;
  153.         virtual void PostDuplicate(bool bDuplicateForPIE) override;
  154.         virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
  155.         virtual void PostLoad() override;
  156.         virtual FBoxSphereBounds CalcBounds(const FTransform& BoundTransform) const override;
  157.     #if WITH_EDITOR
  158.         virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override;
  159.     #endif
  160.    
  161.         // UInstancedStaticMesh interface
  162.         virtual int32 AddInstance(const FTransform& InstanceTransform) override;
  163.         virtual bool RemoveInstance(int32 InstanceIndex) override;
  164.         virtual bool UpdateInstanceTransform(int32 InstanceIndex, const FTransform& NewInstanceTransform, bool bWorldSpace, bool bMarkRenderStateDirty = false, bool bTeleport = false) override;
  165.         virtual void ClearInstances() override;
  166.         virtual TArray<int32> GetInstancesOverlappingSphere(const FVector& Center, float Radius, bool bSphereInWorldSpace = true) const override;
  167.         virtual TArray<int32> GetInstancesOverlappingBox(const FBox& Box, bool bBoxInWorldSpace = true) const override;
  168.    
  169.         /** Removes all the instances with indices specified in the InstancesToRemove array. Returns true on success. */
  170.         UFUNCTION(BlueprintCallable, Category = "Components|InstancedStaticMesh")
  171.             bool RemoveInstances(const TArray<int32>& InstancesToRemove);
  172.    
  173.         /** Get the number of instances that overlap a given sphere */
  174.         int32 GetOverlappingSphereCount(const FSphere& Sphere) const;
  175.         /** Get the number of instances that overlap a given box */
  176.         int32 GetOverlappingBoxCount(const FBox& Box) const;
  177.         /** Get the transforms of instances inside the provided box */
  178.         void GetOverlappingBoxTransforms(const FBox& Box, TArray<FTransform>& OutTransforms) const;
  179.    
  180.         virtual bool ShouldCreatePhysicsState() const override;
  181.    
  182.         virtual int32 GetNumRenderInstances() const override { return NumBuiltRenderInstances + UnbuiltInstanceBoundsList.Num(); }
  183.    
  184.         void BuildTree();
  185.         void BuildTreeAsync();
  186.         static void BuildTreeAnyThread(
  187.             TArray<FMatrix>& InstanceTransforms,
  188.             const FBox& MeshBox,
  189.             TArray<FFixed_ClusterNode>& OutClusterTree,
  190.             TArray<int32>& OutSortedInstances,
  191.             TArray<int32>& OutInstanceReorderTable,
  192.             int32& OutOcclusionLayerNum,
  193.             int32 MaxInstancesPerLeaf
  194.         );
  195.         void AcceptPrebuiltTree(TArray<FFixed_ClusterNode>& InClusterTree, int InOcclusionLayerNumNodes);
  196.         bool IsAsyncBuilding() const { return bIsAsyncBuilding; }
  197.         bool IsTreeFullyBuilt() const { return NumBuiltInstances == PerInstanceSMData.Num() && RemovedInstances.Num() == 0; }
  198.    
  199.         void FlushAsyncBuildInstanceBufferTask();
  200.    
  201.         /** Heuristic for the number of leaves in the tree **/
  202.         int32 DesiredInstancesPerLeaf();
  203.  
  204.     protected:
  205.         /** Removes a single instance without extra work such as rebuilding the tree or marking render state dirty. */
  206.         void RemoveInstanceInternal(int32 InstanceIndex);
  207.        
  208.         /** Gets and approximate number of verts for each LOD to generate heuristics **/
  209.         int32 GetVertsForLOD(int32 LODIndex);
  210.         /** Average number of instances per leaf **/
  211.         float ActualInstancesPerLeaf();
  212.         /** For testing, prints some stats after any kind of build **/
  213.         void PostBuildStats();
  214.        
  215.         virtual void GetNavigationPerInstanceTransforms(const FBox& AreaBox, TArray<FTransform>& InstanceData) const override;
  216.         virtual void PartialNavigationUpdate(int32 InstanceIdx) override;
  217.         void FlushAccumulatedNavigationUpdates();
  218.         mutable FBox AccumulatedNavigationDirtyArea;
  219.        
  220.     protected:
  221.         friend FStaticLightingTextureMapping_InstancedStaticMesh;
  222.         friend FInstancedLightMap2D;
  223.         friend FInstancedShadowMap2D;
  224.         friend class FClusterBuilder;
  225. };
  226.  
  227.  
  228. fixed_HI_StaticMeshComponent.cpp
  229.  
  230.  
  231. // Fill out your copyright notice in the Description page of Project Settings.
  232.  
  233. #include "HISM_test.h"
  234.  
  235.  
  236. #include "CoreMinimal.h"
  237. #include "Templates/Greater.h"
  238. #include "Math/RandomStream.h"
  239. #include "Stats/Stats.h"
  240. #include "HAL/IConsoleManager.h"
  241. #include "UObject/ObjectMacros.h"
  242. #include "Async/TaskGraphInterfaces.h"
  243. #include "EngineStats.h"
  244. #include "Async/AsyncWork.h"
  245. #include "PrimitiveViewRelevance.h"
  246. #include "ConvexVolume.h"
  247. #include "AI/Navigation/NavigationSystem.h"
  248. #include "Engine/MapBuildDataRegistry.h"
  249. #include "MaterialShared.h"
  250. #include "UObject/UObjectIterator.h"
  251. #include "MeshBatch.h"
  252. #include "RendererInterface.h"
  253. #include "Engine/StaticMesh.h"
  254. #include "UnrealEngine.h"
  255. #include "Components/InstancedStaticMeshComponent.h"
  256. #include "StaticMeshResources.h"
  257. //#include "Components/HierarchicalInstancedStaticMeshComponent.h"
  258. #include "fixed_HI_StaticMeshComponent.h"
  259. #include "Runtime/Engine/Private/InstancedStaticMesh.h"
  260. #include "SceneManagement.h"
  261.  
  262. //
  263. //// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
  264. //
  265. ///*=============================================================================
  266. //InstancedStaticMesh.cpp: Static mesh rendering code.
  267. //=============================================================================*/
  268. //
  269.  
  270.  
  271. static TAutoConsoleVariable<int32> CVarFoliageSplitFactor(
  272.     TEXT("foliage.SplitFactor"),
  273.     16,
  274.     TEXT("This controls the branching factor of the foliage tree."));
  275.  
  276. static TAutoConsoleVariable<int32> CVarForceLOD(
  277.     TEXT("foliage.ForceLOD"),
  278.     -1,
  279.     TEXT("If greater than or equal to zero, forces the foliage LOD to that level."));
  280.  
  281. static TAutoConsoleVariable<int32> CVarOnlyLOD(
  282.     TEXT("foliage.OnlyLOD"),
  283.     -1,
  284.     TEXT("If greater than or equal to zero, only renders the foliage LOD at that level."));
  285.  
  286. static TAutoConsoleVariable<int32> CVarDisableCull(
  287.     TEXT("foliage.DisableCull"),
  288.     0,
  289.     TEXT("If greater than zero, no culling occurs based on frustum."));
  290.  
  291. static TAutoConsoleVariable<int32> CVarCullAll(
  292.     TEXT("foliage.CullAll"),
  293.     0,
  294.     TEXT("If greater than zero, everything is considered culled."));
  295.  
  296. static TAutoConsoleVariable<int32> CVarDitheredLOD(
  297.     TEXT("foliage.DitheredLOD"),
  298.     1,
  299.     TEXT("If greater than zero, dithered LOD is used, otherwise popping LOD is used."));
  300.  
  301. static TAutoConsoleVariable<int32> CVarOverestimateLOD(
  302.     TEXT("foliage.OverestimateLOD"),
  303.     0,
  304.     TEXT("If greater than zero and dithered LOD is not used, then we use an overestimate of LOD instead of an underestimate."));
  305.  
  306. static TAutoConsoleVariable<int32> CVarMaxTrianglesToRender(
  307.     TEXT("foliage.MaxTrianglesToRender"),
  308.     100000000,
  309.     TEXT("This is an absolute limit on the number of foliage triangles to render in one traversal. This is used to prevent a silly LOD parameter mistake from causing the OS to kill the GPU."));
  310.  
  311. TAutoConsoleVariable<float> CVarFoliageMinimumScreenSize(
  312.     TEXT("foliage.MinimumScreenSize"),
  313.     0.000005f,
  314.     TEXT("This controls the screen size at which we cull foliage instances entirely."),
  315.     ECVF_Scalability);
  316.  
  317. TAutoConsoleVariable<float> CVarFoliageLODDistanceScale(
  318.     TEXT("foliage.LODDistanceScale"),
  319.     1.0f,
  320.     TEXT("Scale factor for the distance used in computing LOD for foliage."));
  321.  
  322. TAutoConsoleVariable<float> CVarRandomLODRange(
  323.     TEXT("foliage.RandomLODRange"),
  324.     0.0f,
  325.     TEXT("Random distance added to each instance distance to compute LOD."));
  326.  
  327. static TAutoConsoleVariable<int32> CVarASyncInstaneBufferConversion(
  328.     TEXT("foliage.ASyncInstaneBufferConversion"),
  329.     1,
  330.     TEXT("If this is > 0, then build game instance buffering async during streaming. This is not thought to be a long term solution to this problem."));
  331.  
  332. static TAutoConsoleVariable<int32> CVarMinVertsToSplitNode(
  333.     TEXT("foliage.MinVertsToSplitNode"),
  334.     16384,
  335.     TEXT("Controls the accuracy between culling and LOD accuracy and culling and CPU performance."));
  336.  
  337. static TAutoConsoleVariable<int32> CVarMaxOcclusionQueriesPerComponent(
  338.     TEXT("foliage.MaxOcclusionQueriesPerComponent"),
  339.     16,
  340.     TEXT("Controls the granualrity of occlusion culling. 16-128 is a reasonable range."));
  341.  
  342. static TAutoConsoleVariable<int32> CVarMinInstancesPerOcclusionQuery(
  343.     TEXT("foliage.MinInstancesPerOcclusionQuery"),
  344.     256,
  345.     TEXT("Controls the granualrity of occlusion culling. 1024 to 65536 is a reasonable range. This is not exact, actual minimum might be off by a factor of two."));
  346.  
  347. static TAutoConsoleVariable<float> CVarFoliageDensityScale(
  348.     TEXT("foliage.DensityScale"),
  349.     1.0,
  350.     TEXT("Controls the amount of foliage to render. Foliage must opt-in to density scaling through the foliage type."),
  351.     ECVF_Scalability);
  352.  
  353. DECLARE_CYCLE_STAT(TEXT("Traversal Time"), STAT_FoliageTraversalTime, STATGROUP_Foliage);
  354. DECLARE_CYCLE_STAT(TEXT("Build Time"), STAT_FoliageBuildTime, STATGROUP_Foliage);
  355. DECLARE_CYCLE_STAT(TEXT("Batch Time"), STAT_FoliageBatchTime, STATGROUP_Foliage);
  356. DECLARE_DWORD_COUNTER_STAT(TEXT("Runs"), STAT_FoliageRuns, STATGROUP_Foliage);
  357. DECLARE_DWORD_COUNTER_STAT(TEXT("Mesh Batches"), STAT_FoliageMeshBatches, STATGROUP_Foliage);
  358. DECLARE_DWORD_COUNTER_STAT(TEXT("Triangles"), STAT_FoliageTriangles, STATGROUP_Foliage);
  359. DECLARE_DWORD_COUNTER_STAT(TEXT("Instances"), STAT_FoliageInstances, STATGROUP_Foliage);
  360. DECLARE_DWORD_COUNTER_STAT(TEXT("Occlusion Culled Instances"), STAT_OcclusionCulledFoliageInstances, STATGROUP_Foliage);
  361. DECLARE_DWORD_COUNTER_STAT(TEXT("Traversals"), STAT_FoliageTraversals, STATGROUP_Foliage);
  362. DECLARE_MEMORY_STAT(TEXT("Instance Buffers"), STAT_FoliageInstanceBuffers, STATGROUP_Foliage);
  363.  
  364. static void FoliageCVarSinkFunction()
  365. {
  366.     static float CachedFoliageDensityScale = 1.0f;
  367.     float FoliageDensityScale = CVarFoliageDensityScale.GetValueOnGameThread();
  368.  
  369.     if (FoliageDensityScale != CachedFoliageDensityScale)
  370.     {
  371.         CachedFoliageDensityScale = FoliageDensityScale;
  372.  
  373.         for (auto* Component : TObjectRange<Ufixed_HI_StaticMeshComponent>(RF_ClassDefaultObject | RF_ArchetypeObject, true, EInternalObjectFlags::PendingKill))
  374.         {
  375.             if (Component->bEnableDensityScaling && Component->GetWorld() && Component->GetWorld()->IsGameWorld())
  376.             {
  377.                 if (FoliageDensityScale == 0)
  378.                 {
  379.                     // exclude all instances
  380.                     Component->ExcludedDueToDensityScaling.Init(true, Component->PerInstanceSMData.Num());
  381.                 }
  382.                 else if (FoliageDensityScale > 0.0f && FoliageDensityScale < 1.0f)
  383.                 {
  384.                     FRandomStream Rand(Component->InstancingRandomSeed);
  385.                     if (Component->ExcludedDueToDensityScaling.Num() == 0)
  386.                     {
  387.                         // TBitArray<> doesn't have SetNumUninitialized...
  388.                         Component->ExcludedDueToDensityScaling.Init(false, Component->PerInstanceSMData.Num());
  389.                     }
  390.  
  391.                     for (int32 i = 0; i < Component->ExcludedDueToDensityScaling.Num(); ++i)
  392.                     {
  393.                         Component->ExcludedDueToDensityScaling[i] = (Rand.FRand() > FoliageDensityScale);
  394.                     }
  395.                 }
  396.                 else
  397.                 {
  398.                     // Show all instances
  399.                     Component->ExcludedDueToDensityScaling.Empty();
  400.                 }
  401.  
  402.                 Component->BuildTree();
  403.                 Component->MarkRenderStateDirty();
  404.             }
  405.         }
  406.     }
  407. }
  408.  
  409. static FAutoConsoleVariableSink CVarFoliageSink(FConsoleCommandDelegate::CreateStatic(&FoliageCVarSinkFunction));
  410.  
  411. struct FClusterTree
  412. {
  413.     TArray<FFixed_ClusterNode> Nodes;
  414.     TArray<int32> SortedInstances;
  415.     TArray<int32> InstanceReorderTable;
  416.     int32 OutOcclusionLayerNum;
  417. };
  418.  
  419.  
  420. class FClusterBuilder
  421. {
  422.     int32 OriginalNum;
  423.     int32 Num;
  424.     FBox InstBox;
  425.     int32 BranchingFactor;
  426.     int32 InternalNodeBranchingFactor;
  427.     int32 OcclusionLayerTarget;
  428.     int32 MaxInstancesPerLeaf;
  429.     int32 NumRoots;
  430.     TArray<int32> SortIndex;
  431.     TArray<FVector> SortPoints;
  432.     TArray<FMatrix> Transforms;
  433.  
  434.     struct FRunPair
  435.     {
  436.         int32 Start;
  437.         int32 Num;
  438.  
  439.         FRunPair(int32 InStart, int32 InNum)
  440.             : Start(InStart)
  441.             , Num(InNum)
  442.         {
  443.         }
  444.  
  445.         bool operator< (const FRunPair& Other) const
  446.         {
  447.             return Start < Other.Start;
  448.         }
  449.     };
  450.     TArray<FRunPair> Clusters;
  451.  
  452.     struct FSortPair
  453.     {
  454.         float d;
  455.         int32 Index;
  456.  
  457.         bool operator< (const FSortPair& Other) const
  458.         {
  459.             return d < Other.d;
  460.         }
  461.     };
  462.     TArray<FSortPair> SortPairs;
  463.  
  464.     void Split(int32 InNum)
  465.     {
  466.         checkSlow(InNum);
  467.         Clusters.Reset();
  468.         Split(0, InNum - 1);
  469.         Clusters.Sort();
  470.         checkSlow(Clusters.Num() > 0);
  471.         int32 At = 0;
  472.         for (auto& Cluster : Clusters)
  473.         {
  474.             checkSlow(At == Cluster.Start);
  475.             At += Cluster.Num;
  476.         }
  477.         checkSlow(At == InNum);
  478.     }
  479.  
  480.     void Split(int32 Start, int32 End)
  481.     {
  482.         int32 NumRange = 1 + End - Start;
  483.         FBox ClusterBounds(ForceInit);
  484.         for (int32 Index = Start; Index <= End; Index++)
  485.         {
  486.             ClusterBounds += SortPoints[SortIndex[Index]];
  487.         }
  488.         if (NumRange <= BranchingFactor)
  489.         {
  490.             Clusters.Add(FRunPair(Start, NumRange));
  491.             return;
  492.         }
  493.         checkSlow(NumRange >= 2);
  494.         SortPairs.Reset();
  495.         int32 BestAxis = -1;
  496.         float BestAxisValue = -1.0f;
  497.         for (int32 Axis = 0; Axis < 3; Axis++)
  498.         {
  499.             float ThisAxisValue = ClusterBounds.Max[Axis] - ClusterBounds.Min[Axis];
  500.             if (!Axis || ThisAxisValue > BestAxisValue)
  501.             {
  502.                 BestAxis = Axis;
  503.                 BestAxisValue = ThisAxisValue;
  504.             }
  505.         }
  506.         for (int32 Index = Start; Index <= End; Index++)
  507.         {
  508.             FSortPair Pair;
  509.  
  510.             Pair.Index = SortIndex[Index];
  511.             Pair.d = SortPoints[Pair.Index][BestAxis];
  512.             SortPairs.Add(Pair);
  513.         }
  514.         SortPairs.Sort();
  515.         for (int32 Index = Start; Index <= End; Index++)
  516.         {
  517.             SortIndex[Index] = SortPairs[Index - Start].Index;
  518.         }
  519.  
  520.         int32 Half = NumRange / 2;
  521.  
  522.         int32 EndLeft = Start + Half - 1;
  523.         int32 StartRight = 1 + End - Half;
  524.  
  525.         if (NumRange & 1)
  526.         {
  527.             if (SortPairs[Half].d - SortPairs[Half - 1].d < SortPairs[Half + 1].d - SortPairs[Half].d)
  528.             {
  529.                 EndLeft++;
  530.             }
  531.             else
  532.             {
  533.                 StartRight--;
  534.             }
  535.         }
  536.         checkSlow(EndLeft + 1 == StartRight);
  537.         checkSlow(EndLeft >= Start);
  538.         checkSlow(End >= StartRight);
  539.  
  540.         Split(Start, EndLeft);
  541.         Split(StartRight, End);
  542.     }
  543. public:
  544.     FClusterTree* Result;
  545.  
  546.     FClusterBuilder(TArray<FMatrix> InTransforms, const FBox& InInstBox, int32 InMaxInstancesPerLeaf, TBitArray<> ExcludedDueToDensityScaling = TBitArray<>())
  547.         : OriginalNum(InTransforms.Num())
  548.         , InstBox(InInstBox)
  549.         , Transforms(MoveTemp(InTransforms))
  550.         , Result(nullptr)
  551.     {
  552.         SortPoints.AddUninitialized(OriginalNum);
  553.         for (int32 Index = 0; Index < OriginalNum; Index++)
  554.         {
  555.             SortPoints[Index] = Transforms[Index].GetOrigin();
  556.         }
  557.  
  558.         for (int32 Index = 0; Index < ExcludedDueToDensityScaling.Num(); ++Index)
  559.         {
  560.             if (!ExcludedDueToDensityScaling[Index])
  561.             {
  562.                 SortIndex.Add(Index);
  563.             }
  564.         }
  565.         for (int32 Index = ExcludedDueToDensityScaling.Num(); Index < OriginalNum; ++Index)
  566.         {
  567.             SortIndex.Add(Index);
  568.         }
  569.  
  570.         Num = SortIndex.Num();
  571.  
  572.         OcclusionLayerTarget = CVarMaxOcclusionQueriesPerComponent.GetValueOnAnyThread();
  573.         int32 MinInstancesPerOcclusionQuery = CVarMinInstancesPerOcclusionQuery.GetValueOnAnyThread();
  574.  
  575.         if (Num / MinInstancesPerOcclusionQuery < OcclusionLayerTarget)
  576.         {
  577.             OcclusionLayerTarget = Num / MinInstancesPerOcclusionQuery;
  578.             if (OcclusionLayerTarget < 6)
  579.             {
  580.                 OcclusionLayerTarget = 0;
  581.             }
  582.         }
  583.         InternalNodeBranchingFactor = CVarFoliageSplitFactor.GetValueOnAnyThread();
  584.         MaxInstancesPerLeaf = InMaxInstancesPerLeaf;
  585.     }
  586.  
  587.     void BuildAsync(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
  588.     {
  589.         Build();
  590.         //FPlatformProcess::Sleep(5);
  591.     }
  592.  
  593.     void Build()
  594.     {
  595.         Result = new FClusterTree;
  596.  
  597.         if (Num == 0)
  598.         {
  599.             // Can happen if all instances are excluded due to scalability
  600.             // It doesn't only happen with a scalability factor of 0 -
  601.             // even with a scalability factor of 0.99, if there's only one instance of this type you can end up with Num == 0 if you're unlucky
  602.             Result->InstanceReorderTable.Init(INDEX_NONE, OriginalNum);
  603.             return;
  604.         }
  605.  
  606.         bool bIsOcclusionLayer = false;
  607.         BranchingFactor = MaxInstancesPerLeaf;
  608.         if (BranchingFactor > 2 && OcclusionLayerTarget && Num / BranchingFactor <= OcclusionLayerTarget)
  609.         {
  610.             BranchingFactor = FMath::Max<int32>(2, (Num + OcclusionLayerTarget - 1) / OcclusionLayerTarget);
  611.             OcclusionLayerTarget = 0;
  612.             bIsOcclusionLayer = true;
  613.         }
  614.         Split(Num);
  615.         if (bIsOcclusionLayer)
  616.         {
  617.             Result->OutOcclusionLayerNum = Clusters.Num();
  618.             bIsOcclusionLayer = false;
  619.         }
  620.  
  621.         TArray<int32>& SortedInstances = Result->SortedInstances;
  622.         SortedInstances.AddUninitialized(Num);
  623.         for (int32 Index = 0; Index < Num; Index++)
  624.         {
  625.             SortedInstances[Index] = SortIndex[Index];
  626.         }
  627.         NumRoots = Clusters.Num();
  628.         Result->Nodes.Reserve(Clusters.Num());
  629.         for (int32 Index = 0; Index < NumRoots; Index++)
  630.         {
  631.             Result->Nodes.Add(FFixed_ClusterNode());
  632.         }
  633.  
  634.         for (int32 Index = 0; Index < NumRoots; Index++)
  635.         {
  636.             FFixed_ClusterNode& Node = Result->Nodes[Index];
  637.             Node.FirstInstance = Clusters[Index].Start;
  638.             Node.LastInstance = Clusters[Index].Start + Clusters[Index].Num - 1;
  639.             FBox NodeBox(ForceInit);
  640.             for (int32 InstanceIndex = Node.FirstInstance; InstanceIndex <= Node.LastInstance; InstanceIndex++)
  641.             {
  642.                 const FMatrix& ThisInstTrans = Transforms[SortedInstances[InstanceIndex]];
  643.                 FBox ThisInstBox = InstBox.TransformBy(ThisInstTrans);
  644.                 NodeBox += ThisInstBox;
  645.             }
  646.             Node.BoundMin = NodeBox.Min;
  647.             Node.BoundMax = NodeBox.Max;
  648.         }
  649.         TArray<int32> NodesPerLevel;
  650.         NodesPerLevel.Add(NumRoots);
  651.         int32 LOD = 0;
  652.  
  653.         TArray<int32> InverseSortIndex;
  654.         TArray<int32> RemapSortIndex;
  655.         TArray<int32> InverseInstanceIndex;
  656.         TArray<int32> OldInstanceIndex;
  657.         TArray<int32> LevelStarts;
  658.         TArray<int32> InverseChildIndex;
  659.         TArray<FFixed_ClusterNode> OldNodes;
  660.  
  661.         while (NumRoots > 1)
  662.         {
  663.             SortIndex.Reset();
  664.             SortPoints.Reset();
  665.             SortIndex.AddUninitialized(NumRoots);
  666.             SortPoints.AddUninitialized(NumRoots);
  667.             for (int32 Index = 0; Index < NumRoots; Index++)
  668.             {
  669.                 SortIndex[Index] = Index;
  670.                 FFixed_ClusterNode& Node = Result->Nodes[Index];
  671.                 SortPoints[Index] = (Node.BoundMin + Node.BoundMax) * 0.5f;
  672.             }
  673.             BranchingFactor = InternalNodeBranchingFactor;
  674.             if (BranchingFactor > 2 && OcclusionLayerTarget && NumRoots / BranchingFactor <= OcclusionLayerTarget)
  675.             {
  676.                 BranchingFactor = FMath::Max<int32>(2, (NumRoots + OcclusionLayerTarget - 1) / OcclusionLayerTarget);
  677.                 OcclusionLayerTarget = 0;
  678.                 bIsOcclusionLayer = true;
  679.             }
  680.             Split(NumRoots);
  681.             if (bIsOcclusionLayer)
  682.             {
  683.                 Result->OutOcclusionLayerNum = Clusters.Num();
  684.                 bIsOcclusionLayer = false;
  685.             }
  686.  
  687.             InverseSortIndex.Reset();
  688.             InverseSortIndex.AddUninitialized(NumRoots);
  689.             for (int32 Index = 0; Index < NumRoots; Index++)
  690.             {
  691.                 InverseSortIndex[SortIndex[Index]] = Index;
  692.             }
  693.  
  694.             {
  695.                 // rearrange the instances to match the new order of the old roots
  696.                 RemapSortIndex.Reset();
  697.                 RemapSortIndex.AddUninitialized(Num);
  698.                 int32 OutIndex = 0;
  699.                 for (int32 Index = 0; Index < NumRoots; Index++)
  700.                 {
  701.                     FFixed_ClusterNode& Node = Result->Nodes[SortIndex[Index]];
  702.                     for (int32 InstanceIndex = Node.FirstInstance; InstanceIndex <= Node.LastInstance; InstanceIndex++)
  703.                     {
  704.                         RemapSortIndex[OutIndex++] = InstanceIndex;
  705.                     }
  706.                 }
  707.                 InverseInstanceIndex.Reset();
  708.                 InverseInstanceIndex.AddUninitialized(Num);
  709.                 for (int32 Index = 0; Index < Num; Index++)
  710.                 {
  711.                     InverseInstanceIndex[RemapSortIndex[Index]] = Index;
  712.                 }
  713.                 for (int32 Index = 0; Index < Result->Nodes.Num(); Index++)
  714.                 {
  715.                     FFixed_ClusterNode& Node = Result->Nodes[Index];
  716.                     Node.FirstInstance = InverseInstanceIndex[Node.FirstInstance];
  717.                     Node.LastInstance = InverseInstanceIndex[Node.LastInstance];
  718.                 }
  719.                 OldInstanceIndex.Reset();
  720.                 Swap(OldInstanceIndex, SortedInstances);
  721.                 SortedInstances.AddUninitialized(Num);
  722.                 for (int32 Index = 0; Index < Num; Index++)
  723.                 {
  724.                     SortedInstances[Index] = OldInstanceIndex[RemapSortIndex[Index]];
  725.                 }
  726.             }
  727.             {
  728.                 // rearrange the nodes to match the new order of the old roots
  729.                 RemapSortIndex.Reset();
  730.                 int32 NewNum = Result->Nodes.Num() + Clusters.Num();
  731.                 // RemapSortIndex[new index] == old index
  732.                 RemapSortIndex.AddUninitialized(NewNum);
  733.                 LevelStarts.Reset();
  734.                 LevelStarts.Add(Clusters.Num());
  735.                 for (int32 Index = 0; Index < NodesPerLevel.Num() - 1; Index++)
  736.                 {
  737.                     LevelStarts.Add(LevelStarts[Index] + NodesPerLevel[Index]);
  738.                 }
  739.  
  740.                 for (int32 Index = 0; Index < NumRoots; Index++)
  741.                 {
  742.                     FFixed_ClusterNode& Node = Result->Nodes[SortIndex[Index]];
  743.                     RemapSortIndex[LevelStarts[0]++] = SortIndex[Index];
  744.  
  745.                     int32 LeftIndex = Node.FirstChild;
  746.                     int32 RightIndex = Node.LastChild;
  747.                     int32 LevelIndex = 1;
  748.                     while (RightIndex >= 0)
  749.                     {
  750.                         int32 NextLeftIndex = MAX_int32;
  751.                         int32 NextRightIndex = -1;
  752.                         for (int32 ChildIndex = LeftIndex; ChildIndex <= RightIndex; ChildIndex++)
  753.                         {
  754.                             RemapSortIndex[LevelStarts[LevelIndex]++] = ChildIndex;
  755.                             int32 LeftChild = Result->Nodes[ChildIndex].FirstChild;
  756.                             int32 RightChild = Result->Nodes[ChildIndex].LastChild;
  757.                             if (LeftChild >= 0 && LeftChild <  NextLeftIndex)
  758.                             {
  759.                                 NextLeftIndex = LeftChild;
  760.                             }
  761.                             if (RightChild >= 0 && RightChild >  NextRightIndex)
  762.                             {
  763.                                 NextRightIndex = RightChild;
  764.                             }
  765.                         }
  766.                         LeftIndex = NextLeftIndex;
  767.                         RightIndex = NextRightIndex;
  768.                         LevelIndex++;
  769.                     }
  770.                 }
  771.                 checkSlow(LevelStarts[LevelStarts.Num() - 1] == NewNum);
  772.                 InverseChildIndex.Reset();
  773.                 // InverseChildIndex[old index] == new index
  774.                 InverseChildIndex.AddUninitialized(NewNum);
  775.                 for (int32 Index = Clusters.Num(); Index < NewNum; Index++)
  776.                 {
  777.                     InverseChildIndex[RemapSortIndex[Index]] = Index;
  778.                 }
  779.                 for (int32 Index = 0; Index < Result->Nodes.Num(); Index++)
  780.                 {
  781.                     FFixed_ClusterNode& Node = Result->Nodes[Index];
  782.                     if (Node.FirstChild >= 0)
  783.                     {
  784.                         Node.FirstChild = InverseChildIndex[Node.FirstChild];
  785.                         Node.LastChild = InverseChildIndex[Node.LastChild];
  786.                     }
  787.                 }
  788.                 {
  789.                     Swap(OldNodes, Result->Nodes);
  790.                     Result->Nodes.Empty(NewNum);
  791.                     for (int32 Index = 0; Index < Clusters.Num(); Index++)
  792.                     {
  793.                         Result->Nodes.Add(FFixed_ClusterNode());
  794.                     }
  795.                     Result->Nodes.AddUninitialized(OldNodes.Num());
  796.                     for (int32 Index = 0; Index < OldNodes.Num(); Index++)
  797.                     {
  798.                         Result->Nodes[InverseChildIndex[Index]] = OldNodes[Index];
  799.                     }
  800.                 }
  801.                 int32 OldIndex = Clusters.Num();
  802.                 int32 InstanceTracker = 0;
  803.                 for (int32 Index = 0; Index < Clusters.Num(); Index++)
  804.                 {
  805.                     FFixed_ClusterNode& Node = Result->Nodes[Index];
  806.                     Node.FirstChild = OldIndex;
  807.                     OldIndex += Clusters[Index].Num;
  808.                     Node.LastChild = OldIndex - 1;
  809.                     Node.FirstInstance = Result->Nodes[Node.FirstChild].FirstInstance;
  810.                     checkSlow(Node.FirstInstance == InstanceTracker);
  811.                     Node.LastInstance = Result->Nodes[Node.LastChild].LastInstance;
  812.                     InstanceTracker = Node.LastInstance + 1;
  813.                     checkSlow(InstanceTracker <= Num);
  814.                     FBox NodeBox(ForceInit);
  815.                     for (int32 ChildIndex = Node.FirstChild; ChildIndex <= Node.LastChild; ChildIndex++)
  816.                     {
  817.                         FFixed_ClusterNode& ChildNode = Result->Nodes[ChildIndex];
  818.                         NodeBox += ChildNode.BoundMin;
  819.                         NodeBox += ChildNode.BoundMax;
  820.                     }
  821.                     Node.BoundMin = NodeBox.Min;
  822.                     Node.BoundMax = NodeBox.Max;
  823.                 }
  824.                 NumRoots = Clusters.Num();
  825.                 NodesPerLevel.Insert(NumRoots, 0);
  826.             }
  827.         }
  828.  
  829.         // Save inverse map
  830.         Result->InstanceReorderTable.Init(INDEX_NONE, OriginalNum);
  831.         for (int32 Index = 0; Index < Num; Index++)
  832.         {
  833.             Result->InstanceReorderTable[SortedInstances[Index]] = Index;
  834.         }
  835.     }
  836.  
  837. };
  838.  
  839.  
  840. static bool PrintLevel(const FClusterTree& Tree, int32 NodeIndex, int32 Level, int32 CurrentLevel, int32 Parent)
  841. {
  842.     const FFixed_ClusterNode& Node = Tree.Nodes[NodeIndex];
  843.     if (Level == CurrentLevel)
  844.     {
  845.         UE_LOG(LogConsoleResponse, Display, TEXT("Level %2d  Parent %3d"),
  846.             Level,
  847.             Parent
  848.         );
  849.         FVector Extent = Node.BoundMax - Node.BoundMin;
  850.         UE_LOG(LogConsoleResponse, Display, TEXT("    Bound (%5.1f, %5.1f, %5.1f) [(%5.1f, %5.1f, %5.1f) - (%5.1f, %5.1f, %5.1f)]"),
  851.             Extent.X, Extent.Y, Extent.Z,
  852.             Node.BoundMin.X, Node.BoundMin.Y, Node.BoundMin.Z,
  853.             Node.BoundMax.X, Node.BoundMax.Y, Node.BoundMax.Z
  854.         );
  855.         UE_LOG(LogConsoleResponse, Display, TEXT("    children %3d [%3d,%3d]   instances %3d [%3d,%3d]"),
  856.             (Node.FirstChild < 0) ? 0 : 1 + Node.LastChild - Node.FirstChild, Node.FirstChild, Node.LastChild,
  857.             1 + Node.LastInstance - Node.FirstInstance, Node.FirstInstance, Node.LastInstance
  858.         );
  859.         return true;
  860.     }
  861.     else if (Node.FirstChild < 0)
  862.     {
  863.         return false;
  864.     }
  865.     bool Ret = false;
  866.     for (int32 Child = Node.FirstChild; Child <= Node.LastChild; Child++)
  867.     {
  868.         Ret = PrintLevel(Tree, Child, Level, CurrentLevel + 1, NodeIndex) || Ret;
  869.     }
  870.     return Ret;
  871. }
  872.  
  873. static void TestFoliage(const TArray<FString>& Args)
  874. {
  875.     UE_LOG(LogConsoleResponse, Display, TEXT("Running Foliage test."));
  876.     TArray<FInstancedStaticMeshInstanceData> Instances;
  877.  
  878.     FMatrix Temp;
  879.     Temp.SetIdentity();
  880.     FRandomStream RandomStream(0x238946);
  881.     for (int32 i = 0; i < 1000; i++)
  882.     {
  883.         Instances.Add(FInstancedStaticMeshInstanceData());
  884.         Temp.SetOrigin(FVector(RandomStream.FRandRange(0.0f, 1.0f), RandomStream.FRandRange(0.0f, 1.0f), 0.0f) * 10000.0f);
  885.         Instances[i].Transform = Temp;
  886.     }
  887.  
  888.     FBox TempBox(ForceInit);
  889.     TempBox += FVector(-100.0f, -100.0f, -100.0f);
  890.     TempBox += FVector(100.0f, 100.0f, 100.0f);
  891.  
  892.     TArray<FMatrix> InstanceTransforms;
  893.     InstanceTransforms.AddUninitialized(Instances.Num());
  894.     for (int32 Index = 0; Index < Instances.Num(); Index++)
  895.     {
  896.         InstanceTransforms[Index] = Instances[Index].Transform;
  897.     }
  898.     FClusterBuilder Builder(InstanceTransforms, TempBox, 16);
  899.     Builder.Build();
  900.  
  901.     int32 Level = 0;
  902.  
  903.     UE_LOG(LogConsoleResponse, Display, TEXT("-----"));
  904.  
  905.     while (PrintLevel(*Builder.Result, 0, Level++, 0, -1))
  906.     {
  907.     }
  908.  
  909.     delete Builder.Result;
  910. }
  911.  
  912. static FAutoConsoleCommand TestFoliageCmd(
  913.     TEXT("foliage.Test"),
  914.     TEXT("Useful for debugging."),
  915.     FConsoleCommandWithArgsDelegate::CreateStatic(&TestFoliage)
  916. );
  917.  
  918. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  919. static uint32 GDebugTag = 1;
  920. static uint32 GCaptureDebugRuns = 0;
  921. #endif
  922.  
  923. static void FreezeFoliageCulling(const TArray<FString>& Args)
  924. {
  925. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  926.     UE_LOG(LogConsoleResponse, Display, TEXT("Freezing Foliage Culling."));
  927.     GDebugTag++;
  928.     GCaptureDebugRuns = GDebugTag;
  929. #endif
  930. }
  931.  
  932. static FAutoConsoleCommand FreezeFoliageCullingCmd(
  933.     TEXT("foliage.Freeze"),
  934.     TEXT("Useful for debugging. Freezes the foliage culling and LOD."),
  935.     FConsoleCommandWithArgsDelegate::CreateStatic(&FreezeFoliageCulling)
  936. );
  937.  
  938. static void UnFreezeFoliageCulling(const TArray<FString>& Args)
  939. {
  940. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  941.     UE_LOG(LogConsoleResponse, Display, TEXT("Unfreezing Foliage Culling."));
  942.     GDebugTag++;
  943.     GCaptureDebugRuns = 0;
  944. #endif
  945. }
  946.  
  947. static FAutoConsoleCommand UnFreezeFoliageCullingCmd(
  948.     TEXT("foliage.UnFreeze"),
  949.     TEXT("Useful for debugging. Freezes the foliage culling and LOD."),
  950.     FConsoleCommandWithArgsDelegate::CreateStatic(&UnFreezeFoliageCulling)
  951. );
  952.  
  953.  
  954. struct FFoliageOcclusionResults
  955. {
  956.     TArray<bool>* Results;
  957.     int32 ResultsStart;
  958.     int32 NumResults;
  959.     uint32 FrameNumberRenderThread;
  960.  
  961.     FFoliageOcclusionResults(TArray<bool>* InResults, int32 InResultsStart, int32 InNumResults)
  962.         : Results(InResults)
  963.         , ResultsStart(InResultsStart)
  964.         , NumResults(InNumResults)
  965.         , FrameNumberRenderThread(GFrameNumberRenderThread)
  966.     {
  967.  
  968.     }
  969. };
  970.  
  971. struct FFoliageElementParams;
  972. struct FFoliageRenderInstanceParams;
  973. struct FFoliageCullInstanceParams;
  974.  
  975. class FHierarchicalStaticMeshSceneProxy : public FInstancedStaticMeshSceneProxy
  976. {
  977.     TSharedRef<TArray<FFixed_ClusterNode>, ESPMode::ThreadSafe> ClusterTreePtr;
  978.     const TArray<FFixed_ClusterNode>& ClusterTree;
  979.  
  980.     TArray<FBox> UnbuiltBounds;
  981.     int32 FirstUnbuiltIndex;
  982.     int32 LastUnbuiltIndex;
  983.  
  984.     int32 FirstOcclusionNode;
  985.     int32 LastOcclusionNode;
  986.     TArray<FBoxSphereBounds> OcclusionBounds;
  987.     TMap<uint32, FFoliageOcclusionResults> OcclusionResults;
  988.     bool bIsGrass;
  989.     uint32 SceneProxyCreatedFrameNumberRenderThread;
  990.     bool bDitheredLODTransitions;
  991.  
  992. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  993.     mutable TArray<uint32> SingleDebugRuns[MAX_STATIC_MESH_LODS];
  994.     mutable int32 SingleDebugTotalInstances[MAX_STATIC_MESH_LODS];
  995.     mutable TArray<uint32> MultipleDebugRuns[MAX_STATIC_MESH_LODS];
  996.     mutable int32 MultipleDebugTotalInstances[MAX_STATIC_MESH_LODS];
  997.     mutable int32 CaptureTag;
  998. #endif
  999.  
  1000. public:
  1001.  
  1002.     FHierarchicalStaticMeshSceneProxy(bool bInIsGrass, Ufixed_HI_StaticMeshComponent* InComponent, ERHIFeatureLevel::Type InFeatureLevel)
  1003.         : FInstancedStaticMeshSceneProxy(InComponent, InFeatureLevel)
  1004.         , ClusterTreePtr(InComponent->ClusterTreePtr.ToSharedRef())
  1005.         , ClusterTree(*InComponent->ClusterTreePtr)
  1006.         , UnbuiltBounds(InComponent->UnbuiltInstanceBoundsList)
  1007.         , FirstUnbuiltIndex(InComponent->NumBuiltRenderInstances)
  1008.         , LastUnbuiltIndex(InComponent->GetNumRenderInstances() - 1)
  1009.         , bIsGrass(bInIsGrass)
  1010.         , SceneProxyCreatedFrameNumberRenderThread(UINT32_MAX)
  1011.         , bDitheredLODTransitions(InComponent->SupportsDitheredLODTransitions())
  1012. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1013.         , CaptureTag(0)
  1014. #endif
  1015.     {
  1016.         check(InComponent->InstanceReorderTable.Num() == InComponent->PerInstanceSMData.Num());
  1017.         SetupOcclusion(InComponent);
  1018.     }
  1019.  
  1020.     FHierarchicalStaticMeshSceneProxy(bool bInIsGrass, Ufixed_HI_StaticMeshComponent* InComponent, ERHIFeatureLevel::Type InFeatureLevel, FStaticMeshInstanceData& Other)
  1021.         : FInstancedStaticMeshSceneProxy(InComponent, InFeatureLevel, Other)
  1022.         , ClusterTreePtr(InComponent->ClusterTreePtr.ToSharedRef())
  1023.         , ClusterTree(*InComponent->ClusterTreePtr)
  1024.         , UnbuiltBounds(InComponent->UnbuiltInstanceBoundsList)
  1025.         , FirstUnbuiltIndex(InComponent->NumBuiltRenderInstances)
  1026.         , LastUnbuiltIndex(InComponent->GetNumRenderInstances() - 1)
  1027.         , bIsGrass(bInIsGrass)
  1028.         , SceneProxyCreatedFrameNumberRenderThread(UINT32_MAX)
  1029.         , bDitheredLODTransitions(InComponent->SupportsDitheredLODTransitions())
  1030. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1031.         , CaptureTag(0)
  1032. #endif
  1033.     {
  1034.         check(!bInIsGrass || (!InComponent->InstanceReorderTable.Num() && !InComponent->PerInstanceSMData.Num()));
  1035.         SetupOcclusion(InComponent);
  1036.     }
  1037.  
  1038.     void SetupOcclusion(Ufixed_HI_StaticMeshComponent* InComponent)
  1039.     {
  1040.         FirstOcclusionNode = 0;
  1041.         LastOcclusionNode = 0;
  1042.         if (ClusterTree.Num() && InComponent->OcclusionLayerNumNodes)
  1043.         {
  1044.             while (true)
  1045.             {
  1046.                 int32 NextFirstOcclusionNode = ClusterTree[FirstOcclusionNode].FirstChild;
  1047.                 int32 NextLastOcclusionNode = ClusterTree[LastOcclusionNode].LastChild;
  1048.  
  1049.                 if (NextFirstOcclusionNode < 0 || NextLastOcclusionNode < 0)
  1050.                 {
  1051.                     break;
  1052.                 }
  1053.                 int32 NumNodes = 1 + NextLastOcclusionNode - NextFirstOcclusionNode;
  1054.                 if (NumNodes > InComponent->OcclusionLayerNumNodes)
  1055.                 {
  1056.                     break;
  1057.                 }
  1058.                 FirstOcclusionNode = NextFirstOcclusionNode;
  1059.                 LastOcclusionNode = NextLastOcclusionNode;
  1060.             }
  1061.         }
  1062.         int32 NumNodes = 1 + LastOcclusionNode - FirstOcclusionNode;
  1063.         if (NumNodes < 2)
  1064.         {
  1065.             FirstOcclusionNode = -1;
  1066.             LastOcclusionNode = -1;
  1067.             NumNodes = 0;
  1068.             if (ClusterTree.Num())
  1069.             {
  1070.                 //UE_LOG(LogTemp, Display, TEXT("No SubOcclusion %d inst"), 1 + ClusterTree[0].LastInstance - ClusterTree[0].FirstInstance);
  1071.             }
  1072.         }
  1073.         else
  1074.         {
  1075.             //int32 NumPerNode = (1 + ClusterTree[0].LastInstance - ClusterTree[0].FirstInstance) / NumNodes;
  1076.             //UE_LOG(LogTemp, Display, TEXT("Occlusion level %d   %d inst / node"), NumNodes, NumPerNode);
  1077.             OcclusionBounds.Reserve(NumNodes);
  1078.             FMatrix XForm = InComponent->ComponentToWorld.ToMatrixWithScale();
  1079.             for (int32 Index = FirstOcclusionNode; Index <= LastOcclusionNode; Index++)
  1080.             {
  1081.                 OcclusionBounds.Add(FBoxSphereBounds(FBox(ClusterTree[Index].BoundMin, ClusterTree[Index].BoundMax).TransformBy(XForm)));
  1082.             }
  1083.         }
  1084.     }
  1085.  
  1086.     // FPrimitiveSceneProxy interface.
  1087.  
  1088.     virtual void CreateRenderThreadResources() override
  1089.     {
  1090.         FInstancedStaticMeshSceneProxy::CreateRenderThreadResources();
  1091.         SceneProxyCreatedFrameNumberRenderThread = GFrameNumberRenderThread;
  1092.     }
  1093.  
  1094.     virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
  1095.     {
  1096.         FPrimitiveViewRelevance Result;
  1097.         if (bIsGrass ? View->Family->EngineShowFlags.InstancedGrass : View->Family->EngineShowFlags.InstancedFoliage)
  1098.         {
  1099.             Result = FStaticMeshSceneProxy::GetViewRelevance(View);
  1100.             Result.bDynamicRelevance = true;
  1101.             Result.bStaticRelevance = false;
  1102.         }
  1103.         return Result;
  1104.     }
  1105.  
  1106.     virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override;
  1107.  
  1108.     virtual const TArray<FBoxSphereBounds>* GetOcclusionQueries(const FSceneView* View) const override;
  1109.     virtual void AcceptOcclusionResults(const FSceneView* View, TArray<bool>* Results, int32 ResultsStart, int32 NumResults) override;
  1110.     virtual bool HasSubprimitiveOcclusionQueries() const override
  1111.     {
  1112.         return FirstOcclusionNode > 0;
  1113.     }
  1114.  
  1115.  
  1116.     virtual void DrawStaticElements(FStaticPrimitiveDrawInterface* PDI) override
  1117.     {
  1118.     }
  1119.  
  1120.     void FillDynamicMeshElements(FMeshElementCollector& Collector, const FFoliageElementParams& ElementParams, const FFoliageRenderInstanceParams& Instances) const;
  1121.  
  1122.     template<bool TUseVector>
  1123.     void Traverse(const FFoliageCullInstanceParams& Params, int32 Index, int32 MinLOD, int32 MaxLOD, bool bFullyContained = false) const;
  1124. };
  1125.  
  1126. struct FFoliageRenderInstanceParams
  1127. {
  1128.     bool bNeedsSingleLODRuns;
  1129.     bool bNeedsMultipleLODRuns;
  1130.     bool bOverestimate;
  1131.     mutable TArray<uint32, SceneRenderingAllocator> MultipleLODRuns[MAX_STATIC_MESH_LODS];
  1132.     mutable TArray<uint32, SceneRenderingAllocator> SingleLODRuns[MAX_STATIC_MESH_LODS];
  1133.     mutable int32 TotalSingleLODInstances[MAX_STATIC_MESH_LODS];
  1134.     mutable int32 TotalMultipleLODInstances[MAX_STATIC_MESH_LODS];
  1135.  
  1136.     FFoliageRenderInstanceParams(bool InbNeedsSingleLODRuns, bool InbNeedsMultipleLODRuns, bool InbOverestimate)
  1137.         : bNeedsSingleLODRuns(InbNeedsSingleLODRuns)
  1138.         , bNeedsMultipleLODRuns(InbNeedsMultipleLODRuns)
  1139.         , bOverestimate(InbOverestimate)
  1140.     {
  1141.         for (int32 Index = 0; Index < MAX_STATIC_MESH_LODS; Index++)
  1142.         {
  1143.             TotalSingleLODInstances[Index] = 0;
  1144.             TotalMultipleLODInstances[Index] = 0;
  1145.         }
  1146.     }
  1147.     static FORCEINLINE_DEBUGGABLE void AddRun(TArray<uint32, SceneRenderingAllocator>& Array, int32 FirstInstance, int32 LastInstance)
  1148.     {
  1149.         if (Array.Num() && Array.Last() + 1 == FirstInstance)
  1150.         {
  1151.             Array.Last() = (uint32)LastInstance;
  1152.         }
  1153.         else
  1154.         {
  1155.             Array.Add((uint32)FirstInstance);
  1156.             Array.Add((uint32)LastInstance);
  1157.         }
  1158.     }
  1159.     FORCEINLINE_DEBUGGABLE void AddRun(int32 MinLod, int32 MaxLod, int32 FirstInstance, int32 LastInstance) const
  1160.     {
  1161.         if (bNeedsSingleLODRuns)
  1162.         {
  1163.             AddRun(SingleLODRuns[bOverestimate ? MaxLod : MinLod], FirstInstance, LastInstance);
  1164.             TotalSingleLODInstances[bOverestimate ? MaxLod : MinLod] += 1 + LastInstance - FirstInstance;
  1165.         }
  1166.         if (bNeedsMultipleLODRuns)
  1167.         {
  1168.             for (int32 Lod = MinLod; Lod <= MaxLod; Lod++)
  1169.             {
  1170.                 TotalMultipleLODInstances[Lod] += 1 + LastInstance - FirstInstance;
  1171.                 AddRun(MultipleLODRuns[Lod], FirstInstance, LastInstance);
  1172.             }
  1173.         }
  1174.     }
  1175.  
  1176.     FORCEINLINE_DEBUGGABLE void AddRun(int32 MinLod, int32 MaxLod, const FFixed_ClusterNode& Node) const
  1177.     {
  1178.         AddRun(MinLod, MaxLod, Node.FirstInstance, Node.LastInstance);
  1179.     }
  1180. };
  1181.  
  1182. struct FFoliageCullInstanceParams : public FFoliageRenderInstanceParams
  1183. {
  1184.     FConvexVolume ViewFrustumLocal;
  1185.     int32 MinInstancesToSplit[MAX_STATIC_MESH_LODS];
  1186.     const TArray<FFixed_ClusterNode>& Tree;
  1187.     const FSceneView* View;
  1188.     FVector ViewOriginInLocalZero;
  1189.     FVector ViewOriginInLocalOne;
  1190.     int32 LODs;
  1191.     float LODPlanesMax[MAX_STATIC_MESH_LODS];
  1192.     float LODPlanesMin[MAX_STATIC_MESH_LODS];
  1193.     int32 FirstOcclusionNode;
  1194.     int32 LastOcclusionNode;
  1195.     TArray<bool>* OcclusionResults;
  1196.     int32 OcclusionResultsStart;
  1197.  
  1198.  
  1199.  
  1200.     FFoliageCullInstanceParams(bool InbNeedsSingleLODRuns, bool InbNeedsMultipleLODRuns, bool InbOverestimate, const TArray<FFixed_ClusterNode>& InTree)
  1201.         : FFoliageRenderInstanceParams(InbNeedsSingleLODRuns, InbNeedsMultipleLODRuns, InbOverestimate)
  1202.         , Tree(InTree)
  1203.         , FirstOcclusionNode(-1)
  1204.         , LastOcclusionNode(-1)
  1205.         , OcclusionResults(nullptr)
  1206.         , OcclusionResultsStart(0)
  1207.     {
  1208.     }
  1209. };
  1210.  
  1211. static bool GUseVectorCull = true;
  1212.  
  1213. static void ToggleUseVectorCull(const TArray<FString>& Args)
  1214. {
  1215.     GUseVectorCull = !GUseVectorCull;
  1216. }
  1217.  
  1218. static FAutoConsoleCommand ToggleUseVectorCullCmd(
  1219.     TEXT("foliage.ToggleVectorCull"),
  1220.     TEXT("Useful for debugging. Toggles the optimized cull."),
  1221.     FConsoleCommandWithArgsDelegate::CreateStatic(&ToggleUseVectorCull)
  1222. );
  1223.  
  1224. static uint32 GFrameNumberRenderThread_CaptureFoliageRuns = MAX_uint32;
  1225.  
  1226. static void LogFoliageFrame(const TArray<FString>& Args)
  1227. {
  1228.     GFrameNumberRenderThread_CaptureFoliageRuns = GFrameNumberRenderThread + 2;
  1229. }
  1230.  
  1231. static FAutoConsoleCommand LogFoliageFrameCmd(
  1232.     TEXT("foliage.LogFoliageFrame"),
  1233.     TEXT("Useful for debugging. Logs all foliage rendered in a frame."),
  1234.     FConsoleCommandWithArgsDelegate::CreateStatic(&LogFoliageFrame)
  1235. );
  1236.  
  1237. const VectorRegister        VECTOR_HALF_HALF_HALF_ZERO = DECLARE_VECTOR_REGISTER(0.5f, 0.5f, 0.5f, 0.0f);
  1238.  
  1239. template<bool TUseVector>
  1240. static FORCEINLINE_DEBUGGABLE bool CullNode(const FFoliageCullInstanceParams& Params, const FFixed_ClusterNode& Node, bool& bOutFullyContained)
  1241. {
  1242.     if (TUseVector)
  1243.     {
  1244.         checkSlow(Params.ViewFrustumLocal.PermutedPlanes.Num() == 4);
  1245.  
  1246.         //@todo, once we have more than one mesh per tree, these should be aligned
  1247.         VectorRegister BoxMin = VectorLoadFloat3(&Node.BoundMin);
  1248.         VectorRegister BoxMax = VectorLoadFloat3(&Node.BoundMax);
  1249.  
  1250.         VectorRegister BoxDiff = VectorSubtract(BoxMax, BoxMin);
  1251.         VectorRegister BoxSum = VectorAdd(BoxMax, BoxMin);
  1252.  
  1253.         // Load the origin & extent
  1254.         VectorRegister Orig = VectorMultiply(VECTOR_HALF_HALF_HALF_ZERO, BoxSum);
  1255.         VectorRegister Ext = VectorMultiply(VECTOR_HALF_HALF_HALF_ZERO, BoxDiff);
  1256.         // Splat origin into 3 vectors
  1257.         VectorRegister OrigX = VectorReplicate(Orig, 0);
  1258.         VectorRegister OrigY = VectorReplicate(Orig, 1);
  1259.         VectorRegister OrigZ = VectorReplicate(Orig, 2);
  1260.         // Splat the abs for the pushout calculation
  1261.         VectorRegister AbsExtentX = VectorReplicate(Ext, 0);
  1262.         VectorRegister AbsExtentY = VectorReplicate(Ext, 1);
  1263.         VectorRegister AbsExtentZ = VectorReplicate(Ext, 2);
  1264.         // Since we are moving straight through get a pointer to the data
  1265.         const FPlane* RESTRICT PermutedPlanePtr = (FPlane*)Params.ViewFrustumLocal.PermutedPlanes.GetData();
  1266.         // Process four planes at a time until we have < 4 left
  1267.         // Load 4 planes that are already all Xs, Ys, ...
  1268.         VectorRegister PlanesX = VectorLoadAligned(PermutedPlanePtr);
  1269.         PermutedPlanePtr++;
  1270.         VectorRegister PlanesY = VectorLoadAligned(PermutedPlanePtr);
  1271.         PermutedPlanePtr++;
  1272.         VectorRegister PlanesZ = VectorLoadAligned(PermutedPlanePtr);
  1273.         PermutedPlanePtr++;
  1274.         VectorRegister PlanesW = VectorLoadAligned(PermutedPlanePtr);
  1275.         PermutedPlanePtr++;
  1276.         // Calculate the distance (x * x) + (y * y) + (z * z) - w
  1277.         VectorRegister DistX = VectorMultiply(OrigX, PlanesX);
  1278.         VectorRegister DistY = VectorMultiplyAdd(OrigY, PlanesY, DistX);
  1279.         VectorRegister DistZ = VectorMultiplyAdd(OrigZ, PlanesZ, DistY);
  1280.         VectorRegister Distance = VectorSubtract(DistZ, PlanesW);
  1281.         // Now do the push out FMath::Abs(x * x) + FMath::Abs(y * y) + FMath::Abs(z * z)
  1282.         VectorRegister PushX = VectorMultiply(AbsExtentX, VectorAbs(PlanesX));
  1283.         VectorRegister PushY = VectorMultiplyAdd(AbsExtentY, VectorAbs(PlanesY), PushX);
  1284.         VectorRegister PushOut = VectorMultiplyAdd(AbsExtentZ, VectorAbs(PlanesZ), PushY);
  1285.         VectorRegister PushOutNegative = VectorNegate(PushOut);
  1286.  
  1287.         bOutFullyContained = !VectorAnyGreaterThan(Distance, PushOutNegative);
  1288.         // Check for completely outside
  1289.         return !!VectorAnyGreaterThan(Distance, PushOut);
  1290.     }
  1291.     FVector Center = (Node.BoundMin + Node.BoundMax) * 0.5f;
  1292.     FVector Extent = (Node.BoundMax - Node.BoundMin) * 0.5f;
  1293.     if (!Params.ViewFrustumLocal.IntersectBox(Center, Extent, bOutFullyContained))
  1294.     {
  1295.         return true;
  1296.     }
  1297.     return false;
  1298. }
  1299.  
  1300. inline void CalcLOD(int32& InOutMinLOD, int32& InOutMaxLOD, const FVector& BoundMin, const FVector& BoundMax, const FVector& ViewOriginInLocalZero, const FVector& ViewOriginInLocalOne, const float LODPlanesMin[], const float LODPlanesMax[])
  1301. {
  1302.     if (InOutMinLOD != InOutMaxLOD)
  1303.     {
  1304.         const FVector Center = (BoundMax + BoundMin) * 0.5f;
  1305.         const float DistCenterZero = FVector::Dist(Center, ViewOriginInLocalZero);
  1306.         const float DistCenterOne = FVector::Dist(Center, ViewOriginInLocalOne);
  1307.         const float HalfWidth = FVector::Dist(BoundMax, BoundMin) * 0.5f;
  1308.         const float NearDot = FMath::Min(DistCenterZero, DistCenterOne) - HalfWidth;
  1309.         const float FarDot = FMath::Max(DistCenterZero, DistCenterOne) + HalfWidth;
  1310.  
  1311.         while (InOutMaxLOD > InOutMinLOD && NearDot > LODPlanesMax[InOutMinLOD])
  1312.         {
  1313.             InOutMinLOD++;
  1314.         }
  1315.         while (InOutMaxLOD > InOutMinLOD && FarDot < LODPlanesMin[InOutMaxLOD - 1])
  1316.         {
  1317.             InOutMaxLOD--;
  1318.         }
  1319.     }
  1320. }
  1321.  
  1322. template<bool TUseVector>
  1323. void FHierarchicalStaticMeshSceneProxy::Traverse(const FFoliageCullInstanceParams& Params, int32 Index, int32 MinLOD, int32 MaxLOD, bool bFullyContained) const
  1324. {
  1325.     const FFixed_ClusterNode& Node = Params.Tree[Index];
  1326.     if (!bFullyContained)
  1327.     {
  1328.         if (CullNode<TUseVector>(Params, Node, bFullyContained))
  1329.         {
  1330.             return;
  1331.         }
  1332.     }
  1333.  
  1334.     if (MinLOD != MaxLOD)
  1335.     {
  1336.         CalcLOD(MinLOD, MaxLOD, Node.BoundMin, Node.BoundMax, Params.ViewOriginInLocalZero, Params.ViewOriginInLocalOne, Params.LODPlanesMin, Params.LODPlanesMax);
  1337.  
  1338.         if (MinLOD >= Params.LODs)
  1339.         {
  1340.             return;
  1341.         }
  1342.     }
  1343.     if (Index >= Params.FirstOcclusionNode && Index <= Params.LastOcclusionNode)
  1344.     {
  1345.         check(Params.OcclusionResults != NULL);
  1346.         TArray<bool>& OcclusionResultsArray = *Params.OcclusionResults;
  1347.         if (OcclusionResultsArray[Params.OcclusionResultsStart + Index - Params.FirstOcclusionNode])
  1348.         {
  1349.             INC_DWORD_STAT_BY(STAT_OcclusionCulledFoliageInstances, 1 + Node.LastInstance - Node.FirstInstance);
  1350.             return;
  1351.         }
  1352.     }
  1353.  
  1354.     bool bSplit = (!bFullyContained || MinLOD < MaxLOD || Index < Params.FirstOcclusionNode)
  1355.         && Node.FirstChild >= 0
  1356.         && (1 + Node.LastInstance - Node.FirstInstance) >= Params.MinInstancesToSplit[MinLOD];
  1357.  
  1358.     if (!bSplit)
  1359.     {
  1360.         MaxLOD = FMath::Min(MaxLOD, Params.LODs - 1);
  1361.         Params.AddRun(MinLOD, MaxLOD, Node);
  1362.         return;
  1363.     }
  1364.     for (int32 ChildIndex = Node.FirstChild; ChildIndex <= Node.LastChild; ChildIndex++)
  1365.     {
  1366.         Traverse<TUseVector>(Params, ChildIndex, MinLOD, MaxLOD, bFullyContained);
  1367.     }
  1368. }
  1369.  
  1370. struct FFoliageElementParams
  1371. {
  1372.     const FInstancingUserData* PassUserData[2];
  1373.     int32 NumSelectionGroups;
  1374.     const FSceneView* View;
  1375.     int32 ViewIndex;
  1376.     bool bSelectionRenderEnabled;
  1377.     bool BatchRenderSelection[2];
  1378.     bool bIsWireframe;
  1379.     bool bUseHoveredMaterial;
  1380.     bool bInstanced;
  1381.     bool bBlendLODs;
  1382.     ERHIFeatureLevel::Type FeatureLevel;
  1383.     bool ShadowFrustum;
  1384.     float FinalCullDistance;
  1385. };
  1386.  
  1387. void FHierarchicalStaticMeshSceneProxy::FillDynamicMeshElements(FMeshElementCollector& Collector, const FFoliageElementParams& ElementParams, const FFoliageRenderInstanceParams& Params) const
  1388. {
  1389.     SCOPE_CYCLE_COUNTER(STAT_FoliageBatchTime);
  1390.     int64 TotalTriangles = 0;
  1391.  
  1392.     int32 OnlyLOD = FMath::Min<int32>(CVarOnlyLOD.GetValueOnRenderThread(), InstancedRenderData.VertexFactories.Num() - 1);
  1393.     int32 FirstLOD = (OnlyLOD < 0) ? 0 : OnlyLOD;
  1394.     int32 LastLODPlusOne = (OnlyLOD < 0) ? InstancedRenderData.VertexFactories.Num() : (OnlyLOD + 1);
  1395.  
  1396.     for (int32 LODIndex = FirstLOD; LODIndex < LastLODPlusOne; LODIndex++)
  1397.     {
  1398.         const FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[LODIndex];
  1399.  
  1400.         for (int32 SelectionGroupIndex = 0; SelectionGroupIndex < ElementParams.NumSelectionGroups; SelectionGroupIndex++)
  1401.         {
  1402.             for (int32 SectionIndex = 0; SectionIndex < LODModel.Sections.Num(); SectionIndex++)
  1403.             {
  1404.                 const FLODInfo& ProxyLODInfo = LODs[LODIndex];
  1405.                 UMaterialInterface* Material = ProxyLODInfo.Sections[SectionIndex].Material;
  1406.                 const bool bDitherLODEnabled = ElementParams.bBlendLODs;
  1407.  
  1408.                 TArray<uint32, SceneRenderingAllocator>& RunArray = bDitherLODEnabled ? Params.MultipleLODRuns[LODIndex] : Params.SingleLODRuns[LODIndex];
  1409.  
  1410.                 if (!RunArray.Num())
  1411.                 {
  1412.                     continue;
  1413.                 }
  1414.  
  1415.                 int32 NumBatches = 1;
  1416.                 int32 CurrentRun = 0;
  1417.                 int32 CurrentInstance = 0;
  1418.                 int32 RemainingInstances = bDitherLODEnabled ? Params.TotalMultipleLODInstances[LODIndex] : Params.TotalSingleLODInstances[LODIndex];
  1419.  
  1420.                 if (!ElementParams.bInstanced)
  1421.                 {
  1422.                     NumBatches = FMath::DivideAndRoundUp(RemainingInstances, (int32)FInstancedStaticMeshVertexFactory::NumBitsForVisibilityMask());
  1423.                     if (NumBatches)
  1424.                     {
  1425.                         check(RunArray.Num());
  1426.                         CurrentInstance = RunArray[CurrentRun];
  1427.                     }
  1428.                 }
  1429.  
  1430. #if STATS
  1431.                 INC_DWORD_STAT_BY(STAT_FoliageInstances, RemainingInstances);
  1432.                 if (!ElementParams.bInstanced)
  1433.                 {
  1434.                     INC_DWORD_STAT_BY(STAT_FoliageRuns, NumBatches);
  1435.                 }
  1436. #endif
  1437.                 bool bDidStats = false;
  1438.                 for (int32 BatchIndex = 0; BatchIndex < NumBatches; BatchIndex++)
  1439.                 {
  1440.                     FMeshBatch& MeshElement = Collector.AllocateMesh();
  1441.                     INC_DWORD_STAT(STAT_FoliageMeshBatches);
  1442.  
  1443.                     if (!FStaticMeshSceneProxy::GetMeshElement(LODIndex, 0, SectionIndex, GetDepthPriorityGroup(ElementParams.View), ElementParams.BatchRenderSelection[SelectionGroupIndex], ElementParams.bUseHoveredMaterial, true, MeshElement))
  1444.                     {
  1445.                         continue;
  1446.                     }
  1447.                     checkSlow(MeshElement.GetNumPrimitives() > 0);
  1448.  
  1449.                     MeshElement.VertexFactory = &InstancedRenderData.VertexFactories[LODIndex];
  1450.                     FMeshBatchElement& BatchElement0 = MeshElement.Elements[0];
  1451.  
  1452.                     BatchElement0.UserData = ElementParams.PassUserData[SelectionGroupIndex];
  1453.                     BatchElement0.bUserDataIsColorVertexBuffer = false;
  1454.                     BatchElement0.MaxScreenSize = 1.0;
  1455.                     BatchElement0.MinScreenSize = 0.0;
  1456.                     BatchElement0.InstancedLODIndex = LODIndex;
  1457.                     BatchElement0.InstancedLODRange = bDitherLODEnabled ? 1 : 0;
  1458.                     BatchElement0.bIsInstancedMesh = true;
  1459.                     MeshElement.bCanApplyViewModeOverrides = true;
  1460.                     MeshElement.bUseSelectionOutline = ElementParams.BatchRenderSelection[SelectionGroupIndex];
  1461.                     MeshElement.bUseWireframeSelectionColoring = ElementParams.BatchRenderSelection[SelectionGroupIndex];
  1462.                     MeshElement.bUseAsOccluder = ShouldUseAsOccluder();
  1463.  
  1464.                     if (!bDidStats)
  1465.                     {
  1466.                         bDidStats = true;
  1467.                         int64 Tris = int64(RemainingInstances) * int64(BatchElement0.NumPrimitives);
  1468.                         TotalTriangles += Tris;
  1469. #if STATS
  1470.                         if (GFrameNumberRenderThread_CaptureFoliageRuns == GFrameNumberRenderThread)
  1471.                         {
  1472.                             if (ElementParams.FinalCullDistance > 9.9E8)
  1473.                             {
  1474.                                 UE_LOG(LogStaticMesh, Display, TEXT("lod:%1d/%1d   sel:%1d   section:%1d/%1d   runs:%4d   inst:%8d   tris:%9lld   cast shadow:%1d   cull:-NONE!!-   shadow:%1d     %s %s"),
  1475.                                     LODIndex, InstancedRenderData.VertexFactories.Num(), SelectionGroupIndex, SectionIndex, LODModel.Sections.Num(), RunArray.Num() / 2,
  1476.                                     RemainingInstances, Tris, (int)MeshElement.CastShadow, ElementParams.ShadowFrustum,
  1477.                                     *StaticMesh->GetPathName(),
  1478.                                     *MeshElement.MaterialRenderProxy->GetMaterial(ElementParams.FeatureLevel)->GetFriendlyName());
  1479.                             }
  1480.                             else
  1481.                             {
  1482.                                 UE_LOG(LogStaticMesh, Display, TEXT("lod:%1d/%1d   sel:%1d   section:%1d/%1d   runs:%4d   inst:%8d   tris:%9lld   cast shadow:%1d   cull:%8.0f   shadow:%1d     %s %s"),
  1483.                                     LODIndex, InstancedRenderData.VertexFactories.Num(), SelectionGroupIndex, SectionIndex, LODModel.Sections.Num(), RunArray.Num() / 2,
  1484.                                     RemainingInstances, Tris, (int)MeshElement.CastShadow, ElementParams.FinalCullDistance, ElementParams.ShadowFrustum,
  1485.                                     *StaticMesh->GetPathName(),
  1486.                                     *MeshElement.MaterialRenderProxy->GetMaterial(ElementParams.FeatureLevel)->GetFriendlyName());
  1487.                             }
  1488.                         }
  1489. #endif
  1490.                     }
  1491.                     if (ElementParams.bInstanced)
  1492.                     {
  1493.                         BatchElement0.NumInstances = RunArray.Num() / 2;
  1494.                         BatchElement0.InstanceRuns = &RunArray[0];
  1495.                         BatchElement0.bIsInstanceRuns = true;
  1496. #if STATS
  1497.                         INC_DWORD_STAT_BY(STAT_FoliageRuns, BatchElement0.NumInstances);
  1498. #endif
  1499.                     }
  1500.                     else
  1501.                     {
  1502.                         uint32 NumInstancesThisBatch = FMath::Min(RemainingInstances, (int32)FInstancedStaticMeshVertexFactory::NumBitsForVisibilityMask());
  1503.  
  1504.                         MeshElement.Elements.Reserve(NumInstancesThisBatch);
  1505.                         check(NumInstancesThisBatch);
  1506.  
  1507.                         for (uint32 Instance = 0; Instance < NumInstancesThisBatch; ++Instance)
  1508.                         {
  1509.                             FMeshBatchElement* NewBatchElement;
  1510.  
  1511.                             if (Instance == 0)
  1512.                             {
  1513.                                 NewBatchElement = &MeshElement.Elements[0];
  1514.                             }
  1515.                             else
  1516.                             {
  1517.                                 NewBatchElement = new(MeshElement.Elements) FMeshBatchElement();
  1518.                                 *NewBatchElement = MeshElement.Elements[0];
  1519.                             }
  1520.  
  1521.                             NewBatchElement->UserIndex = CurrentInstance;
  1522.                             if (--RemainingInstances)
  1523.                             {
  1524.                                 if ((uint32)CurrentInstance >= RunArray[CurrentRun + 1])
  1525.                                 {
  1526.                                     CurrentRun += 2;
  1527.                                     check(CurrentRun + 1 < RunArray.Num());
  1528.                                     CurrentInstance = RunArray[CurrentRun];
  1529.                                 }
  1530.                                 else
  1531.                                 {
  1532.                                     CurrentInstance++;
  1533.                                 }
  1534.                             }
  1535.                         }
  1536.                     }
  1537.                     if (TotalTriangles < (int64)CVarMaxTrianglesToRender.GetValueOnRenderThread())
  1538.                     {
  1539.                         Collector.AddMesh(ElementParams.ViewIndex, MeshElement);
  1540.                     }
  1541.                 }
  1542.             }
  1543.         }
  1544.     }
  1545. #if STATS
  1546.     TotalTriangles = FMath::Min<int64>(TotalTriangles, MAX_int32);
  1547.     INC_DWORD_STAT_BY(STAT_FoliageTriangles, (uint32)TotalTriangles);
  1548.     INC_DWORD_STAT_BY(STAT_StaticMeshTriangles, (uint32)TotalTriangles);
  1549. #endif
  1550. }
  1551.  
  1552. void FHierarchicalStaticMeshSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
  1553. {
  1554.     if (Views[0]->bRenderFirstInstanceOnly)
  1555.     {
  1556.         FInstancedStaticMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector);
  1557.         return;
  1558.     }
  1559.  
  1560.     QUICK_SCOPE_CYCLE_COUNTER(STAT_HierarchicalInstancedStaticMeshSceneProxy_GetMeshElements);
  1561.  
  1562.     bool bMultipleSections = ALLOW_DITHERED_LOD_FOR_INSTANCED_STATIC_MESHES && bDitheredLODTransitions && CVarDitheredLOD.GetValueOnRenderThread() > 0;
  1563.     bool bSingleSections = !bMultipleSections;
  1564.     bool bOverestimate = CVarOverestimateLOD.GetValueOnRenderThread() > 0;
  1565.  
  1566.     int32 MinVertsToSplitNode = CVarMinVertsToSplitNode.GetValueOnRenderThread();
  1567.  
  1568.     for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
  1569.     {
  1570.         if (VisibilityMap & (1 << ViewIndex))
  1571.         {
  1572.             const FSceneView* View = Views[ViewIndex];
  1573.  
  1574.             FFoliageElementParams ElementParams;
  1575.             ElementParams.bSelectionRenderEnabled = GIsEditor && ViewFamily.EngineShowFlags.Selection;
  1576.             ElementParams.NumSelectionGroups = (ElementParams.bSelectionRenderEnabled && bHasSelectedInstances) ? 2 : 1;
  1577.             ElementParams.PassUserData[0] = bHasSelectedInstances && ElementParams.bSelectionRenderEnabled ? &UserData_SelectedInstances : &UserData_AllInstances;
  1578.             ElementParams.PassUserData[1] = &UserData_DeselectedInstances;
  1579.             ElementParams.BatchRenderSelection[0] = ElementParams.bSelectionRenderEnabled && IsSelected();
  1580.             ElementParams.BatchRenderSelection[1] = false;
  1581.             ElementParams.bIsWireframe = ViewFamily.EngineShowFlags.Wireframe;
  1582.             ElementParams.bUseHoveredMaterial = IsHovered();
  1583.             ElementParams.bInstanced = GRHISupportsInstancing;
  1584.             ElementParams.FeatureLevel = InstancedRenderData.FeatureLevel;
  1585.             ElementParams.ViewIndex = ViewIndex;
  1586.             ElementParams.View = View;
  1587.  
  1588.             // Render built instances
  1589.             if (ClusterTree.Num())
  1590.             {
  1591.  
  1592.                 FFoliageCullInstanceParams InstanceParams(bSingleSections, bMultipleSections, bOverestimate, ClusterTree);
  1593.                 InstanceParams.LODs = RenderData->LODResources.Num();
  1594.  
  1595.                 InstanceParams.View = View;
  1596.  
  1597.                 FMatrix WorldToLocal = GetLocalToWorld().Inverse();
  1598.                 bool bUseVectorCull = GUseVectorCull;
  1599.                 bool bIsOrtho = false;
  1600.  
  1601.                 bool bDisableCull = !!CVarDisableCull.GetValueOnRenderThread();
  1602.                 ElementParams.ShadowFrustum = !!View->GetDynamicMeshElementsShadowCullFrustum();
  1603.                 if (View->GetDynamicMeshElementsShadowCullFrustum())
  1604.                 {
  1605.                     for (int32 Index = 0; Index < View->GetDynamicMeshElementsShadowCullFrustum()->Planes.Num(); Index++)
  1606.                     {
  1607.                         FPlane Src = View->GetDynamicMeshElementsShadowCullFrustum()->Planes[Index];
  1608.                         FPlane Norm = Src / Src.Size();
  1609.                         // remove world space preview translation
  1610.                         Norm.W -= (FVector(Norm) | View->GetPreShadowTranslation());
  1611.                         FPlane Local = Norm.TransformBy(WorldToLocal);
  1612.                         FPlane LocalNorm = Local / Local.Size();
  1613.                         InstanceParams.ViewFrustumLocal.Planes.Add(LocalNorm);
  1614.                     }
  1615.                     bUseVectorCull = InstanceParams.ViewFrustumLocal.Planes.Num() == 4;
  1616.                 }
  1617.                 else
  1618.                 {
  1619.                     // Instanced stereo needs to use the right plane from the right eye when constructing the frustum bounds to cull against.
  1620.                     // Otherwise we'll cull objects visible in the right eye, but not the left.
  1621.                     if (Views[0]->IsInstancedStereoPass() && ViewIndex == 0)
  1622.                     {
  1623.                         check(Views.Num() == 2);
  1624.  
  1625.                         const FMatrix LeftEyeLocalViewProjForCulling = GetLocalToWorld() * Views[0]->ViewMatrices.GetViewProjectionMatrix();
  1626.                         const FMatrix RightEyeLocalViewProjForCulling = GetLocalToWorld() * Views[1]->ViewMatrices.GetViewProjectionMatrix();
  1627.  
  1628.                         FConvexVolume LeftEyeBounds, RightEyeBounds;
  1629.                         GetViewFrustumBounds(LeftEyeBounds, LeftEyeLocalViewProjForCulling, false);
  1630.                         GetViewFrustumBounds(RightEyeBounds, RightEyeLocalViewProjForCulling, false);
  1631.  
  1632.                         InstanceParams.ViewFrustumLocal.Planes.Empty(5);
  1633.                         InstanceParams.ViewFrustumLocal.Planes.Add(LeftEyeBounds.Planes[0]);
  1634.                         InstanceParams.ViewFrustumLocal.Planes.Add(RightEyeBounds.Planes[1]);
  1635.                         InstanceParams.ViewFrustumLocal.Planes.Add(LeftEyeBounds.Planes[2]);
  1636.                         InstanceParams.ViewFrustumLocal.Planes.Add(LeftEyeBounds.Planes[3]);
  1637.                         InstanceParams.ViewFrustumLocal.Planes.Add(LeftEyeBounds.Planes[4]);
  1638.                         InstanceParams.ViewFrustumLocal.Init();
  1639.                     }
  1640.                     else
  1641.                     {
  1642.                         const FMatrix LocalViewProjForCulling = GetLocalToWorld() * View->ViewMatrices.GetViewProjectionMatrix();
  1643.                         GetViewFrustumBounds(InstanceParams.ViewFrustumLocal, LocalViewProjForCulling, false);
  1644.                     }
  1645.  
  1646.                     if (View->ViewMatrices.IsPerspectiveProjection())
  1647.                     {
  1648.                         if (InstanceParams.ViewFrustumLocal.Planes.Num() == 5)
  1649.                         {
  1650.                             InstanceParams.ViewFrustumLocal.Planes.Pop(false); // we don't want the far plane either
  1651.                             FMatrix ThreePlanes;
  1652.                             ThreePlanes.SetIdentity();
  1653.                             ThreePlanes.SetAxes(&InstanceParams.ViewFrustumLocal.Planes[0], &InstanceParams.ViewFrustumLocal.Planes[1], &InstanceParams.ViewFrustumLocal.Planes[2]);
  1654.                             FVector ProjectionOrigin = ThreePlanes.Inverse().GetTransposed().TransformVector(FVector(InstanceParams.ViewFrustumLocal.Planes[0].W, InstanceParams.ViewFrustumLocal.Planes[1].W, InstanceParams.ViewFrustumLocal.Planes[2].W));
  1655.  
  1656.                             for (int32 Index = 0; Index < InstanceParams.ViewFrustumLocal.Planes.Num(); Index++)
  1657.                             {
  1658.                                 FPlane Src = InstanceParams.ViewFrustumLocal.Planes[Index];
  1659.                                 FVector Normal = Src.GetSafeNormal();
  1660.                                 InstanceParams.ViewFrustumLocal.Planes[Index] = FPlane(Normal, Normal | ProjectionOrigin);
  1661.                             }
  1662.                         }
  1663.                         else
  1664.                         {
  1665.                             // zero scaling or something, cull everything
  1666.                             continue;
  1667.                         }
  1668.                     }
  1669.                     else
  1670.                     {
  1671.                         bIsOrtho = true;
  1672.                         bUseVectorCull = false;
  1673.                     }
  1674.                 }
  1675.                 if (!InstanceParams.ViewFrustumLocal.Planes.Num())
  1676.                 {
  1677.                     bDisableCull = true;
  1678.                 }
  1679.                 else
  1680.                 {
  1681.                     InstanceParams.ViewFrustumLocal.Init();
  1682.                 }
  1683.  
  1684.                 ElementParams.bBlendLODs = bMultipleSections;
  1685.  
  1686.                 InstanceParams.ViewOriginInLocalZero = WorldToLocal.TransformPosition(View->GetTemporalLODOrigin(0, bMultipleSections));
  1687.                 InstanceParams.ViewOriginInLocalOne = WorldToLocal.TransformPosition(View->GetTemporalLODOrigin(1, bMultipleSections));
  1688.  
  1689.                 float MinSize = bIsOrtho ? 0.0f : CVarFoliageMinimumScreenSize.GetValueOnRenderThread();
  1690.                 float LODScale = CVarFoliageLODDistanceScale.GetValueOnRenderThread();
  1691.                 float LODRandom = CVarRandomLODRange.GetValueOnRenderThread();
  1692.                 float MaxDrawDistanceScale = GetCachedScalabilityCVars().ViewDistanceScale;
  1693.                 float SphereRadius = RenderData->Bounds.SphereRadius;
  1694.  
  1695.                 float FinalCull = MAX_flt;
  1696.                 if (MinSize > 0.0)
  1697.                 {
  1698.                     FinalCull = ComputeBoundsDrawDistance(MinSize, SphereRadius, View->ViewMatrices.GetProjectionMatrix()) * LODScale;
  1699.                 }
  1700.                 if (UserData_AllInstances.EndCullDistance > 0.0f)
  1701.                 {
  1702.                     FinalCull = FMath::Min(FinalCull, UserData_AllInstances.EndCullDistance * MaxDrawDistanceScale);
  1703.                 }
  1704.                 ElementParams.FinalCullDistance = FinalCull;
  1705.  
  1706.                 for (int32 LODIndex = 1; LODIndex < InstanceParams.LODs; LODIndex++)
  1707.                 {
  1708.                     float Distance = ComputeBoundsDrawDistance(RenderData->ScreenSize[LODIndex], SphereRadius, View->ViewMatrices.GetProjectionMatrix()) * LODScale;
  1709.                     InstanceParams.LODPlanesMin[LODIndex - 1] = Distance - LODRandom;
  1710.                     InstanceParams.LODPlanesMax[LODIndex - 1] = Distance;
  1711.                 }
  1712.                 InstanceParams.LODPlanesMin[InstanceParams.LODs - 1] = FinalCull - LODRandom;
  1713.                 InstanceParams.LODPlanesMax[InstanceParams.LODs - 1] = FinalCull;
  1714.  
  1715.                 for (int32 LODIndex = 0; LODIndex < InstanceParams.LODs; LODIndex++)
  1716.                 {
  1717.                     InstanceParams.MinInstancesToSplit[LODIndex] = 2;
  1718.                     int32 NumVerts = RenderData->LODResources[LODIndex].VertexBuffer.GetNumVertices();
  1719.                     if (NumVerts)
  1720.                     {
  1721.                         InstanceParams.MinInstancesToSplit[LODIndex] = MinVertsToSplitNode / NumVerts;
  1722.                     }
  1723.                 }
  1724.  
  1725.                 if (FirstOcclusionNode >= 0 && LastOcclusionNode >= 0 && FirstOcclusionNode <= LastOcclusionNode)
  1726.                 {
  1727.                     uint32 ViewId = View->GetViewKey();
  1728.                     const FFoliageOcclusionResults* OldResults = OcclusionResults.Find(ViewId);
  1729.                     if (OldResults &&
  1730.                         OldResults->FrameNumberRenderThread == GFrameNumberRenderThread &&
  1731.                         1 + LastOcclusionNode - FirstOcclusionNode == OldResults->NumResults &&
  1732.                         // OcclusionResultsArray[Params.OcclusionResultsStart + Index - Params.FirstOcclusionNode]
  1733.  
  1734.                         OldResults->Results->IsValidIndex(OldResults->ResultsStart) &&
  1735.                         OldResults->Results->IsValidIndex(OldResults->ResultsStart + LastOcclusionNode - FirstOcclusionNode)
  1736.                         )
  1737.                     {
  1738.                         InstanceParams.FirstOcclusionNode = FirstOcclusionNode;
  1739.                         InstanceParams.LastOcclusionNode = LastOcclusionNode;
  1740.                         InstanceParams.OcclusionResults = OldResults->Results;
  1741.                         InstanceParams.OcclusionResultsStart = OldResults->ResultsStart;
  1742.                     }
  1743.                 }
  1744.  
  1745.                 INC_DWORD_STAT(STAT_FoliageTraversals);
  1746. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1747.                 if (GCaptureDebugRuns == GDebugTag && CaptureTag == GDebugTag)
  1748.                 {
  1749.                     for (int32 LODIndex = 0; LODIndex < InstanceParams.LODs; LODIndex++)
  1750.                     {
  1751.                         for (int32 Run = 0; Run < SingleDebugRuns[LODIndex].Num(); Run++)
  1752.                         {
  1753.                             InstanceParams.SingleLODRuns[LODIndex].Add(SingleDebugRuns[LODIndex][Run]);
  1754.                         }
  1755.                         InstanceParams.TotalSingleLODInstances[LODIndex] = SingleDebugTotalInstances[LODIndex];
  1756.                         for (int32 Run = 0; Run < MultipleDebugRuns[LODIndex].Num(); Run++)
  1757.                         {
  1758.                             InstanceParams.MultipleLODRuns[LODIndex].Add(MultipleDebugRuns[LODIndex][Run]);
  1759.                         }
  1760.                         InstanceParams.TotalMultipleLODInstances[LODIndex] = MultipleDebugTotalInstances[LODIndex];
  1761.                     }
  1762.                 }
  1763.                 else
  1764. #endif
  1765.                 {
  1766.                     SCOPE_CYCLE_COUNTER(STAT_FoliageTraversalTime);
  1767.  
  1768.                     // validate that the bounding box is layed out correctly in memory
  1769.                     check(&((const FVector4*)&ClusterTree[0].BoundMin)[1] == (const FVector4*)&ClusterTree[0].BoundMax);
  1770.                     //check(UPTRINT(&ClusterTree[0].BoundMin) % 16 == 0);
  1771.                     //check(UPTRINT(&ClusterTree[0].BoundMax) % 16 == 0);
  1772.  
  1773.                     int32 UseMinLOD = ClampedMinLOD;
  1774.  
  1775.                     int32 DebugMin = FMath::Min(CVarMinLOD.GetValueOnRenderThread(), InstanceParams.LODs - 1);
  1776.                     if (DebugMin >= 0)
  1777.                     {
  1778.                         UseMinLOD = FMath::Max(UseMinLOD, DebugMin);
  1779.                     }
  1780.                     int32 UseMaxLOD = InstanceParams.LODs;
  1781.  
  1782.                     int32 Force = CVarForceLOD.GetValueOnRenderThread();
  1783.                     if (Force >= 0)
  1784.                     {
  1785.                         UseMinLOD = FMath::Clamp(Force, 0, InstanceParams.LODs - 1);
  1786.                         UseMaxLOD = FMath::Clamp(Force, 0, InstanceParams.LODs - 1);
  1787.                     }
  1788.  
  1789.                     if (CVarCullAll.GetValueOnRenderThread() < 1)
  1790.                     {
  1791.                         if (bUseVectorCull)
  1792.                         {
  1793.                             Traverse<true>(InstanceParams, 0, UseMinLOD, UseMaxLOD, bDisableCull);
  1794.                         }
  1795.                         else
  1796.                         {
  1797.                             Traverse<false>(InstanceParams, 0, UseMinLOD, UseMaxLOD, bDisableCull);
  1798.                         }
  1799.                     }
  1800. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  1801.                     if (GCaptureDebugRuns == GDebugTag && CaptureTag != GDebugTag)
  1802.                     {
  1803.                         CaptureTag = GDebugTag;
  1804.                         for (int32 LODIndex = 0; LODIndex < InstanceParams.LODs; LODIndex++)
  1805.                         {
  1806.                             SingleDebugRuns[LODIndex].Empty();
  1807.                             SingleDebugTotalInstances[LODIndex] = InstanceParams.TotalSingleLODInstances[LODIndex];
  1808.                             for (int32 Run = 0; Run < InstanceParams.SingleLODRuns[LODIndex].Num(); Run++)
  1809.                             {
  1810.                                 SingleDebugRuns[LODIndex].Add(InstanceParams.SingleLODRuns[LODIndex][Run]);
  1811.                             }
  1812.                             MultipleDebugRuns[LODIndex].Empty();
  1813.                             MultipleDebugTotalInstances[LODIndex] = InstanceParams.TotalMultipleLODInstances[LODIndex];
  1814.                             for (int32 Run = 0; Run < InstanceParams.MultipleLODRuns[LODIndex].Num(); Run++)
  1815.                             {
  1816.                                 MultipleDebugRuns[LODIndex].Add(InstanceParams.MultipleLODRuns[LODIndex][Run]);
  1817.                             }
  1818.                         }
  1819.                     }
  1820. #endif
  1821.                 }
  1822.  
  1823.                 FillDynamicMeshElements(Collector, ElementParams, InstanceParams);
  1824.             }
  1825.  
  1826.             // Render unbuilt instances
  1827.             if (FirstUnbuiltIndex <= LastUnbuiltIndex)
  1828.             {
  1829.                 FFoliageRenderInstanceParams InstanceParams(true, false, false);
  1830.  
  1831.                 // disable LOD blending for unbuilt instances as we haven't calculated the correct LOD.
  1832.                 ElementParams.bBlendLODs = false;
  1833.  
  1834.                 const int32 NumUnbuiltInstances = LastUnbuiltIndex - FirstUnbuiltIndex + 1;
  1835.                 if (NumUnbuiltInstances < 1000)
  1836.                 {
  1837.                     const int32 NumLODs = RenderData->LODResources.Num();
  1838.  
  1839.                     int32 Force = CVarForceLOD.GetValueOnRenderThread();
  1840.                     if (Force >= 0)
  1841.                     {
  1842.                         Force = FMath::Clamp(Force, 0, NumLODs - 1);
  1843.                         InstanceParams.AddRun(Force, Force, FirstUnbuiltIndex, LastUnbuiltIndex);
  1844.                     }
  1845.                     else
  1846.                     {
  1847.                         FMatrix WorldToLocal = GetLocalToWorld().Inverse();
  1848.                         FVector ViewOriginInLocalZero = WorldToLocal.TransformPosition(View->GetTemporalLODOrigin(0, bMultipleSections));
  1849.                         FVector ViewOriginInLocalOne = WorldToLocal.TransformPosition(View->GetTemporalLODOrigin(1, bMultipleSections));
  1850.                         float LODPlanesMax[MAX_STATIC_MESH_LODS];
  1851.                         float LODPlanesMin[MAX_STATIC_MESH_LODS];
  1852.  
  1853.                         const bool bIsOrtho = !View->ViewMatrices.IsPerspectiveProjection();
  1854.                         const float MinSize = bIsOrtho ? 0.0f : CVarFoliageMinimumScreenSize.GetValueOnRenderThread();
  1855.                         const float LODScale = CVarFoliageLODDistanceScale.GetValueOnRenderThread();
  1856.                         const float LODRandom = CVarRandomLODRange.GetValueOnRenderThread();
  1857.                         const float MaxDrawDistanceScale = GetCachedScalabilityCVars().ViewDistanceScale;
  1858.                         const float SphereRadius = RenderData->Bounds.SphereRadius;
  1859.  
  1860.                         checkSlow(NumLODs > 0);
  1861.  
  1862.                         float FinalCull = MAX_flt;
  1863.                         if (MinSize > 0.0)
  1864.                         {
  1865.                             FinalCull = ComputeBoundsDrawDistance(MinSize, SphereRadius, View->ViewMatrices.GetProjectionMatrix()) * LODScale;
  1866.                         }
  1867.                         if (UserData_AllInstances.EndCullDistance > 0.0f)
  1868.                         {
  1869.                             FinalCull = FMath::Min(FinalCull, UserData_AllInstances.EndCullDistance * MaxDrawDistanceScale);
  1870.                         }
  1871.                         ElementParams.FinalCullDistance = FinalCull;
  1872.  
  1873.                         for (int32 LODIndex = 1; LODIndex < NumLODs; LODIndex++)
  1874.                         {
  1875.                             float Distance = ComputeBoundsDrawDistance(RenderData->ScreenSize[LODIndex], SphereRadius, View->ViewMatrices.GetProjectionMatrix()) * LODScale;
  1876.                             LODPlanesMin[LODIndex - 1] = Distance - LODRandom;
  1877.                             LODPlanesMax[LODIndex - 1] = Distance;
  1878.                         }
  1879.                         LODPlanesMin[NumLODs - 1] = FinalCull - LODRandom;
  1880.                         LODPlanesMax[NumLODs - 1] = FinalCull;
  1881.  
  1882.                         // calculate runs
  1883.                         int32 MinLOD = 0;
  1884.                         int32 MaxLOD = NumLODs;
  1885.                         CalcLOD(MinLOD, MaxLOD, UnbuiltBounds[0].Min, UnbuiltBounds[0].Max, ViewOriginInLocalZero, ViewOriginInLocalOne, LODPlanesMin, LODPlanesMax);
  1886.                         int32 FirstIndexInRun = 0;
  1887.                         for (int32 Index = 1; Index < NumUnbuiltInstances; ++Index)
  1888.                         {
  1889.                             int32 TempMinLOD = 0;
  1890.                             int32 TempMaxLOD = NumLODs;
  1891.                             CalcLOD(TempMinLOD, TempMaxLOD, UnbuiltBounds[Index].Min, UnbuiltBounds[Index].Max, ViewOriginInLocalZero, ViewOriginInLocalOne, LODPlanesMin, LODPlanesMax);
  1892.                             if (TempMinLOD != MinLOD)
  1893.                             {
  1894.                                 if (MinLOD < NumLODs)
  1895.                                 {
  1896.                                     InstanceParams.AddRun(MinLOD, MinLOD, FirstIndexInRun + FirstUnbuiltIndex, (Index - 1) + FirstUnbuiltIndex);
  1897.                                 }
  1898.                                 MinLOD = TempMinLOD;
  1899.                                 FirstIndexInRun = Index;
  1900.                             }
  1901.                         }
  1902.                         InstanceParams.AddRun(MinLOD, MinLOD, FirstIndexInRun + FirstUnbuiltIndex, LastUnbuiltIndex);
  1903.                     }
  1904.                 }
  1905.                 else
  1906.                 {
  1907.                     // more than 1000, render them all at lowest LOD (until we have an updated tree)
  1908.                     InstanceParams.AddRun(RenderData->LODResources.Num() - 1, RenderData->LODResources.Num() - 1, FirstUnbuiltIndex, LastUnbuiltIndex);
  1909.                 }
  1910.                 FillDynamicMeshElements(Collector, ElementParams, InstanceParams);
  1911.             }
  1912.         }
  1913.     }
  1914. }
  1915.  
  1916. void FHierarchicalStaticMeshSceneProxy::AcceptOcclusionResults(const FSceneView* View, TArray<bool>* Results, int32 ResultsStart, int32 NumResults)
  1917. {
  1918.     // Don't accept subprimitive occlusion results from a previously-created sceneproxy - the tree may have been different
  1919.     if (OcclusionBounds.Num() == NumResults && SceneProxyCreatedFrameNumberRenderThread < GFrameNumberRenderThread)
  1920.     {
  1921.         uint32 ViewId = View->GetViewKey();
  1922.         FFoliageOcclusionResults* OldResults = OcclusionResults.Find(ViewId);
  1923.         if (OldResults)
  1924.         {
  1925.             OldResults->FrameNumberRenderThread = GFrameNumberRenderThread;
  1926.             OldResults->Results = Results;
  1927.             OldResults->ResultsStart = ResultsStart;
  1928.             OldResults->NumResults = NumResults;
  1929.         }
  1930.         else
  1931.         {
  1932.             // now is a good time to clean up any stale entries
  1933.             for (auto Iter = OcclusionResults.CreateIterator(); Iter; ++Iter)
  1934.             {
  1935.                 if (Iter.Value().FrameNumberRenderThread != GFrameNumberRenderThread)
  1936.                 {
  1937.                     Iter.RemoveCurrent();
  1938.                 }
  1939.             }
  1940.             OcclusionResults.Add(ViewId, FFoliageOcclusionResults(Results, ResultsStart, NumResults));
  1941.         }
  1942.     }
  1943. }
  1944.  
  1945. const TArray<FBoxSphereBounds>* FHierarchicalStaticMeshSceneProxy::GetOcclusionQueries(const FSceneView* View) const
  1946. {
  1947.     return &OcclusionBounds;
  1948. }
  1949.  
  1950. FBoxSphereBounds Ufixed_HI_StaticMeshComponent::CalcBounds(const FTransform& BoundTransform) const
  1951. {
  1952.     ensure(BuiltInstanceBounds.IsValid || ClusterTreePtr->Num() == 0);
  1953.  
  1954.     if (BuiltInstanceBounds.IsValid || UnbuiltInstanceBounds.IsValid)
  1955.     {
  1956.         FBoxSphereBounds Result = BuiltInstanceBounds + UnbuiltInstanceBounds;
  1957.         return Result.TransformBy(BoundTransform);
  1958.     }
  1959.     else
  1960.     {
  1961.         QUICK_SCOPE_CYCLE_COUNTER(STAT_Ufixed_HI_StaticMeshComponent_CalcBounds_SlowPath);
  1962.         return Super::CalcBounds(BoundTransform);
  1963.     }
  1964. }
  1965.  
  1966. Ufixed_HI_StaticMeshComponent::Ufixed_HI_StaticMeshComponent(const FObjectInitializer& ObjectInitializer)
  1967.     : Super(ObjectInitializer)
  1968.     , ClusterTreePtr(MakeShareable(new TArray<FFixed_ClusterNode>))
  1969.     , WriteOncePrebuiltInstanceBuffer(/*NeedsCPUAccess*/ false, /*bSupportsVertexHalfFloat*/ GVertexElementTypeSupport.IsSupported(VET_Half2))
  1970.     , NumBuiltInstances(0)
  1971.     , NumBuiltRenderInstances(0)
  1972.     , UnbuiltInstanceBounds(0)
  1973.     , bEnableDensityScaling(false)
  1974.     , bIsAsyncBuilding(false)
  1975.     , bDiscardAsyncBuildResults(false)
  1976.     , bConcurrentRemoval(false)
  1977.     , AccumulatedNavigationDirtyArea(0)
  1978. {
  1979.     bCanEverAffectNavigation = true;
  1980.     bUseAsOccluder = false;
  1981. }
  1982.  
  1983. Ufixed_HI_StaticMeshComponent::~Ufixed_HI_StaticMeshComponent()
  1984. {
  1985.     if (ProxySize)
  1986.     {
  1987.         DEC_DWORD_STAT_BY(STAT_FoliageInstanceBuffers, ProxySize);
  1988.     }
  1989.     ProxySize = 0;
  1990.     FlushAsyncBuildInstanceBufferTask();
  1991. }
  1992.  
  1993. #if WITH_EDITOR
  1994. void Ufixed_HI_StaticMeshComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
  1995. {
  1996.     if ((PropertyChangedEvent.Property != NULL && PropertyChangedEvent.Property->GetFName() == "PerInstanceSMData") ||
  1997.         (PropertyChangedEvent.Property != NULL && PropertyChangedEvent.Property->GetFName() == "Transform"))
  1998.     {
  1999.         BuildTree();
  2000.     }
  2001.  
  2002.     Super::PostEditChangeChainProperty(PropertyChangedEvent);
  2003. }
  2004. #endif
  2005.  
  2006. void Ufixed_HI_StaticMeshComponent::FlushAsyncBuildInstanceBufferTask()
  2007. {
  2008.     if (AsyncBuildInstanceBufferTask)
  2009.     {
  2010.         AsyncBuildInstanceBufferTask->EnsureCompletion();
  2011.         delete AsyncBuildInstanceBufferTask;
  2012.         AsyncBuildInstanceBufferTask = nullptr;
  2013.     }
  2014. }
  2015.  
  2016.  
  2017.  
  2018. void Ufixed_HI_StaticMeshComponent::Serialize(FArchive& Ar)
  2019. {
  2020.     // On save, if we have a pending async build we should wait for it to complete rather than saving an incomplete tree
  2021.     if (Ar.IsSaving())
  2022.     {
  2023.         if (!IsTreeFullyBuilt())
  2024.         {
  2025.             BuildTree();
  2026.         }
  2027.     }
  2028.  
  2029.     Super::Serialize(Ar);
  2030.  
  2031.     if (Ar.IsLoading())
  2032.     {
  2033.         ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>);
  2034.     }
  2035.     TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  2036.     ClusterTree.BulkSerialize(Ar);
  2037.     if (Ar.IsLoading() && !BuiltInstanceBounds.IsValid)
  2038.     {
  2039.         BuiltInstanceBounds = (ClusterTree.Num() > 0 ? FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax) : FBox(0));
  2040.     }
  2041. }
  2042.  
  2043. void Ufixed_HI_StaticMeshComponent::PostDuplicate(bool bDuplicateForPIE)
  2044. {
  2045.     Super::PostDuplicate(bDuplicateForPIE);
  2046.     BuildTree();
  2047. }
  2048.  
  2049. void Ufixed_HI_StaticMeshComponent::RemoveInstanceInternal(int32 InstanceIndex)
  2050. {
  2051.     PartialNavigationUpdate(InstanceIndex);
  2052.  
  2053.     // Save the render index
  2054.     const int32 RemovedRenderIndex = InstanceReorderTable[InstanceIndex];
  2055.     if (RemovedRenderIndex != INDEX_NONE)
  2056.     {
  2057.         RemovedInstances.Add(RemovedRenderIndex);
  2058.     }
  2059.  
  2060.     // Remove the instance
  2061.     PerInstanceSMData.RemoveAtSwap(InstanceIndex);
  2062.     InstanceReorderTable.RemoveAtSwap(InstanceIndex);
  2063. #if WITH_EDITOR
  2064.     if (SelectedInstances.Num())
  2065.     {
  2066.         SelectedInstances.RemoveAtSwap(InstanceIndex);
  2067.     }
  2068. #endif
  2069.  
  2070.     // update the physics state
  2071.     if (bPhysicsStateCreated)
  2072.     {
  2073.         // Clean up physics for removed instance
  2074.         if (InstanceBodies[InstanceIndex])
  2075.         {
  2076.             InstanceBodies[InstanceIndex]->TermBody();
  2077.             delete InstanceBodies[InstanceIndex];
  2078.         }
  2079.  
  2080.         int32 LastInstanceIndex = PerInstanceSMData.Num();
  2081.  
  2082.         if (InstanceIndex == LastInstanceIndex)
  2083.         {
  2084.             // If we removed the last instance in the array we just need to remove it from the InstanceBodies array too.
  2085.             InstanceBodies.RemoveAt(InstanceIndex);
  2086.         }
  2087.         else
  2088.         {
  2089.             if (InstanceBodies[LastInstanceIndex])
  2090.             {
  2091.                 // term physics for swapped instance
  2092.                 InstanceBodies[LastInstanceIndex]->TermBody();
  2093.             }
  2094.  
  2095.             // swap in the last instance body if we have one
  2096.             InstanceBodies.RemoveAtSwap(InstanceIndex);
  2097.  
  2098.             // recreate physics for the instance we swapped in the removed item's place
  2099.             if (InstanceBodies[InstanceIndex])
  2100.             {
  2101.                 InitInstanceBody(InstanceIndex, InstanceBodies[InstanceIndex]);
  2102.             }
  2103.         }
  2104.     }
  2105. }
  2106.  
  2107. bool Ufixed_HI_StaticMeshComponent::RemoveInstances(const TArray<int32>& InstancesToRemove)
  2108. {
  2109.     if (InstancesToRemove.Num() == 0)
  2110.     {
  2111.         return true;
  2112.     }
  2113.  
  2114.     TArray<int32> SortedInstancesToRemove = InstancesToRemove;
  2115.  
  2116.     // Sort so RemoveAtSwaps don't alter the indices of items still to remove
  2117.     SortedInstancesToRemove.Sort(TGreater<int32>());
  2118.  
  2119.     if (!PerInstanceSMData.IsValidIndex(SortedInstancesToRemove[0]) || !PerInstanceSMData.IsValidIndex(SortedInstancesToRemove.Last()))
  2120.     {
  2121.         return false;
  2122.     }
  2123.  
  2124.     for (int32 Index : SortedInstancesToRemove)
  2125.     {
  2126.         RemoveInstanceInternal(Index);
  2127.     }
  2128.  
  2129.     if (IsAsyncBuilding())
  2130.     {
  2131.         // invalidate the results of the current async build as it's too slow to fix up deletes
  2132.         bConcurrentRemoval = true;
  2133.     }
  2134.     else
  2135.     {
  2136.         BuildTreeAsync();
  2137.     }
  2138.  
  2139.     ReleasePerInstanceRenderData();
  2140.     MarkRenderStateDirty();
  2141.  
  2142.     return true;
  2143. }
  2144.  
  2145. bool Ufixed_HI_StaticMeshComponent::RemoveInstance(int32 InstanceIndex)
  2146. {
  2147.     if (!PerInstanceSMData.IsValidIndex(InstanceIndex))
  2148.     {
  2149.         return false;
  2150.     }
  2151.  
  2152.     RemoveInstanceInternal(InstanceIndex);
  2153.  
  2154.     if (IsAsyncBuilding())
  2155.     {
  2156.         // invalidate the results of the current async build as it's too slow to fix up deletes
  2157.         bConcurrentRemoval = true;
  2158.     }
  2159.     else
  2160.     {
  2161.         BuildTreeAsync();
  2162.     }
  2163.  
  2164.     ReleasePerInstanceRenderData();
  2165.     MarkRenderStateDirty();
  2166.  
  2167.     return true;
  2168. }
  2169.  
  2170. bool Ufixed_HI_StaticMeshComponent::UpdateInstanceTransform(int32 InstanceIndex, const FTransform& NewInstanceTransform, bool bWorldSpace, bool bMarkRenderStateDirty, bool bTeleport)
  2171. {
  2172.     if (!PerInstanceSMData.IsValidIndex(InstanceIndex))
  2173.     {
  2174.         return false;
  2175.     }
  2176.  
  2177.     if (IsAsyncBuilding())
  2178.     {
  2179.         // invalidate the results of the current async build we need to modify the tree
  2180.         bConcurrentRemoval = true;
  2181.     }
  2182.  
  2183.     int32 RenderIndex = InstanceReorderTable[InstanceIndex];
  2184.     const FMatrix OldTransform = PerInstanceSMData[InstanceIndex].Transform;
  2185.     const FTransform NewLocalTransform = bWorldSpace ? NewInstanceTransform.GetRelativeTransform(ComponentToWorld) : NewInstanceTransform;
  2186.     const FVector NewLocalLocation = NewLocalTransform.GetTranslation();
  2187.  
  2188.     // if we are only updating rotation/scale we update the instance directly in the cluster tree
  2189.     const bool bIsOmittedInstance = (RenderIndex == INDEX_NONE);
  2190.     const bool bIsBuiltInstance = !bIsOmittedInstance && RenderIndex < NumBuiltRenderInstances;
  2191.     const bool bDoInPlaceUpdate = bIsBuiltInstance && NewLocalLocation.Equals(OldTransform.GetOrigin());
  2192.  
  2193.     bool Result = Super::UpdateInstanceTransform(InstanceIndex, NewInstanceTransform, bWorldSpace, bMarkRenderStateDirty, bTeleport);
  2194.  
  2195.     bool bDirtyRenderState = false;
  2196.     if (GetStaticMesh())
  2197.     {
  2198.         const FBox NewInstanceBounds = GetStaticMesh()->GetBounds().GetBox().TransformBy(NewLocalTransform);
  2199.  
  2200.         if (bDoInPlaceUpdate)
  2201.         {
  2202.             // If the new bounds are larger than the old ones, then expand the bounds on the tree to make sure culling works correctly
  2203.             const FBox OldInstanceBounds = GetStaticMesh()->GetBounds().GetBox().TransformBy(OldTransform);
  2204.             if (!OldInstanceBounds.IsInside(NewInstanceBounds))
  2205.             {
  2206.                 BuiltInstanceBounds += NewInstanceBounds;
  2207.                 bDirtyRenderState = true;
  2208.             }
  2209.         }
  2210.         else
  2211.         {
  2212.             // If we can't update an instance in-place, we have to remove it and re-add it
  2213.             // Allocate a new instance render order ID, rendered last (it is now an unbuilt instance)
  2214.             const int32 OldRenderIndex = RenderIndex;
  2215.             RenderIndex = GetNumRenderInstances();
  2216.             InstanceReorderTable[InstanceIndex] = RenderIndex;
  2217.  
  2218.             // Treat the old instance render data like a removal.
  2219.             if (!bIsOmittedInstance)
  2220.             {
  2221.                 RemovedInstances.Add(OldRenderIndex);
  2222.             }
  2223.  
  2224.             UnbuiltInstanceBounds += NewInstanceBounds;
  2225.             UnbuiltInstanceBoundsList.Add(NewInstanceBounds);
  2226.         }
  2227.  
  2228.         if (bDirtyRenderState)
  2229.         {
  2230.             MarkRenderStateDirty();
  2231.         }
  2232.  
  2233.         if (!bDoInPlaceUpdate && !IsAsyncBuilding())
  2234.         {
  2235.             BuildTreeAsync();
  2236.         }
  2237.     }
  2238.  
  2239.     return Result;
  2240. }
  2241.  
  2242. int32 Ufixed_HI_StaticMeshComponent::AddInstance(const FTransform& InstanceTransform)
  2243. {
  2244.     int32 InstanceIndex = UInstancedStaticMeshComponent::AddInstance(InstanceTransform);
  2245.  
  2246.     if (PerInstanceSMData.Num() == 1)
  2247.     {
  2248.         BuildTree();
  2249.     }
  2250.     else
  2251.     {
  2252.         if (!IsAsyncBuilding())
  2253.         {
  2254.             BuildTreeAsync();
  2255.         }
  2256.  
  2257.         if (GetStaticMesh())
  2258.         {
  2259.             // Need to offset the newly added instance's RenderIndex by the amount that will be adjusted at the end of the frame
  2260.             InstanceReorderTable.Add(GetNumRenderInstances());
  2261.  
  2262.             const FBox NewInstanceBounds = GetStaticMesh()->GetBounds().GetBox().TransformBy(InstanceTransform);
  2263.             UnbuiltInstanceBounds += NewInstanceBounds;
  2264.             UnbuiltInstanceBoundsList.Add(NewInstanceBounds);
  2265.         }
  2266.     }
  2267.  
  2268.     return InstanceIndex;
  2269. }
  2270.  
  2271. void Ufixed_HI_StaticMeshComponent::ClearInstances()
  2272. {
  2273.     if (IsAsyncBuilding())
  2274.     {
  2275.         bConcurrentRemoval = true;
  2276.     }
  2277.  
  2278.     ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>);
  2279.     NumBuiltInstances = 0;
  2280.     NumBuiltRenderInstances = 0;
  2281.     SortedInstances.Empty();
  2282.     UnbuiltInstanceBounds.Init();
  2283.     UnbuiltInstanceBoundsList.Empty();
  2284.  
  2285.     if (ProxySize)
  2286.     {
  2287.         DEC_DWORD_STAT_BY(STAT_FoliageInstanceBuffers, ProxySize);
  2288.     }
  2289.  
  2290.     Super::ClearInstances();
  2291. }
  2292.  
  2293. bool Ufixed_HI_StaticMeshComponent::ShouldCreatePhysicsState() const
  2294. {
  2295.     if (bDisableCollision)
  2296.     {
  2297.         return false;
  2298.     }
  2299.     return Super::ShouldCreatePhysicsState();
  2300. }
  2301.  
  2302. int32 Ufixed_HI_StaticMeshComponent::GetVertsForLOD(int32 LODIndex)
  2303. {
  2304.     if (GetStaticMesh() && GetStaticMesh()->HasValidRenderData())
  2305.     {
  2306.         return GetStaticMesh()->GetNumVertices(LODIndex);
  2307.     }
  2308.     return 0;
  2309. }
  2310.  
  2311. int32 Ufixed_HI_StaticMeshComponent::DesiredInstancesPerLeaf()
  2312. {
  2313.     int32 LOD0Verts = GetVertsForLOD(0);
  2314.     int32 VertsToSplit = CVarMinVertsToSplitNode.GetValueOnAnyThread();
  2315.     if (LOD0Verts)
  2316.     {
  2317.         return FMath::Clamp(VertsToSplit / LOD0Verts, 1, 1024);
  2318.     }
  2319.     return 16;
  2320. }
  2321.  
  2322. float Ufixed_HI_StaticMeshComponent::ActualInstancesPerLeaf()
  2323. {
  2324.     const TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  2325.     if (ClusterTree.Num())
  2326.     {
  2327.         int32 NumLeaves = 0;
  2328.         int32 NumInstances = 0;
  2329.         for (int32 Index = ClusterTree.Num() - 1; Index >= 0; Index--)
  2330.         {
  2331.             if (ClusterTree[Index].FirstChild >= 0)
  2332.             {
  2333.                 break;
  2334.             }
  2335.             NumLeaves++;
  2336.             NumInstances += 1 + ClusterTree[Index].LastInstance - ClusterTree[Index].FirstInstance;
  2337.         }
  2338.         if (NumLeaves)
  2339.         {
  2340.             return float(NumInstances) / float(NumLeaves);
  2341.         }
  2342.     }
  2343.     return 0.0f;
  2344. }
  2345.  
  2346. void Ufixed_HI_StaticMeshComponent::PostBuildStats()
  2347. {
  2348. #if 0
  2349.     const TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  2350.     int32 NumInst = WriteOncePrebuiltInstanceBuffer.NumInstances() ? WriteOncePrebuiltInstanceBuffer.NumInstances() : PerInstanceSMData.Num();
  2351.     UE_LOG(LogStaticMesh, Display, TEXT("Built a foliage hierarchy with %d instances, %d nodes, %f instances / leaf (desired %d) and %d verts in LOD0. Grass? %d "), NumInst, ClusterTree.Num(), ActualInstancesPerLeaf(), DesiredInstancesPerLeaf(), GetVertsForLOD(0), !!WriteOncePrebuiltInstanceBuffer.NumInstances());
  2352. #endif
  2353. }
  2354.  
  2355.  
  2356. void Ufixed_HI_StaticMeshComponent::BuildTree()
  2357. {
  2358.     checkSlow(IsInGameThread());
  2359.  
  2360.     // If we try to build the tree with the static mesh not fully loaded, we can end up in an inconsistent state which ends in a crash later
  2361.     checkSlow(!GetStaticMesh() || !GetStaticMesh()->HasAnyFlags(RF_NeedPostLoad));
  2362.  
  2363.     QUICK_SCOPE_CYCLE_COUNTER(STAT_Ufixed_HI_StaticMeshComponent_BuildTree);
  2364.     // Verify that the mesh is valid before using it.
  2365.     const bool bMeshIsValid =
  2366.         // make sure we have instances
  2367.         PerInstanceSMData.Num() > 0 &&
  2368.         // make sure we have an actual staticmesh
  2369.         GetStaticMesh() &&
  2370.         GetStaticMesh()->HasValidRenderData() &&
  2371.         // You really can't use hardware instancing on the consoles with multiple elements because they share the same index buffer.
  2372.         // @todo: Level error or something to let LDs know this
  2373.         1;//GetStaticMesh()->LODModels(0).Elements.Num() == 1;
  2374.  
  2375.     if (bMeshIsValid)
  2376.     {
  2377.         //double StartTime = FPlatformTime::Seconds();
  2378.         // If we don't have a random seed for this instanced static mesh component yet, then go ahead and
  2379.         // generate one now.  This will be saved with the static mesh component and used for future generation
  2380.         // of random numbers for this component's instances. (Used by the PerInstanceRandom material expression)
  2381.         while (InstancingRandomSeed == 0)
  2382.         {
  2383.             InstancingRandomSeed = FMath::Rand();
  2384.         }
  2385.  
  2386.         TArray<FMatrix> InstanceTransforms;
  2387.         InstanceTransforms.AddUninitialized(PerInstanceSMData.Num());
  2388.         for (int32 Index = 0; Index < PerInstanceSMData.Num(); Index++)
  2389.         {
  2390.             InstanceTransforms[Index] = PerInstanceSMData[Index].Transform;
  2391.         }
  2392.  
  2393.         FClusterBuilder Builder(InstanceTransforms, GetStaticMesh()->GetBounds().GetBox(), DesiredInstancesPerLeaf(), ExcludedDueToDensityScaling);
  2394.         Builder.Build();
  2395.  
  2396.         NumBuiltInstances = Builder.Result->InstanceReorderTable.Num();
  2397.         NumBuiltRenderInstances = Builder.Result->SortedInstances.Num();
  2398.         OcclusionLayerNumNodes = Builder.Result->OutOcclusionLayerNum;
  2399.         UnbuiltInstanceBounds.Init();
  2400.         RemovedInstances.Empty();
  2401.         UnbuiltInstanceBoundsList.Empty();
  2402.         BuiltInstanceBounds = (Builder.Result->Nodes.Num() > 0 ? FBox(Builder.Result->Nodes[0].BoundMin, Builder.Result->Nodes[0].BoundMax) : FBox(0));
  2403.  
  2404.         ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>(MoveTemp(Builder.Result->Nodes)));
  2405.         InstanceReorderTable = MoveTemp(Builder.Result->InstanceReorderTable);
  2406.         SortedInstances = MoveTemp(Builder.Result->SortedInstances);
  2407.  
  2408.         FlushAccumulatedNavigationUpdates();
  2409.  
  2410.         PostBuildStats();
  2411.     }
  2412.     else
  2413.     {
  2414.         ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>);
  2415.         NumBuiltInstances = 0;
  2416.         NumBuiltRenderInstances = 0;
  2417.         InstanceReorderTable.Empty();
  2418.         SortedInstances.Empty();
  2419.         RemovedInstances.Empty();
  2420.  
  2421.         UnbuiltInstanceBoundsList.Empty();
  2422.         BuiltInstanceBounds.Init();
  2423.     }
  2424.  
  2425.     if (bIsAsyncBuilding)
  2426.     {
  2427.         // We did a sync build while async building. The sync build is newer so we will use that.
  2428.         bDiscardAsyncBuildResults = true;
  2429.     }
  2430.  
  2431.     ReleasePerInstanceRenderData();
  2432. }
  2433.  
  2434. void Ufixed_HI_StaticMeshComponent::BuildTreeAnyThread(
  2435.     TArray<FMatrix>& InstanceTransforms,
  2436.     const FBox& MeshBox,
  2437.     TArray<FFixed_ClusterNode>& OutClusterTree,
  2438.     TArray<int32>& OutSortedInstances,
  2439.     TArray<int32>& OutInstanceReorderTable,
  2440.     int32& OutOcclusionLayerNum,
  2441.     int32 MaxInstancesPerLeaf
  2442. )
  2443. {
  2444.     check(MaxInstancesPerLeaf > 0);
  2445.  
  2446.     FClusterBuilder Builder(InstanceTransforms, MeshBox, MaxInstancesPerLeaf);
  2447.     Builder.Build();
  2448.     OutOcclusionLayerNum = Builder.Result->OutOcclusionLayerNum;
  2449.  
  2450.     OutClusterTree = MoveTemp(Builder.Result->Nodes);
  2451.     OutInstanceReorderTable = MoveTemp(Builder.Result->InstanceReorderTable);
  2452.     OutSortedInstances = MoveTemp(Builder.Result->SortedInstances);
  2453. }
  2454.  
  2455. void Ufixed_HI_StaticMeshComponent::AcceptPrebuiltTree(TArray<FFixed_ClusterNode>& InClusterTree, int InOcclusionLayerNumNodes)
  2456. {
  2457.     checkSlow(IsInGameThread());
  2458.  
  2459.     QUICK_SCOPE_CYCLE_COUNTER(STAT_Ufixed_HI_StaticMeshComponent_AcceptPrebuiltTree);
  2460.     // this is only for prebuild data, already in the correct order
  2461.     check(!PerInstanceSMData.Num());
  2462.     NumBuiltInstances = 0;
  2463.     NumBuiltRenderInstances = WriteOncePrebuiltInstanceBuffer.NumInstances();
  2464.     check(NumBuiltRenderInstances);
  2465.     UnbuiltInstanceBounds.Init();
  2466.     UnbuiltInstanceBoundsList.Empty();
  2467.     RemovedInstances.Empty();
  2468.     ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>);
  2469.     InstanceReorderTable.Empty();
  2470.     SortedInstances.Empty();
  2471.     OcclusionLayerNumNodes = InOcclusionLayerNumNodes;
  2472.     BuiltInstanceBounds = (InClusterTree.Num() > 0 ? FBox(InClusterTree[0].BoundMin, InClusterTree[0].BoundMax) : FBox(0));
  2473.  
  2474.     // Verify that the mesh is valid before using it.
  2475.     const bool bMeshIsValid =
  2476.         // make sure we have instances
  2477.         NumBuiltRenderInstances > 0 &&
  2478.         // make sure we have an actual staticmesh
  2479.         GetStaticMesh() &&
  2480.         GetStaticMesh()->HasValidRenderData() &&
  2481.         // You really can't use hardware instancing on the consoles with multiple elements because they share the same index buffer.
  2482.         // @todo: Level error or something to let LDs know this
  2483.         1;//GetStaticMesh()->LODModels(0).Elements.Num() == 1;
  2484.  
  2485.     if (bMeshIsValid)
  2486.     {
  2487.         //double StartTime = FPlatformTime::Seconds();
  2488.         // If we don't have a random seed for this instanced static mesh component yet, then go ahead and
  2489.         // generate one now.  This will be saved with the static mesh component and used for future generation
  2490.         // of random numbers for this component's instances. (Used by the PerInstanceRandom material expression)
  2491.         while (InstancingRandomSeed == 0)
  2492.         {
  2493.             InstancingRandomSeed = FMath::Rand();
  2494.         }
  2495.         *ClusterTreePtr = MoveTemp(InClusterTree);
  2496.         PostBuildStats();
  2497.  
  2498.     }
  2499.     QUICK_SCOPE_CYCLE_COUNTER(STAT_Ufixed_HI_StaticMeshComponent_AcceptPrebuiltTree_Mark);
  2500.  
  2501.     MarkRenderStateDirty();
  2502. }
  2503.  
  2504. void Ufixed_HI_StaticMeshComponent::ApplyBuildTreeAsync(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent, TSharedRef<FClusterBuilder, ESPMode::ThreadSafe> Builder, double StartTime)
  2505. {
  2506.     checkSlow(IsInGameThread());
  2507.  
  2508.     bIsAsyncBuilding = false;
  2509.  
  2510.     if (bDiscardAsyncBuildResults)
  2511.     {
  2512.         // We did a sync build while async building. The sync build is newer so we will use that.
  2513.         bDiscardAsyncBuildResults = false;
  2514.     }
  2515.     else
  2516.     {
  2517.         if (bConcurrentRemoval)
  2518.         {
  2519.             bConcurrentRemoval = false;
  2520.  
  2521.             UE_LOG(LogStaticMesh, Verbose, TEXT("Discarded foliage hierarchy of %d elements build due to concurrent removal (%.1fs)"), Builder->Result->InstanceReorderTable.Num(), (float)(FPlatformTime::Seconds() - StartTime));
  2522.  
  2523.             // There were removes or updates while we were building, it's too slow to fix up the result now, so build async again.
  2524.             BuildTreeAsync();
  2525.         }
  2526.         else
  2527.         {
  2528.             NumBuiltInstances = Builder->Result->InstanceReorderTable.Num();
  2529.             NumBuiltRenderInstances = Builder->Result->SortedInstances.Num();
  2530.  
  2531.             if (NumBuiltInstances < PerInstanceSMData.Num())
  2532.             {
  2533.                 // Add remap entries for unbuilt instances
  2534.                 Builder->Result->InstanceReorderTable.AddUninitialized(PerInstanceSMData.Num() - NumBuiltInstances);
  2535.                 for (int32 Index = NumBuiltInstances; Index < PerInstanceSMData.Num(); Index++)
  2536.                 {
  2537.                     Builder->Result->InstanceReorderTable[Index] = Index;
  2538.                 }
  2539.             }
  2540.  
  2541.             ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>(MoveTemp(Builder->Result->Nodes)));
  2542.             TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  2543.             InstanceReorderTable = MoveTemp(Builder->Result->InstanceReorderTable);
  2544.             SortedInstances = MoveTemp(Builder->Result->SortedInstances);
  2545.             RemovedInstances.Empty();
  2546.             OcclusionLayerNumNodes = Builder->Result->OutOcclusionLayerNum;
  2547.             BuiltInstanceBounds = (ClusterTree.Num() > 0 ? FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax) : FBox(0));
  2548.  
  2549.             UE_LOG(LogStaticMesh, Verbose, TEXT("Built a foliage hierarchy with %d of %d elements in %.1fs."), NumBuiltInstances, PerInstanceSMData.Num(), (float)(FPlatformTime::Seconds() - StartTime));
  2550.  
  2551.             if (NumBuiltInstances < PerInstanceSMData.Num())
  2552.             {
  2553.                 // There are new outstanding instances, build again!
  2554.                 UnbuiltInstanceBoundsList.RemoveAt(0, UnbuiltInstanceBoundsList.Num() - (PerInstanceSMData.Num() - NumBuiltInstances));
  2555.                 BuildTreeAsync();
  2556.             }
  2557.             else
  2558.             {
  2559.                 UnbuiltInstanceBounds.Init();
  2560.                 UnbuiltInstanceBoundsList.Empty();
  2561.                 FlushAccumulatedNavigationUpdates();
  2562.             }
  2563.  
  2564.             ReleasePerInstanceRenderData();
  2565.             MarkRenderStateDirty();
  2566.  
  2567.             PostBuildStats();
  2568.         }
  2569.     }
  2570. }
  2571.  
  2572. void Ufixed_HI_StaticMeshComponent::BuildTreeAsync()
  2573. {
  2574.     checkSlow(IsInGameThread());
  2575.  
  2576.     // If we try to build the tree with the static mesh not fully loaded, we can end up in an inconsistent state which ends in a crash later
  2577.     checkSlow(!GetStaticMesh() || !GetStaticMesh()->HasAnyFlags(RF_NeedPostLoad));
  2578.  
  2579.     check(!bIsAsyncBuilding);
  2580.  
  2581.     // Verify that the mesh is valid before using it.
  2582.     const bool bMeshIsValid =
  2583.         // make sure we have instances
  2584.         PerInstanceSMData.Num() > 0 &&
  2585.         // make sure we have an actual staticmesh
  2586.         GetStaticMesh() &&
  2587.         GetStaticMesh()->HasValidRenderData() &&
  2588.         // You really can't use hardware instancing on the consoles with multiple elements because they share the same index buffer.
  2589.         // @todo: Level error or something to let LDs know this
  2590.         1;//GetStaticMesh()->LODModels(0).Elements.Num() == 1;
  2591.  
  2592.     if (bMeshIsValid)
  2593.     {
  2594.         double StartTime = FPlatformTime::Seconds();
  2595.         // If we don't have a random seed for this instanced static mesh component yet, then go ahead and
  2596.         // generate one now.  This will be saved with the static mesh component and used for future generation
  2597.         // of random numbers for this component's instances. (Used by the PerInstanceRandom material expression)
  2598.         while (InstancingRandomSeed == 0)
  2599.         {
  2600.             InstancingRandomSeed = FMath::Rand();
  2601.         }
  2602.  
  2603.         int32 Num = PerInstanceSMData.Num();
  2604.         TArray<FMatrix> InstanceTransforms;
  2605.         InstanceTransforms.AddUninitialized(Num);
  2606.         for (int32 Index = 0; Index < Num; Index++)
  2607.         {
  2608.             InstanceTransforms[Index] = PerInstanceSMData[Index].Transform;
  2609.         }
  2610.  
  2611.         UE_LOG(LogStaticMesh, Verbose, TEXT("Copied %d transforms in %.3fs."), Num, float(FPlatformTime::Seconds() - StartTime));
  2612.  
  2613.         TSharedRef<FClusterBuilder, ESPMode::ThreadSafe> Builder(new FClusterBuilder(InstanceTransforms, GetStaticMesh()->GetBounds().GetBox(), DesiredInstancesPerLeaf()));
  2614.  
  2615.         bIsAsyncBuilding = true;
  2616.  
  2617.         FGraphEventRef BuildTreeAsyncResult(
  2618.             FDelegateGraphTask::CreateAndDispatchWhenReady(FDelegateGraphTask::FDelegate::CreateRaw(&Builder.Get(), &FClusterBuilder::BuildAsync), GET_STATID(STAT_FoliageBuildTime), NULL, ENamedThreads::GameThread, ENamedThreads::AnyBackgroundThreadNormalTask));
  2619.  
  2620.         // add a dependent task to run on the main thread when build is complete
  2621.         FGraphEventRef UnusedAsyncResult(
  2622.             FDelegateGraphTask::CreateAndDispatchWhenReady(
  2623.                 FDelegateGraphTask::FDelegate::CreateUObject(this, &Ufixed_HI_StaticMeshComponent::ApplyBuildTreeAsync, Builder, StartTime), GET_STATID(STAT_FoliageBuildTime),
  2624.                 BuildTreeAsyncResult, ENamedThreads::GameThread, ENamedThreads::GameThread
  2625.             )
  2626.         );
  2627.     }
  2628.     else
  2629.     {
  2630.         ClusterTreePtr = MakeShareable(new TArray<FFixed_ClusterNode>);
  2631.         NumBuiltInstances = 0;
  2632.         NumBuiltRenderInstances = 0;
  2633.         InstanceReorderTable.Empty();
  2634.         SortedInstances.Empty();
  2635.         RemovedInstances.Empty();
  2636.  
  2637.         UnbuiltInstanceBoundsList.Empty();
  2638.         BuiltInstanceBounds.Init();
  2639.         ReleasePerInstanceRenderData();
  2640.     }
  2641. }
  2642.  
  2643. FPrimitiveSceneProxy* Ufixed_HI_StaticMeshComponent::CreateSceneProxy()
  2644. {
  2645.     QUICK_SCOPE_CYCLE_COUNTER(STAT_HierarchicalInstancedStaticMeshComponent_CreateSceneProxy);
  2646.  
  2647.     if (ProxySize)
  2648.     {
  2649.         DEC_DWORD_STAT_BY(STAT_FoliageInstanceBuffers, ProxySize);
  2650.     }
  2651.     ProxySize = 0;
  2652.  
  2653.     if (PerInstanceSMData.Num() != InstanceReorderTable.Num())
  2654.     {
  2655.         // this is a bizzaro case where folks are editing the PerInstanceSMData in a template of a blueprint component
  2656.         // not a great solution, but we can fix it now.
  2657.         BuildTree();
  2658.     }
  2659.  
  2660.     FlushAsyncBuildInstanceBufferTask();
  2661.  
  2662.     // Verify that the mesh is valid before using it.
  2663.     const bool bMeshIsValid =
  2664.         // make sure we have instances
  2665.         (GetNumRenderInstances() - RemovedInstances.Num() > 0 || WriteOncePrebuiltInstanceBuffer.NumInstances() > 0 || bPerInstanceRenderDataWasPrebuilt) &&
  2666.         // make sure we have an actual staticmesh
  2667.         GetStaticMesh() &&
  2668.         GetStaticMesh()->HasValidRenderData() &&
  2669.         // You really can't use hardware instancing on the consoles with multiple elements because they share the same index buffer.
  2670.         // @todo: Level error or something to let LDs know this
  2671.         1;//GetStaticMesh()->LODModels(0).Elements.Num() == 1;
  2672.  
  2673.     if (bMeshIsValid)
  2674.     {
  2675.         if (bHasPerInstanceHitProxies && GetWorld() && GetWorld()->IsGameWorld())
  2676.         {
  2677.             // hit proxies take forever to build, don't do it if this is a game world.
  2678.             bHasPerInstanceHitProxies = false;
  2679.         }
  2680.         // If we don't have a random seed for this instanced static mesh component yet, then go ahead and
  2681.         // generate one now.  This will be saved with the static mesh component and used for future generation
  2682.         // of random numbers for this component's instances. (Used by the PerInstanceRandom material expression)
  2683.         while (InstancingRandomSeed == 0)
  2684.         {
  2685.             InstancingRandomSeed = FMath::Rand();
  2686.         }
  2687.  
  2688.         if (WriteOncePrebuiltInstanceBuffer.NumInstances() > 0 || bPerInstanceRenderDataWasPrebuilt)
  2689.         {
  2690.             ProxySize = WriteOncePrebuiltInstanceBuffer.GetResourceSize();
  2691.             INC_DWORD_STAT_BY(STAT_FoliageInstanceBuffers, ProxySize);
  2692.  
  2693.             bool bIsGrass = !PerInstanceSMData.Num();
  2694.  
  2695.             check(bIsGrass || WriteOncePrebuiltInstanceBuffer.NumInstances() == GetNumRenderInstances());
  2696.             return ::new FHierarchicalStaticMeshSceneProxy(bIsGrass, this, GetWorld()->FeatureLevel, WriteOncePrebuiltInstanceBuffer);
  2697.         }
  2698.  
  2699.         const bool bSupportsVertexHalfFloat = GVertexElementTypeSupport.IsSupported(VET_Half2);
  2700.         ProxySize = FStaticMeshInstanceData::GetResourceSize(PerInstanceSMData.Num(), bSupportsVertexHalfFloat);
  2701.         INC_DWORD_STAT_BY(STAT_FoliageInstanceBuffers, ProxySize);
  2702.         return ::new FHierarchicalStaticMeshSceneProxy(false, this, GetWorld()->FeatureLevel);
  2703.     }
  2704.     return nullptr;
  2705. }
  2706.  
  2707. void FFixed_AsyncBuildInstanceBuffer::DoWork()
  2708. {
  2709.     QUICK_SCOPE_CYCLE_COUNTER(FFixed_AsyncBuildInstanceBuffer_DoWork);
  2710.  
  2711.     const int32 NumInstances = Component->PerInstanceSMData.Num();
  2712.     const int32 NumRenderInstances = Component->GetNumRenderInstances();
  2713.     Component->WriteOncePrebuiltInstanceBuffer.AllocateInstances(NumRenderInstances);
  2714.     FRandomStream RandomStream(Component->InstancingRandomSeed);
  2715.     bool bUseRemapTable = Component->PerInstanceSMData.Num() == Component->InstanceReorderTable.Num();
  2716.  
  2717.     int32 InitializedIndexCount = 0;
  2718.     const FMeshMapBuildData* MeshMapBuildData = NULL;
  2719.  
  2720.     if (Component->LODData.Num() > 0)
  2721.     {
  2722.         MeshMapBuildData = Component->GetMeshMapBuildData(Component->LODData[0]);
  2723.     }
  2724.  
  2725.     for (int32 InstanceIndex = 0; InstanceIndex < NumInstances; InstanceIndex++)
  2726.     {
  2727.         const FInstancedStaticMeshInstanceData& Instance = Component->PerInstanceSMData[InstanceIndex];
  2728.         const int32 DestInstanceIndex = bUseRemapTable ? Component->InstanceReorderTable[InstanceIndex] : InstanceIndex;
  2729.         if (DestInstanceIndex != INDEX_NONE)
  2730.         {
  2731.             FVector2D LightmapUVBias = Instance.LightmapUVBias_DEPRECATED;
  2732.             FVector2D ShadowmapUVBias = Instance.ShadowmapUVBias_DEPRECATED;
  2733.  
  2734.             if (MeshMapBuildData && MeshMapBuildData->PerInstanceLightmapData.IsValidIndex(InstanceIndex))
  2735.             {
  2736.                 LightmapUVBias = MeshMapBuildData->PerInstanceLightmapData[InstanceIndex].LightmapUVBias;
  2737.                 ShadowmapUVBias = MeshMapBuildData->PerInstanceLightmapData[InstanceIndex].ShadowmapUVBias;
  2738.             }
  2739.  
  2740.             Component->WriteOncePrebuiltInstanceBuffer.SetInstance(DestInstanceIndex, Instance.Transform, RandomStream.GetFraction(), LightmapUVBias, ShadowmapUVBias);
  2741.             InitializedIndexCount++;
  2742.         }
  2743.     }
  2744.     if (Component->RemovedInstances.Num())
  2745.     {
  2746.         check(bUseRemapTable);
  2747.         for (int32 InstanceIndex = 0; InstanceIndex < Component->RemovedInstances.Num(); InstanceIndex++)
  2748.         {
  2749.             const int32 DestInstanceIndex = Component->RemovedInstances[InstanceIndex];
  2750.             Component->WriteOncePrebuiltInstanceBuffer.NullifyInstance(DestInstanceIndex);
  2751.             InitializedIndexCount++;
  2752.         }
  2753.     }
  2754.  
  2755.     if (!ensure(InitializedIndexCount == NumRenderInstances))
  2756.     {
  2757.         // Nullify any remaining bogus render instances that were not init above.
  2758.         // This should not happen, but this code will avoid uninitialized memory causing odd behavior if it does.
  2759.         TSet<int32> InitializedIdicies;
  2760.         for (int32 InstanceIndex = 0; InstanceIndex < NumInstances; InstanceIndex++)
  2761.         {
  2762.             const FInstancedStaticMeshInstanceData& Instance = Component->PerInstanceSMData[InstanceIndex];
  2763.             const int32 DestInstanceIndex = bUseRemapTable ? Component->InstanceReorderTable[InstanceIndex] : InstanceIndex;
  2764.             if (DestInstanceIndex != INDEX_NONE)
  2765.             {
  2766.                 InitializedIdicies.Add(DestInstanceIndex);
  2767.             }
  2768.         }
  2769.  
  2770.         for (int32 InstanceIndex = 0; InstanceIndex < Component->RemovedInstances.Num(); InstanceIndex++)
  2771.         {
  2772.             const int32 DestInstanceIndex = Component->RemovedInstances[InstanceIndex];
  2773.             InitializedIdicies.Add(DestInstanceIndex);
  2774.         }
  2775.  
  2776.         for (int32 InstanceIndex = 0; InstanceIndex < NumRenderInstances; InstanceIndex++)
  2777.         {
  2778.             if (!InitializedIdicies.Contains(InstanceIndex))
  2779.             {
  2780.                 // This was an instance that was not initialized. Nullify it.
  2781.                 Component->WriteOncePrebuiltInstanceBuffer.NullifyInstance(InstanceIndex);
  2782.             }
  2783.         }
  2784.     }
  2785.  
  2786.     check(World);
  2787.     check(World->AsyncPreRegisterLevelStreamingTasks.GetValue() > 0);
  2788.     FPlatformMisc::MemoryBarrier();
  2789.     World->AsyncPreRegisterLevelStreamingTasks.Decrement();
  2790. }
  2791.  
  2792. void Ufixed_HI_StaticMeshComponent::PostLoad()
  2793. {
  2794.     Super::PostLoad();
  2795.  
  2796.     NumBuiltRenderInstances = ClusterTreePtr.IsValid() && ClusterTreePtr->Num() > 0 ? (*ClusterTreePtr.Get())[0].LastInstance - (*ClusterTreePtr.Get())[0].FirstInstance + 1 : 0;
  2797.  
  2798.     if (bEnableDensityScaling && GetWorld() && GetWorld()->IsGameWorld())
  2799.     {
  2800.         const float ScalabilityDensity = FMath::Clamp(CVarFoliageDensityScale.GetValueOnGameThread(), 0.0f, 1.0f);
  2801.         if (ScalabilityDensity == 0)
  2802.         {
  2803.             // exclude all instances
  2804.             ExcludedDueToDensityScaling.Init(true, PerInstanceSMData.Num());
  2805.             NumBuiltRenderInstances = 0;
  2806.         }
  2807.         else if (ScalabilityDensity > 0.0f && ScalabilityDensity < 1.0f)
  2808.         {
  2809.             FRandomStream Rand(InstancingRandomSeed);
  2810.             ExcludedDueToDensityScaling.Init(false, PerInstanceSMData.Num());
  2811.  
  2812.             for (int32 i = 0; i < ExcludedDueToDensityScaling.Num(); ++i)
  2813.             {
  2814.                 ExcludedDueToDensityScaling[i] = (Rand.FRand() > ScalabilityDensity);
  2815.             }
  2816.  
  2817.             // prune tree
  2818.             if (GetStaticMesh())
  2819.             {
  2820.                 GetStaticMesh()->ConditionalPostLoad();
  2821.             }
  2822.             BuildTree();
  2823.         }
  2824.     }
  2825.  
  2826. #if WITH_EDITOR
  2827.     // If any of the data is out of sync, build the tree now!
  2828.     if (InstanceReorderTable.Num() != PerInstanceSMData.Num() ||
  2829.         NumBuiltInstances != PerInstanceSMData.Num() ||
  2830.         UnbuiltInstanceBoundsList.Num() > 0 ||
  2831.         GetLinkerUE4Version() < VER_UE4_REBUILD_HIERARCHICAL_INSTANCE_TREES)
  2832.     {
  2833.         UE_LOG(LogStaticMesh, Warning, TEXT("Rebuilding hierarchical instanced mesh component, please resave map %s."), *GetFullName());
  2834.         check(!IsAsyncBuilding());
  2835.         if (GetStaticMesh())
  2836.         {
  2837.             GetStaticMesh()->ConditionalPostLoad();
  2838.         }
  2839.         BuildTree();
  2840.     }
  2841. #endif
  2842.  
  2843.     if (CVarASyncInstaneBufferConversion.GetValueOnGameThread() > 0)
  2844.     {
  2845.         UWorld* World = GetWorld();
  2846.         if (World && World->IsGameWorld() && NumBuiltRenderInstances > 0)
  2847.         {
  2848.             World->AsyncPreRegisterLevelStreamingTasks.Increment();
  2849.             while (InstancingRandomSeed == 0)
  2850.             {
  2851.                 InstancingRandomSeed = FMath::Rand();
  2852.             }
  2853.             AsyncBuildInstanceBufferTask = new FAsyncTask<FFixed_AsyncBuildInstanceBuffer>(this, World);
  2854.             AsyncBuildInstanceBufferTask->StartBackgroundTask();
  2855.         }
  2856.     }
  2857. }
  2858.  
  2859. static void GatherInstanceTransformsInArea(const Ufixed_HI_StaticMeshComponent& Component, const FBox& AreaBox, int32 Child, TArray<FTransform>& InstanceData)
  2860. {
  2861.     const TArray<FFixed_ClusterNode>& ClusterTree = *Component.ClusterTreePtr;
  2862.     if (ClusterTree.Num())
  2863.     {
  2864.         const FFixed_ClusterNode& ChildNode = ClusterTree[Child];
  2865.         const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.ComponentToWorld);
  2866.  
  2867.         if (AreaBox.Intersect(WorldNodeBox))
  2868.         {
  2869.             if (ChildNode.FirstChild < 0 || AreaBox.IsInside(WorldNodeBox))
  2870.             {
  2871.                 // Unfortunately ordering of PerInstanceSMData does not match ordering of cluster tree, so we have to use remaping
  2872.                 const bool bUseRemaping = Component.SortedInstances.Num() > 0;
  2873.  
  2874.                 // In case there no more subdivision or node is completely encapsulated by a area box
  2875.                 // add all instances to the result
  2876.                 for (int32 i = ChildNode.FirstInstance; i <= ChildNode.LastInstance; ++i)
  2877.                 {
  2878.                     int32 SortedIdx = bUseRemaping ? Component.SortedInstances[i] : i;
  2879.  
  2880.                     FTransform InstanceToComponent;
  2881.                     if (Component.PerInstanceSMData.IsValidIndex(SortedIdx))
  2882.                     {
  2883.                         InstanceToComponent = FTransform(Component.PerInstanceSMData[SortedIdx].Transform);
  2884.                     }
  2885.                     else if (Component.PerInstanceRenderData.IsValid())
  2886.                     {
  2887.                         // if there's no PerInstanceSMData (e.g. for grass), we'll go ge the transform from the render buffer
  2888.                         FMatrix XformMat;
  2889.                         Component.PerInstanceRenderData->InstanceBuffer.GetInstanceTransform(i, XformMat);
  2890.                         InstanceToComponent = FTransform(XformMat);
  2891.                     }
  2892.  
  2893.                     if (!InstanceToComponent.GetScale3D().IsZero())
  2894.                     {
  2895.                         InstanceData.Add(InstanceToComponent*Component.ComponentToWorld);
  2896.                     }
  2897.                 }
  2898.             }
  2899.             else
  2900.             {
  2901.                 for (int32 i = ChildNode.FirstChild; i <= ChildNode.LastChild; ++i)
  2902.                 {
  2903.                     GatherInstanceTransformsInArea(Component, AreaBox, i, InstanceData);
  2904.                 }
  2905.             }
  2906.         }
  2907.     }
  2908. }
  2909.  
  2910. int32 Ufixed_HI_StaticMeshComponent::GetOverlappingSphereCount(const FSphere& Sphere) const
  2911. {
  2912.     int32 Count = 0;
  2913.     TArray<FTransform> Transforms;
  2914.     const FBox AABB(Sphere.Center - FVector(Sphere.W), Sphere.Center + FVector(Sphere.W));
  2915.     GatherInstanceTransformsInArea(*this, AABB, 0, Transforms);
  2916.     const FBoxSphereBounds MeshBounds = GetStaticMesh()->GetBounds();
  2917.  
  2918.     for (const FTransform& TM : Transforms)
  2919.     {
  2920.         const FVector Center = TM.GetLocation();
  2921.         const FSphere InstanceSphere(Center, MeshBounds.SphereRadius);
  2922.  
  2923.         if (Sphere.Intersects(InstanceSphere))
  2924.         {
  2925.             ++Count;
  2926.         }
  2927.     }
  2928.  
  2929.     return Count;
  2930. }
  2931.  
  2932. int32 Ufixed_HI_StaticMeshComponent::GetOverlappingBoxCount(const FBox& Box) const
  2933. {
  2934.     TArray<FTransform> Transforms;
  2935.     GatherInstanceTransformsInArea(*this, Box, 0, Transforms);
  2936.  
  2937.     int32 Count = 0;
  2938.     const FBoxSphereBounds MeshBounds = GetStaticMesh()->GetBounds();
  2939.     for (FTransform& T : Transforms)
  2940.     {
  2941.         const FVector Centre = T.GetLocation();
  2942.         const FBox OtherBox(FVector(Centre - MeshBounds.BoxExtent), FVector(Centre + MeshBounds.BoxExtent));
  2943.  
  2944.         if (Box.Intersect(OtherBox))
  2945.         {
  2946.             Count++;
  2947.         }
  2948.     }
  2949.  
  2950.     return Count;
  2951. }
  2952.  
  2953. void Ufixed_HI_StaticMeshComponent::GetOverlappingBoxTransforms(const FBox& Box, TArray<FTransform>& OutTransforms) const
  2954. {
  2955.     GatherInstanceTransformsInArea(*this, Box, 0, OutTransforms);
  2956.  
  2957.     const FBoxSphereBounds MeshBounds = GetStaticMesh()->GetBounds();
  2958.     int32 NumTransforms = OutTransforms.Num();
  2959.     for (int32 Idx = NumTransforms - 1; Idx >= 0; --Idx)
  2960.     {
  2961.         FTransform& TM = OutTransforms[Idx];
  2962.         const FVector Centre = TM.GetLocation();
  2963.         const FBox OtherBox(FVector(Centre - MeshBounds.BoxExtent), FVector(Centre + MeshBounds.BoxExtent));
  2964.  
  2965.         if (!Box.Intersect(OtherBox))
  2966.         {
  2967.             OutTransforms.RemoveAt(Idx);
  2968.         }
  2969.     }
  2970. }
  2971.  
  2972. void Ufixed_HI_StaticMeshComponent::GetNavigationPerInstanceTransforms(const FBox& AreaBox, TArray<FTransform>& InstanceData) const
  2973. {
  2974.     if (IsTreeFullyBuilt())
  2975.     {
  2976.         const TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  2977.         if (ClusterTree.Num())
  2978.         {
  2979.             GatherInstanceTransformsInArea(*this, AreaBox, 0, InstanceData);
  2980.         }
  2981.     }
  2982.     else
  2983.     {
  2984.         // This area should be processed again by navigation system when cluster tree is available
  2985.         // Store smaller tile box in accumulated dirty area, so we will not unintentionally mark as dirty neighbor tiles
  2986.         const FBox SmallTileBox = AreaBox.ExpandBy(-AreaBox.GetExtent() / 2.f);
  2987.         AccumulatedNavigationDirtyArea += SmallTileBox;
  2988.     }
  2989. }
  2990.  
  2991. void Ufixed_HI_StaticMeshComponent::PartialNavigationUpdate(int32 InstanceIdx)
  2992. {
  2993.     if (InstanceIdx == INDEX_NONE)
  2994.     {
  2995.         AccumulatedNavigationDirtyArea.Init();
  2996.         UNavigationSystem::UpdateComponentInNavOctree(*this);
  2997.     }
  2998.     else if (GetStaticMesh())
  2999.     {
  3000.         // Accumulate dirty areas and send them to navigation system once cluster tree is rebuilt
  3001.         UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
  3002.         // Check if this component is registered in navigation system
  3003.         if (NavSys && NavSys->GetObjectsNavOctreeId(this))
  3004.         {
  3005.             FTransform InstanceTransform(PerInstanceSMData[InstanceIdx].Transform);
  3006.             FBox InstanceBox = GetStaticMesh()->GetBounds().TransformBy(InstanceTransform*ComponentToWorld).GetBox(); // in world space
  3007.             AccumulatedNavigationDirtyArea += InstanceBox;
  3008.         }
  3009.     }
  3010. }
  3011.  
  3012. void Ufixed_HI_StaticMeshComponent::FlushAccumulatedNavigationUpdates()
  3013. {
  3014.     if (AccumulatedNavigationDirtyArea.IsValid)
  3015.     {
  3016.         QUICK_SCOPE_CYCLE_COUNTER(STAT_Ufixed_HI_StaticMeshComponent_FlushAccumulatedNavigationUpdates);
  3017.  
  3018.         const TArray<FFixed_ClusterNode>& ClusterTree = *ClusterTreePtr;
  3019.         UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
  3020.         // Check if this component is registered in navigation system
  3021.         if (ClusterTree.Num() && NavSys && NavSys->GetObjectsNavOctreeId(this))
  3022.         {
  3023.             FBox NewBounds = FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax).TransformBy(ComponentToWorld);
  3024.             NavSys->UpdateNavOctreeElementBounds(this, NewBounds, AccumulatedNavigationDirtyArea);
  3025.         }
  3026.  
  3027.         AccumulatedNavigationDirtyArea.Init();
  3028.     }
  3029. }
  3030.  
  3031. // recursive helper to gather all instances with locations inside the specified area. Supply a Filter to exclude leaf nodes based on the instance transform.
  3032. static void GatherInstancesOverlappingArea(const Ufixed_HI_StaticMeshComponent& Component, const FBox& AreaBox, int32 Child, TFunctionRef<bool(const FMatrix&)> Filter, TArray<int32>& OutInstanceIndices)
  3033. {
  3034.     const TArray<FFixed_ClusterNode>& ClusterTree = *Component.ClusterTreePtr;
  3035.     const FFixed_ClusterNode& ChildNode = ClusterTree[Child];
  3036.     const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.ComponentToWorld);
  3037.  
  3038.     if (AreaBox.Intersect(WorldNodeBox))
  3039.     {
  3040.         if (ChildNode.FirstChild < 0 || AreaBox.IsInside(WorldNodeBox))
  3041.         {
  3042.             // Unfortunately ordering of PerInstanceSMData does not match ordering of cluster tree, so we have to use remaping
  3043.             const bool bUseRemaping = Component.SortedInstances.Num() > 0;
  3044.  
  3045.             // In case there no more subdivision or node is completely encapsulated by a area box
  3046.             // add all instances to the result
  3047.             for (int32 i = ChildNode.FirstInstance; i <= ChildNode.LastInstance; ++i)
  3048.             {
  3049.                 int32 SortedIdx = bUseRemaping ? Component.SortedInstances[i] : i;
  3050.                 if (Component.PerInstanceSMData.IsValidIndex(SortedIdx))
  3051.                 {
  3052.                     const FMatrix& Matrix = Component.PerInstanceSMData[SortedIdx].Transform;
  3053.                     if (Filter(Matrix))
  3054.                     {
  3055.                         OutInstanceIndices.Add(SortedIdx);
  3056.                     }
  3057.                 }
  3058.             }
  3059.         }
  3060.         else
  3061.         {
  3062.             for (int32 i = ChildNode.FirstChild; i <= ChildNode.LastChild; ++i)
  3063.             {
  3064.                 GatherInstancesOverlappingArea(Component, AreaBox, i, Filter, OutInstanceIndices);
  3065.             }
  3066.         }
  3067.     }
  3068. }
  3069.  
  3070. TArray<int32> Ufixed_HI_StaticMeshComponent::GetInstancesOverlappingSphere(const FVector& Center, float Radius, bool bSphereInWorldSpace) const
  3071. {
  3072.     if (ClusterTreePtr.IsValid() && ClusterTreePtr->Num())
  3073.     {
  3074.         TArray<int32> Result;
  3075.         FSphere Sphere(Center, Radius);
  3076.  
  3077.         FBox WorldSpaceAABB(Sphere.Center - FVector(Sphere.W), Sphere.Center + FVector(Sphere.W));
  3078.         if (bSphereInWorldSpace)
  3079.         {
  3080.             Sphere = Sphere.TransformBy(ComponentToWorld.Inverse());
  3081.         }
  3082.         else
  3083.         {
  3084.             WorldSpaceAABB = WorldSpaceAABB.TransformBy(ComponentToWorld);
  3085.         }
  3086.  
  3087.         const float StaticMeshBoundsRadius = GetStaticMesh()->GetBounds().SphereRadius;
  3088.         GatherInstancesOverlappingArea(*this, WorldSpaceAABB, 0,
  3089.             [Sphere, StaticMeshBoundsRadius](const FMatrix& InstanceTransform)->bool
  3090.         {
  3091.             FSphere InstanceSphere(InstanceTransform.GetOrigin(), StaticMeshBoundsRadius * InstanceTransform.GetScaleVector().GetMax());
  3092.             return Sphere.Intersects(InstanceSphere);
  3093.         },
  3094.             Result);
  3095.         return Result;
  3096.     }
  3097.     else
  3098.     {
  3099.         return Super::GetInstancesOverlappingSphere(Center, Radius, bSphereInWorldSpace);
  3100.     }
  3101. }
  3102.  
  3103. TArray<int32> Ufixed_HI_StaticMeshComponent::GetInstancesOverlappingBox(const FBox& InBox, bool bBoxInWorldSpace) const
  3104. {
  3105.     if (ClusterTreePtr.IsValid() && ClusterTreePtr->Num())
  3106.     {
  3107.         TArray<int32> Result;
  3108.  
  3109.         FBox WorldSpaceBox(InBox);
  3110.         FBox LocalSpaceSpaceBox(InBox);
  3111.         if (bBoxInWorldSpace)
  3112.         {
  3113.             LocalSpaceSpaceBox = LocalSpaceSpaceBox.TransformBy(ComponentToWorld.Inverse());
  3114.         }
  3115.         else
  3116.         {
  3117.             WorldSpaceBox = WorldSpaceBox.TransformBy(ComponentToWorld);
  3118.         }
  3119.  
  3120.         const FBox StaticMeshBox = GetStaticMesh()->GetBounds().GetBox();
  3121.         GatherInstancesOverlappingArea(*this, WorldSpaceBox, 0,
  3122.             [LocalSpaceSpaceBox, StaticMeshBox](const FMatrix& InstanceTransform)->bool
  3123.         {
  3124.             FBox InstanceBox = StaticMeshBox.TransformBy(InstanceTransform);
  3125.             return LocalSpaceSpaceBox.Intersect(InstanceBox);
  3126.         },
  3127.             Result);
  3128.  
  3129.         return Result;
  3130.     }
  3131.     else
  3132.     {
  3133.         return Super::GetInstancesOverlappingBox(InBox, bBoxInWorldSpace);
  3134.     }
  3135. }
  3136.  
  3137. static void RebuildFoliageTrees(const TArray<FString>& Args)
  3138. {
  3139. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
  3140.     UE_LOG(LogConsoleResponse, Display, TEXT("Rebuild Foliage Trees"));
  3141. #endif
  3142.     for (TObjectIterator<Ufixed_HI_StaticMeshComponent> It; It; ++It)
  3143.     {
  3144.         Ufixed_HI_StaticMeshComponent* Comp = *It;
  3145.         if (Comp && !Comp->IsTemplate() && !Comp->IsPendingKill())
  3146.         {
  3147.             Comp->BuildTree();
  3148.             Comp->MarkRenderStateDirty();
  3149.         }
  3150.     }
  3151. }
  3152.  
  3153. static FAutoConsoleCommand RebuildFoliageTreesCmd(
  3154.     TEXT("foliage.RebuildFoliageTrees"),
  3155.     TEXT("Rebuild the trees for non-grass foliage."),
  3156.     FConsoleCommandWithArgsDelegate::CreateStatic(&RebuildFoliageTrees)
  3157. );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement