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