Surface-Stable Fractal Dithering in Unreal Engine 5

Off

Following the release of Rune Skovbo Johansen‘s fantastic video on Surface-Stable Fractal Dithering, I’ve been working on trying to implement the same type of effect in Unreal Engine. However, due to some limitations in how Unreal does it’s rendering, I’ve hit a bit of a wall, so I figured it was time to share my progress with the world and allow anyone else to take a stab at improving my implementation.

I’ve currently implemented the effect in two different ways. One directly on the material, and one as a post process effect.

Material Implementation

The material-based implementation has two modes currently, Black & White or CMYK, which can be changed through a toggle parameter.

The material looks like this:

The material uses a couple of material functions, first of all the actual dithering logic. The dithering material function looks as follows:

I will not embed the MF_RGB2CMYK or MF_CMYK2RGB functions directly here, as they are not my work. However, their implementations can be found at ~8:00 in this video:

The result of this implemenation looks like this:

BW:

CMYK:

This method has some very obvious limitation, such as the fact that the shadows are calculated after the material shader is complete, in the post process step. This means that we can’t get the shadow values and use those to resize the dots or change their frequency. We would have to implement it in the post process shader instead to get that effect. So moving on.

Post Process Implementation

Now to do the same thing in a post process material, I’ve had to do a few quite hacky solutions. I am not an Unreal Material expert, so maybe there are better ways to do these things, but this is done to the best of my abilities.

First I’ve created a material which should be applied to the individual objects. This material needs to pass it’s UVs on to the post process shader, as I don’t believe you can get the object UVs otherwise. I’m currently passing those through the Metallic and Roughness channels, which will give some artifacts in the final output, but this is a proof of concept so I’m not too worried about that right now.

Then I’ve created a post process material which reads and filters the base color and then passes it through a dithering function. The post process material looks like this:

As you might be able to tell, the BW / CMYK functionality is not fully implemented here, so the result I will show at the end consists of one channel from the CMYK masking.

The dithering material function looks like this:

Finally, for the reason why I’ve gotten stuck. After implementing all this, the final result looks like this:

You can tell that the intended effect is happening, however the resolution of the effect is way too poor to be useable. I’m fairly certain that this is a limitation of the post processing resolution in Unreal, and not the fault of my material, as changing the various sizing parameters in my code have no effect on the size of the ‘pixels’ on the final material.

Hopefully someone smarter than me will come along and help figure out a solution. You can join the Github discussion here.

khalkjaer

Comments are closed.