Archive for the ‘Blog’ Category

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!

New York, New York… no really

Sunday, January 8th, 2006

So, remember that post I wrote a long time about the friend I haven’t seen since forever that now lives in New York? Well in case you don’t: New York, New York. Anyway, this time it really is going to happen.

I won’t go into all of the details here, because chances are if you are reading this you probably know them all already, but let’s just say I need a little vacation. Now granted I understand that going online yesterday night at 6:00 PM and buying a plane ticket for a week stay in NY is a bit spontaneous and not very like me, but everyone needs a little craziness in their life every now and then right?

At any rate, I will be staying with my Friend/Older Brother Type/Ex Youth Pastor/Future Business Partner? for the next week and hopefully having a blast the whole time. The only problem with this is that the day I get back I get to start going to class again :) WHOO HOO. Oh well, it will still be a great trip

That Good Ol’ Game Design Itch

Wednesday, December 28th, 2005

Every now and then I get these little voices in the back of my head that tell me I should quit my job, drop out of school, cut off all human contact, and start working on coding some amazing video games so you can get going on your damn goals, but then I stop and think about how much electricity it takes to run a computer and how difficult it is to generate that without simplay sending a check to the power company every month and I change my mind

I’m also entirely positive I couldn’t cut off human contact if I wanted to. Not only would I go entirely crazy in about 20 minutes just knowing that I was never going to see another human again, but I’m am also pretty sure I’d be in a terrible mood the whole time, and who can write good games when they are in a bad mood? Not me.

And anyway, I would much rather keep my current job, finish school, go on dates with my wonderful/gorgeous girlfriend, and hang out with other nerdly types when the chance arrives than sit at home and stare into the cold glow of my LCD’s while I listen to the ever comforing humm of my CPU fan… (uh huh..)

One of these days though, the game design itch is gonna come back, and I’ll just have to tell it to be patient and let me get there when I get there. Even if that might still be a while

Sigh…

Thursday, December 15th, 2005

Ok, as many of you who know me already know, school is not exactly my thing. Regardless of how smart I am, I just am not that good at school nor do I really care to be. I have absolutely no problem with skirting by on C’s (sorry mom, but you already knew it was true :/), but when my professors screw up and don’t put in test grades in the book and drop me to a failing grade I get a little angry.

Hopefully Mr. Year Back Yoo will be around in his office tomorrow so I can go in and ask him why he neglected to insert my final test score. Now part of the problem I am fully aware is that I missed a few of the tests in that class :/ but for once I did all the damned homework in one and I would like to at least have the friggin C to show for it…

Oh well. I am not going to stress too much about it because there are enough things going on in my life right now to completely remove any stress that school might cause me to have, (even when my parents scream at me about wasting my money if I’m not going to at least TRY to get a grade or two, which is completely understandable, but only relative to what they find important in life, and I’m not entirely sure our views in that respect are completely parallel.)

Anyway, to sum up this terrible semester I will probably end up retaking most of the classes I took even if I pass them just because I’m pissed and want to replace the grades I do get with something better. (Damned 8:00 AM Tests)

On the lighter side, I finally found the perfect girl and the perfect job (yes yes I know too good to be true and all that, but I think there are exceptions to any rule) and I am incredibly ecstatic about both of those areas of my life and all the time I get to sit and think about where they might be going (sounds a bit more upbeat than my previous whiny IS THERE NO GIRL FOR ME???? posts of past eh?)

Anyway, I have a physics final in 1.5 hours so I am going to hit the books (literally, with something very blunt and heavy), so until next time… ___Insert whitty closing line here___

World AIDS Day

Thursday, December 1st, 2005

Just thought I’d show my support for a group of people who probably go through the holdiays not being thought about as much as they should be. Visit the website and show some support by sporting a red ribbon. Anything we can do to help out those who are having a less fortunate or difficult holiday.

Support World AIDS Day

Is it just me or…?

Saturday, October 29th, 2005

Anybody else get the feeling that somebody is stealing all of their good ideas? Ever since about the fourth grade I have been having some very random creative spark moments where I will get an awesome idea and tell a bunch of people about it, and then somehow two months later it shows up in a movie or a commercial or a video game and someone else is making a million from it. Now I am not saying that every idea I have ever had is an amazing one or that they are all being stolen, but I can remember quite a few (I won’t list them ’cause you won’t believe me anyway.)

The reason I ask is this: I am trying to someday become a game designer. I want to make games for a living, and not the way that every other goddamned Computer Science student in the world does, I am actually doing something about it (as some of you have already noticed from reading my 3D Engine tutorials.) Since I am trying so hard to get to the point of making games for a living, I spend much of my time thinking about different games I could design and how they would play out.

