Lighting Basics

http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Lighting_basics.php

This tutorial was fun for me, I learnt a lot working with the custom vertex structure, these changed quite a bit with the alterations XNA 4.0 made to the VertexDeclaration. I actually beefed up the struct a little adding a constructor and properties.

So the VertexDeclaration that we have had to keep changing in each tutorial up to now is actually contained in the struct, as you can see when we declare the struct it implements the IVertexType interface

public struct VertexPositionColorNormal : IVertexType

which means that we no longer need to store the declaration in our game class! Yay, less code to write. This is facilitated by constructing a VertexDeclaration rather than an array of VertexElements and under the hood XNA takes care of all of this for us.

public static VertexElement[] VertexElements = new VertexElement[]{};

we can now just go straight ahead and type:

public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration

this is now has a readonly static modifier, we want to make sure we are only calculating this once, and never ever changing it. This should never ever change at runtime, or you risk seriously corrupting the state of your game.

Next we can go ahead and just remove the line:

public static int SizeInBytes = 7 * 4;

Again XNA now takes care of this under the hood, I like this trend of having less things to worry about.

Last but not least for this struct, there was a bug in there too (not really a bug it’s more me being picky over syntax since a float and uint are the same size) which we should correct. The offset for the VertexElement storing the normal was set as

sizeof(float) * 4

but vertexPosition is a Vector3 which would be 3 floats, sizeof(float) * 3, and Color stores four values for RGBA as a uint, a quick look in reflector tell us it’s “uint packedValue”, calling sizeof(uint) returns 4 which gives us:

sizeof(float) * 3 + 4

And lastly thanks to the guys on #xna at efnet I have renamed the struct to accuratly reflect the order that the data is used, so no more will we say VertexPositionNormalColored but more correctly VertexPositionColorNormal

So the full code for the VertexPositionColorNormal struct is:

public struct VertexPositionColorNormal : IVertexType

{

public Vector3 vertexPosition;

public Color vertexColor;

public Vector3 vertexNormal;

public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration

(

new VertexElement( 0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0 ),

new VertexElement( sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0 ),

new VertexElement( sizeof(float) * 3 + 4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0 )

);

//The constructor for the custom vertex. This allows similar

//initialization of custom vertex arrays as compared to arrays of a

//standard vertex type, such as VertexPositionColor.

public VertexPositionColorNormal(Vector3 position, Color color, Vector3 normal)

{

vertexPosition = position;

vertexColor = color;

vertexNormal = normal;

}

//Public method for accessing the Position component of this custom vertex.

public Vector3 Position

{

get { return vertexPosition; }

set { vertexPosition = value; }

}

//Public method for accessing the Color component.

public Color Color

{

get { return vertexColor; }

set { vertexColor = value; }

}

//Public method for accessing the Normal component.

public Vector3 Normal

{

get { return vertexNormal; }

set { vertexNormal = value; }

}

//Implement the IVertexType interface so that we can get the vertex

//declaration straight from our custom vertex!

VertexDeclaration IVertexType.VertexDeclaration

{

get { return VertexDeclaration; }

}

}

Now we’ll need to change:

VertexPositionNormalColored[] vertices;

to:

VertexPositionColorNormal[] vertices;

and in the SetUpVertices() method when we allocate the array:

vertices = new VertexPositionNormalColored[6];

vertices = new VertexPositionColorNormal[6];

We will also need to alter the code in our Draw() method so that we use the new effect technique we created in the effects file tutorial, if you’re not already using the updated effects file you can download it from the link at the bottom of that blog post, just replace the one in your content directory of this project with the new one. So we change this line:

effect.CurrentTechnique = effect.Techniques[“Colored”];

to this:

effect.CurrentTechnique = effect.Techniques[“ColoredNormal”];

If you just copied the code from the bottom of the tutorial be sure to apply the changes that we stated in the World Space tutorial.

Last but not least, now that we obtain the VertexDeclaration from the custom vertex, we can get rid of the lines where we declare and initialize the myVertexDeclaration variable.

In the game class:

VertexDeclaration myVertexDeclaration;

In the SetUpVertices() method:

myVertexDeclaration = VertexDeclaration.VertexPositionColor;

In our Draw() method:

device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 2, myVertexDeclaration);

becomes:

device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 2);

So that concludes this tutorial, phew! I’m going to take a break for lunch now and next up is Terrain lighting.