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


// MAYA HEADERS

#include <maya/MFnPlugin.h>

#include <maya/MDagPath.h>

#include <maya/MFnMesh.h>

#include <maya/MItSelectionList.h>

#include <maya/MItMeshPolygon.h>

#include <maya/MObject.h>

#include <maya/MSelectionList.h>

#include <maya/MArgList.h>

#include <maya/MFloatPoint.h>

#include <maya/MFnDependencyNode.h>

#include <maya/MFnSpotLight.h>

#include <maya/MFloatPointArray.h>

#include <maya/MPxCommand.h>

#include <maya/MDGModifier.h>

#include <maya/MFnDagNode.h>

#include <maya/MDagPath.h>

#include <maya/MGlobal.h>



#ifndef INTERSECTCMD

#define INTERSECTCMD



#define MERR_CHK(stat,msg) if ( !stat ) { MGlobal::displayError(msg); } // cerr << msg << endl; }




//

//  PLUGIN DESCRIPTION

//  

//  This is an example of finding the intersection points on a mesh from a spotlight using the          //  intersection acceleration methods in MFnMesh.

//  

//

//  PLUGIN INSTRUCTIONS

//

//  - create a spotlight and a poly plane (mesh)

//  - orient the light to shine onto the plane

//  - run the command as such: intersectCmd <spotLightName> <planeName>

//  - if there is an intersection, a small sphere will be created at the intersection point.

//  

//  Use the following script to automatically display intersections on the mesh (assuming 

//  a spotlight and a mesh with the names used here exist):

//

//  global proc intersectExample()

//  {

//      intersectCmd spotLight1 pPlane1;

//      select -r spotLight1;

//  }

//

//  scriptJob -ac "spotLight1.tx" intersectExample;

//  scriptJob -ac "spotLight1.ty" intersectExample;

//  scriptJob -ac "spotLight1.tz" intersectExample;

//

//  scriptJob -ac "spotLight1.rx" intersectExample;

//  scriptJob -ac "spotLight1.ry" intersectExample;

//  scriptJob -ac "spotLight1.rz" intersectExample;

//




// MAIN CLASS FOR THE INTERSECTCMD COMMAND:

class intersectCmd : public MPxCommand

{

    public:

        intersectCmd();

        virtual ~intersectCmd();

        static void* creator();

        bool isUndoable() const;

        

        MStatus doIt(const MArgList&);

        MStatus undoIt();

};

#endif



// CONSTRUCTOR:

intersectCmd::intersectCmd()

{

}



// DESTRUCTOR:

intersectCmd::~intersectCmd()

{

}



// FOR CREATING AN INSTANCE OF THIS COMMAND:

void* intersectCmd::creator()

{

   return new intersectCmd;

}



// MAKE THIS COMMAND NOT UNDOABLE:

bool intersectCmd::isUndoable() const

{

   return false;

}





MStatus intersectCmd::doIt(const MArgList& args)



// Description:

//      Determine if the ray from the spotlight intersects the mesh.

//      If it does, display the intersection points.



