backfillShader/backfillShader.cpp
 
 
 
backfillShader/backfillShader.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>

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

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

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

        // Id tag for use with binary file format
    static MTypeId    id;

        private:
    static MObject  aTranslucenceCoeff;
    static MObject  aDiffuseReflectivity;
        static MObject  aColor;
        static MObject  aBackColor;
    static MObject  aBoost;
        static MObject  aIncandescence;

        static MObject  aOutColor;
        static MObject  aPointCamera;
        static MObject  aNormalCamera;
        static MObject  aLightDirection;
        static MObject  aLightIntensity;
    static MObject  aPower;
    static MObject  aSpecularity;
    static MObject  aThreshold;                         // for backfill percentage

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

MTypeId BackNode::id( 0x81003 );

MObject  BackNode::aTranslucenceCoeff;
MObject  BackNode::aBackColor;
MObject  BackNode::aBoost;
MObject  BackNode::aDiffuseReflectivity;
MObject  BackNode::aColor;
MObject  BackNode::aIncandescence;
MObject  BackNode::aOutColor;
MObject  BackNode::aPointCamera;
MObject  BackNode::aNormalCamera;
MObject  BackNode::aLightData;
MObject  BackNode::aLightDirection;
MObject  BackNode::aLightIntensity; 
MObject  BackNode::aLightAmbient;
MObject  BackNode::aLightDiffuse;
MObject  BackNode::aLightSpecular;
MObject  BackNode::aThreshold;
MObject  BackNode::aLightShadowFraction;
MObject  BackNode::aPreShadowIntensity;
MObject  BackNode::aLightBlindData;
MObject  BackNode::aPower;
MObject  BackNode::aSpecularity;

#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) );

void BackNode::postConstructor( )
{
        setMPSafe(true);
}

//
// DESCRIPTION:
BackNode::BackNode()
{
}

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

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

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

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

    aBackColor = nAttr.createColor( "backColor", "bc" );
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS( nAttr.setDefault(1.0f, 1.0f, 1.0f) );

    aThreshold = nAttr.create( "threshold", "thr", MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS( nAttr.setDefault(0.2f) );
    CHECK_MSTATUS( nAttr.setMin(0.0f) );
    CHECK_MSTATUS( nAttr.setMax(1.0f) );

    aBoost = nAttr.create( "boost", "boo", MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS( nAttr.setDefault(2.0f) );
    CHECK_MSTATUS( nAttr.setMin(0.0f) );
    CHECK_MSTATUS( nAttr.setMax(5.0f) );

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

    aTranslucenceCoeff = nAttr.create("translucenceCoeff", "tc", 
                                                                          MFnNumericData::kFloat);
    MAKE_INPUT(nAttr);
    CHECK_MSTATUS( nAttr.setMin(0.0f) );
    CHECK_MSTATUS( nAttr.setMax(1.0f) );

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

    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) );

    aNormalCamera = nAttr.createColor( "normalCamera", "n" );
    MAKE_INPUT(nAttr);
    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) );

    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) );

    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) );

    CHECK_MSTATUS( addAttribute(aTranslucenceCoeff) );
    CHECK_MSTATUS( addAttribute(aDiffuseReflectivity) );
    CHECK_MSTATUS( addAttribute(aColor) );
    CHECK_MSTATUS( addAttribute(aIncandescence) );
    CHECK_MSTATUS( addAttribute(aPointCamera) );
    CHECK_MSTATUS( addAttribute(aNormalCamera) );
        
        // Only add the parent of the compound
    CHECK_MSTATUS( addAttribute(aLightData) );
    
    CHECK_MSTATUS( addAttribute(aPower) );
    CHECK_MSTATUS( addAttribute(aSpecularity) );
    CHECK_MSTATUS( addAttribute(aOutColor) );

    CHECK_MSTATUS( addAttribute(aBackColor) );
    CHECK_MSTATUS( addAttribute(aThreshold) );
    CHECK_MSTATUS( addAttribute(aBoost) );

    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 (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 (aBackColor, aOutColor) );
    CHECK_MSTATUS( attributeAffects (aThreshold, aOutColor) );
    CHECK_MSTATUS( attributeAffects (aBoost, aOutColor) );

    return MS::kSuccess;
}


//
// DESCRIPTION:
MStatus BackNode::compute(const MPlug& plug, MDataBlock& block) 
{
        // outColor or individual R, G, B channel, or alpha
    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();

    MFloatVector& surfaceColor  = block.inputValue( aColor ).asFloatVector();
    MFloatVector& incandescence = block.inputValue( aIncandescence ).asFloatVector();
    float diffuseReflectivity = block.inputValue( aDiffuseReflectivity ).asFloat();
    // float translucenceCoeff   = block.inputValue( aTranslucenceCoeff ).asFloat();
    float threshold   = block.inputValue( aThreshold ).asFloat();
    MFloatVector& BackLightColor  = block.inputValue( aBackColor ).asFloatVector();
    float Boost  = block.inputValue( aBoost ).asFloat();
  

    // Phong shading attributes
    float power = block.inputValue( aPower ).asFloat();
    float spec = block.inputValue( aSpecularity ).asFloat();

    float specularR, specularG, specularB;
    float diffuseR, diffuseG, diffuseB;
    float BackR, BackG, BackB;
    diffuseR = diffuseG = diffuseB = specularR = specularG = specularB = 0.0;
    BackR = BackG = BackB = 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();
        // float lightShadowF = currentLight.child(aLightShadowFraction).asFloat();

        // find ambient component
        if( currentLight.child(aLightAmbient).asBool() ) {
            diffuseR += lightIntensity[0];
            diffuseG += lightIntensity[1];
            diffuseB += lightIntensity[2];
        }

        // find diffuse and specular component
        if( currentLight.child(aLightDiffuse).asBool() )
        {
            MFloatVector& lightDirection = currentLight.child(aLightDirection).asFloatVector();

            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 );
            }
            if (((cosln > 0.0) && (cosln <= threshold)) ||
                 (cosln <= 0.0))
            {
                float interp;
                if (threshold != 0.0) {
                    interp = ((1.0f / (-1 - threshold)) * cosln) +
                                                (threshold / (threshold + 1));
                }
                else
                {
                    interp = fabsf(cosln);
                }

                BackR += (BackLightColor[0] * interp);
                BackG += (BackLightColor[1] * interp);
                BackB += (BackLightColor[2] * interp);
            }

            cameraPosition.normalize();

            if( cosln > 0.0f ) // calculate only if facing light
            {
                float RV = ( ( (2*surfaceNormal) * cosln ) - lightDirection ) * cameraPosition;
                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; 
            }
       }
       if( !lightData.next() ) break;
    }

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

    // 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( "backFillShader", BackNode::id, 
                         BackNode::creator, BackNode::initialize,
                         MPxNode::kDependNode, &UserClassify ) );

   return MS::kSuccess;
}

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

   return MS::kSuccess;
}