Wednesday, 21 May 2014

Masking a volume.

Today we'll look at defining a 3d mask.

I originally made this set up for a quick and dirty rain test. The rain was one big gpu particles emitter, no collisions, no nothing, so it was raining indoors.
The dirty approach to solve this issue was to make the rain transparent in the indoors volume.

The idea is to define the range which will remain white in each of the x, y and z axis and then multiply everything together to define the volume.

Defining the range per axis.

We're using a set up I've already described so I'll be quick there. (Told you I liked to use it all over the place.)
 
 For each axis, we're remapping a range of values to a gradient from 0 to 1, then we will also ceil it and clamp the result.


We do it for the min, and we end up with 0 below the minimum and 1 until the infinite.
We do the same thing again but we invert the values (min becomes max and vice versa) so we end up with 0 above the max and an infinite 1 in the negative direction.
Finally, we multiply the min and the max.

Now our range is 1 and any value above or below is 0.

Doing it the proper way.

That was the simple way of explaining it and the way I actually created the original material, but while I recreated it for this post I realised the set up could be simplified a lot with a decent saving on instructions count (34 instead of 43). The idea is the same but we're dealing with all 3 channels at the same time for the mins on the one hand and on the other hand for the maxs. After we've been through the value (world position in this case) minus min / divided by max minus min / ceil / constant clamp, we separate the 3 channels (with a component mask) and multiply them by one another.

We end up for the mins with 0 below the min and an infinite 1 along the positive of each axis, and for the maxs with 0 above the max and an infinite 1 along the negative of each axis. 
Multiply mins and maxs together and you've got your volume.


In the following video, I'm moving the emitter around so you can see that the coordinates are in world space. (I applied that material to a bunch of simple sprites.)




We could also make them local space if we'd fancy that, by simply subtracting the object position to the world position.