Agrarsense
Public Member Functions | Static Public Member Functions | Protected Attributes | Private Member Functions | Private Attributes | Static Private Attributes | List of all members
AInstancedRenderer Class Reference

#include <InstancedRenderer.h>

Inheritance diagram for AInstancedRenderer:
Inheritance graph
[legend]
Collaboration diagram for AInstancedRenderer:
Collaboration graph
[legend]

Public Member Functions

 AInstancedRenderer (const FObjectInitializer &ObjectInitializer)
 
bool AddActorToInstancedRendering (AInstancedActor *InstancedActor)
 
void RemoveInstance (int32 ComponentIndex, int32 InstanceNumber)
 
void UpdateInstanceTransform (int32 ComponentIndex, int32 InstanceNumber, const FTransform &NewTransform)
 
bool IsRendering () const
 
int32 GetTotalInstanceCount () const
 
int32 GetUniqueInstancesCount () const
 
TArray< FInstanceEntryGetInstanceEntries () const
 
void SetInstancedRendering (bool ShouldRender)
 
void SetComponentIndexVisibility (int32 Index, bool Visible)
 
void SetRenderCustomDepth (bool Enabled)
 
void SetWorldPositionOffsetDistance (int32 NewWPODistance)
 
void SetShadowCacheBehaviour (EShadowCacheInvalidationBehavior ShadowCacheInvalidationBehaviour)
 
void SetRenderWorldPositionOffet (bool RenderWPO)
 
void LogInfo () const
 
void DebugMaterialImpact (bool SetUnrealDefaultMaterial)
 
void ToggleProxyMesh ()
 
void SpawnAllInstancesBackActors ()
 
void UpdateRenderDistances ()
 
void DestroyOverlappingInstancesBox (UInstancedStaticMeshComponent *ISM, FBox AreaBox, bool OnlyTrees)
 
bool SpawnInstanceBackToActor (UInstancedStaticMeshComponent *ISM, int32 Index, bool OnlyTree)
 

Static Public Member Functions

static AInstancedRendererGet ()
 

Protected Attributes

TArray< FInstanceEntryInstanceEntries
 
TArray< UInstancedStaticMeshComponent * > InstancesStaticMeshComponents
 
int32 TotalInstanceCount = 0
 

Private Member Functions

virtual void BeginPlay () override
 
virtual void EndPlay (const EEndPlayReason::Type EndPlayReason) override
 
void OnGraphicsSettingsChanged (FGlobalGraphicsSettings GraphicsSettings)
 
void OnWeatherParametersChanged (FWeatherParameters WeatherParameters)
 
bool FindOrAddUniqueMesh (UStaticMeshComponent *StaticMeshComponent, AInstancedActor *InstancedActor, int32 &InstanceNum)
 

Private Attributes

TWeakObjectPtr< UStaticMesh > CubeMesh
 
int32 WorldPositionOffsetDistance = 30000
 
FWeatherParameters CurrentWeatherParameters
 
bool Rendering = true
 
bool RenderingWPO = false
 

Static Private Attributes

static AInstancedRendererInstance = nullptr
 

Detailed Description

This Actor is responsible for managing all Instanced Static Mesh Components in the level.

The way this works is by creating blueprint based on AInstancedActor in Unreal Editor, setup the desired mesh and material in the blueprint and placing them in the level in any way. Then at runtime (AInstancedActor BeginPlay), its Mesh and Material is added to this Renderer.

Or you can setup AInstancedActor based actors in your level and then go to BP_InstancedRenderer Actor and click "AddExistingActorsToRenderer" button to turn AInstancedActors into BP_InstancedRenderer ISM instances in Editor. This reduces the amount of Actors in the level and should speed up loading and Editor play times.

AInstancedActors marked as "TreeActor" can be turned back into regular Actor at runtime when vehicle gets close.

Note. Mesh material(s) need to have bUsedWithInstancedStaticMeshes set to True to work with UInstancedStaticMeshComponent.

Definition at line 76 of file InstancedRenderer.h.

Constructor & Destructor Documentation

◆ AInstancedRenderer()

AInstancedRenderer::AInstancedRenderer ( const FObjectInitializer &  ObjectInitializer)

Definition at line 22 of file InstancedRenderer.cpp.

23 : Super(ObjectInitializer)
24{
25 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
26 RootComponent->SetMobility(EComponentMobility::Static);
27 PrimaryActorTick.bCanEverTick = false;
28
29 // Load a default cube mesh asset
30 static ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultMesh(TEXT("/Engine/BasicShapes/Cube.Cube"));
31 if (DefaultMesh.Succeeded())
32 {
33 CubeMesh = DefaultMesh.Object;
34 }
35}
TWeakObjectPtr< UStaticMesh > CubeMesh

References CubeMesh.

Member Function Documentation

◆ AddActorToInstancedRendering()

bool AInstancedRenderer::AddActorToInstancedRendering ( AInstancedActor InstancedActor)

Definition at line 138 of file InstancedRenderer.cpp.

