I predict that DualTextureEffect will turn out to be the secret weapon in the armory of all the best looking Windows Phone games. It is efficient (only 7 vertex and 6 pixel shader instructions when not using fog), yet enables visually lush rendering techniques such as lightmaps and detail textures. For instance, the Harvest demo makes heavy use of DualTextureEffect.
DualTextureEffect samples from a pair of textures. Each has its own texture coordinates, so they can be independently aligned, tiled, rotated, etc. The textures are combined using Modulate2X blend mode:
output.rgb = Texture1.rgb * Texture2.rgb * 2;
output.a = Texture1.a * Texture2.a;
The easiest way to think about this operation is that the first texture defines the basic color of the object, which can then be adjusted by the second texture:
To use DualTextureEffect, you must:
The idea behind lightmapping is simple. Instead of trying to compute lighting and shadows in realtime, you precompute them for an entire level, and store the results in one or more textures. These textures are uniquely mapped across the level, which means that every triangle gets its own unique area of the texture, with no tiling or texture reuse. Even with the largest textures that can fit in memory, the lightmap data typically ends up quite low resolution, but when you use DualTextureEffect to combine this with the base textures (which are usually tiled and thus appear to have higher resolution), the results can be stunning.
The big advantage of lightmaps is that because everything is precomputed, even the most complex lighting effects (soft shadows, radiosity, large numbers of lights, area lights, gobos, etc) can be rendered using even the weakest GPU hardware. Who cares if your crazy photon mapping algorithm takes hours on a high end workstation, when at runtime this will require just a simple texture fetch to display?
Of course the disadvantage is that because everything is precomputed, lightmaps only work for static models and static lighting. They are no use for things that animate.
Some people write their own code for generating lightmaps, and many game engines have lightmap generators built into their level editors. But the easiest way to get started is using a 3D modeling program: here are tutorials on how to render lightmaps with Max or Maya.
In the Reach Graphics Demo, our DualTextureEffect demo uses these simple base textures:
Combined with this lightmap, which we created in Maya:
The result is:
I wrote about detail textures a while ago, so won’t repeat the details here. Detail textures are a valuable technique for high resolution Xbox games, but less useful when targeting smaller phone screens.
The interesting thing is that from a runtime perspective, lightmaps and detail textures are exactly the same thing! The only difference is in the artwork. Lightmaps use a texture that is stretched just once over the world (so they provide very coarse color information), and are typically generated by programs, while detail textures are tiled many times (so they provide very fine color information), and are typically drawn by artists. But they use the exact same data formats and shader code, so once you set up a game to use DualTextureEffect, artists can choose whether they want lightmaps or detail textures just by changing their models!