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; }
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); } }
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); } }
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; }
// // 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; }
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 ); }
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 ); } } }
//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)); } } }