コード例 #1
0
MStatus 
simpleFluidEmitter::fluidEmitter( 
	const MObject& fluidObject, 
	const MMatrix& worldMatrix, 
	int plugIndex 
)
//==============================================================================
//
//	Description:
//
//		Callback function that gets called once per frame by each fluid
//		into which this emitter is emitting.  Emits values directly into
//		the fluid object.  The MFnFluid object passed to this routine is
//		not pointing to a DAG object, it is pointing to an internal fluid
//		data structure that the fluid node is constructing, eventually to
//		be set into the fluid's output attribute.
//
//	Parameters:
//
//		fluid:			fluid into which we are emitting
//		worldMatrix:	object->world matrix for the fluid
//		plugIndex:		identifies which fluid connected to the emitter
//						we are emitting into
//
//	Returns:
//
//		MS::kSuccess 			if the method wishes to override the default
//								emitter behaviour
//		MS::kUnknownParameter 	if the method wishes to have the default
//								emitter behaviour execute after this routine
//								exits.
//
//	Notes:
//
//		The method first does some work common to all emitter types, then
//		calls one of 4 different methods to actually do the emission.
//		The methods are:
//
//			omniEmitter: 	omni-directional emitter from a point,
//							or from the vertices of an owner object.
//
//			volumeEmitter:	emits from the surface of an exact cube, sphere,
//							cone, cylinder, or torus.
//
//			surfaceEmitter:	emits from the surface of an owner object.
//
//==============================================================================
{

	//	make sure the fluid is valid.  If it isn't, return MS::kSuccess, indicating
	//	that no work needs to be done.  If we return a failure code, then the default
	//	fluid emitter code will try to run, which is pointless if the fluid is not
	//	valid.
	//
	MFnFluid fluid( fluidObject );
	if( fluid.object() != MObject::kNullObj )
	{
		return MS::kSuccess;
	}

	//	get a data block for the emitter, so we can get attribute values
	//
	MDataBlock block = forceCache();

	//	figure out the time interval for emission for the given fluid
	//
	double dTime = getDeltaTime( plugIndex, block ).as(MTime::kSeconds);
	if( dTime == 0.0 )
	{
		// shouldn't happen, but if the time interval is 0, then no fluid should
		// be emitted
		return MS::kSuccess;
	}

	// 	if currentTime <= startTime, return. The startTime is connected to 
	// 	the target fluid object.
	//
	MTime cTime = getCurrentTime( block );
	MTime sTime = getStartTime( plugIndex, block );

	//	if we are at or before the start time, reset the random number
	//	state to the appropriate seed value for the given fluid
	//
	if( cTime < sTime )
	{
		resetRandomState( plugIndex, block );
		return MS::kSuccess;
	}

	//	check to see if we need to emit anything into the target fluid.
	//	if the emission rate is 0, or if the fluid doesn't have a grid
	//	for one of the quantities, then we needn't do any emission
	//
	
	//	emission rates
	double density = fluidDensityEmission( block );	
	double heat = fluidHeatEmission( block );	
	double fuel = fluidFuelEmission( block );	
	bool doColor = fluidEmitColor( block );	

	//	fluid grid settings
	MFnFluid::FluidMethod densityMode, tempMode, fuelMode;
	MFnFluid::ColorMethod colorMode;
	MFnFluid::FluidGradient grad;
	MFnFluid::FalloffMethod falloffMode;
	fluid.getDensityMode( densityMode, grad );
	fluid.getTemperatureMode( tempMode, grad );
	fluid.getFuelMode( fuelMode, grad );
	fluid.getColorMode( colorMode );
	fluid.getFalloffMode( falloffMode );

	//	see if we need to emit density, heat, fuel, or color
	bool densityToEmit = (density != 0.0) && ((densityMode == MFnFluid::kDynamicGrid)||(densityMode == MFnFluid::kStaticGrid));
	bool heatToEmit = (heat != 0.0) && ((tempMode == MFnFluid::kDynamicGrid)||(tempMode == MFnFluid::kStaticGrid));
	bool fuelToEmit = (fuel != 0.0) && ((fuelMode == MFnFluid::kDynamicGrid)||(fuelMode == MFnFluid::kStaticGrid));
	bool colorToEmit = doColor && ((colorMode == MFnFluid::kDynamicColorGrid)||(colorMode == MFnFluid::kStaticColorGrid));
	bool falloffEmit = (falloffMode == MFnFluid::kStaticFalloffGrid);
	

	//	nothing to emit, do nothing
	//
	if( !densityToEmit && !heatToEmit && !fuelToEmit && !colorToEmit && !falloffEmit )
	{
		return MS::kSuccess;
	}

	//	get the dropoff rate for the fluid 
	//	
	double dropoff = fluidDropoff( block );

	//	modify the dropoff rate to account for fluids that have
	//	been scaled in worldspace - larger scales mean slower
	//	falloffs and vice versa
	//
	MTransformationMatrix xform( worldMatrix );
	double xformScale[3];
	xform.getScale( xformScale, MSpace::kWorld );
	double dropoffScale = sqrt( xformScale[0]*xformScale[0] + 
								xformScale[1]*xformScale[1] + 
								xformScale[2]*xformScale[2] );
	if( dropoffScale > 0.1 )
	{
		dropoff /= dropoffScale;
	}
	
	//	retrieve the current random state from the "randState" attribute, and
	//	store it in the member variable "randState".  We will use this member 
	//	value numerous times via the randgen() method.  Once we are done emitting,
	//	we will set the random state back into the attribute via setRandomState().
	//
	getRandomState( plugIndex, block );

	//	conversion value used to map user input emission rates into internal
	//	values.
	//
	double conversion = 0.01;

	MEmitterType emitterType = getEmitterType( block );
	switch( emitterType )
	{
		case kOmni:
			omniFluidEmitter( fluid, worldMatrix, plugIndex, block, dTime,
							  conversion, dropoff );
			break;

		case kVolume:
			volumeFluidEmitter( fluid, worldMatrix, plugIndex, block, dTime,
							    conversion, dropoff );
			break;
			
		case kSurface:
			surfaceFluidEmitter( fluid, worldMatrix, plugIndex, block, dTime,
							     conversion, dropoff );
			break;

		default:
			break;
	}

	//	store the random state back into the datablock
	//	
	setRandomState( plugIndex, block );
	return MS::kSuccess;
}
コード例 #2
0
ファイル: cacheTransform.cpp プロジェクト: goofoo/algae
//
// A very simple implementation of validAndSetValue().  No lock
// or limit checking on the rocking attribute is done in this method.
// If you wish to apply locks and limits to the rocking attribute, you
// would follow the approach taken in the rockingTransformCheck example.
// Meaning you would implement methods similar to:
//	* applyRotationLocks();
//	* applyRotationLimits();
//	* checkAndSetRotation();  
// but for the rocking attribute.  The method checkAndSetRotation()
// would be called below rather than updating the rocking attribute
// directly.
//
MStatus rockingTransformNode::validateAndSetValue(const MPlug& plug,
												const MDataHandle& handle,
												const MDGContext& context)
{
	MStatus status = MS::kSuccess;

	//	Make sure that there is something interesting to process.
	//
	if (plug.isNull())
		return MS::kFailure;

	MDataBlock block = forceCache(*(MDGContext *)&context);
	MDataHandle blockHandle = block.outputValue(plug, &status);
	ReturnOnError(status);
	
	MString cachename =  block.inputValue( acachename ).asString();
	MString meshname =  block.inputValue( ameshname ).asString();
	
/*	
	if ( plug == aRockInX )
	{
		// Update our new rock in x value
		double rockInX = handle.asDouble();
		blockHandle.set(rockInX);
		rockXValue = rockInX;
		
		// Update the custom transformation matrix to the
		// right rock value.  
		rockingTransformMatrix *ltm = getRockingTransformMatrix();
		if (ltm)
			ltm->setRockInX(rockXValue);
		else 
			MGlobal::displayError("Failed to get rock transform matrix");
			
		blockHandle.setClean();
		
		// Mark the matrix as dirty so that DG information
		// will update.
		dirtyMatrix();		
	}
*/	
	if ( plug == aframe )
	{
		// Update our new rock in x value
		double rockInX = handle.asDouble();
		blockHandle.set(rockInX);
		rockXValue = rockInX;
		
		// Update the custom transformation matrix to the
		// right rock value.  
		rockingTransformMatrix *ltm = getRockingTransformMatrix();
		if (ltm)
			ltm->setRockInX(rockXValue, cachename, meshname);
		else 
			MGlobal::displayError("Failed to get rock transform matrix");
			
		blockHandle.setClean();
		
		// Mark the matrix as dirty so that DG information
		// will update.
		dirtyMatrix();		
	}
	
	// Allow processing for other attributes
	return ParentClass::validateAndSetValue(plug, handle, context);
}