From: John Stone (johns_at_ks.uiuc.edu)
Date: Sun Jul 16 2000 - 14:06:08 CDT

Hi,

[JS - moved my original post to the end of this message]
On Sun, Jul 16, 2000 at 10:05:02AM -0700, Tim Freeman wrote:
> Are you using OpenGL? If so, how do you render spheres?

Yes, we use OpenGL. We're drawing spheres using display listed
gluSpheres. I'll point out some of the issues I have with other
methods below.

> There are two ways I know of to render a sphere in OpenGL: either draw
> a bunch of polygons (probably by calling gluSphere, maybe with the
> optimization of using display lists), or create a depth buffer for the
> sphere and render it with a primitive that renders a depth buffer
> (specifically glDrawPixels with the format GL_DEPTH_COMPONENT, making
> sure that the background pixels in the texture are transparent).

I'm aware of quite a number of different tricks for drawing spheres quickly,
depending on what amount of quality you're willing to trade for the speed.
You can draw spheres by using texture mapped quads (no depth image though),
glDrawPixels (as you mention), gluSpheres with or without display lists,
other sphere tesselations using qaud or triangle strips, etc, etc. Which
type of sphere algorithm you use depends on whether or not it is important
to you to have good hidden surface removal, speed, flexible lighting,
perspective correct rendering, lots of colors, etc... One of the problems
with using the tricks involving pre-computed sphere images is that you have
to re-compute the template image every time the lighting conditions or
rendered materials change. If you use 40 different colors to render your
scene, you have to generate sphere template images for each of the colors.
If you vary the lighting parameters or material characteristics of the
spheres, then those have to be re-computed as well. (you you need to build
a big lookup table with pre-computed spheres..) These aren't so bad if you
limit your color changes and materials changes per scene draw, but if you
start taking into account things like scaling your template images to the
correct size for the radius of the atom being drawn, and then having to
correct the depth image accordingly, it really starts to chisel into
the performance that you work so hard to get out of it. If one is willing
to compromise some aspect of rendering precision, then you can always
find a way to render faster. Even using gluSpheres is a compromise, since
we'd ideally want a sphere tesselated with a million triangles, but that
would be far far far too slow.

> When developing Fungimol I tried both. If you draw, say, 20 polygons
> per sphere, then you've instantly reduced your graphics performance by
> a factor of 20.

Well, that all depends on the relative speed of glDrawPixels vs. display
listed triangles, but sure, a board with a fast AGP bus could probably render
using glDrawPixels() at least 5 times faster than with gluSphere, but this
may not always be the case. At some point the speed of the bus connecting
the CPU and the framebuffer is going to be the limiting factor. Since
glDrawPixels() doesn't really have a way of caching images on the
framebuffer's local memory, it will eventually be slower than using
glCallList() to render the gluSphere, simply because all of the geometry
of the gluSphere will already be cached on the framebuffer. This isn't
the case with the graphics boards we have this year, but its definitely
coming. Perhaps one could use a non-visible section of framebuffer memory
to perform glCopyPixels() for drawing spheres, this would be a nice trick
that would mostly eliminate eliminate the CPU to framebuffer bus on well
designed graphics boards. Another problem I thought of with the
glDrawPixels() method of drawing spheres, is that the OpenGL Z-buffer
isn't linear, so if you render the spheres with glDrawPixels() and
you render other geometry in the same scene using the standard OpenGL
primitives, the hidden surface removal may not work out correctly.
(take a look at figure 3-18 in the OpenGL 1.1 book, "perspective
 projection and transformed depth coordinates")
The relative depth corresponding to a given delta in the Z-buffer depends
on the absolute depth and settings for the front and rear clipping planes...
A small delta-Z stored in a pre-computed sphere image might look fine when
rendered close to the front clipping plane, but may not match with other
geometry at all when rendered near the rear clipping plane. If one's scene
only contains spheres, all rendered using glDrawPixels, then this doesn't
matter, but in the case of VMD this is often not the case.

Anyway, despite these points I bring up, I've thought about implementing
a glDrawPixels()-based sphere drawing option for VMD before, as an alternative
to the slower but more flexible gluSphere/display listed spheres we use now.
As long as the user has control of which method is used, and they understand
what the tradeoffs are, its a win-win situation to be able to use both.

By the way, I would love to know what sorts of frame rates you are able
to achieve with the glDrawPixels() method that you've implemented.
How fast for a scene with 10,000 spheres or so? Have you come up with
a good way to deal with handling many different colors/materials using
the glDrawPixels() method?

One beautiful aspect of the glDrawPixels() method is that you can render
your pre-computed spheres at very very high geometric resolution,
(or ray trace them for that matter!) and get some awesome looking images.
This is basically what the old "vector balls" PC demos did...
I wrote a 3-D demo for old 256-color VGA graphics on PC's that used
pre-computed spheres, with my own software renderer to draw scenes with
about 250 spheres at 30 frames per second or so. This was pretty impressive
for those days, since we're talking about 386s and the first 486s. :)
One of the things I miss about the "bad old days" of graphics is that
it used to be a lot of fun to write custom graphics algorithms in software
where the only consideration was CPU time used, and bandwidth to the
framebuffer :-)

