Thursday, May 10, 2007

Converting OpenDX VRML to Texture-mapped VRML

OpenDX typically writes VRML files with vertex colors, so that every vertex has an associated RGB value. Many modeling programs cannot read VRML with vertex colors, so it is useful to convert them. If you are converting a single object or a relatively simple object, there are applications to do the conversion, such as Ultimate Unwrap3D. This program examines the given Shape and figures out how to dice it evenly onto a two-dimensional texture map.

VRML from OpenDX is typically special, though, in that all of the color comes from a colormap applied to a scalar value. That means you probably started with every vertex being associated with a number between some min and max and assigned RGB values to the range of numbers. Because of this, we can use a one-dimensional texture to color a VRML from OpenDX. The process is a lot faster than unwrapping the texture, and it doesn't leave any seams.

Here's how we did it.
  1. Save the VRML as grayscale.
  2. Save the colormap as a jpeg or tiff (depending on what colormaps your VRML viewer can read).
  3. Use a custom python script to translate each grayscale value into a u-v index into the saved colormap.
Because I didn't want to write code to read VRML, I used a shortcut. There is a program called X3D-Edit which translates VRML to X3D, which is essentially VRML in XML form. Then I used Python's ElementTree to process the XML and write a new X3D file. Then X3D-Edit or the standard XSLT will translate X3D back to VRML. It sounds complicated, but the translation from VRML to X3D and back is quite sure, and X3D is a lot easier to parse than VRML.

Powershell XML Handling for Empty nodes

Windows Powershell handles xml objects a little inconsistently. If a node is empty, then Powershell treats it as a string. If the node is non-empty, then it treats the node as an XmlNode. You can circumvent this behavior by using the Item() interface.

PS>$x=[xml]"<root/>"
PS>$x.root.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object

PS>$x.Item("root").GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False XmlElement System.Xml.XmlLinkedNode