XNA Game Development Forums are located here: thehazymind.com/smf

Archive for the ‘Blog’ Category

Graduation, Tutorials, XNA 3.0

Saturday, August 16th, 2008

So a lot has been happening lately. I graduated (at least they haven’t yet told me that I missed some tiny obscure requirements yet.

I have been spending a lot of time lately making sure the new version of XNA coming out in a little while here is fully compatible with the current tutorials and updating the architecture of some of those tutorials a bit as well to reflect some speedup changes that have occurred in my own local copy of the engine’s code.

On top of all of that I have also been working diligently on a good GUI tutorial to try and get some nice menu systems and some in game hud and controls implemented as well. I’ll keep posting updates on that front as it continues.

Lastly, I just hired on as a full time employee at my first real job, which is actually just a continuation of the contract work i have been doing for the last year and a half. The company is a tech startup that offers online management software at a very low price point for foundations and scholarship organizations. We are doing fairly well so far, and hopefully that continues.

That’s all for now. More updates to come as I get more work done on the tutorials. Maybe even some screen shots ;)

Everything is Back

Wednesday, April 23rd, 2008

Well, I went back through an old archive and a backup of the website from a while ago and got back as much of the original content as I could from those and got it all back on here where it belongs.

I’ll have to be a little more frequent with my backups from now on I guess ;)

More Weekend Brewing

Sunday, December 3rd, 2006

My roommate Nick and I put together a nice Irish Red Ale a few weeks ago, and it is happily bubbling away in the primary fermenter. I am hoping to get time today to rack it off to the secondary sometime later on today, but that will depend on how much time I need to get some more programming projects done.

On a similar note, the batch of mead we did back in October has been bottled and is aging nicely. We did a spied apple cider mead, which I guess would be called a Metheglin Cyser. It isn’t very pretty to look at, as we made the cider ourselves simply by boiling the crap out of a bunch of apples and spices, and I don’t have much of a filtering method to get all the apple sauce that is left over out. We have saved some small bottles on the side for tasting as it ages and so far it is working out pretty well.

The batch of Huckleberry Hefeweizen I did a while back is kegged and would be mostly if not entirely gone had I not run out of CO2 leaving me with no way to get the stuff out of the keg. I’ll get some more soon. Wouldn’t want to see good beer going bad.

Forums are up!

Saturday, July 22nd, 2006

Well, I got to it and posted the forums for everyone. I decided to go with an installation of SMF because of my deep seeded loathing for the phpBB codebase that the O.C.D. in me will not let me be happy with.

The forums are located at http://www.thehazymind.com/smf, so for all of you who have something to discuss about the Hazy Mind 3D Engine, Hazy Mind Scene Editor, or just 3D game development in general, GET POSTING!!!

Have fun, but not too much. Moderators are being added soo

Forums Anyone?

Tuesday, July 11th, 2006

I have been noticing for quite a while now that there have been mini conversations going on in some of the comments on my blog here, and I was wondering what everyone would think if I simply install some kind of forum for you all to use as well. I would love to turn this site into a general resource for Managed DirectX, and the community component is a very large part of that.

For arguments sake, if I do install some forums, which would everyone like to see on here the most?

Brewing away… (Homebrewing, that is)

Saturday, June 17th, 2006

So last night (Friday) I brewed a batch of beer with my neighbor Travis from the other building. It was the first time I had ever done any homebrewing, and I am excited to see how it is going to turn out. We started out with a recipe for Jeffery C. Grisold’s Black Lager, and we ended up getting fairly close to it with the ingredients available at the homebrew store here in town.

