From: Dave Stampe-Psy+Eng <dstamp@watserv1>
Date: Sat, 25 Apr 92 17:38:38 -0400

Just finished up the stereoscopic vision support for REND386.
I'll describe it and the math behind it, and hopefully it'll
fit most systems.

SEGA AND POWERGLOVE DRIVER MODULE

The soft/hardware basis of this is a new interrupt driver that supports
Sega glasses and the PowerGlove.  All you have to do with this one
is "set it and forget it"-- it's fully self calibrating.  You can also
eliminate the Sega or Powerglove support.

Basically, the PowerGlove driver polls the glove (serial bit-banger) till
it gets a 0xA0 "packet ready" code, then receives an 8-bit packet.  The
polling is done about every 5.5 mS, via interrupt.  The rest of the
interface is much like the one we did in November, but much more
reliable and simplified.  You call glove_ready() till you get a 1
(packet ready) or 2 (packet and RX flags ready), then glove_read() to
get a copy of the data.  Data is denoised, and deglitching is switchable.
The Z axis is now denoised but rotate is not (hysterisis makes it unusable).

The PG driver is adaptable to most interfaces, but the present code is
configured for the printer port method. It adapts to your computer's speed,
but uses I/O space accesses rather than counting loops in its delay
timing loop, so is not sensitive to cache effects like the old one was.

The Sega driver does not rely on your VGA card having a vertical interrupt.
Instead, it uses a synchronized interrupt driver.  The setup routine finds
the length of a vertical scan time in timer clocks (1.19 MHz), then
sets up the timer to be 100 uS faster. If a PG is used, 2 or 3 interrupts
are done per frame so as to service the PG driver too.)  Every 5 frames,
the interrupts are resynchronized to the video by waiting for the retrace:
about 500 uS (long enough to assure that interrupt blockages will not
cause full-frame time stalls).  Seems to work: I tried it on 60 Hz and
72 Hz cards, and it's very hard to crash.  The Sega interrupt calls a
routine, so you can replace the default serial-port Sega circuit with
something else.

Total CPU overhead for this driver is something like 0.7% for the Sega
driver, and 4.5% for the Powerglove driver.  Not too bad. Even the PC
clock keeps time properly.

STEREOSCOPIC VIEW MODULE

Every time I think about doing stereo images I have to figure out "what to
draw, where, and how big?"  Well, no more-- I sat down and figured out all
the math and came up with a geometric model relating world model stuff
to real-world stuff.  Now all you need to do is fill in a few variables
and let a routine compute left and right eye views based on the "cyclopian"
basis view.

The math is based on simple "similar triangle" stuff, but here are the
results.

Data Required:

psd -> physical screen-to-eye distance in mm
psw -> width of screen (or view window) in mm
swp -> screen (or view window) width in pixels
pes -> physical eye seperation in mm (62 mm is the average)
pcd -> physical convergence distance in mm (usually same as psd)
wsr -> world scaling ratio (units per mm)

Formula:

zoom = 2 * psd / psw

--the z-plane (image plane) distance and sets overall magnification
and perspective in the image. Multiply by 65536 for the REND386 parameter.

x_fixup = (psd * pes * swp)/(2 * pcd * psw)

--used to displace the image on the screen to the side to correct the
convergence distance (displace x_fixup pixels to the left for the left eye,
to the right for the right eye view).  Had to update some of the REND386
view definition code to let it do this.  While I was at it, I added the
ability to flip the image horizontally or vertically, in case you use
mirrors in a HMD, or have to flip an LCD panel to fit.

world_iod = (pes * wsr) / 2

--used to compute left and right eye "camera positions".  To do this,
get the 3x3 camera translation matrix[ A B C ]
				     [ D E F ]
				     [ G H I ]
and modify the camera position by these values:
    xinc = world_iod * A
    yinc = world_iod * B
    zinc = world_iod * C
Add these to the camera position for the right eye, subtract for the
left eye views.  Again, REND386's VIEW structure was updated to make
the matrix available.  I also added two routines to allow you to set
a viewpoint from a matrix, or convert a viewpoint to a matrix.

world_conv_dist = pcd * wsr

--for an object to appear at the convergence point (should be the
monitor screen, or the focal distance if a HMD is used), it should
be this distance from the viewpoint.  If you do this, you can use wsr
to set the size of objects in the "real world"!  Not easy to explain
how this works, but basically it's changing your eye spacing while
moving you closer to the object, thus changing its size.  Confused?
Good!

HEAD MOUNTED DISPLAYS

All this applies for headmounted displays, but of course the screen
size and distance becomes hard to compute.  Putting a display close to
your eyes requires a lens to let you focus on it, but the lens also
changes the distance:size ratio measurably, largely due to its effect on
eye movement scaling.  Also, the displays are close to your eyes and
are offset by somewhat more than half your eye spacing.  So you've
got to add an offset in addition to the stereoscopic offset here.  This
will be strongly influenced by the lens system as well.  I assume you'd
use trial and error, making the offset adjustable (this is a good idea
anyway, as it will make the display more comfortable for different eye
spacings).

An interesting situation is when the HMD display is tilted instead of
parallel to your forehead.  Here (unless your lens system fixes it)
the image needs more magnification at one side.  To do this, pan the
view transform angle (using matrix multiplication AFTER having set up
the view and before rendering) and add an offset to the display (BEFORE
setting up the view).  Result: perfect compensation for a tilted display
(but not for lens distortion, unfortunately).

RESULTS

I haven't done a 3D glove object yet, but the driver works fine.  The 3D
and Sega stuff is working great, but I don't like the smearing effect or
the dark image they produce much.  I seem to notice some stretching in
depth, but everyone who's tried it says it's just me...
Speed is of course half that without stereo.  That gives about 7.5 fps
for the 500-poly bishban.plg demo in 256-color mode, and about 14 fps
on a 486/33.  A 100-poly test is about 15 fps on a 486/25 (the full glove
will be 65-85 polys).

The code for this should be out soon.  Have to figure out how to
package it without invalidating the last release...

--------------------------------------------------------------------------
| My life is Hardware,                    |                              | 
| my destiny is Software,                 |         Dave Stampe          |
| my CPU is Wetware...                    |                              | 
| Anybody got a SDB I can borrow?         | [email-masked] |
__________________________________________________________________________