// used when ray does not intersect object
	// to account for perspective, all edges are flattened onto 
	// a plane defined by the raySource and rayDirection
	double gpuCacheIsectUtil::getEdgeSnapPointOnTriangle(const MPoint& raySource, const MVector& rayDirection, const MPoint& vert1, const MPoint& vert2, const MPoint& vert3, MPoint& snapPoint){
		MPointArray verts;
		verts.insert(vert1,0);
		verts.insert(vert2,1);
		verts.insert(vert3,2);

		int edgeIndices[3][2]={{0,1},{1,2},{2,0}};

		double minDistTri = std::numeric_limits<double>::max();

		for(int edge=0; edge<3;edge++){
			MPoint vertex1Org = verts[edgeIndices[edge][0]];
			MPoint vertex2Org = verts[edgeIndices[edge][1]];

			double coef_plane = rayDirection * raySource;
			double d = coef_plane - rayDirection * vertex1Org;
			MPoint vertex1 = vertex1Org + rayDirection * d;
			d = coef_plane - rayDirection * vertex2Org;
			MPoint vertex2 = vertex2Org + rayDirection * d;

			MVector edgeDir = vertex2 - vertex1;
			
			if (edgeDir.length()<0.0000001){
				double dist = vertex1.distanceTo(raySource);
				if (dist < minDistTri) {
					minDistTri = dist;
					snapPoint = vertex1Org;
				}
			} else {
				MPoint edgePt;
				// Compute the closest point from the edge to cursor Ray.
				double percent = gpuCacheIsectUtil::getClosestPointOnLine(raySource, vertex1, vertex2, edgePt);
				double dist = edgePt.distanceTo(raySource);                                                            
				if (dist < minDistTri) {
					minDistTri = dist;
					snapPoint =  (vertex1Org + percent * (vertex2Org - vertex1Org));
				}
			}
		}

		return minDistTri;
	}
	// used when ray does not intersect object
	// to account for perspective, all edges are flattened onto 
	// a plane defined by the raySource and rayDirection
	double gpuCacheIsectUtil::getEdgeSnapPointOnBox(const MPoint& raySource, const MVector& rayDirection, const MBoundingBox& bbox, MPoint& snapPoint){
		//if ray intersects bbox
		MPoint boxIntersectionPt;
		if(firstRayIntersection(bbox.min(), bbox.max(), raySource, rayDirection, NULL, &boxIntersectionPt))
		{
			//	ray intersects bounding box, so snapPoint is
			//	closest hit on the outside of the box
			//  and distance to box is 0 (for snapping purposes)
			snapPoint = boxIntersectionPt;
			return 0.0;
		}

		MPointArray verts;
		MPoint vmin = bbox.min();
		MPoint vmax = bbox.max();

		verts.insert(vmin,0);
		verts.insert(MPoint(vmax[0],vmin[1],vmin[2]),1);
		verts.insert(MPoint(vmax[0],vmax[1],vmin[2]),2);
		verts.insert(MPoint(vmin[0],vmax[1],vmin[2]),3);
		verts.insert(MPoint(vmin[0],vmin[1],vmax[2]),4);
		verts.insert(MPoint(vmax[0],vmin[1],vmax[2]),5);
		verts.insert(vmax,6);
		verts.insert(MPoint(vmin[0],vmax[1],vmax[2]),7);

		int edgeIndices[12][2]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{3,7},{2,6}};

		double minDistRect = std::numeric_limits<double>::max();
		
		for(int edge=0; edge<12;edge++){
			MPoint vertex1Org = verts[edgeIndices[edge][0]];
			MPoint vertex2Org = verts[edgeIndices[edge][1]];
			
			double coef_plane = rayDirection * raySource;
			double d = coef_plane - rayDirection * vertex1Org;
			MPoint vertex1 = vertex1Org + rayDirection * d;
			d = coef_plane - rayDirection * vertex2Org;
			MPoint vertex2 = vertex2Org + rayDirection * d;

			MVector edgeDir = vertex2 - vertex1;

			if (edgeDir.length()<0.0000001){
				double dist = vertex1.distanceTo(raySource);
				if (dist < minDistRect) {
					minDistRect = dist;
					snapPoint = vertex1Org;
				}
			} else {
				MPoint edgePt;
				// Compute the closest point from the edge to cursor Ray.
				double percent = gpuCacheIsectUtil::getClosestPointOnLine(raySource, vertex1, vertex2, edgePt);
				double dist = edgePt.distanceTo(raySource);
				if (dist < minDistRect) {
					minDistRect = dist;
					snapPoint =  (vertex1Org + percent * (vertex2Org - vertex1Org));
				}
			}
		}
		
		return minDistRect;
	}