139{
140 if (!InstancedActor)
141 {
142#if WITH_EDITOR
143 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Actor is null!"));
144#endif
145 return false;
146 }
147
148 if (InstancedActor->UpdateTransformAutomatically())
149 {
150#if WITH_EDITOR
151 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: AInstancedActor %s is set to update transform automatically."), *InstancedActor->GetName());
152#endif
153 return false;
154 }
155
156 UStaticMeshComponent* StaticMeshComponent = InstancedActor->GetStaticMeshComponent();
157 if (!StaticMeshComponent)
158 {
159#if WITH_EDITOR
160 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent is null!"), *InstancedActor->GetName());
161#endif
162 return false;
163 }
164
165 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
166 if (!Mesh)
167 {
168#if WITH_EDITOR
169 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: AInstancedActor %s UStaticMeshComponent mesh is null!"), *InstancedActor->GetName());
170#endif
171 return false;
172 }
173
174 int32 ComponentIndex = 9999;
175
176 // Find or create InstancedStaticMeshComponents array index for this instance
177 bool Found = FindOrAddUniqueMesh(StaticMeshComponent, InstancedActor, ComponentIndex);
178
179 if (!Found || !InstanceEntries.IsValidIndex(ComponentIndex))
180 {
181#if WITH_EDITOR
182 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: ComponentIndex is not valid!"));
183#endif
184 return false;
185 }
186
187 UInstancedStaticMeshComponent* InstancedStaticMeshComponent = InstanceEntries[ComponentIndex].InstancedStaticMeshComponent;
188 if (!InstancedStaticMeshComponent)
189 {
190#if WITH_EDITOR
191 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: UInstancedStaticMeshComponent is nullptr!"));
192#endif
193 return false;
194 }
195
196 // Get the StaticMeshComponent transform and add instance
197 FTransform ActorTransform = StaticMeshComponent->GetComponentTransform();
198 InstancedStaticMeshComponent->AddInstance(ActorTransform);
199
200 int32 InstanceIndex = InstancedStaticMeshComponent->GetNumRenderInstances() - 1;
201
202 // Notify the actor that instance has been added successfully.
203 InstancedActor->InstanceAdded(ComponentIndex, InstanceIndex);
204 // InstancedActor->Destroy();
205
207
208 return true;
209}
bool UpdateTransformAutomatically() const
void InstanceAdded(int32 CompIndex, int32 InstanceNum)
UStaticMeshComponent * GetStaticMeshComponent() const
bool FindOrAddUniqueMesh(UStaticMeshComponent *StaticMeshComponent, AInstancedActor *InstancedActor, int32 &InstanceNum)
TArray< FInstanceEntry > InstanceEntries

References FindOrAddUniqueMesh(), AInstancedActor::GetStaticMeshComponent(), AInstancedActor::InstanceAdded(), InstanceEntries, TotalInstanceCount, and AInstancedActor::UpdateTransformAutomatically().

Referenced by AInstancedActor::AddToInstancedRendering().

◆ BeginPlay()

void AInstancedRenderer::BeginPlay ( )
overrideprivatevirtual

Definition at line 37 of file InstancedRenderer.cpp.

38{
39 Super::BeginPlay();
40
41 // SetActorEnableCollision(false);
42
43 if (Instance == nullptr)
44 {
45 Instance = this;
46 }
47 else
48 {
49#if WITH_EDITOR
50 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Instance already exists. Destroying this actor.."));
51#endif
52 Destroy();
53 }
54
55 UWorld* World = GetWorld();
56
58 if (Settings)
59 {
62 }
63
65 if (Weather)
66 {
69 }
70
71#if WITH_EDITOR
72 FTimerHandle Handle;
73 World->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([this] {
74 LogInfo();
75 }),
76 1.0f, false);
77
78 if (!InstanceEntries.IsEmpty() && InstanceEntries[0].UsingProxy)
79 {
81 }
82#endif
83}
void OnWeatherParametersChanged(FWeatherParameters WeatherParameters)
void OnGraphicsSettingsChanged(FGlobalGraphicsSettings GraphicsSettings)
FWeatherParameters CurrentWeatherParameters
static AInstancedRenderer * Instance
const FWeatherParameters & GetCurrentWeather() const
Definition: Weather.h:76
FLevelEventDelegate_WeatherChanged OnWeatherChanged
Definition: Weather.h:85
int32 GetWorldPositionOffsetRenderDistance() const
FGraphicsSettingsDelegate OnGraphicsSettingsChanged
static UAgrarsenseSettings * GetAgrarsenseSettings()
static AWeather * GetWeatherActor(const UObject *WorldContextObject)

References CurrentWeatherParameters, Destroy, UAgrarsenseStatics::GetAgrarsenseSettings(), AWeather::GetCurrentWeather(), UAgrarsenseStatics::GetWeatherActor(), UAgrarsenseSettings::GetWorldPositionOffsetRenderDistance(), Instance, InstanceEntries, LogInfo(), OnGraphicsSettingsChanged(), UAgrarsenseSettings::OnGraphicsSettingsChanged, AWeather::OnWeatherChanged, OnWeatherParametersChanged(), ToggleProxyMesh(), and WorldPositionOffsetDistance.

◆ DebugMaterialImpact()

void AInstancedRenderer::DebugMaterialImpact ( bool  SetUnrealDefaultMaterial)

Definition at line 534 of file InstancedRenderer.cpp.

