21
$\begingroup$

I am trying to make an animation of a rotating cube using the following code:

cube = GraphicsComplex[
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}},
Polygon[{{1, 2, 4, 3}, {5, 6, 8, 7}, {1, 2, 6, 5}, {3, 4, 8, 7}, {1, 3, 7, 5}, {2, 4, 8, 6}}]
]

cubes = Table[
Graphics3D[{Rotate[cube, x, {1, 1, 1}, {0, 0, 0}]}, 
ViewPoint -> {3, 1/2, -2}, ViewVertical -> {1, 1, 1}, 
Boxed -> False], {x, 0, 2 Pi/3 - Pi/48, Pi/24}]

However, as the cube rotates, the bounding box (which is not drawn because Boxed->False) causes the image of the cube to be shrunk to fit the larger bounding box in the field of view. Is there a way to keep the scale constant and not vary with the varying size of the bounding box?

I've gone through the list of options for Graphics3D, yet none seem to help.


Edit:

Heike's answer works like a charm! For those interested, here is the finished code, used to create the illustration for this answer on math.SE.

cube =
GraphicsComplex[
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}},
Polygon[{{1, 2, 4, 3}, {5, 6, 8, 7}, {1, 2, 6, 5}, {3, 4, 8, 7}, {1, 3, 7, 5}, {2, 4, 8, 6}}]
];

envelope[t_] := If[t < 1, t, If[t < 2, Sqrt[(2 t - 3)^2 + 3]/2, 3 - t]]

lozenge = 
Rotate[
RevolutionPlot3D[{Sqrt[2/3] envelope[t], t/Sqrt[3]}, {t, 0, 3}, MaxRecursion -> 5][[1]],
{{0, 0, 1}, {1, 1, 1}}];

enveloped = 
Table[
Graphics3D[{Rotate[cube, x, {1, 1, 1}, {0, 0, 0}],  Opacity[1/2], lozenge},
ViewVector -> {3, 1/2, -2}, ViewAngle -> 30 Degree, ViewCenter -> {1/2, 1/2, 1/2}, 
ViewVertical -> {1, 1, 1}, Boxed -> False, ImageSize -> 300],
{x, 0, 2 Pi/3 - Pi/48, Pi/24}];

Export["enveloped.gif", enveloped, "GraphicsList", "DisplayDurations" -> {.05}]

Migration to Newer Versions

With changes to Mathematica, the code above does not parse. When I fixed the code so it parsed, it renders on screen nicely, but upon Export, it rendered pretty badly (at least on the Mac Powerbook, which has 144 dpi screen resolution and tells some applications to render at 144 and others to render at 72 dpi). I was able to adjust some parameters in the code and in the Export statement to get an almost identical output.

cube =
GraphicsComplex[
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}},
Polygon[{{1, 2, 4, 3}, {5, 6, 8, 7}, {1, 2, 6, 5}, {3, 4, 8, 7}, {1, 3, 7, 5}, {2, 4, 8, 6}}]
];

envelope[t_] := If[t < 1, t, If[t < 2, Sqrt[(2 t - 3)^2 + 3]/2, 3 - t]]

lozenge = 
Rotate[
RevolutionPlot3D[{Sqrt[2/3] envelope[t], t/Sqrt[3]}, {t, 0, 3}, MaxRecursion -> 5,
PlotTheme -> "Classic",Exclusions -> None, MeshStyle -> {Thickness[1/144]}][[1]],
{{0, 0, 1}, {1, 1, 1}}];

enveloped = 
Table[
Graphics3D[{EdgeForm[Thickness[1/144]], 
Rotate[cube, x, {1, 1, 1}, {0, 0, 0}], Opacity[1/2], lozenge}, ViewVector -> {3, 1/2, -2},
ViewAngle -> 30 Degree, ViewCenter -> {1/2, 1/2, 1/2}, ViewVertical -> {1, 1, 1},
Background -> None, Boxed -> False, ImageSize -> 300, Lighting -> "Classic"],
{x, 0, 2 Pi/3 - Pi/48, Pi/24}]

Export["enveloped.gif", enveloped, "GraphicsList", "DisplayDurations" -> .05,
"AnimationRepetitions" -> Infinity, ImageSize -> 300, ImageResolution -> 144]

(* For the high resolution image, we need to change the Thickness Directive to *)
(* Thickness[1/288] then *)

Export["enveloped2.gif", enveloped, "GraphicsList", "DisplayDurations" -> .05,
"AnimationRepetitions" -> Infinity, ImageSize -> 600, ImageResolution -> 144]
$\endgroup$
4
  • 2
    $\begingroup$ Try SphericalRegion->True? $\endgroup$
    – Yves Klett
    Commented Mar 3, 2012 at 19:31
  • $\begingroup$ @Yves: Thanks. I did, but it produced the same varying size. I also tried ViewRange, but it only clips in distance from the ViewPoint, so anything affecting the width and height are not clipped. $\endgroup$
    – robjohn
    Commented Mar 3, 2012 at 19:45
  • $\begingroup$ Nice! By always displaying lozenge you should even get away with using ViewPoint, because the bounding box of the object is constant. $\endgroup$
    – Yves Klett
    Commented Mar 5, 2012 at 6:53
  • $\begingroup$ @Yves: That is true. Luckily, I didn't add lozenge until later, so that I could learn what the nomenclature of Graphics3D really means. $\endgroup$
    – robjohn
    Commented Mar 6, 2012 at 9:27

1 Answer 1

18
$\begingroup$

The variation in size is due to variation in camera position and viewing angle. Since ViewPoint uses special coordinates which depend on the bounding box it's better to use ViewVector instead (or even ViewMatrix if you can make it work). To keep the viewing angle fixed you should give an explicit value for ViewAngle. To place the object at the right position in the field of view you could use ViewCentre. For the example above you could do something like

cubes = Table[
  Graphics3D[{Rotate[cube, x, {1, 1, 1}, {0, 0, 0}]}, 
   ViewVector -> {3, 1/2, -2}, 
   ViewAngle -> 35 Degree,
   ViewCenter -> {.5, .5, .5},
   ViewVertical -> {1, 1, 1}, Boxed -> False],
  {x, 0, 2 Pi/3 - Pi/48, Pi/24}]
$\endgroup$
1
  • 1
    $\begingroup$ Ah, I shouldn't assume that ViewPoint is the point at which the viewer sits. I wrote a Camera Library for QuickDraw GX (when I worked at Apple), and I was assuming Mathematica's terminology was similar. I should read the documentation for ViewPoint, which says just what you said. I see that ViewVector and ViewCenter are the options I should have been setting. Thank you very much! $\endgroup$
    – robjohn
    Commented Mar 3, 2012 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.