# Extract values for ViewMatrix from a Graphics3D

Under More Information in the help page of ViewMatrix the following entry can be found

With the setting ViewMatrix->Automatic, explicit forms for the matrix m can be found using AbsoluteOptions[g,ViewMatrix].

Trying this with a basic example

gr = Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}];
AbsoluteOptions[gr, ViewMatrix]

(* Out[11]= {ViewMatrix -> Automatic} *)

shows, that this does not work as I would have expected it. Even setting ViewMatrix explicitely to Automatic does not help. I tried this on Linux and MacOSX.

Can someone tell me how this is supposed to be used and how I can extract explicit values for the viewing matrix which is used for the projection?

-
According to the documentation, "With the default setting ViewMatrix->Automatic, the matrices {t,p} are found automatically from the settings for options such as ViewPoint, ViewVertical, and ViewAngle." It may be useful to take examine the code at demonstrations.wolfram.com/UsingViewMatrix to see how the default settings can be used to produce the two needed matrices. –  David Carraher Mar 26 '12 at 17:57

The documentation is wrong. It should have been fixed, but AbsoluteOptions does not work with ViewMatrix (on all platforms). M- introduced interactive 3D graphics since V6, and after that getting values through AbsoluteOptions (which is an old function) becomes very tricky since the Kernel (who evaluates the option) cannot fully know what is happening on FrontEnd side. To compare, before V6, the Kernel was solely responsible for rendering 3D scene (Postscript!), and of course it could tell every matrix value.

Instead, you can try to use 5 values that can define the matrix using Dynamic: ViewPoint, ViewAngle, ViewVertical, ViewCenter, and ViewRange.

For instance, the following example takes those 5 values from one graphics, and use it for another:

DynamicModule[
{point = {1.3, -2.4, 2}, angle = N[35 Degree], vertical = {0, 0, 1},
center = Automatic},
Grid[{{
Framed[
Graphics3D[{
(* Objects *)
EdgeForm[], Specularity[White, 20],
FaceForm[Red], Sphere[{-0.2, -0.1, -0.3}, .2],
FaceForm[Blue], Cylinder[{{0., 0.3, -.5}, {0., 0.3, 0.}}, .1],
FaceForm[Green], Cone[{{0.2, 0., -0.5}, {0.2, 0., -0.1}}, .2]
},
Boxed -> True, Lighting -> "Neutral",
ImageSize -> 300, RotationAction -> "Clip",

(* View control *)
ViewPoint -> Dynamic[point],
ViewAngle -> Dynamic[angle],
ViewVertical -> Dynamic[vertical],
ViewCenter -> Dynamic[center]
],
FrameStyle -> LightGray],

(* The second object *)
Framed[
Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3},
ImageSize -> 300, Axes -> False,
(* View control *)
ViewPoint -> Dynamic[point],
ViewAngle -> Dynamic[angle],
ViewVertical -> Dynamic[vertical],
ViewCenter -> Dynamic[center]
],
FrameStyle -> LightGray]
}}]
]

Examples:

and

This free course explains about the values in vary detail (with some cool demos--OK. shameless self-promotion :) ):

Wolfram Training: Visualization: Advanced 3D Graphics

Also, in essence, you can reconstruct the view matrix and projection matrix out of those values, but I need to take a look at an old textbook to make sure that I am not saying something wrong :)

-
+1 Very useful diagram and explanation. Much better than the documentation for the individual View settings! –  David Carraher Mar 26 '12 at 20:23
+1 for this very illustrative answer, although I already know all this from OpenGL, rendering, and so on. The reason, why I specifically asked how to extract the used projection is, because I want to transform the underly 3d mesh points by myself. For this, I need the used projection for any arbitrary Mathematica Graphics3D. Can we get this from the FE? –  halirutan Mar 27 '12 at 12:26
@Yu-Sung Chang, since this clearly answers my question, I'll accept this. Maybe, I ask a follow-up in another post and I would be grateful when you would look at it too;-) –  halirutan Mar 27 '12 at 14:40
@halitutan, Certainly! –  Yu-Sung Chang Mar 27 '12 at 16:39
This image should be part of the documentation. –  István Zachar May 9 '12 at 13:20

