Author Topic: Random gradient from custom bitmap lines  (Read 9250 times)

@Sergey Danchenko amazing stuff

I'm having the exact same requirement for a current project.
Looking to introduce slopes to cracks cells, in order to mimic tile destruction from refs.
Basically that requires filling with gradients everywhere, and as you can see it's quite a complex task to do manually.

I'm super curious how you managed that bit.

I've managed it only because the solution was already laying in front of me thanks to the two nodes I've made before (lucky!  ;D). Still took me three full days to grasp it.

In a nutshell, there are three key aspects to this node:

1) You need to generate a gradient that is able to run in different directions basing on some "angle" parameter. At first, I thought that this would be the most difficult part. Surprisingly, it was the easiest part as there are already some great solutions for gradients on Share that worked perfectly well.

Initially, I was looking for a way to generate the gradient that would run from black to white for each tile in the mask right away. Somehow I figured that it's more important to actually HAVE a gradient, and it would be more productive to look for a way to maximize its range in a separate step.

2) You need a variation map to drive gradient angles. This one was covered by the Randomize Mask node I've made earlier.

3) You need some kind of Auto Levels functionality to maximize the gradient's dynamic range for each individual tile.

The problem with "vanilla" Auto Levels shipped with Substance Designer was that it can work on a "macro" level only, so it would level out an entire image. It would remap it to a new range in a way that would make the darkest pixel in the image the "new black" and the brightest one would be the "new white". Unfortunately, this wouldn't be helpful for our case.

Here the Auto Levels Plus node comes into play. It was implemented through the Pixel Processor, so it can work on a "micro" level, i.e. on a per-pixel basis. The node uses a specific math formula to remap each pixel to a new range of values. However, it is required to be supplied with two values to work correctly: one that would define the "old range minimum" and one for the "old range maximum". In our case, that would be the darkest pixel in a gradient and the brightest one.

As the Auto Levels Plus node works on the per-pixel basis, it can level out individual tiles in the mask to a common new range if supplied with correct data. From here, we need to get the "old minimum" value and the "old maximum" value for each tile in the mask, then store them in two additional "data" maps to provide the Auto Levels Plus function with this values for each pixel processed. The important thing here is that such values should be exactly the same throughout the individual tile in the mask, so the entire tile would be remapped to a new range using the same data.

From here, the Randomize Mask node comes back into play. The key feature of this node is a function that can spread (propagate) brightest pixels sampled in the tile throughout the entire tile without crossing its borders. Using this function, we can find and store in a map maximum values of gradients that run in each tile. This will cover half of our needs for the Auto Levels Plus function. In a similar manner, we can sample for the darkest pixels in tile's gradients and store them in a map as well.

At this point, we have everything we need to auto level individual tiles with random gradients to their maximum range (for example, 0-1, or black-to-white). The Auto Levels Plus function would take the mask with gradients as the main input and two data maps as additional inputs. The function will sample each pixel in all three maps and use appropriate values to remap main input pixels to a new range using the math formula.

Basically, that's it. See the image attached for a visual guide.

Fun fact: working on this node I've detected a couple of shortcomings in the Auto Levels Plus node itself. Fixing them made the node 10x-30x times faster than the "vanilla" Auto Levels (was so-so). Double profit.  ::)

I'm super curious how you managed that bit.

bunch of really clever stuff

Wow using levels is brilliant!

I wonder, on a complex mask like mine, would each gradient be very pixallated?

Nope. In my tests, it seems that using 16-bit mode for the node gives it enough values to produce a smooth gradient. In a corner case, 32F bit depth can be used.


Hey mate, any progress on your plugin? can't wait to start messing with it!

I was a bit busy until today, so the node was put on hold. Now I have some time for it, so I will continue.  ::)

I was a bit busy until today, so the node was put on hold. Now I have some time for it, so I will continue.  ::)

Oh , dude , you ARE amazing!!!

I came up with almost the exact same idea a while ago , and have been working on it for 3 days . I have got some how acceptable result using both fx-map and pixel processor.(fx-map to get max and min luminosity , pixel processor to level every mask to full white-to-black range). But i had trouble processing maps sized up to 4096 , my fx-map take TOO MUCH time to get me result .  I was going crazy to get it  to work , the fx-map had the Iteration number overflowed and it just stopped working , I thought i was done there.

And then I came across with two of your post : the randomized mask and this post . Turns out your node is far more organized and runs better!

I'm looking forward to your next work!!

And by the way ,
would you like to look into one of my node ?

I made this node for my co-workers to generate unique curve shapes , but it turns out to be difficult to use . Is there some way around or some ways to optimize it , any tips could be apprecialted.

Thank you for kind words. Actually, the implementation concept posted above is my second take on this task. First I've assembled a prototype that used literally 1000+ Pixel Processor nodes to isolate and level out luminance values in a range of 1-255. It worked to some extent, but it wasn't reliable and what's more important it was slow. Computation times were acceptable around 1500ms, but before computation, it had to pump the data through that many nodes, and it was lagging for like 5-6 seconds before the node would be updated.

I was quite lucky to find another solution same morning.

And by the way ,
would you like to look into one of my node ?

I made this node for my co-workers to generate unique curve shapes , but it turns out to be difficult to use . Is there some way around or some ways to optimize it, any tips could be apprecialted.

I'll take a peak, but I'm not really that advanced in SD nodes as it may look. If something useful would come up, I'll let you know.  ;)

Sergey, how did you get the RotateMask node to be seamless?
Afaik it just samples the uvs in rotational pattern, so if a tile is overlapping the edges the gradient breaks.

Edit: figured it out, if you're stuck on this lemmi know. ;)

Last Edit: June 24, 2017, 04:55:05 am

I've found Slope Mask works best with pretty thick borders.
To compensate I've added padding & spread to the gradients so it essentially remove the borders.

Here's a test of simply plugging it to the height mask.
Really awesome node thanks for sharing the theory Sergey! can't wait to play more with this ;)

Seems that you get it working. Nice job! ;)

Apologies for the thread-necro, but is this something either of you have shared anywhere? That last image from chai looks like something that would be incredibly useful as a tool in my (and I'm sure many other's) arsenal. :)

BTW, we may come with an official solution (really) soon ;)

Cool! Can't wait to check it out  ;D

thephobos, I haven't shared anything yet. I was going to make a push and finish the node, but it seems that it may be too late  ;).