Shader Dev Study 02: Sidemask Pattern

Table of Contents


  • This project is a study in C++ programming techniques to develop an custom pattern node called “SideMask“.
  • In addition, it covers creating a Maya interface for the shader using a template Python script from Arnold.
  • The current implementation of the SideMask node allows an artist to:
    • Apply two colors to a surface – one color for the front side and a second color for the back side. 
    • Swap the front/back side colors  
    • Perform a cross-dissolve of the two colors


#include <ai.h>
#include <cstring>
#include "utilities.h"

namespace {
    enum paramIndex { k_front_color, k_rear_color, k_swap, k_cross_dissolve};

node_parameters {
    AiParameterRGB("frontColor", 0.7f, 0.7f, 0);
    AiParameterRGB("rearColor", 0.7f, 0, 0);
    AiParameterBool("swap", 0);
    AiParameterFlt("cross_dissolve", 0);

shader_evaluate {
    AtRGB front = AiShaderEvalParamRGB(k_front_color);
    AtRGB rear = AiShaderEvalParamRGB(k_rear_color);
    bool  swap = AiShaderEvalParamBool(k_swap);
    float dissolve = AiShaderEvalParamFlt(k_cross_dissolve);

    // incoming direction of the "camera ray", already
    // normalized, but it must be reversed so that it is
    // tail-to-tail with the surface normal.

    // Geometric surface normal, but we have to normalize
    // the vector otherwise we get the wrong angle (as the
    // cosine) when we use the dot product.
    float dot = AiV3Dot(-(sg->Rd), AiV3Normalize(sg->Ng));
    AtRGB a, b;

    if(dot < 0) {
        a = (swap) ? front : rear;
        b = (swap) ? rear : front;
        a = (swap) ? rear : front;
        b = (swap) ? front : rear;

    sg->out.RGB() = mix(a, b, dissolve);
node_loader {
    if (i > 0)
        return false; 
    node->methods        = SampleMethods;
    node->output_type    = AI_TYPE_RGB;
	node->name           = "ddFrontRear";
    node->node_type      = AI_NODE_SHADER;
    strcpy(node->version, AI_VERSION);
    return true;
// The remaining macros can be left "empty"
node_initialize { }
node_update { }
node_finish { }


Instead of having to write a Mix function in each coding project, a utility header file “utilities.h” was created. This allows us to define the functions and declarations which can be reused for multiple coding project, thus minimizing the potential for errors.

To use make use of that header file, we need to: write in a #include directive in every .cpp file or other header file that requires that declaration. The #include directive inserts a copy of the header file directly into the .cpp file prior to compilation.

Notice in line 6 of the above C++ code that we do so via ‘#include “utilities.h” ‘. To learn more, visit


AtRGB mix(AtRGB a, AtRGB b, float alpha){
	return a*(1-alpha) +b *alpha;
					# This .mtd file is intended for use with Maya. If your shader will be used by
# Houdini the "style" of the .mtd can be set in Preferences->Languages-Arnold SDK.
# This file is automatically updated by Cutter when its corresponding shader
# is compiled.

[node ddFrontRear]				INT		15			STRING	"ddFrontRear"
	maya.classification	STRING	"Utility"
	[attr frontColor]		STRING	"frontColor"
#		desc			STRING	""
	[attr rearColor]		STRING	"rearColor"
#		desc			STRING	""
	[attr swap]		STRING	"swap"
#		desc			STRING	""
	[attr cross_dissolve]		STRING	"cross_dissolve"
#		desc			STRING	""
		min				FLOAT	0
		max				FLOAT	1
#		softmin			FLOAT	0
#		softmax			FLOAT	10


Template Python File

					# maya/projects/arnold/
import pymel.core as pm
import mtoa.utils as utils
import as aeUtils
from import ShaderAETemplate

# notice  the name of the class must be AE<shadername>template

class AEddFrontRearTemplate(ShaderAETemplate):

    def setup(self):
        # Add the shader swatch to the AE

        # Add a list that allows to replace the shader for other one
        self.addCustom('message', 'AEshaderTypeNew', 'AEshaderTypeReplace')

        # Begins a "Color Section"
        self.beginLayout("Color Section", collapse=True)
        self.addControl("frontColor", label="Front Color", annotation="Front Color")
        self.addControl("rearColor", label="Rear Color", annotation="Rear Color")

        # Begins a "Swap Dissolve"
        self.beginLayout("Swap Dissolve", collapse=True)
        self.addControl("swap", label="swap", annotation="swap")
        self.addControl("cross_dissolve", label="Cross Dissolve",
                        annotation="Dissolves between front and rear colors")


        # include/call base class/node attributes

        # Add Section for the extra controls not displayed before


How to Install

Placing the files

  • Download this zip file.

  • Unzip and put the files under your Maya script folder: Users/username/Documents/Maya/projects/arnold 

  •  The node will located in Maya > Hypershade > Arnold Utility

* This node will only work on Mac OS.

Referencing the python file

  • Open your Maya Environment file located in: ~/Library/Preferences/Autodesk/maya/2020/
  • Add this line at the end: MTOA_TEMPLATES_PATH = $HOME/Documents/maya/projects/arnold
  • Save the file


As interesting as Shader Development is, I find that it is a shame that I will not being using this skill set in my future employment or Motion Design career. One of thing I asked myself when selecting courses to take at SCAD is: “Can I learn this outside of school after I graduate?” Technically yes, but it would be immensely difficult due to lack of allocation of resources, time, and effort as this is quite niche and advanced topic. Taking a ten-week course allows one to focus and deeper on an expertise or subject matter, and come out with a substantial research or portfolio piece.

That said, this course and study will serve as a testimony to how different disciplines can inform a creative practice. Only time will tell how “useful” this study was in hindsight, or maybe not at all which is just as perfectly fine.