535{
536 UMaterialInterface* DefaultMaterial = nullptr;
537 if (SetUnrealDefaultMaterial)
538 {
539 DefaultMaterial = UMaterial::GetDefaultMaterial(EMaterialDomain(0));
540 }
541
542 for (FInstanceEntry& Entry : InstanceEntries)
543 {
544 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
545 {
546 if (SetUnrealDefaultMaterial)
547 {
548 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
549 {
550 UMaterialInterface* CurrentMaterial = Entry.InstancedStaticMeshComponent->GetMaterial(i);
551 Entry.Materials.Add(CurrentMaterial);
552 }
553 for (int32 i = 0; i < Entry.InstancedStaticMeshComponent->GetNumMaterials(); ++i)
554 {
555 Entry.InstancedStaticMeshComponent->SetMaterial(i, DefaultMaterial);
556 }
557 }
558 else
559 {
560 if (Entry.Materials.Num() > 0)
561 {
562 for (int32 i = 0; i < Entry.Materials.Num(); ++i)
563 {
564 UMaterialInterface* OriginalMaterial = Entry.Materials[i];
565 Entry.InstancedStaticMeshComponent->SetMaterial(i, OriginalMaterial);
566 }
567 }
568 }
569 }
570 }
571}

References InstanceEntries.

◆ DestroyOverlappingInstancesBox()

void AInstancedRenderer::DestroyOverlappingInstancesBox ( UInstancedStaticMeshComponent *  ISM,
FBox  AreaBox,
bool  OnlyTrees 
)

Destroys all instances overlapping the specified Box area.

Parameters
ISM- The instanced static mesh component.
AreaBox- The bounding box defining the area to check.
OnlyTrees- Whether to limit destruction to tree instances only.

Definition at line 738 of file InstancedRenderer.cpp.

739{
740 // Check incoming ISM exists in InstanceEntries
741 FInstanceEntry* Entry = InstanceEntries.FindByPredicate([ISM](const FInstanceEntry& InEntry) {
742 return InEntry.InstancedStaticMeshComponent == ISM;
743 });
744
745 if (!Entry || (!Entry->IsTree && OnlyTrees))
746 {
747 return;
748 }
749
750 // Remove all instances that overlap incoming AreaBox bounds
751 if (UInstancedStaticMeshComponent* Comp = Entry->InstancedStaticMeshComponent)
752 {
753 TArray<int32> OverlappingInstances = Comp->GetInstancesOverlappingBox(AreaBox);
754 for (int32 InstanceIndex : OverlappingInstances)
755 {
756 Comp->RemoveInstance(InstanceIndex);
757 }
758 }
759}
UInstancedStaticMeshComponent * InstancedStaticMeshComponent

References FInstanceEntry::InstancedStaticMeshComponent, InstanceEntries, and FInstanceEntry::IsTree.

Referenced by ADeletionVolume::DestroyOverlappingActors().

◆ EndPlay()

void AInstancedRenderer::EndPlay ( const EEndPlayReason::Type  EndPlayReason)
overrideprivatevirtual

Definition at line 92 of file InstancedRenderer.cpp.

93{
94 Super::EndPlay(EndPlayReason);
95
96 if (Instance == this)
97 {
98 Instance = nullptr;
99 }
100 else
101 {
102 return;
103 }
104
105 UWorld* World = GetWorld();
106
108 if (Settings)
109 {
111 }
112
114 if (Weather)
115 {
117 }
118
119 // Destroy all Instanced entries
120 for (FInstanceEntry& Entry : InstanceEntries)
121 {
122 if (Entry.InstancedStaticMeshComponent)
123 {
124 Entry.InstancedStaticMeshComponent->ClearInstances();
125 Entry.InstancedStaticMeshComponent->UnregisterComponent();
126 Entry.InstancedStaticMeshComponent->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
127 Entry.InstancedStaticMeshComponent->DestroyComponent();
128 Entry.InstancedStaticMeshComponent = nullptr;
129 }
130
131 Entry.Materials.Empty();
132 Entry.Mesh.Reset();
133 }
134
135 InstanceEntries.Empty();
136}

References UAgrarsenseStatics::GetAgrarsenseSettings(), UAgrarsenseStatics::GetWeatherActor(), Instance, InstanceEntries, OnGraphicsSettingsChanged(), UAgrarsenseSettings::OnGraphicsSettingsChanged, AWeather::OnWeatherChanged, and OnWeatherParametersChanged().

◆ FindOrAddUniqueMesh()

bool AInstancedRenderer::FindOrAddUniqueMesh ( UStaticMeshComponent *  StaticMeshComponent,
AInstancedActor InstancedActor,
int32 &  InstanceNum 
)
private

Definition at line 211 of file InstancedRenderer.cpp.

