Adding ability to modify motion blur settings (#1690)

* Adding ability to modify motion blur settings of RGB scene capture from the PythonAPI
* Adjust motion blur default values
This commit is contained in:
Aidan Clear 2019-05-31 16:50:30 +02:00 committed by Néstor Subirón
parent 39c75378b6
commit 35fdaec670
5 changed files with 164 additions and 63 deletions

View File

@ -1,7 +1,8 @@
## Latest
* Add ability to set motion blur settings for rgb camera in sensor python blueprint
* Improved visual quality of the screen capture for the rgb sensor
- Enabled Temporal AA for screen captures with no post-processing to prevent jaggies during motion
- Reduced the target gamma of render target to 1.4 to minimize brightness differences with main camera
- Reduced the target gamma of render target to 1.4 to minimize brightness differences with main camera
* Upgraded to Unreal Engine 4.22
* Recorder fixes:
- Fixed a possible crash if an actor is respawned before the episode is ready when a new map is loaded automatically.

View File

@ -65,6 +65,9 @@ The "RGB" camera acts as a regular camera capturing images from the scene.
| `fov` | float | 90.0 | Horizontal field of view in degrees |
| `enable_postprocess_effects` | bool | True | Whether the post-process effect in the scene affect the image |
| `sensor_tick` | float | 0.0 | Seconds between sensor captures (ticks) |
| `motion_blur_intensity` | float | 0.45 | Strength of motion blur. 1 is max and 0 is off |
| `motion_blur_max_distortion` | float | 0.35 | Max distortion caused by motion blur, in percent of the screen width, 0 is off |
| `motion_blur_min_object_screen_size` | float | 0.1 | Percentage of screen width objects must have for motion blur, lower value means less draw calls
`sensor_tick` tells how fast we want the sensor to capture the data. A value of 1.5 means that we want the sensor to capture data each second and a half. By default a value of 0.0 means as fast as possible.

View File

@ -16,7 +16,8 @@
#include <stack>
/// Checks validity of FActorDefinition.
class FActorDefinitionValidator {
class FActorDefinitionValidator
{
public:
/// Iterate all actor definitions and their properties and display messages on
@ -49,11 +50,11 @@ private:
Message += String;
}
Message += TEXT(" ");
Message += FString::Printf(Format, std::forward<ARGS>(Args)...);
Message += FString::Printf(Format, std::forward<ARGS>(Args) ...);
UE_LOG(LogCarla, Error, TEXT("%s"), *Message);
#if WITH_EDITOR
if(GEngine)
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(42, 15.0f, FColor::Red, Message);
}
@ -94,7 +95,7 @@ private:
template <typename T>
bool AreValid(const FString &Type, const TArray<T> &Array)
{
return ForEach(Type, Array, [this](const auto &Item){ return IsValid(Item); });
return ForEach(Type, Array, [this](const auto &Item) { return IsValid(Item); });
}
bool IsIdValid(const FString &Id)
@ -124,38 +125,39 @@ private:
bool IsValid(const FActorVariation &Variation)
{
return
IsIdValid(Variation.Id) &&
IsValid(Variation.Type) &&
OnScreenAssert(Variation.RecommendedValues.Num() > 0, TEXT("Recommended values cannot be empty")) &&
ForEach(TEXT("Recommended Value"), Variation.RecommendedValues, [&](auto &Value) {
return ValueIsValid(Variation.Type, Value);
});
IsIdValid(Variation.Id) &&
IsValid(Variation.Type) &&
OnScreenAssert(Variation.RecommendedValues.Num() > 0, TEXT("Recommended values cannot be empty")) &&
ForEach(TEXT("Recommended Value"), Variation.RecommendedValues, [&](auto &Value) {
return ValueIsValid(Variation.Type, Value);
});
}
bool IsValid(const FActorAttribute &Attribute)
{
return
IsIdValid(Attribute.Id) &&
IsValid(Attribute.Type) &&
ValueIsValid(Attribute.Type, Attribute.Value);
IsIdValid(Attribute.Id) &&
IsValid(Attribute.Type) &&
ValueIsValid(Attribute.Type, Attribute.Value);
}
bool IsValid(const FActorDefinition &ActorDefinition)
{
/// @todo Validate Class and make sure IDs are not repeated.
return
IsIdValid(ActorDefinition.Id) &&
AreTagsValid(ActorDefinition.Tags) &&
AreValid(TEXT("Variation"), ActorDefinition.Variations) &&
AreValid(TEXT("Attribute"), ActorDefinition.Attributes);
IsIdValid(ActorDefinition.Id) &&
AreTagsValid(ActorDefinition.Tags) &&
AreValid(TEXT("Variation"), ActorDefinition.Variations) &&
AreValid(TEXT("Attribute"), ActorDefinition.Attributes);
}
FScopedStack<FString> Stack;
};
template <typename ... ARGS>
static FString JoinStrings(const FString &Separator, ARGS && ... Args) {
return FString::Join(TArray<FString>{std::forward<ARGS>(Args)...}, *Separator);
static FString JoinStrings(const FString &Separator, ARGS && ... Args)
{
return FString::Join(TArray<FString>{std::forward<ARGS>(Args) ...}, *Separator);
}
static FString ColorToFString(const FColor &Color)
@ -187,11 +189,11 @@ bool UActorBlueprintFunctionLibrary::CheckActorDefinitions(const TArray<FActorDe
/// -- Helpers to create actor definitions -------------------------------------
/// ============================================================================
template <typename... TStrs>
static void FillIdAndTags(FActorDefinition &Def, TStrs &&... Strings)
template <typename ... TStrs>
static void FillIdAndTags(FActorDefinition &Def, TStrs && ... Strings)
{
Def.Id = JoinStrings(TEXT("."), std::forward<TStrs>(Strings)...).ToLower();
Def.Tags = JoinStrings(TEXT(","), std::forward<TStrs>(Strings)...).ToLower();
Def.Id = JoinStrings(TEXT("."), std::forward<TStrs>(Strings) ...).ToLower();
Def.Tags = JoinStrings(TEXT(","), std::forward<TStrs>(Strings) ...).ToLower();
// each actor gets an actor role name attribute (empty by default)
FActorVariation ActorRole;
ActorRole.Id = TEXT("role_name");
@ -201,11 +203,13 @@ static void FillIdAndTags(FActorDefinition &Def, TStrs &&... Strings)
Def.Variations.Emplace(ActorRole);
}
static void AddRecommendedValuesForActorRoleName(FActorDefinition &Definition, TArray<FString> &&RecommendedValues)
static void AddRecommendedValuesForActorRoleName(
FActorDefinition &Definition,
TArray<FString> &&RecommendedValues)
{
for (auto &&ActorVariation: Definition.Variations)
{
if ( ActorVariation.Id == "role_name" )
if (ActorVariation.Id == "role_name")
{
ActorVariation.RecommendedValues = RecommendedValues;
return;
@ -215,7 +219,8 @@ static void AddRecommendedValuesForActorRoleName(FActorDefinition &Definition, T
static void AddRecommendedValuesForSensorRoleNames(FActorDefinition &Definition)
{
AddRecommendedValuesForActorRoleName(Definition, {TEXT("front"), TEXT("back"), TEXT("left"), TEXT("right"), TEXT("front_left"), TEXT("front_right"), TEXT("back_left"), TEXT("back_right")});
AddRecommendedValuesForActorRoleName(Definition, {TEXT("front"), TEXT("back"), TEXT("left"), TEXT(
"right"), TEXT("front_left"), TEXT("front_right"), TEXT("back_left"), TEXT("back_right")});
}
static void AddVariationsForSensor(FActorDefinition &Def)
@ -314,7 +319,27 @@ void UActorBlueprintFunctionLibrary::MakeCameraDefinition(
PostProccess.Type = EActorAttributeType::Bool;
PostProccess.RecommendedValues = { TEXT("true") };
PostProccess.bRestrictToRecommended = false;
Definition.Variations.Add(PostProccess);
// Motion Blur
FActorVariation MBIntesity;
MBIntesity.Id = TEXT("motion_blur_intensity");
MBIntesity.Type = EActorAttributeType::Float;
MBIntesity.RecommendedValues = { TEXT("0.45") };
MBIntesity.bRestrictToRecommended = false;
FActorVariation MBMaxDistortion;
MBMaxDistortion.Id = TEXT("motion_blur_max_distortion");
MBMaxDistortion.Type = EActorAttributeType::Float;
MBMaxDistortion.RecommendedValues = { TEXT("0.35") };
MBMaxDistortion.bRestrictToRecommended = false;
FActorVariation MBMinObjectScreenSize;
MBMinObjectScreenSize.Id = TEXT("motion_blur_min_object_screen_size");
MBMinObjectScreenSize.Type = EActorAttributeType::Float;
MBMinObjectScreenSize.RecommendedValues = { TEXT("0.1") };
MBMinObjectScreenSize.bRestrictToRecommended = false;
Definition.Variations.Append({PostProccess, MBIntesity, MBMaxDistortion, MBMinObjectScreenSize});
}
Success = CheckActorDefinition(Definition);
@ -381,7 +406,8 @@ void UActorBlueprintFunctionLibrary::MakeVehicleDefinition(
{
/// @todo We need to validate here the params.
FillIdAndTags(Definition, TEXT("vehicle"), Parameters.Make, Parameters.Model);
AddRecommendedValuesForActorRoleName(Definition, {TEXT("autopilot"), TEXT("scenario"), TEXT("ego_vehicle")});
AddRecommendedValuesForActorRoleName(Definition,
{TEXT("autopilot"), TEXT("scenario"), TEXT("ego_vehicle")});
Definition.Class = Parameters.Class;
if (Parameters.RecommendedColors.Num() > 0)
{
@ -409,9 +435,9 @@ void UActorBlueprintFunctionLibrary::MakeVehicleDefinition(
Parameters.ObjectType});
Definition.Attributes.Emplace(FActorAttribute{
TEXT("number_of_wheels"),
EActorAttributeType::Int,
FString::FromInt(Parameters.NumberOfWheels)});
TEXT("number_of_wheels"),
EActorAttributeType::Int,
FString::FromInt(Parameters.NumberOfWheels)});
Success = CheckActorDefinition(Definition);
}
@ -642,7 +668,11 @@ FColor UActorBlueprintFunctionLibrary::ActorAttributeToColor(
ActorAttribute.Value.ParseIntoArray(Channels, TEXT(","), false);
if (Channels.Num() != 3)
{
UE_LOG(LogCarla, Error, TEXT("ActorAttribute '%s': invalid color '%s'"), *ActorAttribute.Id, *ActorAttribute.Value);
UE_LOG(LogCarla,
Error,
TEXT("ActorAttribute '%s': invalid color '%s'"),
*ActorAttribute.Id,
*ActorAttribute.Value);
return Default;
}
TArray<uint8> Colors;
@ -651,7 +681,11 @@ FColor UActorBlueprintFunctionLibrary::ActorAttributeToColor(
auto Val = FCString::Atoi(*Str);
if ((Val < 0) || (Val > std::numeric_limits<uint8>::max()))
{
UE_LOG(LogCarla, Error, TEXT("ActorAttribute '%s': invalid color '%s'"), *ActorAttribute.Id, *ActorAttribute.Value);
UE_LOG(LogCarla,
Error,
TEXT("ActorAttribute '%s': invalid color '%s'"),
*ActorAttribute.Id,
*ActorAttribute.Value);
return Default;
}
Colors.Add(Val);
@ -669,8 +703,8 @@ bool UActorBlueprintFunctionLibrary::RetrieveActorAttributeToBool(
bool Default)
{
return Attributes.Contains(Id) ?
ActorAttributeToBool(Attributes[Id], Default) :
Default;
ActorAttributeToBool(Attributes[Id], Default) :
Default;
}
int32 UActorBlueprintFunctionLibrary::RetrieveActorAttributeToInt(
@ -679,8 +713,8 @@ int32 UActorBlueprintFunctionLibrary::RetrieveActorAttributeToInt(
int32 Default)
{
return Attributes.Contains(Id) ?
ActorAttributeToInt(Attributes[Id], Default) :
Default;
ActorAttributeToInt(Attributes[Id], Default) :
Default;
}
float UActorBlueprintFunctionLibrary::RetrieveActorAttributeToFloat(
@ -689,8 +723,8 @@ float UActorBlueprintFunctionLibrary::RetrieveActorAttributeToFloat(
float Default)
{
return Attributes.Contains(Id) ?
ActorAttributeToFloat(Attributes[Id], Default) :
Default;
ActorAttributeToFloat(Attributes[Id], Default) :
Default;
}
FString UActorBlueprintFunctionLibrary::RetrieveActorAttributeToString(
@ -699,8 +733,8 @@ FString UActorBlueprintFunctionLibrary::RetrieveActorAttributeToString(
const FString &Default)
{
return Attributes.Contains(Id) ?
ActorAttributeToString(Attributes[Id], Default) :
Default;
ActorAttributeToString(Attributes[Id], Default) :
Default;
}
FColor UActorBlueprintFunctionLibrary::RetrieveActorAttributeToColor(
@ -709,8 +743,8 @@ FColor UActorBlueprintFunctionLibrary::RetrieveActorAttributeToColor(
const FColor &Default)
{
return Attributes.Contains(Id) ?
ActorAttributeToColor(Attributes[Id], Default) :
Default;
ActorAttributeToColor(Attributes[Id], Default) :
Default;
}
/// ============================================================================
@ -720,15 +754,15 @@ FColor UActorBlueprintFunctionLibrary::RetrieveActorAttributeToColor(
// Here we do different checks when we are in editor, because we don't want the
// editor crashing while people is testing new actor definitions.
#if WITH_EDITOR
# define CARLA_ABFL_CHECK_ACTOR(ActorPtr) \
if ((ActorPtr == nullptr) || ActorPtr->IsPendingKill()) \
{ \
UE_LOG(LogCarla, Error, TEXT("Cannot set empty actor!")); \
return; \
}
# define CARLA_ABFL_CHECK_ACTOR(ActorPtr) \
if ((ActorPtr == nullptr) || ActorPtr->IsPendingKill()) \
{ \
UE_LOG(LogCarla, Error, TEXT("Cannot set empty actor!")); \
return; \
}
#else
# define CARLA_ABFL_CHECK_ACTOR(ActorPtr) \
check((ActorPtr != nullptr) && !ActorPtr->IsPendingKill());
check((ActorPtr != nullptr) && !ActorPtr->IsPendingKill());
#endif // WITH_EDITOR
void UActorBlueprintFunctionLibrary::SetCamera(
@ -745,8 +779,14 @@ void UActorBlueprintFunctionLibrary::SetCamera(
{
Camera->EnablePostProcessingEffects(
ActorAttributeToBool(
Description.Variations["enable_postprocess_effects"],
true));
Description.Variations["enable_postprocess_effects"],
true));
Camera->SetMotionBlurIntensity(
RetrieveActorAttributeToFloat("motion_blur_intensity", Description.Variations, 0.5f));
Camera->SetMotionBlurMaxDistortion(
RetrieveActorAttributeToFloat("motion_blur_max_distortion", Description.Variations, 5.0f));
Camera->SetMotionBlurMinObjectScreenSize(
RetrieveActorAttributeToFloat("motion_blur_min_object_screen_size", Description.Variations, 0.5f));
}
}

View File

@ -41,7 +41,7 @@ namespace SceneCaptureSensor_local_ns {
// -- ASceneCaptureSensor ------------------------------------------------------
// =============================================================================
ASceneCaptureSensor::ASceneCaptureSensor(const FObjectInitializer& ObjectInitializer)
ASceneCaptureSensor::ASceneCaptureSensor(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
@ -101,6 +101,42 @@ float ASceneCaptureSensor::GetFOVAngle() const
return CaptureComponent2D->FOVAngle;
}
void ASceneCaptureSensor::SetMotionBlurIntensity(float Intensity)
{
check(CaptureComponent2D != nullptr);
CaptureComponent2D->PostProcessSettings.MotionBlurAmount = Intensity;
}
float ASceneCaptureSensor::GetMotionBlurIntensity() const
{
check(CaptureComponent2D != nullptr);
return CaptureComponent2D->PostProcessSettings.MotionBlurAmount;
}
void ASceneCaptureSensor::SetMotionBlurMaxDistortion(float MaxDistortion)
{
check(CaptureComponent2D != nullptr);
CaptureComponent2D->PostProcessSettings.MotionBlurMax = MaxDistortion;
}
float ASceneCaptureSensor::GetMotionBlurMaxDistortion() const
{
check(CaptureComponent2D != nullptr);
return CaptureComponent2D->PostProcessSettings.MotionBlurMax;
}
void ASceneCaptureSensor::SetMotionBlurMinObjectScreenSize(float ScreenSize)
{
check(CaptureComponent2D != nullptr);
CaptureComponent2D->PostProcessSettings.MotionBlurPerObjectSize = ScreenSize;
}
float ASceneCaptureSensor::GetMotionBlurMinObjectScreenSize() const
{
check(CaptureComponent2D != nullptr);
return CaptureComponent2D->PostProcessSettings.MotionBlurPerObjectSize;
}
void ASceneCaptureSensor::PostActorCreated()
{
Super::PostActorCreated();
@ -141,7 +177,8 @@ void ASceneCaptureSensor::BeginPlay()
CaptureRenderTarget->InitCustomFormat(ImageWidth, ImageHeight, PF_B8G8R8A8, bInForceLinearGamma);
if (bEnablePostProcessingEffects) {
if (bEnablePostProcessingEffects)
{
CaptureRenderTarget->TargetGamma = 2.2f;
}
@ -172,7 +209,8 @@ void ASceneCaptureSensor::BeginPlay()
GetWorld(),
FString("g.TimeoutForBlockOnRenderFence 300000"));
SceneCaptureSensor_local_ns::ConfigureShowFlags(CaptureComponent2D->ShowFlags, bEnablePostProcessingEffects);
SceneCaptureSensor_local_ns::ConfigureShowFlags(CaptureComponent2D->ShowFlags,
bEnablePostProcessingEffects);
Super::BeginPlay();
}
@ -192,8 +230,8 @@ void ASceneCaptureSensor::UpdateDrawFrustum()
// 1000 is the default frustum distance, ideally this would be infinite but
// that might cause rendering issues.
DrawFrustum->FrustumEndDist =
(CaptureComponent2D->MaxViewDistanceOverride > DrawFrustum->FrustumStartDist)
? CaptureComponent2D->MaxViewDistanceOverride : 1000.0f;
(CaptureComponent2D->MaxViewDistanceOverride > DrawFrustum->FrustumStartDist)
? CaptureComponent2D->MaxViewDistanceOverride : 1000.0f;
DrawFrustum->FrustumAngle = CaptureComponent2D->FOVAngle;
}
@ -209,16 +247,17 @@ namespace SceneCaptureSensor_local_ns {
{
auto &PostProcessSettings = CaptureComponent2D.PostProcessSettings;
// Set motion Blur settings
// Set motion blur settings (defaults)
PostProcessSettings.bOverride_MotionBlurAmount = true;
PostProcessSettings.MotionBlurAmount = 0.5f;
PostProcessSettings.MotionBlurAmount = 0.45f;
PostProcessSettings.bOverride_MotionBlurMax = true;
PostProcessSettings.MotionBlurMax = 10.0f;
PostProcessSettings.MotionBlurMax = 0.35f;
PostProcessSettings.bOverride_MotionBlurPerObjectSize = true;
PostProcessSettings.MotionBlurPerObjectSize = 0.5f;
PostProcessSettings.MotionBlurPerObjectSize = 0.1f;
}
// Remove the show flags that might interfere with post-processing effects like
// Remove the show flags that might interfere with post-processing effects
// like
// depth and semantic segmentation.
static void ConfigureShowFlags(FEngineShowFlags &ShowFlags, bool bPostProcessing)
{

View File

@ -67,6 +67,24 @@ public:
UFUNCTION(BlueprintCallable)
float GetFOVAngle() const;
UFUNCTION(BlueprintCallable)
void SetMotionBlurIntensity(float Intensity);
UFUNCTION(BlueprintCallable)
float GetMotionBlurIntensity() const;
UFUNCTION(BlueprintCallable)
void SetMotionBlurMaxDistortion(float MaxDistortion);
UFUNCTION(BlueprintCallable)
float GetMotionBlurMaxDistortion() const;
UFUNCTION(BlueprintCallable)
void SetMotionBlurMinObjectScreenSize(float ScreenSize);
UFUNCTION(BlueprintCallable)
float GetMotionBlurMinObjectScreenSize() const;
/// Use for debugging purposes only.
UFUNCTION(BlueprintCallable)
bool ReadPixels(TArray<FColor> &BitMap) const