|
Another in a series of
programming experiments. This program is FREE, not shareware. Just enjoy it. What Is synVertigo?
This is another of those
ideas which came to me while driving along I5 from Oregon
to California (well, technically I should say being
driven, since my lovely wife does all the driving.
This leaves me with plenty of time to stare at the
passing scenery).
Basically the
justification for the program was to see if I could get a
reasonably high frame rate of 3D rendering using
Microsoft Foundation Classes. But along the way I thought
it might be interesting to see if it was possible to have
a program generate the same level of vertigo-induced fear
that I find myself feeling in certain high altitude
circumstances. Partially, I reasoned, such a program
might be useful in desensitizing someone against that
panic (hopefully not so desensitized that they then
freely jump off the next high building!)
I got distracted during
development and ended up just focusing on the frame rate
issue. Perhaps I will return to this project and do
something more interesting with it. As it is, you have no
control whatever. It just does a lissajous flyover a
city, looking straight down. On a Pentium 2 300Mhz the
frame rate hits my target of 25 frames per second with
100 buildings. Not very spectacular compared to 3D
hardware accelerated programs, but this is a simple MFC
app using GDI calls for the drawing
Running the Program
Well, just download the
executable and run it.
It is a SDI-based MFC
app written in VC++ 4.2b
While it appears that
there are some controls, these are just the fluff which
VC++ generates automatically for you and that I was too
lazy to even remove. (My justification being that I would
eventually add a parachute/hangglider simulation and then
I would need some of those controls - but really I was
just too lazy, I only had a budget of 3 hours to write
this program, and I ended up spending 2 of those on the
fractal city builder again.)
If you left-click in the
window, it will generate a new city.
Along the top of the
window is a line of text indicating:
- FPS: Frames Per
Second (25 is the max possible)
- #visible: How many
of the 100 buildings have NOT been clipped
- #polys: How many
polygons were drawn this frame
- #collisions: How
many buildings are we actually INSIDE of at this
moment
The Math
The basic 3D math is the
same as in synVista, so I won't go into that here. The
vaguely interesting bits are:
- I have been
generally unsatisfied with the jerkiness of frame
rates in an MFC application when using the
standard or multimedia timers (WM_TIMER message).
Also, I find that it is only too easy to perform
operations within the WM_TIMER handler which are
not safe. What I did in this program was override
the ::Run method of the CWinApp class and
basically stick a call to a new method
"DoTick()" in the middle of the idle
loop of the ::Run method. You have to be a little
tricky to prevent windows from lowering your
priority, but it isn't all that hard to get it
right. This would then basically call DoTick() as
fast as possible (whenever not handling other
messages). However, that would create a situation
where the program would be unpleasant to look at
in 20 years when processors are all running at 30
terahertz. So I put in an explicit check and will
not call DoTick() within 40 msec of the last time
I started it. This creates the upper limit on
frame rate of 25 hertz. DoTick is the number
cruncher which moves the viewpoint and rebuilds
the polygon display list. Then it invalidates the
window rectangle and the OnPaint handler paints
the polygons.
- The city is an
array of building objects where each building is
defined by the x,y of the center of its shado on
the ground, a Z value which is its altitude and a
few extra values for future cleverness. The first
thing DoTick() does after calculating the new
view location (moving the camera, I mean), is to
sort the list of buildings by their distance to
the viewer. At this time any buildings whose
shadows are completely outside the 'view pyramid'
are discarded. The result is a sorted list of
buildings inside the viewing pyramid. We then
generate a list of polygons (3 4-sided polygons
per building) starting with the most remote
building and working towards the closest one
(this provides the hidden surface elimination).
- For each building
we need to determine which of the 3 surfaces we
can see, and which order they should be drawn in.
This is done by determining which 'octant' the
center of the building is in relative to our
position (the more clever way to do this would be
to compute the dot-product between a 'normal
vector' sticking out of the polygon and a vector
from the center of the polygon to the camera.
Based on the sign of the dot-product we would
know if the polygon was visible or not. BUt I was
able to use this cheat since I knew I wasn't
going to be viwing the buildings from all
possible angles.
- For each possible
octant relative to camera position, I computed a
list of the polygons in the order they should be
drawn. Again, a simple cheat. At the last
possible second, the actual 3D coordinates of the
8 points which comprise the building's corners
are computed and transformed into 2D screen
coordinates using the normal linear algebra
described in synVista. The 2D polygon is then
added to the end of the polygon list and the next
building is processed. When done, the polygn list
is perfectly sorted by distance (furthest away
polygon is first in list). If the camera stops
moving, this polygon list can be kept around
indefinitely with no additional computation
required.
- The OnPaint handler
does no thinking at all and just renders the
polygon list as fast as it can (in this case I
just use calls to CDC::Polygon)
- The fractal city
planner is similar to the fractal world builder
used in synVista, only instead of breaking the
world into 4 equal squares per recursion, I just
cut it in half, either horizontally or vertically
(random selection made at each level of
recursion). The recursion proceeds by cutting the
area into smaller and smaller pieces, withthe
probabilty at any level that a building will be
emitted filling the current piece instead of
further recursion. This results in buildings
coming in 3 basic shapes: square, horiz. rect,
and vert. rect.
- The tricky bit is
that the probability of a particular piece
becoming a building has to DECREASE the smaller
the piece becomes. Otherwise all the bits get
stuck in one corner of the available space since
the recursion is NOT done as a parallel process.
|
|
COPYRIGHTsynVertigo
is the property of Synthetic Reality and all rights are
reserved. If we can figure out a way to convince people
to pay for this, you can be sure we'll give it a try. But
for now it is expressly intended to provide a moment of
joy for the math geeks in the audience, looking for
number-crunching programs to show off their power
computers!
Thanks for your feedback
in advance!
Dan Samuel
Synthetic Reality Co.
|