qemLOSS3 

Lightwave Object Surface Simplification
using Quadric Error Metrics

Version 3



Obtaining qemLOSS3

Introduction

Using qemLOSS3 (Quick Reference)

Tutorials and Hints

Scriptable Version (Experimental)



Summary: This Lightwave Modeler plugin uses a surface simplification algorithm in an attempt to reduce the number of polygons in a Lightwave object. The plugin allows the user to rapidly produce good quality approximations of excessively detailed polygonal models.

This is a new version of the qemLOSS2 plugin, with added support for all the standard Lightwave vertex maps (UV maps, weight maps, color maps, endomorphs, and selection sets). This version preserves all vertex maps in the original object, and interpolates the values in the vertex maps when a vertex is relocated during the reduction. It allows the discontinuous vertices in a vertex map to be constrained during the reduction process. It also includes support for weight map values and endomorph magnitudes to be used as reduction constraints, giving the user control over which parts of the object will be reduced.

This plugin uses routines adapted from Michael Garland's MixKit library distributed with his QSlim Simplification Software. The algorithms used in this software are described in the papers written by Michael Garland and Paul S. Heckbert: "Surface Simplification Using Quadric Error Metrics", SIGGRAPH '97, and "Simplifying Surfaces with Color and Texture using Quadric Error Metrics", IEEE Visualization '98.



Obtaining qemLOSS3

When I originally released this plugin it was not available for download. I decided to conduct an experiment that required a Lightwave related item be sent to me in exchange for the plugin. It was an interesting experiment, and I truly enjoyed the contact with the people who requested the plugin. For years I made all my plugins available for download from my web pages, and I was always curious as to who was actually downloading the plugins. This gave me a wonderful chance to find out more about the users who were interested in the plugin. I sincerely want to thank everyone who participated in this trade experiment, I enjoyed every single trade item that was sent my way. I received a wide range of trade items... simple items from beginning Lightwave users, many low polygon objects from people using Lightwave to create game models, some terrific movies, images and DVDs created with Lightwave, as well as some very sophisticated scenes, plugins, scripts and other items from very advanced users. I enjoyed them all, thanks again to everyone who made this experiment a very enjoyable and memorable experience.

But when I received my LW8 upgrade, I thought it was finally time to bring the experiment to an end. So, it is my pleasure to finally make it available as a free download from this web page.

Thanks very much to Richard Brak for providing the Mac OSX compile and Michael Wolf for the Mac UB compile.


Introduction

Many 3D models contain a large number of polygons, especially algorithmically created models (such as those created by implicit surface construction techniques) and models created with 3D scanners and digitizers. Polygon reduction in these types of models is currently a very active research area in computer graphics. Obviously, rendering 3D scenes is much faster when the models contain a minimum number of polygons. Also when sharing 3D worlds over the internet using VRML, level of detail models (LOD) are becoming absolutely necessary for creating worlds in which the user can browse and interact in a reasonable manner.

This plugin provides polygon reduction on objects within the Lightwave Modeler environment. Only one parameter, the Reduction Goal, must be set by the user. The remaining default values should provide good reduction for many objects with a high polygon count. However, to get the best results from this plugin, the user will need to understand some of the basic concepts behind the algorithm. A little terminology along with some simplified illustrations will be presented in the remainder of this introduction. These terms will be reinforced by the short examples in the Tutorial section.


Terminology

The simplification algorithm is based on contractions of vertex pairs. An Edge contraction can occur when a vertex pair shares an edge. The following figure shows an example of an edge contraction where vertex v1 and vertex v2 are joined to form a new vertex v3. Since v1 and v2 share an edge (marked in orange), one or more triangles will always be removed during this contraction. In this example, 2 triangles are eliminated from the mesh.

Edge Contraction

As the algorithm proceeds through each iteration, a geometric error weight is accumulated at each vertex of the object. During each iteration, the vertex pair with the smallest combined geometric error weight will be chosen for the current contraction. The algorithm will proceed until the simplified object is reduced to the user's targetted Reduction Goal, which can be specified by either a percentage of the original object's polygon count or with a user specified number of polygons.

There are 2 types of vertices that always receive special consideration by this plugin: surface border and boundary vertices. Parameters are provided for the user to weight the geometric error for these 2 special types of vertices.

This simplified 2D grid shows examples of both types of vertices. The colored triangles represent the different surfaces assigned to the object.


Red - Surface Border vertices

Green - Boundary vertices

Blue - both types
 

In this example, obviously there are boundary edges all along the perimeter of the grid, but notice that any hole in the grid also defines several boundary edges.

The Surface Border Weight and Boundary Weight parameters allows the user to weight the geometric error at these points. The higher the weight, the less chance the vertex will be removed. Clever use of these parameters (along with some equally clever surfacing) can provide some control over the contraction process.

