Shader Dev Study 02: Sidemask Pattern

Table of Contents

Abstract

  • 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

Algorithm

				
					/*
maya/projects/arnold/src_c++/dd_SideMask.cpp
*/
#include <ai.h>
#include <cstring>
#include "utilities.h"


AI_SHADER_NODE_EXPORT_METHODS(SampleMethods);
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;
        }
    else
        {
        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 docs.microsoft.com.

				
					/*
maya/projects/arnold/src_c++/utilties.h
*/


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]
	maya.id				INT		15
	maya.name			STRING	"ddFrontRear"
	maya.classification	STRING	"Utility"
	[attr frontColor]
		maya.name		STRING	"frontColor"
#		desc			STRING	""
	[attr rearColor]
		maya.name		STRING	"rearColor"
#		desc			STRING	""
	[attr swap]
		maya.name		STRING	"swap"
#		desc			STRING	""
	[attr cross_dissolve]
		maya.name		STRING	"cross_dissolve"
#		desc			STRING	""
		min				FLOAT	0
		max				FLOAT	1
#		softmin			FLOAT	0
#		softmax			FLOAT	10

				
			

Template Python File

				
					# maya/projects/arnold/ddFrontRearTemplate.py
import pymel.core as pm
import mtoa.utils as utils
import mtoa.ui.ae.utils as aeUtils
from mtoa.ui.ae.shaderTemplate 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
        self.addSwatch()
        self.beginScrollLayout()

        # 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")

        self.endLayout()

        # include/call base class/node attributes
        pm.mel.AEdependNodeTemplate(self.nodeName)

        # Add Section for the extra controls not displayed before
        self.addExtraControls()
        self.endScrollLayout()

				
			

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

Conclusion

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.