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:
BeautifyManager.css
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); }
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.