phongShader.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

#include <math.h>

#include <maya/MPxNode.h>
#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnLightDataAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnPlugin.h>

// add for raytracing api enhancement
#include <maya/MRenderUtil.h>

//
// DESCRIPTION:
class PhongNode : public MPxNode
{
    public:
                      PhongNode();
    virtual           ~PhongNode();

    virtual MStatus   compute( const MPlug&, MDataBlock& );
    virtual void      postConstructor();

    static void *     creator();
    static MStatus    initialize();
    static MTypeId    id;

    private:
    static MObject aColor;
    static MObject aTranslucenceCoeff;
    static MObject aDiffuseReflectivity;
    static MObject aIncandescence;
    static MObject aPointCamera;
    static MObject aNormalCamera;
    static MObject aLightDirection;
    static MObject aLightIntensity;
    static MObject aPower;
    static MObject aSpecularity;
    static MObject aLightAmbient;
    static MObject aLightDiffuse;
    static MObject aLightSpecular;
    static MObject aLightShadowFraction;
    static MObject aPreShadowIntensity;
    static MObject aLightBlindData;
    static MObject aLightData;

    static MObject aRayOrigin;
    static MObject aRayDirection;

    static MObject aObjectId;
    static MObject aRaySampler;
    static MObject aRayDepth;

    static MObject aReflectGain;

    static MObject aTriangleNormalCamera;

    static MObject aOutColor;

};

// Static data
MTypeId PhongNode::id( 0x81001 );

// Attributes 
MObject PhongNode::aColor;
MObject PhongNode::aTranslucenceCoeff;
MObject PhongNode::aDiffuseReflectivity;
MObject PhongNode::aIncandescence;
MObject PhongNode::aOutColor;
MObject PhongNode::aPointCamera;
MObject PhongNode::aNormalCamera;
MObject PhongNode::aLightData;
MObject PhongNode::aLightDirection;
MObject PhongNode::aLightIntensity;
MObject PhongNode::aLightAmbient;
MObject PhongNode::aLightDiffuse;
MObject PhongNode::aLightSpecular;
MObject PhongNode::aLightShadowFraction;
MObject PhongNode::aPreShadowIntensity;
MObject PhongNode::aLightBlindData;
MObject PhongNode::aPower;
MObject PhongNode::aSpecularity;

MObject PhongNode::aRayOrigin;
MObject PhongNode::aRayDirection;
MObject PhongNode::aObjectId;
MObject PhongNode::aRaySampler;
MObject PhongNode::aRayDepth;

MObject PhongNode::aReflectGain;

MObject PhongNode::aTriangleNormalCamera;

#define MAKE_INPUT(attr)                        \
    CHECK_MSTATUS ( attr.setKeyable(true) );    \
    CHECK_MSTATUS ( attr.setStorable(true) );   \
    CHECK_MSTATUS ( attr.setReadable(true) );  \
    CHECK_MSTATUS ( attr.setWritable(true) );

#define MAKE_OUTPUT(attr)                           \
    CHECK_MSTATUS ( attr.setKeyable(false) ) ;      \
    CHECK_MSTATUS ( attr.setStorable(false) );      \
    CHECK_MSTATUS ( attr.setReadable(true) ) ;      \
    CHECK_MSTATUS ( attr.setWritable(false) );

//
// DESCRIPTION:
void PhongNode::postConstructor( )
{
    setMPSafe(true);
}

//
// DESCRIPTION:
PhongNode::PhongNode()
{
}

//
// DESCRIPTION:
PhongNode::~PhongNode()
{
}

//
// DESCRIPTION:
void * PhongNode::creator()
{
    return new PhongNode();
}

