skip to Main Content

Adding Motion Sensibility to Beautify in Unreal Engine

Recently we submitted a version of our Beautify asset for Unreal engine. This plugin improves the quality of the image in real time and works as a post-processing effect.

Here’s a video of the setup:

The effect works out of the box and includes controls to tweak the strength and behaviour.

One aspect we may want to control is the sharpen strength from code, especially when the camera moves or rotates. Usually we want sharp images only when camera is not rotating fast contributing to a motion blur effect. Also, by reducing the sharpen intensity when camera moves fast, we can reduce any flickering caused by some bright pixels (especially in VR).

Below you can find the component source which can be added to any Actor in the scene. This component exposes two properties:

  • Beautify Material Instance: drag & drop your material instance to this field. The component will create a dynamic material instance in order to modify the sharpen intensity value dynamically.
  • Motion Sensibility: this is a value in the 0..1 range that acts as a threshold for the motion sensibility. The greater the value, the more sensitive to any camera movement/rotation.

Here’s the code:


See Full Code:
#pragma once #include “CoreMinimal.h” #include “Components/ActorComponent.h” #include “BeautifyManager.generated.h” UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class BEAUTIFY_API UBeautifyManager : public UActorComponent { GENERATED_BODY() UPROPERTY(EditAnywhere, Category = “Motion Sensibility”, meta = (ClampMin = “0.0”, ClampMax = “1.0”, UIMin = “0.0”, UIMax = “1.0”)) float MotionSenbility = 0.5; UPROPERTY(EditAnywhere, Category = “Motion Sensibility”) UMaterialInterface* BeautifyMaterialInstance; public: // Sets default values for this component’s properties UBeautifyManager(); protected: // Called when the game starts virtual void BeginPlay() override; public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; };

And BeautifyManager.css:

See Full Code:
#include “BeautifyManager.h” #include “Interfaces/Interface_PostProcessVolume.h” float sharpen; FVector prevCamPos; FVector prevCamForward; float currSens; UMaterialInstanceDynamic *bMat; // Sets default values for this component’s properties UBeautifyManager::UBeautifyManager() { // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // off to improve performance if you don’t need them. PrimaryComponentTick.bCanEverTick = true; } // Called when the game starts void UBeautifyManager::BeginPlay() { Super::BeginPlay(); if (!BeautifyMaterialInstance) return; UWorld* world = GetWorld(); int32 count = world->PostProcessVolumes.Num(); // Find global Post Processing volume for (int32 x = 0; x < count; ++x) { FPostProcessVolumeProperties volume = world->PostProcessVolumes[x]->GetProperties(); if (volume.bIsUnbound) { FPostProcessSettings* settings = (FPostProcessSettings*)volume.Settings; FWeightedBlendables blendables = settings->WeightedBlendables; bMat = UMaterialInstanceDynamic::Create(BeautifyMaterialInstance, this); bMat->GetScalarParameterValue(FName(“SharpenIntensity”), sharpen); blendables.Array.Empty(); FWeightedBlendable blendable; blendable.Object = bMat; blendable.Weight = 1.0f; blendables.Array.Add(blendable); settings->WeightedBlendables = blendables; return; } } } float AngleBetweenVectors(FVector v1, FVector v2) { float dotProduct = FVector::DotProduct(v1, v2); float lengthProduct = v1.Size() * v2.Size(); // Angle float angle = FMath::Acos( dotProduct / lengthProduct ) * 360.0 / 3.1415927; return angle; } // Called every frame void UBeautifyManager::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (!bMat) return; // Motion sensibility APlayerCameraManager *camManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager; FVector cameraPosition = camManager->GetCameraLocation(); FVector cameraForward = camManager->GetCameraRotation().Vector(); float angleDiff = AngleBetweenVectors(prevCamForward, cameraForward) * MotionSenbility; float posDiff = (cameraPosition — prevCamPos).SizeSquared() * 10.0 * MotionSenbility; float diff = angleDiff + posDiff; if (diff > 0.1) { prevCamForward = cameraForward; prevCamPos = cameraPosition; if (diff > MotionSenbility) diff = MotionSenbility; currSens += diff; float min = sharpen * MotionSenbility * 0.75f; float max = sharpen * (1.0 + MotionSenbility) * 0.5f; currSens = FMath::Clamp(currSens, min, max); } else { if (currSens <= 0.001f) return; currSens *= 0.75f; } float tempSharpen = FMath::Clamp(sharpen — currSens, 0.0f, sharpen); bMat->SetScalarParameterValue(FName(“SharpenIntensity”), tempSharpen); }
0 0 vote
Article Rating
Notify of
Inline Feedbacks
View all comments
Back To Top