Draw Material To Render Target - Inaccurate blending at >5 FPS?

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);
}


Instead of drawing translucent material on top of another, you could just lerp between the final RT and initial color on your Mat_ImpulseNormalizer, that way you’d get definite control over it from your code.

I still don’t think that will work, I’ll just be drawing the render target ontop of itself (and rinse and repeat) and still have to draw by delta seconds.

Also if this is an underlying issue, it’ll be a problem for me since the values have to be accurate in order for the displacement effects to work. Essentially I’m doing this:

I think you have to call Begin Draw Canvas to Render Target and End Draw Canvas to Render Target before and after rendering to the render target.

That’s only if you want to do multiple draws in one batch (which I will do eventually, but just testing for now) - but it shouldn’t make a difference to this atm :confused:

EDIT: Okay this is getting even wierder. If i set the “clear colour” to Black, it works fine. One thing I have noticed however, is that my blending isn’t working over the course of one second (which it should be if I’m multiplying the opacity by delta time right?) Instead it’s taking several seconds…

Something seems strange about this…

EDIT #2:

Okay think I solved it. The problem was apparently the format I was using. I was initializing with bHdr = true and bForceLinearGamma = true which was correct, but the format needs to be PF_FloatRGBA - NOT “PF_FloatRGB” or PF_B8G8R8A8.

This makes senese I guess, since the Alpha Channel is used to blend Translucent materials on top of each other according to this answerhub post. Now I just need to work out why I have to multiply delta seconds by ten to get a fade out of one second…