Extract values for ViewMatrix from a Graphics3D
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 :)
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]
]
]