예제 #1
0
void dynExprField::apply(
MDataBlock         &block,
int                 receptorSize,
const MDoubleArray &magnitudeArray,
const MDoubleArray &magnitudeOwnerArray,
const MVectorArray &directionArray,
const MVectorArray &directionOwnerArray,
MVectorArray       &outputForce
)
//
//      Compute output force for each particle.  If there exists the 
//      corresponding per particle attribute, use the data passed from
//      particle shape (stored in magnitudeArray and directionArray).  
//      Otherwise, use the attribute value from the field.
//
{
        // get the default values
	MVector defaultDir = direction(block);
	double  defaultMag = magnitude(block);
	int magArraySize = magnitudeArray.length();
	int dirArraySize = directionArray.length();
	int magOwnerArraySize = magnitudeOwnerArray.length();
	int dirOwnerArraySize = directionOwnerArray.length();
	int numOfOwner = magOwnerArraySize;
	if( dirOwnerArraySize > numOfOwner )
	    numOfOwner = dirOwnerArraySize;

	double  magnitude = defaultMag;
	MVector direction = defaultDir;

	for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ ) {
	    if(receptorSize == magArraySize)
	        magnitude = magnitudeArray[ptIndex];
	    if(receptorSize == dirArraySize)
	        direction = directionArray[ptIndex];
	    if( numOfOwner > 0) {
	        for( int nthOwner = 0; nthOwner < numOfOwner; nthOwner++ ) {
		    if(magOwnerArraySize == numOfOwner)
		        magnitude = magnitudeOwnerArray[nthOwner];
		    if(dirOwnerArraySize == numOfOwner)
		        direction = directionOwnerArray[nthOwner];
		    outputForce.append( direction * magnitude );
		}
	    } else {
	        outputForce.append( direction * magnitude );
	    }
	}
}
MStatus metro_model_translator::create_shape( const m2033::mesh_ptr m )
{
	MFloatPointArray v;
	MVectorArray norm;
	MIntArray p;
	MIntArray idx;

	MFnTransform transform_fn;
	MObject transform_obj = transform_fn.create( MObject::kNullObj );
	transform_fn.setName( m->get_name().c_str() );

	m2033::mesh::vertices mv = m->get_vertices();
	m2033::mesh::indices mi = m->get_indices();
	m2033::mesh::texcoords mt = m->get_tex_coords();
	m2033::mesh::normals mn = m->get_normals();

	for( unsigned i = 0; i < mv.size(); i++ ) {
		v.append( -mv[i].x, mv[i].y, mv[i].z );
		norm.append( MVector( -mn[i].x, mn[i].y, mn[i].z ) );
	}

	for( unsigned i = 0; i < mi.size() / 3; i++ ) {
		idx.append( mi[i*3+2] );
		idx.append( mi[i*3+1] );
		idx.append( mi[i*3] );
		p.append( 3 );
	}

	MFloatArray u_values, v_values;
	for( unsigned i = 0; i < mt.size(); i++ ) {
		u_values.append( mt[i].x );
		v_values.append( -mt[i].y );
	}

	MFnMesh meshFn;
	MObject mesh = meshFn.create( v.length(), p.length(), v, p, idx, u_values, v_values, transform_obj );
	MString name = m->get_name().c_str();
	meshFn.setName( name + MString("_shape") );

	MStatus s = meshFn.assignUVs( p, idx, 0 );
	if( !s ) {
		return s;
	}

	s = meshFn.unlockVertexNormals( idx );
	if( !s ) {
		return s;
	}
	meshFn.setVertexNormals( norm, idx );

	MObject mat = create_material( m->get_texture_name(), &s );
	if( !s ) {
		return s;
	}
	MFnSet mat_fn(mat);
	mat_fn.addMember(mesh);

	return MS::kSuccess;
}
예제 #3
0
void rigidBodyNode::addContactInfo(const MString& contactObjectName, const MVector& point)
{
	MObject thisObject(thisMObject());

	// contactCount
	m_contactCount++;
	MPlug plugContactCount(thisObject, rigidBodyNode::oa_contactCount);
	plugContactCount.setValue(m_contactCount);
	
	// contactName
	MPlug plugContactName(thisObject, rigidBodyNode::oa_contactName);

	if ( !plugContactName.isNull() )
	{
		MObject strArrObject;
		plugContactName.getValue(strArrObject);

		MFnStringArrayData stringArrayData(strArrObject);
		MStringArray stringArray = stringArrayData.array();

		stringArray.append(contactObjectName);

		MFnStringArrayData newStringArrayData;
		MObject newStrArrObject = newStringArrayData.create(stringArray);
	
		plugContactName.setValue(newStrArrObject);
	}

	// contactPosition
	MPlug plugContactPosition(thisObject, rigidBodyNode::oa_contactPosition);

	if ( !plugContactPosition.isNull() )
	{
		MObject arrObject;
		plugContactPosition.getValue(arrObject);	

		MFnVectorArrayData vectorArrayData(arrObject);
		MVectorArray vectorArray = vectorArrayData.array();

		vectorArray.append(point);
	
		MFnVectorArrayData newVectorArrayData;
		MObject newArrObject = newVectorArrayData.create(vectorArray);	
	
		plugContactPosition.setValue(newArrObject);
	}
}
예제 #4
0
void CylinderMesh::transform(MPointArray& points, MVectorArray& normals)
{
    MVector forward = mEnd - mStart;
    double s = forward.length();
    forward.normalize();

    MVector left = MVector(0,0,1)^forward;
    MVector up;
    if (left.length() < 0.0001)
    {
        up = forward^MVector(0,1,0);
        left = up^forward;
    }
    else
    {
        up = forward^left;
    }

    MMatrix mat;
    mat[0][0] = forward[0]; mat[0][1] = left[0]; mat[0][2] = up[0]; mat[0][3] = 0;
    mat[1][0] = forward[1];   mat[1][1] = left[1]; mat[1][2] = up[1]; mat[1][3] = 0;
    mat[2][0] = forward[2];   mat[2][1] = left[2]; mat[2][2] = up[2]; mat[2][3] = 0;
    mat[3][0] = 0;            mat[3][1] = 0;       mat[3][2] = 0;     mat[3][3] = 1;
    mat = mat.transpose();

    for (int i = 0; i < gPoints.length(); i++)
    {
        MPoint p = gPoints[i];
        p.x = p.x * s; // scale
        p = p * mat + mStart; // transform
        points.append(p);

        MVector n = gNormals[i] * mat;
        normals.append(n);
    }
}
예제 #5
0
void 
simpleFluidEmitter::omniFluidEmitter(
	MFnFluid& 		fluid,
	const MMatrix&	fluidWorldMatrix,
	int 			plugIndex,
	MDataBlock& 	block,
	double 			dt,
	double			conversion,
	double			dropoff
)
//==============================================================================
//
//	Method:	
//
//		simpleFluidEmitter::omniFluidEmitter
//
//	Description:
//
//		Emits fluid from a point, or from a set of object control points.
//
//	Parameters:
//
//		fluid:				fluid into which we are emitting
//		fluidWorldMatrix:	object->world matrix for the fluid
//		plugIndex:			identifies which fluid connected to the emitter
//							we are emitting into
//		block:				datablock for the emitter, to retrieve attribute
//							values
//		dt:					time delta for this frame
//		conversion:			mapping from UI emission rates to internal units
//		dropoff:			specifies how much emission rate drops off as
//							we move away from each emission point.
//
//	Notes:
//
//		If no owner object is present for the emitter, we simply emit from
//		the emitter position.  If an owner object is present, then we emit
//		from each control point of that object in an identical fashion.
//		
//		To associate an owner object with an emitter, use the
//		addDynamic MEL command, e.g. "addDynamic simpleFluidEmitter1 pPlane1".
//
//==============================================================================
{
	//	find the positions that we need to emit from
	//
	MVectorArray emitterPositions;
	
	//	first, try to get them from an owner object, which will have its
	//	"ownerPositionData" attribute feeding into the emitter.  These
	//	values are in worldspace
	//
	bool gotOwnerPositions = false;
	MObject ownerShape = getOwnerShape();
	if( ownerShape != MObject::kNullObj )
	{
		MStatus status;
		MDataHandle hOwnerPos = block.inputValue( mOwnerPosData, &status );
		if( status == MS::kSuccess )
		{
			MObject dOwnerPos = hOwnerPos.data();
			MFnVectorArrayData fnOwnerPos( dOwnerPos );
			MVectorArray posArray = fnOwnerPos.array( &status );
			if( status == MS::kSuccess )
			{
				// assign vectors from block to ownerPosArray.
				//
				for( unsigned int i = 0; i < posArray.length(); i ++ )
				{
					emitterPositions.append( posArray[i] );
				}
				
				gotOwnerPositions = true;
			}
		}
	}
	
	//	there was no owner object, so we just use the emitter position for
	//	emission.
	//
	if( !gotOwnerPositions )
	{
		MPoint emitterPos = getWorldPosition();
		emitterPositions.append( emitterPos );
	}

	//	get emission rates for density, fuel, heat, and emission color
	//	
	double densityEmit = fluidDensityEmission( block );
	double fuelEmit = fluidFuelEmission( block );
	double heatEmit = fluidHeatEmission( block );
	bool doEmitColor = fluidEmitColor( block );
	MColor emitColor = fluidColor( block );

	//	rate modulation based on frame time, user value conversion factor, and
	//	standard emitter "rate" value (not actually exposed in most fluid
	//	emitters, but there anyway).
	//
	double theRate = getRate(block) * dt * conversion;

	//	get voxel dimensions and sizes (object space)
	//
	double size[3];
	unsigned int res[3];
	fluid.getDimensions( size[0], size[1], size[2] );
	fluid.getResolution( res[0], res[1], res[2] );
	
	//	voxel sizes
	double dx = size[0] / res[0];
	double dy = size[1] / res[1];
	double dz = size[2] / res[2];
	
	//	voxel centers
	double Ox = -size[0]/2;
	double Oy = -size[1]/2;
	double Oz = -size[2]/2;	

	//	emission will only happen for voxels whose centers lie within
	//	"minDist" and "maxDist" of an emitter position
	//
	double minDist = getMinDistance( block );
	double maxDist = getMaxDistance( block );

	//	bump up the min/max distance values so that they
	//	are both > 0, and there is at least about a half
	//	voxel between the min and max values, to prevent aliasing
	//	artifacts caused by emitters missing most voxel centers
	//
	MTransformationMatrix fluidXform( fluidWorldMatrix );
	double fluidScale[3];
	fluidXform.getScale( fluidScale, MSpace::kWorld );
	
	//	compute smallest voxel diagonal length
	double wsX =  fabs(fluidScale[0]*dx);
	double wsY = fabs(fluidScale[1]*dy);
	double wsZ = fabs(fluidScale[2]*dz);
	double wsMin = MIN( MIN( wsX, wsY), wsZ );
	double wsMax = MAX( MAX( wsX, wsY), wsZ );
	double wsDiag  = wsMin * sqrt(3.0);

	//	make sure emission range is bigger than 0.5 voxels
	if ( maxDist <= minDist || maxDist <= (wsDiag/2.0) ) {
		if ( minDist < 0 ) minDist = 0;

		maxDist = minDist + wsDiag/2.0;
		dropoff = 0;
	}

	//	Now, it's time to actually emit into the fluid:
	//	
	//	foreach emitter point
	//		foreach voxel
	//			- select some points in the voxel
	//			- compute a dropoff function from the emitter point
	//			- emit an appropriate amount of fluid into the voxel
	//
	//	Since we've already expanded the min/max distances to cover
	//	the smallest voxel dimension, we should only need 1 sample per
	//	voxel, unless the voxels are highly non-square.  We increase the
	//	number of samples in these cases.
	//
	//	If the "jitter" flag is enabled, we jitter each sample position,
	//	using the rangen() function, which keeps track of independent 
	//	random states for each fluid, to make sure that results are
	//	repeatable for multiple simulation runs.
	//	

	// basic sample count
	int numSamples = 1;

	// increase samples if necessary for non-square voxels
	if(wsMin >.00001) 
	{
		numSamples = (int)(wsMax/wsMin + .5);
		if(numSamples > 8) 
			numSamples = 8;
		if(numSamples < 1)
			numSamples = 1;
	}
	
	bool jitter =  fluidJitter(block);
	if( !jitter )
	{
		//	I don't have a good uniform sample generator for an 
		//	arbitrary number of samples.  It would be a good idea to use
		//	one here.  For now, just use 1 sample for the non-jittered case.
		//
		numSamples = 1;
	}

	for( unsigned int p = 0; p < emitterPositions.length(); p++ )
	{
		MPoint emitterWorldPos = emitterPositions[p];

		//	loop through all voxels, looking for ones that lie at least
		//	partially within the dropoff field around this emitter point
		//
		for( unsigned int i = 0; i < res[0]; i++ )
		{
			double x = Ox + i*dx;
			
			for( unsigned int j = 0; j < res[1]; j++ )
			{
				double y = Oy + j*dy;
				
				for( unsigned int k = 0; k < res[2]; k++ )
				{
					double z = Oz + k*dz;
	
					int si;
					for( si = 0; si < numSamples; si++ )
					{
						//	compute sample point (fluid object space)
						//
						double rx, ry, rz;
						if( jitter )
						{
							rx = x + randgen()*dx;
							ry = y + randgen()*dy;
							rz = z + randgen()*dz;
						}
						else
						{
							rx = x + 0.5*dx;
							ry = y + 0.5*dy;
							rz = z + 0.5*dz;
						}

						//	compute distance from sample to emitter point
						//	
						MPoint point( rx, ry, rz );
						point *= fluidWorldMatrix;
						MVector diff = point - emitterWorldPos;
						double distSquared = diff * diff;
						double dist = diff.length();
					
						//	discard if outside min/max range
						//
						if( (dist < minDist) || (dist > maxDist) )
						{
							continue;
						}
						
						//	drop off the emission rate according to the falloff
						//	parameter, and divide to accound for multiple samples
						//	in the voxel
						//
						double distDrop = dropoff * distSquared;
						double newVal = theRate * exp( -distDrop ) / (double)numSamples;

						//	emit density/heat/fuel/color into the current voxel
						//
						if( newVal != 0 )
						{
							fluid.emitIntoArrays( (float) newVal, i, j, k, (float)densityEmit, (float)heatEmit, (float)fuelEmit, doEmitColor, emitColor );
						}

						float *fArray = fluid.falloff();
						if( fArray != NULL )
						{
							MPoint midPoint( x+0.5*dx, y+0.5*dy, z+0.5*dz );
							midPoint.x *= 0.2;
							midPoint.y *= 0.2;
							midPoint.z *= 0.2;

							float fdist = (float) sqrt( midPoint.x*midPoint.x + midPoint.y*midPoint.y + midPoint.z*midPoint.z );
							fdist /= sqrtf(3.0f);
							fArray[fluid.index(i,j,k)] = 1.0f-fdist;
						}
					}
				}
			}
		}
	}
}
MStatus DA_GridGenerator::compute(const MPlug &plug, MDataBlock &data)
{
    MStatus stat;
    if (plug != aOutDynamicArray)
        return MS::kFailure;

    //
    // Control Inputs
    //
    double dWidth = data.inputValue(aWidth).asDouble();
    double dHeight = data.inputValue(aHeight).asDouble();

    int iResolutionX = data.inputValue(aResolutionX).asInt();
    int iResolutionY = data.inputValue(aResolutionY).asInt();

    short ePattern = data.inputValue(aPattern).asShort();

    // Create output
    MFnArrayAttrsData fnOutDynamicArray;
    fnOutDynamicArray.create();

    // Create position data
    MVectorArray outPositionPP = fnOutDynamicArray.vectorArray("position");

    //
    // Create grid
    //
    double xOffset = dWidth / ((double)iResolutionX - 1);
    double yOffset = dHeight / ((double)iResolutionY - 1);

    // Keep brick pattern in range
    if (ePattern == 1)
        xOffset -= (xOffset/2) / double(iResolutionX);
    if (ePattern == 2)
        yOffset -= (yOffset/2) / double(iResolutionY);

    // Generate grid
    for(int i = 0; i < iResolutionX; i++)
    {
        for(int j = 0; j < iResolutionY; j++)
        {
            MVector position;
            position.x = -dWidth / 2;
            position.y = 0;
            position.z = -dHeight / 2;

            // Pattern offset
            if (ePattern == 1)
                position.x += (xOffset/2) * double(j % 2);
            if (ePattern == 2)
                position.z += (yOffset/2) * double(i % 2);

            position.x += xOffset * i;
            position.z += yOffset * j;

            outPositionPP.append( position );
        }
    }


    //
    // Set output data
    //
    MDataHandle outArray = data.outputValue(aOutDynamicArray);
    outArray.set(fnOutDynamicArray.object());

    // Set plug to clean
    data.setClean(aOutDynamicArray);

    // Done
    return MS::kSuccess;
}
예제 #7
0
//
// Main routine
///////////////////////////////////////////////////////////////////////////////
MStatus particleSystemInfoCmd::doIt( const MArgList& args )
{
	MStatus stat = parseArgs( args );
	if( stat != MS::kSuccess ) return stat;

	if( particleNode.isNull() ) {
	        MObject parent;
		MFnParticleSystem dummy;
		particleNode = dummy.create(&stat);
		CHECKRESULT(stat,"MFnParticleSystem::create(status) failed!");

		MFnParticleSystem ps( particleNode, &stat );
		CHECKRESULT(stat,"MFnParticleSystem::MFnParticleSystem(MObject,status) failed!");

		MPointArray posArray;
		posArray.append(MPoint(-5,  5, 0));
		posArray.append(MPoint(-5, 10, 0));

		MVectorArray velArray;
		velArray.append(MPoint(1, 1, 0));
		velArray.append(MPoint(1, 1, 0));
		stat = ps.emit(posArray, velArray);
		CHECKRESULT(stat,"MFnParticleSystem::emit(posArray,velArray) failed!");

		stat = ps.emit(MPoint(5,  5, 0));
		CHECKRESULT(stat,"MFnParticleSystem::emit(pos) failed!");
		stat = ps.emit(MPoint(5, 10, 0));
		CHECKRESULT(stat,"MFnParticleSystem::emit(pos) failed!");

		stat = ps.saveInitialState();
		CHECKRESULT(stat,"MFnParticleSystem::saveInitialState() failed!");

		MVectorArray accArray;
		accArray.setLength(4);
		for( unsigned int i=0; i<accArray.length(); i++ )
		{
		        MVector& acc = accArray[i];
			acc.x = acc.y = acc.z = 3.0;
		}
		MString accName("acceleration");
		ps.setPerParticleAttribute( accName, accArray, &stat );
		CHECKRESULT(stat,"MFnParticleSystem::setPerParticleAttribute(vectorArray) failed!");
	} 

	MFnParticleSystem ps( particleNode, &stat );
	CHECKRESULT(stat,"MFnParticleSystem::MFnParticleSystem(MObject,status) failed!");

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

	const MString name = ps.particleName();
	const MFnParticleSystem::RenderType psType = ps.renderType();
	const unsigned int count = ps.count();

	const char* typeString = NULL;
	switch( psType )
	{
	case MFnParticleSystem::kCloud:
		typeString = "Cloud";
		break;
	case MFnParticleSystem::kTube:
		typeString = "Tube system";
		break;
	case MFnParticleSystem::kBlobby:
		typeString = "Blobby";
		break;
	case MFnParticleSystem::kMultiPoint:
		typeString = "MultiPoint";
		break;
	case MFnParticleSystem::kMultiStreak:
		typeString = "MultiStreak";
		break;
	case MFnParticleSystem::kNumeric:
		typeString = "Numeric";
		break;
	case MFnParticleSystem::kPoints:
		typeString = "Points";
		break;
	case MFnParticleSystem::kSpheres:
		typeString = "Spheres";
		break;
	case MFnParticleSystem::kSprites:
		typeString = "Sprites";
		break;
	case MFnParticleSystem::kStreak:
		typeString = "Streak";
		break;
	default:
		typeString = "Particle system";
		assert( false );
		break;
	}

	char buffer[256];

	sprintf( buffer, "%s \"%s\" has %u primitives.", typeString, name.asChar(), count );
	MGlobal::displayInfo( buffer );

	unsigned i;

	MIntArray ids;
	ps.particleIds( ids );

	sprintf( buffer, "count : %u ", count );
	MGlobal::displayInfo( buffer );
	sprintf( buffer, "%u ids.", ids.length() );
	MGlobal::displayInfo( buffer );

	assert( ids.length() == count );
	for( i=0; i<ids.length(); i++ )
	{
		sprintf( buffer, "id %d  ", ids[i] );
		MGlobal::displayInfo( buffer );
	}

	MVectorArray positions;
	ps.position( positions );
	assert( positions.length() == count );
	for( i=0; i<positions.length(); i++ )
	{
		MVector& p = positions[i];
		sprintf( buffer, "pos %f %f %f  ", p[0], p[1], p[2] );
		MGlobal::displayInfo( buffer );
	}

	MVectorArray vels;
	ps.velocity( vels );
	assert( vels.length() == count );
	for( i=0; i<vels.length(); i++ )
	{
		const MVector& v = vels[i];
		sprintf( buffer, "vel %f %f %f  ", v[0], v[1], v[2] );
		MGlobal::displayInfo( buffer );
	}

	MVectorArray accs;
	ps.acceleration( accs );
	assert( accs.length() == count );
	for( i=0; i<accs.length(); i++ )
	{
		const MVector& a = accs[i];
		sprintf( buffer, "acc %f %f %f  ", a[0], a[1], a[2] );
		MGlobal::displayInfo( buffer );
	}

	bool flag = ps.isDeformedParticleShape(&stat);
	CHECKRESULT(stat,"MFnParticleSystem::isDeformedParticleShape() failed!");
	if( flag ) {
	        MObject obj = ps.originalParticleShape(&stat);
		CHECKRESULT(stat,"MFnParticleSystem::originalParticleShape() failed!");
		if( obj != MObject::kNullObj ) {
		        MFnParticleSystem ps( obj );
			sprintf( buffer, "original particle shape : %s ", ps.particleName().asChar() );
			MGlobal::displayInfo( buffer );
		}
	}

	flag = ps.isDeformedParticleShape(&stat);
	CHECKRESULT(stat,"MFnParticleSystem::isDeformedParticleShape() failed!");
	if( !flag ) {
	        MObject obj = ps.deformedParticleShape(&stat);
		CHECKRESULT(stat,"MFnParticleSystem::deformedParticleShape() failed!");
		if( obj != MObject::kNullObj ) {
		        MFnParticleSystem ps( obj );
			sprintf( buffer, "deformed particle shape : %s ", ps.particleName().asChar() );
			MGlobal::displayInfo( buffer );
		}
	}

	if( ids.length() == positions.length() &&
	    ids.length() == vels.length()      &&
	    ids.length() == accs.length()       ) { 
	        setResult( int(ids.length()) );
	} else {
	        setResult( int(-1) );
	}

	return MS::kSuccess;
}
예제 #8
0
MStatus sweptEmitter::compute(const MPlug& plug, MDataBlock& block)
//
//	Descriptions:
//		Call emit emit method to generate new particles.
//
{
	MStatus status;

	// Determine if we are requesting the output plug for this emitter node.
	//
	if( !(plug == mOutput) )
        return( MS::kUnknownParameter );

	// Get the logical index of the element this plug refers to,
	// because the node can be emitting particles into more 
    // than one particle shape.
	//
	int multiIndex = plug.logicalIndex( &status );
	McheckErr(status, "ERROR in plug.logicalIndex.\n");

	// Get output data arrays (position, velocity, or parentId)
	// that the particle shape is holding from the previous frame.
	//
	MArrayDataHandle hOutArray = block.outputArrayValue(mOutput, &status);
	McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n");

	// Create a builder to aid in the array construction efficiently.
	//
	MArrayDataBuilder bOutArray = hOutArray.builder( &status );
	McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n");

	// Get the appropriate data array that is being currently evaluated.
	//
	MDataHandle hOut = bOutArray.addElement(multiIndex, &status);
	McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n");

    // Get the data and apply the function set.
    //
    MFnArrayAttrsData fnOutput;
    MObject dOutput = fnOutput.create ( &status );
    McheckErr(status, "ERROR in fnOutput.create.\n");

	// Check if the particle object has reached it's maximum,
	// hence is full. If it is full then just return with zero particles.
	//
	bool beenFull = isFullValue( multiIndex, block );
	if( beenFull )
	{
		return( MS::kSuccess );
	}

	// Get deltaTime, currentTime and startTime.
	// If deltaTime <= 0.0, or currentTime <= startTime,
	// do not emit new pariticles and return.
	//
	MTime cT = currentTimeValue( block );
	MTime sT = startTimeValue( multiIndex, block );
	MTime dT = deltaTimeValue( multiIndex, block );
	if( (cT <= sT) || (dT <= 0.0) )
	{
		// We do not emit particles before the start time, 
		// and do not emit particles when moving backwards in time.
		// 

		// This code is necessary primarily the first time to 
		// establish the new data arrays allocated, and since we have 
		// already set the data array to length zero it does 
		// not generate any new particles.
		// 
		hOut.set( dOutput );
		block.setClean( plug );

		return( MS::kSuccess );
	}

	// Get speed, direction vector, and inheritFactor attributes.
	//
	double speed = speedValue( block );
	MVector dirV = directionVector( block );
	double inheritFactor = inheritFactorValue( multiIndex, block );

	// Get the position and velocity arrays to append new particle data.
	//
	MVectorArray fnOutPos = fnOutput.vectorArray("position", &status);
	MVectorArray fnOutVel = fnOutput.vectorArray("velocity", &status);

	// Convert deltaTime into seconds.
	//
	double dt = dT.as( MTime::kSeconds );
	
	// Apply rotation to the direction vector
	MVector rotatedV = useRotation ( dirV );


	// position,
	MVectorArray inPosAry;
	// velocity
	MVectorArray inVelAry;
	// emission rate
	MIntArray emitCountPP;


	// Get the swept geometry data
	//
	MObject thisObj = this->thisMObject();
	MPlug sweptPlug( thisObj, mSweptGeometry );

	if ( sweptPlug.isConnected() ) 
	{
		MDataHandle sweptHandle = block.inputValue( mSweptGeometry );
		// MObject sweptData = sweptHandle.asSweptGeometry();
		MObject sweptData = sweptHandle.data();
		MFnDynSweptGeometryData fnSweptData( sweptData );


		// Curve emission
		//
		if (fnSweptData.lineCount() > 0) {
			int numLines = fnSweptData.lineCount();
		
			for ( int i=0; i<numLines; i++ )
			{
				inPosAry.clear();
				inVelAry.clear();
				emitCountPP.clear();

				MDynSweptLine line = fnSweptData.sweptLine( i );

				// ... process current line ...
				MVector p1 = line.vertex( 0 );
				MVector p2 = line.vertex( 1 );

				inPosAry.append( p1 );
				inPosAry.append( p2 );

				inVelAry.append( MVector( 0,0,0 ) );
				inVelAry.append( MVector( 0,0,0 ) );

				// emit Rate for two points on line
				emitCountPP.clear();
				status = emitCountPerPoint( plug, block, 2, emitCountPP );

				emit( inPosAry, inVelAry, emitCountPP,
					dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel );

			}
		}

		// Surface emission (nurb or polygon)
		//
		if (fnSweptData.triangleCount() > 0) {
			int numTriangles = fnSweptData.triangleCount();
		
			for ( int i=0; i<numTriangles; i++ )
			{
				inPosAry.clear();
				inVelAry.clear();
				emitCountPP.clear();

				MDynSweptTriangle tri = fnSweptData.sweptTriangle( i );

				// ... process current triangle ...
				MVector p1 = tri.vertex( 0 );
				MVector p2 = tri.vertex( 1 );
				MVector p3 = tri.vertex( 2 );

				MVector center = p1 + p2 + p3;
				center /= 3.0;

				inPosAry.append( center );

				inVelAry.append( MVector( 0,0,0 ) );

				// emit Rate for two points on line
				emitCountPP.clear();
				status = emitCountPerPoint( plug, block, 1, emitCountPP );

				emit( inPosAry, inVelAry, emitCountPP,
					dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel );

			}
		}
	}

	// Update the data block with new dOutput and set plug clean.
	//
	hOut.set( dOutput );
	block.setClean( plug );

	return( MS::kSuccess );
}
예제 #9
0
void sweptEmitter::emit
	(
		const MVectorArray &inPosAry,	// points where new particles from
		const MVectorArray &inVelAry,	// initial velocity of new particles
		const MIntArray &emitCountPP,	// # of new particles per point
		double dt,						// elapsed time
		double speed,					// speed factor
		double inheritFactor,			// for inherit velocity
		MVector dirV,					// emit direction
		MVectorArray &outPosAry,		// holding new particles position
		MVectorArray &outVelAry			// holding new particles velocity
	)