Now, I know what you are thinking, “An all grain mash with 15 lbs of Malted Barley for your first batch ever… are you crazy or just plain stupid?” Well, actually it’s both, but so far as I can tell the beer has turned out fine. Even for a first batch. I modified our recipe to not only use our available ingredients, but also to use the temperature controlled step mash procedure in Charlize Papazian’s, “The Compete Joy of Home Brewing (3rd Edition).” For those of you who would like to try it out, the entire procedure is listed below.

  • Malts
  • Color (Lovibond)
  • Amount (lbs)
  • Great Western 2-row Domestic Malt
  • 1.8
  • 10
  • Light Munich Malt (2-row)
  • 6.5
  • 2
  • Briess Organic Caramel Malt
  • 60
  • 1
  • Briess Black Patent Malt
  • 500
  • 1
  • Organic Chocolate Malt
  • 350
  • 1
  • Hops
  • Alpha %
  • Amount (oz)
  • Domestic Hallertauer 2005 Loose Raw Hops
  • 4.75
  • 4
  • Domesitc Simcoe
  • 13.3
  • 2
  • Yeast
  • San Fransisco Lager Yeast #WLP 810 (Pitchable Liquid)
  • Other
  • Specs.
  • Amount
  • Gypsum
  • -
  • 2 oz

Procedure

  • Bring 16 liters of water with 1/2 tsp. Gypsum to 145° F
  • Add crushed malted barley and hold at 135° F for 30 min.
  • Add 7.1 liters of boiling water with 1/2 tsp. Gypsum
  • Hold at 155° F for 45 min. then raise to 158° F for 15 min.
  • Sparge to 28 liters or until the brew pot is full, bring to a boil
  • Add Hallertauer (bittering) Hops and boil for 58 minutes
  • Add Simcoe (flavor/aroma) Hops and boil for 2 minutes
  • Cool to 70° F, pitch yeast, pour into primary fermenter (should have about 21 liters)
  • Once fermentation begins, keep fermenter at 55° F for 2 weeks
  • Rack into secondary fermenter and keep for 1 week at 55° F (should have at least 19 liters)
  • Bottle or Keg (with appropriate priming sugar added) and condition for 1 week
  • Drink your Homebrew!

Back to Business

Tuesday, April 25th, 2006

Well, school is just about out here and the summer is on the ay. You know what that means. HARDCORE CODING TIME. Well, after work and taekondo of course ;), but I should have plenty of free time to get going on writing some more tutorials. Recent activity on the site suggests people are craving more, so I am going to get down to business and give the people what they want. Let’s just hope the continuing work lives up to all your expectations

Another V-Day down the tube

Wednesday, February 15th, 2006

Well, that’s two years in a row now that I have managed to be single on Valentine’s Day. Although it is the cheaper way to go, it is definately not the most pleasant way to spend the day. Of course, I wasn’t really all that worried about today in general. What I am worried about is what I am going to do with these reservations I have at Chico Hot Springs the first weekend of March.

It would have been a great anniversary weekend but as the song says, “but because there’s no more you, there’s no more aniversary.” You being the reason I made the reservations in the first place. I sure as hell am not spending the weekend there alone, but I don’t want to just ask some random cute girl to go with me since that will immediately sound:

  1. A little creepy
  2. A little like I am trying to get laid…
  3. A little like I am about to kidnap someone
  4. Really Pathetic
  5. Like the most elaborate pickup line ever

Regardless of how many of the above are true… I am still not going alone. I would just hate to have to cancel them as they are very difficult to get without calling insanely far in advance (at least the private cabin that I got is…) Oh, well. I guess I’ll just look for someone who won’t think it is too creepy/weird/pickupliney and hope for the best.

I’ll tell you where we all are…

Tuesday, January 31st, 2006

Earlier tonight I overheard my roommate Ryan reading a blog from one of his female friends entitled “Where have all the good men gone?” Her answer to this perplexing question was “oh yeah, to the other women.” Now I don’t exactly agree with that statement, but I do see her point.

I would be more inclined to say all the good men have done one of two things:

  • Become an asshole because they see that all the good men always lose
  • Decided to be single on purpose (this is what I am doing) because they are sick of being good men and getting badly hurt

I don’t know if the good men of the world would agree with me on that point or not, but that is how I see it anyway.

Implementing Lighting with Shaders

Sunday, January 22nd, 2006

