Panda3D Manual: Transparency and Blending
  <<prev top next>>     

Don't use Image Files with Alpha Channels

There are several image file formats that can store an alpha channel. Among these are PNG, TIF, TGA, and others. However, the programs that create these image files (such as Photoshop) have such unpredictable and unreliable behavior that it's more trouble than its worth.

The following section summarizes the difficulties associated with creating alpha channels in Photoshop. The section after that describes an easier method: storing opacity maps in a separate file.

Creating Alpha Channels in Photoshop

Photoshop has three separate, unrelated ways to store transparency:

Using an alpha channel: using the Photoshop "Layers and Channels" dialog, select the channels tab, and then click the "Create new Channel" button.

Using a layer mask: using the Photoshop "Layers and Channels" dialog, select a layer, then using the "Layer" menu, select "Layer Mask/Reveal All."

Using cutout transparency: use the eraser tool to create transparency. Or, select an area of the image, and then click "delete."

Unfortunately, when trying to export an image from Photoshop and import it into Panda, data is often lost in the process. The following table shows which export/import procedures work, and which ones fail:

Image FormatTransparency TypeResults
PNGAlphaPhotoshop export loses data
PNGLayer MaskSuccess!
PNGCutoutPhotoshop export loses data
TGAAlphaPanda import loses data
TGALayer MaskPhotoshop export loses data
TGACutoutPhotoshop export loses data
TIFAlphaSuccess!
TIFLayer MaskPanda import loses data
TIFCutoutPanda import loses data

Even the ones that yielded "success" were not necessarily 100% straightforward. These image files that load correctly into Panda3D do not always load back into Photoshop.

Storing Opacity Maps Separately

A better way, that avoids the difficulties associated with Photoshop and alpha channels, is to store your opacity maps in a separate file.

When loading a texture, Panda3D can load a pair of files together, like this:

tex = loader.loadTexture("mytexture-color.jpg", "mytexture-opacity.jpg")

The idea here is that mytexture-color is an ordinary RGB (not RGBA) color map, and mytexture-opacity is a black-and-white image representing opacity. The two images must both be the same size. When loading, Panda3D will combine the two images together into a single RGBA texture.

Panda has model exporters for a number of different 3D modeling programs. Some of those exporters are better than others. The best among them will make this process automatic. For example, if you apply a color map and an opacity map to your model in Maya, then the maya exporter will automatically put annotations into the EGG file indicating that those textures should be merged at load time.

Dealing with Depth-Sorting

Note: this page is cut-and-pasted from a howto we found. We'll polish it later.

Usually transparency works as expected in Panda automatically, but sometimes it just seems to go awry, where a semitransparent object in the background seems to partially obscure a semitransparent object in front of it. This is especially likely to happen with large flat polygon cutouts, or when a transparent object is contained within another transparent object, or when parts of a transparent object can be seen behind other parts of the same object.

The fundamental problem is that correct transparency, in the absence of special hardware support involving extra framebuffer bits, requires drawing everything in order from farthest away to nearest. This means sorting each polygon--actually, each pixel, for true correctness--into back-to-front order before drawing the scene.

It is, of course, impossible to split up every transparent object into individual pixels or polygons for sorting individually, so Panda sorts objects at the Geom level, according to the center of the bounding volume. This works well 95% of the time.

You run into problems with large flat polygons, though, since these tend to have parts that are far away from the center of their bounding volume. The bounding-volume sorting is especially likely to go awry when you have two or more large flats close behind the other, and you view them from slightly off-axis. (Try drawing a picture, of the two flats as seen from the top, and imagine yourself viewing them from different directions. Also imagine where the center of the bounding volumes is.)

Now, there are a number of solutions to this sort of problem. No one solution is right for every situation.

First, the easiest thing to do is to use M_dual transparency. This is a special transparency mode in which the completely invisible parts of the object aren't drawn into the Z-buffer at all, so that they don't have any chance of obscuring things behind them. This only works well if the flats are typical cutouts, where there is a big solid part (alpha == 1.0) and a big transparent part (alpha == 0.0), and not a lot of semitransparent parts (0.0 < alpha < 1.0). It is also a slightly more expensive rendering mode than the default of M_alpha, so it's not enabled by default in Panda. But egg-palettize will turn it on automatically for a particular model if it detects textures that appear to be cutouts of the appropriate nature, which is another reason to use egg-palettize if you are not using it already.

If you don't use egg-palettize (you really should, you know), you can just hand-edit the egg files to put the line:

 <Scalar> alpha { dual }

within the <Texture> reference for the textures in question.

A second easy option is to use M_multisample transparency, which doesn't have any ordering issues at all, but it only looks good on very high-end cards that have special multisample bits to support full-screen antialiasing. Also, at the present it only looks good on these high-end cards in OpenGL mode (since our pandadx drivers don't support M_multisample explicitly right now). But if M_multisample is not supported by a particular hardware or panda driver, it automatically falls back to M_binary, which also doesn't have any ordering issues, but it always has jaggy edges along the cutout edge. This only works well on texture images that represent cutouts, like M_dual, above.

If you use egg-palettize, you can engage M_multisample mode by putting the keyword "ms" on the line with the texture(s). Without egg-palettize, hand-edit the egg files to put the line:

 <Scalar> alpha { ms }

within the <Texture> reference for the textures in question.

A third easy option is to chop up one or both competing models into smaller pieces, each of which can be sorted independently by Panda. For instance, you can split one big polygon into a grid of little polygons, and the sorting is more likely to be accurate for each piece (because the center of the bounding volume is closer to the pixels). You can draw a picture to see how this works. In order to do this properly, you can't just make it one big mesh of small polygons, since Panda will make a mesh into a single Geom of tristrips; instead, it needs to be separate meshes, so that each one will become its own Geom. Obviously, this is slightly more expensive too, since you are introducing additional vertices and adding more objects to the sort list; so you don't want to go too crazy with the smallness of your polygons.

A fourth option is simply to disable the depth write on your transparent objects. This is most effective when you are trying to represent something that is barely visible, like glass or a soap bubble. Doing this doesn't improve the likelihood of correct sorting, but it will tend to make the artifacts of an incorrect sorting less obvious. You can achieve this by using the transparency option "blend_no_occlude" in an egg file, or by explicitly disabling the depth write on a loaded model with node_path.set_depth_write(false). You should be careful only to disable depth write on the transparent pieces, and not on the opaque parts.

A final option is to make explicit sorting requests to Panda. This is often the last resort because it is more difficult, and doesn't generalize well, but it does have the advantage of not adding additional performance penalties to your scene. It only works well when the transparent objects can be sorted reliably with respect to everything else behind them. For instance, clouds in the sky can reliably be drawn before almost everything else in the scene, except the sky itself. Similarly, a big flat that is up against an opaque wall can reliably be drawn after all of the opaque objects, but before any other transparent object, regardless of where the camera happens to be placed in the scene. See howto.control_render_order.txt for more information about explicitly controlling the rendering order.

  <<prev top next>>