shadowMatteShader.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/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>

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

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

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

    private:

    static MObject  aOutColor;
    static MObject  aOutTransparency;
    static MObject  aViewColor;

    static MObject  aLightDirection;
    static MObject  aLightIntensity;
    static MObject  aLightAmbient;
    static MObject  aLightDiffuse;
    static MObject  aLightSpecular;
    static MObject  aLightShadowFraction;
    static MObject  aPreShadowIntensity;
    static MObject  aLightBlindData;
    static MObject  aLightData;
};

MTypeId ShadowMatte::id( 0x81013 );

MObject  ShadowMatte::aViewColor;
MObject  ShadowMatte::aOutColor;
MObject  ShadowMatte::aOutTransparency;
MObject  ShadowMatte::aLightData;
MObject  ShadowMatte::aLightDirection;
MObject  ShadowMatte::aLightIntensity;
MObject  ShadowMatte::aLightAmbient;
MObject  ShadowMatte::aLightDiffuse;
MObject  ShadowMatte::aLightSpecular;
MObject  ShadowMatte::aLightShadowFraction;
MObject  ShadowMatte::aPreShadowIntensity;
MObject  ShadowMatte::aLightBlindData;

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

//
// DESCRIPTION:
ShadowMatte::ShadowMatte()
{
}

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

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

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

// Outputs

    aViewColor = nAttr.create( "viewColor", "vc", MFnNumericData::kBoolean);
    nAttr.setKeyable(true);
    nAttr.setStorable(true);
    nAttr.setHidden(false);
    nAttr.setDefault(true);

    aOutColor = nAttr.createColor( "outColor", "oc");
    nAttr.setStorable(false);
    nAttr.setHidden(false);
    nAttr.setReadable(true);
    nAttr.setWritable(false);

    aOutTransparency  = nAttr.createColor( "outTransparency", "ot" );
    nAttr.setStorable(false);
    nAttr.setHidden(false);
    nAttr.setReadable(true);
    nAttr.setWritable(false);


// Inputs

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

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

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

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

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

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

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

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

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

    addAttribute(aLightData);
    addAttribute(aOutColor);
    addAttribute(aOutTransparency);
    addAttribute(aViewColor);


    attributeAffects (aViewColor, aOutColor);
    attributeAffects (aLightIntensity, aOutColor);
    attributeAffects (aLightData, aOutColor);
    attributeAffects (aLightAmbient, aOutColor);
    attributeAffects (aLightSpecular, aOutColor);
    attributeAffects (aLightDiffuse, aOutColor);
    attributeAffects (aLightDirection, aOutColor);
    attributeAffects (aLightShadowFraction, aOutColor);
    attributeAffects (aPreShadowIntensity, aOutColor);
    attributeAffects (aLightBlindData, aOutColor);

    attributeAffects (aViewColor, aOutTransparency);
    attributeAffects (aLightIntensity, aOutTransparency);
    attributeAffects (aLightData, aOutTransparency);
    attributeAffects (aLightAmbient, aOutTransparency);
    attributeAffects (aLightSpecular, aOutTransparency);
    attributeAffects (aLightDiffuse, aOutTransparency);
    attributeAffects (aLightDirection, aOutTransparency);
    attributeAffects (aLightShadowFraction, aOutTransparency);
    attributeAffects (aPreShadowIntensity, aOutTransparency);
    attributeAffects (aLightBlindData, aOutTransparency);

    return MS::kSuccess;
}

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

    MFloatVector shadowColor(0.0,0.0,0.0);

    bool  ViewFlag  = block.inputValue( aViewColor ).asBool();

    // 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();
        float lightShadow = currentLight.child(aLightShadowFraction).asFloat();

        // shadow fraction tells how much an object is in shadow:
        // (1)   totally in shadow
        // (0-1) partially in shadow
        // (0)   not in shadow

        shadowColor[0] += lightShadow;
        shadowColor[1] += lightShadow;
        shadowColor[2] += lightShadow;
     
        if( !lightData.next() ) break;
    }

    // set ouput color attribute
    MFloatVector ghostColor(0.0,0.0,0.0);
    MDataHandle outColorHandle = block.outputValue( aOutColor );
    MFloatVector& outColor = outColorHandle.asFloatVector();

    if (ViewFlag)
        outColor = shadowColor;
    else
        outColor = ghostColor;

    outColorHandle.setClean();

    // set ouput transparency
    MDataHandle outTransHandle = block.outputValue( aOutTransparency );
    MFloatVector& outTrans = outTransHandle.asFloatVector();
    outTrans = shadowColor;
    outTransHandle.setClean();

    return MS::kSuccess;
}

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

   MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
   plugin.registerNode( "shadowMatte", ShadowMatte::id, 
                         ShadowMatte::creator, ShadowMatte::initialize,
                         MPxNode::kDependNode, &UserClassify );

   return MS::kSuccess;
}

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

   return MS::kSuccess;
}