Another type of vertex that can receive special consideration in the reduction process is a discontinuous vertex in a Lightwave UV, Weight, Subpatch Weight, or Color map. (For an online discussion about Lightwave's discontinuous vertex map capability, see Arnie Cachelin's "Advanced Guide to UV Mapping" or "A 12-Step Program for dealing with Discontinuous Textures"). Since discontinuous vertices in a vertex map usually define important mesh features, Discontinuous Vertex Constraints are provided for the user to choose how to weight the geometric error for these types of vertices.

And last, but certainly not least, vertices that have been assigned weight maps and endomorphs can be used to constrain the reduction process. (For online discussions about these Lightwave features, you can start with DaliLlama's "Weight Maps Tutorial" and Tony G.'s "Basic Facial Setup" for Endomorphs). The Reduction Constraints in qemLOSS3 provide the user with control over how those Weight map values and the magnitudes of Endomorphs can be used to control the geometric error weight of a vertex.



Using qemLOSS3

ALWAYS save your objects before you run qemLOSS3! This software is provided as-is, and although it is fairly stable, it will probably crash at the most critical moment. You can prevent any permanent loss of your hard work by assuring that you have saved all objects before running the plugin!

Make sure you have an object in the current foreground layer(s) of Modeller. The existing object will remain unchanged, and the reduced object will be placed in the first available empty layer. Choose Modeler's Construct tab, and in the Utility section, use the Additional pulldown menu and locate the qemLOSS3 option. You should be presented with an information requester that looks similar to the following panel.

ATTENTION Lightwave 8.2 users: It has been reported to me that under LW 8.2, qemLOSS3 posts an error message saying there must be an empty layer available to run the plugin. It looks as if LW 8.2 has changed the functionality of the SDK's layerMask function and therefore the plugin cannot find an empty layer for doing it's reduction. The reported workaround is to select the desired empty background layer before running the plugin. So make sure you still have the object to be reduced in the foreground layer, but also make sure you have selected an empty background layer by clicking on the bottom of a layer button (in the Layer Navigation area located at the top-right corner of the Modeler interface).


Quick Reference

Here is a brief description of each parameter in the qemLOSS3 Options requester. Please refer to the Terminology section of this document if you have any questions about the highlighted words in these descriptions.


Well, that's it! Once you click on the OK button, qemLOSS3 will show a progress monitor in the lower area of the Modeler interface while it creates the reduced object in the first available empty layer of Modeler. You will probably also see various stages of the entire procedure (described in the next paragraph) occur in the Modeler viewports.

Here is what is happening. First, the object in the foreground layer(s) is copied to the first available empty layer, then all its polygons are converted to triangles using Modeler's Triple function. Next all vertices and polygons are converted into the necessary data structures needed for the simplification routines, and the copied object is subsequently removed. Once the simplification routine is finished, the reduced polygon object is placed in the previously empty layer.

IMPORTANT: You should always be aware of the fact that the more vertex maps you have assigned to an object, the longer the reduction process will take. Each vertex map increases the dimensionality of the quadric error metric, and as that dimension gets larger, the more time the algorithm takes to calculate all the interpolations and constraints. If at all possible, you should try to disable as many discontinuous vertex constraints and reduction constraints as you can. However, there are no controls to disable the interpolation process, so if you have many vertex maps in your object it is going to take a long time to process even if you disable the constraints.

I am very interested in seeing how this plugin can be used. If you use it, send me some e-mail (marvinl AT email.arizona.edu) and let me know what kind of success or failure you achieved.



Tutorials and Hints

These tutorials will provide you with some hands-on examples of using the various parameters found on the qemLOSS3 panel interface. You'll find some hints and tips scattered throughout the tutorials, but there is also a page specifically for various hints about using qemLOSS3. If you have something you would like to contribute to these pages, please feel free to send me e-mail (marvinl AT email.arizona.edu) with your own words of wisdom.

The first tutorial will be familiar to anyone who read the qemLOSS2 documentation (all 3 or 4 of you :-). It's main purpose is to introduce you to the idea of geometric error weights and the difference between surface borders and boundaries. The remainder of the tutorials are probably the most useful, as they use some typical objects and introduce you to techniques that you can use to control the amount of reduction that takes place on specific parts of an object.

A couple of these tutorials use objects from Newtek's "SIGGRAPH 2002 Content". The scenes and objects included in the download are fun and educational, and the various objects I refer to in the tutorials have some nice examples of Weight maps, Color maps, and Endomorphs. For example, the images of "Nuthead" the squirrel at the top of this page shows an object colored completely with Color vertex maps and has some Weight maps assigned to various parts of its body. I'll use those Weight maps to demonstrate qemLOSS3's weight map reduction constraints in the third tutorial below. If you don't already have this free download from Newtek's site, I suggest filling out the form on their "Get Access to our SIGGRAPH 2002 Content" page so you can follow along with all of the qemLOSS3 vertex map tutorials.

Surface Borders and Boundaries

Discontinuous Vertex Constraints

Weight Map Reduction Constraints

Endomorph Reduction Constraints

Hints from Users



