Top

An Introduction to HLSL (Part II)

April 3, 2008

introtohlsl2_title.jpgContinuing on in our exploration of HLSL, let’s look at building a simple shader that applies a texture to a model using UV coordinates.

Before we get to anything super complicated, we still have a couple basics to cover that we didn’t touch on in part 1. Now we’ll look at passing textures to our shader, using our model’s UV coordinate map to apply that texture to our model, and setting up a couple render states. This isn’t all that complicated, although finding out exactly how to do this is a little tough.

To start it off, let’s look at our HLSL:

  1.  
  2. float4×4 World;
  3. float4×4 View;
  4. float4×4 Projection;
  5. texture myTexture;
  6.  
  7. sampler2D mySampler = sampler_state {
  8.     Texture = (myTexture);
  9.     MinFilter = Linear;
  10.     MagFilter = Linear;
  11.     AddressU = Clamp;
  12.     AddressV = Clamp;
  13. };
  14.  
  15. struct VertexShaderInput {
  16.     float4 Position : POSITION0;
  17.     float4 Color: COLOR0;
  18.     float2 TexCoord: TEXCOORD0;
  19.     float3 tNormal: NORMAL;
  20. };
  21.  
  22. struct VertexShaderOutput {
  23.     float4 Position : POSITION0;
  24.     float4 Color: COLOR0;
  25.     float2 TexCoord: TEXCOORD0;
  26. };
  27.  
  28. VertexShaderOutput VertexShaderFunction(VertexShaderInput input) {
  29.     VertexShaderOutput output;
  30.     float4 worldPosition = mul(input.Position, World);
  31.     float4 viewPosition = mul(worldPosition, View);
  32.     output.Position = mul(viewPosition, Projection);
  33.     output.Color = input.Color;
  34.     output.Color.a = 1.0;
  35.     output.TexCoord = input.TexCoord;
  36.  
  37.     return output;
  38. }
  39.  
  40. float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 {
  41.     float4 output;
  42.     output = tex2D( mySampler, input.TexCoord);
  43.     //output.r = 1 - output.r;
  44.     //output.g = 1 - output.g;
  45.     //output.b = 1 - output.b;
  46.     output.a = 1;
  47.  
  48.     return output;
  49. }
  50.  
  51. technique Main {
  52.     pass Pass0 {
  53.          ZENABLE = TRUE;
  54.          ZWRITEENABLE = TRUE;
  55.          CULLMODE = CCW;
  56.          VertexShader = compile vs_1_1 VertexShaderFunction();
  57.          PixelShader = compile ps_1_1 PixelShaderFunction();
  58.     }
  59. }

That’s the whole thing. What’s different?

First of all, we’ve got a new parameter in the header: a texture. The HLSL texture type maps directly to the XNA Texture2D type. We also have a sampler2D variable that is defined with a sampler_state block. All we really need to know here is that the sampler2D is the thing we’ll be getting our texture data from. Presumably we could set up a couple different sampler2D objects with completely different sampler_states but which reference the same texture. We can also pass in non-texture data in a texture, but that’s beyond our little exploration for now.

Now, we’ve changed the definition of our VertexShaderInput and VertexShaderOutput. We’ve done this because we need a few more things from XNA in order to texture. Most importantly, we need the uv coordinates of each vertex, so we add float2 TexCoord: TEXCOORD0; to our struct to make sure we get it.

At this point, we’ve got our texture, and we have the uv coordinates for our vertices. Our vertex shader doesn’t need to do anything with these, but it does need to pass them along to the pixel shader, which will do something with them. That’s why the VertexShaderInput and VertexShaderOutput are nearly identical.

So let’s look at the pixel shader, since that’s where the texturing actually happens. Remember, the pixel shader has one job: to return the color of a pixel. In our case, the color we need is stored at the uv coordinate of the texture, so we just need a way to grab that pixel and look at it’s color. HLSL has a function that does this for us:

tex2D(mySampler, input.TexCoord);

This is pretty simple. This function looks at the first parameter, a sampler, and returns a float4 containing the RGBA values of the pixel at location input.TexCoord, which is a 2D vector containing the UV coordinates of the pixel. Just return this value, and we’re done.

040308_screen1.jpgIf we stopped here, we’d have one small problem. Take a look at the picture to the right and see what I mean.