{

    MStatus stat = MStatus::kSuccess;



    if (args.length() != 2) 

    {

        MGlobal::displayError("Need 2 items!");

        return MStatus::kFailure;

    }



    MSelectionList activeList;

    int i;

    

    for ( i = 0; i < 2; i++)

    {

        MString strCurrSelection;

        stat = args.get(i, strCurrSelection);

        if (MStatus::kSuccess == stat) activeList.add(strCurrSelection);

    }



    MItSelectionList iter(activeList);

    MFnSpotLight fnLight;  

    MFnMesh fnMesh;

    MFnDagNode dagNod;

    MFnDependencyNode fnDN;



    float fX = 0;

    float fY = 0;

    float fZ = 0;



    for ( ; !iter.isDone(); iter.next() )

    {

        MObject tempObjectParent, tempObjectChild;

        iter.getDependNode(tempObjectParent);



        if (tempObjectParent.apiType() == MFn::kTransform)

        {

            dagNod.setObject(tempObjectParent);

            tempObjectChild = dagNod.child(0, &stat);

        }



        // check what type of object is selected

        if (tempObjectChild.apiType() == MFn::kSpotLight)

        {

            MDagPath pathToLight;

            MERR_CHK(MDagPath::getAPathTo(tempObjectParent, pathToLight), "Couldn't get a path to the spotlight");

            MERR_CHK(fnLight.setObject(pathToLight), "Failure on assigning light");

            

            stat = fnDN.setObject(tempObjectParent);



            MPlug pTempPlug = fnDN.findPlug("translateX", &stat);

            if (MStatus::kSuccess == stat)

            {

                pTempPlug.getValue(fX);

            }



            pTempPlug = fnDN.findPlug("translateY", &stat);

            if (MStatus::kSuccess == stat)

            {

                pTempPlug.getValue(fY);

            }



            pTempPlug = fnDN.findPlug("translateZ", &stat);

            if (MStatus::kSuccess == stat)

            {

                pTempPlug.getValue(fZ);

            }   

        }

        else if (tempObjectChild.apiType() == MFn::kMesh)

        {

            MDagPath pathToMesh;

            MERR_CHK(MDagPath::getAPathTo(tempObjectChild, pathToMesh), "Couldn't get a path to the spotlight");

            MERR_CHK(fnMesh.setObject(pathToMesh), "Failure on assigning light");   

        }

        else

        {

            MGlobal::displayError("Need a spotlight and a mesh");

            return MStatus::kFailure;

        }

    }



    MFloatPoint fpSource(fX, fY, fZ);

    MFloatVector fvRayDir = fnLight.lightDirection(0, MSpace::kWorld, &stat);

    MFloatPoint hitPoint;

    

    MMeshIsectAccelParams mmAccelParams = fnMesh.autoUniformGridParams();

    

    float fHitRayParam, fHitBary1, fHitBary2;

    int nHitFace, nHitTriangle;



    // a large positive number is used here for the maxParam parameter

    bool bAnyIntersection = fnMesh.anyIntersection(fpSource, fvRayDir, NULL, NULL, false,               MSpace::kWorld, (float)9999, false, &mmAccelParams, hitPoint, &fHitRayParam, &nHitFace, &nHitTriangle,      &fHitBary1, &fHitBary2, (float)1e-6, &stat);

    

    if (! bAnyIntersection) 

    {

        MGlobal::displayInfo("There were no intersection points detected");

        return stat;

    }



    MFloatPointArray hitPoints;

    MFloatArray faHitRayParams;

    MIntArray iaHitFaces;

    MIntArray iaHitTriangles;

    MFloatArray faHitBary1;

    MFloatArray faHitBary2;



    bool bAllIntersections = fnMesh.allIntersections(fpSource, fvRayDir, NULL, NULL, false, MSpace::kWorld, 9999, false, NULL, false, hitPoints, &faHitRayParams, &iaHitFaces, &iaHitTriangles, &faHitBary1, &faHitBary2, 0.000001f, &stat);

    

    if (! bAllIntersections)

    {

        MGlobal::displayInfo("Error getting all intersections");

        return stat;

    }

    

    // check how many intersections are found

    unsigned int nNumberHitPoints = hitPoints.length();



    if (! nNumberHitPoints)

    {

        MGlobal::displayInfo("No hit points detected");

        return MStatus::kSuccess;

    }



    // Intersection exists; display intersections as spheres

    MString strCommandString = "string $strBall[] = `polySphere -r 0.5`;";

    strCommandString += "$strBallName = $strBall[0];";



    float x = 0;

    float y = 0;

    float z = 0;



    for (i = 0; i < (int)nNumberHitPoints; i++)

    {

        // get the points

        x = hitPoints[i][0];

        y = hitPoints[i][1];

        z = hitPoints[i][2];



        // execute some MEL to create a small sphere

        strCommandString += "setAttr ($strBallName + \".tx\") ";

        strCommandString += x;

        strCommandString += ";";



        strCommandString += "setAttr ($strBallName + \".ty\") ";

        strCommandString += y;

        strCommandString += ";";



        strCommandString += "setAttr ($strBallName + \".tz\") ";

        strCommandString += z;

        strCommandString += ";";



        MGlobal::executeCommand(strCommandString);

    }



    return stat;

}



// UNDO THE COMMAND

MStatus intersectCmd::undoIt()

{

    MStatus status;

    // undo not implemented

    return status;

}



// INITIALIZE THE PLUGIN:

MStatus initializePlugin(MObject obj)

{

    MStatus status;

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



    status = plugin.registerCommand("intersectCmd", intersectCmd::creator);



    return status;

}



// UNINITIALIZE THE PLUGIN:

MStatus uninitializePlugin(MObject obj)

{

    MStatus status;

    MFnPlugin plugin(obj);



    plugin.deregisterCommand("intersectCmd");



    return status;

}