void vixo_hairCacheExport::getInCurveInfo(map<int,int>& plugMapVID,MString vixoHairNode,map<int,MVectorArray>& inCurveShape)
{

	MSelectionList slist;
	MGlobal::getSelectionListByName(vixoHairNode,slist);
	MDagPath vixoHairNodeDag;
	slist.getDagPath(0,vixoHairNodeDag);
	vixoHairNodeDag.extendToShape();
	MFnDagNode fnVixoHair(vixoHairNodeDag);
	MPlug plugInCtrlCurveData=fnVixoHair.findPlug("inCtrlCurveData");

	map<int,int>::iterator iterPlugMapVID;
	for(iterPlugMapVID=plugMapVID.begin();iterPlugMapVID!=plugMapVID.end();iterPlugMapVID++)
	{
		MPlug inCurvePlug=plugInCtrlCurveData.elementByLogicalIndex(iterPlugMapVID->first);
		MFnVectorArrayData fnVector(inCurvePlug.asMObject());
		MVectorArray data=fnVector.array();
		MVectorArray tangent(data.length()-1);

		MPlugArray tempArr;
		inCurvePlug.connectedTo(tempArr,true,false);
		MFnDependencyNode fnHairSystem(tempArr[0].node());
		MPlug inputHairs=fnHairSystem.findPlug("inputHair");
		tempArr.clear();
		inputHairs.elementByLogicalIndex(iterPlugMapVID->first).connectedTo(tempArr,true,false);
		MFnDependencyNode fnFolli(tempArr[0].node());
		MFnMatrixData fnMatData(fnFolli.findPlug("worldMatrix[0]").asMObject());
		MMatrix mat=fnMatData.matrix();

		for(int i=0;i<data.length()-1;i++)
		{
			tangent[i]=data[i+1]*mat-data[i]*mat;
		}

		inCurveShape.insert(pair<int,MVectorArray>(iterPlugMapVID->second,tangent));
	}
	
}
MStatus vixo_hairCacheExport::doIt(const MArgList& args)
{
	MString vixoHairNode;
	int startFrame,endFrame;
	unsigned index;
	index=args.flagIndex("vhn","vixoHairNode");
	if(MArgList::kInvalidArgIndex!=index)
	{
		args.get(index+1,vixoHairNode);
	}
	index=args.flagIndex("sf","startFrame");
	if(MArgList::kInvalidArgIndex!=index)
	{
		args.get(index+1,startFrame);
	}
	index=args.flagIndex("ef","endFrame");
	if(MArgList::kInvalidArgIndex!=index)
	{
		args.get(index+1,endFrame);
	}

	//get hairCacheFileName
	MSelectionList slist;
	MGlobal::getSelectionListByName(vixoHairNode,slist);
	MDagPath vixoHairNodeDag;
	slist.getDagPath(0,vixoHairNodeDag);
	vixoHairNodeDag.extendToShape();
	MFnDagNode fnVixoHair(vixoHairNodeDag);
	MPlug plugCacheFileName=fnVixoHair.findPlug("hairCacheFileName");
	MString cacheFileName=plugCacheFileName.asString();
	//~get hairCacheFileName

	//get staticMesh
	MPlug plugStaticMesh=fnVixoHair.findPlug("staticInMesh");
	MObject staticMeshObj=MFnMeshData(plugStaticMesh.asMObject()).object();
	//~get staticMesh

	//build out dataBase
	MFnMesh fnStaticMesh(staticMeshObj);
	map<int,set<outInVertexRelationInfo>> outVertexDataBase;
	map<int,vector<outVIDCtrlInfo>> outVertexControlData;
	for(int i=0;i<fnStaticMesh.numVertices();i++)
	{
		set<outInVertexRelationInfo> temp;
		temp.clear();
		outVertexDataBase.insert(pair<int,set<outInVertexRelationInfo>>(i,temp));
	}
	//build out dataBase

	//get inCurveVID
	map<int,int> plugMapVID;
	map<int,int> VIDMapPlug;
	map<int,inVertexBasicInfo> inVIDMapInVertexDataBase;
	MPlug plugAllInCurve=fnVixoHair.findPlug("inCtrlCurveData");
	MIntArray existIndex;
	plugAllInCurve.getExistingArrayAttributeIndices(existIndex);
	for(int i=0;i<existIndex.length();i++)
	{
		MPlugArray arr;
		plugAllInCurve.elementByLogicalIndex(existIndex[i]).connectedTo(arr,true,false);
		MFnDependencyNode fnHairSystem(arr[0].node());
		MPlug inputHairs=fnHairSystem.findPlug("inputHair");
		arr.clear();
		inputHairs.elementByLogicalIndex(existIndex[i]).connectedTo(arr,true,false);
		MFnDependencyNode fnFolli(arr[0].node());
		int vid=fnFolli.findPlug("vertexID").asInt();
		plugMapVID.insert(pair<int,int>(existIndex[i],vid));
		VIDMapPlug.insert(pair<int,int>(vid,existIndex[i]));
		initBasicStepInfo(vid,staticMeshObj,inVIDMapInVertexDataBase);
	}	
	//~get inCurveVID

	//build in out relation
	map<int,inVertexBasicInfo>::iterator inDBIter;
	for(inDBIter=inVIDMapInVertexDataBase.begin();inDBIter!=inVIDMapInVertexDataBase.end();inDBIter++)
	{
		buileRelationBetweenInOut(inDBIter->first,inVIDMapInVertexDataBase,outVertexDataBase);
	}

	map<int,set<outInVertexRelationInfo>>::iterator outDBIter;
	for(outDBIter=outVertexDataBase.begin();outDBIter!=outVertexDataBase.end();outDBIter++)
	{
		sortControlOrder(outDBIter->first,outVertexDataBase,outVertexControlData);
	}
	//~build in out relation

	for(int i=startFrame;i<=endFrame;i++)
	{
		MString currentTime;
		currentTime.set(i);
		MGlobal::executeCommand("currentTime "+currentTime);
		MGlobal::executeCommand("dgeval "+vixoHairNode+".hiddenOutput");

		//get dynamic mesh
		MPlug plugDynamicMesh=fnVixoHair.findPlug("dynamicInMesh");
		MObject dynamicMeshObj=MFnMeshData(plugDynamicMesh.asMObject()).object();
		//~get dynamic mesh

		//export cache
		//faceid triid vid position normal tangent
		vector<forExportHairCache> exportData;
		exportBasicData(dynamicMeshObj,exportData);
		//curve tangent
		//get in curve infos
		map<int,MVectorArray> inCurveShape;
		getInCurveInfo(plugMapVID,vixoHairNode,inCurveShape);
		//~get in curve infos

		vector<vec3> outCurveCacheData;
		vec3 init;
		init.x=0;
		init.y=0;
		init.z=0;
		outCurveCacheData.resize(fnStaticMesh.numVertices()*inCurveShape.begin()->second.length(),init);
		buildCache(inCurveShape.begin()->second.length(),dynamicMeshObj,outCurveCacheData,inCurveShape,outVertexControlData);
		//~export cache

		//write to file
		MString fileName=getFileName(cacheFileName,i);
		fstream fout(fileName.asChar(),ios_base::out|ios_base::binary);
		int triNumvertexNum[3];
		triNumvertexNum[0]=exportData.size();
		triNumvertexNum[1]=fnStaticMesh.numVertices();
		triNumvertexNum[2]=inCurveShape.begin()->second.length();
		fout.write((char*)triNumvertexNum,sizeof(int)*3);
		fout.write((char*)&exportData[0],sizeof(forExportHairCache)*exportData.size());
		fout.write((char*)&outCurveCacheData[0],sizeof(vec3)*outCurveCacheData.size());
		fout.flush();
		fout.close();
		/*
		MString fileNameDebug=fileName+".dbg";
		fout.open(fileNameDebug.asChar(),ios_base::out);
		for(int i=0;i<outCurveCacheData.size();i++)
		{
			fout<<outCurveCacheData[i].x<<" "<<outCurveCacheData[i].y<<" "<<outCurveCacheData[i].z<<endl;
		}
		fout.flush();
		fout.close();
		*/
		//~write to file
	}

	return MS::kSuccess;
}
Esempio n. 3
0
bool		preFrame(
				const MObject		hairSystem,
				const double		curTime,
				void				**privateData )
{
	MStatus status;

	// If you need want to perform any preprocessing on your collision
	// objects pre-frame, do it here. One option for storing the pre-
	// processed data is on a typed attribute on the hairSystem node.
	// That data could be fetched and updated here.
	//
	// In our example, we'll just compute a bounding box here and NOT use
	// attribute storage. That is an exercise for the reader.
	//
	MFnDependencyNode fnHairSystem( hairSystem, &status );
	CHECK_MSTATUS_AND_RETURN( status, false );
	fprintf( stderr,
			"preFrame: calling hairSystem node=`%s', time=%g\n",
			fnHairSystem.name().asChar(), curTime );
	MObjectArray	cols;
	MIntArray		logIdxs;
	CHECK_MSTATUS_AND_RETURN( MHairSystem::getCollisionObject( hairSystem,
			cols, logIdxs ), false );
	int nobj = cols.length();

	// Allocate private data.
	// This allows us to pre-process data on a pre-frame basis to avoid
	// calculating it per hair inside the collide() call. As noted earlier
	// we could allocate this in preFrame() and hang it off the hairSystem
	// node via a dynamic attribute.
	// Instead we'll allocate it here.
	//
	COLLISION_INFO *collisionInfo = (COLLISION_INFO *) malloc(
			sizeof( COLLISION_INFO ) );
	collisionInfo->objs = (COLLISION_OBJ *) malloc(
			nobj * sizeof( COLLISION_OBJ ) );
	collisionInfo->numObjs = nobj;

	// Create the private data that we'll make available to the collide
	// method. The data should actually be stored in a way that it can
	// be cleaned up (such as storing the pointer on the hairSystem node
	// using a dynamic attribute). As it stands right now, there is a
	// memory leak with this plug-in because the memory we're allocating
	// for the private data is never cleaned up.
	//
	// Note that when using the dynamic attribute approach, it is still
	// wise to set *privateData because this avoids the need to look up
	// the plug inside the collide() routine which is a high-traffic
	// method.
	//
	*privateData = (void *) collisionInfo;

	// Loop through the collision objects and pre-process, storing the
	// results in the collisionInfo structure.
	//
	int	   obj;
	for ( obj = 0; obj < nobj; ++obj ) {
		// Get the ith collision geometry we are connected to.
		//
		MObject colObj = cols[obj];

		// Get the DAG path for the collision object so we can transform
		// the vertices to world space.
		//
		MFnDagNode fnDagNode( colObj, &status );
		CHECK_MSTATUS_AND_RETURN( status, false );
		MDagPath path;
		status = fnDagNode.getPath( path );
		CHECK_MSTATUS_AND_RETURN( status, false );
		MFnMesh fnMesh( path, &status );
		if ( MS::kSuccess != status ) {
			fprintf( stderr,
					"%s:%d: collide was not passed a valid mesh shape\n",
					__FILE__, __LINE__ );
			return( false );
		}

		// Get the vertices of the object transformed to world space.
		//
		MFloatPointArray	verts;
		status = fnMesh.getPoints( verts, MSpace::kWorld );
		CHECK_MSTATUS_AND_RETURN( status, false );

		// Compute the bounding box for the collision object.
		// As this is a quick and dirty demo, we'll just support collisions
		// between hair and the bbox.
		//
		double minx, miny, minz, maxx, maxy, maxz, x, y, z;
		minx = maxx = verts[0].x;
		miny = maxy = verts[0].y;
		minz = maxz = verts[0].z;
		int nv = verts.length();
		int i;
		for ( i = 1; i < nv; ++i ) {
			x = verts[i].x;
			y = verts[i].y;
			z = verts[i].z;

			if ( x < minx ) {
				minx = x;
			}
			if ( y < miny ) {
				miny = y;
			}
			if ( z < minz ) {
				minz = z;
			}

			if ( x > maxx ) {
				maxx = x;
			}
			if ( y > maxy ) {
				maxy = y;
			}
			if ( z > maxz ) {
				maxz = z;
			}
		}

		// Store this precomputed informantion into our private data
		// structure.
		//
		collisionInfo->objs[obj].numVerts = nv;
		collisionInfo->objs[obj].minx = minx;
		collisionInfo->objs[obj].miny = miny;
		collisionInfo->objs[obj].minz = minz;
		collisionInfo->objs[obj].maxx = maxx;
		collisionInfo->objs[obj].maxy = maxy;
		collisionInfo->objs[obj].maxz = maxz;
		fprintf( stderr, "Inside preFrameInit, bbox=%g %g %g %g %g %g\n",
				minx,miny,minz,maxx,maxy,maxz);
	}

	return( true );
}