[DEMO] Minimal world engine with 3D widgets

Positioning lights is one of the more time-consuming chores in setting up an
OpenGL scene, at least if you have to do it by recompiling a program over and
over again. Being able to do it interactively is a big benefit, and today’s
demo shows one way to do that:

http://people.nl.linux.org/~phillips/world/lamps5.png

Code is here:

http://people.nl.linux.org/~phillips/world/world.tgz
http://people.nl.linux.org/~phillips/world/world.zip

Each lamp stand is a 3D widget with four controls:

  • Change the color of a light by rotating the color wheel
  • Move a light by dragging on the middle of the color wheel
  • Change the light’s height by sliding the top dot up or down
  • Aim the light by grabbing and aiming the arrowhead

This is the kind of interactive control you’d expect to find in something
like SGI’s Open Inventor (GPL, by the way) but you wouldn’t it implemented in
less than 500 lines, as you’ll find here. On the other hand, I didn’t
provide a fully general framework like Open Inventor does, but on the third
hand, the goal was really to debug the math and make the widgets work well.

There’s a design philosophy behind this widget set: when you grab a widget
with the mouse, the grab point is supposed to stay exactly under the mouse
pointer as you drag the object, whether you are rotating a dial, sliding
along a line, sliding in a plane or rotating around a sphere. Even if you
move the pointer way off the object while dragging, the dragged object should
still move in a reasonable way in relation to the mouse. For example, you
don’t have to stay exactly on a slider to slide along it, or on the lamp base
to turn it.

In the case of aiming a light, we have the problem of aiming a vector in
three coordinates, when there are only two coordinates worth of mouse motion
to do it. This problem has been researched by such luminaries as Ken
Shoemake, the man who brought quaternions to the attention of the 3D graphics
world. You can try out Shoemake’s rotation control in example5 of the GLUI
test programs:

http://www.cs.unc.edu/~rademach/glui/

It works, but as you’ll see, it feels sort of like a remote control and you
never get the feeling you’re actually touching the object. I’d appreciate
feedback on this, but what I think is, with my 3D widget you can aim a vector
more accurately and easily than with Shoemake’s arcball. (Note: I didn’t use
quaternions here because we aren’t defining a full orientation, just a vector
direction: 3D as opposed to 4D.)

Another possibly interesting item in today’s demo is the view-dependent
rendering of the arrowheads:

http://people.nl.linux.org/~phillips/world/arrows.png

Notice that, whichever direction you are looking from, the arrowheads look
like arrowheads. This is because the arrowheads turn to face you as you
move, while still keeping a proper orientation along the axis. Using this
technique, I’m able to draw an arrowhead that looks like a drafting-style
arrow instead of like an umbrella or lawn dart as you’ll typically see.

Another type of view-dependent object I’ve been using for a while is the
round spot, which again, always turns to face you, making it look something
like a sphere, but much cheaper to render than a sphere. You’ll see a
similar technique used in so-called “point sprites”, which shows that point
sprites are easy to implement in OpenGL, even with no special feature to
support them (short description: read the sprite’s x and y axes straight out
of the projection matrix).

The style of coding in this demo is distincly C++, even though it’s straight
C. Writing in C gives me a advantage in terms of program size and eliminates
linking hassles, but even so, this is about as far as I’ll push the envelope
of good old C, and from now on I’ll be writing in C++.

I hope somebody finds this useful.

Regards,

Daniel