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