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

# clearcoat.cpp

    //-
    // ==========================================================================
    // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All
    // rights reserved.
    //
    // The coded instructions, statements, computer programs, and/or related
    // material (collectively the "Data") in these files contain unpublished
    // information proprietary to Autodesk, Inc. ("Autodesk") and/or its
    // licensors, which is protected by U.S. and Canadian federal copyright
    // law and by international treaties.
    //
    // The Data is provided for use exclusively by You. You have the right
    // to use, modify, and incorporate this Data into other products for
    // purposes authorized by the Autodesk software license agreement,
    // without fee.
    //
    // The copyright notices in the Software and this entire statement,
    // including the above license grant, this restriction and the
    // following disclaimer, must be included in all copies of the
    // Software, in whole or in part, and all derivative works of
    // the Software, unless such copies or derivative works are solely
    // in the form of machine-executable object code generated by a
    // source language processor.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
    // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
    // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
    // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
    // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
    // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
    // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
    // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
    // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
    // OR PROBABILITY OF SUCH DAMAGES.
    //
    // ==========================================================================
    //+

    #include <maya/MStatus.h>
    #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/MFnCompoundAttribute.h>
    #include <maya/MFloatVector.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MGlobal.h>

    #include <math.h>

    #define kPi                 3.14159265358979323846264338327950
    #define kFloatEpsilon       1.0e-5F

    // Plugin clearcoat Shader Class //

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

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

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

    protected:

       static MObject aIndex;
       static MObject aScale;
       static MObject aBias;

       static MObject  aNormalCameraX;
       static MObject  aNormalCameraY;
       static MObject  aNormalCameraZ;
       static MObject  aNormalCamera;

       static MObject  aRayDirectionX;
       static MObject  aRayDirectionY;
       static MObject  aRayDirectionZ;
       static MObject  aRayDirection;

       static MObject  aOutValue;
    };

    //
    // DESCRIPTION: node classification

    MTypeId clearcoat::id( 0x58000400 );

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

    //
    // DESCRIPTION: attribute information

    MObject  clearcoat::aIndex;
    MObject  clearcoat::aScale;
    MObject  clearcoat::aBias;

    MObject  clearcoat::aNormalCamera;
    MObject  clearcoat::aNormalCameraX;
    MObject  clearcoat::aNormalCameraY;
    MObject  clearcoat::aNormalCameraZ;

    MObject  clearcoat::aRayDirection;
    MObject  clearcoat::aRayDirectionX;
    MObject  clearcoat::aRayDirectionY;
    MObject  clearcoat::aRayDirectionZ;

    MObject  clearcoat::aOutValue;

    //
    // DESCRIPTION:
    clearcoat::clearcoat()
    {
    }

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

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

    //
    // DESCRIPTION:
    MStatus clearcoat::initialize()
    {
        MFnNumericAttribute nAttr;
        MFnCompoundAttribute   cAttr;

        aIndex = nAttr.create( "index", "ix", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(true) );
        CHECK_MSTATUS ( nAttr.setDefault(1.8f) );
        CHECK_MSTATUS ( nAttr.setSoftMin(1.0f) );
        CHECK_MSTATUS ( nAttr.setSoftMax(5.0f) );

        aScale = nAttr.create( "scale", "s", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(true) );
        CHECK_MSTATUS ( nAttr.setDefault(1.55f) );
        CHECK_MSTATUS ( nAttr.setSoftMin(0.0f) );
        CHECK_MSTATUS ( nAttr.setSoftMax(5.0f) );

        aBias = nAttr.create( "bias", "b", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(true) );
        CHECK_MSTATUS ( nAttr.setDefault(-0.1f) );
        CHECK_MSTATUS ( nAttr.setSoftMin(-1.0f) );
        CHECK_MSTATUS ( nAttr.setSoftMax( 1.0f) );

        aNormalCameraX = nAttr.create( "normalCameraX", "nx", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(false) );
        CHECK_MSTATUS ( nAttr.setDefault(1.0f) );

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

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

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

        aRayDirectionX = nAttr.create( "rayDirectionX", "rx", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(false) );
        CHECK_MSTATUS ( nAttr.setDefault(1.0f) );

        aRayDirectionY = nAttr.create( "rayDirectionY", "ry", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(false));
        CHECK_MSTATUS ( nAttr.setDefault(1.0f));

        aRayDirectionZ = nAttr.create( "rayDirectionZ", "rz", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setStorable(false) );
        CHECK_MSTATUS ( nAttr.setDefault(1.0f) );

        aRayDirection = nAttr.create( "rayDirection","r",
                                      aRayDirectionX, aRayDirectionY, aRayDirectionZ);
        CHECK_MSTATUS ( nAttr.setStorable(false) );
        CHECK_MSTATUS ( nAttr.setDefault(1.0f, 1.0f, 1.0f) );
        CHECK_MSTATUS ( nAttr.setHidden(true) );

    // Outputs

        aOutValue = nAttr.create( "outValue", "ov", MFnNumericData::kFloat);
        CHECK_MSTATUS ( nAttr.setHidden(false) );
        CHECK_MSTATUS ( nAttr.setReadable(true) );
        CHECK_MSTATUS ( nAttr.setWritable(false) );

        CHECK_MSTATUS ( addAttribute(aIndex));
        CHECK_MSTATUS ( addAttribute(aScale) );
        CHECK_MSTATUS ( addAttribute(aBias) );

        // compound attribute - only need to add parent
        CHECK_MSTATUS ( addAttribute(aNormalCamera) );

        // compound attribute - only need to add parent
        CHECK_MSTATUS ( addAttribute(aRayDirection) );

        CHECK_MSTATUS ( addAttribute(aOutValue) );

        CHECK_MSTATUS ( attributeAffects (aIndex, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aScale, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aBias, aOutValue) );

        CHECK_MSTATUS ( attributeAffects (aNormalCameraX, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aNormalCameraY, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aNormalCameraZ, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aNormalCamera, aOutValue) );

        CHECK_MSTATUS ( attributeAffects (aRayDirectionX, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aRayDirectionY, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aRayDirectionZ, aOutValue) );
        CHECK_MSTATUS ( attributeAffects (aRayDirection, aOutValue) );

        return MS::kSuccess;
    }

    //
    // DESCRIPTION:
    MStatus clearcoat::compute(
    const MPlug&      plug,
          MDataBlock& block )
    {
      if( plug == aOutValue )
      {

        MFloatVector& surfaceNormal = block.inputValue( aNormalCamera ).asFloatVector();
        MFloatVector& rayDirection  = block.inputValue( aRayDirection ).asFloatVector();

        float index = block.inputValue(aIndex).asFloat();
        float scale = block.inputValue(aScale).asFloat();
        float bias  = block.inputValue(aBias).asFloat();

        // This is Jim Craighead's code.  Ripped straight from Studio...

        /* This basically computes a fresnel reflection coeficient.  */
        /* It could probably use some optimization, but the trig     */
        /* identities are left as an exercise for the masochistic.   */
        /* Also note that this is reasonably accurate for refractive */
        /* indices greater than 1, but a complete hack for smaller   */
        /* values.  There are still problems with values below 0.6   */
        /* such as Gold and Silver.                                  */

        float origCosne  = - (rayDirection * surfaceNormal);
        float ninety        = (float) kPi * 0.5f;
        float I             = (float) acos( origCosne );
        float transSin      = (float) sin(I) / (float)(index);
        float ccFresnel     = 1.0;
        float ccBlend       = 0.0;
        float sum           = 0.0;
        float difference    = 0.0;
        if( transSin > 1.0 ) {
            float limit   = (float) asin( (float)(index));
            sum           = limit + ninety;
            difference    = limit - ninety;
        } else {
            float T       = (float) asin( transSin );
            sum           = I + T;
            difference    = I - T;
        }

        if( ! (fabs(difference) < kFloatEpsilon ) ) {
            float fudgedScale = (float)(scale) * 2.0f;
            float fudgedBias  = (float)(bias) * 1.0f;
            if( sum < ninety ) {
                float parallel      = (float) (tan(difference) / tan(sum));
                float perpendicular = (float) (sin(difference) / sin(sum));
                ccFresnel = 0.5f * ( perpendicular * perpendicular
                                    + parallel * parallel );
            } else {
                float perpendicular = (float) sin(difference);
                ccFresnel = 0.5f * ( perpendicular * perpendicular );
            }
            ccBlend   = ccFresnel * fudgedScale + fudgedBias;
            if(      ccBlend > 1.0 ) ccBlend = 1.0;
            else if( ccBlend < 0.0 ) ccBlend = 0.0;
        }

        // set ouput color attribute
        MDataHandle outHandle = block.outputValue( aOutValue );
        float& outV = outHandle.asFloat();

        outV = ccBlend;
        outHandle.setClean();

      } else
          return MS::kUnknownParameter;

      return MS::kSuccess;
    }

    //
    // DESCRIPTION:
    MStatus initializePlugin( MObject obj )
    {
       const MString UserClassify( "utility/general:drawdb/shader/operation/clearCoat" );

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

       CHECK_MSTATUS ( plugin.registerUIStrings( NULL, "clearcoatInitStrings") );

       CHECK_MSTATUS ( plugin.registerNode( "clearCoat", clearcoat::id,
                             clearcoat::creator, clearcoat::initialize,
                             MPxNode::kDependNode, &UserClassify ) );

       return MS::kSuccess;
    }

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

       return MS::kSuccess;
    }