//
// DESCRIPTION:
MStatus PhongNode::initialize()
{
    MFnNumericAttribute nAttr; 
    MFnLightDataAttribute lAttr;

    aTranslucenceCoeff = nAttr.create("translucenceCoeff", "tc", 
                                      MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);

    aDiffuseReflectivity = nAttr.create("diffuseReflectivity", "drfl",
                                        MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setDefault(0.8f) );

    aColor = nAttr.createColor( "color", "c" );
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setDefault(0.0f, 0.58824f, 0.644f) );

    aIncandescence = nAttr.createColor( "incandescence", "ic" );
    MAKE_INPUT(nAttr);

    aOutColor = nAttr.createColor( "outColor", "oc" );
    MAKE_OUTPUT(nAttr);

    aPointCamera = nAttr.createPoint( "pointCamera", "pc" );
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );

    aPower = nAttr.create( "power", "pow", MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setMin(0.0f) );
    CHECK_MSTATUS ( nAttr.setMax(200.0f) );
    CHECK_MSTATUS ( nAttr.setDefault(10.0f) );

    aSpecularity = nAttr.create( "specularity", "spc", MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setMin(0.0f) );
    CHECK_MSTATUS ( nAttr.setMax(1.0f) ) ;
    CHECK_MSTATUS ( nAttr.setDefault(0.5f) );

    aReflectGain = nAttr.create( "reflectionGain", "rg", MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setMin(0.0f) );
    CHECK_MSTATUS ( nAttr.setMax(1.0f) );
    CHECK_MSTATUS ( nAttr.setDefault(0.5f) );

    aNormalCamera = nAttr.createPoint( "normalCamera", "n" );
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );

    aTriangleNormalCamera = nAttr.createPoint( "triangleNormalCamera", "tn" );
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f));
    CHECK_MSTATUS ( nAttr.setHidden(true));

    aLightDirection = nAttr.createPoint( "lightDirection", "ld" );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f) );

    aLightIntensity = nAttr.createColor( "lightIntensity", "li" );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f) );

    aLightAmbient = nAttr.create( "lightAmbient", "la",
                                  MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );

    aLightDiffuse = nAttr.create( "lightDiffuse", "ldf", 
                                  MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );

    aLightSpecular = nAttr.create( "lightSpecular", "ls", 
                                   MFnNumericData::kBoolean);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );

    aLightShadowFraction = nAttr.create("lightShadowFraction", "lsf",
                                        MFnNumericData::kFloat);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );

    aPreShadowIntensity = nAttr.create("preShadowIntensity", "psi",
                                       MFnNumericData::kFloat);
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );

    aLightBlindData = nAttr.createAddr("lightBlindData", "lbld");
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(true) );
    CHECK_MSTATUS ( nAttr.setWritable(false) );

    aLightData = lAttr.create( "lightDataArray", "ltd", 
                               aLightDirection, aLightIntensity, aLightAmbient,
                               aLightDiffuse, aLightSpecular, 
                               aLightShadowFraction,
                               aPreShadowIntensity,
                               aLightBlindData);
    CHECK_MSTATUS ( lAttr.setArray(true) );
    CHECK_MSTATUS ( lAttr.setStorable(false) );
    CHECK_MSTATUS ( lAttr.setHidden(true) );
    CHECK_MSTATUS ( lAttr.setDefault(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, true, true,
                     false, 0.0f, 1.0f, NULL) );

    // rayOrigin
    MObject RayX = nAttr.create( "rayOx", "rxo", MFnNumericData::kFloat, 0.0 );
    MObject RayY = nAttr.create( "rayOy", "ryo", MFnNumericData::kFloat, 0.0 );
    MObject RayZ = nAttr.create( "rayOz", "rzo", MFnNumericData::kFloat, 0.0 );
    aRayOrigin = nAttr.create( "rayOrigin", "rog", RayX, RayY, RayZ );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(false) );

    // rayDirection 
    RayX = nAttr.create( "rayDirectionX", "rdx", MFnNumericData::kFloat, 1.0 );
    RayY = nAttr.create( "rayDirectionY", "rdy", MFnNumericData::kFloat, 0.0 );
    RayZ = nAttr.create( "rayDirectionZ", "rdz", MFnNumericData::kFloat, 0.0 );
    aRayDirection = nAttr.create( "rayDirection", "rad", RayX, RayY, RayZ );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(false) );

    // objectId
    aObjectId = nAttr.createAddr( "objectId", "oi" );
    CHECK_MSTATUS ( nAttr.setStorable(false) ); 
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(false) );

    // raySampler
    aRaySampler = nAttr.createAddr("raySampler", "rtr");
    CHECK_MSTATUS ( nAttr.setStorable(false));
    CHECK_MSTATUS ( nAttr.setHidden(true) );
    CHECK_MSTATUS ( nAttr.setReadable(false) );

    // rayDepth
    aRayDepth = nAttr.create( "rayDepth", "rd", MFnNumericData::kShort, 0.0 );
    CHECK_MSTATUS ( nAttr.setStorable(false) );
    CHECK_MSTATUS  (nAttr.setHidden(true) ) ;
    CHECK_MSTATUS ( nAttr.setReadable(false) );

    CHECK_MSTATUS ( addAttribute(aTranslucenceCoeff) );
    CHECK_MSTATUS ( addAttribute(aDiffuseReflectivity) );
    CHECK_MSTATUS ( addAttribute(aColor) );
    CHECK_MSTATUS ( addAttribute(aIncandescence) );
    CHECK_MSTATUS ( addAttribute(aPointCamera) );
    CHECK_MSTATUS ( addAttribute(aNormalCamera) );
    CHECK_MSTATUS ( addAttribute(aTriangleNormalCamera) );

    CHECK_MSTATUS ( addAttribute(aLightData) );

    CHECK_MSTATUS ( addAttribute(aPower) );
    CHECK_MSTATUS ( addAttribute(aSpecularity) );
    CHECK_MSTATUS ( addAttribute(aOutColor) );

    CHECK_MSTATUS ( addAttribute(aRayOrigin) );
    CHECK_MSTATUS ( addAttribute(aRayDirection) );
    CHECK_MSTATUS ( addAttribute(aObjectId) );
    CHECK_MSTATUS ( addAttribute(aRaySampler) );
    CHECK_MSTATUS ( addAttribute(aRayDepth) );
    CHECK_MSTATUS ( addAttribute(aReflectGain) );

    CHECK_MSTATUS ( attributeAffects (aTranslucenceCoeff, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aDiffuseReflectivity, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightIntensity, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aIncandescence, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aPointCamera, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aNormalCamera, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aTriangleNormalCamera, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightData, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightAmbient, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightSpecular, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightDiffuse, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightDirection, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightShadowFraction, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aPreShadowIntensity, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aLightBlindData, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aPower, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aSpecularity, aOutColor));
    CHECK_MSTATUS ( attributeAffects (aColor, aOutColor));

    CHECK_MSTATUS ( attributeAffects (aRayOrigin,aOutColor));
    CHECK_MSTATUS ( attributeAffects (aRayDirection,aOutColor));
    CHECK_MSTATUS ( attributeAffects (aObjectId,aOutColor));
    CHECK_MSTATUS ( attributeAffects (aRaySampler,aOutColor));
    CHECK_MSTATUS ( attributeAffects (aRayDepth,aOutColor));
    CHECK_MSTATUS ( attributeAffects (aReflectGain,aOutColor) );

    return MS::kSuccess;
}


