Creating a pass-compliant shader using the AdskShaderSDK
 
 
 

Create a shader based on the AdskShaderSDK to implement components resulting in a shader that automatically supports multi-render passes. A component represents the decomposition of material and light interaction, that is, the diffuse material color component, the ambient component, and so forth.

A pass-compliant shader is made of 2 distinctive parts: a shader mi declaration, and the C++ implementation which needs to be built using the mentalmay API and the AdskShaderSDK.

The shader declaration file defines the interface between Maya and mentalray. It also defines the supported version of MentalRay for this shader.

Pass-compliant shaders written using the AdskShaderSDK must be implemented in C++ in order to leverage the hierarchical design of the framework.

The files are then compiled and linked against the mentalray API and the AdskShaderSDK to create a dynamic library which can be used in Maya.

A complete reference to AdskShaderSDK can be found here.

Sample shader implementation

The shader declaration file

A sample MayaPhong.mi is as follows:

declare shader  
 # Return struct	
struct {
	color "outColor",	
	color "outGlowColor",		
	color "outMatteOpacity",		
	color "outTransparency",		
	# BRDF components		
	color "outAmbient",		
	color "outIncandescence",		
	color "outIrradiance",	
	color "outDiffuseShadowed",		
	color "outDiffuseNoShadow",		
	color "outShadow",		
	color "outSpecularShadowed",	
	color "outSpecularNoShadow",		
	color "outReflection",		
	color "outRefraction",		
	color "outScatter",		
	color "outOpacity"    }   
"MayaPhong" (        	
	# Render Pass Parameters        	
	array string        "FrameBufferNames",        
	array integer       "FrameBufferTypeCounts",        	
	boolean             "UsingPerLightContribution", 
	string              "LightFrameBufferMapping", 
	# Inherited from Base Material        	
	color               "color", 
	color               "transparency", 
	# Inherited from Matte Material	
	integer             "matteOpacityMode",	
	scalar              "matteOpacity", 
	# Inherited from Glow Material
	scalar              "glowIntensity",
	# Inherited from Lambertian Material
	integer             "refractionLimit",	
	scalar              "refractiveIndex",	
	boolean             "refractions",	
	scalar              "diffuse",	
	color               "ambientColor",	
	color               "incandescence",	
	scalar              "translucence",	
	scalar              "translucenceFocus",	
	scalar              "translucenceDepth",	
	scalar              "opacityGain", 
	Boolean             "hideSource",	
	scalar              "surfaceThickness",	
	scalar              "shadowAttenuation",	
	scalar              "transparencyDepth",	
	scalar              "lightAbsorbance",	
	boolean             "chromaticAberration",	
	vector              "normalCamera",	
	color               "irradiance",	
	color               "irradianceColor",	
	scalar              "refractionBlur",	
	integer             "refractionBlurLimit",	
	integer             "refractionRays",	
	color               "scatterColor",	
	scalar              "scatterRadius",	
	integer             "scatterAccuracy",	
	integer             "scatterFalloff",	
	integer             "scatterLimit",	
	integer             "scatterCache",	
	# Inherited from Reflective Material	
	integer             "reflectionLimit",	
	color               "specularColor",	
	color               "reflectedColor",	
	scalar              "reflectivity",	
	scalar              "reflectionSpecularity", 
	scalar              "reflectionBlur", 
	scalar              "reflectionBlurLimit", 
	integer             "reflectionRays", 
	# Phong parameters	
	scalar              "cosinePower" 
 ) 
version 1   
apply material
end declare

As shown above, the shader declaration comprises two sections, the return structure and the render pass parameters.

In our example, the return structure contains the components of the legacy Maya render passes. The render passes (for multi-render passes) are automatically written to named frame buffers in the AdskShaderSDK.

For a more complete guide on how to write shader declaration file, refer to the documents mental ray shader language extensions and Write a shader declaration file.

AdskShaderSDK shader C++ implementation

The shader parameters

This section of the C++ file is needed to expose the parameters used by our shader. The order of this parameter list must match the one defined in the shader declaration file.

To achieve this, the MayaPhongParameters struct is defined to first expose the default parameters of a reflective shader using the macro ADSK_REFLECTIVE_MATERIAL_PARAMETERS, followed by the custom parameters necessary to implement MayaPhong. In our example, the miScalar cosPower represents the Phong specular exponent for our sample shader. Refer to adskShader.h for other relevant parameter macros.

struct MayaPhongParameters {   
	ADSK_REFLECTIVE_MATERIAL_PARAMETERS 
	miScalar cosPower;
};

The shader component definition

The AdskShaderSDK default components are defined in adskComponent.h. For this particular example, we override the specular component since the default has no specularity. The component written as an override must match the declaration of the default exactly:

template <typename ParameterType>
class MayaPhongSpecularComponent {
 public:    
	MayaPhongSpecularComponent(miState *state, ParameterType *paras);
	~MayaPhongSpecularComponent() {};    
	miColor operator()(miState *state,    
 			   ParameterType *paras, 
 			   miColor &pLightColor, 
 			   miVector &pLightDirection,
			   miVector &pReflectionDirection);
};

The shader component implementation

The operator() member function is called for each sample. Inside this function, any mental ray and AdskShaderSDK functions may be called. If you require any dynamically allocated memory you must use the mental ray API calls mi_mem_allocate() and mi_mem_release().

The following is an example of how to implement basic Phong specularity:

template<typename ParameterType>
miColor MayaPhongSpecularComponent<ParameterType>::operator()(miState *state,
	                                ParameterType *paras,
	                                miColor &pLightColor,
	                                miVector &pLightDirection,
	                                miVector &pReflectionDirection){
	// get the relevent parameters   
	miScalar specularExponent = *mi_eval_scalar(&paras->cosPower);
		miScalar reflectionSpecularity = *mi_eval_scalar(&paras->reflectionSpec);
	miColor materialSpecularColor = *mi_eval_color(&paras->specularColor);
	miScalar phongSpecular = compute_phong_specular(&pLightDirection,
						specularExponent,
						reflectionSpecularity,
						&pReflectionDirection,
						state);
	if (phongSpecular > 0.0){ 
		return phongSpecular * materialSpecularColor * pLightColor;
	} 
 else{ 
 return BLACK;  
 }
} 

Defining the shader class

Our new shader class is a template instance of the material class and therefore we need to specify the template parameters:

typedef Material<    
	MayaPhongParameters,
	DefaultAmbientMaterialColorComponent<MayaPhongParameters>, 
	DefaultAmbientComponent<MayaPhongParameters>,
	DefaultDiffuseMaterialColorComponent<MayaPhongParameters>, 
	DefaultDiffuseComponent<MayaPhongParameters>, 
	MayaPhongSpecularComponent<MayaPhongParameters>
> MayaPhongClass;

Finally, in order to expose our new shader to Maya we must call the macro below.

EXPOSE_CUSTOM_MATERIAL(MayaPhong) 

The macro parameter must be named such that MayaPhongParameters, and MayaPhongClass are already defined, that is, it always appends the words Parameter and Class to the argument when looking for the respective types.

NoteRefer to the adskShaderSDK\Samples\MayaPhong folder in the devkit for a shaderSDK example.