Beispiel #3
0
MStatus particlePathsCmd::doIt( const MArgList& args )
{
	MStatus stat = parseArgs( args );
	if( stat != MS::kSuccess ) 
	{
		return stat;
	}

	MFnParticleSystem cloud( particleNode );

	if( ! cloud.isValid() )
	{
		MGlobal::displayError( "The function set is invalid!" );
		return MS::kFailure;
	}

	//
	// Create curves from the particle system in two stages.  First, sample 
	// all particle positions from the start time to the end time.  Then,
	// use the data that was collected to create curves.
	//

	// Create the particle hash table at a fixed size.  This should work fine
	// for small particle systems, but may become inefficient for larger ones.
	// If the plugin is running very slow, increase the size.  The value should
	// be roughly the number of particles that are expected to be emitted
	// within the time period.
	//
	ParticleIdHash hash(1024);
	MIntArray idList;

	//
	// Stage 1
	//

	MVectorArray positions;
	MIntArray ids;
	int i = 0;
	for (double time = start; time <= finish + TOLERANCE; time += increment)
	{
		MTime timeSeconds(time,MTime::kSeconds);

		// It is necessary to query the worldPosition attribute to force the 
		// particle positions to update.
		//
		cloud.evaluateDynamics(timeSeconds,false);
//		MGlobal::executeCommand(MString("getAttr ") + cloud.name() + 
//			MString(".worldPosition"));

		if (!cloud.isValid())
		{
			MGlobal::displayError( "Particle system has become invalid." );
			return MS::kFailure;
		}

		MGlobal::displayInfo( MString("Received ") + (int)(cloud.count()) + 
			" particles, at time " + time);

		// Request position and ID data for particles
		//
		cloud.position( positions );
		cloud.particleIds( ids );

		if (ids.length() != cloud.count() || positions.length() != cloud.count())
		{
			MGlobal::displayError( "Invalid array sizes." );
			return MS::kFailure;
		}

		for (int j = 0; j < (int)cloud.count(); j++)
		{
			// Uncomment to show particle positions as the plugin accumulates
			// samples.
			/*
			MGlobal::displayInfo(MString("(") + (positions[j])[0] + MString(",") + 
				(positions[j])[1] + MString(",") + (positions[j])[2] + MString(")"));
			*/

			MPoint pt(positions[j]);
			if (hash.getPoints(ids[j]).length() == 0)
			{
				idList.append(ids[j]);
			}
			hash.insert(ids[j],pt);
		}

		i++;
	}
	
	//
	// Stage 2
	//

	for (i = 0; i < (int)(idList.length()); i++)
	{
		MPointArray points = hash.getPoints(idList[i]);

		// Don't bother with single samples
		if (points.length() <= 1)
		{
			continue;
		}

		// Add two additional points, so that the curve covers all sampled
		// values.
		//
		MPoint p1 = points[0]*2 - points[1];
		MPoint p2 = points[points.length()-1]*2 - points[points.length()-2];
		points.insert(p1,0);
		points.append(p2);

		// Uncomment to show information about the generated curves
		/*
		MGlobal::displayInfo( MString("ID ") + (int)(idList[i]) + " has " + (int)(points.length()) + " curve points.");
		for (int j = 0; j < (int)(points.length()); j++)
		{
			MGlobal::displayInfo(MString("(") + points[j][0] + MString(",") + points[j][1] + MString(",") + points[j][2] + MString(")"));
		}
		*/

		MDoubleArray knots;
		knots.insert(0.0,0);
		for (int j = 0; j < (int)(points.length()); j++)
		{
			knots.append((double)j);
		}
		knots.append(points.length()-1);

		MStatus status;
		MObject dummy;
		MFnNurbsCurve curve;
		curve.create(points,knots,3,MFnNurbsCurve::kOpen,false,false,dummy,&status);
		if (!status)
		{
			MGlobal::displayError("Failed to create nurbs curve.");
			return MS::kFailure;
		}
	}

	return MS::kSuccess;
}