//
//	Descriptions:
//
{
	// check the length of input arrays.
	//
	int posLength = inPosAry.length();
	int velLength = inVelAry.length();
	int countLength = emitCountPP.length();
	if( (posLength != velLength) || (posLength != countLength) )
		return;

	// Compute total emit count.
	//
	int index;
	int totalCount = 0;
	for( index = 0; index < countLength; index ++ )
		totalCount += emitCountPP[index];

	if( totalCount <= 0 )
		return;

	// Map direction vector into world space and normalize it.
	//
	dirV.normalize();

	// Start emission.
	//
	int emitCount;
	MVector newPos, newVel;
	MVector prePos, sPos, sVel;
	for( index = 0; index < posLength; index++ )
	{
		emitCount = emitCountPP[index];
		if( emitCount <= 0 )
			continue;

		sPos = inPosAry[index];
		sVel = inVelAry[index];
		prePos = sPos - sVel * dt;

		for( int i = 0; i < emitCount; i++ )
		{
			double alpha = ( (double)i + drand48() ) / (double)emitCount;
			newPos = (1 - alpha) * prePos + alpha * sPos;
			newVel = dirV * speed;

			newPos += newVel * ( dt * (1 - alpha) );
			newVel += sVel * inheritFactor;

			// Add new data into output arrays.
			//
			outPosAry.append( newPos );
			outVelAry.append( newVel );
		}
	}

}
예제 #10
0
//apply fields in the scene from the rigid body
void dSolverNode::applyFields(MPlugArray &rbConnections, float dt)
{
    MVectorArray position;
    MVectorArray velocity;
    MDoubleArray mass;

    std::vector<rigid_body_t*> rigid_bodies;
    //gather active rigid bodies
    for(size_t i = 0; i < rbConnections.length(); ++i) {
        MObject node = rbConnections[i].node();
        MFnDagNode fnDagNode(node);
        if(fnDagNode.typeId() == rigidBodyNode::typeId) {
            rigidBodyNode *rbNode = static_cast<rigidBodyNode*>(fnDagNode.userNode()); 
            rigid_body_t::pointer rb = rbNode->rigid_body();

            MPlug plgMass(node, rigidBodyNode::ia_mass);
            float mass = 0.f;
            plgMass.getValue(mass);
			bool active = (mass>0.f);
            if(active) {
                rigid_bodies.push_back(rb.get());
            }
        } else if(fnDagNode.typeId() == rigidBodyArrayNode::typeId) {
            rigidBodyArrayNode *rbNode = static_cast<rigidBodyArrayNode*>(fnDagNode.userNode()); 
            std::vector<rigid_body_t::pointer>& rbs = rbNode->rigid_bodies();

            MPlug plgMass(node, rigidBodyArrayNode::ia_mass);
            float mass = 0.f;
			plgMass.getValue(mass);
			bool active = (mass>0.f);
            if(active) {
                for(size_t j = 0; j < rbs.size(); ++j) {
                    rigid_bodies.push_back(rbs[j].get());
                }
            }
        }
    }

    //clear forces and get the properties needed for field computation    
    for(size_t i = 0; i < rigid_bodies.size(); ++i) {
        rigid_bodies[i]->clear_forces();
        vec3f pos, vel;
        quatf rot;
        rigid_bodies[i]->get_transform(pos, rot); 
        rigid_bodies[i]->get_linear_velocity(vel);
        position.append(MVector(pos[0], pos[1], pos[2]));
        velocity.append(MVector(vel[0], vel[1], vel[2]));
        //TODO
        mass.append(1.0);
        //
    }

    //apply the fields to the rigid bodies
    MVectorArray force;
    for(MItDag it(MItDag::kDepthFirst, MFn::kField); !it.isDone(); it.next()) {
        MFnField fnField(it.item());
        fnField.getForceAtPoint(position, velocity, mass, force, dt);
        for(size_t i = 0; i < rigid_bodies.size(); ++i) {
            rigid_bodies[i]->apply_central_force(vec3f(force[i].x, force[i].y, force[i].z));
        }
    }
}