Now that we have an easy way of running shaders on our meshes, I thought it would be a good time to implement a simple lighting shader so we can start making the objects in our world look a little more like they belong there.

Step 1: Temporary Tiger Modifications

To start out, I am going to add a temporary line of code in our HMMesh class to change our tiger into the simple DirectX Teapot. I am doing this mostly because playing with this lighting shader will make more sense if at first we don’t have to worry about texturing the model. Here is the temorary code:

// Directly beneath the myMesh = Mesh.FromFile() line myMesh = Mesh.Teapot(myDevice);

Step 2: Baby Steps, Adding to our current shader

Now that we have a lovely little teapot mesh being rendered on the screen with a grossly stretched and deformed tiger texture on its surface, it seems time to get down to making our lighting work. The lighting model that we will be implementing is called Phong Shading (named after its creator, Bui Tuong Phong), and it consists of three separate lighting components that will be added together to get our final light values on the mesh. From here on out this tutorial will be broken into sections for each of the three types of lighting.

Component 1: Ambient Lighting

Ambient lighting is the type of light that brightens everything in the scene evenly. It usually comes from a very bright, very far away source like the sun. Because everything gets lit evenly, it is the simplest type of lighting to implement. The modifications to our shader script will be very minimal to accomplish this simple task. Before we simply modify the shader though, let’s make a copy of it and rename it to TransformPhong.fx so we can keep all our our different rendering types in their own separate files for ease of use later. Now, the only thing we need to change about this shader is in the Texture() function (which I am going to rename Phong in this script). Here is what the new pixel shader section will look like:

sampler TextureSampler; float4 Ambient = float4(0.25, 0.25, 0.25, 1.0); struct PS_INPUT { float2 Texcoord : TEXCOORD0; }; float4 Phong(PS_INPUT Input) : COLOR0{ return saturate(Ambient); }; technique TransformPhong { pass P0 { VertexShader = compile vs_2_0 Transform(); PixelShader = compile ps_2_0 Phong(); } }

The float4 values were chosen as 0.25 simply because we only want our ambient light to brighten the model a little bit so we have room to add in other light components later. If you run the demo now, you will see a nice little gray Teapot in the middle of the screen. There is one thing about this type of lighting that has always bothered me slightly, and that is the fact that none of the contours of the object are visible at all. Even though it is supposed to be an object with even lighting on all sides, in the real world we are still able to distinguish edges on objects like this, so I am going to add an edge component to the final color to help out with this.

The edge component will require a few more changes and a bit more math than the simple ambient lighting addition, but it won’t be anything major. To start off I will explain the property of vectors that we are going to be taking advantage of to do this and all of our other lighting calculations, that of the dot product.

The dot product of a vector is defined like this:

V.W = ||V|| * ||W|| * cos(theta) where theta is the angle between the two vectors

Now since most of our lighting calculations will require that we get the angle between two vectors (the view and the light direction, or the light direction and a surface normal) or a representation of the angle in cosine form, we can manipulate this equation to give ourselves a simple way of obtaining this value using the built in shader functions normalize() and dot():

V.W = ||V|| * ||W|| * cos(theta) normalize both vectors, making ||V|| and ||W|| = 1: V.W = 1 * 1 * cos(theta) = cos(theta) V.W = cos(theta) Now, to retrieve the (cosine of the) angle between two of our vectors in a shader: float3 V = normalize(vector1); float3 W = normalize(vector2); float cosangle = dot(V, W);

The two vectors that we will be using to calculate our edge component will be the view vector, which is projected from the camera’s position to the position of the mesh being drawn, and the normal that we calculated for each vertex in the mesh when we first wrote the HMMesh class. We will need to pass the camera’s position to the shader in the same way that we are already passing the WorldViewProj matrix, but to do so, we will first need to add a property to the camera class in Vector4 format so we can use the SetValue function to pass it along. Here is the new property in the camera class.

public Vector4 Position4 { get { return new Vector4(position.X, position.Y, position.Z, 0); } }