212{
213 if (InstancedActor == nullptr || StaticMeshComponent == nullptr)
214 {
215#if WITH_EDITOR
216 UE_LOG(LogTemp, Warning, TEXT("StaticInstancedRenderer.cpp: StaticMeshComponent or InstancedActor is null!"));
217#endif
218 return false;
219 }
220
221 UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
222
223 if (!InstancedActor->HasAlternativeMaterial())
224 {
225 const int32 Num = InstanceEntries.Num();
226 for (int32 Index = 0; Index < Num; ++Index)
227 {
228 if (InstanceEntries[Index].Mesh == Mesh)
229 {
230 InstanceNum = Index;
231 return true;
232 }
233 }
234 }
235
236 const int32 NumberOfMaterials = StaticMeshComponent->GetNumMaterials();
237
238 TArray<UMaterialInterface*> MeshMaterials;
239 MeshMaterials.Reserve(NumberOfMaterials);
240
241 for (int32 i = 0; i < NumberOfMaterials; i++)
242 {
243 MeshMaterials.Add(StaticMeshComponent->GetMaterial(i));
244 }
245
246 const int Size = InstanceEntries.Num();
247 for (int32 Index = 0; Index < Size; ++Index)
248 {
249 if (InstanceEntries[Index].Mesh == Mesh)
250 {
251 bool bMaterialsMatch = true;
252
253 for (int32 MaterialIndex = 0; MaterialIndex < InstanceEntries[Index].Materials.Num(); ++MaterialIndex)
254 {
255 UMaterialInterface* UniqueMeshMaterial = InstanceEntries[Index].Materials[MaterialIndex];
256 UMaterialInterface* MeshMaterial = MeshMaterials[MaterialIndex];
257 if (UniqueMeshMaterial != MeshMaterial)
258 {
259 bMaterialsMatch = false;
260 }
261 }
262
263 if (bMaterialsMatch)
264 {
265 InstanceNum = Index;
266 return true;
267 }
268 }
269 }
270
271 // Else this is completely new mesh and/or mesh with alternative material,
272 // we need to create new FInstanceEntry and UInstancedStaticMeshComponent for it
273
274 // Create and setup new UInstancedStaticMeshComponent
275 UInstancedStaticMeshComponent* InstancedStaticMeshComponent = NewObject<UInstancedStaticMeshComponent>(this);
276
277 UClass* ClassPtr = InstancedActor->GetClass();
278
279 FString Name = IInteractable::Execute_GetInteractableName(InstancedActor).ToString();
280
281 if (Name.IsEmpty())
282 {
283 Name = ClassPtr->GetAuthoredName();
284 if (Name.EndsWith(TEXT("_C")))
285 {
286 Name = Name.LeftChop(2);
287 }
288 if (Name.StartsWith(TEXT("BP_")))
289 {
290 Name = Name.RightChop(3);
291 }
292 Name.ReplaceInline(TEXT("_"), TEXT(" "));
293 Name.ReplaceInline(TEXT("Instanced"), TEXT(" "));
294 }
295
296 // Generate a 4-character GUID
297 FString Guid = FGuid::NewGuid().ToString().Left(4);
298
299 Name = FString::Printf(TEXT("%s(_%s_)"), *Name, *Guid);
300
301 InstancedStaticMeshComponent->Rename(*Name);
302
303 // Add Actor component list
304 InstancedStaticMeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
305 AddInstanceComponent(InstancedStaticMeshComponent);
306
307 InstancedStaticMeshComponent->bEditableWhenInherited = false;
308 InstancedStaticMeshComponent->RegisterComponent();
309 InstancedStaticMeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
310 InstancedStaticMeshComponent->CreatePhysicsState(false);
311 InstancedStaticMeshComponent->SetSimulatePhysics(false);
312 InstancedStaticMeshComponent->SetStaticMesh(Mesh);
313 InstancedStaticMeshComponent->SetMobility(EComponentMobility::Static);
314 InstancedStaticMeshComponent->SetHiddenInGame(false);
315 InstancedStaticMeshComponent->SetVisibility(true);
316 InstancedStaticMeshComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
317 InstancedStaticMeshComponent->InstanceStartCullDistance = InstancedActor->GetInstanceStartCullDistance();
318 InstancedStaticMeshComponent->InstanceEndCullDistance = InstancedActor->GetInstanceEndCullDistance();
319
320 // Set WPO distance and evaluation
321 InstancedStaticMeshComponent->SetWorldPositionOffsetDisableDistance(WorldPositionOffsetDistance);
322 /*InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(true);
323 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(true);*/
324
325 bool AllowWorldPositionOffsetDisable = InstancedActor->GetAllowWorldPositionOffsetDisable();
326
327 // For whatever reason this only works when done a bit later..
328 FTimerHandle Handle;
329 GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([this, InstancedStaticMeshComponent, AllowWorldPositionOffsetDisable] {
330 if (InstancedStaticMeshComponent && AllowWorldPositionOffsetDisable && CurrentWeatherParameters.WindIntensity < 0.05f)
331 {
332 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(false);
333 InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(false);
334 }
335 }),
336 0.350f, false);
337
338 // Thermal and Semantic camera use custom depth.
339 // RenderCustomDepth is set to false, if no Thermal or Semantic camera exists in the level,
340 // and is automatically set to true/false for all instances when they are spawned/destroyed.
341 // Doing this saves a lot rendering performance.
342 InstancedStaticMeshComponent->SetRenderCustomDepth(true);
343 InstancedStaticMeshComponent->SetCustomDepthStencilValue(StaticMeshComponent->CustomDepthStencilValue);
344
345 // Huge performance implication, recommend is Rigid (especially for Foliage with WPO).
346 // https://docs.unrealengine.com/5.3/en-US/PythonAPI/class/ShadowCacheInvalidationBehavior.html
347 InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = EShadowCacheInvalidationBehavior::Rigid;
348
349 // Create new FInstanceEntry
350 FInstanceEntry InstanceEntry;
351 InstanceEntry.InstancedStaticMeshComponent = InstancedStaticMeshComponent;
352 InstanceEntry.ActorClass = ClassPtr;
353 InstanceEntry.Mesh = Mesh;
354 InstanceEntry.Materials = MeshMaterials;
355 InstanceEntry.InstanceEntryIndex = InstanceEntries.Num();
356 InstanceEntry.CustomDepthStencilValue = StaticMeshComponent->CustomDepthStencilValue;
357 InstanceEntry.AllowWorldPositionOffsetDisable = AllowWorldPositionOffsetDisable;
358 InstanceEntry.IsTree = InstancedActor->IsTreeActor();
359
360 // Set materials to newly created UInstancedStaticMeshComponent
361 const int32 MaterialCount = MeshMaterials.Num();
362 for (int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex)
363 {
364 UMaterialInterface* MaterialInterface = InstanceEntry.Materials[MaterialIndex];
365
366 if (MaterialInterface)
367 {
368 InstancedStaticMeshComponent->SetMaterial(MaterialIndex, MaterialInterface);
369
370#if WITH_EDITOR
371 // Validate in Editor that material has bUsedWithInstancedStaticMeshes on
372 UMaterial* Material = Cast<UMaterial>(MaterialInterface);
373 if (Material)
374 {
375 if (!Material->bUsedWithInstancedStaticMeshes)
376 {
377 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Material '%s' bUsedWithInstancedStaticMeshes is not set to true!"), *Material->GetName());
378 }
379 }
380#endif
381 }
382 }
383
384 InstanceEntries.Add(InstanceEntry);
385
386 InstanceNum = InstanceEntries.Num() - 1;
387
388 return true;
389}
int32 GetInstanceEndCullDistance() const
bool HasAlternativeMaterial() const
int32 GetInstanceStartCullDistance() const
bool GetAllowWorldPositionOffsetDisable() const
bool IsTreeActor() const
TWeakObjectPtr< UStaticMesh > Mesh
TArray< UMaterialInterface * > Materials
int32 CustomDepthStencilValue
bool AllowWorldPositionOffsetDisable
TSubclassOf< AActor > ActorClass

