Postprocessing pipeline is FUBAR!

Playing around with postprocessing materials last couple of days I can conclude that they’re kinda… not working as I expected them to work in AAA engine.

  1. I’m trying to capture the scene. Creating RenderTarget, adding SceneCaptured2D to MyCharacter, setting TextureTarget to created rendertarget, CaptureSource is LDR.
    To see what I’ve captured I created simple blendable material, which draws captured rt into upper-left quarter of the screen. Then I found substantial difference in colors of the scene and captured rt. I think I tried all checkboxes I can change to see if that will work, but no success so far. What setting are required to catch properly?

  2. Blendables don’t work with SceneCapture2D (created simple blendable which outputs red, but SceneCapture2D ignores it). Found several (some old) topics on forum/answerhub, so I’m not the first to find this bug.

  3. Can’t control material instance blendable order (see this thread which I created earlier Postprocess material instance blendable priority - Feedback for Unreal Engine team - Unreal Engine Forums)

  4. Is there any way to create postprocessing chaining? I.e. I want to get scene texture, run some material with it, save the result to some render target, optionally downsample/upsample it to lower/higher resolution rt, use that render target in some other postprocessing material which will output to the screen (or save it for the next frame). So far I can’t find the way to make it work (nor can I find documentation how to make it).

  5. Not being able to create/resize RenderTargets from blueprints was a surprise for me as well.

To summarize, my experience with postprocessing in UE4 was a pain so far, I hope it’ll get updated in the future.


  1. SceneTexture node in postprocessing materials have Size and InvSize parameters which are undocumented (as the node itself undocumented as well). What are those params contain?

  2. I am crazy or there are no loops in materials? (both graph and customnode)

Hey there! I know we have some improvements on the docket for postprocess (and how settings are exposed via blueprints) but I’ll make sure the devs see your feedback so that we can address in future versions.

Loops in materials are a recipe for disaster! :slight_smile:

You can certainly do a loop in a custom node. I did that for my POM material that is in the forums.

Tell that to SSAO, blur and sheer of other algorithms :slight_smile: Loops are almost always have to be unrolled, but we need them pretty often!

I actually did the search and people were complaining about this. Right now I need tex sampling inside the loop and I also remember that was a problem for custom node…

To answer onto my 1. from the first post (seems that I found settings combination):
-SceneCapture2D component

  • set CaptureSource to LDR
    -RenderTarget asset
  • HDR off
  • TargetGamma 2.2
    -Inside postprocess material
  • SceneTexture’s SamplerType is LinearColor

Below is a snippet of one of the Custom Nodes from my POM material. As you can see there is a texture sample (SampleGrad) done in a loop (while). I have also done for loops in other Custom Nodes. so it is certainly possible. The only downside I would say is having to reference the textures and samplers directly.

There may have been some issues with Custom Nodes at the beginning, but I have had no real problems with them now.

float CurrRayHeight = 1.0;
float2 CurrOffset = float2( 0, 0 );
float2 LastOffset = float2( 0, 0 );

float LastSampledHeight = 1;
float CurrSampledHeight = 1;

int CurrSample = 0;

while ( CurrSample < (int) InNumSamples )
	float4 Temp = Material.Texture2D_0.SampleGrad( Material.Texture2D_0Sampler, InTexCoord + CurrOffset, InDX, InDY );
	CurrSampledHeight = ( ( Temp.r * InChannelMask.r ) + ( Temp.g * InChannelMask.g ) + ( Temp.b * InChannelMask.b ) );
	if ( CurrSampledHeight > CurrRayHeight )
		float Delta1 = CurrSampledHeight - CurrRayHeight;
		float Delta2 = ( CurrRayHeight + InStepSize ) - LastSampledHeight;

		float Ratio = Delta1/( Delta1 + Delta2 );

		CurrOffset = ( Ratio ) * LastOffset + ( 1.0 - Ratio ) * CurrOffset;

		CurrSample = InNumSamples + 1;

		CurrRayHeight -= InStepSize;

		LastOffset = CurrOffset;
		CurrOffset += InStepSize * InMaxOffset;

		LastSampledHeight = CurrSampledHeight;

return CurrOffset;

****, great, thanks!

One thing though, how to to directly reference SceneTexture:PostProcessInput0 inside the CustomNode?

You should be able to do the following:

Texture2DSample( PostprocessInput0, PostprocessInput0Sampler, InTexCoord );

Texture2DSample is just a wrapper around Tex.Sample (So instead of PostprocessInput0.Sample( PostprocessInput0Sampler, … ); ) That also applies to PostprocessInput0 through to 6

Bah. Copy-paste material nodes to simulate loop is not much better :smiley:

I think the lighting difference in your original screen shot could be explained by auto-exposure.

****, thanks for the help, really appreciate it. However CustomNode still gives me a headache, this time it dislikes arrays:

float3 res = 0;
const float] offsets = { -2, -1, 0, 1, 2 };
return res;

And this is what I get in the log:

Error [SM5] error X3000: syntax error: unexpected token ‘’

Since when array brackets are unexpected in SM5? :smiley:

Thanks, gonna try this suggestion!

Alright, I’m dumb this time: float array] not float] array!

Oh dear…a new one

Error [SM5] error X3004: undeclared identifier 'PostProcessInput0’

edit: nvm, works now


Could you tell me how you fixed it?

Example Custom Node code which produces this error looks like this (UV is input in this case):

float3 postproc = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV);
return postproc;

And I’ve got exactly the same error X3004, dunno how to resolve it.

Edit: I have not noticed this topic is over 1 year old, sorry, I was tired. But anyway problem still actual.

Ok, I managed to resolve it! :slight_smile: I had to change custom shader code a little bit, but I got functionality I needed.

Post from this topic helped me - in short - dummy SceneTexture node should be placed and connected to our Custom Code node, because it probably forces to define NEEDS_SCENE_TEXTURES, which includes SceneTextureLookup function in MaterialTemplate.usf during shader compilation.

In case anybody would have the same problem: here I done simple example, which should work (4.9 and 4.10 tested):

Guess what: Since 4.9 it’s not possible to alter post-processing settings with blueprint AT ALL…

The best way to do Loops I’ve found is to create a material functions out of the part of the material you want to loop, and copy-pasterino it a few times into the graph and have it feedback into the next one and so on. This way it also takes full advantage of the cross-compiler and is probably a good practice to get into making Material Functions anyway.