Node:Focuses Getstart, Next:, Previous:Projections, Up:Pictures



Focuses

The perspective transformation requires a focus; as a consequence, outputting a Picture requires an object of class Focus. Picture::output() takes an optional pointer-to-Focus argument, which is 0 by default. If the default is used, (or 0 is passed explicitly), the global variable default_focus is used. See Focus Reference; Global Variables.

A Focus can be thought of as the observer of a scene, or a camera. It contains a Point position for its location with respect to 3DLDF's coordinate system, and a Point direction, specifying the direction where the observer is looking, or where the camera is pointed. The Focus can be rotated freely about the line PD, where P stands for position and D for direction, so a Focus contains a third Point up, to indicate which direction will be "up" on the projection, when a Picture is projected.

The projection plane q will always be perpendicular to the line PD, or to put it another way, the line PD, is normal to q.

Unlike the traditional perspective construction, where the distance from the focus to the center of vision fixes both the location of the focus in space, and its distance to the picture plane,1 these two parameters can be set independently when the perspective transformation is used. The distance from a Focus to the picture plane is stored in the data member distance, of type real.

A Focus can be declared using two Point arguments for position and direction, and a real argument for distance, in that order.

     Point pos(0, 5, -10);
     Point dir(0, 5, 10);
     Focus f(pos, dir, 10);
     
     Point center(2, 0, 3);
     Rectangle r(center, 3, 3);
     r.draw();
     current_picture.output(f);
     


[Figure 60. Not displayed.]

Fig. 60.

The "up" direction is calculated by the Focus constructor automatically. An optional argument can be used to specify the angle by which to rotate the Focus about the line PD.

     Point pos(0, 5, -10);
     Point dir(0, 5, 10);
     Focus f(pos, dir, 10, 30);
     Point center(2, 0, 3);
     Rectangle r(center, 3, 3);
     r.draw();
     current_picture.output(f);
     


[Figure 61. Not displayed.]

Fig. 61.

Alternatively, a Focus can be declared using three real arguments each for the x, y, and z-coordinates of position and direction, respectively, followed by the real arguments for distance and the angle of rotation:

     Focus f(3, 5, -5, 0, 3, 0, 10, 10);
     Point center(2, 0, 3);
     Rectangle r(center, 3, 3);
     r.draw();
     current_picture.output(f);
     


[Figure 62. Not displayed.]

Fig. 62.

Focuses contain two Transforms, transform and persp. A Focus can be located anywhere in 3DLDF's coordinate system. However, performing the perspective projection is more convenient, if position and direction both lie on one of the major axes, and the plane of projection corresponds to one of the major planes. transform is the transformation which would have this affect on the Focus, and is calculated by the Focus constructor. When a Picture is output using that Focus, transform is applied to all of the Shapes on the Picture, maintaining the relationship between the Focus and the Shapes, while making it easier to calculate the projection. The Focus need never be transformed by transform. The actual perspective transformation is stored in persp.

Focuses can be moved by using one of the setting functions, which take the same arguments as the constructors. Currently, there are no affine transformation functions for moving Focuses, but I plan to add them soon. If 3DLDF is used for making animation, resetting the Focus can be used to simulate camera movements:

     beginfig(1);
     Point pos(2, 10, 3);
     Point dir(2, -10, 3);
     Focus f;
     Point center(2, 0, 3);
     for (int i = 0; i < 5; ++i)
       {
         f.set(pos, dir, 10, (15 * i));
         Rectangle r(center, 3, 3);
         r.draw();
         current_picture.output(f);
         current_picture.clear();
         pos.shift(1, 1, 0);
         dir.rotate(0, 0, 10);
       }
     endfig(1);
     


[Figure 63. Not displayed.]

Fig. 63.

In [the previous figure] , current_picture is output 5 times within a single MetaPost figure. Since the file passed to MetaPost is called persp.mp, the file of Encapsulated PostScript (EPS) code containing [the previous figure] is called persp.1. To use this technique for making an animation, it's necessary to output the Picture into multiple MetaPost figures.

     Point pos(2, 10, 3);
     Point dir(2, -10, 3);
     Focus f;
     Point center(2, 0, 3);
     for (int i = 0; i < 5; ++i)
       {
         f.set(pos, dir, 10, (15 * i));
         Rectangle r(center, 3, 3);
         r.draw();
         beginfig(i+1);
         current_picture.output(f);
         endfig();
         current_picture.clear();
         pos.shift(1, 1, 0);
         dir.rotate(0, 0, 10);
       }
     

Now, running MetaPost on persp.mp generates the EPS files persp.1, persp.2, persp.3, persp.4, and persp.5, containing the five separate drawings of r.


Footnotes

  1. I believe this to be true, but I'm not certain.