[vtk-developers] fixing camera-tracking lights in vtk

Michael Halle halazar at media.mit.edu
Wed Aug 9 00:30:23 EDT 2000


Hey there,

I've implemented some improvements to the way VTK handles its lights.
Specifically, I've moved the ability to have lights attached to the
camera out of the interactors and into the renderers.  While the
changes are good things, I need some help in thinking through legacy
issues before I commit any more changes.  Any comments will be
helpful!

In vtk 3.1 release, lights are defined in world space coordinates and
stuck onto the renderer.  The interactors have a flag
(LightFollowCamera).  If the flag is set, the interactor moves the
"CurrentLight" to the current position of the camera every time a
frame is rendered.

There a few limitations with this plan.  First, every interactor
re-implements this functionality.  Next, what's a "CurrentLight"?
What's more, what if I want more than one, or want my lights offset
from the camera position but still attached to it?  What if I don't
want to use an interactor?  

It's so hard to deal with this situation that essentially none of the
examples in vtk use lighting other than a "headlight," the built-in
camera tracking functionality.  The headlight is, arguably, one of
the worst lights for showing the shape of the object.

Here's my fix.  I've added a transformation matrix to each light
(vtkLight).  If the matrix is set, the light should be transformed by
the matrix.  I've implemented the transform functionality in
vtkOpenGLLight, since I can just dump a matrix into the graphics pipe.
I've also added two convenience methods in vtkLight:
GetTransformedPosition() and GetTransformedFocalPoint().  These
methods are exactly analogous to GetPosition() and GetFocalPoint()
except they use the transform if it is set.  This matrix can be used
for a bunch of stuff, but I specifically use it to track the camera.

Next, I defined a new coordinate system called the
CameraLightTransform.  In this space, the camera is at (0, 0, 1), up
being (0, 1, 0), looking at (0, 0, 0), and the focal distance is
scaled to 1.  The space is centered around the lookat point, so it's
easy to position lights around what you've looking at.  I've added to
methods to vtkCamera to compute and get the CameraLightTransformMatrix.

Since the changes to vtkLight, vtkOpenGLLight, and vtkCamera don't have
any backwards compatibility issues, I checked them in.  

I've also hacked vtkRenderer/vtkOpenGLRenderer to add the camera
tracking functionality. I added a new collection of lights called
CameraLights.  Every time the scene gets rendered, the renderer
traverses the CameraLights collection and sets each Light's matrix to
be the CameraLightTransformMatrix from the camera.  Both the normal
and the camera lights get rendered as normal.  Thus, the camera lights
track the camera's coordinate system.  

To avoid confusion, I created another collection of lights, called
SceneLights, that are do not track the camera like CameraLights do.
Having SceneLights and CameraLights collections fixes the inherent
ambiguity of the current codebase in distinguishing between the two
types.

Okay, works great, looks great.  The problems are all related to
backwards compatibility.  There's lots of existing code in vtk that
reimplements camera tracking.  I'd love to be able to strip it all
out, but code outside the vtk distribution does the same thing and
will break too.  Here are the major problems:

* LightFollowCamera is now obsolete: you control if a light follows
the camera if you add it using AddSceneLight or AddCameraLight.

* Any code that expects to get all the lights in the scene using
GetLights() will be disappointed.  That's probably okay, because
exporters really needed a way to distinguish between, say, headlights
and fixed lights, and now they can be updated to do the right thing.

* The CreatedLight for vtkRenderer is now a CameraLight located at (0,
0, 1), looking at (0, 0, 0).  It's Position and FocalPoint never needs
to be touched.

* Some code used GetLights() to find a light to track the camera, and
it's in several places in the source tree.  Basically, the code gets
the light collection using GetLights(), begins traversing it, finds
the first light, calls it the CurrentLight, and sets its position and
focal point to correspond to the current camera.  Well, this code is
now unnecessary.  However, if there is only one CameraLight, the
Lights collection is empty, CurrentLight is NULL, and the code dies
dereferencing it.  It doesn't help to point CurrentLight to the
CameraLight, since we don't want the light's position and focal point
updated.

I sort of solved the problem by creating a fake light in the
vtkRenderer constructor called "CreatedLightCompat."  I turn it off,
and I add it to the legacy Lights collection.  When simple-minded code
calls the deprecated GetLights() method, they get a handle to this
fake light, don't dump core, and merrily set its Position and
FocalPoint.  The Lights collection doesn't actually get fed to the
graphics pipe.  Since the light doesn't get rendered, nothing bad
happens.  Since all the code was trying to do was produce a
"headlight," and that's what the default light is, the visual results
are as expected even though the code is disabled.  Calls to AddLight()
and GetLights() generate a deprecation warning.  This "Compatibility"
light is conditionally compiled in so it can be removed someday.

* Then there's the part of the code base and test suite that has to be
changed to reflect the new lighting flexibility.  Most of the
interactors are easy.  Since lighting was so hard to do right before,
not too many tests used interesting lighting, so there aren't too many
non-headlight examples that will break.  The mainline
vtkOpenGLRenderer is an easy fix, and I've got it; the other renderers
will take time, and I don't know them very well.

So, what's the best way to make the change to vtkRenderer/vtkOpenGLRenderer
and then the rest of the affected code?  

Thanks for your ideas.

Michael Halle
mhalle at bwh.harvard.edu






More information about the vtk-developers mailing list