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

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

    //
    //      Translate selected objects
    //
    #include <maya/MIOStream.h>
    #include <stdio.h>
    #include <stdlib.h>

    #include <maya/MPxCommand.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MArgList.h>
    #include <maya/MGlobal.h>
    #include <maya/M3dView.h>

    #include <maya/MDagPath.h>
    #include <maya/MMatrix.h>
    #include <maya/MFloatMatrix.h>

    #include <maya/MRenderUtil.h>
    #include <maya/MFloatPoint.h>
    #include <maya/MFloatPointArray.h>
    #include <maya/MFloatArray.h>
    #include <maya/MFloatVectorArray.h>
    #include <math.h>

    #ifndef M_PI
    #define M_PI        3.14159265358979323846  /* pi */
    #endif

    class sampleParticles : public MPxCommand
    {
    public:
                        sampleParticles() {};
        virtual         ~sampleParticles();

        MStatus         doIt( const MArgList& args );
        static void*    creator();
    };

    sampleParticles::~sampleParticles() {}

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

    /*

        emits particles with color sampled from specified
        shading node/shading engine

    */
    MStatus sampleParticles::doIt( const MArgList& args )
    {
        unsigned int i;
        bool shadow = 0;
        bool reuse = 0;

        for ( i = 0; i < args.length(); i++ )
            if ( args.asString(i) == MString("-shadow") ||
                args.asString(i) == MString("-s") )
                shadow = 1;
            else if ( args.asString(i) == MString("-reuse") ||
                args.asString(i) == MString("-r") )
                reuse = 1;
            else
                break;
        if ( args.length() - i < 5 )
        {
            displayError( "Usage: sampleParticles [-shadow|-reuse] particleName <shadingEngine|shadingNode.plug> resX resY scale\n"
                "  Example: sampleParticles -shadow particle1 phong1SG 64 64 10;\n"
                "  Example: sampleParticles particle1 file1.outColor 128 128 5;\n" );
            return MS::kFailure;
        }
        if ( reuse && !shadow ) // can only reuse if shadow is turned on
            reuse = 0;

        MString particleName = args.asString( i );
        MString node = args.asString( i+1 );
        int resX = args.asInt( i+2 );
        int resY = args.asInt( i+3 );
        double scale = args.asDouble( i+4 );

        if ( scale <= 0.0 )
            scale = 1.0;

        MFloatArray uCoord, vCoord;
        MFloatPointArray points;
        MFloatVectorArray normals, tanUs, tanVs;

        if ( resX <= 0 )
            resX = 1;
        if ( resY <= 0 )
            resY = 1;

        MString command( "emit -o " );
        command += particleName;
        char tmp[2048];

        float stepU = (float) (1.0 / resX);
        float stepV = (float) (1.0 / resY);

        // stuff sample data by iterating over grid
        // Y is set to arch along the X axis

        int x, y;
        for ( y = 0; y < resY; y++ )
            for ( x = 0; x < resX; x++ )
            {
                uCoord.append( stepU * x );
                vCoord.append( stepV * y );

                float curY = (float) (sin( stepU * (x) * M_PI )*2.0);

                MFloatPoint curPt(
                    (float) (stepU * x * scale),
                    curY,
                    (float) (stepV * y * scale ));

                MFloatPoint uPt(
                    (float) (stepU * (x+1) * scale),
                    (float) (sin( stepU * (x+1) * M_PI )*2.0),
                    (float) (stepV * y * scale ));

                MFloatPoint vPt(
                    (float) (stepU * (x) * scale),
                    curY,
                    (float) (stepV * (y+1) * scale ));

                MFloatVector du, dv, n;
                du = uPt-curPt;
                dv = vPt-curPt;

                n = dv^du;  // normal is based on dU x dV
                n = n.normal();
                normals.append( n );

                du.normal();
                dv.normal();
                tanUs.append( du );
                tanVs.append( dv );

                points.append( curPt );
            }

        // get current camera's world matrix

        MDagPath cameraPath;
        M3dView::active3dView().getCamera( cameraPath );
        MMatrix mat = cameraPath.inclusiveMatrix();
        MFloatMatrix cameraMat( mat.matrix );

        MFloatVectorArray colors, transps;
        if ( MS::kSuccess == MRenderUtil::sampleShadingNetwork(
                node,
                points.length(),
                shadow,
                reuse,

                cameraMat,

                &points,
                &uCoord,
                &vCoord,
                &normals,
                &points,
                &tanUs,
                &tanVs,
                NULL,   // don't need filterSize

                colors,
                transps ) )
        {
            fprintf( stderr, "%u points sampled...\n", points.length() );
            for ( i = 0; i < uCoord.length(); i++ )
            {
                sprintf( tmp, " -pos %g %g %g -at velocity -vv %g %g %g -at rgbPP -vv %g %g %g",
                    points[i].x,
                    points[i].y,
                    points[i].z,

                    normals[i].x,
                    normals[i].y,
                    normals[i].z,

                    colors[i].x,
                    colors[i].y,
                    colors[i].z );

                command += MString( tmp );

                // execute emit command once every 512 samples
                if ( i % 512 == 0 )
                {
                    fprintf( stderr, "%u...\n", i );
                    MGlobal::executeCommand( command, false, false );
                    command = MString( "emit -o " );
                    command += particleName;
                }
            }

            if ( i % 512 )
                MGlobal::executeCommand( command, true, true );
        }
        else
        {
            displayError( node + MString(" is not a shading engine!  Specify node.attr or shading group node." ) );
        }

        return MS::kSuccess;
    }

    //
    // The following routines are used to register/unregister
    // the command we are creating within Maya
    //
    MStatus initializePlugin( MObject obj )
    {
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

        status = plugin.registerCommand( "sampleParticles", sampleParticles::creator );
        if (!status) {
            status.perror("registerCommand");
            return status;
        }

        return status;
    }

    MStatus uninitializePlugin( MObject obj)
    {
        MStatus   status;
        MFnPlugin plugin( obj );

        status = plugin.deregisterCommand( "sampleParticles" );
        if (!status) {
            status.perror("deregisterCommand");
            return status;
        }

        return status;
    }