//
// DESCRIPTION:
MStatus PhongNode::compute(
const MPlug&      plug,
      MDataBlock& block ) 
{ 
    if ((plug != aOutColor) && (plug.parent() != aOutColor))
        return MS::kUnknownParameter;

    MFloatVector resultColor(0.0,0.0,0.0);

    // get sample surface shading parameters
    MFloatVector& surfaceNormal = block.inputValue( aNormalCamera ).asFloatVector();
    MFloatVector& cameraPosition = block.inputValue( aPointCamera ).asFloatVector();

    // use for raytracing api enhancement below
    MFloatVector point = cameraPosition;
    MFloatVector normal = surfaceNormal;

    MFloatVector& surfaceColor  = block.inputValue( aColor ).asFloatVector();
    MFloatVector& incandescence = block.inputValue( aIncandescence ).asFloatVector();
    float diffuseReflectivity = block.inputValue( aDiffuseReflectivity ).asFloat();
    // float translucenceCoeff   = block.inputValue( aTranslucenceCoeff ).asFloat();
    // User-defined Reflection Color Gain
    float reflectGain = block.inputValue( aReflectGain ).asFloat();
  
    // Phong shading attributes
    float power = block.inputValue( aPower ).asFloat();
    float spec = block.inputValue( aSpecularity ).asFloat();

    float specularR, specularG, specularB;
    float diffuseR, diffuseG, diffuseB;
    diffuseR = diffuseG = diffuseB = specularR = specularG = specularB = 0.0;

    // get light list
    MArrayDataHandle lightData = block.inputArrayValue( aLightData );
    int numLights = lightData.elementCount();
    
    // iterate through light list and get ambient/diffuse values
    for( int count=1; count <= numLights; count++ )
    {
        MDataHandle currentLight = lightData.inputValue();
        MFloatVector& lightIntensity = currentLight.child(aLightIntensity).asFloatVector();
        
        // Find the blind data
        void*& blindData = currentLight.child( aLightBlindData ).asAddr();
     
        // find ambient component
        if( currentLight.child(aLightAmbient).asBool() ) {
            diffuseR += lightIntensity[0];
            diffuseG += lightIntensity[1];
            diffuseB += lightIntensity[2];
        }

        MFloatVector& lightDirection = currentLight.child(aLightDirection).asFloatVector();
        
        if ( blindData == NULL )
        {
            // find diffuse and specular component
            if( currentLight.child(aLightDiffuse).asBool() )
            {           
                float cosln = lightDirection * surfaceNormal;;              
                if( cosln > 0.0f )  // calculate only if facing light
                {
                     diffuseR += lightIntensity[0] * ( cosln * diffuseReflectivity );
                     diffuseG += lightIntensity[1] * ( cosln * diffuseReflectivity );
                     diffuseB += lightIntensity[2] * ( cosln * diffuseReflectivity );
                }

                CHECK_MSTATUS( cameraPosition.normalize() );
                            
                if( cosln > 0.0f ) // calculate only if facing light
                {               
                    float RV = ( ( (2*surfaceNormal) * cosln ) - lightDirection ) * cameraPosition;
                    if( RV > 0.0 ) RV = 0.0;
                    if( RV < 0.0 ) RV = -RV;

                    if ( power < 0 ) power = -power;

                    float s = spec * powf( RV, power );

                    specularR += lightIntensity[0] * s; 
                    specularG += lightIntensity[1] * s; 
                    specularB += lightIntensity[2] * s; 
                }
            }    
        }
        else
        {
            float cosln = MRenderUtil::diffuseReflectance( blindData, lightDirection, point, surfaceNormal, true );
            if( cosln > 0.0f )  // calculate only if facing light
            {
                 diffuseR += lightIntensity[0] * ( cosln * diffuseReflectivity );
                 diffuseG += lightIntensity[1] * ( cosln * diffuseReflectivity );
                 diffuseB += lightIntensity[2] * ( cosln * diffuseReflectivity );
            }

            CHECK_MSTATUS ( cameraPosition.normalize() );
            
            if ( currentLight.child(aLightSpecular).asBool() )
            {
                MFloatVector specLightDirection = lightDirection;
                MDataHandle directionH = block.inputValue( aRayDirection );
                MFloatVector direction = directionH.asFloatVector();
                float lightAttenuation = 1.0;
                        
                specLightDirection = MRenderUtil::maximumSpecularReflection( blindData,
                                        lightDirection, point, surfaceNormal, direction );
                lightAttenuation = MRenderUtil::lightAttenuation( blindData, point, surfaceNormal, false );     

                // Are we facing the light
                if ( specLightDirection * surfaceNormal > 0.0f )
                {           
                    float power2 = block.inputValue( aPower ).asFloat();
                    MFloatVector rv = 2 * surfaceNormal * ( surfaceNormal * direction ) - direction;
                    float s = spec * powf( rv * specLightDirection, power2 );
                        
                    specularR += lightIntensity[0] * s * lightAttenuation; 
                    specularG += lightIntensity[1] * s * lightAttenuation; 
                    specularB += lightIntensity[2] * s * lightAttenuation;
                }
             }
       }
       if( !lightData.next() ) break;
    }

    // factor incident light with surface color and add incandescence
    resultColor[0] = ( diffuseR * surfaceColor[0] ) + specularR + incandescence[0];
    resultColor[1] = ( diffuseG * surfaceColor[1] ) + specularG + incandescence[1];
    resultColor[2] = ( diffuseB * surfaceColor[2] ) + specularB + incandescence[2];

    // add the reflection color
    if (reflectGain > 0.0) {

        MStatus status;

        // required attributes for using raytracer
        // origin, direction, sampler, depth, and object id.
        //
        MDataHandle originH = block.inputValue( aRayOrigin, &status);
        MFloatVector origin = originH.asFloatVector();

        MDataHandle directionH = block.inputValue( aRayDirection, &status);
        MFloatVector direction = directionH.asFloatVector();

        MDataHandle samplerH = block.inputValue( aRaySampler, &status);
        void*& samplerPtr = samplerH.asAddr();

        MDataHandle depthH = block.inputValue( aRayDepth, &status);
        short depth = depthH.asShort();

        MDataHandle objH = block.inputValue( aObjectId, &status);
        void*& objId = objH.asAddr();

        MFloatVector reflectColor;
        MFloatVector reflectTransparency;

        MFloatVector& triangleNormal = block.inputValue( aTriangleNormalCamera ).asFloatVector();

        // compute reflected ray
        MFloatVector l = -direction;
        float dot = l * normal;
        if( dot < 0.0 ) dot = -dot;
        MFloatVector refVector = 2 * normal * dot - l;  // reflection ray
        float dotRef = refVector * triangleNormal;
        if( dotRef < 0.0 ) {
            const float s = 0.01f;
            MFloatVector mVec = refVector - dotRef * triangleNormal;
            mVec.normalize();
            refVector = mVec + s * triangleNormal;
        }
        CHECK_MSTATUS ( refVector.normalize() );

        status = MRenderUtil::raytrace(
                point,      //  origin
                refVector,  //  direction
                objId,      //  object id
                samplerPtr, //  sampler info
                depth,      //  ray depth
                reflectColor,   // output color and transp
                reflectTransparency);

        // add in the reflection color
        resultColor[0] += reflectGain * (reflectColor[0]);
        resultColor[1] += reflectGain * (reflectColor[1]);
        resultColor[2] += reflectGain * (reflectColor[2]);
    
    }

    // set ouput color attribute
    MDataHandle outColorHandle = block.outputValue( aOutColor );
    MFloatVector& outColor = outColorHandle.asFloatVector();
    outColor = resultColor;
    outColorHandle.setClean();

    return MS::kSuccess;
}

//
// DESCRIPTION:
MStatus initializePlugin( MObject obj )
{
   const MString UserClassify( "shader/surface" );

   MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
   CHECK_MSTATUS ( plugin.registerNode( "phongNode", PhongNode::id, 
                         PhongNode::creator, PhongNode::initialize,
                         MPxNode::kDependNode, &UserClassify ) );

   return MS::kSuccess;
}

//
// DESCRIPTION:
MStatus uninitializePlugin( MObject obj )
{
   MFnPlugin plugin( obj );
   CHECK_MSTATUS ( plugin.deregisterNode( PhongNode::id ) );

   return MS::kSuccess;
}