3D->2D perspective projection 
Author Message
 3D->2D perspective projection

A while ago, someone asked about doing perspective projection.  I did this a
few years ago for M2Amiga:

DEFINITION MODULE Perspective;

   FROM SYSTEM IMPORT FFP;

   FROM Windows IMPORT Window;
   VAR

       Wind : Window;

   CONST

      Xmin = -195.0; Xmax = 195.0;   (* These _MUST_ be symmetric *)

      Ymin = -195.0; Ymax = 195.0;

      Zmin = -195.0; Zmax = 195.0;

   TYPE

      Arc = POINTER TO PointList;

      PointList = RECORD
         x, y, z    : FFP;
         next, prev : Arc
      END;

      Object = POINTER TO ArcList;

      ArcList = RECORD
         Points     : Arc;
         next, prev : Object
      END;

   PROCEDURE OpenWind;

   PROCEDURE ClearWind;

   PROCEDURE SetObserver (x, y, z : FFP);  

   PROCEDURE Transform (x, y, z : FFP; VAR sx, sy : INTEGER);

   PROCEDURE AllocArc():Arc;

   PROCEDURE AddPoint (VAR arc : Arc; x, y, z : FFP);

   PROCEDURE PlotArc (arc : Arc);

   PROCEDURE FreeArc (VAR arc : Arc);

   PROCEDURE AllocObj () : Object;

   PROCEDURE AddArc (object : Object; arc : Arc);

   PROCEDURE PlotObj (object : Object);

   PROCEDURE AddObj (object : Object);

   PROCEDURE FreeObj (VAR object : Object);

   PROCEDURE Redraw;

   PROCEDURE Axes;

   PROCEDURE AddAxes;

END Perspective.

IMPLEMENTATION MODULE Perspective;

   FROM Windows    IMPORT Window, WinGadSet, WinGad, OpenWindow, Clear,
                          SetColor;
   FROM MathLibFFP   IMPORT sin, cos, sqrt;
   FROM Graphics   IMPORT Move, Draw, WritePixel;
   FROM Heap       IMPORT Allocate, Deallocate;

   FROM SYSTEM IMPORT FFP;
   (* need to add CloseWind, RemObj, RemAxes *)

   TYPE

      List = POINTER TO ObjList;

      ObjList = RECORD
         obj        : Object;
         prev, next : List
      END;

   CONST

      PointSize = SIZE (PointList);

      ObjSize   = SIZE (ArcList);

      ListSize  = SIZE (ObjList);

      Sx = INTEGER (2.0 * Xmax);

      Sy = INTEGER (2.0 * Ymax);

      Wx = 390-1;   Wx2 = FFP((Wx+1) DIV 2);

      Wy = 390-1;   Wy2 = FFP((Wy+1) DIV 2);

   VAR

      vx, vy, vz : FFP;

      R, r : FFP;

      ObjID : FFP;

      Objects : List;

      Ry11, Ry13, Ry31 : FFP;

      Rz11, Rz12, Rz21 : FFP;

      AxesObj : Object;

      axis : Arc;

      WindOpen : BOOLEAN;

   PROCEDURE Transform (x, y, z : FFP; VAR sx, sy : INTEGER);

      PROCEDURE Rotate (x, y, z : FFP; VAR rx, ry, rz : FFP);

         VAR
            x1, y1 : FFP;

         BEGIN
           x1 := Rz11 * x + Rz12 * y;     ry := Rz11 * y - Rz12 * x;
           rx := Ry11 * x1 + Ry13 * z;    rz := Ry11 * z - Ry13 * x1
      END Rotate;

      PROCEDURE Project (x, y, z : FFP; VAR sx, sy : INTEGER);

         VAR
            p : FFP;

         BEGIN
            p := Xmax / (R-x);
            sx := TRUNC (y * p + Wx2);
            sy := TRUNC (Wy2 - z * p);
            IF sx >  Wx THEN
               sx := Wx - 1;
            ELSIF sx <  0 THEN
               sx := 0
            END;
            IF sy >  Wy THEN
               sy := Wy - 1;
            ELSIF sy <  0 THEN
               sy := 0
            END;
      END Project;

      BEGIN
         Rotate (x, y, z, x, y, z);
         Project (x, y, z, sx, sy)
   END Transform;

   PROCEDURE OpenWind;
      BEGIN
         IF WindOpen THEN
            ClearWind
         ELSE
            OpenWindow (Wind, 0, 10, Wx, Wy, "The Smiths",
                        WinGadSet {moving, arranging});
            WindOpen := TRUE;
         END
   END OpenWind;

   PROCEDURE ClearWind;
      BEGIN
         Clear (Wind)
   END ClearWind;

   PROCEDURE SetObserver (x, y, z : FFP);

      VAR
         vx2, vy2 : FFP;

      BEGIN
         vx := x; vy := y; vz := z;
         vx2 := vx*vx; vy2 := vy*vy;
         R := sqrt (vx2 + vy2 + vz * vz);
         r := sqrt (vx2 + vy2);
         Ry11 := r / R;  Ry13 := vz / R;
         IF r = 0.0 THEN
            Rz11 := 1.0;      Rz12 := 0.0;
         ELSE
            Rz11 := vx / r; Rz12 := vy / r
         END
   END SetObserver;

   PROCEDURE AllocArc;

      VAR
         start : Arc;

      BEGIN
         Allocate (start, PointSize);
         start^.next := NIL;
         start^.prev := start;
         RETURN start
   END AllocArc;

   PROCEDURE AddPoint (VAR arc : Arc; x, y, z : FFP);

      VAR
         node : Arc;

      BEGIN
         Allocate (node, PointSize);
         node^.x := x; node^.y := y; node^.z := z;
         node^.next := NIL;
         node^.prev := arc^.prev;
         arc^.prev^.next := node;
         arc^.prev := node
   END AddPoint;

   PROCEDURE FreeArc (VAR arc : Arc);

      VAR
         mark : Arc;

      BEGIN
         IF arc^.next # NIL THEN
            mark := arc^.prev;
            WHILE arc^.next # mark DO
               Deallocate (arc^.prev);
               arc := arc^.next
            END;
            Deallocate (arc^.prev)
         END;
         Deallocate (arc)
   END FreeArc;

   PROCEDURE PlotArc (arc : Arc);

      VAR
         sx, sy, eatme : INTEGER;

      BEGIN
         arc := arc^.next;
         WITH arc^ DO
            Transform (x, y, z, sx, sy)
         END;
         arc := arc^.next;
         IF arc = NIL THEN
           eatme := WritePixel (Wind^.rPort, sx, sy )
         ELSE
            Move (Wind^.rPort, sx, sy);
            REPEAT
               WITH arc^ DO
                  Transform (x, y, z, sx, sy)  
               END;
               Draw (Wind^.rPort, sx, sy);
               arc := arc^.next
            UNTIL arc = NIL
         END
   END PlotArc;

   PROCEDURE AllocObj () : Object;

      VAR
         start : Object;

      BEGIN
         Allocate (start, ObjSize);
         start^.Points := AllocArc();
         AddPoint (start^.Points,ObjID,ObjID,ObjID);
         ObjID := ObjID + 0.05;
         start^.prev := start;
         start^.next := NIL;
         RETURN start
   END AllocObj;

   PROCEDURE FreeObj (VAR object : Object);

      VAR
         mark : Object;

      BEGIN
         IF object^.next # NIL THEN
            mark := object^.prev;
            WHILE object^.next # mark DO
               FreeArc (object^.prev^.Points);
               Deallocate (object^.prev);
               object := object^.next
            END;
            FreeArc (object^.Points);
            Deallocate (object^.prev)
         END;
         FreeArc (object^.Points);
         Deallocate (object)
   END FreeObj;

   PROCEDURE AddArc (object : Object; arc : Arc);

      VAR
         node : Object;

      BEGIN
         Allocate (node,ObjSize);
         node^.Points := arc;
         node^.next := NIL;
         node^.prev := object^.prev;
         object^.prev^.next := node;
         object^.prev := node
   END AddArc;

   PROCEDURE PlotObj (object : Object);
      BEGIN
         object := object^.next;
         WHILE object # NIL DO
            PlotArc (object^.Points);
            object := object^.next
         END
   END PlotObj;

   PROCEDURE AddObj (object : Object);

      VAR
         node : List;

      BEGIN
         Allocate (node, ListSize);
         node^.obj := object;
         node^.next := NIL;
         node^.prev := Objects^.prev;
         Objects^.prev^.next := node;
         Objects^.prev := node
   END AddObj;

   PROCEDURE Redraw;

      VAR
          objList : List;

      BEGIN
         ClearWind;
         objList := Objects^.next;
         WHILE objList # NIL DO
            PlotObj (objList^.obj);
            objList := objList^.next
         END
   END Redraw;

   PROCEDURE Axes;
      BEGIN
         PlotObj (AxesObj)
   END Axes;

   PROCEDURE AddAxes;
      BEGIN
         Axes;
         AddObj (AxesObj)
   END AddAxes;

