LEGO TUTORIAL This is a brief tutorial that will make you easily be able to voxelize objects and replace their geometry with polygonal primitives, such as lego bricks, as was shown in this amazing honda commercial The main idea is to substitute a previous modeled object with a set of primitive elements and make them go upwards with the helps of Maya fields. By playing the animation backwards all the bricks will fall to their original position rebuilding the object. There are several ways to voxelize an object. I am going to make use of standard Maya tools (1) in order to make everything very handy. The first thing to do is choose an object (mesh or nurbs surface is the same): as the markets have recently gone down I will place a bull in the center of the scene in order to propitiate the gods :)Pic1 Place a fluid container that enclose the entire bounding box of the bull.The more we increase the fluid resolution the more we will achieve a finer resolution in our reconstruction. Then select the object and in the Fluid Effects Add/Edit Contents menu choose Emit from Object. The type of emitter selected in the option box is Surface. In the fluidShape properties set the Damp attribute of the Dynamic Simulation panel at 1. After playing the animation for a while you should be able to see your 'ghost' bull as shown in Pic2 where the mesh has been hidden.
Pic2 At this point we can go sample the container and create a particle (or a geometry(2)) in every point of the container showing a value of density greater than a chosen threshold. In our example we are going to choose the voxel centers and place a particle in it but you can make different choices i.e. double the original resolution). To sample fluid density values I've made use of the MEL function getFluidAttr while fluidVoxelInfo reckons voxel positions. Here is the script I've made to transfer the density information to particle position: { //First: create the particle object particle -n particle1; //Get the fluid resolution W, H, D int $w = `getAttr fluidShape1.resolutionW`; int $h = `getAttr fluidShape1.resolutionH`; int $d = `getAttr fluidShape1.resolutionD`; //Cycle through all the fluid voxels (three indices $i $j $k for W,H,D respectively) for($i=0;$i<$w;$i++) for($j=0;$j<$h;$j++) for($k=0;$k<$d;$k++) { //Get the center position (-vc parameter) of the (i,j,k)-th voxel vector $pos = `fluidVoxelInfo -vc -xi ($i) -yi ($j) -zi ($k) fluid1`; //Get the density value of the (i,j,k)-th voxel float $val[] = `getFluidAttr -at "density" -xi ($i) -yi ($j) -zi ($k) fluid1`; //If the voxel density value is greater than 0.1 (the threshold) add a particle to particle1 if($val[0] > 0.1) { emit -o particle1 -pos ($pos.x) ($pos.y) ($pos.z); } } } You can hide the fluid container and execute the script: you should obtain a bull made of particle as shown in pic3. At this point select the particle and choose from the Solver menu Initial State and the Set for selected.
Pic3 Geometry replacement: select the geometry to be instanced (i.e. a LEGO brick) the object particle and choose Instancer (Replacement) from the Particle menu: if it needed adjust your primitive scale. You should see a result similar to that of Pic4. At this point I'd rather hide the particle instancer to save time of redrawing while focusing on the particle animation. Remember that your animation will be played backwards.
Pic4 Animation: I made use of a group of fields which is animated along the Y axis. All fields are set to Volume, Box shape as shown in pic4. The group is made up of the following: a) a gravity field with an inverse direction and a strong magnitude in order to avoid bricks falling too slowly when they return to their original position (that is, when they fall down playing at reverse speed). b) the second field is again a gravity, bigger than the first one, with a value of magnitude much much smaller. c) a turbulence field placed to add some noise.
Pic5 Set a key on the Y value at the beginning of the animation (above the bull) and one at the end when the field reached the baseline of the object. Play the animation, make the necessary tweaks and make a particle disk cache. At this point turn on the instancer visibility set up your scene (lights and texturing(3) and render it! pic6).
Pic6 That's it! Michele Any suggestions and comments are welcomed. Yuo can watch a rendered test here (~4Mb) PS If you like voxel art take a look at this: Cailler That's hot :-) Notes (1) Instead of using a fluid container any other voxelization method could be used: for example, a function which returns if a point is inside or ouside a mesh could have been used. this way, the fluid container space limitations could be overcome. In addition, using a function like that can easily build filled volume (You can still fill the volume with this approach but you need to make use of some floodfill algorithm for each plane of the particle volume). (2) Instancing geometry is fine if you are not going to deal with animation and need still frames. The particle instance approach allows us a deeper control and easy animations. (3) If you need to 'texture' your object, i.e. build your object with different kind of bricks, you can either use different shapes (or colours) when instancing or replace the instanced geometry with real geometries and assign them different shaders. The first solution is more elegant because perhaps you can get information on the original object colour when the particle is created (closestPointOnMesh?). © www.adunaton.it
Pic1
Place a fluid container that enclose the entire bounding box of the bull.The more we
increase the fluid resolution the more we will achieve a finer resolution in our
reconstruction. Then select the object and in the Fluid Effects Add/Edit Contents
menu choose Emit from Object. The type of emitter selected in the option box is Surface.
In the fluidShape properties set the Damp attribute of the Dynamic Simulation panel at 1.
After playing the animation for a while you should be able to see your 'ghost' bull as
shown in Pic2 where the mesh has been hidden.
Pic2
At this point we can go sample the container and create a particle (or a geometry(2))
in every point of the container showing a value of density greater than a chosen threshold.
In our example we are going to choose the voxel centers and place a particle in it but you can
make different choices i.e. double the original resolution). To sample fluid density values
I've made use of the MEL function getFluidAttr while fluidVoxelInfo reckons voxel positions.
Here is the script I've made to transfer the density information to particle position:
{
//First: create the particle object
particle -n particle1;
//Get the fluid resolution W, H, D
int $w = `getAttr fluidShape1.resolutionW`;
int $h = `getAttr fluidShape1.resolutionH`;
int $d = `getAttr fluidShape1.resolutionD`;
//Cycle through all the fluid voxels (three indices $i $j $k for W,H,D respectively)
for($i=0;$i<$w;$i++)
for($j=0;$j<$h;$j++)
for($k=0;$k<$d;$k++)
{
//Get the center position (-vc parameter) of the (i,j,k)-th voxel
vector $pos = `fluidVoxelInfo -vc -xi ($i) -yi ($j) -zi ($k) fluid1`;
//Get the density value of the (i,j,k)-th voxel
float $val[] = `getFluidAttr -at "density" -xi ($i) -yi ($j) -zi ($k) fluid1`;
//If the voxel density value is greater than 0.1 (the threshold) add a particle to particle1
if($val[0] > 0.1)
{
emit -o particle1 -pos ($pos.x) ($pos.y) ($pos.z);
}
}
}
You can hide the fluid container and execute the script: you should obtain a bull made of
particle as shown in pic3. At this point select the particle and choose from the Solver menu
Initial State and the Set for selected.
Pic3
Geometry replacement: select the geometry to be instanced (i.e. a LEGO brick) the object
particle and choose Instancer (Replacement) from the Particle menu: if it needed adjust your
primitive scale. You should see a result similar to that of Pic4. At this point I'd rather hide
the particle instancer to save time of redrawing while focusing on the particle animation.
Remember that your animation will be played backwards.
Pic4
Animation: I made use of a group of fields which is animated along the Y axis. All fields are
set to Volume, Box shape as shown in pic4. The group is made up of the following:
a) a gravity field with an inverse direction and a strong magnitude in order to avoid bricks
falling too slowly when they return to their original position (that is, when they fall down
playing at reverse speed).
b) the second field is again a gravity, bigger than the first one, with a value of magnitude
much much smaller.
c) a turbulence field placed to add some noise.
Pic5
Set a key on the Y value at the beginning of the animation (above the bull) and one at the end
when the field reached the baseline of the object. Play the animation, make the necessary tweaks
and make a particle disk cache. At this point turn on the instancer visibility set up your scene
(lights and texturing(3) and render it! pic6).
Pic6
That's it! Michele
Any suggestions and comments are welcomed.
Yuo can watch a rendered test