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

# noiseShader.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 <stdlib.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/MFnNumericAttribute.h>
    #include <maya/MFnMatrixAttribute.h>
    #include <maya/MFloatPoint.h>
    #include <maya/MFloatVector.h>
    #include <maya/MFloatMatrix.h>
    #include <maya/MFnPlugin.h>

    class noise3 : public MPxNode
    {
        public:

        noise3();
        virtual ~noise3();

        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 void init();
        static float pnoise3( MFloatPoint& vec );
        static float pnoise3( float vx, float vy, float vz );

        // Input attributes
        static MObject aColor1;
        static MObject aColor2;
        static MObject aScale;
        static MObject aBias;
        static MObject aPlaceMat;
        static MObject aPointWorld;

        // Output attributes
        static MObject          aOutColor;
        static MObject          aOutAlpha;
    };

    // Static data
    MTypeId noise3::id( 0x8100a );

    // Attributes
    MObject noise3::aColor1;
    MObject noise3::aColor2;
    MObject noise3::aPlaceMat;
    MObject noise3::aPointWorld;
    MObject noise3::aScale;
    MObject noise3::aBias;

    MObject noise3::aOutColor;
    MObject noise3::aOutAlpha;

    #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 noise3::postConstructor( )
    {
        setMPSafe(true);
    }

    noise3::noise3()
    {
    }

    noise3::~noise3()
    {
    }

    // creates an instance of the node
    void * noise3::creator()
    {
        return new noise3();
    }

    // initializes attribute information
    MStatus noise3::initialize()
    {
        MFnMatrixAttribute mAttr;
        MFnNumericAttribute nAttr;

        // Create input attributes

        aColor1 = nAttr.createColor("color1", "c1");
        MAKE_INPUT(nAttr);
        CHECK_MSTATUS ( nAttr.setDefault(0., .58824, .644) );       // Light blue

        aColor2 = nAttr.createColor("color2", "c2");
        MAKE_INPUT(nAttr);
        CHECK_MSTATUS ( nAttr.setDefault(1., 1., 1.) );         // White

        aScale = nAttr.create( "scale", "s", MFnNumericData::kFloat);
        MAKE_INPUT(nAttr);
        CHECK_MSTATUS ( nAttr.setDefault( 1. ) );

        aBias = nAttr.create( "bias", "b", MFnNumericData::kFloat);
        MAKE_INPUT(nAttr);

        aPlaceMat = mAttr.create("placementMatrix", "pm",
                                 MFnMatrixAttribute::kFloat);
        MAKE_INPUT(mAttr);

        // Implicit shading network attributes

        aPointWorld = nAttr.createPoint("pointWorld", "pw");
        MAKE_INPUT(nAttr);
        CHECK_MSTATUS ( nAttr.setHidden(true) );

        // Create output attributes

        aOutColor = nAttr.createColor("outColor", "oc");
        MAKE_OUTPUT(nAttr);

        aOutAlpha = nAttr.create( "outAlpha", "oa", MFnNumericData::kFloat);
        MAKE_OUTPUT(nAttr);

        // Add the attributes here
        CHECK_MSTATUS ( addAttribute(aColor1) );
        CHECK_MSTATUS ( addAttribute(aColor2) );
        CHECK_MSTATUS ( addAttribute(aScale) );
        CHECK_MSTATUS ( addAttribute(aBias) );
        CHECK_MSTATUS ( addAttribute(aPointWorld) );
        CHECK_MSTATUS ( addAttribute(aPlaceMat) );

        CHECK_MSTATUS ( addAttribute(aOutColor) );
        CHECK_MSTATUS ( addAttribute(aOutAlpha) );

        // All input affect the output color and alpha
        CHECK_MSTATUS ( attributeAffects (aColor1, aOutColor) );
        CHECK_MSTATUS ( attributeAffects (aColor1, aOutAlpha) );

        CHECK_MSTATUS ( attributeAffects (aColor2, aOutColor) ) ;
        CHECK_MSTATUS ( attributeAffects (aColor2, aOutAlpha) );

        CHECK_MSTATUS ( attributeAffects (aScale, aOutAlpha) );
        CHECK_MSTATUS ( attributeAffects (aScale, aOutColor) );

        CHECK_MSTATUS ( attributeAffects (aBias, aOutAlpha) );
        CHECK_MSTATUS ( attributeAffects (aBias, aOutColor) );

        CHECK_MSTATUS ( attributeAffects (aPointWorld, aOutColor) );
        CHECK_MSTATUS ( attributeAffects (aPointWorld, aOutAlpha) );

        CHECK_MSTATUS ( attributeAffects (aPlaceMat, aOutColor) );
        CHECK_MSTATUS ( attributeAffects (aPlaceMat, aOutAlpha) );

        return MS::kSuccess;
    }

    /* Ken Perlin */

    #define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
    #define B 256
    static int p[B +B +2];
    static float g[B + B + 2][3];
    static int start = 1;

    #define setup(i,b0,b1,r0,r1) t = i + 10000.0f; b0 = ((int)t) & (B-1);  b1 = (b0+1) & (B-1);  r0 = t - (int)t;  r1 = r0 - 1.0f;

    inline float noise3::pnoise3( MFloatPoint& vec )
    {
        return pnoise3( vec.x, vec.y, vec.z );
    }

    float noise3::pnoise3(float vx, float vy, float vz)
    {
        int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
        float rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v;
        register int i, j;

        if (start)
        {
            start = 0;
            init();
        }
        setup(vx, bx0,bx1, rx0,rx1);
        setup(vy, by0,by1, ry0,ry1);
        setup(vz, bz0,bz1, rz0,rz1);
        i = p[ bx0 ];
        j = p[ bx1 ];
        b00 = p[ i + by0 ];
        b10 = p[ j + by0 ];
        b01 = p[ i + by1 ];
        b11 = p[ j + by1 ];

        #define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
        #define s_curve(t) ( t * t * (3.0f - 2.0f * t) )
        #define lerp(t, a, b) ( a + t * (b - a) )

        sx = s_curve(rx0);
        sy = s_curve(ry0);
        sz = s_curve(rz0);
        q = g[ b00 + bz0 ] ;
        u = at(rx0,ry0,rz0);
        q = g[ b10 + bz0 ] ;
        v = at(rx1,ry0,rz0);
        a = lerp(sx, u, v);
        q = g[ b01 + bz0 ] ;
        u = at(rx0,ry1,rz0);
        q = g[ b11 + bz0 ] ;
        v = at(rx1,ry1,rz0);
        b = lerp(sx, u, v);
        c = lerp(sy, a, b);                     // interpolate in y at lo x
        q = g[ b00 + bz1 ] ;
        u = at(rx0,ry0,rz1);
        q = g[ b10 + bz1 ] ;
        v = at(rx1,ry0,rz1);
        a = lerp(sx, u, v);
        q = g[ b01 + bz1 ] ;
        u = at(rx0,ry1,rz1);
        q = g[ b11 + bz1 ] ;
        v = at(rx1,ry1,rz1);
        b = lerp(sx, u, v);
        d = lerp(sy, a, b);                     // interpolate in y at hi x
        return 1.5f * lerp(sz, c, d);           // interpolate in z
    }

    void noise3::init()
    {
        int i, j, k;
        float v[3], s;

        // Create an array of random gradient vectors uniformly on the
        // unit sphere
        srandom(1);
        for (i = 0 ; i < B ; i++)
        {
            do
            {
                // Choose uniformly in a cube
                for (j=0 ; j<3 ; j++)
                    v[j] = (float)((random() % (B + B)) - B) / B;
                s = DOT(v,v);
            } while (s > 1.0);                  // If not in sphere try again
            s = sqrtf(s);
            for (j = 0 ; j < 3 ; j++)           // Else normalize
                g[i][j] = v[j] / s;
        }

        // Create a pseudorandom permutation of [1..B]
        for (i = 0 ; i < B ; i++)
            p[i] = i;
        for(i=B ;i >0 ;i -=2)
        {
            k = p[i];
            p[i] = p[j = random() % B];
            p[j] = k;
        }
        // Extend g and p arrays to allow for faster indexing
        for(i=0 ;i <B +2 ;i++)
        {
            p[B + i] = p[i];
            for (j = 0 ; j < 3 ; j++)
                g[B + i][j] = g[i][j];
        }
    }

    //
    // This function gets called by Maya to evaluate the texture.
    //
    MStatus noise3::compute(const MPlug& plug, MDataBlock& block)
    {
        // outColor or individial R, G, B channel, or alpha
        if((plug != aOutColor) && (plug.parent() != aOutColor) &&
           (plug != aOutAlpha))
            return MS::kUnknownParameter;

        MFloatVector resultColor;
        MFloatVector & col1 = block.inputValue(aColor1).asFloatVector();
        MFloatVector & col2 = block.inputValue(aColor2).asFloatVector();

        float3 & worldPos = block.inputValue( aPointWorld ).asFloat3();
        MFloatMatrix& mat = block.inputValue( aPlaceMat ).asFloatMatrix();
        float& sc = block.inputValue( aScale ).asFloat();
        float& bi = block.inputValue( aBias ).asFloat();

        MFloatPoint solidPos(worldPos[0], worldPos[1], worldPos[2]);
        solidPos *= mat;                        // Convert into solid space

        float val = fabsf( pnoise3( solidPos ) * sc + bi );
        if (val < 0.) val = 0.;
        if (val > 1.) val = 1.;
        resultColor = col1 * val + col2*(1-val);

        // Set output color attribute
        MDataHandle outColorHandle = block.outputValue( aOutColor );
        MFloatVector& outColor = outColorHandle.asFloatVector();
        outColor = resultColor;
        outColorHandle.setClean();

        MDataHandle outAlphaHandle = block.outputValue( aOutAlpha );
        float& outAlpha = outAlphaHandle.asFloat();
        outAlpha = val;
        outAlphaHandle.setClean();

        return MS::kSuccess;
    }

    MStatus initializePlugin( MObject obj )
    {
        const MString UserClassify( "texture/3d" );

        MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
        CHECK_MSTATUS ( plugin.registerNode( "solidNoise", noise3::id,
                             &noise3::creator, &noise3::initialize,
                             MPxNode::kDependNode, &UserClassify ) );

        return MS::kSuccess;
    }

    MStatus uninitializePlugin( MObject obj )
    {
        MFnPlugin plugin( obj );
        CHECK_MSTATUS ( plugin.deregisterNode( noise3::id ) );

        return MS::kSuccess;
    }