Beispiel #1
0
void load_from_hds(HDS &hds, MFloatPointArray &points, MIntArray &nFV, MIntArray &F)
{
    size_t nV   = hds.nV();
    size_t nF   = hds.nF();
    size_t nIHE = hds.nIHE();
    
    points.setLength(nV);
    for (size_t k=0; k<nV; k++) 
    {
        points[k](0) = hds.V[3*k+0];
        points[k](1) = hds.V[3*k+1];
        points[k](2) = hds.V[3*k+2];
    }
    
    nFV.setLength(nF);
    for (size_t k=0; k<nF; k++) nFV[k] = hds.nFV[k];
    
    F.setLength(nIHE);
    for (size_t k=0; k<nIHE; k++) F[k] = hds.tip[k];
}
bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const
{
	MStatus s;

	IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from );
	assert( mesh );

	if ( !mesh->arePrimitiveVariablesValid() )
	{
		return false;
	}

	MFloatPointArray vertexArray;
	MIntArray polygonCounts;
	MIntArray polygonConnects;

	MFnMesh fnMesh;

	int numVertices = 0;
	IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P");
	if ( it != mesh->variables.end() )
	{
		/// \todo Employ some M*Array converters to simplify this
		IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
		if (p)
		{
			numVertices = p->readable().size();

			vertexArray.setLength( numVertices );
			for (int i = 0; i < numVertices; i++)
			{
				vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] );
			}
		}
		else
		{
			IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
			if (p)
			{
				numVertices = p->readable().size();

				vertexArray.setLength( numVertices );
				for (int i = 0; i < numVertices; i++)
				{
					vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] );
				}
			}
			else
			{
				// "P" is not convertible to an array of "points"
				return false;
			}
		}
	}


	IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace();
	assert( verticesPerFace );
	int numPolygons = verticesPerFace->readable().size();

	polygonCounts.setLength( numPolygons );
	for (int i = 0; i < numPolygons; i++)
	{
		polygonCounts[i] = verticesPerFace->readable()[i];
	}

	IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds();
	assert( vertexIds );
	int numPolygonConnects = vertexIds->readable().size();
	polygonConnects.setLength( numPolygonConnects );
	for (int i = 0; i < numPolygonConnects; i++)
	{
		polygonConnects[i] = vertexIds->readable()[i];
	}

	MObject mObj = fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s );

	if (!s)
	{
		return false;
	}

	it = mesh->variables.find("N");
	if ( it != mesh->variables.end() )
	{
		if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying )
		{
			/// \todo Employ some M*Array converters to simplify this
			MVectorArray vertexNormalsArray;
			IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
			if (n)
			{
				int numVertexNormals = n->readable().size();

				vertexNormalsArray.setLength( numVertexNormals );
				for (int i = 0; i < numVertexNormals; i++)
				{
					vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3f>( n->readable()[i] );
				}
			}
			else
			{
				IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
				if (n)
				{
					int numVertexNormals = n->readable().size();

					vertexNormalsArray.setLength( numVertexNormals );
					for (int i = 0; i < numVertexNormals; i++)
					{
						vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3d>( n->readable()[i] );
					}
				}
				else
				{
					IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() );
				}
			}
			
			if ( vertexNormalsArray.length() )
			{
				MStatus status;
				MItMeshPolygon itPolygon( mObj, &status );
				if( status != MS::kSuccess )
				{
					IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to create mesh iterator" );
				}

				unsigned v = 0;
				MIntArray vertexIds;
				MIntArray faceIds;
				
				for ( ; !itPolygon.isDone(); itPolygon.next() )
				{
					for ( v=0; v < itPolygon.polygonVertexCount(); ++v )
					{
						faceIds.append( itPolygon.index() );
						vertexIds.append( itPolygon.vertexIndex( v ) );
					}
				}

				if( !fnMesh.setFaceVertexNormals( vertexNormalsArray, faceIds, vertexIds ) )
				{
					IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Setting normals failed" );
				}
			}
		}
		else
		{
			IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." );
		}
	}

	bool haveDefaultUVs = false;
	IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( "s" );
	IECore::RefCountedPtr sDataRef = ( sIt == mesh->variables.end() ) ? 0 : static_cast<IECore::RefCountedPtr>( sIt->second.data );

	/// Add named UV sets
	std::set< std::string > uvSets;
	for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it )
	{
		const std::string &sName = it->first;

		size_t suffixOffset = sName.rfind( "_s" );

		if ( ( suffixOffset != std::string::npos) && ( suffixOffset == sName.length() - 2 ) )
		{
			std::string uvSetNameStr = sName.substr( 0, suffixOffset );

			if ( uvSetNameStr.size() )
			{
				MString uvSetName = uvSetNameStr.c_str();
				std::string tName = uvSetNameStr + "_t";
				std::string stIdName = uvSetNameStr + "Indices";

				addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName );

				uvSets.insert( uvSetNameStr );
				
				if ( sDataRef == static_cast<IECore::RefCountedPtr>( it->second.data ) )
				{
					haveDefaultUVs = true;
				}
			}
		}
	}

	/// Add default UV set if it isn't just a reference to a named set
	if ( !haveDefaultUVs )
	{
		addUVSet( fnMesh, polygonCounts, mesh, "s", "t", "stIndices" );
	}

	// We do the search again, but looking for primvars ending "_t", so we can catch cases where either "UVSETNAME_s" or "UVSETNAME_t" is present, but not both, taking care
	// not to attempt adding any duplicate sets
	for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it )
	{
		const std::string &tName = it->first;

		size_t suffixOffset = tName.rfind( "_t" );

		if ( ( suffixOffset != std::string::npos) && ( suffixOffset == tName.length() - 2 ) )
		{
			std::string uvSetNameStr = tName.substr( 0, suffixOffset );

			if ( uvSetNameStr.size() && uvSets.find( uvSetNameStr ) == uvSets.end() )
			{
				MString uvSetName = uvSetNameStr.c_str();
				std::string sName = uvSetNameStr + "_s";
				std::string stIdName = uvSetNameStr + "Indices";
				
				addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName );
				uvSets.insert( uvSetNameStr );
			}
		}
	}

	/// If we're making a mesh node (rather than a mesh data) then make sure it belongs
	/// to the default shading group and add the ieMeshInterpolation attribute.
	MObject oMesh = fnMesh.object();
	if( oMesh.apiType()==MFn::kMesh )
	{
		assignDefaultShadingGroup( oMesh );
		setMeshInterpolationAttribute( oMesh, mesh->interpolation() );
	}

	/// \todo Other primvars, e.g. vertex color ("Cs")

	return true;
}
MStatus testNpassiveNode::compute(const MPlug &plug, MDataBlock &data)
{
    MStatus stat;
    if ( plug == currentState )
    { 
      // get old positions and numVerts
      // if num verts is different, reset topo and zero velocity
      // if num verts is the same, compute new velocity
        int ii,jj;
        // initialize MnCloth
        MObject inMeshObj = data.inputValue(inputGeom).asMesh();
                
        MFnMesh inputMesh(inMeshObj);       
        unsigned int numVerts = 0;
        numVerts = inputMesh.numVertices();
        unsigned int prevNumVerts;
        fNObject.getNumVertices(prevNumVerts);
        if(numVerts != prevNumVerts) {
                int numPolygons = inputMesh.numPolygons();
                int * faceVertCounts = new int[numPolygons];
                
        
                int facesArrayLength = 0;
                for(ii=0;ii<numPolygons;ii++) {
                MIntArray verts;
                inputMesh.getPolygonVertices(ii,verts);
                faceVertCounts[ii] = verts.length();
                facesArrayLength += verts.length();
                }
                int * faces = new int[facesArrayLength];
                int currIndex = 0;
                for(ii=0;ii<numPolygons;ii++) {
                MIntArray verts;
                inputMesh.getPolygonVertices(ii,verts);
                for(jj=0;jj<(int)verts.length();jj++) {
                    faces[currIndex++] = verts[jj];
                }
            }
                int numEdges = inputMesh.numEdges();
                int * edges = new int[2*numEdges];
                currIndex = 0;
                for(ii=0;ii<numEdges;ii++) {
                int2 edge;
                inputMesh.getEdgeVertices(ii,edge);
                edges[currIndex++] = edge[0];
                edges[currIndex++] = edge[1];
                }
                // When you are doing the initialization, the first call must to be setTopology().  All other
                // calls must come after this.
            fNObject.setTopology(numPolygons, faceVertCounts, faces,numEdges, edges );
                delete[] faceVertCounts;
                delete[] faces;
                delete[] edges;        
                MFloatPointArray vertexArray;
                inputMesh.getPoints(vertexArray, MSpace::kWorld);
                fNObject.setPositions(vertexArray,true);
                MFloatPointArray velocitiesArray;
                velocitiesArray.setLength(numVerts);
                for(ii=0;ii<(int)numVerts;ii++) {
                velocitiesArray[ii].x = 0.0f;
                velocitiesArray[ii].y = 0.0f;
                velocitiesArray[ii].z = 0.0f;
                velocitiesArray[ii].w = 0.0f;
            }
            fNObject.setVelocities(velocitiesArray);
        } else {
                MFloatPointArray vertexArray;
                MFloatPointArray prevVertexArray;
                inputMesh.getPoints(vertexArray, MSpace::kWorld);
                fNObject.getPositions(prevVertexArray);
            // you may want to get the playback rate for the dt
            // double dt = MAnimControl::playbackBy() \ 24.0;
            // or get the real dt by caching the last eval time
            double dt = 1.0/24.0;
                MFloatPointArray velocitiesArray;
                velocitiesArray.setLength(numVerts);
                for(ii=0;ii<(int)numVerts;ii++) {
                velocitiesArray[ii].x = (float)( (vertexArray[ii].x - prevVertexArray[ii].x)/dt);
                velocitiesArray[ii].y = (float)( (vertexArray[ii].y - prevVertexArray[ii].y)/dt);
                velocitiesArray[ii].z = (float)( (vertexArray[ii].x - prevVertexArray[ii].z)/dt);
                velocitiesArray[ii].w = 0.0f;
            }
            fNObject.setVelocities(velocitiesArray);
            fNObject.setPositions(vertexArray,true);
        }
        // in real life, you'd get these attribute values each frame and set them
        fNObject.setThickness(0.1f);
        fNObject.setBounce(0.0f);
        fNObject.setFriction(0.1f);
        fNObject.setCollisionFlags(true, true, true);               
        MFnNObjectData outputData;
        MObject mayaNObjectData = outputData.create();
        outputData.setObject(mayaNObjectData);
        
        outputData.setObjectPtr(&fNObject);        
        outputData.setCached(false);
        MDataHandle currStateOutputHandle = data.outputValue(currentState);
        currStateOutputHandle.set(outputData.object());
      
    }
    if ( plug == startState )
    {
        int ii,jj;
        // initialize MnCloth
        MObject inMeshObj = data.inputValue(inputGeom).asMesh();
                
        MFnMesh inputMesh(inMeshObj);       
        int numPolygons = inputMesh.numPolygons();
            int * faceVertCounts = new int[numPolygons];
                
        
            int facesArrayLength = 0;
            for(ii=0;ii<numPolygons;ii++) {
                MIntArray verts;
                inputMesh.getPolygonVertices(ii,verts);
                faceVertCounts[ii] = verts.length();
                facesArrayLength += verts.length();
            }
            int * faces = new int[facesArrayLength];
            int currIndex = 0;
            for(ii=0;ii<numPolygons;ii++) {
                MIntArray verts;
                inputMesh.getPolygonVertices(ii,verts);
                for(jj=0;jj<(int)verts.length();jj++) {
                    faces[currIndex++] = verts[jj];
               }
           }
            int numEdges = inputMesh.numEdges();
            int * edges = new int[2*numEdges];
            currIndex = 0;
            for(ii=0;ii<numEdges;ii++) {
                int2 edge;
                inputMesh.getEdgeVertices(ii,edge);
                edges[currIndex++] = edge[0];
                edges[currIndex++] = edge[1];
            }
            // When you are doing the initialization, the first call must to be setTopology().  All other
            // calls must come after this.
            fNObject.setTopology(numPolygons, faceVertCounts, faces,numEdges, edges );
            delete[] faceVertCounts;
            delete[] faces;
            delete[] edges;        
            unsigned int numVerts = 0;
            numVerts = inputMesh.numVertices();        
            MFloatPointArray vertexArray;
            inputMesh.getPoints(vertexArray, MSpace::kWorld);
            fNObject.setPositions(vertexArray,true);
            MFloatPointArray velocitiesArray;
            velocitiesArray.setLength(numVerts);
            for(ii=0;ii<(int)numVerts;ii++) {
                velocitiesArray[ii].x = 0.0f;
                velocitiesArray[ii].y = 0.0f;
                velocitiesArray[ii].z = 0.0f;
                velocitiesArray[ii].w = 0.0f;
           }
           fNObject.setVelocities(velocitiesArray);
           fNObject.setThickness(0.1f);
            fNObject.setBounce(0.0f);
            fNObject.setFriction(0.1f);
            fNObject.setCollisionFlags(true, true, true);               
        
            MFnNObjectData outputData;
            MObject mayaNObjectData = outputData.create();
            outputData.setObject(mayaNObjectData);
        
            outputData.setObjectPtr(&fNObject);        
            outputData.setCached(false);
            MDataHandle startStateOutputHandle = data.outputValue(startState);
            startStateOutputHandle.set(outputData.object());
    }
    else {
        stat = MS::kUnknownParameter;
    }
    return stat;
}
Beispiel #4
0
MStatus TCC::createSubdividedMesh(int sdRes, int sdRefRes, MFnMesh &srcMesh, TCCData &tccData, MDataHandle outMeshHandle, float lineThickness, MStatus& stat)
{   
    HDS hds;
    bool shouldCreateUVs = true;
    
    size_t nV = srcMesh.numVertices();
    size_t nF = srcMesh.numPolygons();
    size_t nIHE = tccData.F.length();
    
    bool consistentSizes= (tccData.pole.length()==nV) && (tccData.T.length()==nIHE) && (tccData.itv.length()==nIHE) & (tccData.corner.length()==nV);
    
    if ((nV==0)||(nF==0)||(!consistentSizes)) return MS::kFailure;

    MFloatArray uArray, vArray, sc_uArray, sc_vArray;
    MIntArray uvIdx;
    if (shouldCreateUVs)
    {
        createUVset(tccData, sdRes, uArray, vArray, sc_uArray, sc_vArray, uvIdx, lineThickness);
    }
    
    
    MFloatPointArray points;
    srcMesh.getPoints(points);
    
    store_in_hds(hds, points, tccData.nFV, tccData.F);     // convert to HDS

    finalize_HDS(hds);
    size_t nHE = hds.nHE();

    hds.T.setDims(1, nHE);
    hds.itv.setDims(1, nHE);
    hds.corner.setDims(1, nV);
    
    // interior halfedge tags
    for (size_t k=0; k<nV; k++) 
    {
        hds.corner[k] = tccData.corner[k];
    }

    // interior halfedge tags
    for (size_t k=0; k<nIHE; k++) 
    {
        hds.T[k] = tccData.T[k];
        hds.itv[k] = tccData.itv[k];
    }
    
    // border halfedge tags
    for (size_t k=nIHE; k<nHE; k++) 
    {
        hds.T[k] = false;
        hds.itv[k] = hds.itv[hds.twin[k]];
    }
        
    TCC_MAX::subdivide(hds, sdRes);
    
    if (sdRefRes>0)
    {
        HDS hds2;
        copy_HDS(hds, hds2);
        TCC_MAX::subdivide(hds2, sdRefRes);
        memcpy(&hds.V[0], &hds2.V[0], hds.V.size() * sizeof(double));
    }
    

    
    MObject outMeshObj = outMeshHandle.asMesh();
    MFnMesh outMeshFn(outMeshObj);
    
    // if no topology change necessary, just update points!
    if ( (outMeshFn.numFaceVertices() == hds.nIHE()) && (outMeshFn.numPolygons() == hds.nF()) )
    {
        size_t nV   = hds.nV();
        points.setLength(nV);
        for (size_t k=0; k<nV; k++) 
        {
            points[k](0) = hds.V[3*k+0];
            points[k](1) = hds.V[3*k+1];
            points[k](2) = hds.V[3*k+2];
        }
        stat = outMeshFn.setPoints(points); McheckErr(stat, "ERROR creating outputData");
        
        if (shouldCreateUVs)
        {
            MString uvSet = "UnitPatchUVs";
            MString sc_uvSet = "ScaledPatchUVs";
            stat = outMeshFn.setUVs(uArray, vArray, &uvSet); McheckErr(stat, "ERROR setting UVs");
            stat = outMeshFn.setUVs(sc_uArray, sc_vArray, &sc_uvSet); McheckErr(stat, "ERROR setting UVs");
        }
        
        return MS::kSuccess;
    }

    
    // Have to update connectivity and geometry

    load_from_hds(hds, points, tccData.nFV, tccData.F);

    nV = points.length();
    nF = tccData.nFV.length();
    
    MFnMeshData dataCreator;
    MObject newOutputData = dataCreator.create(&stat); McheckErr(stat, "ERROR creating outputData");
    MFnMesh newOutMeshFn;
    
    MObject newMesh;
    
    newMesh = newOutMeshFn.create(nV, nF, points, tccData.nFV, tccData.F, newOutputData, &stat); McheckErr(stat, "ERROR in MFnMesh.create\n");

    if (shouldCreateUVs)
    {
        MString uvSet = "UnitPatchUVs";
        MString sc_uvSet = "ScaledPatchUVs";
        
        uvSet = newOutMeshFn.createUVSetDataMeshWithName(uvSet, &stat); McheckErr(stat, "ERROR creating UVset");
        stat = newOutMeshFn.clearUVs(&uvSet);
        stat = newOutMeshFn.setUVs(uArray, vArray, &uvSet); McheckErr(stat, "ERROR setting UVs");
        stat = newOutMeshFn.assignUVs(tccData.nFV, uvIdx, &uvSet); McheckErr(stat, "ERROR assigning UVs");
        
        sc_uvSet = newOutMeshFn.createUVSetDataMeshWithName(sc_uvSet, &stat); McheckErr(stat, "ERROR creating UVset");
        stat = newOutMeshFn.clearUVs(&sc_uvSet);
        stat = newOutMeshFn.setUVs(sc_uArray, sc_vArray, &sc_uvSet); McheckErr(stat, "ERROR setting UVs");
        stat = newOutMeshFn.assignUVs(tccData.nFV, uvIdx, &sc_uvSet); McheckErr(stat, "ERROR assigning UVs");
    }
    
    
    if (stat == MS::kSuccess)
    {
        outMeshHandle.set(newOutputData);
    }
    
    
    return MS::kSuccess;
}
Beispiel #5
0
MStatus testNobjectNode::compute(const MPlug &plug, MDataBlock &data)
{
	MStatus stat;

	if ( plug == outputGeom )
	{
		MObject inMeshObj = data.inputValue(inputGeom).asMesh();
		
        cerr<<"pull on outputGeom\n";

		MFnMeshData meshDataFn;
        MFnMesh inputMesh(inMeshObj);
		MObject newMeshObj = meshDataFn.create();
		MFnMesh newMeshFn;
		newMeshFn.copy( inMeshObj, newMeshObj );        

        //get the value of the currentTime so it can correctly dirty the
        //startState, currentState.
        data.inputValue(currentTime).asTime();

		// pull on next state.  This will cause the solver to pull on either
        // the startState or the currentState, depending on the time of solve.
        // When we return the state to the solver, it will do the solve and update
        // The N Object data directly.
		MObject nextNObj = data.inputValue(nextState).data();
        MFloatPointArray pts;        

        //At this point the N Object's internal state should have been updated
        //by the solver.  Read it out and set the output mesh.
        fNObject.getPositions(pts);
        if(pts.length() == (unsigned int) inputMesh.numVertices()) {
            newMeshFn.setPoints(pts);
        }

		newMeshFn.setObject( newMeshObj );

		data.outputValue(outputGeom).set(newMeshObj);
		data.setClean(plug);

	}
	if ( plug == currentState )
	{               
        MFnNObjectData outputData;
        MObject mayaNObjectData = outputData.create();
        outputData.setObject(mayaNObjectData);
        
        outputData.setObjectPtr(&fNObject);        
        outputData.setCached(false);

        MDataHandle currStateOutputHandle = data.outputValue(currentState);
        currStateOutputHandle.set(outputData.object());
	  
        cerr<<"pull on currentState\n";
	}
	if ( plug == startState )
	{
	    int ii,jj;
        // initialize MnCloth
        MObject inMeshObj = data.inputValue(inputGeom).asMesh();
				
        MFnMesh inputMesh(inMeshObj);		

        int numPolygons = inputMesh.numPolygons();
        int * faceVertCounts = new int[numPolygons];
                
        
        int facesArrayLength = 0;
        for(ii=0;ii<numPolygons;ii++) {
            MIntArray verts;
            inputMesh.getPolygonVertices(ii,verts);
            faceVertCounts[ii] = verts.length();
            facesArrayLength += verts.length();
        }
        int * faces = new int[facesArrayLength];
        int currIndex = 0;
        for(ii=0;ii<numPolygons;ii++) {
            MIntArray verts;
            inputMesh.getPolygonVertices(ii,verts);
            for(jj=0;jj<(int)verts.length();jj++) {
                faces[currIndex++] = verts[jj];
            }
        }

        int numEdges = inputMesh.numEdges();
        int * edges = new int[2*numEdges];
        currIndex = 0;
        for(ii=0;ii<numEdges;ii++) {
            int2 edge;
            inputMesh.getEdgeVertices(ii,edge);
            edges[currIndex++] = edge[0];
            edges[currIndex++] = edge[1];
        }

        // When you are doing the initialization, the first call must to be setTopology().  All other
        // calls must come after this.
        fNObject.setTopology(numPolygons, faceVertCounts, faces,numEdges, edges );
        delete[] faceVertCounts;
        delete[] faces;
        delete[] edges;        


        unsigned int numVerts = 0;
        numVerts = inputMesh.numVertices();        

        MFloatPointArray vertexArray;
        inputMesh.getPoints(vertexArray);
        fNObject.setPositions(vertexArray,true);

        MFloatPointArray velocitiesArray;
        velocitiesArray.setLength(numVerts);
        for(ii=0;ii<(int)numVerts;ii++) {
            velocitiesArray[ii].x = 0.0f;
            velocitiesArray[ii].y = 0.0f;
            velocitiesArray[ii].z = 0.0f;
            velocitiesArray[ii].w = 0.0f;
        }
        fNObject.setVelocities(velocitiesArray);
        fNObject.setThickness(0.05f);
        fNObject.setInverseMass(1.0f);
        fNObject.setBounce(0.0f);
        fNObject.setFriction(0.1f);
        fNObject.setDamping(0.0f);
        fNObject.setBendResistance(0.0f);
        fNObject.setMaxIterations(100);        
        fNObject.setMaxSelfCollisionIterations(100);
        fNObject.setStretchAndCompressionResistance(20.0f,10.0f);
        fNObject.setSelfCollisionFlags(false);
        fNObject.setCollisionFlags(true);        	    

        
        MFnNObjectData outputData;
        MObject mayaNObjectData = outputData.create();
        outputData.setObject(mayaNObjectData);
        
        outputData.setObjectPtr(&fNObject);        
        outputData.setCached(false);

        MDataHandle startStateOutputHandle = data.outputValue(startState);
        startStateOutputHandle.set(outputData.object());

        cerr<<"pull on startState\n";
	}
	else {
		stat = MS::kUnknownParameter;
	}
	return stat;
}