Triplanar normal mapping for terrain

First, before having gotten into terrain normal mapping, I added mouse picking for objects. I have some interactivity now!

screen26-1

This is taken from an XNA code sample, then I modified it so it supports instanced meshes. So now it’s able to pick the exact instances that the ray intersets, and displays their mesh name. It doesn’t do anything other than that for now, but it’s just the first step towards editing objects in the level editor.

Mapping the terrain

The new update was for fixing a problem that’s been bugging me for a few weeks- combining normal mapping with triplanar texturing. It was a tricky affair as the normal maps get re-oriented along three planes so you also have to shift the normals accordingly. After revising how I did my regular normal mapping for other objects, I was able to get correct triplanar normal mapping for the terrain. This goes for both forward and deferred rendering.

I have only two regular textures- the base texture for mostly flat areas, and a blend texture for cliffs in steep areas. My normal map is for the cliff texture, and no normal mapping is applied for the flat areas. You can also set a bump intensity which increases the roughness of the terrain. Naturally, with great roughness comes great respons- less specular highlights. So you would have to tune the specular and roughness so it achieves a good balance. Most of the time terrain, doesn’t need specular lighting, but it’s needed for wet and icy areas.

Bump up the volume

Terrain normals, binormals, and tangents are all calculated on the CPU, which is the ideal way to go as it saves a lot of overhead of doing it every frame. In the vertex shader, the normal, binormal and tangent are transformed to view space and added to a 3×3 matrix.

output.TangentToWorld[0] = mul(normalize(mul(input.tangent, World)), View);
output.TangentToWorld[1] = mul(normalize(mul(input.binormal, World)), View);
output.TangentToWorld[2] = mul(normalize(mul(input.Normal, World)), View);

In the main pixel shader function we must first compute the normal mapping output before it can be contributed to the vertex normal outputs.

PixelShaderOutput PixelTerrainGBuffer(VT_Output input)
{
    // Sample normal map color. 4 is the texture scale
    float3 normal = TriplanarNormalMapping(input, 4);

    // Output the normal, in [0,1] space
    // Get normal into world space

    float3 normalFromMap = mul(normal, input.TangentToWorld);
    normalFromMap = normalize(normalFromMap);
    output.Normal.rgb = 0.5f * (normalFromMap + 1.0f);

    // ... Then output the other G-Buffer stuff
}

The textures are expected to be in the [0, 1] range and TriplanarNormalMapping outputs them to [-1, 1] so they are properly transformed with the TBN matrix. After that we can set the normals right back to the [0, 1] range for the lighting pass. Remember that it outputs to an unsigned format, so if we don’t do this, all values below zero will be lost.

The following function computes triplanar normal mapping for terrains.

float3 TriplanarNormalMapping(VT_Output input, float scale = 1)
{
    float tighten = 0.3679f;

    float mXY = saturate(abs(input.Normal.z) - tighten);
    float mXZ = saturate(abs(input.Normal.y) - tighten);
    float mYZ = saturate(abs(input.Normal.x) - tighten);

    float total = mXY + mXZ + mYZ;
    mXY /= total;
    mXZ /= total;
    mYZ /= total;

    float3 cXY = tex2D(normalMapSampler, input.NewPosition.xy / scale);
    float3 cXZ = float3(0, 0, 1);
    float3 cYZ = tex2D(normalMapSampler, input.NewPosition.zy / scale);

    // Convert texture lookups to the [-1, 1] range
    cXY = 2.0f * cXY - 1.0f;
    cYZ = 2.0f * cYZ - 1.0f;

    float3 normal = cXY * mXY + cXZ * mXZ + cYZ * mYZ;
    normal.xy *= bumpIntensity;
    return normal;
}

Note that where I define the texture lookups, the XZ plane is just set to a normal pointing directly towards the viewer. The X and Y values are in the [-1, 1] range, and Z is by default 1 because it is not used for view-space coordinates. So don’t forget to flip normalized negative values! Then X and Y are multiplied by the bumpIntensity. The default roughness is 1, and a roughness of 0 will completely ignore the normal map for the final output.

A lot of my texture mapping code was adapted from Memoirs of a Texel. Take caution, that if you want to follow that guide, there is a glaring mistake in that code that I noticed only after seeing this GPU Gems example (see example 1-3). You need to clamp your weight values to between 0 and 1 before averaging them out. The blog article doesn’t do this in its code. Otherwise you will get many dark patches in your textures. I fixed this with the saturate() function shown in the above example. This goes for regular texture mapping as well as normal mapping.

