I described in Part 1 and Part 2 the basis of an approach for a planetary renderer with Level of Detail (LOD) support, and I've been working on integrating this into the project, as shown below in Figure 1.
Figure 1. Level of Detail (LOD) tiles for Earth and Moon.
I previously thought that my background process for loading LOD textures was not locking the rendering loop, however it turns out this was not the case it was using Texture2D.FromFile to load a LOD texture which locks the GraphicsDevice1.
I therefore needed to minimise the time spent loading textures, and tried the following:
- Pre-processing image textures using the Content Pipeline.
- Using an HTM mesh and TOAST projection.
- Pre-loading image data on a background thread.
Content Pipeline
Running some LOD tiles for Earth through the Content Processor. L0-L5 tiles for texture, specularity, normals and clouds (10,920 files) took just over 48 minutes to process on my machine, not a problem given that I only needed to do this once. However, it resulted in 10.6Gb of .xnb files wasn't a practical approach nor significantly reduced lock time on the GraphicsDevice.
HTM and TOAST
Switching from an equirectangular to a Tessellated Octahedral Adaptive Subdivision Transform (TOAST) projection, as I descibed previously, provides a more even coverage of texture tiles across the surface of a sphere, thus minimising texture loads. Pressure on IO was further reduced by using smaller tile sizes (256px square).
Background Image Loads
Loading image data on a background thread can be done independently from the GraphicsDevice. The data can then be set on a Texture2D from memory, locking the GraphicsDevice for minimal time. I load the System.Drawing.Bitmap as follows:
int[] pixels = new int[256 * 256];
using (Bitmap bitmap = (Bitmap)Bitmap.FromFile(path))
{
// PixelFormat.Format32bppArgb
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// copy bitmap data into buffer
System.Runtime.InteropServices.Marshal.Copy(data.Scan0, pixels, 0, pixels.Length);
// unlock bitmap data
bitmap.UnlockBits(data);
}
I can then use Texture2D.SetData(int[] pixels) to create the texture.
Loading images in this way currently provides an acceptable lock time.
1 See Shawn Hargreaves' blog entry on Lock contention during load screen animations











