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.
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
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(¶s->cosPower); miScalar reflectionSpecularity = *mi_eval_scalar(¶s->reflectionSpec); miColor materialSpecularColor = *mi_eval_color(¶s->specularColor); miScalar phongSpecular = compute_phong_specular(&pLightDirection, specularExponent, reflectionSpecularity, &pReflectionDirection, state); if (phongSpecular > 0.0){ return phongSpecular * materialSpecularColor * pLightColor; } else{ return BLACK; } }
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.