It might not be totally obvious from the picture what’s going on, but there is no backface culling going on. Which means the triangles which should be obscured by those triangles closest to us are getting drawn anyways. HLSL by default does no culling. So everything gets drawn, even if it overlaps something else. To fix this, we need to set a few render states. As you can see from the Pass0 body, we set the culling mode to CCW (counter clockwise) and enable z-buffering. Now everything works right.

040308_screen2.jpgWell, there wasn’t much to it but that’s our second shader. Just to make it a little more interesting, I included some commented out code to manipulate the texture color in the pixel shader. Uncomment those three lines to mess with the colors, and invert the image.

That’s all for part 2 of the Intro to HLSL series. Now I’ll have to figure out what to do in part 3. If you have any suggestions, feel free to let me know.

Comments

11 Responses to “An Introduction to HLSL (Part II)”

  1. chanka on April 4th, 2008 3:10 am

    Can you do some tutorial about applying shaders to strings. I am having some problems to do it.

    http://forums.xna.com/thread/53984.aspx

  2. GameDevKicks.com on April 4th, 2008 6:42 am

    An Introduction to HLSL (Part II)…

    You’ve been kicked (a good thing) - Trackback from GameDevKicks.com…

  3. stromdotcom on April 4th, 2008 11:04 am

    chanka-

    Can you clarify? I’m not sure I understand what you are trying to do.

  4. stromdotcom on April 4th, 2008 11:06 am

    Woops just read your thread. I see now.

    I don’t know that I’d have much to offer beyond what Nick has suggested.

  5. Phewsie on June 9th, 2008 7:19 am

    Hi,

    Thanks for all the brilliant tutorials on this website, I use them a lot!

    Do you have or know of any really good tutorials for adding a working HUD in a 3D game? I’m making a puzzle style RPG (similar to PuzzleQuest) and I need to display the health and ‘mana’ points. I’ve looked at renderTargets, but can’t find any good examples which use XNA 2.0. I’ve also looked at SpriteBatches and .PNG files, but I don’t even understand how that could work (using static images I mean).

    Thanks in advance for any help you can offer!!

  6. stromdotcom on June 9th, 2008 8:42 am

    Check out my Intro to Effects and Post Processing article here. I cover the render targets stuff in that. If you need to do that. You probably don’t though.

    It’s pretty easy. Just render your scene, then render your HUD as sprites using the spritebatch. Don’t over think it, XNA will handle all the 3D/2D stuff for you.

  7. BlackSpiderWolf on August 15th, 2008 4:07 am

    Great Tuts, I hope you make more.
    It’s nice to see somone explain the basics, i’ve been avoding HLSL because most sites make even the basics seem complicated.

    The only problem i’ve got is with textures, how do you get the textures in a .fbx. out and into HLSL?
    I understand the myeffect.Parameters[”myTexture”].SetValue(); it’s getting them to that point.
    Since i’m guessing it’s all stored inside the single Model.fbx. file.

    I’ve been searching around but i can’t seem to figure out how they do it, somthing to do with arrays and having to load them in separately for each model.

    For the next part maybe adding lights might be good.

  8. chibitotoro on October 28th, 2009 6:12 am

    Nice tutorial, I did something similar with my code before visiting this site and i ran into the same problem. Because we are using one texture in our shader, it wraps the whole model. When the model is rendered using default lighting and mesh.draw() the dome is a light blue with no textures. In both your screen shots and my own results, the vertices of the dome seem to contain UV values that maps it to the texture as well. Is there a way around this? like turning it off for those primitives that shouldnt have texture?

  9. Wholesale NFL Jerseys on August 30th, 2010 5:09 pm

    hey buddy,this is one of the best posts that I’ve ever seen; you may include some more ideas in the same theme. I’m still waiting for some interesting thoughts from your side in your next post.

  10. converse all star on August 30th, 2010 7:39 pm

    Good post.Thanks for your sharing.
    http://www.conversewu.com

  11. ibm thinkpad battery on September 2nd, 2010 1:05 am

    For laptops with a DVD accordant drive, this entails amphitheatre abashed a acclimatized DVD cine in a bend until the acclimation shuts down. On laptops afterwards a DVD drive, in entails amphitheatre abashed a sony laptop battery charger Quicktime based video bend until the acclimation shuts down. This in my appraisement gives some of the best complete angel accepting numbers available.

Got something to say?





Bottom