[fpc-pascal] Calculating Pixels to represent 3D coordinates

Karoly Balogh (Charlie/SGR) charlie at scenergy.dfmk.hu
Tue Sep 17 23:26:18 CEST 2019


On Tue, 17 Sep 2019, James Richters wrote:

> What I'm trying to do is much simpler than rendering a 3D object..  All
> I'm trying to do is display a 3D line drawing or wireframe on the
> screen.  I don't need it to dynamically rotate or anything, and it
> doesn't need to show any surfaces, textures, lighting, reflections, or
> shadows, just give a representation of the XYZ points and lines
> connecting 2 pair of XYZ coordinates on the screen.  The purpose of this
> is to show a 3D representation of a CNC tool path including the Z
> movements.

Well, it all boils down to the projection you want to make while you
transform from your coordinates from 3D to 2D. For the most simple
"isometric" projection with no perspective, you just throw away one of the
XYZ coordinates, and use the other two - this will result in a simple
"camera" which views at your object from either the front (XY), side (YZ)
or from the top (XZ). (Actually, this also depends on wether in your
coordinate system Y or Z represents depth, 3D editors/engines don't even
agree on this one, the code below assumes "Z" is depth.)

For a simple "perspective" projection, you can use a simplistic formula,
something like:

{ untested pseudocode }
procedure perspective_vertex(const v: T3DVertex; ZCenter: single;
          out X, Y: single);
  rdist1: single;
  zdist1:=1.0 / (v.z - zcenter);
  X:=(v.x * zcenter) * zdist1;
  Y:=(v.y * zcenter) * zdist1;

This will put some sort of "perspective" on your 3D vertex, depending on
its Z coordinate. The ZCenter should be larger than the maximum dimension
of your object facing the "camera". Note that this formula is massively
simplified, but serves as the most simple perspective projection.

After this, you can use x/y coordinates to feed the wireframe drawer using
whatever drawing unit you see fit. You might need to do inc(x,width/2);
and inc(y,height/2); and/or multiply your values with a certain
scale-factor, depending on the size of your object, and how its
coordinates map to your 2D resolution.

All of the above methods assume that your object's 3D center resides at
the origo (center of the coordinate system). Anything more complicated
would require some proper matrices to be set up and calculate a full
series of model, view, and projection matrices, as others have already
mentioned, or would require pre-processing your 3D coordinates in a
certain way, so this simplistic formula can work.

Hope this helps,

(Ps: actually, the FPC Packages contain two similar examples of a rotating
3D cube, for PalmOS and Atari, both written by me, to showcase the m68k
code generator and the units for these retro/niche OSes. They're at (SVN

- packages/tosunits/examples/gemcube.pas
- packages/palmunits/examples/palmcube.pas

Showcased here (with video):

These show this most simplistic form of 3D calculation, and they also use
fixed point math, as that fit the only a few mhz fast 68000 CPUs in these
machines. But the basic algo and formula is the same with float and on
faster platforms. Now I'm quite tempted to make a ptc-graph version. :) )

More information about the fpc-pascal mailing list