Generating Light Maps for Director/Shockwave 3D using 3DS Max 5

There are a number of steps that must be done in order to generate light maps for use in Director. Unfortunately one of the biggest problems is that the W3D format itself doesn't support multiple texture coordinates. This support is necessary to create lightMaps.

Fortunately we can get around this problem by exporting the scene twice. Once as it should be seen in the final project, with all models and textures in place. The other export should contain just the geometry used for the lightMapping. Once this is done we process the geometryData to match up the lightMap texture coordinates to the appropriate faces on the original geometry. Then map these onto the original geometry using Lingo. The basic steps for all of this are outlined below.

Generating the scene in Max

  1. First you need to generate your scene, and pick out which geometry is going to be used for the lightMapping (this may be all of the geometry in your scene, but it doesn't have to be)

  2. Texture your geometry and generate UVW coordinates for it, using UVW modifier, or some other method to generate UVW coordinates.

  3. Export your scene to W3D. This should look exactly how you want your final scene to look (save the lightMapping). From here on we will refer to this as the "source scene."

  4. Go to RENDER TO TEXTURES, enable "per object settings", select Use Channel 1, add lightmaps. Check the settings of the file and location, and click RENDER

  5. Select object, apply a new material, name it the same as the original, and load in the diffuse channel the generated image, it already gets the right UVs of the lightmap.

  6. Export this to W3D. From here on we will refer to this as the "lightmap scene."

Combining the scene in Director

The basic process for combining the scenes in Director, is to loop through each face on each mesh in each model in our lightmap scene, and map the corresponding texture coordinates into a second texture layer on each model in our source scene. This can be a processor intensive process, especially for scenes with lots of geometry. Fortunately, much of this can be preprocessed and does not need to be recalculated at runtime.

Pre Processing

  1. Import your source scene, and lightmap scene into Director.

  2. In the message window run

    generateLightMap(member("Source Scene"), member("lightmap scene"))
  3. This will dump all of the texture coordinate data for the entire scene into the text member lightMapText. It may take a little while, and when it's finished you should see a success message printed to the message window.

Runtime Application

  1. Import all of the lightMap images into the cast. These should have been generated from Max. The naming convention on these images is important. The given scripts assume the images will be named, <modelName>lightMap, so for a model named "ground" the image will be "groundlightMap"

  2. At run-time you need to call the function:

    getLightmap(member("source scene"))
  3. This will parse the lightMapText member we previously created, and map the 2nd layer of texture coordinates onto all of the models in the scene. This will also create and apply the textures from the images you imported in step 1.


Technically What We're Doing

I'll attempt to explain what we're doing technically so that you can write your own applications of this technique either for Shockwave, or for a completely different application.

Our source scene starts out with all the geometry, shaders, and textures that the final scene should have. The light map scene has all of the geometry, but it does not have any of the shaders and textures. What we have to do is map the texture coordinates that exist on the models in the lightmap scene, onto the second textureLayer of the cooresponding models that exist in the source scene.

To make this an even more difficult problem, the Max exporter will almost always scramble the vertices between the two scenes (ie, the first vertex in source scene.model(1), will not be the same as lightmap scene.model(1).

However, the vertices should all be in the exact same place between the two scenes. (Update: They actually may not be in the exact same place, but they should be VERY near and our code handles the slight discrepancies) Therefore, the basic process is to loop through every face in each mesh of each model in the source scene, and find the corresponding face in the lightmap scene. Once we have the corresponding face, we grab the textureCoordinates for each vertex in the lightmap scene's face, and populate a new textureCoordinateList for the source scene's mesh.

Once we have a list of texture coordinates for each mesh, in each model of the source scene (or at least the ones we want to lightMap), we save the list to text.

At run-Time, we read in our text containing all of the textureCoordinates, for each mesh and model in our source scene.

We then go into each mesh, add a new texture layer, and set it's textureCoordinateList to the appropriate entry from our text file. We don't need to worry about ordering or anything else here, because we took care of all that in the preprocessing step.

Finally, we need to set textureLayer 2 for the model's shader to the lightMap texture generated from Max.

That's *all* there is to it.

Version History:
v 0.2
June 23, 2003
Updates to documentation and source files based on feedback from Jack Kristoffersen
v 0.1
June 13, 2003
Brian Robbins and Matias Zadicoff
Fuel Industries