Oops, I just realized I have to be somewhere in a few minutes, so I'll
have to leave more on this until later. I love this topic though,
and I'm very curious to know what other ideas people might have for
alternative sphere drawing algorithms, particularly in the context of
taking some advantage of hardware acceleration with OpenGL.

Have a good day!

  John Stone
  vmd_at_ks.uiuc.edu

> The OpenGL driver I had did not correctly implement
> glDrawPixels with GL_DEPTH_COMPONENT, so drawing one depth buffer per
> sphere was not an option for me either. The OpenGL driver I was using
> was with XFree 3.something and it was available from NVIDIA as
> RIVA-X-GLX-1.0-glibc-i386-dyn.tar.gz. Their versioning scheme for
> XFree 4.whatever is completely different and incomparable. I haven't
> tried Nvidia's latest driver yet.
>
> So now, even though I have a functioning RIVA TNT2 3D graphics card
> and a mostly-functioning OpenGL driver, Fungimol does software
> rendering of spheres because that was the best performance I could
> get. To ensure that all views of all instances of an atom are exactly
> the same, Fungimol doesn't use perspective. The size of the image of
> the atom is the same regardless of the depth.
>
> Software rendering also allowed me to do a trick that I couldn't do
> with hardware. Specifically, I render from front to back and maintain
> a summary of the depth buffer. The summary is structured so that in
> many cases if a figure (such as a sphere for an atom) is completely
> obscured by stuff in front of it, I can efficiently determine this and
> avoid drawing the figure altogether. This is good for nanotech
> designs and space-filling atoms, since for these figures most of the
> atoms are often hidden and therefore need not be drawn. On a 600 Mhz
> Pentium III, Fungimol can draw Drexler's differential gear (which has
> 8297 atoms) full-screen in 166 milliseconds. Rasmol takes
> more like 500 milliseconds. This is with C++ code that ought to be
> portable; I haven't tried using MMX instructions yet. At the time I
> abandonded my OpenGL implementation, Rasmol was at least 10 times
> faster than my OpenGL implementation.
>
> The code for Fungimol is LGPL'd and located at
> http://www.infoscreen.com/fungimol.
>
> --
> Tim Freeman
> tim_at_infoscreen.com
> >From John Stone <johns_at_ks.uiuc.edu>:
> > My own suggestion for getting the most bang for the buck with running
> >VMD on a Linux box is to get one of the GeForce 256, or GeForce 2 GTS boards.
> >We have had some great results with ours so far, and VMD (unlike most games)
> >is extremely well suited to taking advantage of the hardware T&L on the
> >GeForce boards. The hardware T&L gives the GeForce a big advantage over
> >the other boards we've tried so far. The Voodoo boards are probably
> >the next best choice, although they lack hardware T&L, and would be much
> >more dependant on main CPU speed. I have no experience with the "xig"
> >software you mention below, but we have been using XFree 4.0 with
> >success, and intend to keep using that on the Linux boxes that some of
> >our group's scientists use.
>

-- 
Theoretical Biophysics Group   Email: johns_at_ks.uiuc.edu
Beckman Institute              http://www.ks.uiuc.edu/~johns/
University of Illinois         Phone:  (217) 244-3349
405 N. Mathews  Ave              FAX:  (217) 244-6078 
Urbana, IL 61801, USA          Unix Is Good For You!!!