Subtractive Colour Mixing in Material Editor

I’m trying to replicate subtractive colour mixing in UE4 with materials. Ue4 uses additive so my “paints” don’t “mix” as they would in real life.

Currently my test scene projects a brush onto a render target. This brush material will change based on the colour of the jet that hit it. In the test scene there are three Red. Green and Blue. The colours are applied to the mesh correctly but when they overlap they mix additively. See below.

Also : [Video of Test][2]

After a lot of searching and material experimenting, I feel like I’m either missing something fundamental or attempting the impossible. I’m not really sure what conversions I can perform to correctly determine subtractive colours in an additive material system.

1 Like

So I solved my own problem eventually and although this seems like a niche technical challenge I figured it was worth giving my solution for anyone in the future.

As a disclaimer this answer does not give perfect results, but it is relatively cheap.

The leftmost add represents your “In” colours.

We use the RGB to HSV conversion node which converts our colour data into Hue, Saturation and Value (brightness).
These three pieces of information are stored in the R, G and B channels respectively.

R is now effectively a number between 0 and 179. 0 Being Red, and 179 being magenta. There is no saturation and no brightness in this number. As far as the computer is concerned this 0-179 represents this:


What we’re going to do is remap those colours by creating a gradient map. A gradient map is just that, usually a 1px high texture which we input our texture as a UV map. This is often use in things like fire sprites where the sprite is black and white.

I had to create a new gradient to keep red and blue in the same place, which is why they are out of position. Probably because we are moving from 255 to 179. This gradient is then better tweaked to reflect paint colours.


You will notice there is no cyan and no magenta. In the visible wavelength Magenta and Cyan don’t actually exist. Well cyan does but not thy hyper-saturated form we’re aware of. Because cyan is a primary colour, it can’t be created. And magenta, well [magenta is just something your brain invented.][4]

To clarify, what we’re tying to do here is replicate paints mixing, not hyper-realistic subtractive colour. If you want to replicate perfect subtractive colour then in theory you just need to change your gradient map.

SO with our colours plugged into our gradient map, you can see we now have the three primary colours and their respective secondary colours. Which of course is all a lie; what you’re taught in school are primary colours, are not actually the primary colours.

By using the Saturation and Brightness and multiplying them together, what we get is a value that represents how white something is. In subtractive colour you can’t mix white, instead you just slowly reduce the wavelengths. In most cases you can’t mix black, but for our purposes inverting the white created by additive colour mixing creates the approximate effect we’re looking for.

For my purposes I only want fully-saturated colour, so I haven’t used that. It means the colour blending looks a lot harsher than it should be but obviously you have the saturation values to use represented in the Green component of your HSV conversion.

The elephant in the room is that I have to ENTER different colours to get the right results. This is because usually green + red = orange. And as long as yellow is on the left side of the spectrum to green, this will always be the outcome. By shifting green to be yellow. Yellow(green) + Red will always be orange. This is the same case for cyan and magenta. So what colours you use in your material/render target will be shifted.

For example a spray can marked as “Blue Paint” will actually be adding cyan paint to the wall. Using this method, it will appear Blue correctly, and mix correctly.

I hope this helps any of you trying to replicate subtractive colour, or paint mixing in your Unreal game.

1 Like