References FInstanceEntry::ActorClass, FInstanceEntry::AllowWorldPositionOffsetDisable, CurrentWeatherParameters, FInstanceEntry::CustomDepthStencilValue, AInstancedActor::GetAllowWorldPositionOffsetDisable(), AInstancedActor::GetInstanceEndCullDistance(), AInstancedActor::GetInstanceStartCullDistance(), AInstancedActor::HasAlternativeMaterial(), FInstanceEntry::InstancedStaticMeshComponent, InstanceEntries, FInstanceEntry::InstanceEntryIndex, FInstanceEntry::IsTree, AInstancedActor::IsTreeActor(), FInstanceEntry::Materials, FInstanceEntry::Mesh, FWeatherParameters::WindIntensity, and WorldPositionOffsetDistance.

Referenced by AddActorToInstancedRendering().

◆ Get()

static AInstancedRenderer * AInstancedRenderer::Get ( )
inlinestatic

Definition at line 239 of file InstancedRenderer.h.

240 {
241 return Instance;
242 }

◆ GetInstanceEntries()

TArray< FInstanceEntry > AInstancedRenderer::GetInstanceEntries ( ) const
inline

Definition at line 141 of file InstancedRenderer.h.

142 {
143 return InstanceEntries;
144 }

◆ GetTotalInstanceCount()

int32 AInstancedRenderer::GetTotalInstanceCount ( ) const
inline

Definition at line 121 of file InstancedRenderer.h.

122 {
123 return TotalInstanceCount;
124 }

◆ GetUniqueInstancesCount()

int32 AInstancedRenderer::GetUniqueInstancesCount ( ) const
inline

Definition at line 131 of file InstancedRenderer.h.

132 {
133 return InstanceEntries.Num();
134 }

◆ IsRendering()

bool AInstancedRenderer::IsRendering ( ) const
inline

Definition at line 111 of file InstancedRenderer.h.

112 {
113 return Rendering;
114 }

◆ LogInfo()

void AInstancedRenderer::LogInfo ( ) const

Definition at line 85 of file InstancedRenderer.cpp.

86{
87#if WITH_EDITOR
88 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Unique mesh entries: %d | Total Instance Count: %d"), InstanceEntries.Num(), TotalInstanceCount);
89#endif
90}

References InstanceEntries, and TotalInstanceCount.

Referenced by BeginPlay().

◆ OnGraphicsSettingsChanged()

void AInstancedRenderer::OnGraphicsSettingsChanged ( FGlobalGraphicsSettings  GraphicsSettings)
private

Definition at line 460 of file InstancedRenderer.cpp.

461{
464}
void SetShadowCacheBehaviour(EShadowCacheInvalidationBehavior ShadowCacheInvalidationBehaviour)
void SetWorldPositionOffsetDistance(int32 NewWPODistance)
EShadowCacheInvalidationBehavior FoliageShadowCacheInvalidationBehaviour

References FGlobalGraphicsSettings::FoliageShadowCacheInvalidationBehaviour, SetShadowCacheBehaviour(), SetWorldPositionOffsetDistance(), and FGlobalGraphicsSettings::WorldPositionOffsetDistance.

