Here is an example of the code I use to produce animations.
Needs["Graphics`Shapes`"] (*I read in this file to use the embedded
functions RotateShape and TranslateShape*)
(*Here is code to produce a right prism; the prism is regular, i.e., has
square lateral faces, when height is set to 1. It is centered on the
origin*)
Prism[n_Integer,height_] :=
Block[{d=((2*Sin[Pi/n])*height)/2},
Graphics3D[{N[Table[
Polygon[{{Cos[2Pi i/n], Sin[2Pi i/n], -d},
{Cos[2Pi (i+1)/n], Sin[2Pi (i+1)/n], -d},
{Cos[2Pi (i+1)/n], Sin[2Pi (i+1)/n], d},
{Cos[2Pi i/n], Sin[2Pi i/n], d}}],
{i, n}]],
Polygon[Table[N[{Cos[2Pi i/n],Sin[2Pi i/n],-d}],{i, n}]],
Polygon[Table[N[{Cos[2Pi i/n],Sin[2Pi i/n],d}],{i, n, 1, -1}]]}]]/;
n > 2
Prism[n_:12, height_:1] := Prism[n, height]
(*preview the object to be animated, assigning it a name; I usually use a
single letter, like g, but that's immaterial. Display the object with
Axes->True so that you can get an idea of what the PlotRange must be to
show all of it.*)
object=Show[Prism[12,6],
Boxed->True,
Axes->True,
ViewPoint->{1.199, -1.242, 1.010}]
(*Here is the Do loop which produces the animation frames. The iterator
specification is last; it is the variable i. My first step is to preview
the object, by setting the beginning and end of the loop to zero. Only one
frame is generated. If my PlotRange has been set properly, the entire
object is visible. I set PlotRange by choosing the largest dimension of
the object, dividing by 2, adding a little bit, and giving this value a
name, say, r. The prism above extends 3 units above and below the xy
plane, its largest dimension is 6, and I set r=6.25.
Unless I specify otherwise, the object has inherited the ViewPoint used for
the initial preview. I usually choose a ViewPoint fairly close to the
object, perhaps {0,0,2}. The distance from the object greatly affects its
colors; close ViewPoints result in richly saturated colors, which I like.
I then crop the preview image; on my Macintosh this means selecting it and
dragging its handles with the command key down. I crop it because,
especially when the ViewPoint is close to the object, the perspective
transformation in MMA leaves a rather large margin of empty space around
the object. Since it is the object I want to see, I crop as close as seems
esthetically proper. Then I resize the image, by selecting it and dragging
the handles: I make it larger. Within the constraints of memory, I wish
to have the object be as large as possible. In practice, this often means
merely restoring it to roughly its original size, say, 284 by 284 pixels.
But I have sometimes created larger frames, say, 400 by 480 pixels. But
memory use is a real bugbear. As the frames are created, one sees the
front end memory use meter filling. I very often find myself selecting
large blocks of frames in the middle of the process and then choosing
"Convert to Bitmap PICT," which destroys the Postscipt code but reduces
memory use significantly.
The process above, of cropping and resizing, takes some practice and
forethought. For instance, in the case of a prism which stretches, say, 10
units along the z axis but has a basal radius of only 1 unit, if one
previews at ViewPoint->{0,0,2} and then crops as detailed above, and then
rotates the prism about the x-axis, parts of it will swing out of view.
In an animation such as this the ViewPoint is fixed, and the object
rotates. This prism is symmetrical by a rotation of 60 degrees around the
z axis, so an animation will show continuous smooth motion by creating
frames in, say, 3- or 4- or 5-degree steps. In this case I have set the
iterator i to take steps of 3 degrees. I often find it easier to work in
degrees, rather than radians, when setting up animations. OK. Now, the
RotateShape function accepts three variables, in this form:
RotateShape[object, {zrotation, xrotation, zrotation}]. Don't ask me why
the last one isn't rotation about the y axis. At any rate, for the simple
animation below, only rotation around the z axis is done. I am using
degrees but the rotation matrix wants radians, so I write Degree i. The
iterator is incrementing in steps of 3, therefore the rotation hapens in
steps of 3 degrees. I know that the object will be carried into itself in
60 degrees, since it is a hexagonal prism. Since the iterator starts
counting at 0, I must stop counting at 57. Then, when I double-click any
frame to initiate animation, and the MMA animation default is in place, the
frames will show smooth, continuous rotation, since the first frame (when
i=0) will be displayed immediately after the 20th frame (when i=57). All
this is only to say that, in this case, the iterator specification will
look like {i,0,57,3}.
20 frames of a size such as 280 by 280 pixels will usually be produced
without memory problems on a typical platform. Of course, for animation,
the more RAM the better.
Where too little RAM may easily become a problem is when more complex or
less symmetrical objects are involved, or when more complex rotations are
involved. So far we have only rotated the hexagonal prism about its axis
of symmetry, and have only had to step through an interval of 60 degrees.
However, we might wish to rotate the axis of symmetry itself, while
rotating the prism about this axis. It requires a rotation of 180 degrees
to carry the prism into itself, in this case. We may suddenly realize that
a step of 3 is too small; we switch to 4, 5, even 6, to reduce the number
of frames. However, for now, stick with 3. Now, instead of 20 frames, we
need 60 frames. We write RotateShape[object, Degree i, Degree i, 0]. The
iterator now must be {i, 0, 177, 3}. I am using a Mac with 64 MB available
to MMA, and usually create frames around 320 pixels square. If the forms I
animate are not too complex, I can sometimes allocate much more memory to
the front end and let the kernel struggle along with just as little as
possible. Of course, one can also proceed in stages: First set the
iterator like this: {i, 0, 57, 3}; then save the frames to a separate
file, delete, and set the iterator like this: {i, 60, 117, 3}; save frames,
delete, then {i, 120, 177, 3}. When all the frames have been generated, I
usually use the Convert to QuickTime, with compression algorithm set to
Animation, bit depth to Thousands, quality to Best, and frames per second
to 12.
By combining the RotateShape function with the TranslateShape function
(which were read in from Graphics Shapes), one can create animations of
solar systems of polyhedra, pyramids spinning while orbiting prisms which
in turn spin while orbiting a pentagonal dodecahedron. TranlsateShape can
also be used to close-pack polyhedra which close-pack (like cubes, or
rhombic dodecahedra, or Platonic tetrahedra mixed with octahedra), and then
in an animation one can cause the close-packing to explode, by using an
iterator inside the TranslateShape (just as we used an iterator in
RotateShape, above).
I hope this is helpful. I find animation to be one of the most desirable
and wonderful features of MMA, and would like to see it used to its best
advantage.
If perchance I have made some dreadful error or omission in this, I would
be very pleased to hear about it. Or the same, if anyone makes good use of
these techniques.*)
r=6.25;
Do[
Show[
RotateShape[object,Degree i,0,0],
ViewPoint->{.5,.5,.75},
PlotRange->{{-r,r},{-r,r},{-r,r}},
Boxed->False,
Axes->False,
Background->GrayLevel[0]],
{i, 0, 0, 3}]
Russell Towle
Box 141
Dutch Flat, CA 95714
USA