11#include "UObject/ConstructorHelpers.h"
12#include "Kismet/GameplayStatics.h"
13#include "Materials/Material.h"
14#include "TimerManager.h"
15#include "Engine/World.h"
21 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT(
"SceneRoot"));
22 RootComponent->SetMobility(EComponentMobility::Static);
23 PrimaryActorTick.bCanEverTick =
false;
26 static ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultMesh(TEXT(
"/Engine/BasicShapes/Cube.Cube"));
27 if (DefaultMesh.Succeeded())
37 SetActorEnableCollision(
false);
46 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Instance already exists. Destroying this actor.."));
51 UWorld* World = GetWorld();
69 World->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([
this]
85 Super::EndPlay(EndPlayReason);
96 UWorld* World = GetWorld();
113 if (Entry.InstancedStaticMeshComponent)
115 Entry.InstancedStaticMeshComponent->ClearInstances();
116 Entry.InstancedStaticMeshComponent->UnregisterComponent();
117 Entry.InstancedStaticMeshComponent->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
118 Entry.InstancedStaticMeshComponent->DestroyComponent();
119 Entry.InstancedStaticMeshComponent =
nullptr;
122 Entry.Materials.Empty();
131 if (InstancedActor ==
nullptr)
134 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Actor is null!"));
140 if (StaticMeshComponent ==
nullptr)
143 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent is null!"), *InstancedActor->GetName());
148 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
152 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent mesh is null!"), *InstancedActor->GetName());
164 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: ComponentIndex is not valid!"));
169 UInstancedStaticMeshComponent* InstancedStaticMeshComponent =
InstanceEntries[ComponentIndex].InstancedStaticMeshComponent;
170 if (!InstancedStaticMeshComponent)
173 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: UInstancedStaticMeshComponent is nullptr!"));
179 FTransform ActorTransform = StaticMeshComponent->GetComponentTransform();
180 InstancedStaticMeshComponent->AddInstance(ActorTransform);
182 int32 InstanceIndex = InstancedStaticMeshComponent->GetNumRenderInstances() - 1;
185 InstancedActor->
InstanceAdded(ComponentIndex, InstanceIndex);
195 if (InstancedActor ==
nullptr || StaticMeshComponent ==
nullptr)
198 UE_LOG(LogTemp, Warning, TEXT(
"StaticInstancedRenderer.cpp: StaticMeshComponent or InstancedActor is null!"));
204 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
209 for (int32 Index = 0; Index < num; ++Index)
218 const int count = StaticMeshComponent->GetNumMaterials();
220 TArray<UMaterialInterface*> MeshMaterials;
221 MeshMaterials.Reserve(count);
223 for (int32 i = 0; i < count; i++)
225 MeshMaterials.Add(StaticMeshComponent->GetMaterial(i));
229 for (int32 Index = 0; Index < Size; ++Index)
233 bool bMaterialsMatch =
true;
235 for (int32 MaterialIndex = 0; MaterialIndex <
InstanceEntries[Index].Materials.Num(); ++MaterialIndex)
237 UMaterialInterface* UniqueMeshMaterial =
InstanceEntries[Index].Materials[MaterialIndex];
238 UMaterialInterface* MeshMaterial = MeshMaterials[MaterialIndex];
239 if (UniqueMeshMaterial != MeshMaterial)
241 bMaterialsMatch =
false;
256 UInstancedStaticMeshComponent* InstancedStaticMeshComponent = NewObject<UInstancedStaticMeshComponent>(
this);
259 InstancedStaticMeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
260 AddInstanceComponent(InstancedStaticMeshComponent);
262 InstancedStaticMeshComponent->bEditableWhenInherited =
false;
263 InstancedStaticMeshComponent->RegisterComponent();
264 InstancedStaticMeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
265 InstancedStaticMeshComponent->CreatePhysicsState(
false);
266 InstancedStaticMeshComponent->SetSimulatePhysics(
false);
267 InstancedStaticMeshComponent->SetStaticMesh(Mesh);
268 InstancedStaticMeshComponent->SetMobility(EComponentMobility::Static);
269 InstancedStaticMeshComponent->SetHiddenInGame(
false);
270 InstancedStaticMeshComponent->SetVisibility(
true);
271 InstancedStaticMeshComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
284 GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([
this, InstancedStaticMeshComponent, AllowWorldPositionOffsetDisable]
288 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(false);
289 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(false);
297 InstancedStaticMeshComponent->SetRenderCustomDepth(
true);
298 InstancedStaticMeshComponent->SetCustomDepthStencilValue(StaticMeshComponent->CustomDepthStencilValue);
302 InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = EShadowCacheInvalidationBehavior::Rigid;
307 InstanceEntry.
ActorClass = InstancedActor->GetClass();
308 InstanceEntry.
Mesh = Mesh;
316 const int32 MaterialCount = MeshMaterials.Num();
317 for (int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex)
319 UMaterialInterface* MaterialInterface = InstanceEntry.
Materials[MaterialIndex];
321 if (MaterialInterface)
323 InstancedStaticMeshComponent->SetMaterial(MaterialIndex, MaterialInterface);
327 UMaterial* Material = Cast<UMaterial>(MaterialInterface);
330 if (!Material->bUsedWithInstancedStaticMeshes)
332 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Material '%s' bUsedWithInstancedStaticMeshes is not set to true!"), *Material->GetName());
381 if (Entry.InstancedStaticMeshComponent)
383 Entry.InstancedStaticMeshComponent->SetVisibility(
Rendering);
388 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Rendering: %s"), (
Rendering ? TEXT(
"true") : TEXT(
"false")));
397 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Index %d is not valid!"), Index);
433 if (Entry.InstancedStaticMeshComponent)
435 Entry.InstancedStaticMeshComponent->SetRenderCustomDepth(Enabled);
451 if (Entry.InstancedStaticMeshComponent)
462 if (Entry.InstancedStaticMeshComponent)
464 Entry.InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = ShadowCacheInvalidationBehaviour;
473 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
475 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(RenderWPO);
476 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(RenderWPO);
483 UMaterialInterface* DefaultMaterial =
nullptr;
484 if (SetUnrealDefaultMaterial)
486 DefaultMaterial = UMaterial::GetDefaultMaterial(EMaterialDomain(0));
491 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
493 if (SetUnrealDefaultMaterial)
495 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
497 UMaterialInterface* CurrentMaterial = Entry.InstancedStaticMeshComponent->GetMaterial(i);
498 Entry.Materials.Add(CurrentMaterial);
500 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
502 Entry.InstancedStaticMeshComponent->SetMaterial(i, DefaultMaterial);
507 if (Entry.Materials.Num() > 0)
509 for (int32 i = 0; i < Entry.Materials.Num(); ++i)
511 UMaterialInterface* OriginalMaterial = Entry.Materials[i];
512 Entry.InstancedStaticMeshComponent->SetMaterial(i, OriginalMaterial);
525 auto& ISMComponent = Entry.InstancedStaticMeshComponent;
529 if (!Entry.UsingProxy)
531 ISMComponent->SetStaticMesh(
ProxyMesh.Get());
532 Entry.UsingProxy =
true;
536 ISMComponent->SetStaticMesh(Entry.Mesh.Get());
537 Entry.UsingProxy =
false;
547 UWorld* World = GetWorld();
556 UInstancedStaticMeshComponent* ISMComponent = Entry.InstancedStaticMeshComponent;
562 ISMComponent->SetVisibility(
false);
565 TArray<FTransform> Transforms;
567 const int32 InstanceCount = ISMComponent->GetInstanceCount();
569 for (int32 i = 0; i < InstanceCount; i++)
572 ISMComponent->GetInstanceTransform(i,
Transform);
577 UClass* Class = Entry.ActorClass;
578 for (
const FTransform&
Transform : Transforms)
580 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(Class,
Transform);
587 ISMComponent->DestroyComponent();
596 if (!ISM || Index < 0 || Index >= ISM->GetInstanceCount())
601 UWorld* World = GetWorld();
608 FTransform InstanceTransform;
609 ISM->GetInstanceTransform(Index, InstanceTransform);
629 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(ActorClass, InstanceTransform);
638 SpawnedActor->FinishSpawning(InstanceTransform);
641 return ISM->RemoveInstance(Index);
bool AddToInstancedRenderer
void InstanceAdded(int32 CompIndex, int32 InstanceNum)
int GetInstanceEndCullDistance() const
int GetInstanceStartCullDistance() const
bool HasAlternativeMaterial() const
UStaticMeshComponent * GetStaticMeshComponent() const
bool GetAllowWorldPositionOffsetDisable() const
TWeakObjectPtr< UStaticMesh > ProxyMesh
bool AddActorToInstancedRendering(AInstancedActor *InstancedActor)
void RemoveInstance(int32 ComponentIndex, int32 InstanceNumber)
void OnWeatherParametersChanged(FWeatherParameters WeatherParameters)
void SpawnAllInstancesBackActors()
void SetShadowCacheBehaviour(EShadowCacheInvalidationBehavior ShadowCacheInvalidationBehaviour)
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
void UpdateInstanceTransform(int32 ComponentIndex, int32 InstanceNumber, const FTransform &NewTransform)
void SetInstancedRendering(bool ShouldRender)
virtual void BeginPlay() override
void OnGraphicsSettingsChanged(FGlobalGraphicsSettings GraphicsSettings)
bool SpawnInstanceBackToActor(UInstancedStaticMeshComponent *ISM, int32 Index)
TArray< FInstanceEntry > InstanceEntries
void SetWorldPositionOffsetDistance(int32 NewWPODistance)
void SetRenderWorldPositionOffet(bool RenderWPO)
FWeatherParameters CurrentWeatherParameters
int32 FindOrAddUniqueMesh(UStaticMeshComponent *StaticMeshComponent, AInstancedActor *InstancedActor)
int32 WorldPositionOffsetDistance
void SetRenderCustomDepth(bool Enabled)
AInstancedRenderer(const FObjectInitializer &ObjectInitializer)
void DebugMaterialImpact(bool SetUnrealDefaultMaterial)
void SetComponentIndexVisibility(int32 Index, bool Visible)
static AInstancedRenderer * Instance
const FWeatherParameters & GetCurrentWeather() const
FLevelEventDelegate_WeatherChanged OnWeatherChanged
int32 GetWorldPositionOffsetRenderDistance() const
FGraphicsSettingsDelegate OnGraphicsSettingsChanged
static UAgrarsenseSettings * GetAgrarsenseSettings()
static AWeather * GetWeatherActor(const UObject *WorldContextObject)
int32 WorldPositionOffsetDistance
EShadowCacheInvalidationBehavior FoliageShadowCacheInvalidationBehaviour
TWeakObjectPtr< UStaticMesh > Mesh
TArray< UMaterialInterface * > Materials
int32 CustomDepthStencilValue
bool AllowWorldPositionOffsetDisable
TSubclassOf< AActor > ActorClass
UInstancedStaticMeshComponent * InstancedStaticMeshComponent