shatter help


#141

I seem to have found a cheap way of fixing the “cup problem”
if you scale the cup wide enough, so the distance from one particle to the other on the other end is far enough you dont get that big of a problem

You get minor random cut extrusion.


#142

AtrusDni
this voronoi shatter is besides being a bit slow (which is no offense) extremely sweet!
and such a great idea to get around the maya rigid boody dynamics problems.

if i would get some time (which is quite unlikely in the upcoming months) i would love to incorporate it with my already existent shatter script from the start post(which had the biggest problem while using the maya shatter:))

keep up :slight_smile:

alex


#143

Hi all, I’ve been watching this thread with great interest. Many thanks to AtrusDni for releasing your script. I hope I can add something to the cause… I’ve attached a simple scene, with a cube, a cutPlane and a few locators. I’ve created an expression to control the position and rotation of the cutplane without using constraints:


 float $aX = firstPoint.translateX;
 float $aY = firstPoint.translateY;
 float $aZ = firstPoint.translateZ;
 float $bX = secondPoint.translateX;
 float $bY = secondPoint.translateY;
 float $bZ = secondPoint.translateZ;
 float $mPX = ($aX+$bX)/2;
 float $mPY = ($aY+$bY)/2;
 float $mPZ = ($aZ+$bZ)/2;
 midPoint.translateX =$mPX;
 midPoint.translateY =$mPY;
 midPoint.translateZ =$mPZ;
 
 // Convert to vectors
 vector $midPoint	=<<$mPX, $mPY, $mPZ>>;
 vector $aPosVector = << $aX, $aY, $aZ >>;
 vector $bPosVector = << $bX, $bY, $bZ >>;
 
 // Calculate direction vector
 vector $dir = $aPosVector - $bPosVector;
 	  
 // Normalize
 $dir = $dir / mag($dir);
 
 vector $y = <<1,0,0>>;
 vector $x = <<0,1,0>>;
 
 float $dotY = dotProduct($y, $dir , 0);
 float $angY = 0-((rad_to_deg(acos($dotY))) -90);
 
 float $dotX = dotProduct($x, $dir , 0);
 float $angX = (rad_to_deg(acos($dotX)))-90;
 
 //print ("
 X rotation ="+$angX +"
 Y rotation ="+$angY+"
");
 
 midPoint.rotateZ =0;
 midPoint.rotateX =$angX;
 midPoint.rotateY =$angY;
 
 //apply values to cutplane
 polyCut1.cutPlaneCenterX= $mPX;
 polyCut1.cutPlaneCenterY= $mPY;
 polyCut1.cutPlaneCenterZ= $mPZ;
 polyCut1.cutPlaneRotateX =$angX;
 polyCut1.cutPlaneRotateY =$angY;
 

It should be pretty easy to chop this into your script if you wish to get rid the aim constraints…
Somebody more expert than me should maybe take a look at the scene and check I figured the rotation correctly, I’m at my maths limit:)

Dave.


#144

Hi again, I’d also like to share a tip about particle positioning. I really like using particles to visualise the result, but there are problems if they are not contained within the object.
What worked for me was to place an emitter within the object, flip the objects normals, emit the particles and make collide with the object. Stop emitting when you have enough particles, but you could let them rattle around inside for a while… then don’t forget to flip back the normals.
Dave.


#145

@ Dave -

Nice!!! I will have to take a look at your code a bit closer. By the way, you wouldn’t know how to compare the angle between 2 vectors would you?

One more problem I need to know is to tell if a point lies in front of, or behind a plane . . . :frowning:

Thanks for your help though, its much appreciated.


#146

Hi, to compare two angles is more or less how the expression works. Its these mel commands:

float $dot = dotProduct($vector1, $vector2, 1); // 1 means normalise 0 not normalised

and the angle in radians :

float $ang = acos($dot); // arccosine of the dot product

and to convert the result to degrees:

rad_to_deg($ang);

Are you going to use this to detect concave objects, ie the ‘cup’ problem? I felt that was more to do with polyCloseBorder not making a good choice…

Dave


#147

Hi again, I have an idea to drastically speed up the process on large splits. If you divide your object into ‘voxels’ , and then create a point in random space within that voxel, you will automatically gain a distance tolerance. eg if your are sampling from one point you don’t need to measure more than two voxels away, so max calculations for any point is 125 (2 voxels in all directions creates a 5x5x5 space). It’s not an original idea, i’m sure other people are using it, and definitely in 2d:

http://home.scarlet.be/zoetrope/voronoi/index.htm

and probably 3d:

http://morfogen.blogspot.com/2007/07/3d-voronoi-patio.html

Dave.


#148

I had an idea for particle placement. Emit from the surface of the object with a noise texture, and possibly a negative emission speed (to shoot the particle nagetive the normals)

OR mor complicated
reverse the nomals
emit particles off surface, rand speed and have them collide with the surface.
reset normals and shatter. (if needed)


#149

@ davegreenwood -

Actually no, I was going to use the angle between the vectors to remove unwanted locators. Basically locators outside of the mesh. I could have inverted the normals and emitted inside the mesh, thats a good workaround, but im looking for a cleaner approach.

Yes the issue with the cup is that the poly close boarders command does not understand how to close the border on a mesh with more then 1 poly shell.