BEGIN
   WindOpen := FALSE;
   SetObserver (Xmax+25.0,Ymax+25.0,Zmax+25.0);
   ObjID := 12.0;
   Allocate (Objects, ListSize);
   Objects^.obj := NIL;
   Objects^.next := NIL;
   Objects^.prev := Objects;
   AxesObj := AllocObj();
   axis := AllocArc();
   AddPoint (axis,Xmax, 0.0, 0.0);
   AddPoint (axis,Xmin, 0.0, 0.0);
   AddArc (AxesObj, axis);
   axis := AllocArc();
   AddPoint (axis,0.0, Ymax, 0.0);
   AddPoint (axis,0.0, Ymin, 0.0);
   AddArc (AxesObj, axis);
   axis := AllocArc();
   AddPoint (axis,0.0, 0.0, Zmax);
   AddPoint (axis,0.0, 0.0, Zmin);
   AddArc (AxesObj, axis);
END Perspective.



Tue, 02 Dec 1997 03:00:00 GMT  
 
 [ 1 post ] 

 Relevant Pages 

1. 3D rotation and projection in Assembler

2. Developing 3D perspective

3. 2D (or better 3D) packages for VisualWorks ?

4. 2D and 3D Array Classes

5. 3D array to 2D concatenate array?!

6. Converting Nx15 x1000 3D array to 15by1000*N 2D array

7. LOGO-L> Re: mswlogo perspective

8. LOGO-L> mswlogo perspective

9. 3d-coordinate to 2d coordinate

10. LOGO-L> ChessBoard in Perspective

11. LOGO-L> Perspective OFF

12. ANN: disipyl - a 2D and 3D plotting library for Python/Jython

 

 
Powered by phpBB® Forum Software