Here are some screenshots with the normal mapping in place. The bump intensity is set to 1.8 for a greater effect.

Edit: I’ve used some better textures for testing now. I got some free texture samples at FilterForge.

screen27-4

screen27-3

screen26-4

screen26-2

Normal computation is the same for forward rendering as it is for deferred rendering. The normals as they contribute to lighting would still be in the [0, 1] range in view space.

Advertisements

Making a flexible level selection menu: Part 2

Continuing off from last time, we’re going to improve on the Level Selection menu made using the Game State Management sample. If you haven’t done so already, read part 1 of the article so you can catch up.

For any other game modes you would want, you do need other classes that differ from GameplayScreen to some extent, because they’ll need to run different code, for different game rules and settings. But do we also need to make another class like the LevelSelectScreen class, displaying the same list of level choices, but change the Select event so it loads these other game modes? Not really, and that would be too much repetition. Instead, the menu screen can be re-purposed to recognize different entry and exit points and load the appropriate game mode.

The end result would be making the Level Select menu reusable. It will load a different GameScreen from the Level Select menu, depending on what item you selected in the Main Menu.

Main Menu -> Select “Play Game” -> Select a level -> Gameplay on selected level

Main Menu -> Select “Level Editor” -> Select a level -> Level Editor on selected level

Suppose you’re tired of coding those levels by hand and you finally want to start working on a fancy level editor. All its functions and logic will neatly reside in a LevelEditorScreen class. We can use GameplayScreen as a starting point. So let’s copy GameplayScreen.cs and rename it to LevelEditorScreen.cs, and also rename the class as such.

You may notice that it carried the new constructor and parameters that we introduced into GameplayScreen class with it. These will be used for the Level Editor as well. To distinguish it visually from the Gameplay screen, replace the "Playing level " text in the Update and Draw functions with "Editing level ", noting the trailing space at the end.

Now, let’s add another entry to the Main Menu screen. Just below the playGameMenuEntry, add another new MenuEntry with the text “Level Editor”. Add it to the MenuEntries list and assign an event handler to it as well. Copy the PlayGameMenuEntrySelected method and rename it to LevelEditorMenuEntrySelected, this will be the method to attach the event to. Here is the class, only showing the constructor and methods we just updated:

// MainMenuScreen.cs

        public MainMenuScreen()
            : base("Main Menu")
        {
            // Create our menu entries.
            MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
			MenuEntry levelEditorMenuEntry = new MenuEntry("Level Editor");
            MenuEntry optionsMenuEntry = new MenuEntry("Options");
            MenuEntry exitMenuEntry = new MenuEntry("Exit");

            // Hook up menu event handlers.
            playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
			levelEditorMenuEntry.Selected += LevelEditorMenuEntrySelected;
            optionsMenuEntry.Selected += OptionsMenuEntrySelected;
            exitMenuEntry.Selected += OnCancel;

            // Add entries to the menu.
            MenuEntries.Add(playGameMenuEntry);
			MenuEntries.Add(levelEditorMenuEntry);
            MenuEntries.Add(optionsMenuEntry);
            MenuEntries.Add(exitMenuEntry);
        }

        /// Event handler for when the Play Game menu entry is selected.

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
        }

		/// Event handler for when the Level Editor menu entry is selected.

		void LevelEditorMenuEntrySelected(object sender, PlayerIndexEventArgs e)
		{
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
		}

We now have two menu choices that take you to the Level Select menu. But Level Select still takes you to the Gameplay screen no matter where you came from. Let’s change that! The Level Select menu needs to know where to go next. To do that, we’ll have to pass the Type of the GameScreen as a new parameter to LevelSelectScreen’s constructor.

The two event handlers of the Main Menu that take you to the Level Select menu use this updated constructor, and each call to AddScreen will pass to the constructor a different Type. For selecting “Play Game”, GameplayScreen is passed, and for “Level Editor”, it is a LevelEditorScreen.

// MainMenuScreen.cs

        /// Event handler for when the Play Game menu entry is selected.

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(typeof(GameplayScreen)), e.PlayerIndex);
        }

		/// Event handler for when the Level Editor menu entry is selected.

		void LevelEditorMenuEntrySelected(object sender, PlayerIndexEventArgs e)
		{
			ScreenManager.AddScreen(new LevelSelectScreen(typeof(LevelEditorScreen)), e.PlayerIndex);
		}