We will not only need to be passing the camera position to the shader, but the World matrix as well so that we can transform the positions and the input vectors into the objects world space. Using the new camera property in the ShaderRender function, we pass the camera’s position and our World matrix along like this:

// In the ShaderRender function myShader.MyEffect.SetValue(”EyePosition”, myCamera.Position4); myShader.MyEffect.SetValue(”World”, matWorld); // In the TransformPhong shader file float4×4 World; float3 EyePosition;

Now that we have our EyePosition going into our shader, we need to normalize it and pass it through to the pixel shader so we can add it into our final lighting calculation there. Here are the modifications to the shader:

// In the VS_INPUT struct float3 Normal : NORMAL0; // In the VS_OUTPUT struct float3 Normal : TEXCOORD1; float3 ViewDirection : TEXCOORD2; // In the Transform function float3 ObjectPosition = mul(Input.Position, World); Output.Normal = mul(Input.Normal, World); Output.ViewDirection = EyePosition - ObjectPosition; // In the PS_INPUT struct float3 Normal : TEXCOORD1; float3 ViewDirection : TEXCOORD2; // In the Phong function float3 Normal = normalize(Input.Normal); float3 ViewDirection = normalize(Input.ViewDirection); float EdgeComponent = dot(Normal, ViewDirection); float4 TotalAmbient = Ambient * EdgeComponent; return saturate(TotalAmbient);

Rendering our teapots now will give us an image that looks much more true to life because all of the edges are now visible. Now that we have an ambiently lit set of teapots, we should add in our second component of Phong lighting, the Diffuse component.

Component 2: Diffuse Lighting

Diffuse lighitng is the type of lighting that is affected by the direction of a light source, and its position relative to the object being lit. For this type of lighting calculation, we will need to pass the light position the same way we passed our camera position along to the shader. Here is the code for that:

// In the ShaderRender function myShader.MyEffect.SetValue(”LightPosition”, new Vector4(0.0f, 850.0f, 1000.0f, 0.0f)); // Beneath our float4 Ambient value float4 Diffuse = float4(0.80, 0.80, 0.80, 1.0); // In the VS_OUTPUT struct float3 LightDirection : TEXCOORD3; // In the Transform function Output.LightDirection = LightPosition - ObjectPosition; // In the PS_INPUT struct float3 LightDirection : TEXCOORD3; // In the Phong function float3 LightDirection = normalize(Input.LightDirection); float NDotL = dot(Normal, LightDirection); // The cos(angle) between the normal and light direction float4 TotalDiffuse = saturate(Diffuse * NDotL); return saturate(TotalAmbient + TotalDiffuse);

Now when we render our scene we will see the teapots looking like they are being lit by the sun in our skybox. This is close to the final realistic lighting that we have been working towards. The last component of our Phong lighting model is called the Specular component. It is usually used for simulate a shiny plastic or matallic object, or anything else with a smooth reflective surface.

Component 3: Specular Lighting

Luckily, the specular component of light is calcuated based on all of the values that we have already passed into our shader and requries very little change to our pixel shader code. One thing that we will pass however is the specular power value, which will affect how shiny the surface looks, and how large the reflective areas appear. Here are the final changes to include specular lighting in our model:

// In the ShaderRender function myShader.MyEffect.SetValue(”SpecularPower”, 16); // Under our float4 Ambient and Diffuse values float4 Specular = float4(0.50, 0.50, 0.50, 1.0); float SecularPower; // In the Phong function // These values are based directly from the Phong function defined in this form: // R = 2.0 * N * N.L - L // RDotV = R.V // S = (R.V)^N * SIntensity float3 Reflection = normalize((2.0 * Normal * NDotL) - LightDirection); float RDotV = max(0.0, dot(Reflection, ViewDirection)); float4 TotalSpecular = saturate(Specular * pow(RDotV, SpecularPower)); return saturate(TotalAmbient + TotalDiffuse + TotalSpecular);