It got a bit out of hand, but here's a way to construct a ViewMatrix pair from the triple ViewVector, ViewAngle, and ViewVertical. The left figure is the Graphics3D object using ViewVector, ViewAngle, and ViewVertical and the right is the one using ViewMatrix. If you rotate the left figure or scale it (by dragging the figure while keeping Alt depressed), the ViewMatrix is updated automatically.

DynamicModule[{tt, pp, bb, gr, center, scale, v1, vv,
theta, phi, alpha, vert, viewAngle},
gr = {Cuboid[{-1, -1, -1}, {0, 0, 0}],
Cuboid[], {Red, Cuboid[{-1, 0, 0}, {0, 1, 1}]},
{Blue, Cuboid[{2, 0, 1}, {3, 1, 2}]}};
bb = PlotRange[Graphics3D[gr]];
scale = 1/Abs[#1 - #2] & @@@ bb;
center = Mean /@ bb;
vv = {{6, 5, 2}, Mean /@ bb};
v1 = (vv[[1]] - center);
vert = {0, 0, 1} - {0, 0, 1}.v1 v1;
viewAngle = 50 Degree;

theta[v1_] := ArcTan[v1[[3]], Norm[v1[[;; 2]]]];
phi[v1_] := If[Norm[v1[[;; 2]]] > .0001, ArcTan[v1[[1]], v1[[2]]], 0];
alpha[vert_, v1_] := ArcTan[{-Sin[phi[v1]], Cos[phi[v1]], 0}.vert,
Cross[v1/Norm[v1], {-Sin[phi[v1]], Cos[phi[v1]], 0}].vert];

tt[v1_, vert_, center_, r_] := TransformationMatrix[
RotationTransform[-alpha[vert/scale, v1], {0, 0, 1}].
RotationTransform[-theta[v1], {0, 1, 0}].
RotationTransform[-phi[v1], {0, 0, 1}].
ScalingTransform[r {1, 1, 1}].
TranslationTransform[-center]];

pp[ang_] := {{1, 0, - Tan[ang], 1}, {0, 1, - Tan[ang ], 1}, {0,
0, -Tan[ang ], 0}, {0, 0, -2 Tan[ang] , 2}};

Panel[Column[{Labeled[#,
Style["Transforming ViewVector/ViewVertical/ViewAngle to ViewMatrix",
15, FontFamily -> "Helvetica", Bold],
Top, Background -> White, Frame -> True, FrameStyle -> Gray] &@
Grid[{
{Labeled[Dynamic@
Graphics3D[{gr}, Axes -> True, AxesLabel -> {"x", "y", "z"},
ViewAngle -> Dynamic[viewAngle],
ViewVector -> Dynamic[vv, (vv = #; center = vv[[2]]; v1 = vv[[1]] - center) &],
ViewVertical -> Dynamic[vert],
ImageSize -> 270],
Style["ViewVector, ViewVertical, ViewAngle", FontFamily -> "Helvetica", Bold],
Top, Frame -> True],

Labeled[Dynamic@Graphics3D[{gr},
ViewMatrix -> {tt[v1, vert, center, Cot[viewAngle/2]/Norm[v1]], pp[viewAngle/2]},
Axes -> True, AxesLabel -> {"x", "y", "z"}, ImageSize -> 270],
Style["ViewMatrix", Bold, FontFamily -> "Helvetica"], Top,
Frame -> True]},

{Dynamic@ Labeled[N[{tt[v1, vert, center, Cot[viewAngle/2]/Norm[v1]],
pp[viewAngle/2]}] /. {a_?NumericQ :> NumberForm[a, 3]} //
MatrixForm[#, TableDirections -> Row] &,
Style["ViewMatrix", 12, FontFamily -> "Helvetica", Bold], Left], SpanFromLeft}},
Spacings -> {1, 2}],
Button["Print ViewMatrix",
Print[N[{tt[v1, vert, center, Cot[viewAngle/2]/Norm[v1]], pp[viewAngle/2]}]],
ImageSize -> 150]},
Alignment -> Left]
]
]

-
+1 for getting out of hand! ;) –  R Hall Jul 5 '12 at 11:23
If you ever come back to the site, I just wanted to let you know I've found this answer useful many times now, especially tt. –  Michael E2 Jul 31 '13 at 22:06