qemLOSS3 
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.
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.
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.
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.
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).

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.
These 2 requesters allow two different ways to determine the final number of polygons you would like in the simplified object. The first time you run qemLOSS3, the (Percent) parameter will display 50% and the (Polygons) parameter will show you how many polygons would result from a 50% reduction. You may either use the (Percent) parameter's arrows to change the amount of reduction or just type a new percentage into the requester. When you change the (Percent) parameter, the (Polygons) parameter will automatically update to show the final number of polygons that will be in the reduced object. You may also enter a desired polygon count in the (Polygons) requester, in which case the (Percent) parameter will change automatically to reflect the percentage of original polygons that will appear in the reduced object.
This parameter allows you some control over whether surface border vertices are relocated during the contraction process.
A large value restricts the relocation of points that lie along surface
borders, thereby preserving the shape of the surface border
fairly well. Smaller values will allow the points to move farther from
their original location, possibly causing the border to change its
shape. A value of 0 will not constrain the surface borders at all, and
vertices along a border may not end up where you expect when the
simplification is finished.
This parameter allows you some control over whether boundary vertices are relocated during the reduction process.
A small value allows the boundary points to move farther than larger
values. A value of 0 will not constrain the boundary at all, and the
object may not look at all like you expect when the simplification is
finished.
These tabs display all the standard types of vertex maps available in Lightwave. By clicking on each tab, the bottom portion of the panel will display the available constraints for each type of vertex map. The four letter identifiers are used so all the labels on the tab will show up in the panel, and not display the annoying "..." that would be shown if I used longer labels. The four letter identifiers on each tab are the tags used in a Lightwave object file when saving each type of vertex map; here is a more friendly description of each of these identifiers:
| TXUV | UV map |
| WGHT | Weight map |
| MNVW | Subpatch Weight map |
| RGB | Color map |
| RGBA | Color map with Alpha channel |
| MORF | Relative Endomorph |
| SPOT | Absolute Endomorph |
| PICK | Selection set |
You will find these parameters under the TXUV, WGHT, MNVW, RGB, RGBA, and PICK tabs. These parameters allow you to constrain discontinuous vertices found in a vertex map. In the remainder of this section, I will only describe the TXUV map parameters, but you can freely substitute WGHT, MNVW, RGB, RGBA, or PICK for the TXUV description that follows.
If there are no TXUV discontinuous vertices in your object, these parameters will be ghosted. If there is at least one TXUV map that contains one or more discontinuous vertices, you can choose to enable all discontinuous vertex constraints by selecting the "Constrain Discontinuous UV Map Vertices" parameter. If that parameter is unselected, the remaining 2 parameters will be ghosted.
The remaining two parameters will allow you to specify a single geometric error weight for every discontinuous vertex in every TXUV map, or you can specify a different geometric error weight for all the discontinuous vertices in individual TXUV maps. Initially all discontinuous vertices in every TXUV map will be assigned a geometric error weight of 1000. If the "UV Map" pull-down menu shows "All UV Maps", when you type a new value into the "Weight" requester, every discontinuous TXUV vertex will be assigned that global value. If you choose an individual TXUV map from the pull-down menu, and then type in a new "Weight" value, only those discontinuous vertices in that particular TXUV map will be assigned the new geometric error weight. You can always see the geometric error weight value assigned to vertices in any TXUV map by choosing the appropriate map name from the "UV Map" pull-down menu.
NOTE: Despite the fact that the first option in the "UV
Map" pulldown list reads "All UV Maps", this
really means "All UV Maps with discontinuous vertices".
Remember, this pulldown list will not show all UV Maps in your object,
it will only show those maps that contain at least one discontinuous
vertex.
You will find these parameters under the WGHT, MNVW, MORF, and SPOT tabs. These parameters allow you to use the values in your WGHT maps or MNVW map to control the geometric error weight of the vertices in the map (for the MORF and SPOT maps, it uses the magnitude of the morph vector as the control value). In the remainder of this section, I will only describe the WGHT map parameters, but you can freely substitute MNVW, MORF, or SPOT for the WGHT description that follows.
If there are no WGHT maps in your object, these parameters will be ghosted. If there is at least one WGHT map in your object, you can choose to enable all WGHT constraints by selecting the "Use Weights as Reduction Constraint" parameter. If that parameter is unselected, the remaining 2 parameters will be ghosted.
The remaining two parameters will allow you to specify a value that will be multiplied by the vertex's WGHT map value to determine the final geometric error weight for the vertex. Using the "Weight Map" pull-down menu, you can specify a multiplier for every vertex in every WGHT map, or you can specify a different multiplier for all the vertices in individual WGHT maps. By default, all vertices in every WGHT map will be assigned a multiplier of 1000. If the "Weight Map" pull-down menu shows "All Weight Maps", when you type a new value into the "Multiplier" requester, every vertex in every WGHT map will be assigned that global multiplier. If you choose an individual WGHT map from the pull-down menu, and then type in a new "Multiplier" value, only those vertices in that particular WGHT map will be assigned the new multiplier. You can always see the multiplier value assigned to vertices in any WGHT map by choosing the appropriate map name from the "Weight Map" pull-down menu.
Remember, the "Multiplier" value assigned to each
WGHT and MNVW map will be multiplied by the actual weight map value of
each vertex to determine the final geometric error weight for
that vertex. For MORF and SPOT maps, the "Multiplier" value
is multiplied by the magnitude of the morph vector at each vertex to
determine the final geometric error weight. In other words, those
vertices that are morphed farther from their original position will be
less likely to be removed than those vertices that remain close to
their original position (unless you use a negative multiplier, in which
case the likelihood of removal is reversed).
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.
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
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.
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.