Adding Particle Effects to DMM Fracture
Adding particle effects to fracturing DMM objects will improve the realism and look of the fracture. Puffs of dust for breaking stone, small wooden splinters for breaking wood, tiny bits of glass for breaking glass can be done with Maya particles. Of course particles can be added "by hand" using the Maya particle tools. It is much more convenient, though, to add particles automatically when and where fracture occurs. This can be done with a script.
Below is a MEL script for automatically creating particles where fracture occurs on DMM objects. Executing the dmmAddParticles() procedure causes all selected DMM objects to get particle effects when they fracture. It takes a string as an argument. This string will be passed to the eventual procedure dmmDoParticle() that is called for each newly exposed tetrahedral face. This routine is also passed a vector that is the centroid of the newly exposed tetrahedral face and is a reasonable point in space to create some particles. The dmmDoParticle() procedure must be customized to create particles they way you want them. The default code just creates a particle with no shape, no physics, and an infinite life span. The dmmDoParticles() procedure should be called once per frame from a MEL animation expression or a job.
// mel script for creating particles for DMM object fracture global string $dmmParticleObjects[]; global string $dmmParticleString[]; global int $dmmParticleObjectFlags[]; global int $dmmParticleObjectNumFlags[]; global int $dmmParticleAllFlags[]; global int $dmmTetFaceMagic[12] = { 1, 2, 3, 0, 3, 2, 0, 1, 3, 0, 2, 1 }; global proc vector dmmTetFaceCentroid(float $tetNodes[], int $tetId, int $faceId) { float $tv1[3], $tv2[3], $tv3[3]; int $i; int $index; global int $dmmTetFaceMagic[]; $index = $tetId*12+3*$dmmTetFaceMagic[$faceId*3+0]; for ($i=0; $i < 3; $i++) { $tv1[$i] = $tetNodes[$index+$i]; } $index = $tetId*12+3*$dmmTetFaceMagic[$faceId*3+1]; for ($i=0; $i < 3; $i++) { $tv2[$i] = $tetNodes[$index+$i]; } $index = $tetId*12+3*$dmmTetFaceMagic[$faceId*3+2]; for ($i=0; $i < 3; $i++) { $tv3[$i] = $tetNodes[$index+$i]; } return <<($tv1[0] + $tv2[0] + $tv3[0])/3, ($tv1[1] + $tv2[1] + $tv3[1])/3, ($tv1[2] + $tv2[2] + $tv3[2])/3>>; } // // dmmDoParticle -- the routine that creates a particle // this should be customized to create the desired // particle effect // global proc dmmDoParticle(vector $v, string $particleString) { string $particleName[] = `particle -position ($v.x) ($v.y) ($v.z)`; } // // dmmDoParticles -- this procedure should be called once per frame // it causes particles to be created on fracture of // DMM objects that are on the list of DMM objects // that will get fracture particles // global proc dmmDoParticles() { global string $dmmParticleObjects[]; global string $dmmParticleString[]; global int $dmmParticleObjectFlags[]; global int $dmmParticleObjectNumFlags[]; global int $dmmParticleAllFlags[]; int $i, $numObjects; $numObjects = size($dmmParticleObjects); for ($i=0; $i < $numObjects; $i++) { string $dmmObj = $dmmParticleObjects[$i]; int $tflags[] = `getAttr ($dmmObj+".tetFlags")`; int $numTets = size($tflags); // see if any faces changed int $j, $k; int $changeCount = 0; int $m; $k = $dmmParticleObjectFlags[$i]; for ($j=0; $j < $numTets; $j++) { if ($dmmParticleAllFlags[$k+$j] != $tflags[$j]) { $changeCount++; } } if ($changeCount != 0) { float $t[] = `getAttr ($dmmObj+".tetNodes")`; for ($j=0; $j < $numTets; $j++) { if ($dmmParticleAllFlags[$k+$j] != $tflags[$j]) { int $oldFlag = $dmmParticleAllFlags[$k+$j]; int $newFlag = $tflags[$j]; for ($m=0; $m < 4; $m++) { if (($newFlag % 2) != ($oldFlag % 2)) { vector $v = dmmTetFaceCentroid($t, $j, $m); dmmDoParticle($v, $dmmParticleString[$i]); } $oldFlag /= 2; $newFlag /= 2; } $dmmParticleAllFlags[$k+$j] = $tflags[$j]; // new flags become old } } } } } global proc dmmAddParticlesToObject(string $dmmObj, string $particleString) { global string $dmmParticleObjects[]; global string $dmmParticleString[]; global int $dmmParticleObjectFlags[]; global int $dmmParticleObjectNumFlags[]; global int $dmmParticleAllFlags[]; int $i, $numObjects; int $slot = -1; int $oldNumFlags = 0; // find a slot or reuse old slot $numObjects = size($dmmParticleObjects); for ($i=0; $i < $numObjects; $i++) { if ($dmmParticleObjects[$i] == $dmmObj) { $slot = $i; break; } } if ($slot < 0) { $slot = $i; $dmmParticleObjects[$slot] = $dmmObj; } else { $oldNumFlags = $dmmParticleObjectNumFlags[$slot]; } $dmmParticleString[$slot] = $particleString; int $tflags[] = `getAttr ($dmmObj+".tetFlags")`; int $numTets = size($tflags); $dmmParticleObjectNumFlags[$slot] = $numTets; if ($oldNumFlags < $numTets) { // new flags too big to fit on old area $dmmParticleObjectFlags[$slot] = size($dmmParticleAllFlags); } // copy tet flags to save area int $j = $dmmParticleObjectFlags[$slot]; for ($i=0; $i < $numTets; $i++) { $dmmParticleAllFlags[$j+$i] = $tflags[$i]; } } // // dmmAddParticles -- call to add all selected DMM objects to the list // of DMM objects that will get particles when they fracture // global proc dmmAddParticles(string $particleString) { string $a[] = `selectedNodes`; // find the DMM objects selected for ($node in $a) { string $children[] = `listRelatives -c $node`; for ($child in $children) { string $typ = `nodeType $child`; if ($typ == "DMMObject") { dmmAddParticlesToObject($child, $particleString); } } } } // // dmmParticlesInit -- (re)initialize DMM particle script // global proc dmmParticlesInit() { global string $dmmParticleObjects[]; global string $dmmParticleString[]; global int $dmmParticleObjectFlags[]; global int $dmmParticleObjectNumFlags[]; global int $dmmParticleAllFlags[]; clear($dmmParticleObjects); clear($dmmParticleString); clear($dmmParticleObjectFlags); clear($dmmParticleObjectNumFlags); clear($dmmParticleAllFlags); } dmmParticlesInit();