Download the sample project

Alpha blending is, to say the least, handy. In 3d modelling, you can find plenty of uses for it; say, creating hair or leaf textures, translucent or transparent materials, and so on. Needless to say, XNA can do it.

For this example, we’ll use a terrain model that’s made up of two meshes; a grid, which will represent the ground, and a cube, which will represent the water. The Blender file for this model can be downloaded here. Yes, I know it’s ugly.

The model, rendered in Blend. I know, I know

The material applied to the water mesh has an alpha of 0.572, which means that it’s only partially opaque. Materials with low alpha values are more translucent, with 0 being totally transparent. Materials with higher alpha values are more opaque, with 1 being totally solid. Depending on the tools or frameworks in question, these ranges may vary (WPF brushes describe alpha as a value between 0 and 255 for instance, while some tools use a percentage value), but the two extremes hold true in whatever case.

To load the model into our XNA project, we can export it from Blender using the .FBX exporter (File->Export->Autodesk FXB). Once the file is exported, we can add it to the content in our project, and draw it as we would any other model. Except that, unfortunately, what we get is this:

Where'd the seabed go?

Let’s be clear

What happened to the transparency? Well, the framework normally just ignores transparencies, since they can be quite an overhead to work out. To enable transparency, you need to enable it explicitly when you are drawing your model:

   1: GraphicsDevice.RenderState.AlphaBlendEnable = true;
   2: GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
   3: GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
   5: // Do stuff with the mesh effects here.
   6: // Render the mesh.
   8: GraphicsDevice.RenderState.AlphaBlendEnable = false;

Note: Line 8 is your friend. Never, ever, ever leave that out. Tattoo it on the insides of your eyelids if you have to. For the purposes of this demo it’s not going to do much, but if you’re going to go for more complex blending effects, leaving it out could leave you seriously wierded out.

Once we add the above, we get the effect we were after:

Better. Sort of.

Function over form

Of course this is simply a straight forward effect; there are other blending functions you can play with, defined in the aptly named BlendFunction property of the RenderState. You can also combine this with different SourceBlend and DestinationBlend values for various effects. The image below shows the same scene as above, except that the water now looks substantially more horrid:

To my untrained eye, that gloop looks highly toxic

   1: GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
   2: GraphicsDevice.RenderState.DestinationBlend = Blend.DestinationColor;
   3: GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;

Order, order

While I was preparing this model and playing about with transparency, I learned something very important: the order in which the meshes are rendered is vital when you have transparency effects. Any opaque meshes need to be rendered first, and then the transparent ones can be painted on top. Don’t just take my word for it; in the sample project, load up terrain-1 instead of terrain-2. The files are identical, except for the loading order of the meshes – the grid is loaded before the cube, so it gets rendered first. No amount of AlphaBlendEnable is going to get you transparency this way.

I’m not very familiar with Blender, so I don’t really know if there is a cleaner way to do this, but, to sort this out (pun intended… sorry) you can open the FBX file in a text editor, and search for “Connections:”. In the case of terrain-1.fbx, you should find (around line 30,107):

Connections:Β  {
Connect: “OO”, “Model::blend_root”, “Model::Scene”
Connect: “OO”, “Model::Cube”, “Model::blend_root”
Connect: “OO”, “Model::Grid”, “Model::blend_root”
Connect: “OO”, “Material::Material.002”, “Model::Cube”
Connect: “OO”, “Material::Material.003”, “Model::Grid”

Moving the line saying ‘Connect: “OO”, “Model::Grid”, “Model::blend_root”‘ to the second position will make the grid mesh load first, solving the transparency problem.

I’d be interested in knowing if there’s any way to set this order explicitly from Blender. Any advice on where to look would be greatly appreciated.

kick it on