For a simulation of a laser-based sensor I am designing, I want to verify how four points projected on a surface would appear from a camera. And so I have undertaken to implement a Graphics3D visualization.
The visualization places 4 lasers in a pyramid-like arrangement with a camera 20 centimeters two one side viewing the laser's projections. My notebook code produces two views: one outside a room the sensor would operate within and a second view point which represents the camera which is rotated with the lasers. The Euler angles and x,y,z coordinates of the camera-laser ensemble can be controlled using sliders.
My problem is that in the simulation the camera is be being automatically oriented. And so the view from a real physical camera is not reproduced because Mathematica is adjusting the viewpoint. If the camera and laser rotated together than rotations in Psi would cause the camera to rotate in lockstep with the laser and the view should be unchanged. Likewise shifts in x and y shouldn't make the camera jiggle so.
How can I control the camera orientation to produce a more coherent simulation?
The notebook code is:
\[Delta] = N[(38*Degree)/2];
PointPlaneIntersection[{{x1_, y1_, z1_},
{x2_, y2_, z2_}, {x3_, y3_, z3_}},
{{x4_, y4_, z4_}, {x5_, y5_, z5_}}] :=
Module[{t = -Det[{{1, 1, 1, 1}, {x1, x2, x3, x4},
{y1, y2, y3, y4}, {z1, z2, z3, z4}}]/
Det[{{1, 1, 1, 0}, {x1, x2, x3, x5 - x4},
{y1, y2, y3, y5 - y4}, {z1, z2, z3,
z5 - z4}}]}, Point[{x4 + t*(x5 - x4),
y4 + t*(y5 - y4), z4 + t*(z5 - z4)}]];
UnitSpherePoint[azimuth_, polar_] :=
{Cos[azimuth]*Sin[polar], Sin[azimuth]*Sin[polar],
Cos[polar]};
Manipulate[rx := RotationMatrix[\[Theta], {1, 0, 0}];
ry := RotationMatrix[\[Phi], {0, 1, 0}];
rz := RotationMatrix[\[Psi], {0, 0, 1}];
line1 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[0,
Pi + \[Delta]] + {x, y, z}};
line2 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
Pi/2, Pi + \[Delta]] + {x, y, z}};
line3 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
Pi, Pi + \[Delta]] + {x, y, z}};
line4 = {{x, y, z}, rx . ry . rz . UnitSpherePoint[
3*(Pi/2), Pi + \[Delta]] + {x, y, z}};
cline = {{x + 0.2, y, z},
rx . ry . rz . UnitSpherePoint[0, Pi] +
{x + 0.2, y, z}}; roomplane :=
{{0, 0, 0}, {30, 0, 0}, {0, 15, 0}};
Scene := Graphics3D[{Red, Opacity[1],
PointPlaneIntersection[roomplane, line1],
PointPlaneIntersection[roomplane, line2],
PointPlaneIntersection[roomplane, line3],
PointPlaneIntersection[roomplane, line4], White,
Opacity[0.1], Cuboid[{0, 0, 0}, {30, 15, 6}]},
Boxed -> False, Lighting -> "Neutral"];
Grid[{{Show[Scene], Show[Scene, ViewVector -> cline,
ViewAngle -> 64*Degree, RotationAction ->
"Clip"]}}], {{x, 15}, 0, 30}, {{y, 7.5}, 0, 15},
{{z, 3}, 0, 6}, {{\[Theta], Pi}, 0, 2*Pi},
{{\[Phi], Pi}, 0, 2*Pi}, {{\[Psi], Pi}, 0, 2*Pi}]
As I guess you are fully aware, you need to somehow specify the camera position, orientation and angle of view. In typical Mathematica fashion, you can do this by specifying a million different subsets of interrelated options. The following is how I would do it:
Firstly, the camera position. This can be specified in graphics coordinates (ViewVector
) or relative to the bounding box (ViewPoint
). Either of these should work. While specifying the camera position, remember that the perspective effects diminish when you move further away from ViewCenter
.
The camera orientation is defined by the ViewCenter
(specifying 2 degrees of the camera orientation) and ViewVertical
(the direction that will end up being vertical in the 2D projection). ViewCenter
is usually fine by default if you have specified a PlotRange
.
Finally, Automatic
is most often fine for ViewAngle
if you have a well defined PlotRange
, but you might need to set SphericalRegion
to true if you are moving around your subject.
All the view geometry options are listed here, but I guess ViewRange
is about the only one I haven't mentioned above :). As far as I can tell, you just need to specify ViewVertical
?