The MuPAD^{®} 3D graphics model includes an observer at a specific
position, pointing a camera with a lens of a specific opening angle
to some specific focal point. The specific parameters "position",
"angle", and "focal point" determine the
picture that the camera will take.

When a 3D picture is created in MuPAD, a camera with an appropriate default lens is positioned automatically. Its focal point is chosen as the center of the graphical scene. The interactive viewer allows to rotate the scene which, in fact, is implemented internally as a change of the camera position. Also interactive zooming in and zooming out is realized by moving the camera closer to or farther away from the scene.

Apart from interactive camera motions, the perspective of a
3D picture can also be set in the calls generating the plot. One way
is to specify the direction from which the camera is pointing towards
the scene. This is done via the attribute `CameraDirection`

:

plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), CameraDirection = [-25, 20, 30]):

plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), CameraDirection = [10, -40, 10]):

In these calls, the position of the camera is not fully specified
by `CameraDirection`

.
This attribute just requests the camera to be placed at some large
distance from the scene along the ray in the direction given by the
attribute. The actual distance from the scene is determined automatically
to let the graphical scene fill the picture optimally.

For a full specification of the perspective, there are camera
objects of type `plot::Camera`

that
allow to specify the position of the camera, its focal point and the
opening angle of its lens:

position := [-5, -10, 5]: focalpoint := [0, 0, 0]: angle := PI/12: camera := plot::Camera(position, focalpoint, angle):

This camera can be passed like any graphical object to the `plot`

command
generating the scene. Once a camera object is specified in a graphical
scene, it determines the view. No "automatic camera"
is used:

plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), camera):

Camera objects can be animated:

camera := plot::Camera([3*cos(a), 3*sin(a), 1 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Frames = 100):

Inserting the animated camera in a graphical scene, we obtain an animated plot simulating a "flight around the scene":

plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), camera):

In fact, several cameras can be installed simultaneously in a scene:

camera1 := plot::Camera([3*cos(a), 3*sin(a), 1 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Name = "Camera 1"): camera2 := plot::Camera([2*cos(a), 2*sin(a), 2 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Name = "Camera 2"): plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), camera1, camera2):

Per default, the first camera produces the view rendered. After clicking on another camera in the object browser of the viewer (see section Viewer, Browser, and Inspector: Interactive Manipulation), the selected camera takes over and the new view is shown.

Next, we have a look at a more appealing example: the so-called "Lorenz attractor." The Lorenz ODE is the system

with fixed parameters *p*, *r*, *b*.
As a dynamic system for *Y* =
[*x*, *y*, *z*],
we have to solve the ODE
with
the following vector field:

f := proc(t, Y) local x, y, z; begin [x, y, z] := Y: [p*(y - x), -x*z + r*x - y, x*y - b*z] end_proc:

Consider the following parameters and the following initial
condition `Y0`

:

p := 10: r := 28: b := 1: Y0 := [1, 1, 1]:

The routine `plot::Ode3d`

serves
for generating a graphical 3D solution of a dynamic system. It solves
the ODE numerically and generates graphical data from the numerical
mesh. The plot data are specified by the user via "generators"
(procedures) that map a solution point (*t*, *Y*) to
a point (*x*, *y*, *z*) in
3D.

The following generator `Gxyz`

produces a 3D
phase plot of the solution. The generator `Gyz`

projects
the solution curve to the (*y*, *z*) plane
with *x* = - 20;
the generator `Gxz`

projects the solution curve to
the (*x*, *z*) plane
with *y* = - 20;
the generator `Gxy`

projects the solution curve to
the (*x*, *y*) plane
with *z* = 0:

Gxyz := (t, Y) -> Y: Gyz := (t, Y) -> [-20, Y[2], Y[3]]: Gxz := (t, Y) -> [Y[1], -20, Y[3]]: Gxy := (t, Y) -> [Y[1], Y[2], 0]:

With these generators, we create a 3D plot object consisting
of the phase curve and its projections. The following command calls
the numerical solver `numeric::odesolve`

to
produce the graphical data. It takes about half a minute on a 1 GHz
computer:

object := plot::Ode3d(f, [i/10 $ i=1..500], Y0, [Gxyz, Style = Splines, Color = RGB::Red], [Gyz, Style = Splines, Color = RGB::LightGrey], [Gxz, Style = Splines, Color = RGB::LightGrey], [Gxy, Style = Splines, Color = RGB::LightGrey]):

We define an animated camera moving around the scene:

camera := plot::Camera([-1 + 100*cos(a), 6 + 100*sin(a), 120], [-1, 6, 25], PI/6, a = 0..2*PI, Frames = 120):

The following `plot`

call also takes about
half a minute on a 1 GHz computer:

plot(object, camera, Axes = Boxed, TicksNumber = Low):

Next, we wish to fly *along the Lorenz attractor*.
We cannot use `plot::Ode3d`

,
because we need access to the numerical data of the attractor to build
a suitable animated camera object. We use the numerical ODE solver `numeric::odesolve2`

and
compute a list of numerical sample points on the Lorenz attractor.
This takes about half a minute on a 1 GHz computer:

Y := numeric::odesolve2(f, 0, Y0, RememberLast): timemesh := [i/50 $ i = 0..2000]: Y := [Y(t) $ t in timemesh]:

Similar to the picture above, we define a box around the attractor with the projections of the solution curve:

box := [-15, 20, -20, 26, 1, 50]: Yyz := map(Y, pt -> [box[1], pt[2], pt[3]]): Yxy := map(Y, pt -> [pt[1], pt[2], box[5]]): Yxz := map(Y, pt -> [pt[1], box[3], pt[3]]):

We create an animated camera using an animation parameter `a`

that
corresponds to the index of the list of numerical sample points. The
following procedure returns the *i*-th
coordinate (*i* = 1, 2, 3)
of the *a*-th
point in the list of sample points:

Point := proc(a, i) begin if domtype(float(a)) <> DOM_FLOAT then procname(args()); else Y[round(a)][i]; end_if; end_proc:

In the *a*-th
frame of the animation, the camera is positioned at the *a*-th
sample point of the Lorenz attractor, pointing toward the next sample
point. Setting `TimeRange = 0..n/10`

, the camera
visits about 10 points per second:

n := nops(timemesh) - 1: plot(plot::Scene3d( plot::Camera([Point(a, i) $ i = 1..3], [Point(a + 1, i) $ i = 1..3], PI/4, a = 1..n, Frames = n, TimeRange = 0..n/10), plot::Polygon3d(Y, LineColor = RGB::Red, PointsVisible = TRUE), plot::Polygon3d(Yxy, LineColor = RGB::DimGrey), plot::Polygon3d(Yxz, LineColor = RGB::DimGrey), plot::Polygon3d(Yyz, LineColor = RGB::DimGrey), plot::Box(box[1]..box[2], box[3]..box[4], box[5]..box[6], LineColor = RGB::Black, Filled = TRUE, FillColor = RGB::Grey.[0.1]), BackgroundStyle = Flat) ):

Was this topic helpful?