shatter help


#101

Thats what this place is for :slight_smile: …My first iteration of the shatter script worked around booleans as well, it was a nightmare to use.

Have you tried the rayIntersect plugin? May need a compile for 2009.

  1. A way (through code only) to aim an object at another. I need the vector so I can input that into the cut plane. Right now its all constraint based, which is fine, but it’d be nicer to have it as code.

I have a function in my Shatter script that handles this based on the poluCut method. What you describe is exactly how I am doing it there. You may look into just ripping my code out and fitting it in to fit yours perhaps?

Wrapping this around a UI would be great, especially if you wanted to specify exactly how many chunks you wanted. With your particle method, that should be very easy. Plus shader assignment, blahblah…

Thanks again for sharing this stuff! I’m excited to get some free time to see if there is anything I can add!


#102

i tryied to use but it`s slow as hell, so i ended up writing my own

here are some numbers:

rayIntersect (mel script):

  • 6500 polyface
  • 20.000 locators
  • 1 test for each locator
  • about 5% misses
  • 105s to remove the outside locators

my version of rayIntersect (python script):

  • 6500 polyface
  • 20.000 locators
  • 2 tests for each locator ( random direction and revers )
  • 0% misses
  • 9s to remove the outside locators

#103

Sanctuary, thats awesome! Maybe we should convert this thing over to python?


#104

Sanctuary, …How are you going about creating the shards? Are you also using the polyCut method or are you actually tessellating them?


#105

WOW
just WOW

omg
You all are just such amazing people. I never would have thought this would have happened soo soon.

Really, such amazing scripts, I really need to start learning mel so I can help out with this thing.

I know I wont be the first, and definitely not the last …

BUT THANK YOU ALL FOR EVERYTHING

hoping something even bigger comes out of this.


#106

Now it assigns an interior shard shader and there is a progress bar that you can cancel:

// Voronoi Shatter
  
  proc callVoronoi()
  {
      // Variables
      float $crackOffset = 0.002;
  
      // Gather selected items
      string $s[] = `ls -sl -fl`;
  
      // Store particle name and object name
      $pTName = $s[0];
      string $objName = $s[1];
  
      // Store particle shape name and particle count
      string $pRelatives[] = `listRelatives -s $s[0]`;
      $pSName = $pRelatives[0];
      int $pCount = `getAttr ($pSName+".count")`;
  
      // Pass selection to the voronoi shatter procedure
      voronoiShatter($pTName, $pSName, $pCount, $objName, $crackOffset);
  }
  callVoronoi();
  
  // The main voronoi shatter procedure
  proc voronoiShatter(string $pTName, string $pSName, int $pCount, string $objName, float $crackOffset)
  {
      int $amount = 0;
       progressWindow
         -title "Voronoi Shatter"
         -progress 0
         -status "Initializing . . ."
         -isInterruptable true
      -maxValue $pCount;
  
      // Disable the undo que
      undoInfo -state off;
  
      // Create shard material if it doesn't exist
      int $shardMatExists = `objExists voronoiShardMaterial`;
      if($shardMatExists == 0)
      {
          string $mat = `shadingNode -asShader lambert -name voronoiShardMaterial`;
          sets -renderable true -noSurfaceShader true -empty -name ($mat + "SG");
          connectAttr -f ($mat + ".outColor") ($mat + "SG.surfaceShader");
          setAttr ($mat + ".color") -type double3 1 1 0 ;
      }
  
      // Create an empty group node to store shards
      string $shardsGRP = `group -empty -n "shardsGRP"`;
  
      // Hide particles
      setAttr ($pTName + ".visibility") 0;
  
      // Create cut block
      string $cutBlock = voronoiCreateCutBlock($objName);
  
      // Convert all the particles to locators
      string $locGRP = voronoiParticlesToLocators($pSName);
      setAttr ($locGRP + ".visibility") 0;
      
      // Get list of all locators under locator group
      string $locators[] = `listRelatives -c -type transform $locGRP`;
  
      // Go thru every locator and compare it to every other locator
      // Find the midpoint, create shatter cube, and shatter
      for($a=0;$a<size($locators);$a++)
      {
             // Check if the dialog has been cancelled
             if ( `progressWindow -query -isCancelled` ) break;
  
             // Check if end condition has been reached
             if ( `progressWindow -query -progress` >= $pCount ) break;
  
             $amount += 1;
  
          // Store worldspace translate of a
          float $aPos[] = `xform -q -ws -t $locators[$a]`;
      
          // Variable to store active shard mesh name
          string $activeShard = "";
      
          // Duplicate mesh to shatter
          string $dupMesh[] = `duplicate -rr $objName`;
          setAttr ($objName + ".visibility") 0;
          $activeShard = $dupMesh[0];
          setAttr ($activeShard + ".visibility") 1;
      
          // Go thru each locator
          for($b=0;$b<size($locators);$b++)
          {
              // Check that its not going to itself
              if($a != $b)
              {
                  // Store worldspace translate of b
                  float $bPos[] = `xform -q -ws -t $locators[$b]`;
                  
                  // Find the midpoint between locator A and locator B
                  vector $midPoint = <<(($aPos[0] + $bPos[0])/2), (($aPos[1] + $bPos[1])/2), (($aPos[2] + $bPos[2])/2)>>;
      
                  // Convert to vectors
                  vector $aPosVector = {$aPos[0],$aPos[1],$aPos[2]};
                  vector $bPosVector = {$bPos[0],$bPos[1],$bPos[2]};
      
                  // Calculate direction vector
                  vector $dir = $aPosVector - $midPoint;
      
                  // Normalize
                  $dir = $dir / mag($dir);
      
                  // Calculate new offset midpoint
                  vector $offMidPoint = $midPoint + ($crackOffset * $dir);
      
                  // Create aim locator
                  string $aimLoc[] = `spaceLocator -p $bPos[0] $bPos[1] $bPos[2]`;
                  xform -cp $aimLoc[0];
      
                  // Position cut block
                  string $cutCube[] = `duplicate -rr $cutBlock`;
                  setAttr ($cutCube[0] + ".visibility") 1;
                  setAttr ($cutCube[0] + ".translateX") ($offMidPoint.x);
                  setAttr ($cutCube[0] + ".translateY") ($offMidPoint.y);
                  setAttr ($cutCube[0] + ".translateZ") ($offMidPoint.z);
      
                  // Aim cut cube
                  string $aimConstraint[] = `aimConstraint -offset 0 0 0 -weight 1 -aimVector 0 1 0 -upVector 0 1 0 -worldUpType "vector" -worldUpVector 0 1 0 $aimLoc[0] $cutCube[0]`;
                  for($ac=0;$ac<size($aimConstraint);$ac++)
                  {
                      if(`objExists $aimConstraint[$ac]`)
                      {
                          delete $aimConstraint[$ac];
                      }
                  }
      
                  // Cleanup
                  for($al=0;$al<size($aimLoc);$al++)
                  {
                      if(`objExists $aimLoc[$al]`)
                      {
                          delete $aimLoc[$al];
                      }
                  }
                  
                  // Do Cut procedure
                  vector $cutBlockRot = `xform -q -ws -rotation $cutCube[0]`;
                  int $numFace[] = `polyEvaluate -f $activeShard`;
                  polyCut -ch off -df 1 -pc ($offMidPoint.x) ($offMidPoint.y) ($offMidPoint.z) -ro ($cutBlockRot.x + 90) ($cutBlockRot.y) ($cutBlockRot.z) ($activeShard + ".f[0:" + $numFace[0] + "]");
  
                  // Evaluate the new cut faces        
                  int $numCutFace[] = `polyEvaluate -f $activeShard`;
  
                  polyCloseBorder -ch 0 $activeShard;
  
                  // Evaluate the new cut and filled faces
                  int $numNewFace[] = `polyEvaluate -f $activeShard`;
  
                  // Go through all the new faces and assign new shader
                  for($f=($numCutFace[0]);$f<($numNewFace[0]);$f++)
                  {
                      // Assign the shard material to the new face    
                      sets -e -forceElement voronoiShardMaterialSG ($activeShard + ".f[" + $f + "]");
                  }
                  select -cl;
  
                  // Cleanup
                  if(`objExists $cutCube[0]`)
                  {
                      delete $cutCube[0];
                  }
              }
              else
              {
                  //delete $dupMesh[0];
              }
          }
  
          // Parent shard under group node
          parent $activeShard $shardsGRP;
      
          // Refresh the viewport
          //select -cl;
          refresh();
  
               progressWindow -edit
                   -progress $amount
                   -status ("Voronoi Shatter step " + $amount + " of " + $pCount + " completed . . .");
  
      }
  
      progressWindow -endProgress;
  
      // Delete the cut block
      delete $cutBlock;
  
  undoInfo -state on;
  }
  
  
  // Creates the cut block
  proc string voronoiCreateCutBlock(string $objName)
  {
      // Find the bounding box of obj
      float $bbox[] = `exactWorldBoundingBox $objName`; 
      float $biggestDimension = abs($bbox[3]-$bbox[0]); 
      if (abs($bbox[4]-$bbox[1]) > $biggestDimension)
      { 
          $biggestDimension = abs($bbox[4]-$bbox[1]); 
      } 
  
      if (abs($bbox[5]-$bbox[2]) > $biggestDimension)
      { 
          $biggestDimension = abs($bbox[5]-$bbox[2]); 
      }
      
      // Now that we have the biggest dimension, lets increase it a bit
      $biggestDimension = $biggestDimension * 4;
  
      // Create the cut block geometry and store its name
      string $cutBlockCreate[] = `polyPlane -w 1 -h 1 -sx 1 -sy 1 -ax 0 1 0 -cuv 2 -ch 0 -n "cutBlock"`;
      string $cutBlockName = $cutBlockCreate[0];
  
      // Set the scale of the plane
      setAttr ($cutBlockName + ".scaleX") $biggestDimension;
      setAttr ($cutBlockName + ".scaleZ") $biggestDimension;
  
      // Extrude the plane into a block
      polyExtrudeFacet -ch 0 -ltz ($biggestDimension * 2) -smoothingAngle 0 ($cutBlockName+".f[0]");
  
      // Freeze transforms
      makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $cutBlockName;
  
      // Hide the cut block
      setAttr ($cutBlockName + ".visibility") 0;
  
      select -cl;
  
      return $cutBlockName;
  }
  
  
  
  // Converts particles to locators
  proc string voronoiParticlesToLocators(string $pName)
  {
      // Create group to hold locators
      string $pGRP = `group -empty -n "particleLocatorGrp"`;
  
      // Get particle count
      int $pCount = `getAttr ($pName + ".count")`;
  
      // Go thru each particle
      for($p=0;$p<$pCount;$p++)
      {
          // Store worldspace translate of each particle
          float $pPos[] = `getParticleAttr -at worldPosition ($pName + ".pt[" + $p + "]")`;
  
          // Create locator
          string $pLoc[] = `spaceLocator -n "voronoiPoint_#"`;
  
          // Set attributes
          setAttr ($pLoc[0] + ".translateX") $pPos[0];
          setAttr ($pLoc[0] + ".translateY") $pPos[1];
          setAttr ($pLoc[0] + ".translateZ") $pPos[2];
          setAttr ($pLoc[0] + ".scaleX") 0.1;
          setAttr ($pLoc[0] + ".scaleY") 0.1;
          setAttr ($pLoc[0] + ".scaleZ") 0.1;
  
          // Parent locator
          parent $pLoc[0] $pGRP;
      }
  
      // Return the locator group name
      return $pGRP;
  }

#107

thank you AtrusDni for sharing your script! it work great!


#108

I can’t get it to work. Is it using any code specific to Windows? I’m on a Mac. I try pasting in the Python Script Editor field wiht a mesh selected but I get this:

Error: (‘invalid syntax’, (’<maya console>’, 2, 2, '// Voronoi Shatter

'))

File “<maya console>”, line 1

// Voronoi Shatter

^

SyntaxError: invalid syntax

If I try it as MEL, I get this:

// Error: No object matches name: pCubeShape1.count //


#109

This is a MEL script, not Python.


#110

and you are not selecting objects in the right order


#111

sorry - I missed the steps from the previous page. works now - amazing work. So sweet.

Is there a way to have it so that the mesh seams aren’t visible? I think most people are going to want to use this to make realistic object explosions à la Blast Code.


#112

Yeah theres no GUI yet, but if you look at the code at the top you’ll see

float $crackOffset = 0.002;

Change this to make the cracks thicker / thinner. Smaller values = smaller cracks.


#113

As soon as this is in a more robust state I’ll write up a nice clean UI for it.


#114

nice. so now the only question is: how much are all the other voronoi plug-ins going to cost :stuck_out_tongue:


#115

@ Azshall - Sounds good :thumbsup:


#116

If anything, :slight_smile: … I think that will be determined by ease of use and scalability.

Does it retain history? Is the voronoi shattering texture driven (ILM’s works this way), if so is there a benefit to it? How fast is it? What is its fail rate? Does it maintain or create usable UV’s on the new faces? Does it work on any mesh object, if so does it have to be water tight? … Lots of things could determine whether its even worth purchasing…


#117

no one knows
but really all the other voronoi scripts that cost money, is usually what AtrusDni provided but with a GUI and maybe some more options, but really, if you think about it, the script is there and it does what we wanted, which is a proper shatter tool.

I mean, really, if I knew mel script, I would totally add onto this script with a GUI or help out with other options.


#118

i just tried an imported mesh and got a crash. Is there something I should avoid like mixing tris and quads?


#119

How many particles did you use? Was your mesh air-tight? I haven’t tested this extensively, so theres bound to be quirks. Also Im working on a way to have a “smart” search, because as it is now, it has to go thru every particle, and compare itself to every other particle. To put this into persepective, take the number of particles you have and multiply it by itself. So:

300 particles x 300 = 90,000! For 300 particles there are 90,000 poly cut operations. Soooo im working on a way aroudn this. maybe you set a threshold, so for example you enter 10. It will find the 10 closest particles and only consider those for shatter. This should speed up the script tremendously. It would still have to search for the closest particles, but that should be decently fast.


#120

Okay
So I may be a newb at mel script, But I was able to look at the help file
and create a Message window asking how big much offset you want in the cracks.

Still dont know how to have a default number already typed in the window, soo you can do 2 things

either type in the default number which is 0.004

or you can hit cancel and it will go to the default number (which is 0.004)

It may be small, but it can work out if your gonna use it often and dont want to go in and change the number all the time.

// Voronoi Shatter
  
  proc callVoronoi()
  {

// Show the dialog box:
string $crackOffsetImput;
string $result = `promptDialog
	-title "Voronoi Shatter"
	-message "Crack Offset:"
	-button "OK" -button "Cancel"
	-defaultButton "OK" -cancelButton "Cancel"
	-dismissString "Cancel"`;

// Use the command again in query mode to
// get the text:
if ($result == "OK") {
	$crackOffsetImput = `promptDialog -query -text`;
}
if ($result == "Cancel"){
	$crackOffsetImput = 0.004;
}
      // Variables
      float $crackOffset =$crackOffsetImput;
  
      // Gather selected items
      string $s[] = `ls -sl -fl`;
  
      // Store particle name and object name
      $pTName = $s[0];
      string $objName = $s[1];
  
      // Store particle shape name and particle count
      string $pRelatives[] = `listRelatives -s $s[0]`;
      $pSName = $pRelatives[0];
      int $pCount = `getAttr ($pSName+".count")`;
  
      // Pass selection to the voronoi shatter procedure
      voronoiShatter($pTName, $pSName, $pCount, $objName, $crackOffset);
  }
  callVoronoi();
  
  // The main voronoi shatter procedure
  proc voronoiShatter(string $pTName, string $pSName, int $pCount, string $objName, float $crackOffset)
  {
      int $amount = 0;
       progressWindow
         -title "Voronoi Shatter"
         -progress 0
         -status "Initializing . . ."
         -isInterruptable true
      -maxValue $pCount;
  
      // Disable the undo que
      undoInfo -state off;
  
      // Create shard material if it doesn't exist
      int $shardMatExists = `objExists voronoiShardMaterial`;
      if($shardMatExists == 0)
      {
          string $mat = `shadingNode -asShader lambert -name voronoiShardMaterial`;
          sets -renderable true -noSurfaceShader true -empty -name ($mat + "SG");
          connectAttr -f ($mat + ".outColor") ($mat + "SG.surfaceShader");
          setAttr ($mat + ".color") -type double3 1 1 0 ;
      }
  
      // Create an empty group node to store shards
      string $shardsGRP = `group -empty -n "shardsGRP"`;
  
      // Hide particles
      setAttr ($pTName + ".visibility") 0;
  
      // Create cut block
      string $cutBlock = voronoiCreateCutBlock($objName);
  
      // Convert all the particles to locators
      string $locGRP = voronoiParticlesToLocators($pSName);
      setAttr ($locGRP + ".visibility") 0;
      
      // Get list of all locators under locator group
      string $locators[] = `listRelatives -c -type transform $locGRP`;
  
      // Go thru every locator and compare it to every other locator
      // Find the midpoint, create shatter cube, and shatter
      for($a=0;$a<size($locators);$a++)
      {
             // Check if the dialog has been cancelled
             if ( `progressWindow -query -isCancelled` ) break;
  
             // Check if end condition has been reached
             if ( `progressWindow -query -progress` >= $pCount ) break;
  
             $amount += 1;
  
          // Store worldspace translate of a
          float $aPos[] = `xform -q -ws -t $locators[$a]`;
      
          // Variable to store active shard mesh name
          string $activeShard = "";
      
          // Duplicate mesh to shatter
          string $dupMesh[] = `duplicate -rr $objName`;
          setAttr ($objName + ".visibility") 0;
          $activeShard = $dupMesh[0];
          setAttr ($activeShard + ".visibility") 1;
      
          // Go thru each locator
          for($b=0;$b<size($locators);$b++)
          {
              // Check that its not going to itself
              if($a != $b)
              {
                  // Store worldspace translate of b
                  float $bPos[] = `xform -q -ws -t $locators[$b]`;
                  
                  // Find the midpoint between locator A and locator B
                  vector $midPoint = <<(($aPos[0] + $bPos[0])/2), (($aPos[1] + $bPos[1])/2), (($aPos[2] + $bPos[2])/2)>>;
      
                  // Convert to vectors
                  vector $aPosVector = {$aPos[0],$aPos[1],$aPos[2]};
                  vector $bPosVector = {$bPos[0],$bPos[1],$bPos[2]};
      
                  // Calculate direction vector
                  vector $dir = $aPosVector - $midPoint;
      
                  // Normalize
                  $dir = $dir / mag($dir);
      
                  // Calculate new offset midpoint
                  vector $offMidPoint = $midPoint + ($crackOffset * $dir);
      
                  // Create aim locator
                  string $aimLoc[] = `spaceLocator -p $bPos[0] $bPos[1] $bPos[2]`;
                  xform -cp $aimLoc[0];
      
                  // Position cut block
                  string $cutCube[] = `duplicate -rr $cutBlock`;
                  setAttr ($cutCube[0] + ".visibility") 1;
                  setAttr ($cutCube[0] + ".translateX") ($offMidPoint.x);
                  setAttr ($cutCube[0] + ".translateY") ($offMidPoint.y);
                  setAttr ($cutCube[0] + ".translateZ") ($offMidPoint.z);
      
                  // Aim cut cube
                  string $aimConstraint[] = `aimConstraint -offset 0 0 0 -weight 1 -aimVector 0 1 0 -upVector 0 1 0 -worldUpType "vector" -worldUpVector 0 1 0 $aimLoc[0] $cutCube[0]`;
                  for($ac=0;$ac<size($aimConstraint);$ac++)
                  {
                      if(`objExists $aimConstraint[$ac]`)
                      {
                          delete $aimConstraint[$ac];
                      }
                  }
      
                  // Cleanup
                  for($al=0;$al<size($aimLoc);$al++)
                  {
                      if(`objExists $aimLoc[$al]`)
                      {
                          delete $aimLoc[$al];
                      }
                  }
                  
                  // Do Cut procedure
                  vector $cutBlockRot = `xform -q -ws -rotation $cutCube[0]`;
                  int $numFace[] = `polyEvaluate -f $activeShard`;
                  polyCut -ch off -df 1 -pc ($offMidPoint.x) ($offMidPoint.y) ($offMidPoint.z) -ro ($cutBlockRot.x + 90) ($cutBlockRot.y) ($cutBlockRot.z) ($activeShard + ".f[0:" + $numFace[0] + "]");
  
                  // Evaluate the new cut faces        
                  int $numCutFace[] = `polyEvaluate -f $activeShard`;
  
                  polyCloseBorder -ch 0 $activeShard;
  
                  // Evaluate the new cut and filled faces
                  int $numNewFace[] = `polyEvaluate -f $activeShard`;
  
                  // Go through all the new faces and assign new shader
                  for($f=($numCutFace[0]);$f<($numNewFace[0]);$f++)
                  {
                      // Assign the shard material to the new face    
                      sets -e -forceElement voronoiShardMaterialSG ($activeShard + ".f[" + $f + "]");
                  }
                  select -cl;
  
                  // Cleanup
                  if(`objExists $cutCube[0]`)
                  {
                      delete $cutCube[0];
                  }
              }
              else
              {
                  //delete $dupMesh[0];
              }
          }
  
          // Parent shard under group node
          parent $activeShard $shardsGRP;
      
          // Refresh the viewport
          //select -cl;
          refresh();
  
               progressWindow -edit
                   -progress $amount
                   -status ("Voronoi Shatter step " + $amount + " of " + $pCount + " completed . . .");
  
      }
  
      progressWindow -endProgress;
  
      // Delete the cut block
      delete $cutBlock;
  
  undoInfo -state on;
  }
  
  
  // Creates the cut block
  proc string voronoiCreateCutBlock(string $objName)
  {
      // Find the bounding box of obj
      float $bbox[] = `exactWorldBoundingBox $objName`; 
      float $biggestDimension = abs($bbox[3]-$bbox[0]); 
      if (abs($bbox[4]-$bbox[1]) > $biggestDimension)
      { 
          $biggestDimension = abs($bbox[4]-$bbox[1]); 
      } 
  
      if (abs($bbox[5]-$bbox[2]) > $biggestDimension)
      { 
          $biggestDimension = abs($bbox[5]-$bbox[2]); 
      }
      
      // Now that we have the biggest dimension, lets increase it a bit
      $biggestDimension = $biggestDimension * 4;
  
      // Create the cut block geometry and store its name
      string $cutBlockCreate[] = `polyPlane -w 1 -h 1 -sx 1 -sy 1 -ax 0 1 0 -cuv 2 -ch 0 -n "cutBlock"`;
      string $cutBlockName = $cutBlockCreate[0];
  
      // Set the scale of the plane
      setAttr ($cutBlockName + ".scaleX") $biggestDimension;
      setAttr ($cutBlockName + ".scaleZ") $biggestDimension;
  
      // Extrude the plane into a block
      polyExtrudeFacet -ch 0 -ltz ($biggestDimension * 2) -smoothingAngle 0 ($cutBlockName+".f[0]");
  
      // Freeze transforms
      makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $cutBlockName;
  
      // Hide the cut block
      setAttr ($cutBlockName + ".visibility") 0;
  
      select -cl;
  
      return $cutBlockName;
  }
  
  
  
  // Converts particles to locators
  proc string voronoiParticlesToLocators(string $pName)
  {
      // Create group to hold locators
      string $pGRP = `group -empty -n "particleLocatorGrp"`;
  
      // Get particle count
      int $pCount = `getAttr ($pName + ".count")`;
  
      // Go thru each particle
      for($p=0;$p<$pCount;$p++)
      {
          // Store worldspace translate of each particle
          float $pPos[] = `getParticleAttr -at worldPosition ($pName + ".pt[" + $p + "]")`;
  
          // Create locator
          string $pLoc[] = `spaceLocator -n "voronoiPoint_#"`;
  
          // Set attributes
          setAttr ($pLoc[0] + ".translateX") $pPos[0];
          setAttr ($pLoc[0] + ".translateY") $pPos[1];
          setAttr ($pLoc[0] + ".translateZ") $pPos[2];
          setAttr ($pLoc[0] + ".scaleX") 0.1;
          setAttr ($pLoc[0] + ".scaleY") 0.1;
          setAttr ($pLoc[0] + ".scaleZ") 0.1;
  
          // Parent locator
          parent $pLoc[0] $pGRP;
      }
  
      // Return the locator group name
      return $pGRP;
  }