Soooo my workaround that i was working on last night, is to evaluate the number of shells the mesh has after the poly cut. If there is more then one, then this would be an “invalid” cut and it should not use that cut angle. Still working out the kinks at the moment. If anyone wants to jump it and give it a shot, please be my guest. I would appreciate any outside help / ideas that people have.

And thanks again davegreenwood, I appreciate your help. Me + Math = Error. Im good at implimenting ideas, just not the math side of things :wink:


#150

P.S. - That is a good idea about the voxels. I do like the randomness and weird shapes that are made from the particles, especially from a point emitter, but maybe random shatter could use the voxel approach and yes that will speed it up a lot. Hmmmm gears turning . . . .


#151

Hey guys cool stuff.

I am new to maya and cannot seem to get AtrusDni’s script to do anything. Should the script work if I simply execute it from the script editor?


#152

Hi’yall! AtrusDni, I had already hacked the math Dave Greenwood mentioned into the script, to see if we’d get a big speed boost by using a matrix transformation to aim the cubes instaed of locators and aimConstraints. Thought I’d share-


 // Voronoi Shatter with Matrix Aim
   
   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 particle count
 	  int $pCount = `getAttr ($pSName + ".count")`;
   
 	  // Go thru every pt and compare it to every other pt
 	  // Find the midpoint, create shatter cube, and shatter
 	  for($a=0;$a<$pCount;$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[] = `getParticleAttr -at worldPosition ($pSName + ".pt[" + $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<$pCount;$b++)
 		  {
 			  // Check that its not going to itself
 			  if($a != $b)
 			  {
 				  // Store worldspace translate of b
 				  float $bPos[] = `getParticleAttr -at worldPosition ($pSName + ".pt[" + $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);
 	  
 
 	  
 				  // 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);
 	  
 
 			rotateObjectToVector($cutCube[0],$dir);
 
 				  // Cleanup
 
 				  
 				  // 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;
   }
 
  global proc rotateObjectToVector(string $object,vector $V)
 {
  float $m[16] = `getAttr ($object+".worldMatrix")`; // the original matrix
  float $xLen = `mag &lt;&lt;$m[00],$m[01],$m[02]&gt;&gt;`;
  float $yLen = `mag &lt;&lt;$m[04],$m[05],$m[06]&gt;&gt;`;
  float $zLen = `mag &lt;&lt;$m[08],$m[09],$m[10]&gt;&gt;`;
  vector $A = unit(cross($V,<<rand(1),rand(1),rand(1)>>)); // dummy cross 1
  vector $B = unit(cross($V,$A));  // dummy cross 2
  vector $X = ($A * $xLen);
 // -1 for reverse Y axis
  vector $Y = -1 * ($V * $yLen);
  vector $Z = ($B * $zLen);
  xform -matrix
   ($X.x) ($X.y) ($X.z) 0
   ($Y.x) ($Y.y) ($Y.z) 0
   ($Z.x) ($Z.y) ($Z.z) 0
 	   $m[12] $m[13] $m[14] 1
 	   $object;
 }  
   
   // 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;
   }
   
   
   
 
   
   
   
 

From the looks of it we’re getting about a 5% speed increase, so the big time killer is the definitely the polycut command. Reducing the # of cuts will definitely help, but I think we need a slightly different approach to get more speed.

I was personally looking into a hybrid of your particle-based approach, and what Dave G posted a link to, with a eye on compiling it to C for speed. The way you find the distance between the points is a brute-force MEL way of calculating a 3d Voronoi texture.

Thinking of taking something like the math behind Qhull, and using it to generate the shattered geometry from a set of points within the original object, not unlike what this guy does here - http://home.scarlet.be/zoetrope/voronoi3d/index.htm If we can somehow find a way to trim the shattered pieces with the original shape in C without using booleans, polyCut or any pokey Maya commands, we should get something pretty zippy, but that’s where my math breaks down. Any ideas, anybody?


#153

Malik!! Awesome! Now we got the aim working without constraints! Yes, I wasn’t expecting much of a speed boost, but the code will be much cleaner now.

Yes, the biggest improvement to speed will be isolating only the cuts that need to be performed from the ones that do not. Really tricky, but I think dave’s idea of voxels and isolating the distance of influence will be a big help.

Yes, doing a C compile would be super slick, but I couldn’t even begin to help with that. That would be the ideal approach though in terms of speed.


#154

any chance this could get multi-threaded? I doubt it’s easy but seeing 1 of 16 threads active on this machine makes baby Nehalem cry.


#155

hey
to make it work
first u need to create particles, then select the particles and then the cube or object and run the script


#156

culprit for the cup problem is polyCloseBorder command, now we need to find a way to do the same thing but using other method/command/script.


#157

Is there a way of testing how many shells an object has in mel? If so then you could test if there was more than one shell and if so select the border edges and bridge them. I think this script could really benefit from being converted to using pymel.


#158

polyBridgeEdge requires equal number of border edges to be selected for source and target so how can you bridge edges if you have 2 or more shells with different number of border edges ?

I think this script could really benefit from being converted to using pymel.

speedwise ?!?


#159

Odd, I was sure bridge edges was smart enough to terminate edges when the counts did not match.

And yes I think pymel could increase the speed and allow usage of some api commands that might be useful.


#160

my implementation was first written in MEL and then translated in python, i haven`t notice any speed improvement.

P.S.
i`ve used python because i needed some API to do the cleaning part (remove locators outside the mesh)