CARLA
CarlaSettingsDelegate.cpp
Go to the documentation of this file.
1 #include "Carla.h"
3 
5 
6 #include "Async.h"
7 #include "Components/StaticMeshComponent.h"
8 #include "Engine/DirectionalLight.h"
9 #include "Engine/Engine.h"
10 #include "Engine/LocalPlayer.h"
11 #include "Engine/PostProcessVolume.h"
12 #include "Engine/StaticMesh.h"
13 #include "GameFramework/HUD.h"
14 #include "InstancedFoliageActor.h"
15 #include "Kismet/GameplayStatics.h"
16 #include "Landscape.h"
17 #include "Scalability.h"
18 
19 
20 static constexpr float CARLA_SETTINGS_MAX_SCALE_SIZE = 50.0f;
21 
22 /// quality settings configuration between runs
24 
26  : ActorSpawnedDelegate(FOnActorSpawned::FDelegate::CreateUObject(
27  this,
28  &UCarlaSettingsDelegate::OnActorSpawned)) {}
29 
31 {
33 }
34 
36 {
37  CheckCarlaSettings(InWorld);
38  InWorld->AddOnActorSpawnedHandler(ActorSpawnedDelegate);
39 }
40 
42 {
43  check(CarlaSettings != nullptr);
44  if (InActor != nullptr && IsValid(InActor) && !InActor->IsPendingKill() &&
45  !InActor->IsA<AInstancedFoliageActor>() && // foliage culling is
46  // controlled per instance
47  !InActor->IsA<ALandscape>() && // dont touch landscapes nor roads
48  !InActor->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) &&
49  !InActor->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG))
50  {
51  TArray<UPrimitiveComponent *> components;
52  InActor->GetComponents(components);
53  switch (CarlaSettings->GetQualityLevel())
54  {
55  case EQualityLevel::Low: {
56  // apply settings for this actor for the current quality level
57  float dist = CarlaSettings->LowStaticMeshMaxDrawDistance;
58  const float maxscale = InActor->GetActorScale().GetMax();
59  if (maxscale > CARLA_SETTINGS_MAX_SCALE_SIZE)
60  {
61  dist *= 100.0f;
62  }
63  SetActorComponentsDrawDistance(InActor, dist);
64  break;
65  }
66  default: break;
67  }
68  }
69 }
70 
72 {
73  CheckCarlaSettings(nullptr);
74  UWorld *InWorld = CarlaSettings->GetWorld();
75 
77 
78  if (AppliedLowPostResetQualityLevel == QualityLevel)
79  {
80  return;
81  }
82 
83  // enable temporal changes of quality (prevent saving last quality settings to file)
84  Scalability::ToggleTemporaryQualityLevels(true);
85 
86  switch (QualityLevel)
87  {
88  case EQualityLevel::Low:
89  {
90  // execute tweaks for quality
91  LaunchLowQualityCommands(InWorld);
92  // iterate all directional lights, deactivate shadows
93  SetAllLights(InWorld, CarlaSettings->LowLightFadeDistance, false, true);
94  // Set all the roads the low quality materials
95  SetAllRoads(InWorld, CarlaSettings->LowRoadPieceMeshMaxDrawDistance, CarlaSettings->LowRoadMaterials);
96  // Set all actors with static meshes a max disntace configured in the
97  // global settings for the low quality
98  SetAllActorsDrawDistance(InWorld, CarlaSettings->LowStaticMeshMaxDrawDistance);
99  // Disable all post process volumes
100  SetPostProcessEffectsEnabled(InWorld, false);
101  break;
102  }
103  default:
104  UE_LOG(LogCarla, Warning, TEXT("Unknown quality level, falling back to default."));
105  case EQualityLevel::Epic:
106  {
107  LaunchEpicQualityCommands(InWorld);
108  SetAllLights(InWorld, 0.0f, true, false);
109  SetAllRoads(InWorld, 0, CarlaSettings->EpicRoadMaterials);
110  SetAllActorsDrawDistance(InWorld, 0);
111  SetPostProcessEffectsEnabled(InWorld, true);
112  break;
113  }
114  }
116 }
117 
119 {
120  CheckCarlaSettings(nullptr);
121  UWorld *InWorld = CarlaSettings->GetWorld();
122  if (!IsValid(InWorld) || InWorld->IsPendingKill())
123  {
124  return;
125  }
126  // enable or disable world and hud rendering
127  APlayerController *playercontroller = UGameplayStatics::GetPlayerController(InWorld, 0);
128  if (playercontroller)
129  {
130  ULocalPlayer *player = playercontroller->GetLocalPlayer();
131  if (player)
132  {
133  player->ViewportClient->bDisableWorldRendering = CarlaSettings->bDisableRendering;
134  }
135  // if we already have a hud class:
136  AHUD *hud = playercontroller->GetHUD();
137  if (hud)
138  {
139  hud->bShowHUD = !CarlaSettings->bDisableRendering;
140  }
141  }
142 
143 }
144 
146 {
147  return GEngine->GetWorldFromContextObjectChecked(this);
148 }
149 
151 {
152  if (IsValid(CarlaSettings))
153  {
154  return;
155  }
156  if (world == nullptr || !IsValid(world) || world->IsPendingKill())
157  {
158  world = GetLocalWorld();
159  }
160  check(world != nullptr);
161  auto GameInstance = Cast<UCarlaGameInstance>(world->GetGameInstance());
162  check(GameInstance != nullptr);
163  CarlaSettings = &GameInstance->GetCarlaSettings();
164  check(CarlaSettings != nullptr);
165 }
166 
168 {
169  if (!world)
170  {
171  return;
172  }
173 
174  // launch commands to lower quality settings
175  GEngine->Exec(world, TEXT("r.DefaultFeature.MotionBlur 0"));
176  GEngine->Exec(world, TEXT("r.DefaultFeature.Bloom 0"));
177  GEngine->Exec(world, TEXT("r.DefaultFeature.AmbientOcclusion 0"));
178  GEngine->Exec(world, TEXT("r.AmbientOcclusionLevels 0"));
179  GEngine->Exec(world, TEXT("r.DefaultFeature.AmbientOcclusionStaticFraction 0"));
180  GEngine->Exec(world, TEXT("r.RHICmdBypass 0"));
181  GEngine->Exec(world, TEXT("r.DefaultFeature.AntiAliasing 1"));
182  GEngine->Exec(world, TEXT("r.Streaming.PoolSize 2000"));
183  GEngine->Exec(world, TEXT("r.HZBOcclusion 0"));
184  GEngine->Exec(world, TEXT("r.MinScreenRadiusForLights 0.01"));
185  GEngine->Exec(world, TEXT("r.SeparateTranslucency 0"));
186  GEngine->Exec(world, TEXT("r.FinishCurrentFrame 0"));
187  GEngine->Exec(world, TEXT("r.MotionBlurQuality 0"));
188  GEngine->Exec(world, TEXT("r.PostProcessAAQuality 0"));
189  GEngine->Exec(world, TEXT("r.BloomQuality 1"));
190  GEngine->Exec(world, TEXT("r.SSR.Quality 0"));
191  GEngine->Exec(world, TEXT("r.DepthOfFieldQuality 0"));
192  GEngine->Exec(world, TEXT("r.SceneColorFormat 2"));
193  GEngine->Exec(world, TEXT("r.TranslucencyVolumeBlur 0"));
194  GEngine->Exec(world, TEXT("r.TranslucencyLightingVolumeDim 4"));
195  GEngine->Exec(world, TEXT("r.MaxAnisotropy 8"));
196  GEngine->Exec(world, TEXT("r.LensFlareQuality 0"));
197  GEngine->Exec(world, TEXT("r.SceneColorFringeQuality 0"));
198  GEngine->Exec(world, TEXT("r.FastBlurThreshold 0"));
199  GEngine->Exec(world, TEXT("r.SSR.MaxRoughness 0.1"));
200  GEngine->Exec(world, TEXT("r.AllowOcclusionQueries 1"));
201  GEngine->Exec(world, TEXT("r.SSR 0"));
202  // GEngine->Exec(world,TEXT("r.StencilForLODDither 1")); //readonly
203  GEngine->Exec(world, TEXT("r.EarlyZPass 2")); // transparent before opaque
204  GEngine->Exec(world, TEXT("r.EarlyZPassMovable 1"));
205  GEngine->Exec(world, TEXT("Foliage.DitheredLOD 0"));
206  // GEngine->Exec(world,TEXT("r.ForwardShading 0")); //readonly
207  GEngine->Exec(world, TEXT("sg.PostProcessQuality 0"));
208  // GEngine->Exec(world,TEXT("r.ViewDistanceScale 0.1")); //--> too extreme
209  // (far clip too short)
210  GEngine->Exec(world, TEXT("sg.ShadowQuality 0"));
211  GEngine->Exec(world, TEXT("sg.TextureQuality 0"));
212  GEngine->Exec(world, TEXT("sg.EffectsQuality 0"));
213  GEngine->Exec(world, TEXT("sg.FoliageQuality 0"));
214  GEngine->Exec(world, TEXT("foliage.DensityScale 0"));
215  GEngine->Exec(world, TEXT("grass.DensityScale 0"));
216  GEngine->Exec(world, TEXT("r.TranslucentLightingVolume 0"));
217  GEngine->Exec(world, TEXT("r.LightShaftDownSampleFactor 4"));
218  GEngine->Exec(world, TEXT("r.OcclusionQueryLocation 1"));
219  // GEngine->Exec(world,TEXT("r.BasePassOutputsVelocity 0")); //--> readonly
220  // GEngine->Exec(world,TEXT("r.DetailMode 0")); //-->will change to lods 0
221  GEngine->Exec(world, TEXT("r.DefaultFeature.AutoExposure 1"));
222 
223 }
224 
226  UWorld *world,
227  const float max_draw_distance,
228  const TArray<FStaticMaterial> &road_pieces_materials) const
229 {
230  if (!world || !IsValid(world) || world->IsPendingKill())
231  {
232  return;
233  }
234  AsyncTask(ENamedThreads::GameThread, [=]() {
235  if (!world || !IsValid(world) || world->IsPendingKill())
236  {
237  return;
238  }
239  TArray<AActor *> actors;
240  UGameplayStatics::GetAllActorsWithTag(world, UCarlaSettings::CARLA_ROAD_TAG, actors);
241 
242  for (int32 i = 0; i < actors.Num(); i++)
243  {
244  AActor *actor = actors[i];
245  if (!IsValid(actor) || actor->IsPendingKill())
246  {
247  continue;
248  }
249  TArray<UStaticMeshComponent *> components;
250  actor->GetComponents(components);
251  for (int32 j = 0; j < components.Num(); j++)
252  {
253  UStaticMeshComponent *staticmeshcomponent = Cast<UStaticMeshComponent>(components[j]);
254  if (staticmeshcomponent)
255  {
256  staticmeshcomponent->bAllowCullDistanceVolume = (max_draw_distance > 0);
257  staticmeshcomponent->bUseAsOccluder = false;
258  staticmeshcomponent->LDMaxDrawDistance = max_draw_distance;
259  staticmeshcomponent->CastShadow = (max_draw_distance == 0);
260  if (road_pieces_materials.Num() > 0)
261  {
262  TArray<FName> meshslotsnames = staticmeshcomponent->GetMaterialSlotNames();
263  for (int32 k = 0; k < meshslotsnames.Num(); k++)
264  {
265  const FName &slotname = meshslotsnames[k];
266  road_pieces_materials.ContainsByPredicate(
267  [staticmeshcomponent, slotname](const FStaticMaterial &material)
268  {
269  if (material.MaterialSlotName.IsEqual(slotname))
270  {
271  staticmeshcomponent->SetMaterial(
272  staticmeshcomponent->GetMaterialIndex(slotname),
273  material.MaterialInterface);
274  return true;
275  }
276  else
277  {
278  return false;
279  }
280  });
281  }
282  }
283  }
284  }
285  }
286  }); // ,DELAY_TIME_TO_SET_ALL_ROADS, false);
287 }
288 
290  AActor *actor,
291  const float max_draw_distance) const
292 {
293  if (!actor)
294  {
295  return;
296  }
297  TArray<UPrimitiveComponent *> components;
298  actor->GetComponents(components, false);
299  float dist = max_draw_distance;
300  const float maxscale = actor->GetActorScale().GetMax();
301  if (maxscale > CARLA_SETTINGS_MAX_SCALE_SIZE)
302  {
303  dist *= 100.0f;
304  }
305  for (int32 j = 0; j < components.Num(); j++)
306  {
307  UPrimitiveComponent *primitivecomponent = Cast<UPrimitiveComponent>(components[j]);
308  if (IsValid(primitivecomponent))
309  {
310  primitivecomponent->SetCullDistance(dist);
311  primitivecomponent->bAllowCullDistanceVolume = dist > 0;
312  }
313  }
314 }
315 
316 void UCarlaSettingsDelegate::SetAllActorsDrawDistance(UWorld *world, const float max_draw_distance) const
317 {
318  /// @TODO: use semantics to grab all actors by type
319  /// (vehicles,ground,people,props) and set different distances configured in
320  /// the global properties
321  if (!world || !IsValid(world) || world->IsPendingKill())
322  {
323  return;
324  }
325  AsyncTask(ENamedThreads::GameThread, [=]() {
326  if (!world || !IsValid(world) || world->IsPendingKill())
327  {
328  return;
329  }
330  TArray<AActor *> actors;
331  // set the lower quality - max draw distance
332  UGameplayStatics::GetAllActorsOfClass(world, AActor::StaticClass(), actors);
333  for (int32 i = 0; i < actors.Num(); i++)
334  {
335  AActor *actor = actors[i];
336  if (!IsValid(actor) || actor->IsPendingKill() ||
337  actor->IsA<AInstancedFoliageActor>() || // foliage culling is controlled
338  // per instance
339  actor->IsA<ALandscape>() || // dont touch landscapes nor roads
340  actor->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) ||
341  actor->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG))
342  {
343  continue;
344  }
345  SetActorComponentsDrawDistance(actor, max_draw_distance);
346  }
347  });
348 }
349 
350 void UCarlaSettingsDelegate::SetPostProcessEffectsEnabled(UWorld *world, const bool enabled) const
351 {
352  TArray<AActor *> actors;
353  UGameplayStatics::GetAllActorsOfClass(world, APostProcessVolume::StaticClass(), actors);
354  for (int32 i = 0; i < actors.Num(); i++)
355  {
356  AActor *actor = actors[i];
357  if (!IsValid(actor) || actor->IsPendingKill())
358  {
359  continue;
360  }
361  APostProcessVolume *postprocessvolume = Cast<APostProcessVolume>(actor);
362  if (postprocessvolume)
363  {
364  postprocessvolume->bEnabled = enabled;
365  }
366  }
367 }
368 
370 {
371  if (!world)
372  {
373  return;
374  }
375 
376  GEngine->Exec(world, TEXT("r.AmbientOcclusionLevels -1"));
377  GEngine->Exec(world, TEXT("r.RHICmdBypass 1"));
378  GEngine->Exec(world, TEXT("r.DefaultFeature.AntiAliasing 1"));
379  GEngine->Exec(world, TEXT("r.Streaming.PoolSize 2000"));
380  GEngine->Exec(world, TEXT("r.MinScreenRadiusForLights 0.03"));
381  GEngine->Exec(world, TEXT("r.SeparateTranslucency 1"));
382  GEngine->Exec(world, TEXT("r.PostProcessAAQuality 4"));
383  GEngine->Exec(world, TEXT("r.BloomQuality 5"));
384  GEngine->Exec(world, TEXT("r.SSR.Quality 3"));
385  GEngine->Exec(world, TEXT("r.DepthOfFieldQuality 2"));
386  GEngine->Exec(world, TEXT("r.SceneColorFormat 4"));
387  GEngine->Exec(world, TEXT("r.TranslucencyVolumeBlur 1"));
388  GEngine->Exec(world, TEXT("r.TranslucencyLightingVolumeDim 64"));
389  GEngine->Exec(world, TEXT("r.MaxAnisotropy 8"));
390  GEngine->Exec(world, TEXT("r.LensFlareQuality 2"));
391  GEngine->Exec(world, TEXT("r.SceneColorFringeQuality 1"));
392  GEngine->Exec(world, TEXT("r.FastBlurThreshold 100"));
393  GEngine->Exec(world, TEXT("r.SSR.MaxRoughness -1"));
394  // GEngine->Exec(world,TEXT("r.StencilForLODDither 0")); //readonly
395  GEngine->Exec(world, TEXT("r.EarlyZPass 3"));
396  GEngine->Exec(world, TEXT("r.EarlyZPassMovable 1"));
397  GEngine->Exec(world, TEXT("Foliage.DitheredLOD 1"));
398  GEngine->Exec(world, TEXT("sg.PostProcessQuality 3"));
399  GEngine->Exec(world, TEXT("r.ViewDistanceScale 1")); // --> too extreme (far
400  // clip too short)
401  GEngine->Exec(world, TEXT("sg.ShadowQuality 3"));
402  GEngine->Exec(world, TEXT("sg.TextureQuality 3"));
403  GEngine->Exec(world, TEXT("sg.EffectsQuality 3"));
404  GEngine->Exec(world, TEXT("sg.FoliageQuality 3"));
405  GEngine->Exec(world, TEXT("foliage.DensityScale 1"));
406  GEngine->Exec(world, TEXT("grass.DensityScale 1"));
407  GEngine->Exec(world, TEXT("r.TranslucentLightingVolume 1"));
408  GEngine->Exec(world, TEXT("r.LightShaftDownSampleFactor 2"));
409  // GEngine->Exec(world,TEXT("r.OcclusionQueryLocation 0"));
410  // GEngine->Exec(world,TEXT("r.BasePassOutputsVelocity 0")); //readonly
411  GEngine->Exec(world, TEXT("r.DetailMode 2"));
412 }
413 
415  UWorld *world,
416  const float max_distance_fade,
417  const bool cast_shadows,
418  const bool hide_non_directional) const
419 {
420  if (!world || !IsValid(world) || world->IsPendingKill())
421  {
422  return;
423  }
424  AsyncTask(ENamedThreads::GameThread, [=]() {
425  if (!world || !IsValid(world) || world->IsPendingKill())
426  {
427  return;
428  }
429  TArray<AActor *> actors;
430  UGameplayStatics::GetAllActorsOfClass(world, ALight::StaticClass(), actors);
431  for (int32 i = 0; i < actors.Num(); i++)
432  {
433  if (!IsValid(actors[i]) || actors[i]->IsPendingKill())
434  {
435  continue;
436  }
437  // tweak directional lights
438  ADirectionalLight *directionallight = Cast<ADirectionalLight>(actors[i]);
439  if (directionallight)
440  {
441  directionallight->SetCastShadows(cast_shadows);
442  directionallight->SetLightFunctionFadeDistance(max_distance_fade);
443  continue;
444  }
445  // disable any other type of light
446  actors[i]->SetActorHiddenInGame(hide_non_directional);
447  }
448  });
449 
450 }
EQualityLevel
static constexpr float CARLA_SETTINGS_MAX_SCALE_SIZE
FOnActorSpawned::FDelegate ActorSpawnedDelegate
void ApplyQualityLevelPostRestart()
After loading a level, apply the current settings.
void SetActorComponentsDrawDistance(AActor *actor, float max_draw_distance) const
void OnActorSpawned(AActor *Actor)
Function to apply to the actor that is being spawned to apply the current settings.
void LaunchLowQualityCommands(UWorld *world) const
Execute engine commands to apply the low quality level to the world.
void SetAllActorsDrawDistance(UWorld *world, float max_draw_distance) const
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
void RegisterSpawnHandler(UWorld *World)
Create the event trigger handler for all the newly spawned actors to be processed with a custom funct...
void SetAllLights(UWorld *world, float max_distance_fade, bool cast_shadows, bool hide_non_directional) const
Used to set settings for every actor that is spawned into the world.
void LaunchEpicQualityCommands(UWorld *world) const
Execute engine commands to apply the epic quality level to the world.
static EQualityLevel AppliedLowPostResetQualityLevel
Currently applied quality level after level is restarted.
float LowLightFadeDistance
Distance at which the light function should be completely faded to DisabledBrightness.
EQualityLevel GetQualityLevel() const
Definition: CarlaSettings.h:41
void SetPostProcessEffectsEnabled(UWorld *world, bool enabled) const
void SetAllRoads(UWorld *world, float max_draw_distance, const TArray< FStaticMaterial > &road_pieces_materials) const
void Reset()
Reset settings to default.
void CheckCarlaSettings(UWorld *world)
Check that the world, instance and settings are valid and save the CarlaSettings instance.
static const FName CARLA_ROAD_TAG
CARLA_ROAD name to tag road mesh actors.
Definition: CarlaSettings.h:60
UCarlaSettings * CarlaSettings
bool bDisableRendering
Enable or disable the viewport rendering of the world.
Definition: CarlaSettings.h:96
static const FName CARLA_SKY_TAG
CARLA_SKY name to tag the sky sphere (BPS) actors in the scenes.
Definition: CarlaSettings.h:63
void ApplyQualityLevelPreRestart()
Before loading a level, apply the current settings.