The video below should show this problem easily enough. Essentially, I create a render target with the default clear colour of 0.5f, 0.5f 0.f - so it should be a neutral yellow colour by default. I’m planning on using this to create world-space normal impulses that fade away over time (R and G channels will be X and Y offsets in world-space respectively).
In order to fade the render target back to that neutral yellow colour, I’m using DrawMaterialToRenderTarget(), and drawing a translucent material with opacity set to game delta seconds. In theory, this should slowly reduce the other colours I draw the the render target. However for some reason, this gets less and less accurate as it gets closer to the correct value.
It’s really important that the values are accurate for this, or the effect won’t work. Material graphs are shown at the end of the video (they’re insanely simple).
Here’s the caveat - when I click off of the editor, it works perfectly. I can only assume because the delta seconds is so high it’s being blended much harder each frame. I can’t run this update at any less than 30FPS, so this seems like an issue with the blending in the actual renderer?
How can I make this work properly? This is how I create and draw the materials in code. I’ve tried using different texture formats (PF_B8G8R8A8), and settings (linear gamma and HDR false/true) - but to no avail.
// Create Render Target & Normalising DMI
void UECGame_WorldFXManager::InitializeImpulseTargets()
{
ImpulseNormalRenderTarget = NewObject<UTextureRenderTarget2D>(this, UTextureRenderTarget2D::StaticClass());
ASSERTV(ImpulseNormalRenderTarget != nullptr, TEXT("Invalid Render Target"));
ImpulseNormalRenderTarget->bHDR = true;
ImpulseNormalRenderTarget->ClearColor = FLinearColor(0.5f, 0.5f, 0.f, 0.f);
ImpulseNormalRenderTarget->InitCustomFormat(TargetRes, TargetRes, PF_FloatRGB, true);
// Create a DynamicMaterialInstance that will render to the full canvas, to normalize the render target back to it's ClearColour.
ImpulseNormalizerDMI = UMaterialInstanceDynamic::Create(ImpulseNormalizerMaterial, this);
ASSERTV(ImpulseNormalizerDMI != nullptr, TEXT("Invalid Normalizer DMI"));
}
// Called Every Frame
void UECGame_WorldFXManager::UpdateImpulseTarget(const float DeltaSeconds)
{
// We multiply the alpha by delta seconds so that values are applied constantly regardless of frame-rate
ImpulseNormalizerDMI->SetScalarParameterValue(TEXT("FrameDelta"), DeltaSeconds);
UKismetRenderingLibrary::DrawMaterialToRenderTarget(this, ImpulseNormalRenderTarget, ImpulseNormalizerDMI);
}