Scriptable Version of qemLOSS3 (Experimental)

Several people have asked about a scriptable version of qemLOSS3 that can do batch reductions on multiple objects. So I decided to make this version available for those of you that like to experiment. Another reason this version might be of interest (it doesn't have to be called from a script), is that it removes the original object in the current layer and completely replaces it with the reduced object in the original layer (unlike the standard qemLOSS3 which does the reduction in the next empty layer and leaves the original object alone). This saves some memory and might allow users to reduce larger objects since both the original and reduced versions of the object do not have to exist at the same time in different layers.

The link below (sorry, Intel only version for now) will allow you to download a modified version of the qemLOSS3 plugin and a test script that is intended to do a batch conversion of a bunch of objects in a directory. The included qemloss3s plugin should show up in Modeler as "qemLOSS3s" so it should be able to be loaded along with the original version of the plugin. You will need to run the "s" version of the plugin manually one time first before it is called from a script (detailed instructions are all included below). This is really just a test and there are several ways the batch version of qemLOSS3s could be improved, but hopefully this experimental version might prove somewhat useful.

Intel qemLOSS3s plugin and example script

The following directions are from the e-mail message I sent to users that had requested the scriptable feature. It is the only directions available about how to use this version of the plugin, so experiment at your own risk. And don't forget, this version removes the original object from the layer before it starts to do the reduction. So make sure you have saved all your hard work before you run this plugin!


It is possible to call MeshDataEdit plugins from another plugin or lscript, but I had never attempted to add the necessary code to any of my plugins. Turns out, it was not difficult to add the code to check to see whether the plugin was invoked from the interface or a script, so the only thing necessary to do was to make qemLOSS3 work in a little different manner. I figured if the plugin was to be called from a script, most likely it would be better to do the reduction in place rather than copying the mesh to the next available layer and doing the reduction in that layer. That way the loading and saving of the object could be scripted and the user would end up with reduced objects saved in their own files rather than an object that contained both the original and reduced object in separate layers.

So I took out the "copy then paste to another layer" commands and created a new plugin called qemLOSS3s (the s stands for scriptable). So it can be added to Modeler along side of the original qemLOSS3 and both can still be available at the same time. I also added the necessary code to allow a very simple command line argument which is necessary for the plugin to be called from a script. So what follows is a simple script that would load a wildcard specified number of files from a directory, freeze the subpatches in those files into polygons, reduce the object, and then save the reduced object with a "Reduced_" prepended to the original file name. I'll make comments interspersed throughout the commands in the script below, but I've also included the fully working script without comments in the qemloss3s.zip file.

dirname = "g:\\qemloss3test\\";
filenames = "NutHead*.lwo";
wghtinfo = "tail 1000";

The previous 3 lines are the most likely things that would need to be changed for this script to work on different objects and I think the changes will be pretty self explanatory. The first is the directory specification where the object would be found, the second is the wildcard specification for which objects should be reduced. The 3rd is the single weight map name and weight multiplier used for the reduction constraint.

lwobjects = matchfiles(dirname, filenames);
for (i = 1; i <= sizeof(lwobjects); i++)
{
loadname = dirname + lwobjects[i]; load(loadname);

The previous lines just load all the objects one by one into Modeler.

freezecurves();
cmdseq("qemLOSS3s", wghtinfo);

These just freeze the subdivision surfaces and then calls the new qemLOSS3s plugin with the weight info assigned in the string above.

newname = "Reduced_" + lwobjects[i];
savename = dirname + newname;
save(savename);
}

And finally each reduced object is saved with the Reduced_ prepended to the original file name.

So here is the way all of this would finally work. The user would need to manually load one object and manually run the qemLOSS3s plugin one time. Make sure you run the new qemLOSS3s version, NOT the original qemLOSS3 version. This allows the user to set a Reduction Goal, Surface Border Weight, Boundary Weight, and any other reduction constraints for the menu options that read "All UV Maps", "All Weight Maps", "All RGB Maps", etc. Those parameters are all globally saved and used the next time the qemLOSS3s plugin is run. Only those reduction constraints for "All" vertex maps are saved though (for various reasons), and that is why the scriptable version of the plugin allows for specifiying the one weight map and weight multiplier for the reduction constraint. This allows for one of your specific weight maps to be used to control the reduction more than just the global "All Weight Maps" option.

Once the first reduction is done manually with qemLOSS3s (you wouldn't need to save the manual reduction you can just clear the object before proceeding), the script can now be run to load, reduce, and save all the objects in the specified directory.

For this to be really useful, it would be nice to allow more than just 1 weight map (and other vertex maps) to be specified as the script's command line argument for the plugin. Probably the best solution would be for the plugin to write a temporary file when qemLOSS3s is run manually that saves any individual weights and multipliers that the user set for the manual reduction. Then the plugin would read that file and those values when the plugin is called from the script. But this simple implementation of the plugin will give you a chance to experiment if you would like and see if such an addition to the plugin might be necessary.