// LevelSelectScreen.cs

        Type gameScreenType;

		public LevelSelectScreen(Type gameScreen)
            : base("Select a Level")
        {
            gameScreenType = gameScreen;
        /* ... */
        }

        /// Event handler for when the Play Game menu entry is selected.

		void MenuEntrySelected(object sender, PlayerIndexEventArgs e, int currentLevel)
        {
			LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
				(GameScreen)Activator.CreateInstance(gameScreenType, currentLevel));
        }

The LevelSelectScreen class now takes in a Type parameter and for the selection event handler, an Activator creates a new instance of the GameScreen, casting it down and passing the currentLevel parameter. Since the type is chosen from the Main Menu, we can always make sure that any GameScreen that gets passed from it must take an extra parameter for the level.

Our new menu gives you two possible choices to access the Level Select menu from, but you can add more if you want. Nothing more needs to be done to the Level Select menu- the menus are already linked at this point. All you need to do is, for every GameScreen that you would want to load a level, create a new menu entry for the Main Menu and pass along the type for the GameScreen.

You can try improving the Level Select menu in other ways, like showing a different list of levels depending on what game mode you choose. To start out, you may set a condition to offset the level ID in the menu.

A more complex problem would be to display an extra selection screen before the “final” screen at the end of the selection process. In racing games, you often would select a vehicle in addition to the track you’ll race on. The logic from the Level Selection screen is flexible and bare-bones enough so you can duplicate it to make a menu for selecting characters, vehicles, etc. It’s pretty much open from there, so hopefully you’ll be able to find better uses for the menu, and make it easier to manage your menu code. Let me know if you have other ideas to improve it.

Making a flexible level selection menu: Part 1

Lately, most of my work on Bubble Tower has been on creating a menu system. The menu will need to support multiple game modes, options, and a screen to select levels with. Since I am basing this off the XNA Game State Management sample, a lot of the work has been done. But my game uses a separate system to handle game states, so I modified to code to keep menus and game states as different kinds objects.

I have finished the first step of building a working level select screen for the game, and notice that it’s pretty easy to do, but it does need a few modifications in the logic. I will show you how to make your own level selection screen with the Game State Management sample, and have it be reusable for as many game modes as you like. This way it’s possible to load a level -whether it’s for a single player game, multiplayer, or for editing- by going through the same menu as an intermediate step.

I won’t be teaching you how to actually load your level data into the game. This article is mainly to show how to create a flexible menu that can pass any parameters you wish to any game screen/state so you can do whatever you want with it. Whether your levels are hard-coded or stored in separate files doesn’t matter.

Adding a new menu

The GameStateManagement sample takes you to the Gameplay screen with the following steps:

Main Menu -> Select “Play Game” -> Gameplay

We’ll add a menu which will change the course of action to the following:

Main Menu -> Select “Play Game” -> Select a level -> Gameplay on selected level

For brevity, all these graphs ignore the Loading screen.

The first thing we’ll do is to copy the MainMenuScreen.cs file from the sample project, and rename the new file LevelSelectScreen.cs. In it, rename the class to LevelSelectScreen and remove all methods except for PlayGameMenuEntrySelected. This will be renamed to MenuEntrySelected. We’ll also make changes to the menu entries to replace with level names, and modify the MenuEntrySelected method. The class should look like this so far:

// LevelSelectScreen.cs

    class LevelSelectScreen : MenuScreen
    {
        public LevelSelectScreen()
            : base("Select a Level")
        {
            // Create our menu entries.
            MenuEntry level1Entry = new MenuEntry("Level 1");
			MenuEntry level2Entry = new MenuEntry("Level 2");
			MenuEntry level3Entry = new MenuEntry("Level 3");

            // Hook up menu event handlers.
			level1Entry.Selected += MenuEntrySelected;
			level2Entry.Selected += MenuEntrySelected;
			level3Entry.Selected += MenuEntrySelected;

            // Add entries to the menu.
			MenuEntries.Add(level1Entry);
			MenuEntries.Add(level2Entry);
			MenuEntries.Add(level3Entry);
        }

        ///
<summary>
        /// Event handler for when a menu entry is selected.
        /// </summary>
        void MenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
                               new GameplayScreen());
        }
}

A lot of repetition going on, but we’ll fix this soon. Now in the MainMenuScreen class we’ll change the PlayGameMenuEntrySelected method to match this:

// MainMenuScreen.cs

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
        }

If we run the code right now, we should see the “Play Game” entry in the main menu have a different function. Instead of taking you to the Gameplay screen, it should load the new menu we just made. This will let you choose between three options, which do load the Gameplay screen. But still, the options call the same exact method with no differences in them. This is where the next step comes in.

Choosing the level

The MenuEntrySelected method must have some way of knowing what level it needs to load. We will add a parameter to the method that will pass the level number, and in turn the Gameplay screen will also need to be modified to take that info and load the specified level.

Back in the LevelSelectScreen class, update MenuEntrySelected so it takes an integer, the selectedEntry from the MenuScreen class, for an extra parameter. The parameter will also be passed into the GameplayScreen constructor so change that as well:

// LevelSelectScreen.cs

		void MenuEntrySelected(object sender, PlayerIndexEventArgs e, int currentLevel)
        {
            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
                               new GameplayScreen(currentLevel));
        }

Now there’s a problem. Because of the extra parameter, there’s no method overload that currently matches the delegate. To have the event handlers recognize the new method, let’s add an anonymous function. We’ll have to replace MenuEntrySelected on each event handler with the following delegate:

level1Entry.Selected += delegate(object sender, PlayerIndexEventArgs e)
				{ MenuEntrySelected(sender, e, selectedEntry); };

To do this on each handler will be repeating the same code. Since all the menu entries are linked to the same method, we can rewrite the LevelSelectScreen constructor to take in the entries as an array. To keep things simple, we’ll assume our game has a fixed number of levels and the array is hardcoded in. Here is the complete code for the constructor:

// LevelSelectScreen.cs

		public LevelSelectScreen()
            : base("Select a Level")
        {
			int totalLevels = 3;
			MenuEntry[] levelEntries = new MenuEntry[totalLevels];

            // Create our menu entries.
			for (int i = 0; i < totalLevels; i++)
			{
				// Add entries to the menu
				levelEntries[i] = new MenuEntry("Level " + (i + 1));
				MenuEntries.Add(levelEntries[i]);

				// Hook up menu event handlers
				levelEntries[i].Selected += delegate(object sender, PlayerIndexEventArgs e)
				{
					MenuEntrySelected(sender, e, selectedEntry + 1);
				};
			}
        }

Another problem remains, but it’s much simpler to fix. selectedEntry is part of the MenuScreen class, and can’t be accessed anywhere else. Changing it from private to protected will fix this. It will also make other custom menus that derive from MenuScreen more flexible.

Finally, we’ll put that selectedEntry parameter to use in GameplayScreen. Edit the constructor and add a variable to store the parameter as a sort of level ID:

// GameplayScreen.cs

	int currentLevel;

        /// Constructor.

        public GameplayScreen(int level)
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

			currentLevel = level;
        }

To see the effect in having the level being chosen for this screen, replace both instances of the string "Insert Gameplay Here" found in the Update and Draw methods with "Playing level " + currentLevel. If you want, you can also remove the “//TODO” text just so the context makes more sense. Run the code, and go through the Level Select menu to choose a level.

Level selection screen

Gameplay screen

The above screens are an example of what you’ll see with the new Level Select menu fully implemented. The Gameplay screen knows what level it’s running, and therefore can load contents specific to that level, and apply its Update and Draw logic to the level as it is played.

Extending the menu further

Normally, we would be done with the menu at this point, but it can still be improved and taken to another level (sorry). What if we wanted to have two or more different game modes for playing the same levels? Maybe it’s a racing game and you’d want to go for a time trial, or play head to head with other players on the same track. Or, maybe even introduce a level editor that can be used right in the game. Suddenly we have more than one reason to use the Level Select menu. In the second part of this article I’ll show you how to reuse the same menu for different GameScreens to load levels with.

XNA 4.0 variance shadow mapping

I’ve just updated and refined another code sample from XNA Community, from XNA version 3.1 to 4.0. This one is on variance shadow mapping, which is basically a way to get shadow maps that are filterable- that is, you can apply any kind of texture filter onto the shadow mapping image to give it a smoother look. Optionally, and usually, a Guassian blur filter is applied. Together, variance shadow mapping improves the visual quality of the shadows as well as giving more leeway to the size and number of textures needed to produce good results.

