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

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

    //
    //  Class: latticeNoiseNode
    //
    //  Description:
    //      A "latticeNoise" node adds random noise to lattice geometry over time.
    //      This makes the geometry being deformed by the lattice look like
    //      wobbly jello.
    //
    //
    //  Node:       latticeNoise
    //
    //  Attributes: input     - input lattice
    //              amplitude - amplitude of the noise
    //              frequency - frequency of the noise
    //              time      - the current time
    //              output    - the modified lattice
    //
    #include "latticeNoise.h"

    #include <string.h>
    #include <maya/MIOStream.h>
    #include <stdio.h>
    #include <math.h>

    #include <maya/MFnUnitAttribute.h>
    #include <maya/MFnNumericAttribute.h>
    #include <maya/MFnTypedAttribute.h>
    #include <maya/MFnLattice.h>
    #include <maya/MFnLatticeData.h>

    #include <maya/MString.h>
    #include <maya/MTypeId.h>
    #include <maya/MPlug.h>
    #include <maya/MDataBlock.h>
    #include <maya/MDataHandle.h>
    #include <maya/MTime.h>

    // CONSTANTS
    //
    #define DEF_AMPLITUDE 0.2
    #define DEF_FREQ      4.0

    #define McheckErr(stat,msg)          \
        if ( MS::kSuccess != stat ) {   \
            cerr << msg;                \
            return MS::kFailure;        \
        }

    //             latticeNoiseNode Methods                 //

    MTypeId     latticeNoiseNode::id( 0x80010 );
    MObject     latticeNoiseNode::input;
    MObject     latticeNoiseNode::amplitude;
    MObject     latticeNoiseNode::frequency;
    MObject     latticeNoiseNode::time;
    MObject     latticeNoiseNode::output;

    MStatus latticeNoiseNode::compute( const MPlug& plug, MDataBlock& data )
    {
        MStatus returnStatus;

        float noiseAmplitude;
        float noiseFreq;

        if( plug == output )
        {
            // Get the lattice data from the input attribute.  First get the
            // data object, and then use the lattice data function set to extract
            // the actual lattice.
            //

            // Get the data handle
            //
            MDataHandle inputData = data.inputValue( input, &returnStatus );
            McheckErr( returnStatus, "ERROR getting lattice data handle\n" );
            // Get the data object
            //
            MObject latticeData = inputData.data();
            MFnLatticeData dataFn( latticeData );
            // Get the actual geometry
            //
            MObject lattice = dataFn.lattice();
            MFnLattice lattFn( lattice, &returnStatus );
            McheckErr( returnStatus, "ERROR getting lattice geometry\n" );

            // Do the same for the output lattice
            //
            MDataHandle outputData = data.outputValue( output, &returnStatus );
            McheckErr( returnStatus, "ERROR getting lattice data handle\n" );
            // Get the data object
            //
            latticeData = outputData.data();
            if ( latticeData.isNull() ) {
                // The data object for this attribute has not been created yet, so
                // we'll create it
                //
                latticeData = dataFn.create();
            } else {
                // Use the data object that is already there
                //
                dataFn.setObject( latticeData );
            }
            // Get the actual geometry
            //
            MObject outLattice = dataFn.lattice();
            MFnLattice outLattFn( outLattice, &returnStatus );
            McheckErr( returnStatus, "ERROR getting lattice geometry\n" );

            // Get the amplitude and frequency
            //
            MDataHandle ampData = data.inputValue( amplitude, &returnStatus );
            McheckErr( returnStatus, "ERROR getting amplitude\n" );
            noiseAmplitude = ampData.asFloat();

            MDataHandle freqData = data.inputValue( frequency, &returnStatus );
            McheckErr( returnStatus, "ERROR getting frequency\n" );
            noiseFreq = freqData.asFloat();

            // Get the time.
            //
            MDataHandle timeData = data.inputValue( time, &returnStatus );
            McheckErr( returnStatus, "ERROR getting time data handle\n" );
            MTime time = timeData.asTime();
            float seconds = (float)time.as( MTime::kSeconds );

            // Easiest way to modify frequency is by modifying the time
            //
            seconds = seconds * noiseFreq;

            // We have the information we need now.  We'll apply noise to the
            // points upon the lattice
            //
            unsigned s, t, u;
            lattFn.getDivisions( s, t, u );
            // match up the divisions in the lattices
            //
            outLattFn.setDivisions( s, t, u );

            for ( unsigned i = 0; i < s; i++ ) {
                for ( unsigned j = 0; j < t; j++ ) {
                    for ( unsigned k = 0; k < u; k++ ) {
                        MPoint & point = lattFn.point( i, j, k );
                        MPoint & outPoint = outLattFn.point( i, j, k );
                        pnt noisePnt = noise::atPointAndTime( (float)point.x, (float)point.y,
                                                              (float)point.z, seconds );
                        // Make noise between -1 and 1 instead of 0 and 1
                        //
                        noisePnt.x =  ( noisePnt.x * 2.0F ) - 1.0F;
                        noisePnt.y =  ( noisePnt.y * 2.0F ) - 1.0F;
                        noisePnt.z =  ( noisePnt.z * 2.0F ) - 1.0F;

                        outPoint.x = point.x + ( noisePnt.x * noiseAmplitude );
                        outPoint.y = point.y + ( noisePnt.y * noiseAmplitude );
                        outPoint.z = point.z + ( noisePnt.z * noiseAmplitude );
                    }
                }
            }
            outputData.set( latticeData );
            data.setClean(plug);
        } else {
            return MS::kUnknownParameter;
        }

        return MS::kSuccess;
    }

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

    MStatus latticeNoiseNode::initialize()
    {
        MFnUnitAttribute    unitAttr;
        MFnTypedAttribute   typedAttr;
        MFnNumericAttribute numAttr;

        MStatus stat;

        input = typedAttr.create( "input", "in", MFnData::kLattice, &stat );
        if ( !stat ) {
            stat.perror("ERROR creating latticeNoiseNode input lattice attribute");
            return stat;
        }

        amplitude = numAttr.create( "amplitude", "amp",
                                                   MFnNumericData::kFloat,
                                                   DEF_AMPLITUDE,
                                                   &stat );
        if ( !stat ) {
            stat.perror("ERROR creating latticeNoiseNode amplitude attribute");
            return stat;
        }

        frequency = numAttr.create( "frequency", "fq",
                                                   MFnNumericData::kFloat,
                                                   DEF_FREQ,
                                                   &stat );
        if ( !stat ) {
            stat.perror("ERROR creating latticeNoiseNode frequency attribute");
            return stat;
        }

        time = unitAttr.create( "time", "tm", MFnUnitAttribute::kTime,
                                                0.0, &stat );
        if ( !stat ) {
            stat.perror("ERROR creating latticeNoiseNode time attribute");
            return stat;
        }

        output = typedAttr.create( "output", "out", MFnData::kLattice, &stat );
        if ( !stat ) {
            stat.perror("ERROR creating latticeNoiseNode output attribute");
            return stat;
        }
        typedAttr.setWritable(false);

        stat = addAttribute( input );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( amplitude );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( frequency );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( time );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( output );
            if (!stat) { stat.perror("addAttribute"); return stat;}

        stat = attributeAffects( input, output );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( amplitude, output );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( frequency, output );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( time, output );
            if (!stat) { stat.perror("attributeAffects"); return stat;}

        return MS::kSuccess;
    }