Using the Effect Interfaces
BasicEffect
implements three different interfaces that are generic enough to be used
by multiple types of effects. Each of the built-in effects in Game
Studio 4.0 uses at least one of these interfaces, and your own custom
effects could also. This enables you to easily cast your effects to
these interface types to do common operations. The most common is the
following:
public interface IEffectMatrices
{
Matrix Projection { get; set; }
Matrix View { get; set; }
Matrix World { get; set; }
}
This is to give you a spot to set your matrices generically. As expected, there is also one to handle basic lighting:
public interface IEffectLights
{
Vector3 AmbientLightColor { get; set; }
DirectionalLight DirectionalLight0 { get; }
DirectionalLight DirectionalLight1 { get; }
DirectionalLight DirectionalLight2 { get; }
bool LightingEnabled { get; set; }
void EnableDefaultLighting();
}
Finally, there is an interface you can use if your effect supports fog:
public interface IEffectFog
{
Vector3 FogColor { get; set; }
bool FogEnabled { get; set; }
float FogEnd { get; set; }
float FogStart { get; set; }
}
All of these interfaces are
used by the built-in effects and are there for you to implement in your
own custom effect classes to write generic code for many common
operations. Now let’s move on to the next built-in effect type.
Using DualTextureEffect
You might have noticed that while using BasicEffect, you can use only a single texture. The DualTextureEffect enables you to use two. A common use of a dual texture is for either light maps or decals. This effect implements IEffectMatrices and IEffectFog, but not IEffectLights,
so you don’t get lights here! Because a common use of this is for light
maps, that makes sense, too. Let’s see it in action. Create a new
project and add a few files in your content project. Add the model
(dualtextureplane.fbx), the first texture (ground.jpg), and the light
map (lightmap.png). Also add a couple new variables to your project:
Model model;
DualTextureEffect effect;
To show this effect, render a
single plane with a texture on it (it can be the “ground”). To do this,
add the following code to your LoadContent method:
model = Content.Load<Model>("dualtextureplane");
effect = new DualTextureEffect(GraphicsDevice);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 50.0f);
effect.View = Matrix.CreateLookAt(
new Vector3(0, 32, 32), Vector3.Zero, Vector3.Up);
effect.DiffuseColor = Color.DarkGray.ToVector3();
effect.Texture = Content.Load<Texture2D>("ground");
This loads your model and
effect and sets up your camera. It also sets the first texture and
updates the diffuse color (the default is bright white). You need to add
a DrawModel call to use this effect, so add that as follows:
private void DrawModel(Model m, Matrix world, DualTextureEffect be)
{
foreach (ModelMesh mm in m.Meshes)
{
foreach (ModelMeshPart mmp in mm.MeshParts)
{
be.World = world;
GraphicsDevice.SetVertexBuffer(mmp.VertexBuffer,mmp.VertexOffset);
GraphicsDevice.Indices = mmp.IndexBuffer;
be.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0,
mmp.NumVertices, mmp.StartIndex, mmp.PrimitiveCount);
}
}
}
This is similar to your last DrawModel
call, except without the generalization of enabling a hierarchy of
world transforms, it simply sets the effect and draws the geometry. Now
include a call to this method in your Draw call:
DrawModel(model, Matrix.Identity, effect);
After you run this, you
expect to see the plane rendered on the screen with the single texture
showing up, but all you see is a black square. This is because you don’t
have the second texture loaded, and the default color it returns if the
texture isn’t there is black. It then combines the two colors from the
textures, but black combined with anything else gives you black, so you
see nothing. Temporarily set your second texture to light grey using the
following code at the end of your LoadContent method:
effect.Texture2 = new Texture2D(GraphicsDevice, 1, 1);
effect.Texture2.SetData(new Color[] { new Color(196, 196, 196, 255) });
This shows you the plane
rendered on the ground with a single texture. Well, it is two textures,
with the second texture as a single light gray pixel. Not hugely
exciting, but if you add this line to the end of your LoadContent method, the second texture is loaded, and running the application makes the ground appear to have spotlights on it (see Figure 1):
effect.Texture2 = Content.Load<Texture2D>("lightmap");
You can also set effect.Texture
to the single light gray pixel and see the light map rendered alone on
the plane. With this effect, you can perform quite a range of techniques
using two textures, and light maps as one of them!