#include <maya/MIOStream.h>
#include <math.h>
#include <stdlib.h>
#include "simpleFluidEmitter.h"
#include <maya/MVectorArray.h>
#include <maya/MDoubleArray.h>
#include <maya/MIntArray.h>
#include <maya/MMatrix.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnVectorArrayData.h>
#include <maya/MFnDoubleArrayData.h>
#include <maya/MFnArrayAttrsData.h>
#include <maya/MFnMatrixData.h>
#include <maya/MDagPath.h>
#include <maya/MMatrix.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MFnDynSweptGeometryData.h>
#include <maya/MDynSweptTriangle.h>
#include <maya/MPlugArray.h>
MTypeId simpleFluidEmitter::id( 0x81020 );
simpleFluidEmitter::simpleFluidEmitter()
{
}
simpleFluidEmitter::~simpleFluidEmitter()
{
}
void *simpleFluidEmitter::creator()
{
return new simpleFluidEmitter;
}
MStatus simpleFluidEmitter::initialize()
{
return( MS::kSuccess );
}
{
{
return MS::kUnknownParameter;
}
else
{
return MS::kUnknownParameter;
}
}
simpleFluidEmitter::fluidEmitter(
int plugIndex
)
{
{
return MS::kSuccess;
}
if( dTime == 0.0 )
{
return MS::kSuccess;
}
MTime cTime = getCurrentTime( block );
MTime sTime = getStartTime( plugIndex, block );
if( cTime < sTime )
{
resetRandomState( plugIndex, block );
return MS::kSuccess;
}
double density = fluidDensityEmission( block );
double heat = fluidHeatEmission( block );
double fuel = fluidFuelEmission( block );
bool doColor = fluidEmitColor( block );
fluid.getDensityMode( densityMode, grad );
fluid.getTemperatureMode( tempMode, grad );
fluid.getFuelMode( fuelMode, grad );
fluid.getColorMode( colorMode );
fluid.getFalloffMode( falloffMode );
if( !densityToEmit && !heatToEmit && !fuelToEmit && !colorToEmit && !falloffEmit )
{
return MS::kSuccess;
}
double dropoff = fluidDropoff( block );
double xformScale[3];
double dropoffScale = sqrt( xformScale[0]*xformScale[0] +
xformScale[1]*xformScale[1] +
xformScale[2]*xformScale[2] );
if( dropoffScale > 0.1 )
{
dropoff /= dropoffScale;
}
getRandomState( plugIndex, block );
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;
}
setRandomState( plugIndex, block );
return MS::kSuccess;
}
#ifdef MIN
#undef MIN
#endif
#ifdef MAX
#undef MAX
#endif
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
void
simpleFluidEmitter::omniFluidEmitter(
int plugIndex,
double dt,
double conversion,
double dropoff
)
{
bool gotOwnerPositions = false;
MObject ownerShape = getOwnerShape();
{
if( status == MS::kSuccess )
{
if( status == MS::kSuccess )
{
for(
unsigned int i = 0; i < posArray.
length(); i ++ )
{
emitterPositions.
append( posArray[i] );
}
gotOwnerPositions = true;
}
}
}
if( !gotOwnerPositions )
{
MPoint emitterPos = getWorldPosition();
emitterPositions.
append( emitterPos );
}
double densityEmit = fluidDensityEmission( block );
double fuelEmit = fluidFuelEmission( block );
double heatEmit = fluidHeatEmission( block );
bool doEmitColor = fluidEmitColor( block );
MColor emitColor = fluidColor( block );
double theRate = getRate(block) * dt * conversion;
double size[3];
unsigned int res[3];
double dx = size[0] / res[0];
double dy = size[1] / res[1];
double dz = size[2] / res[2];
double Ox = -size[0]/2;
double Oy = -size[1]/2;
double Oz = -size[2]/2;
double minDist = getMinDistance( block );
double maxDist = getMaxDistance( block );
double fluidScale[3];
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);
if ( maxDist <= minDist || maxDist <= (wsDiag/2.0) ) {
if ( minDist < 0 ) minDist = 0;
maxDist = minDist + wsDiag/2.0;
dropoff = 0;
}
int numSamples = 1;
if(wsMin >.00001)
{
numSamples = (int)(wsMax/wsMin + .5);
if(numSamples > 8)
numSamples = 8;
if(numSamples < 1)
numSamples = 1;
}
bool jitter = fluidJitter(block);
if( !jitter )
{
numSamples = 1;
}
for(
unsigned int p = 0; p < emitterPositions.
length(); p++ )
{
MPoint emitterWorldPos = emitterPositions[p];
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++ )
{
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;
}
point *= fluidWorldMatrix;
MVector diff = point - emitterWorldPos;
double distSquared = diff * diff;
if( (dist < minDist) || (dist > maxDist) )
{
continue;
}
double distDrop = dropoff * distSquared;
double newVal = theRate * exp( -distDrop ) / (double)numSamples;
if( newVal != 0 )
{
fluid.
emitIntoArrays( (
float) newVal, i, j, k, (
float)densityEmit, (
float)heatEmit, (
float)fuelEmit, doEmitColor, emitColor );
}
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;
}
}
}
}
}
}
}
void
simpleFluidEmitter::volumeFluidEmitter(
int plugIndex,
double dt,
double conversion,
double dropoff
)
{
MPoint emitterPos = getWorldPosition();
MMatrix emitterWorldMatrix = getWorldMatrix();
double densityEmit = fluidDensityEmission( block );
double fuelEmit = fluidFuelEmission( block );
double heatEmit = fluidHeatEmission( block );
bool doEmitColor = fluidEmitColor( block );
MColor emitColor = fluidColor( block );
double theRate = getRate(block) * dt * conversion;
if( !volumePrimitiveBoundingBox( bbox ) )
{
return;
}
bool autoResize = false;
bool resizeToEmitter = false;
MPlug fnPlug = nodeFn.findPlug(
"emissionFunction");
if (connections.
length() > 0) {
MObject sourceNode = connections[0].node();
autoResize = fluidFn.isAutoResize();
resizeToEmitter = fluidFn.isResizeToEmitter();
if(autoResize && resizeToEmitter) {
fluidFn.expandToInclude(lowCorner, highCorner);
}
}
}
}
if(autoResize && resizeToEmitter) {
}
double size[3];
unsigned int res[3];
double dx = size[0] / res[0];
double dy = size[1] / res[1];
double dz = size[2] / res[2];
double Ox = -size[0]/2;
double Oy = -size[1]/2;
double Oz = -size[2]/2;
int3 lowCoords;
int3 highCoords;
int i;
for ( i = 0; i < 3; i++ )
{
if ( lowCoords[i] < 0 ) {
lowCoords[i] = 0;
} else if ( lowCoords[i] > ((int)res[i])-1 ) {
lowCoords[i] = ((int)res[i])-1;
}
if ( highCoords[i] < 0 ) {
highCoords[i] = 0;
} else if ( highCoords[i] > ((int)res[i])-1 ) {
highCoords[i] = ((int)res[i])-1;
}
}
double emitterVoxelSize[3];
emitterVoxelSize[0] = (highCorner[0]-lowCorner[0])/dx;
emitterVoxelSize[1] = (highCorner[1]-lowCorner[1])/dy;
emitterVoxelSize[2] = (highCorner[2]-lowCorner[2])/dz;
double minVoxelSize = MIN(emitterVoxelSize[0],MIN(emitterVoxelSize[1],emitterVoxelSize[2]));
if( minVoxelSize < 1.0 )
{
minVoxelSize = 1.0;
}
int maxSamples = 8;
int numSamples = (int)(8.0/(minVoxelSize*minVoxelSize*minVoxelSize) + 0.5);
if( numSamples < 1 ) numSamples = 1;
if( numSamples > maxSamples ) numSamples = maxSamples;
bool jitter = fluidJitter(block);
if( !jitter )
{
numSamples = 1;
}
for( i = lowCoords[0]; i <= highCoords[0]; i++ )
{
double x = Ox + (i+0.5)*dx;
for( int j = lowCoords[1]; j < highCoords[1]; j++ )
{
double y = Oy + (j+0.5)*dy;
for( int k = lowCoords[2]; k < highCoords[2]; k++ )
{
double z = Oz + (k+0.5)*dz;
for ( int si = 0; si < numSamples; si++) {
double rx, ry, rz;
if(jitter) {
rx = x + dx*(randgen() - 0.5);
ry = y + dy*(randgen() - 0.5);
rz = z + dz*(randgen() - 0.5);
} else {
rx = x;
ry = y;
rz = z;
}
pt *= fluidWorldMatrix;
if( volumePrimitivePointInside( pt, emitterWorldMatrix ) )
{
double dist = pt.distanceTo( emitterPos );
double distDrop = dropoff * (dist*dist);
double newVal = (theRate * exp( -distDrop )) / (double)numSamples;
if( newVal != 0.0 )
{
fluid.
emitIntoArrays( (
float) newVal, i, j, k, (
float)densityEmit, (
float)heatEmit, (
float)fuelEmit, doEmitColor, emitColor );
}
}
}
}
}
}
}
void
simpleFluidEmitter::surfaceFluidEmitter(
int plugIndex,
double dt,
double conversion,
double dropoff
)
{
double densityEmit = fluidDensityEmission( block );
double fuelEmit = fluidFuelEmission( block );
double heatEmit = fluidHeatEmission( block );
bool doEmitColor = fluidEmitColor( block );
MColor emitColor = fluidColor( block );
double theRate = getRate(block) * dt * conversion;
double size[3];
unsigned int res[3];
double dx = size[0] / res[0];
double dy = size[1] / res[1];
double dz = size[2] / res[2];
double Ox = -size[0]/2;
double Oy = -size[1]/2;
double Oz = -size[2]/2;
bool jitter = fluidJitter(block);
if( !jitter )
{
resetRandomState( plugIndex, block );
}
if( fnSweptData.triangleCount() > 0 )
{
double vfArea = pow(dx*dy*dz, 2.0/3.0);
MObject rateTextureAttr = fnNode.attribute(
"textureRate" );
MObject colorTextureAttr = fnNode.attribute(
"particleColor" );
bool texturedRate = hasValidEmission2dTexture( rateTextureAttr );
bool texturedColor = hasValidEmission2dTexture( colorTextureAttr );
if( texturedRate || texturedColor )
{
uCoords.
setLength( fnSweptData.triangleCount() );
vCoords.
setLength( fnSweptData.triangleCount() );
int t;
for( t = 0; t < fnSweptData.triangleCount(); t++ )
{
uCoords[t] = uvMid[0];
vCoords[t] = uvMid[1];
}
}
if( texturedRate )
{
evalEmission2dTexture( rateTextureAttr, uCoords, vCoords, NULL, &texturedRateValues );
}
if( texturedColor )
{
evalEmission2dTexture( colorTextureAttr, uCoords, vCoords, &texturedColorValues, NULL );
}
for( int t = 0; t < fnSweptData.triangleCount(); t++ )
{
double curTexturedRate = texturedRate ? texturedRateValues[t] : 1.0;
if( texturedColor )
{
MVector& curVec = texturedColorValues[t];
curTexturedColor.
r = (float)curVec[0];
curTexturedColor.
g = (float)curVec[1];
curTexturedColor.
b = (float)curVec[2];
curTexturedColor.
a = 1.0;
}
else
{
curTexturedColor = emitColor;
}
double triArea = tri.
area();
int numSamples = (int)(triArea / vfArea);
if( numSamples < 1 ) numSamples = 1;
double triRate = (theRate*(triArea/vfArea))/numSamples;
triRate *= curTexturedRate;
for( int j = 0; j < numSamples; j++ )
{
double r1 = randgen();
double r2 = randgen();
if( r1 + r2 > 1 )
{
r1 = 1-r1;
r2 = 1-r2;
}
double r3 = 1 - (r1+r2);
MPoint randPoint = r1*v0 + r2*v1 + r3*v2;
randPoint *= fluidInverseWorldMatrix;
int3 coord;
if( (coord[0]<0) || (coord[1]<0) || (coord[2]<0) ||
(coord[0]>=(int)res[0]) || (coord[1]>=(int)res[1]) || (coord[2]>=(int)res[2]) )
{
continue;
}
gridPoint.
x = Ox + (coord[0]+0.5)*dx;
gridPoint.y = Oy + (coord[1]+0.5)*dy;
gridPoint.z = Oz + (coord[2]+0.5)*dz;
MVector diff = gridPoint - randPoint;
double distSquared = diff * diff;
double distDrop = dropoff * distSquared;
double newVal = triRate * exp( -distDrop );
if( newVal != 0 )
{
fluid.
emitIntoArrays( (
float) newVal, coord[0], coord[1], coord[2], (
float)densityEmit, (
float)heatEmit, (
float)fuelEmit, doEmitColor, curTexturedColor );
}
}
}
}
}
{
MFnPlugin plugin(obj, PLUGIN_COMPANY,
"3.0",
"Any");
status = plugin.registerNode( "simpleFluidEmitter", simpleFluidEmitter::id,
&simpleFluidEmitter::creator, &simpleFluidEmitter::initialize,
if (!status) {
status.
perror(
"registerNode");
return status;
}
return status;
}
{
status = plugin.deregisterNode( simpleFluidEmitter::id );
if (!status) {
status.
perror(
"deregisterNode");
return status;
}
return status;
}