In the sample code, the program uses one 1024×1024 texture to produce the shadow map, and applies a two-pass filtering technique for Gaussian blur. This blur is not done in screen-space, but because the original shadow map can be filtered, it is almost indistinguishable from a screen-space blur, which will produce leaking artifacts if done with normal shadow maps.. Most of the heavy image computation is done in this step.

The shadow uses a 2-channel 32-bit texture for the depth map, in contrast to a single floating-point texture format used in conventional shadow mapping. This allows us to store two “moments”, which are simply the depth and the squared depth stored in the depth texture. From here we are able to calculate the mean depth and variance of the given pixel in the map. One noticeable drawback to variance shadow mapping is light bleeding among shadows where the shadow casters are of very different depths. An easy fix to reduce this effect would be to raise the shadow amount by a certain exponent, but raised too high and the shadows dampen too much.

I plan to use some form of variance shadow mapping to my graphics engine, but in the meantime I’ll try to make improvements on it, in order to remove the light bleeding more effectively. But in the meantime, you can download current sample project here, compatible with XNA 4.0.

References:

Bounding boxes for your meshes

While making progress with my rendering engine, one of my goals for this week is to finally implement some kind of frustum culling for the meshes. I could have taken the easier route by only using the pre-built bounding spheres with every 3D model loaded in an XNA program, but I wanted to get tighter-fitting bounding boxes instead. They simply work better for selection and picking, and plus more meshes are culled out of the frustum, which means less false positives and less geometry being rendered off-screen.

Mesh bounding boxes

Tank model with boxes enclosing all of its parts

Today I have finally finished the first major step, creating the bounding boxes. Simply figuring out how to perfectly create the boxes proved to be a frustrating chore. It wasn’t really the formula to create a box from points that was the difficult part, but getting the correct set of points from each mesh. This required a proper understanding of the GetData method for the VertexBuffer object of each mesh part. I will show you how I obtained the data to create those boxes.

There are so many requests online for wanting to figure out how to correctly build a bounding box for a mesh object, and a lot of those queries are answered with outdated information, or they don’t turn out to be the best case for that particular user. I’ve browsed through several solutions and a few code samples of how to create them, but they were not working for me. Sometimes the program crashes with an OutOfBounds exception, and other times, the boxes are obviously misaligned with the meshes, even after double checking that the correct transformations are in place. But I finally came up with a solution that used a combination of a few approaches to read and add the vertex data.

Building The Box

Bounding boxes are just simple geometric boxes, and be represented with two three-dimensional points, the minimum and maximum coordinates. The distance between those two points is the longest possible diagonal for the box, and the points can be thought of as the upper right corner in the front of the box, and the lower left corner in the back. These boxes are usually created as mesh metadata, during build time or when resources are initialized. It would be very costly to read the vertices and update the bounding boxes on every frame- besides, you should use matrix transformations to do that. Here is how we would usually initialize a mesh model:

public MeshModel(String modelPath)
{
	/* Load your model from a file here */

	// Set up model data
	boundingBoxes = new List<BoundingBox>();

	Matrix[] transforms = new Matrix[model.Bones.Count];
	model.CopyAbsoluteBoneTransformsTo(transforms);

	foreach (ModelMesh mesh in model.Meshes)
	{
		Matrix meshTransform = transforms[mesh.ParentBone.Index];
		boundingBoxes.Add(BuildBoundingBox(mesh, meshTransform));
	}
}

This would typically go in the constructor or initialization method of the class used to keep your model object, and all of its related data. In this case, we have a List of BoundingBox objects, used to keep track of all the upper and lower bounds for all meshes the model might have. Possible uses may be to do basic picking and collision testing, and debugging those tests by drawing wireframe boxes on the screen (which I will cover further in this article).

You may have noticed the BuildBoundingBox method in adding to the BoundingBox list. This is where we will create an accurate, tight-fitting box for every mesh, and to do this we will need to count all the vertex data for all its mesh parts. It requires a ModelMesh object and a Matrix object which is the bone transformation for that particular mesh.

This method will start out by looping through all the mesh parts to keep track of the maximum and minimum vertices found in the mesh so far, and returns the smallest possible bounding box that contains those vertices:

private BoundingBox BuildBoundingBox(ModelMesh mesh, Matrix meshTransform)
{
	// Create initial variables to hold min and max xyz values for the mesh
	Vector3 meshMax = new Vector3(float.MinValue);
	Vector3 meshMin = new Vector3(float.MaxValue);

	foreach (ModelMeshPart part in mesh.MeshParts)
	{
		// The stride is how big, in bytes, one vertex is in the vertex buffer
		// We have to use this as we do not know the make up of the vertex
		int stride = part.VertexBuffer.VertexDeclaration.VertexStride;

		VertexPositionNormalTexture[] vertexData = new VertexPositionNormalTexture[part.NumVertices];
		part.VertexBuffer.GetData(part.VertexOffset * stride, vertexData, 0, part.NumVertices, stride);

		// Find minimum and maximum xyz values for this mesh part
		Vector3 vertPosition = new Vector3();

		for (int i = 0; i < vertexData.Length; i++)
		{
			vertPosition = vertexData[i].Position;

			// update our values from this vertex
			meshMin = Vector3.Min(meshMin, vertPosition);
			meshMax = Vector3.Max(meshMax, vertPosition);
		}
	}

	// transform by mesh bone matrix
	meshMin = Vector3.Transform(meshMin, meshTransform);
	meshMax = Vector3.Transform(meshMax, meshTransform);

	// Create the bounding box
	BoundingBox box = new BoundingBox(meshMin, meshMax);
	return box;
}

A lot of important stuff just happened here. First is the setting up of vertexData, which is an array of VertexPositionNormalTexture structures. This is one of several built-in vertex structures that can be used to classify and organize vertex data. In particular, I used this one because my vertex buffer contains position, normal and texture coordinates up front, and no color data. It will help us determine where our position data is located, which is the only data needed to create our box.

However, this is not enough to assess the alignment and structure of the vertex buffer. We also need to know the vertex stride, which is simply the number of bytes that each vertex element contains. This number will vary depending on how your meshes are created and what data was imported, and it can even vary with each vertex buffer. With this piece of info, stepping through the vertex buffer should now be straightforward, with the vertex stride ensuring that we get accurate data. The vertexData gets sent to an inner loop where we simply examine each vertex, seeing if we have found a new minimum or maximum position. By default the minimum and maximum are set to extreme opposite values.

After the loop is done, we now have the only two vertex points that matter, and these are transformed by the mesh’s parent bone matrix. Finally, a new bounding box is created and returned from these two points. Optionally you can also choose to create a custom bounding sphere from the bounding box.

Drawing the boxes for debugging

Now with our boxes stored in place, let’s put them to some use. We are going to draw the bounding boxes that correspond to the meshes for each model. If they are drawn together with the model, the wireframes should hide behind solid objects.

Every BoundingBox has a Vector3 array which represent the eight corners of the box. The first four corners are of the front side, and the last four corners are the back. We are going to use a line list to draw the 12 edges representing the box. Each line connects a pair of corners, and the following array will form the edges:

// Initialize an array of indices for the box. 12 lines require 24 indices
short[] bBoxIndices = {
	0, 1, 1, 2, 2, 3, 3, 0, // Front edges
	4, 5, 5, 6, 6, 7, 7, 4, // Back edges
	0, 4, 1, 5, 2, 6, 3, 7 // Side edges connecting front and back
};

Now in the drawing loop, we will loop through the bounding boxes for the model, set the vertices and draw a LineList for those using any desired effect. This example uses a BasicEffect called boxEffect.

// Use inside a drawing loop
foreach (BoundingBox box in boundingBoxes)
{
	Vector3[] corners = box.GetCorners();
	VertexPositionColor[] primitiveList = new VertexPositionColor[corners.Length];

	// Assign the 8 box vertices
	for (int i = 0; i < corners.Length; i++)
	{
 		primitiveList[i] = new VertexPositionColor(corners[i], Color.White);
	}

	/* Set your own effect parameters here */

	boxEffect.World = Matrix.Identity;
	boxEffect.View = View;
	boxEffect.Projection = Projection;
	boxEffect.TextureEnabled = false;

	// Draw the box with a LineList
	foreach (EffectPass pass in boxEffect.CurrentTechnique.Passes)
 	{
		pass.Apply();
		GraphicsDevice.DrawUserIndexedPrimitives(
 			PrimitiveType.LineList, primitiveList, 0, 8,
			bBoxIndices, 0, 12);
	}
}

In practice, you should make sure that if you transformed the scale, position, or rotation of your model, to apply the same transformations to all the boxes as well. Also, remember that it is best to move any shader parameters that won’t change outside of the drawing loop, and set them only once.

That’s all there is to it. This should render solid colored wireframe boxes, not simply around your models, but in all the meshes they contain.