We use the max() function to make sure the values on the unlit side of the object don’t get brightened by the specular component incorrectly. With the addition of our Specular component the Phong lighting model is complete. Here is the final shader file in its complete form.

float4×4 WorldViewProj; float4×4 World; float3 EyePosition; float3 LightPosition; struct VS_INPUT { float4 Position : POSITION0; float2 Texcoord : TEXCOORD0; float3 Normal : NORMAL0; }; struct VS_OUTPUT { float4 Position : POSITION0; float2 Texcoord : TEXCOORD0; float3 Normal : TEXCOORD1; float3 ViewDirection : TEXCOORD2; float3 LightDirection : TEXCOORD3; }; VS_OUTPUT Transform(VS_INPUT Input){ VS_OUTPUT Output; Output.Position = mul(Input.Position, WorldViewProj); Output.Texcoord = Input.Texcoord; float3 ObjectPosition = mul(Input.Position, World); Output.Normal = mul(Input.Normal, World); Output.ViewDirection = EyePosition - ObjectPosition; Output.LightDirection = LightPosition - ObjectPosition; return Output; } float4 Ambient = float4(0.25, 0.25, 0.25, 1.0); float4 Diffuse = float4(0.80, 0.80, 0.80, 1.0); float4 Specular = float4(0.50, 0.50, 0.50, 1.0); float SpecularPower; struct PS_INPUT { float2 Texcoord : TEXCOORD0; float3 Normal : TEXCOORD1; float3 ViewDirection : TEXCOORD2; float3 LightDirection : TEXCOORD3; }; float4 Phong(PS_INPUT Input) : COLOR0{ float3 Normal = normalize(Input.Normal); float3 ViewDirection = normalize(Input.ViewDirection); float3 LightDirection = normalize(Input.LightDirection); float EdgeComponent = dot(Normal, ViewDirection); float4 TotalAmbient = saturate(Ambient * EdgeComponent); float NDotL = dot(Normal, LightDirection); float4 TotalDiffuse = saturate(Diffuse * NDotL); float3 Reflection = normalize((2.0 * Normal * NDotL) - LightDirection); float RDotV = max(0.0, dot(Reflection, ViewDirection)); float4 TotalSpecular = saturate(Specular * pow(RDotV, SpecularPower)); return saturate(TotalAmbient + TotalDiffuse + TotalSpecular); }; technique TransformPhong { pass P0 { VertexShader = compile vs_2_0 Transform(); PixelShader = compile ps_2_0 Phong(); } }

Now to adjust the brightness and the effectivness of each component of the light all you need to do is change the float4 Ambient, Diffuse, and Specular values, and to change the reflectivity of the surface to simply change the SpecularPower variable. With this completed lighting shader, there is only one thing left we should probably add here, and that is the texture of the mesh. The texture color will be calculated the same way we did in the original shader file that we have been adding to for this tutorial. To keep our library of shaders growing, I am going to copy the final version of the TransformPhong.fx file and name the new one TransformTexturePhong.fx. The only change between this and the TransformPhong shader is shown below:

float4 TextureColor = tex2D(TextureSampler, Input.Texcoord); return TextureColor * saturate(TotalAmbient + TotalDiffuse + TotalSpecular); // Changes in the HMDemo class HMShader shader1 = new HMShader(”TransformPhong”, @”../../../Shaders/TransformPhong.fx”, demo1.MyDevice); HMShader shader2 = new HMShader(”TransformTexturePhong”, @”../../../Shaders/TransformTexturePhong.fx”, demo1.MyDevice); demo1.MyScene.AddShader(shader1); demo1.MyScene.AddShader(shader2); mesh1.SetShader(”TransformPhong”); mesh2.SetShader(”TransformTexturePhong”);

I also took out the line that changed our tigers to teapots now that we have the texturing and lighting both working together. So there you have it, a full working Phong lighting model with textured meshes. The next step in the shader implementation process is to set our engine up to allow multiple lights with alpha blending. This will be the topic of the next two tutorials coming soon.

Happy Shading!