11#include "TimerManager.h"
12#include "Materials/Material.h"
13#include "Kismet/GameplayStatics.h"
14#include "Engine/World.h"
20 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT(
"SceneRoot"));
21 RootComponent->SetMobility(EComponentMobility::Static);
22 PrimaryActorTick.bCanEverTick =
true;
30 SetActorEnableCollision(
false);
39 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Instance already exists. Destroying this actor.."));
44 UWorld* World = GetWorld();
62 World->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([
this]
78 Super::EndPlay(EndPlayReason);
89 UWorld* World = GetWorld();
108 if (Entry.InstancedStaticMeshComponent)
110 Entry.InstancedStaticMeshComponent->ClearInstances();
111 Entry.InstancedStaticMeshComponent->UnregisterComponent();
112 Entry.InstancedStaticMeshComponent->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
113 Entry.InstancedStaticMeshComponent->DestroyComponent();
114 Entry.InstancedStaticMeshComponent =
nullptr;
117 Entry.Materials.Empty();
118 Entry.ActorData.Empty();
135 SetActorTickEnabled(
false);
139 for (int32 i = 0; i < NumberOfActorsToUpdate; i++)
145 FTransform CurrentActorTransform = ActorPtr->GetActorTransform();
156 NumberOfActorsToUpdate--;
164 if (InstancedActor ==
nullptr)
167 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Actor is null!"));
173 if (StaticMeshComponent ==
nullptr)
176 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent is null!"), *InstancedActor->GetName());
181 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
185 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent mesh is null!"), *InstancedActor->GetName());
197 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: ComponentIndex is not valid!"));
202 UInstancedStaticMeshComponent* InstancedStaticMeshComponent =
InstanceEntries[ComponentIndex].InstancedStaticMeshComponent;
203 if (!InstancedStaticMeshComponent)
206 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: UInstancedStaticMeshComponent is nullptr!"));
213 InstancedData.
Actor = InstancedActor;
217 FTransform ActorTransform = StaticMeshComponent->GetComponentTransform();
218 InstancedStaticMeshComponent->AddInstance(ActorTransform);
224 InstancedStaticMeshComponent->SetMobility(EComponentMobility::Movable);
228 int32 InstanceIndex = InstancedStaticMeshComponent->GetNumRenderInstances() - 1;
231 InstancedActor->
InstanceAdded(ComponentIndex, InstanceIndex);
240 if (InstancedActor ==
nullptr || StaticMeshComponent ==
nullptr)
243 UE_LOG(LogTemp, Warning, TEXT(
"StaticInstancedRenderer.cpp: StaticMeshComponent or InstancedActor is null!"));
249 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
254 for (int32 Index = 0; Index < num; ++Index)
263 const int count = StaticMeshComponent->GetNumMaterials();
265 TArray<UMaterialInterface*> MeshMaterials;
266 MeshMaterials.Reserve(count);
268 for (int32 i = 0; i < count; i++)
270 MeshMaterials.Add(StaticMeshComponent->GetMaterial(i));
274 for (int32 Index = 0; Index < Size; ++Index)
278 bool bMaterialsMatch =
true;
280 for (int32 MaterialIndex = 0; MaterialIndex <
InstanceEntries[Index].Materials.Num(); ++MaterialIndex)
282 UMaterialInterface* UniqueMeshMaterial =
InstanceEntries[Index].Materials[MaterialIndex];
283 UMaterialInterface* MeshMaterial = MeshMaterials[MaterialIndex];
284 if (UniqueMeshMaterial != MeshMaterial)
286 bMaterialsMatch =
false;
301 UInstancedStaticMeshComponent* InstancedStaticMeshComponent = NewObject<UInstancedStaticMeshComponent>(
this);
302 InstancedStaticMeshComponent->RegisterComponent();
303 InstancedStaticMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
304 InstancedStaticMeshComponent->CreatePhysicsState(
false);
305 InstancedStaticMeshComponent->SetSimulatePhysics(
false);
306 InstancedStaticMeshComponent->SetStaticMesh(Mesh);
307 InstancedStaticMeshComponent->SetMobility(EComponentMobility::Static);
308 InstancedStaticMeshComponent->SetHiddenInGame(
false);
309 InstancedStaticMeshComponent->SetVisibility(
true);
310 InstancedStaticMeshComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
323 GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([
this, InstancedStaticMeshComponent, AllowWorldPositionOffsetDisable]
327 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(false);
328 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(false);
336 InstancedStaticMeshComponent->SetRenderCustomDepth(
true);
337 InstancedStaticMeshComponent->SetCustomDepthStencilValue(StaticMeshComponent->CustomDepthStencilValue);
341 InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = EShadowCacheInvalidationBehavior::Rigid;
345 InstanceEntry.
Mesh = Mesh;
348 InstanceEntry.
MeshName = Mesh->GetName();
353 const int32 MaterialCount = MeshMaterials.Num();
354 for (int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex)
356 UMaterialInterface* MaterialInterface = InstanceEntry.
Materials[MaterialIndex];
358 if (MaterialInterface)
360 InstancedStaticMeshComponent->SetMaterial(MaterialIndex, MaterialInterface);
364 UMaterial* Material = Cast<UMaterial>(MaterialInterface);
367 if (!Material->bUsedWithInstancedStaticMeshes)
369 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Material '%s' bUsedWithInstancedStaticMeshes is not set to true!"), *Material->GetName());
391 InstancedData.
Actor = InstancedActor;
396 SetActorTickEnabled(
true);
403 return Data.Actor == InstancedActor;
445 if (InstanceNumber >= 0 && InstanceNumber < InstancedActors.Num())
448 AInstancedActor* InstanceToRemove = InstancedActors[InstanceNumber].Actor.Get();
449 if (InstanceToRemove)
451 InstancedActors.RemoveAt(InstanceNumber);
455 for (int32 i = 0; i < InstancedActors.Num(); i++)
474 if (TransformA.GetTranslation() != TransformB.GetTranslation())
479 if (TransformA.GetRotation() != TransformB.GetRotation())
484 if (TransformA.GetScale3D() != TransformB.GetScale3D())
498 if (Entry.InstancedStaticMeshComponent)
500 Entry.InstancedStaticMeshComponent->SetVisibility(
Rendering);
505 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Rendering: %s"), (
Rendering ? TEXT(
"true") : TEXT(
"false")));
514 UE_LOG(LogTemp, Warning, TEXT(
"InstancedRenderer.cpp: Index %d is not valid!"), Index);
550 if (Entry.InstancedStaticMeshComponent)
552 Entry.InstancedStaticMeshComponent->SetRenderCustomDepth(Enabled);
568 if (Entry.InstancedStaticMeshComponent)
579 if (Entry.InstancedStaticMeshComponent)
581 Entry.InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = ShadowCacheInvalidationBehaviour;
590 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
592 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(RenderWPO);
593 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(RenderWPO);
600 UMaterialInterface* DefaultMaterial =
nullptr;
601 if (SetUnrealDefaultMaterial)
603 DefaultMaterial = UMaterial::GetDefaultMaterial(EMaterialDomain(0));
608 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
610 if (SetUnrealDefaultMaterial)
612 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
614 UMaterialInterface* CurrentMaterial = Entry.InstancedStaticMeshComponent->GetMaterial(i);
615 Entry.Materials.Add(CurrentMaterial);
617 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
619 Entry.InstancedStaticMeshComponent->SetMaterial(i, DefaultMaterial);
624 if (Entry.Materials.Num() > 0)
626 for (int32 i = 0; i < Entry.Materials.Num(); ++i)
628 UMaterialInterface* OriginalMaterial = Entry.Materials[i];
629 Entry.InstancedStaticMeshComponent->SetMaterial(i, OriginalMaterial);
int GetInstanceIndex() const
bool UpdateTransformAutomatically() const
void InstanceAdded(int32 CompIndex, int32 InstanceNum)
int GetInstanceEndCullDistance() const
FTransform GetPreviousTransform() const
int GetInstanceStartCullDistance() const
void UpdateIndex(int32 UpdatedIndex)
bool HasAlternativeMaterial() const
int GetComponentIndex() const
void UpdatePreviousTransform(const FTransform &NewTransform)
UStaticMeshComponent * GetStaticMeshComponent() const
bool GetAllowWorldPositionOffsetDisable() const
bool AddActorToInstancedRendering(AInstancedActor *InstancedActor)
void RemoveInstance(int32 ComponentIndex, int32 InstanceNumber)
void OnWeatherParametersChanged(FWeatherParameters WeatherParameters)
void SetShadowCacheBehaviour(EShadowCacheInvalidationBehavior ShadowCacheInvalidationBehaviour)
void EndPlay(const EEndPlayReason::Type EndPlayReason) override
void UpdateInstanceTransform(int32 ComponentIndex, int32 InstanceNumber, const FTransform &NewTransform)
void SetInstancedRendering(bool ShouldRender)
void AddOrRemoveActorFromAutomaticTransformUpdates(bool Add, AInstancedActor *InstancedActor)
void BeginPlay() override
bool AreTransformsEqual(const FTransform &TransformA, const FTransform &TransformB) const
void OnGraphicsSettingsChanged(FGlobalGraphicsSettings GraphicsSettings)
TArray< FInstanceEntry > InstanceEntries
void SetWorldPositionOffsetDistance(int32 NewWPODistance)
void SetRenderWorldPositionOffet(bool RenderWPO)
FWeatherParameters CurrentWeatherParameters
int32 FindOrAddUniqueMesh(UStaticMeshComponent *StaticMeshComponent, AInstancedActor *InstancedActor)
std::vector< FInstancedActorData > InstancedActorsToUpdate
void Tick(float DeltaTime) override
int32 WorldPositionOffsetDistance
void SetRenderCustomDepth(bool Enabled)
AInstancedRenderer(const FObjectInitializer &ObjectInitializer)
void DebugMaterialImpact(bool SetUnrealDefaultMaterial)
void SetComponentIndexVisibility(int32 Index, bool Visible)
static AInstancedRenderer * Instance
void UpdateInstancedActors()
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
bool AllowWorldPositionOffsetDisable
UInstancedStaticMeshComponent * InstancedStaticMeshComponent
TWeakObjectPtr< AInstancedActor > Actor