Referenced by BeginPlay(), and EndPlay().

◆ OnWeatherParametersChanged()

void AInstancedRenderer::OnWeatherParametersChanged ( FWeatherParameters  WeatherParameters)
private

Definition at line 466 of file InstancedRenderer.cpp.

467{
468 CurrentWeatherParameters = WeatherParameters;
469
470 bool IsWinter = WeatherParameters.IsWinterSeason();
471 bool IsWindy = WeatherParameters.WindIntensity > 0.05f;
472 bool ShouldRenderWPO = IsWinter || IsWindy;
473
474 // Only update if the rendering state has changed
475 if (RenderingWPO != ShouldRenderWPO)
476 {
477 RenderingWPO = ShouldRenderWPO;
478 SetRenderWorldPositionOffet(ShouldRenderWPO);
479 }
480}
void SetRenderWorldPositionOffet(bool RenderWPO)

References CurrentWeatherParameters, FWeatherParameters::IsWinterSeason(), RenderingWPO, SetRenderWorldPositionOffet(), and FWeatherParameters::WindIntensity.

Referenced by BeginPlay(), and EndPlay().

◆ RemoveInstance()

void AInstancedRenderer::RemoveInstance ( int32  ComponentIndex,
int32  InstanceNumber 
)

Definition at line 406 of file InstancedRenderer.cpp.

407{
408 if (!InstanceEntries.IsValidIndex(ComponentIndex))
409 {
410 return;
411 }
412
413 FInstanceEntry& Entry = InstanceEntries[ComponentIndex];
414
416 {
417 // Ensure InstanceNumber is valid before attempting to remove
418 if (InstanceNumber >= 0 && InstanceNumber < Entry.InstancedStaticMeshComponent->GetInstanceCount())
419 {
420 Entry.InstancedStaticMeshComponent->RemoveInstance(InstanceNumber);
422 }
423 }
424}

References FInstanceEntry::InstancedStaticMeshComponent, InstanceEntries, and TotalInstanceCount.

Referenced by AInstancedActor::RemoveFromInstancedRendering().

◆ SetComponentIndexVisibility()

void AInstancedRenderer::SetComponentIndexVisibility ( int32  Index,
bool  Visible 
)

Set the visibility of a specific UInstancedStaticMeshComponent at the given index. Debugging purposes.

Parameters
IndexThe index of the UInstancedStaticMeshComponent to modify.
VisibleWhether to make the component visible (true) or hidden (false).

Definition at line 442 of file InstancedRenderer.cpp.

443{
444 if (!InstanceEntries.IsValidIndex(Index))
445 {
446#if WITH_EDITOR
447 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Index %d is not valid!"), Index);
448#endif
449 return;
450 }
451
452 FInstanceEntry& Entry = InstanceEntries[Index];
453
455 {
456 Entry.InstancedStaticMeshComponent->SetVisibility(Visible);
457 }
458}

References FInstanceEntry::InstancedStaticMeshComponent, and InstanceEntries.

◆ SetInstancedRendering()

void AInstancedRenderer::SetInstancedRendering ( bool  ShouldRender)

Definition at line 426 of file InstancedRenderer.cpp.

427{
428 Rendering = ShouldRender;
429 for (const FInstanceEntry& Entry : InstanceEntries)
430 {
431 if (Entry.InstancedStaticMeshComponent)
432 {
433 Entry.InstancedStaticMeshComponent->SetVisibility(Rendering);
434 }
435 }
436
437#if WITH_EDITOR
438 UE_LOG(LogTemp, Warning, TEXT("InstancedRenderer.cpp: Rendering: %s"), (Rendering ? TEXT("true") : TEXT("false")));
439#endif
440}

References InstanceEntries, and Rendering.

Referenced by UAgrarsenseSettings::SetInstancedRenderingVisibility().

◆ SetRenderCustomDepth()

void AInstancedRenderer::SetRenderCustomDepth ( bool  Enabled)

Sets whether the custom depth rendering is enabled or disabled.

Parameters
EnabledTrue to enable custom depth rendering, false to disable.

Definition at line 482 of file InstancedRenderer.cpp.

483{
484 for (FInstanceEntry& Entry : InstanceEntries)
485 {
486 if (Entry.InstancedStaticMeshComponent)
487 {
488 Entry.InstancedStaticMeshComponent->SetRenderCustomDepth(Enabled);
489 }
490 }
491}

References InstanceEntries.

◆ SetRenderWorldPositionOffet()

void AInstancedRenderer::SetRenderWorldPositionOffet ( bool  RenderWPO)

Sets whether the World Position Offset (WPO) rendering is enabled or disabled.

Parameters
RenderWPOTrue to enable World Position Offset rendering, false to disable.

Definition at line 522 of file InstancedRenderer.cpp.

523{
524 for (FInstanceEntry& Entry : InstanceEntries)
525 {
526 if (Entry.AllowWorldPositionOffsetDisable && Entry.InstancedStaticMeshComponent)
527 {
528 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffset(RenderWPO);
529 Entry.InstancedStaticMeshComponent->SetEvaluateWorldPositionOffsetInRayTracing(RenderWPO);
530 }
531 }
532}

References InstanceEntries.

Referenced by OnWeatherParametersChanged().

