Please Don’t Use The Mask Input on a Merge Node

This tip is going to be a quick explanation about why I don’t like using the mask input on a merge node in Nuke. It’s something I’ve seen a lot recently when I’ve been picking up other people’s scripts.

When I ask artists why they use the mask input, they say things like, ‘It’s easy’, ‘It’s simple’, ‘It’s less nodes’, ‘It just makes sense to work this way’ – and they think I’m being fussy when I disagree with them.

Maybe I am being fussy. Maybe I’m too stuck in my ways. Maybe I’m just a grumpy old compositor who doesn’t like other ways of doing things (lots of people I’ve worked with might agree with that).

But I thought I should at least explain my reasoning as to why using the mask input on a merge node is far from ideal.

I have made a video version of this post which you can watch here, or continue below to read the text version.

I’ve recently started to learn Python, and one of the things I’ve read, that I really appreciated, is the Style Guide for Python Code.

This is a document about suggested best practices for writing your Python code. One of the key philosophies in the guide is that, ‘Code is read much more often than it is written,’ and therefore: “Readability counts.”

There is also a document called “The Zen of Python”, which includes the lines:

Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.

When I read through these principles, I feel like most of them are equally applicable to how you should build your comp scripts in Nuke.

While it’s important to build an efficient script that renders quickly, it’s equally important to build a script that is easy to read and understand.

Computers are fast and cheap these days. Humans haven’t kept up. Saving a few milliseconds of CPU time is pointless, if you build a script that confuses an artist for 15 minutes before they can address a simple note.

I’m all for using as few nodes in a script as possible, but I agree with the idea that explicit is better than implicit, and I think adding a few basic nodes to your script to make it easier to follow is a good thing.

Which brings me back to the mask input on a merge node.

The mask input on a merge node allows you to control which areas of the A input are merged with the B input via a third input, the mask. By default, it takes the alpha channel of the mask input and uses it as a matte.

In this example, I want to use the alpha channel from the ColorWheel to mask the CheckerBoard as it goes over the white constant.

I can also achieve the same result by separating the mask operation and the merge operation out into two steps. To do this I would apply the alpha channel from the ColorWheel as a mask for the CheckerBoard as step one, then merge the CheckerBoard over the constant.

Some people would argue that this extra node is unnecessary and untidy, but I believe that the added readability makes it worthwhile.

In this setup, I can see the flow of the script more clearly. If I zoom out in our node graph and lose the labels on my node inputs, I still know what each branch of the script is doing, especially if we make a point of always running the B pipes vertically and the A pipes horizontally.

Compare that to the example where everything is happening in one node and you can see that it is far less obvious what’s going on.

By applying the mask to the A pipe before the merge node I can easily visualise the regions of the A input that are being used in the merge operation.

If I apply the mask to the merge node directly, there is no way to see how it is being applied to the A input.

Being able to see this step separately from the merge operation not only helps someone follow what is happening in the script, but is also useful when troubleshooting problems in the script.

And by keeping the mask and the merge operations separate, I can disable each part separately too. This also helps with script readability and troubleshooting.

If the merge and the mask are being applied by the same node, when I disable the node, I can’t differentiate what was coming from the A input, or what was coming from the mask.

Working explicitly goes one step further if I want to start modifying this matte. For example, I might want to use the red channel of the ColorWheel input as the mask, and I might want to invert that red channel too. I could do all of that inside the merge node by changing the mask channel dropdown, and checking the invert checkbox.

But if you look at the merge node, you can see that nothing on the node itself changes when I do this.

As a user, I have no idea that anything other than the default is happening – unless we go looking for it. And even then, it’s hard to visualise what the inverted red channel might look like.

To make these decisions more obvious, I would use a shuffle and then an invert node after the ColorWheel, before I apply it as a mask.

Even if these nodes don’t say exactly what is happening inside them, I at least have an idea that we might be using something other than the alpha channel as the mask, and I can see the result of each step.

As you can probably tell, I think script readability is really important.

I think you should always assume that someone other than yourself might have to open any script you create. Or that even if the deadline for this shot might be today, you could have to open this script in three months’ time and you will need to be able to work out what you were doing when you set everything up.

Using the mask input on a merge node is just one of the many things that I think can make a script slightly less easy to read.

Let me know what you think about using the mask input on a merge node in the comments below.