Node Load.

No. No. No. Nope. No. Nope Nope. No.

In browsing around at various approaches people had taken to achieve novel translucent effects in UE4, I downloaded a few free materials I found online.

To my horror, I keep finding these sorts of approaches. Not only are they dreadful to look at and interpret, but we have no control over the number of iterations that are performed.

I get it – if you’re not a programmer, is it not self-evident how to fix this, particularly as UE4 doesn’t include looping mechanisms in the Material graph – so I shall be self-indulgent and explain how to fix this (in a round-about way).

What’s going on here?

This shader is simply sampling the same texture many times, using different offset values in order to create an illusion of depth within a surface (ice cracks in this case).

In an ideal world, we simply want to provide a node with the number of iterations (how many times we sample), the depth to apply and the texture and let the node do the rest.

We can do this with a Custom node and a for() loop. The above shader uses the BumpOffset node multiple times, each time increasing the depth offset and multiplying the resuling value, until we have something we can use in a lerp node to interpolate between a surface and a depth colour (i.e. white cracks on blue ice).

The entire above network you see can be condensed into:

float outputLerpValue = 1.0;
float iteratorMultiplier = 1.0 / Iterations;
for(int i = 0; i < Iterations; i++)
{
    float m = ( i + 1.0 ) * iteratorMultiplier;
    float height = Texture2DSample(OffsetTex, OffsetTexSampler, UV + (float2(HeightRatio,HeightRatio)*m));
    float2 UVs = UV + ViewDirection.xy * height * m * HeightRatio;
    outputLerpValue += Texture2DSample(MainTex, MainTexSampler,UVs).r;
	
}
return outputLerpValue;

And contained within a single Custom node:

And *breathe*

I then plugged this output value into a lerp, then into a few extra nodes and in no time at all had this:

Multi-sampled bump offset.

But where did you get the magic code from?

Well, if you grab the UE4 source code from GitHub, and give the files a search for BumpOffset (the name of the node used in the original shader network), you end up in:
UnrealEngine\Engine\Source\Runtime\Engine\Classes\Materials\MaterialExpressionBumpOffset.h
where on line 17, we find:

// Outputs: Coordinate + Eye.xy * (Height - ReferencePlane) * HeightRatio

So I then wrapped it around a for() loop and modified the values by the current iteration, adding the output of each iteration up.

I appreciate this isn’t comprehensive, and its a bit of a drain dump – but if you find yourself making these repetitive node networks, consider learning some HLSL syntax and for loops.

Leave a Reply

Your email address will not be published. Required fields are marked *