◆ SetShadowCacheBehaviour()

void AInstancedRenderer::SetShadowCacheBehaviour ( EShadowCacheInvalidationBehavior  ShadowCacheInvalidationBehaviour)

Sets the behavior for shadow cache invalidation. Default Rigid.

Parameters
ShadowCacheInvalidationBehaviourThe new behavior for shadow cache invalidation.

Definition at line 511 of file InstancedRenderer.cpp.

512{
513 for (FInstanceEntry& Entry : InstanceEntries)
514 {
515 if (Entry.InstancedStaticMeshComponent)
516 {
517 Entry.InstancedStaticMeshComponent->ShadowCacheInvalidationBehavior = ShadowCacheInvalidationBehaviour;
518 }
519 }
520}

References InstanceEntries.

Referenced by OnGraphicsSettingsChanged().

◆ SetWorldPositionOffsetDistance()

void AInstancedRenderer::SetWorldPositionOffsetDistance ( int32  NewWPODistance)

Sets the distance for the World Position Offset (WPO) effect.

Parameters
NewWPODistanceThe new distance for the World Position Offset.

Definition at line 493 of file InstancedRenderer.cpp.

494{
495 if (WorldPositionOffsetDistance == NewWPODistance)
496 {
497 return;
498 }
499
500 WorldPositionOffsetDistance = NewWPODistance;
501
502 for (FInstanceEntry& Entry : InstanceEntries)
503 {
504 if (Entry.InstancedStaticMeshComponent)
505 {
506 Entry.InstancedStaticMeshComponent->SetWorldPositionOffsetDisableDistance(WorldPositionOffsetDistance);
507 }
508 }
509}

References InstanceEntries, and WorldPositionOffsetDistance.

Referenced by OnGraphicsSettingsChanged().

◆ SpawnAllInstancesBackActors()

void AInstancedRenderer::SpawnAllInstancesBackActors ( )

Definition at line 597 of file InstancedRenderer.cpp.

598{
599 UWorld* World = GetWorld();
600
601 if (InstanceEntries.IsEmpty() || !World)
602 {
603 return;
604 }
605
606 for (FInstanceEntry& Entry : InstanceEntries)
607 {
608 UInstancedStaticMeshComponent* ISMComponent = Entry.InstancedStaticMeshComponent;
609 if (!ISMComponent)
610 {
611 continue;
612 }
613
614 ISMComponent->SetVisibility(false);
615
616 // Extract transforms from ISM component into TArray
617 TArray<FTransform> Transforms;
618
619 const int32 InstanceCount = ISMComponent->GetInstanceCount();
620
621 for (int32 i = 0; i < InstanceCount; i++)
622 {
623 FTransform Transform;
624 ISMComponent->GetInstanceTransform(i, Transform);
625 Transforms.Add(Transform);
626 }
627
628 // Spawn actors to level
629 UClass* Class = Entry.ActorClass;
630 for (const FTransform& Transform : Transforms)
631 {
632 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(Class, Transform);
633 if (SpawnedActor)
634 {
635 SpawnedActor->FinishSpawning(Transform);
636 }
637 }
638
639 ISMComponent->DestroyComponent();
640 }
641
642 InstanceEntries.Empty();
643}

References InstanceEntries, and Transform.

◆ SpawnInstanceBackToActor()

bool AInstancedRenderer::SpawnInstanceBackToActor ( UInstancedStaticMeshComponent *  ISM,
int32  Index,
bool  OnlyTree 
)

Spawns a specific ISM instance back to its original Actor. Cannot be added back to ISM instance afterwards.

Parameters
ISMThe instanced static mesh component containing the instance.
IndexThe index of the instance to spawn back.
Returns
True if the instance was successfully spawned, false otherwise.

Definition at line 685 of file InstancedRenderer.cpp.

686{
687 if (!ISM || Index < 0 || Index >= ISM->GetInstanceCount())
688 {
689 return false;
690 }
691
692 UWorld* World = GetWorld();
693
694 // Get the transform for the specified instance
695 FTransform InstanceTransform;
696 ISM->GetInstanceTransform(Index, InstanceTransform);
697
698 // Get the actor class from the associated entry
699 FInstanceEntry* Entry = InstanceEntries.FindByPredicate([ISM](const FInstanceEntry& InEntry) {
700 return InEntry.InstancedStaticMeshComponent == ISM;
701 });
702
703 if (!Entry || !World)
704 {
705 return false;
706 }
707
708 if (OnlyTree && !Entry->IsTree)
709 {
710 return false;
711 }
712
713 UClass* ActorClass = Entry->ActorClass;
714 if (!ActorClass)
715 {
716 return false;
717 }
718
719 // Spawn the actor
720 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(ActorClass, InstanceTransform);
721 if (SpawnedActor)
722 {
723 AInstancedActor* InstancedActor = Cast<AInstancedActor>(SpawnedActor);
724 if (InstancedActor)
725 {
726 InstancedActor->AddToInstancedRenderer = false;
727 }
728
729 SpawnedActor->FinishSpawning(InstanceTransform);
730
731 // Remove this ISM instance.
732 return ISM->RemoveInstance(Index);
733 }
734
735 return false;
736}

