Tutorial: Offsetting Texture Scale Using Vertex Painting

I had a problem last week. I needed to be able to vary a texture from a straight grid to one of variable sizes. I had considered using a larger texture, but when your surface area as large as mine was, it became clear that I’d be using a 4096 x 4096 or larger. So instead I looked to using vertex painting to vary the texture size and thus, breakup the design.  The result is a vertex material that can vary the size of the texture using a single vertex color channel.

Part I: The setup & forward logic chain

Before I setup the material i’d like to explain some of the logic I used here. In order to use vertex painting to modify UV coordinates, the values need to be clamped to ranges. This way we can paint at several different intensities between 0.0 and 1.0 and get different sizes without warping the UV’s. I decided to use 0.25, 0.5 and 0.75 as both my painting ranges and my UV multiplication values. This means the brighter the paint color, the smaller my UV multiplier would be set making my image scale larger.

I started with a vertex color node and my clamp / multiplier constants of 0.25, 0.5 and 0.75. Two extra constants of 1 and 0 are added, and their purpose will be explained along the way. I also setup a test constant to manually plug numbers into for testing/demonstration purposes (when we are finished, it will be replaced with the vertex color node.)

Next we’ll setup a basic IF statement. Be sure to activate the box in the upper left corner of the If node to turn on real time display. Plug our test constant into the A slot and 0.25 into the B slot.

Now lets go over the logic of how this node works into our setup.  We want to make sure anything below our smallest value, .25 in this case, doesn’t have anything done to its UV’s. The logic works like this: If the vertex color is less than 0.25, the end result will be 1 or no UV change. If the vertex color is greater than or equal to 0.25, the output will be zero, or off.  Now this may seem weird that we’re using zero as an output, but this will make more sense in the next section. Plug zero into the A>B result slot and 1 into the A=B and A<B result slot.

As it stands now, if we paint a any value in our channel from zero to .24, we will multiply that UV section by 1, which will do nothing to scale our UV’s.  Now lets add 3 more If nodes and get to building the rest of this chain.

Now we want to build our low range. Plug the test constant into the A slot. We want to see if the vertex color is greater than 0.25, so plug 0.25 in to the B slot.

As the If node’s comment indicates, we want anything between 0.25 and 0.54 to scale our UV’s by 0.75. This will make our scale 3/4th’s the size of the original. Therefore the logic for this node is if our vertex color is greater than or equal to 0.25, the end result will be 0.75. If the vertex color is less than 0.25, the end result will be zero or off. Plug 0.75 into the A>B slot and A=B slot and zero into the A<B slot.

Now if we dial our test constant up to 0.255, we can see the if nodes we connected change.

Next we’ll need to setup our mid and high range together. These sequences will have exactly the same logic as our low range sequence, making them easier to do. We’ll start by plugging our text constant into the A slot of the remaining two IF nodes. Plug 0.5 into the B of the Mid Range If node and 0.75 into the B of the High Range If node.

Since the logic the thee nodes is exactly the same, we can repeat the same pattern as the Low range if statement, we can plug up the nodes in exactly the same sequence. We’ll start by connecting zero to both of the A<B result slots.

Now we’ll connect up the remaining slots.  Since 0.5 is the mid tone range starting point and the multiplier, it makes our life easy. Connect .5 to the A>B and A=B result slots. This will declare that when painting 0.5 or greater, that 0.5 will be our end result. The high range works exactly the same way, except we’re looking for a paint range of 0.75 or greater and using 0.25 as our end result. Connect 0.25 to the A>B and A=B result slots.

Dial up the test constant to 0.555.  See how the midtone range value turns on? When we set the value to 0.755 the top if statement will change as well.

Part 2: the inverse logic chain

Now that the first part of the chain is complete, let me explain how the rest of this will work.  Reset the Test Constant value to zero.  See how the bottom if statement turns white while the rest go black? We’ve built up a clamping situation where as the vertex color increases, it activates the ranges in the if nodes of our forward logic chain outputting our ranges instead of zero. The problem now is only the bottom node works properly. The other three all turn on once their range is hit, but once their range is surpassed by another range there isn’t anything turning them off. This is where the inverse logic chain comes into play.

We’ll start by placing two more If nodes. This is because we’re only really interested in being able to turn off the Low and Mid ranges.  The No-Paint Range node already works and nothing exceeds the high range.

For demonstration sake, I’ll set my Test Constant value to 0.555 . Connect it to the A slots of the two new if nodes. Connect the zero node to the A>B slots of both of the if nodes as well.  This will make sense momentarily when we connect up the rest of the inputs.

We’ll start by going over the logic for the If node in the Low Range Check. Since both nodes are active, we want is to turn off (or black) the low range once it exceeds 0.54.  To do this, we’ll be comparing this if node against the vertex color input and 0.5. If the vertex color is greater than 0.5, turn it off (or black.) If the vertex value is less than or equal to .5, allow the Low Range If node to pass through.

Now plug 0.5 into the B slot of the Low Range Check If node and the output of the Low Range If into the A=B and A<B slots.

The same logic applies to the Mid Range Check as well, except we’ll be plugging the 0.75 value for the B slot. Plug the Mid Range If into A=B and A<B slot.  The If node should light up.

See whats going on here? If your still confused, reset the Test Constant to 0 and enter in values 0.255, then 0.555 the 0.755. See how at each end only one if node is a grey color while the others are all black?   We’ve clamped our ranges in a manor that lets us tally the result of all the If nodes and add them up for our final UV multiplier.

Part 3: Setting up the UV multiplier

Place 3 add nodes and connect them up like so. It should become pretty clear how this system works now.

Swap out the Test Constant for a single vertex color channel. I’ll be using red for my setup. The cool thing is we setup all our If nodes with the vertex color channel as the A slot, so disconnecting and reconnecting this node is pretty painless. Because the vertex channel outputs 1 by default, the top node should be the final result.

Setup your texture sample with a Texture coordinate (with any desired base offsets) and multiply node.

As this setup currently stands, we’re going to have to flood fill our desired mesh black, otherwise when the material is applied we’ll see our maximum scale applied to the entire mesh.

Now paint away! Remember our ranges are .25 .5 and .75, so setting them in your color channel will produce the desired scale results.

I hope you found this a useful addition for your creative project.