Painting variable colour to a Material

Started by
5 comments, last by coope 5 years, 8 months ago

I'm working on a project that needs the player to be able to paint their avatars with colours.

I've gotten started, and implemented a solution of sorts. Basically I raytrace to the target material, then call my Draw on Surface function which splits the parameter color into the three channels. Then sends those three channels to their respective UCanvasRenderTarget2D resources.

The problem is that in order to paint in multiple places I need to use additive, and with additive enabled any colors I paint combine to make white. That is if you paint in one spot long enough the result is white on the material. I would love to either:

A) Paint colored pixels directly to a UCanvasRenderTarget2D

B) Limit the alpha in each channel's UCanvasRenderTarget2D

Either would result in the exact color needed being painted, only to be replaced or surpassed if the color is changed. Ideally by lerping towards the new color. So I'm kinda at my ropes length, can someone help?

 

Here is the implementation in order {1,3,2} //sorry

UE4Editor_2018-07-03_10-48-29.png

UE4Editor_2018-07-03_10-49-32.png

UE4Editor_2018-07-03_10-50-13.png

Advertisement
1 hour ago, coope said:

I've gotten started, and implemented a solution of sorts. Basically I raytrace to the target material, then call my Draw on Surface

This is one way to do it. The way it is normally done is a custom shader for drawing on is made, the same as with any other engine. Unreal also allows you to do this by creating a editable instance material, saving the texture is your own responsibility though.

Then again using the UCanvasRenderTarget2D gets the job done.

 

1 hour ago, coope said:

Either would result in the exact color needed being painted, only to be replaced or surpassed if the color is changed. Ideally by lerping towards the new color. So I'm kinda at my ropes length, can someone help?

You want to mix based on the brushes, in other words you want to lerp the colors for real. Unreal has lerp but let me explain how it works:

 

1.) If you add the color(R,G,B,A) Yellow(1,1,0,1) + Blue(0,0,1,1) = White (1,1,1,1); So this is working as expected.

2.) To use it for mixing color we lerp based on a brush strength

Lerp = ((1 - t) * v0) + (t * v1)  To explain lets say v0 = 50 and v1 =100 then lets make t=0.5 for 50%   So solve brackets first : ((1- 0.5) * 50) + (0.5 * 100) -> ((0.5) *50) + (50) -> 25+50 = 75

Now we lerp like this: (ColorA,ColorB,BrushStrength) let's say BrushStrength is 0.5 and the colors are again yellow and blue:

((1f-0.5f)* (1f,1f,0f,1f)) + (0.5f * (0f,0f,1f,1f)) ->  (0.5f, 0.5f, 0f, 0.5f) + (0f, 0f, 0.5f, 0.5f) = ( 0.5f, 0.5f, 0.5f, 1f) 

 

3,) I think you want the alpha lerp trick:

Let's say you have yellow(1,1,0,1) and a transparent blue (0,0,1,0.5). Lerp the alpha based on some kind of brush hardness or something, lets use 0.5 again:

lerp(1f, 0.5f, 0.5f) = 0.75f Then add the two colors and multiply each value except alpha:  ((1f,1f,0f) + (0f, 0f, 1f)) * 0.75f = (0.75f, 0.75f, 0.75f) After this just add back the alpha.

I tried Gimp, it uses a similar formula:

GimpColorMix.jpg.e1ae6fcc4a76da06d5304b58ea33cee5.jpg

Different software will use different alterations to the formula. Some even attempt to recreate real world color mixing.

8 hours ago, Scouting Ninja said:

This is one way to do it. The way it is normally done is a custom shader for drawing on is made, the same as with any other engine. Unreal also allows you to do this by creating a editable instance material, saving the texture is your own responsibility though.

Then again using the UCanvasRenderTarget2D gets the job done.

You want to mix based on the brushes, in other words you want to lerp the colors for real. Unreal has lerp but let me explain how it works:

...

Thank you for taking the time for your reply, I fear you may have missed my goal however. I'm trying to find a solution to a problem. The problem is white. Perhaps this part wasn't even implied, so let me say it explicitly. If I add any two colors, I get white. If I add blue and blue, I get white. The material has to be set to additive in order for this method to work.

Here is a the live training video that all this code was adapted from (by others). 

 The video covers height map painting, and people adapted it for whiteboards and the like. Which I in turn then adapted for painting colours, albeit poorly and malfunctioning.

Here is an example of what I mean, I'm sorry for not having included this initially.

eFfJ8M8.png

19 hours ago, coope said:

Here is an example of what I mean, I'm sorry for not having included this initially.

This is happening because of Unreal's HDR color range. This means that you aren't clamping your colors. HDR allows for colors that go beyond just 1. For example if you made a new material, shadles, then set the color blue to (0,0,10,1) it will have the same effect.

HDR.jpg.72acf07f7af3d3f28f68bb5dc67d7f6e.jpg

Color should ideally always fall into (1,1,1,1), In this image you are showing the color should be something like (0,0,30,1) so the engine uses HDR calculations to get a artistic impression of what a color like that would look like to the eye.

You just keep adding more and more colors, without correcting:

ColorAdding.jpg.6df01642396f5169c19810f8156e73ee.jpg

When you sample the UV map, to get where to draw, try sampling the pixel at that point. Then after adding the two colors, average the colors or clamp them.

For example, if the pixel is blue (0,0,1,1) and you add more blue (0,0,1,1) it should work like this: (0,0,1,1) + (0,0,1,1) = (0,0,2,2) Now we divide by the amount of colors in the equation: (0,0,2,2)/2 = (0,0,1,1)

DevideByTwo.jpg.ba1abd12af58d9c1da37a718b9a443aa.jpg

In this image you see me dividing by the amount of colors added(2). So every time I add two colors I correct the color range. This is the slow accurate way as it will have to divide for every addison.

 

So lets say you had some kind of aggressive addition, lets add  a blue*10 to a blue*100; this emulates the resualt of a 1000 additions.

AgressiveBlue.jpg.53cc5f455b6dc6821a2101d9d6103dc7.jpg

To correct it all at once we use the fast way, a clamping formula:

ClampColor.jpg.e2e0b6e4308b75cea5361e5fb5a6015b.jpg

We break the end color into floats, clamp each to 0 as a min and 1 as a max, then merge them back into a final color.

 

Look at your own formula and decide what would work best.

What ended up getting me where I needed was writing a class to procedurally generate a circular texture. I developed said class with the purpose of being used as a brush, so it has some softness to it and can be scaled as far as the end result is concerned. This texture is then fed into the process covered here:

https://www.raywenderlich.com/5246-unreal-engine-4-tutorial-painting-with-render-targets

This topic is closed to new replies.

Advertisement