//- // ========================================================================== // 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. // // ========================================================================== //+ // // This plug-in is based, in part, upon the folloing literature: // // Digital Seashells, M.B. Cortie, // Computer and Graphics, Vol. 17, No. 1, pp. 79-84, 1993 // // _Shells_, S. Peter Dance, // Harper Collins Publishers 1992, ISBN 0 7322 0067 9 // // Modeling Seashels, Deborah R. Fowler, Hans Meinhardt et al. // Siggraph Proceedings 92, pp. 379-387 // // _The Algorithmic Beauty of Sea Shells_, Hans Meinhardt, // Springer-Verlag Berlin Heidelberg 1995, ISBN 3 540 57842 0 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define Rad(x) ((x)*FPI/180.0F) #define Deg(x) ((x)*180.0F/FPI) #define FPI 3.14159265358979323846264338327950288419716939937510582F #define McheckErr(stat,msg) \ if ( MS::kSuccess != stat ) { \ cerr << msg; \ return MS::kFailure; \ } class shellNode : public MPxNode { public: shellNode(); virtual ~shellNode(); virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static void * creator(); static MStatus initialize(); public: static MTypeId id; // Node attributes // --------------- // Main shape parameters // static MObject alpha; // Profile (Helico-spiral) param #1 static MObject beta; // Profile (Helico-spiral) param #2 static MObject phi; // Section Starting point static MObject my; // Section Slant static MObject omega; // Section angle around Oz static MObject omin; // Spiral start angle static MObject omax; // Spiral end angle static MObject od; // Spiral angle step static MObject smin; // Section start angle static MObject smax; // Section end angle static MObject sd; // Section angle step static MObject A; // Distance of section from Z-axis static MObject a; // Section diameter #1 static MObject b; // Section diameter #2 static MObject scale; // Overall scale // Nodule 1 // static MObject P; // Position on section static MObject L; // Amplitude (extrusion) of nodule static MObject N; // Nodules frequency on profile static MObject W1; // Fatness of nodule static MObject W2; // Fatness of nodule static MObject nstart; // Starting point on spiral // Nodule 2 // static MObject P2; static MObject L2; static MObject N2; static MObject W12; static MObject W22; static MObject off2; static MObject nstart2; // Nodule 3 // static MObject P3; static MObject L3; static MObject N3; static MObject W13; static MObject W23; static MObject off3; static MObject nstart3; // Ribs // static MObject uamp; // Section rib amplitude static MObject ufreq; // Section rib frequency static MObject urib; // Section rib/wave percent static MObject vamp; // Profile rib amplitude static MObject vfreq; // Profile rib frequency static MObject vrib; // Profile rib/wave percent // Output mesh // static MObject outMesh; private: struct ShellParams { float alpha; // Profile (Helico-spiral) param #1 float beta; // Profile (Helico-spiral) param #2 float phi; // Section Starting point float my; // Section Slant float omega; // Section angle around Oz float omin; // Spiral start angle float omax; // Spiral end angle float od; // Spiral angle step float smin; // Section start angle float smax; // Section end angle float sd; // Section angle step float A; // Distance of section from Z-axis float a; // Section diameter #1 float b; // Section diameter #2 float scale; // Overall scale // Nodule 1 // -------- float P; // Position on section float L; // Amplitude (extrusion) of nodule float N; // Nodules frequency on profile float W1; // Fatness of nodule float W2; // Fatness of nodule float nstart; // Starting point on spiral // Nodule 2 // -------- float P2; float L2; float N2; float W12; float W22; float off2; float nstart2; // Nodule 3 // -------- float P3; float L3; float N3; float W13; float W23; float off3; float nstart3; // Ribs // ---- float uamp; // Section rib amplitude float ufreq; // Section rib frequency float urib; // Section rib/wave percent float vamp; // Profile rib amplitude float vfreq; // Profile rib frequency float vrib; // Profile rib/wave percent }; ShellParams shellParams; bool redoTopology; bool rebuild; // Precomputed shell points // int ni; int nj; float **pnts; private: float GetFloatParameter( MObject node, MObject attr ); float GetAngleParameter( MObject node, MObject attr ); static void addFloatParameter( MObject & attr, MString longName, MString briefName, float attrDefault ); static void addAngleParameter( MObject & attr, MString longName, MString briefName, float attrDefault ); void UpdateParameters(); void RedoTopology(); void Rebuild(); float Nodules( float s, float o ); float Ribs( float u, float v ); void Eval( float *p, float o, float s ); }; MTypeId shellNode::id( 0x8000b ); shellNode::shellNode() : rebuild( true ), redoTopology( true ), pnts( NULL ), ni( 0 ), nj( 0 ) {} shellNode::~shellNode() {} MStatus shellNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; int i, j; // Read updated input parameters // UpdateParameters(); bool createNewMesh = redoTopology; RedoTopology(); Rebuild(); if( !pnts || ni<2 || nj<2 ) return MS::kSuccess; if (plug == outMesh) { if( !pnts || ni<2 || nj<2 ) return MS::kSuccess; MDataHandle outputHandle = data.outputValue(outMesh, &returnStatus); McheckErr(returnStatus, "ERROR getting polygon data handle\n"); MObject mesh = outputHandle.asMesh(); if ( createNewMesh || mesh.isNull() ) { MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(&returnStatus); McheckErr(returnStatus, "ERROR creating outputData"); MFloatPointArray vertices; // Build vertices array // for( j=0; joldnj ) { memset( pnts+oldnj, 0, (nj-oldnj)*sizeof(float*) ); } for(int j=0;j=sp.nstart ) { g= G(o,sp.N); p1= g/sp.W2; p2= (s-sp.P)/sp.W1; k= sp.L*expf( -4.0F*(p1*p1+p2*p2) ); } if( sp.L2 && sp.N2 && o>=sp.nstart2 ) { g= G(o+sp.off2,sp.N2); p1= g/sp.W22; p2= (s-sp.P2)/sp.W12; k+= sp.L2*expf( -4.0F*(p1*p1+p2*p2) ); } if( sp.L3 && sp.N3 && o>= sp.nstart3 ) { g= G(o+sp.off3, sp.N3); p1= g/sp.W23; p2= (s-sp.P3)/sp.W13; k+= sp.L3*expf( -4.0F*(p1*p1+p2*p2) ); } return k; } void shellNode::Eval( float *p, float o, float s ) { ShellParams & sp = shellParams; float ss = sinf(s); float cs = cosf(s); float re = 1.0F/sqrtf(cs*cs/(sp.a*sp.a) + ss*ss/(sp.b*sp.b)); float sc = sp.scale*expf(o*SafeCot(sp.alpha)); float csphi = cosf(s+sp.phi); float ssphi = sinf(s+sp.phi); float sbeta = sinf(sp.beta); float smy = sinf(sp.my); float r = re+Nodules(s,o)+Ribs(s,o); float x = sp.A*sbeta*cosf(o) + r*csphi*cosf(o+sp.omega) - r*smy*ssphi*sinf(o); float y = - sp.A*sbeta*sinf(o) - r*csphi*sinf(o+sp.omega) - r*smy*ssphi*cosf(o); float z = - sp.A*cosf(sp.beta) + r*ssphi*cosf(sp.my); p[0] = x*sc; p[1] = -z*sc; p[2] = y*sc; } ///////////////////////////////////// // Attribute Setup and Maintenance // ///////////////////////////////////// // Main shape parameters // MObject shellNode::alpha; // Profile (Helico-spiral) param #1 MObject shellNode::beta; // Profile (Helico-spiral) param #2 MObject shellNode::phi; // Section Starting point MObject shellNode::my; // Section Slant MObject shellNode::omega; // Section angle around Z MObject shellNode::omin; // Spiral start angle MObject shellNode::omax; // Spiral end angle MObject shellNode::od; // Spiral angle step MObject shellNode::smin; // Section start angle MObject shellNode::smax; // Section end angle MObject shellNode::sd; // Section angle step MObject shellNode::A; // Distance of section from Z-axis MObject shellNode::a; // Section diameter #1 MObject shellNode::b; // Section diameter #2 MObject shellNode::scale; // Overall scale // Nodule 1 // MObject shellNode::P; // Position on section MObject shellNode::L; // Amplitude (extrusion) of nodule MObject shellNode::N; // Nodules frequency on profile MObject shellNode::W1; // Fatness of nodule MObject shellNode::W2; // Fatness of nodule MObject shellNode::nstart; // Starting point on spiral // Nodule 2 // MObject shellNode::P2; MObject shellNode::L2; MObject shellNode::N2; MObject shellNode::W12; MObject shellNode::W22; MObject shellNode::off2; MObject shellNode::nstart2; // Nodule 3 // MObject shellNode::P3; MObject shellNode::L3; MObject shellNode::N3; MObject shellNode::W13; MObject shellNode::W23; MObject shellNode::off3; MObject shellNode::nstart3; // Ribs // MObject shellNode::uamp; // Section rib amplitude MObject shellNode::ufreq; // Section rib frequency MObject shellNode::urib; // Section rib/wave percent MObject shellNode::vamp; // Profile rib amplitude MObject shellNode::vfreq; // Profile rib frequency MObject shellNode::vrib; // Profile rib/wave percent // Output mesh // MObject shellNode::outMesh; void shellNode::addFloatParameter( MObject & attr, MString longName, MString briefName, float attrDefault ) // // Description: // Add a float input parameter to the node // { MStatus stat; MFnNumericAttribute nAttr; attr = nAttr.create( longName, briefName, MFnNumericData::kFloat, 0.0, &stat ); if ( stat != MS::kSuccess ) throw stat; stat = nAttr.setDefault ( attrDefault ); if ( stat != MS::kSuccess ) throw stat; stat = nAttr.setKeyable ( true ); if ( stat != MS::kSuccess ) throw stat; stat = nAttr.setCached ( true ); if ( stat != MS::kSuccess ) throw stat; stat = nAttr.setStorable ( true ); if ( stat != MS::kSuccess ) throw stat; stat = addAttribute( attr ); if ( stat != MS::kSuccess ) throw stat; stat = attributeAffects( attr, outMesh ); if ( stat != MS::kSuccess ) throw stat; } void shellNode::addAngleParameter( MObject & attr, MString longName, MString briefName, float attrDefault ) // // Description: // Add an angle input parameter to the node // { MStatus stat; MFnUnitAttribute uAttr; MAngle defaultAngle( (double)attrDefault, MAngle::kDegrees ); attr = uAttr.create( longName, briefName, defaultAngle, &stat ); if ( stat != MS::kSuccess ) throw stat; stat = uAttr.setKeyable ( true ); if ( stat != MS::kSuccess ) throw stat; stat = uAttr.setCached ( true ); if ( stat != MS::kSuccess ) throw stat; stat = uAttr.setStorable ( true ); if ( stat != MS::kSuccess ) throw stat; stat = addAttribute( attr ); if ( stat != MS::kSuccess ) throw stat; stat = attributeAffects( attr, outMesh ); if ( stat != MS::kSuccess ) throw stat; } MStatus shellNode::initialize() // // Description // Set up node attributes // { MFnTypedAttribute typedFn; MStatus stat; outMesh = typedFn.create( "outMesh", "o", MFnData::kMesh, &stat ); if ( MS::kSuccess != stat ) { cerr << "ERROR creating animCube output attribute\n"; return stat; } typedFn.setStorable(false); typedFn.setWritable(false); stat = addAttribute( outMesh ); McheckErr(stat, "ERROR adding attribute"); try { addAngleParameter( alpha, "profileParam1", "pp1", 80.0F ); addAngleParameter( beta, "profileParam2", "pp2", 90.0F ); addAngleParameter( phi, "sectionStartingPoint", "ssp", 1.0F ); addAngleParameter( my, "sectionSlant", "ss", 1.0F ); addAngleParameter( omega, "sectionAngleZ", "saz", 1.0F ); addAngleParameter( omin, "spiralStartAngle", "sps", 0.0F ); addAngleParameter( omax, "spiralEndAngle", "spe", 1200.0F ); addAngleParameter( od, "spiralAngleStep", "spa", 4.0F ); addAngleParameter( smin, "sectionStartAngle", "ssa", -190.0F ); addAngleParameter( smax, "sectionEndAngle", "sea", 190.0F ); addAngleParameter( sd, "sectionAngleStep", "sas", 17.0F ); addFloatParameter( A, "distanceFromZ", "dfz", 1.9F ); addFloatParameter( a, "sectionDiameter1", "sd1", 1.0F ); addFloatParameter( b, "sectionDiameter2", "sd2", 0.9F ); addFloatParameter( scale, "scale", "s", 0.03F ); addAngleParameter( P, "positionOnSection1", "ps1", 10.0F ); addFloatParameter( L, "noduleAmplitude1", "na1", 1.0F ); addFloatParameter( N, "noduleProfileFrequency1", "nf1", 15.0F ); addAngleParameter( W1, "noduleFatness11", "f11", 100.0F ); addAngleParameter( W2, "noduleFatness21", "f21", 20.0F ); addAngleParameter( nstart, "spiralStartingPoint1", "sp1", 0.0F ); addAngleParameter( P2, "positionOnSection2", "ps2", 0.0F ); addFloatParameter( L2, "noduleAmplitude2", "na2", 0.0F ); addFloatParameter( N2, "noduleProfileFrequency2", "nf2", 0.0F ); addAngleParameter( W12, "noduleFatness12", "f12", 30.0F ); addAngleParameter( W22, "noduleFatness22", "f22", 30.0F ); addAngleParameter( off2, "noduleOffset2", "no2", 0.0F ); addAngleParameter( nstart2, "spiralStartingPoint2", "sp2", 0.0F ); addAngleParameter( P3, "positionOnSection3", "ps3", 0.0F ); addFloatParameter( L3, "noduleAmplitude3", "na3", 0.0F ); addFloatParameter( N3, "noduleProfileFrequency3", "nf3", 0.0F ); addAngleParameter( W13, "noduleFatness13", "f13", 30.0F ); addAngleParameter( W23, "noduleFatness23", "f23", 30.0F ); addAngleParameter( off3, "noduleOffset3", "no3", 0.0F ); addAngleParameter( nstart3, "spiralStartingPoint3", "sp3", 0.0F ); addFloatParameter( uamp, "sectionRibAmplitude", "sra", 0.0F ); addFloatParameter( ufreq, "sectionRibFrequency", "srf", 0.0F ); addFloatParameter( urib, "sectionRibWavePercent", "srw", 0.0F ); addFloatParameter( vamp, "profileRibAmplitude", "pra", 0.0F ); addFloatParameter( vfreq, "profileRibFrequency", "prf", 0.0F ); addFloatParameter( vrib, "profileRibWavePercent", "prw", 0.0F ); } catch ( MStatus stat ) { fprintf(stderr,"Attribute Initialize Failed\n"); return stat; } return MS::kSuccess; } inline float shellNode::GetFloatParameter( MObject node, MObject attr ) { MPlug plug( node, attr ); float value; plug.getValue( value ); return value; } inline float shellNode::GetAngleParameter( MObject node, MObject attr ) { MPlug plug( node, attr ); MAngle angle; plug.getValue( angle ); return (float)angle.asRadians(); } #define UpdateFloatAttr(ATTR,TOPOLOGY) \ oldValue = shellParams. ATTR; \ shellParams. ATTR = GetFloatParameter( thisObj, ATTR ); \ if ( shellParams. ATTR != oldValue ) { \ rebuild = true; \ redoTopology = TOPOLOGY ? true : redoTopology; \ } #define UpdateAngleAttr(ATTR,TOPOLOGY) \ oldValue = shellParams. ATTR; \ shellParams. ATTR = GetAngleParameter( thisObj, ATTR ); \ if ( shellParams. ATTR != oldValue ) { \ rebuild = true; \ redoTopology = TOPOLOGY ? true : redoTopology; \ } void shellNode::UpdateParameters( ) // // Description // Read all of the shell parameters and determine what has changed // { MObject thisObj = thisMObject(); float oldValue; UpdateAngleAttr(alpha,false); UpdateAngleAttr(beta,false); UpdateAngleAttr(phi,false); UpdateAngleAttr(my,false); UpdateAngleAttr(omega,false); UpdateFloatAttr(A,false); UpdateFloatAttr(a,false); UpdateFloatAttr(b,false); UpdateFloatAttr(scale,false); UpdateAngleAttr(P,false); UpdateFloatAttr(L,false); UpdateFloatAttr(N,false); UpdateAngleAttr(W1,false); UpdateAngleAttr(W2,false); UpdateAngleAttr(nstart,false); UpdateAngleAttr(P2,false); UpdateFloatAttr(L2,false); UpdateFloatAttr(N2,false); UpdateAngleAttr(W12,false); UpdateAngleAttr(W22,false); UpdateAngleAttr(off2,false); UpdateAngleAttr(nstart2,false); UpdateAngleAttr(P3,false); UpdateFloatAttr(L3,false); UpdateFloatAttr(N3,false); UpdateAngleAttr(W13,false); UpdateAngleAttr(W23,false); UpdateAngleAttr(off3,false); UpdateAngleAttr(nstart3,false); UpdateFloatAttr(uamp,false); UpdateFloatAttr(ufreq,false); UpdateFloatAttr(urib,false); UpdateFloatAttr(vamp,false); UpdateFloatAttr(vfreq,false); UpdateFloatAttr(vrib,false); // These settings change the topology of the geometry // UpdateAngleAttr(omin,true); UpdateAngleAttr(omax,true); UpdateAngleAttr(od,true); UpdateAngleAttr(smin,true); UpdateAngleAttr(smax,true); UpdateAngleAttr(sd,true); } //////////////////////////// // Plug-in Initialization // //////////////////////////// MStatus initializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any"); status = plugin.registerNode( "shell", shellNode::id, &shellNode::creator, &shellNode::initialize, MPxNode::kDependNode ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( shellNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; }