- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Examples

# lambertShader.cpp

    //-
    // ===========================================================================
    // Copyright 2012 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.
    // ===========================================================================
    //+

    // Example Plugin: lambertShader.cpp
    //
    // Produces dependency graph node LambertShader
    // This node is an example of a Lambert shader and how to build a
    // dependency node as a surface shader in Maya. The inputs for this node
    // are many, and can be found in the Maya UI on the Attribute Editor for
    // the node. The output attributes for the node are "outColor" and
    // "outTransparency". To use this shader, create a lambertShader with
    // Shading Group or connect the outputs to a Shading Group's
    // "SurfaceShader" attribute.
    //

    #include <maya/MIOStream.h>
    #include <maya/MPxNode.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>
    #include <maya/MGlobal.h>
    #include <maya/MDrawRegistry.h>

    #include <lambertShaderOverride.h>

    // Plugin Lambert Shader Class //

    // This class will create a new shader. Shaders are custom dependency
    // graph objects so we will derive this class from the basic DG node
    // type MPxNode
    //

    class lambert : public MPxNode
    {
    public:
                        lambert();
        virtual         ~lambert();

        static  void *  creator();
        virtual MStatus compute( const MPlug&, MDataBlock& );
        static  MStatus initialize();

        // postConstructor:
        // The postConstructor method allows us to call MPxNode member
        // functions during initialization. Internally maya creates two
        // objects when a user defined node is created, the internal MObject
        // and the user derived object. The association between the these
        // two objects is not made until after the MPxNode constructor is
        // called. This implies that no MPxNode member function can be called
        // from the MPxNode constructor. The postConstructor will get called
        // immediately after the constructor when it is safe to call any
        // MPxNode member function.
        //

        virtual void    postConstructor();

        static  MTypeId   id;  // The IFF type id

    protected:

       // Translucence coefficient
       static MObject  aTranslucenceCoeff;

       // Diffuse Reflectivity
       static MObject  aDiffuseReflectivity;

       // Red component of surface color
       static MObject  aColorR;

       // Green component of surface color
       static MObject  aColorG;

       // Blue component of surface color
       static MObject  aColorB;

       // Surface color
       static MObject  aColor;

       // Red component of incandescence
       static MObject  aIncandescenceR;

       // Green component of incandescence
       static MObject  aIncandescenceG;

       // Blue component of incandescence
       static MObject  aIncandescenceB;

       // Incandescence
       static MObject  aIncandescence;

       // Red component of surface transparency
       static MObject  aInTransR;

       // Green component of surface transparency
       static MObject  aInTransG;

       // Blue component of surface transparency
       static MObject  aInTransB;

       // Surface transparency
       static MObject  aInTransparency;

       // Red component of output color
       static MObject  aOutColorR;

       // Green component of output color
       static MObject  aOutColorG;

       // Blue component of output color
       static MObject  aOutColorB;

       // Output color
       static MObject  aOutColor;

       // Red component of output transparency
       static MObject  aOutTransR;

       // Green component of output transparency
       static MObject  aOutTransG;

       // Blue component of output transparency
       static MObject  aOutTransB;

       // Output transparency
       static MObject  aOutTransparency;

       // X component of surface normal
       static MObject  aNormalCameraX;

       // Y component of surface normal
       static MObject  aNormalCameraY;

       // Z component of surface normal
       static MObject  aNormalCameraZ;

       // Surface normal
       static MObject  aNormalCamera;

       // X component of light direction vector
       static MObject  aLightDirectionX;

       // Y component of light direction vector
       static MObject  aLightDirectionY;

       // Z component of light direction vector
       static MObject  aLightDirectionZ;

       // Light direction vector
       static MObject  aLightDirection;

       // Red component of light intensity
       static MObject  aLightIntensityR;

       // Green component of light intensity
       static MObject  aLightIntensityG;

       // Blue component of light intensity
       static MObject  aLightIntensityB;

       // Light Intensity vector
       static MObject  aLightIntensity;

       // Ambient flag
       static MObject  aLightAmbient;

       // Diffuse flag
       static MObject  aLightDiffuse;

       // Specular flag
       static MObject  aLightSpecular;

       // Shadow Fraction flag
       static MObject   aLightShadowFraction;

       // Pre Shadow Intensity
       static MObject   aPreShadowIntensity;

       // Light blind data
       static MObject   aLightBlindData;

       // Light data array
       static MObject   aLightData;

    };

    // IFF type ID
    // Each node requires a unique identifier which is used by
    // MFnDependencyNode::create() to identify which node to create, and by
    // the Maya file format.
    //
    // For local testing of nodes you can use any identifier between
    // 0x00000000 and 0x0007ffff, but for any node that you plan to use for
    // more permanent purposes, you should get a universally unique id from
    // Autodesk Support. You will be assigned a unique range that you
    // can manage on your own.
    //
    MTypeId lambert::id( 0x81000 );

    // the postConstructor() function is called immediately after the objects
    // constructor. It is not safe to call MPxNode member functions from the
    // constructor, instead they should be called here.
    //
    void lambert::postConstructor( )
    {
        // setMPSafe indicates that this shader can be used for multiprocessor
        // rendering. For a shading node to be MP safe, it cannot access any
        // shared global data and should only use attributes in the datablock
        // to get input data and store output data.
        //
        setMPSafe( true );
    }

    // DESCRIPTION: attribute information
    //
    MObject  lambert::aTranslucenceCoeff;
    MObject  lambert::aDiffuseReflectivity;
    MObject  lambert::aInTransparency;
    MObject  lambert::aInTransR;
    MObject  lambert::aInTransG;
    MObject  lambert::aInTransB;
    MObject  lambert::aColor;
    MObject  lambert::aColorR;
    MObject  lambert::aColorG;
    MObject  lambert::aColorB;
    MObject  lambert::aIncandescence;
    MObject  lambert::aIncandescenceR;
    MObject  lambert::aIncandescenceG;
    MObject  lambert::aIncandescenceB;
    MObject  lambert::aOutColor;
    MObject  lambert::aOutColorR;
    MObject  lambert::aOutColorG;
    MObject  lambert::aOutColorB;
    MObject  lambert::aOutTransparency;
    MObject  lambert::aOutTransR;
    MObject  lambert::aOutTransG;
    MObject  lambert::aOutTransB;
    MObject  lambert::aNormalCamera;
    MObject  lambert::aNormalCameraX;
    MObject  lambert::aNormalCameraY;
    MObject  lambert::aNormalCameraZ;
    MObject  lambert::aLightData;
    MObject  lambert::aLightDirection;
    MObject  lambert::aLightDirectionX;
    MObject  lambert::aLightDirectionY;
    MObject  lambert::aLightDirectionZ;
    MObject  lambert::aLightIntensity;
    MObject  lambert::aLightIntensityR;
    MObject  lambert::aLightIntensityG;
    MObject  lambert::aLightIntensityB;
    MObject  lambert::aLightAmbient;
    MObject  lambert::aLightDiffuse;
    MObject  lambert::aLightSpecular;
    MObject  lambert::aLightShadowFraction;
    MObject  lambert::aPreShadowIntensity;
    MObject  lambert::aLightBlindData;

    // This node does not need to perform any special actions on creation or
    // destruction
    //

    lambert::lambert() { }
    lambert::~lambert() { }

    // The creator() method allows Maya to instantiate instances of this node.
    // It is called every time a new instance of the node is requested by
    // either the createNode command or the MFnDependencyNode::create()
    // method.
    //
    // In this case creator simply returns a new lambert object.
    //

    void* lambert::creator()
    {
        return new lambert();
    }

    // The initialize method is called only once when the node is first
    // registered with Maya. In this method you define the attributes of the
    // node, what data comes in and goes out of the node that other nodes may
    // want to connect to.
    //

    MStatus lambert::initialize()
    {
        MFnNumericAttribute nAttr;
        MFnLightDataAttribute lAttr;

        MStatus status; // Status will be used to hold the MStatus value
                        // returned by each api function call. It is important
                        // to check the status returned by a call to aid in
                        // debugging. Failed API calls can result in subtle
                        // errors that can be difficult to track down, you may
                        // wish to use the CHECK_MSTATUS macro for any API
                        // call where you do not need to provide your own
                        // error handling.
                        //

        // Attribute Initialization:
        //
        // create      - The create function creates a new attribute for the
        //               node, it takes a long name for the attribute, a short
        //               name for the attribute, the type of the attribute,
        //               and a status object to determine if the api call was
        //               successful.
        //
        // setKeyable  - Sets whether this attribute should accept keyframe
        //               data, Attributes are not keyable by default.
        //
        // setStorable - Sets whether this attribute should be storable. If an
        //               attribute is storable, then it will be writen out
        //               when the node is stored to a file. Attributes are
        //               storable by default.
        //
        // setDefault  - Sets the default value for this attribute.
        //
        // setUsedAsColor - Sets whether this attribute should be presented as
        //               a color in the UI.
        //
        // setHidden   - Sets whether this attribute should be hidden from the
        //               UI. This is useful if the attribute is being used for
        //               blind data, or if it is being used as scratch space
        //               for a geometry calculation (should also be marked
        //               non-connectable in that case). Attributes are not
        //               hidden by default.
        //
        // setReadable - Sets whether this attribute should be readable. If an
        //               attribute is readable, then it can be used as the
        //               source in a dependency graph connection. Attributes
        //               are readable by default.
        //
        // setWritable - Sets whether this attribute should be readable. If an
        //               attribute is writable, then it can be used as the
        //               destination in a dependency graph connection. If an
        //               attribute is not writable then setAttr commands will
        //               fail to change the attribute. If both keyable and
        //               writable for an attribute are set to true it will be
        //               displayed in the channel box when the node is
        //               selected. Attributes are writable by default.
        //
        // setArray    - Sets whether this attribute should have an array of
        //               data. This should be set to true if the attribute
        //               needs to accept multiple incoming connections.
        //               Attributes are single elements by default.
        //

        // Input Attributes
        //
        aTranslucenceCoeff = nAttr.create( "translucenceCoeff", "tc",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f ) );

        aDiffuseReflectivity = nAttr.create( "diffuseReflectivity", "drfl",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.8f ) );

        aColorR = nAttr.create( "colorR", "cr",MFnNumericData::kFloat, 0,
                &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f ) );

        aColorG = nAttr.create( "colorG", "cg", MFnNumericData::kFloat, 0,
                &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.58824f ) );

        aColorB = nAttr.create( "colorB", "cb",MFnNumericData::kFloat, 0,
                &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.644f ) );

        aColor = nAttr.create( "color", "c", aColorR, aColorG, aColorB,
                &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f, 0.58824f, 0.644f ) );
        CHECK_MSTATUS( nAttr.setUsedAsColor( true ) );

        aIncandescenceR = nAttr.create( "incandescenceR", "ir",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f ) );

        aIncandescenceG = nAttr.create( "incandescenceG", "ig",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f ) );

        aIncandescenceB = nAttr.create( "incandescenceB", "ib",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status);
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f ) );

        aIncandescence = nAttr.create( "incandescence", "ic", aIncandescenceR,
                aIncandescenceG, aIncandescenceB, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f, 0.0f, 0.0f ) );
        CHECK_MSTATUS( nAttr.setUsedAsColor( true ) );

        aInTransR = nAttr.create( "transparencyR", "itr",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );

        aInTransG = nAttr.create( "transparencyG", "itg",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );

        aInTransB = nAttr.create( "transparencyB", "itb",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status);
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );

        aInTransparency = nAttr.create( "transparency", "it", aInTransR,
                aInTransG, aInTransB, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setKeyable( true ) );
        CHECK_MSTATUS( nAttr.setStorable( true ) );
        CHECK_MSTATUS( nAttr.setDefault( 0.0f, 0.0f, 0.0f ) );
        CHECK_MSTATUS( nAttr.setUsedAsColor( true ) );

        // Output Attributes
        //

        // Color Output
        //
        aOutColorR = nAttr.create( "outColorR", "ocr", MFnNumericData::kFloat,
                0, &status );
        CHECK_MSTATUS( status );

        aOutColorG = nAttr.create( "outColorG", "ocg", MFnNumericData::kFloat,
                0, &status );
        CHECK_MSTATUS( status );

        aOutColorB = nAttr.create( "outColorB", "ocb", MFnNumericData::kFloat,
                0, &status );
        CHECK_MSTATUS( status );

        aOutColor = nAttr.create( "outColor", "oc", aOutColorR, aOutColorG,
                aOutColorB, &status );
        CHECK_MSTATUS( status );

        CHECK_MSTATUS( nAttr.setHidden( false ) );
        CHECK_MSTATUS( nAttr.setReadable( true ) );
        CHECK_MSTATUS( nAttr.setWritable( false ) );

        // Transparency Output
        //
        aOutTransR = nAttr.create( "outTransparencyR", "otr",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );

        aOutTransG = nAttr.create( "outTransparencyG", "otg",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );

        aOutTransB = nAttr.create( "outTransparencyB", "otb",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );

        aOutTransparency = nAttr.create( "outTransparency", "ot",
                aOutTransR,aOutTransG,aOutTransB, &status );
        CHECK_MSTATUS( status );

        CHECK_MSTATUS( nAttr.setHidden( false ) );
        CHECK_MSTATUS( nAttr.setReadable( true ) );
        CHECK_MSTATUS( nAttr.setWritable( false ) );

        // Camera Normals
        //
        aNormalCameraX = nAttr.create( "normalCameraX", "nx",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setStorable( false ) );
        CHECK_MSTATUS( nAttr.setDefault( 1.0f ) );

        aNormalCameraY = nAttr.create( "normalCameraY", "ny",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setStorable( false ) );
        CHECK_MSTATUS( nAttr.setDefault( 1.0f ) );

        aNormalCameraZ = nAttr.create( "normalCameraZ", "nz",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setStorable( false ) );
        CHECK_MSTATUS( nAttr.setDefault( 1.0f ) );

        aNormalCamera = nAttr.create( "normalCamera","n", aNormalCameraX,
                aNormalCameraY, aNormalCameraZ, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS( nAttr.setStorable( false ) );
        CHECK_MSTATUS( nAttr.setDefault( 1.0f, 1.0f, 1.0f ) );
        CHECK_MSTATUS( nAttr.setHidden( true ) );

        // Light Direction
        //
        aLightDirectionX = nAttr.create( "lightDirectionX", "ldx",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightDirectionY = nAttr.create( "lightDirectionY", "ldy",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightDirectionZ = nAttr.create( "lightDirectionZ", "ldz",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightDirection = nAttr.create( "lightDirection", "ld",
                aLightDirectionX, aLightDirectionY, aLightDirectionZ,
                &status );
        CHECK_MSTATUS( status );
        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 ) );

        // Light Intensity
        //
        aLightIntensityR = nAttr.create( "lightIntensityR", "lir",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightIntensityG = nAttr.create( "lightIntensityG", "lig",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightIntensityB = nAttr.create( "lightIntensityB", "lib",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightIntensity = nAttr.create( "lightIntensity", "li",
                aLightIntensityR, aLightIntensityG, aLightIntensityB,
                &status );
        CHECK_MSTATUS( status );
        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 ) );

        // Light
        //
        aLightAmbient = nAttr.create( "lightAmbient", "la",
                MFnNumericData::kBoolean, 0, &status );
        CHECK_MSTATUS( status );
        CHECK_MSTATUS ( nAttr.setStorable(false) );
        CHECK_MSTATUS ( nAttr.setHidden(true) );
        CHECK_MSTATUS ( nAttr.setReadable(true) );
        CHECK_MSTATUS ( nAttr.setWritable(false) );
        CHECK_MSTATUS( nAttr.setDefault( true ) );

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

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

        aLightShadowFraction = nAttr.create( "lightShadowFraction", "lsf",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aPreShadowIntensity = nAttr.create( "preShadowIntensity", "psi",
                MFnNumericData::kFloat, 0, &status );
        CHECK_MSTATUS( status );
        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 ) );

        aLightBlindData = nAttr.createAddr( "lightBlindData", "lbld",
                &status );
        CHECK_MSTATUS( status );
        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,
                &status );
        CHECK_MSTATUS( status );
        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, 1.0f, 1.0f, NULL ) );

        // Next we will add the attributes we have defined to the node
        //
        CHECK_MSTATUS( addAttribute( aTranslucenceCoeff ) );
        CHECK_MSTATUS( addAttribute( aDiffuseReflectivity ) );
        CHECK_MSTATUS( addAttribute( aColor ) );
        CHECK_MSTATUS( addAttribute( aIncandescence ) );
        CHECK_MSTATUS( addAttribute( aInTransparency ) );
        CHECK_MSTATUS( addAttribute( aOutColor ) );
        CHECK_MSTATUS( addAttribute( aOutTransparency ) );
        CHECK_MSTATUS( addAttribute( aNormalCamera ) );

        // Only add the parent of the compound
        CHECK_MSTATUS( addAttribute( aLightData ) );

        // The attributeAffects() method is used to indicate when the input
        // attribute affects the output attribute. This knowledge allows Maya
        // to optimize dependencies in the graph in more complex nodes where
        // there may be several inputs and outputs, but not all the inputs
        // affect all the outputs.
        //
        CHECK_MSTATUS( attributeAffects( aTranslucenceCoeff, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aDiffuseReflectivity, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aColorR, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aColorG, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aColorB, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aColor, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aInTransR, aOutTransparency ) );
        CHECK_MSTATUS( attributeAffects( aInTransG, aOutTransparency ) );
        CHECK_MSTATUS( attributeAffects( aInTransB, aOutTransparency ) );
        CHECK_MSTATUS( attributeAffects( aInTransparency, aOutTransparency ) );
        CHECK_MSTATUS( attributeAffects( aInTransparency, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aIncandescenceR, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aIncandescenceG, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aIncandescenceB, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aIncandescence, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightIntensityR, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightIntensityB, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightIntensityG, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightIntensity, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aNormalCameraX, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aNormalCameraY, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aNormalCameraZ, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aNormalCamera, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightDirectionX, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightDirectionY, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightDirectionZ, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightDirection, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightAmbient, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightSpecular, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightDiffuse, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightShadowFraction, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aPreShadowIntensity, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightBlindData, aOutColor ) );
        CHECK_MSTATUS( attributeAffects( aLightData, aOutColor ) );

        return( MS::kSuccess );
    }

    // The compute() method does the actual work of the node using the inputs
    // of the node to generate its output.
    //
    // Compute takes two parameters: plug and data.
    // - Plug is the the data value that needs to be recomputed
    // - Data provides handles to all of the nodes attributes, only these
    //   handles should be used when performing computations.
    //
    MStatus lambert::compute( const MPlug& plug, MDataBlock& block )
    {
        // The plug parameter will allow us to determine which output attribute
        // needs to be calculated.
        //
        if( plug == aOutColor
                || plug == aOutColorR
                || plug == aOutColorG
                || plug == aOutColorB
                || plug == aOutTransparency
                || plug == aOutTransR
                || plug == aOutTransG
                || plug == aOutTransB )
        {
            MStatus status;
            MFloatVector resultColor( 0.0, 0.0, 0.0 );

            // Get surface shading parameters from input block
            //
            MFloatVector& surfaceNormal = block.inputValue( aNormalCamera,
                    &status ).asFloatVector();
            CHECK_MSTATUS( status );

            MFloatVector& surfaceColor = block.inputValue( aColor,
                    &status ).asFloatVector();
            CHECK_MSTATUS( status );

            MFloatVector& incandescence = block.inputValue( aIncandescence,
                    &status ).asFloatVector();
            CHECK_MSTATUS( status );

            float diffuseReflectivity = block.inputValue(
                    aDiffuseReflectivity, &status ).asFloat();
            CHECK_MSTATUS( status );

    //      float translucenceCoeff = block.inputValue( aTranslucenceCoeff,
    //              &status ).asFloat();
    //      CHECK_MSTATUS( status );

            // Get light list
            //
            MArrayDataHandle lightData = block.inputArrayValue( aLightData,
                    &status );
            CHECK_MSTATUS( status );

            int numLights = lightData.elementCount( &status );
            CHECK_MSTATUS( status );

            // Calculate the effect of the lights in the scene on the color
            //

            // Iterate through light list and get ambient/diffuse values
            //
            for( int count=1; count <= numLights; count++ )
            {
                // Get the current light out of the array
                //
                MDataHandle currentLight = lightData.inputValue( &status );
                CHECK_MSTATUS( status );

                // Get the intensity of that light
                //
                MFloatVector& lightIntensity = currentLight.child(
                        aLightIntensity ).asFloatVector();

                // Find ambient component
                //
                if ( currentLight.child( aLightAmbient ).asBool() )
                {
                    resultColor += lightIntensity;
                }

                // Find diffuse component
                //
                if ( currentLight.child( aLightDiffuse ).asBool() )
                {
                    MFloatVector& lightDirection = currentLight.child(
                            aLightDirection ).asFloatVector();
                    float cosln = lightDirection * surfaceNormal;

                   if ( cosln > 0.0f ) {
                        resultColor += lightIntensity
                                * ( cosln * diffuseReflectivity );
                   }
                }

                // Advance to the next light.
                //
                if ( count < numLights ) {
                    status = lightData.next();
                    CHECK_MSTATUS( status );
                }
            }

            // Factor incident light with surface color and add incandescence
            //
            resultColor[0] = resultColor[0] * surfaceColor[0] + incandescence[0];
            resultColor[1] = resultColor[1] * surfaceColor[1] + incandescence[1];
            resultColor[2] = resultColor[2] * surfaceColor[2] + incandescence[2];

            // Set ouput color attribute
            //
            if ( plug == aOutColor || plug == aOutColorR || plug == aOutColorG
                    || plug == aOutColorB)
            {
                // Get the handle to the attribute
                //
                MDataHandle outColorHandle = block.outputValue( aOutColor,
                        &status );
                CHECK_MSTATUS( status );
                MFloatVector& outColor = outColorHandle.asFloatVector();

                outColor = resultColor;     // Set the output value
                outColorHandle.setClean(); // Mark the output value as clean
            }

            // Set ouput transparency
            //
            if ( plug == aOutTransparency || plug == aOutTransR
                    || plug == aOutTransG || plug == aOutTransB )
            {
                MFloatVector& transparency = block.inputValue(
                        aInTransparency, &status ).asFloatVector();
                CHECK_MSTATUS( status );

                // Get the handle to the attribute
                //
                MDataHandle outTransHandle = block.outputValue(
                        aOutTransparency, &status );
                CHECK_MSTATUS( status );
                MFloatVector& outTrans = outTransHandle.asFloatVector();

                outTrans = transparency;   // Set the output value
                outTransHandle.setClean(); // Mark the output value as clean
            }
        }
        else
        {
            return( MS::kUnknownParameter ); // We got an unexpected plug
        }

        return( MS::kSuccess );
    }

    // These methods load and unload the plugin, registerNode registers the
    // new node type with maya
    //

    static const MString sRegistrantId("lambertShaderPlugin");
    static const MString sDrawDBClassification("drawdb/shader/surface/lambertShader");
    static const MString sFullClassification("shader/surface:" + sDrawDBClassification);

    MStatus initializePlugin( MObject obj )
    {
        MString command( "if( `window -exists createRenderNodeWindow` ) {refreshCreateRenderNodeWindow(\"" );

        MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any" );

        CHECK_MSTATUS( plugin.registerNode( "lambertShader", lambert::id,
                lambert::creator, lambert::initialize, MPxNode::kDependNode,
                &sFullClassification ) );

        CHECK_MSTATUS(
            MHWRender::MDrawRegistry::registerSurfaceShadingNodeOverrideCreator(
                sDrawDBClassification,
                sRegistrantId,
                lambertShaderOverride::creator));

       command += sFullClassification;

       command += "\");}\n";

       CHECK_MSTATUS( MGlobal::executeCommand( command ) );

       return( MS::kSuccess );
    }

    MStatus uninitializePlugin( MObject obj )
    {
        const MString sFullClassification( "shader/surface:drawdb/shader/surface/lambertShader" );

        MString command( "if( `window -exists createRenderNodeWindow` ) {refreshCreateRenderNodeWindow(\"" );

        MFnPlugin plugin( obj );

        CHECK_MSTATUS( plugin.deregisterNode( lambert::id ) );

        CHECK_MSTATUS(MHWRender::MDrawRegistry::deregisterSurfaceShadingNodeOverrideCreator(
            sDrawDBClassification, sRegistrantId));

        command += sFullClassification;
        command += "\");}\n";

        CHECK_MSTATUS( MGlobal::executeCommand( command ) );

        return MS::kSuccess;
    }