Tonight I was playing x-box and decided to come upstairs to do a little computer work, and just as I shut the game off and started to head to the microwave to grab my newly cooked bowl of beef ramen I got the greatest idea for a game. Wouldn’t it be great if there was a game in the *** genre where you *** for *** in the ***. Sweet idea huh? Exactly… I can’t say a damn word about it. I’m even afraid to type it in a document on my computer ’cause I don’t want another million dollar idea being taken. Especially now that I am actually capable of producing said idea and am not simply a 12 year old grade schooler.

Maybe I’ll tell you what it is when I have copyrighted it and gotten it half done. Maybe… maybe… Maybe not…

Exciting events in the world of music in the BOZ

Thursday, October 13th, 2005

Well, the concerts went well, if well means I didn’t get any permanent injuries. I only had to tackle/call in arrests on a few people at Danzig and Chevelle, and the Motley Crue concert was fairly laid back since I was just working the smoking area; although, I did see about 10 people get thrown out/escorted to a police car by four of our outstanding Bozeman, MT policemen.

There was only 1 minor personal encounter at Motley Crue and it was just stopping a guy who was bolting to the door from the 4 cops escorting him down the hallway, which wasn’t hard because he was drunk off his ass and he damn near fell down the second something solid got in his way.

All in all it was a very interesting few days. Hopefully the B.B. King concert is a bit more laid back so I can actually enjoy the music in stead of worrying about being chokes by a spiky belt or stabbed by a deer skull.

Those aren’t the kinds of people that will be attending a B.B King concert anyway, so I’m sure I’ll be fine.

Silver Sharpies and B.B. King

Tuesday, October 4th, 2005

My friends Nick and Heather were over at my appartment for dinner the other night, and Heather brought up that she needed people to work security at the Valley Ice Gardens and Brick Breeden fieldhouse for some concerts and I told her I could so it, so this Sunday I will be starting with my first job there working at the Chevelle concert.

Now I am not exactly Chevelle’s biggest fan, nor do I usually listen to their genre of music all that often (I do have slightly odd taste in music after all) but I’m sure it will be a good concert at any rate. The one I am really excited about is the B.B. King concert coming up on October 21st, where I will without a doubt be having the time of my life. I am hoping to be able to go backstage (or work back there) and meet B.B. and possibly get him to slap a big signature on my guitar with a silver sharpie.

Guess we’ll have to wait and see how lucky I am that day. Hope it goes as planned. I’ll definately post some pictures on here within a few days after the concert.

A bit of Nerd Chatter

Monday, September 12th, 2005

So I had to take down our internet again because our wonderful friends in tech support at Bresnan have no clue what they are talking about (or they are lying to me to protect their jobs). Now although I do know some of the people in tech over there and they are quite knowledgable about the subjects that pertain to using their internet, the guy I ended up talking to was either really confused or acted like it extremely convincingly.

Here is how the conversation basically went:

  • Mike:We have three computers on a switch… two of them are working, the third isn’t.
  • Tech:You have three computers on a switch… two of them are working, the third isn’t?
  • Mike:Yes…….
  • Tech:That’s really confusing… only one should work. We don’t support switches.
  • Mike:Interesting… so those switches I have been using for the past 4 years with your service were just pretending then?
  • Tech:I guess.
  • etc. etc.

Needless to say, not the most productive tech support conversation I have held. I ended up calling my friend that works in tech there (who happens to sit behind the afformentioned genius) and trying about 5 things before deciding on a solution that basically makes my computer a router. A bit of a pain in the ass because now my computer has to be on most of the time (at least when my roommates want to use internet) whether I am using it or not, and that will without question raise the temperature of my room like 10 degrees.

Oh well, I guess it’s better than a half functional network.

P.S. Well I decided having my computer on at night waking me up all the time with its incessently loud cooling fans (of which there are 8) and having a disgustingly hot room is not to my liking, so I just gave in and spent the $60 I shouldn’t have had to on a router. Hopefully I can still afford my bills this month!

Taekwondo Class Rocks

Wednesday, September 7th, 2005

Today’s class was awesome for a couple of reasons. First of all there were only 4 people there, which for the night class is a very rare occurence. This small number of people changed 2 things about the class. The warmup/cardio workout at the beginning seemed to be a lot harder, and the technqiue section was a lot more effective because Master Saltz could spend more time with each student helping them with their specific corrections on the different kicks where normally he would only be able to give a few pointers every now and then.

Also, today’s class left me feeling even more refreshed than I usually do, which isn’t a bad thing except that I don’t get home until 10:00 P.M. and I feel like I am ready to take on another 12 hours of daylight before I need to sleep again.

I guess I do have some work to catch up on (damn school is taking all my time lately) so it will be a welcome boost in about 4 hours when I would normally be drooping at the keyboard. I just hope this doesn’t mess up my sleep schedule as much as all of my other random hobbies seem to :)