XNA 4.0 dual paraboloid reflection mapping

Graphics Runner did a tutorial three years ago on dual paraboloid reflection mapping, and it used an older version of XNA for the sample code. I’ve ported it completely to XNA 4.0, using the current conventions for graphics rendering and pixel shaders.

Dual paraboloid maps are simpler to implement and more efficient than traditional cube maps for reflections. Like cube maps, they are a view-independent method of rendering reflections. The tradeoff is that you get lower quality reflections for an increase in speed, but the results are still pretty good. The original blog article does a good job explaining the math behind applying the mapping effect.

Here are some of the notable differences with the updated version:

  • Simple quad mesh used in place of quad rendering class
  • The ColorClamp sampler state is deprecated, this was removed

You can view the source at GitHub, or download the sample here. It is ready to work with your XNA 4.0 projects.

Getting ObjImporter to parse quads

The App Hub’s Custom Model Importer sample loads 3D models of the ubiquitous .obj format, and is a straightforward way to get started with the XNA Content Processor. Not surprisingly, this sample just deals with handling the basics- it parses groups, converts triangles to vertices and loads diffuse textures, and not much else. It is not prepared to handle quad polygons, so I came up with a solution for it.

3D modeling with quads is very common and helpful for an artist, since they are better than triangles for reading the topology of the model, but they are not too friendly for real-time game rendering. Graphics hardware prefers triangles, and any quads from models imported into programs need to be handled appropriately. Either they may get totally ignored or crash your program when something goes wrong in your file importer. Using simpler file formats makes it a whole lot easier to understand how to solve such problems, and use the XNA content pipeline for your own needs.

The ObjImporter class of the custom model importer can be updated to handle quads in a certain winding order. I have modified it so that it can either read triangles or quads with vertices winding clockwise. To load models with quads, simply open ObjImporter.cs and look for the “f” case found in the ParseObjLine method (found around line 200) and replace it with the following code I wrote here:

// Faces (triangles and quads are supported)
case "f":

    // For triangles
    int[] polyIndices = {
        0, 1, 2
    };

    // Change the indices if a quad is needed
    if (lineTokens.Length > 4)
    {
        Array.Resize(ref polyIndices, 6);
        polyIndices[2] = 3;
        polyIndices[3] = 1;
        polyIndices[4] = 2;
        polyIndices[5] = 3;
    }

    // If the builder is null, this face is outside of a group
    // Start a new, unnamed group
    if (meshBuilder == null)
        StartMesh(null);

    // For each triangle vertex
    for (int vertexIndex = 0; vertexIndex < polyIndices.Length; vertexIndex++)
    {
        // Each vertex is a set of three indices:
        // position, texture coordinate, and normal
        // The indices are 1-based, separated by slashes
        // and only position is required.
        string[] indices = lineTokens[polyIndices[vertexIndex] + 1].Split('/');

        // Required: Position
        int positionIndex = int.Parse(indices[0],
            CultureInfo.InvariantCulture) - 1;

        if (indices.Length > 1)
        {
            // Optional: Texture coordinate
            int texCoordIndex;
            Vector2 texCoord;
            if (int.TryParse(indices[1], out texCoordIndex))
                texCoord = texCoords[texCoordIndex - 1];
            else
            texCoord = Vector2.Zero;

            // Set channel data for texture coordinate for the following
            // vertex. This must be done before calling AddTriangleVertex
            meshBuilder.SetVertexChannelData(textureCoordinateDataIndex,
                texCoord);
        }

        if (indices.Length > 2)
        {
            // Optional: Normal
            int normalIndex;
            Vector3 normal;
            if (int.TryParse(indices[2], out normalIndex))
                normal = normals[normalIndex - 1];
            else
                normal = Vector3.Zero;

            // Set channel data for normal for the following vertex.
            // This must be done before calling AddTriangleVertex
            meshBuilder.SetVertexChannelData(normalDataIndex, normal);
        }

        // Add the vertex with the vertex data that was just set
        meshBuilder.AddTriangleVertex(positionMap[positionIndex]);
    }
    break;

The notable differences here is the setup of polygon indices for both triangle and quad cases, and the vertexIndex loop parses index data from the order given directly by the index array and not straight as it is read from the line. I suppose there should still be a warning and a break to skip the addition of vertices if a n-gon has more than 4 sides, but these are rare.

Hope this helps people wanting to import mixed-polygon models into their programs!