References FInstanceEntry::ActorClass, AInstancedActor::AddToInstancedRenderer, FInstanceEntry::InstancedStaticMeshComponent, InstanceEntries, and FInstanceEntry::IsTree.

◆ ToggleProxyMesh()

void AInstancedRenderer::ToggleProxyMesh ( )

Definition at line 573 of file InstancedRenderer.cpp.

574{
575#if WITH_EDITOR
576 for (FInstanceEntry& Entry : InstanceEntries)
577 {
578 auto& ISMComponent = Entry.InstancedStaticMeshComponent;
579
580 if (ISMComponent)
581 {
582 if (!Entry.UsingProxy)
583 {
584 ISMComponent->SetStaticMesh(CubeMesh.Get());
585 Entry.UsingProxy = true;
586 }
587 else
588 {
589 ISMComponent->SetStaticMesh(Entry.Mesh.Get());
590 Entry.UsingProxy = false;
591 }
592 }
593 }
594#endif
595}

References CubeMesh, and InstanceEntries.

Referenced by BeginPlay().

◆ UpdateInstanceTransform()

void AInstancedRenderer::UpdateInstanceTransform ( int32  ComponentIndex,
int32  InstanceNumber,
const FTransform &  NewTransform 
)

Definition at line 391 of file InstancedRenderer.cpp.

392{
393 if (!InstanceEntries.IsValidIndex(ComponentIndex))
394 {
395 return;
396 }
397
398 FInstanceEntry& Entry = InstanceEntries[ComponentIndex];
399
401 {
402 Entry.InstancedStaticMeshComponent->UpdateInstanceTransform(InstanceNumber, NewTransform, true, true);
403 }
404}

References FInstanceEntry::InstancedStaticMeshComponent, and InstanceEntries.

Referenced by AInstancedActor::UpdateTransformPosition().

◆ UpdateRenderDistances()

void AInstancedRenderer::UpdateRenderDistances ( )

Definition at line 645 of file InstancedRenderer.cpp.

646{
647#if WITH_EDITOR
648 UWorld* World = GetWorld();
649
650 if (InstanceEntries.IsEmpty() || !World)
651 {
652 return;
653 }
654
655 for (FInstanceEntry& Entry : InstanceEntries)
656 {
657 UInstancedStaticMeshComponent* ISMComponent = Entry.InstancedStaticMeshComponent;
658 if (!ISMComponent)
659 {
660 continue;
661 }
662
663 UClass* Class = Entry.ActorClass;
664 FTransform Transform;
665 AActor* SpawnedActor = World->SpawnActorDeferred<AActor>(Class, Transform);
666 if (SpawnedActor)
667 {
668 SpawnedActor->FinishSpawning(Transform);
669 }
670
671 AInstancedActor* Actor = Cast<AInstancedActor>(SpawnedActor);
672 if (Actor)
673 {
674
675 int32 Min = Actor->GetInstanceStartCullDistance();
676 int32 Max = Actor->GetInstanceEndCullDistance();
677 ISMComponent->SetCullDistances(Min, Max);
678
679 Actor->Destroy();
680 }
681 }
682#endif
683}

References AInstancedActor::GetInstanceEndCullDistance(), AInstancedActor::GetInstanceStartCullDistance(), InstanceEntries, and Transform.

Member Data Documentation

◆ CubeMesh

TWeakObjectPtr<UStaticMesh> AInstancedRenderer::CubeMesh
private

Definition at line 261 of file InstancedRenderer.h.

Referenced by AInstancedRenderer(), and ToggleProxyMesh().

◆ CurrentWeatherParameters

FWeatherParameters AInstancedRenderer::CurrentWeatherParameters
private

Definition at line 286 of file InstancedRenderer.h.

Referenced by BeginPlay(), FindOrAddUniqueMesh(), and OnWeatherParametersChanged().

◆ Instance

AInstancedRenderer * AInstancedRenderer::Instance = nullptr
staticprivate

Definition at line 263 of file InstancedRenderer.h.

Referenced by BeginPlay(), and EndPlay().

◆ InstanceEntries

TArray<FInstanceEntry> AInstancedRenderer::InstanceEntries
protected

◆ InstancesStaticMeshComponents

TArray<UInstancedStaticMeshComponent*> AInstancedRenderer::InstancesStaticMeshComponents
protected

Definition at line 254 of file InstancedRenderer.h.

◆ Rendering

bool AInstancedRenderer::Rendering = true
private

Definition at line 288 of file InstancedRenderer.h.

Referenced by SetInstancedRendering().

◆ RenderingWPO

bool AInstancedRenderer::RenderingWPO = false
private

Definition at line 290 of file InstancedRenderer.h.

Referenced by OnWeatherParametersChanged().

◆ TotalInstanceCount

int32 AInstancedRenderer::TotalInstanceCount = 0
protected

Definition at line 257 of file InstancedRenderer.h.

Referenced by AddActorToInstancedRendering(), LogInfo(), and RemoveInstance().

◆ WorldPositionOffsetDistance

int32 AInstancedRenderer::WorldPositionOffsetDistance = 30000
private

World Position Offset (WPO) render distance in cm

Definition at line 284 of file InstancedRenderer.h.

Referenced by BeginPlay(), FindOrAddUniqueMesh(), and SetWorldPositionOffsetDistance().


The documentation for this class was generated from the following files: