Sign in to follow this  
Tonyyyyyyy

[XNA] Using Textured Quad for HUD

Recommended Posts

I'm trying to render an image of a gun onto a textured quad, which will be part of my HUD (think Minecraft or Ace of Spades).

However, I just can't get the image to rotate or have a Z value.

Here's some code:
[code]

public void Render()
{
//If we have an active screen, don't draw the rest of the HUD, return.
if (displayScreen != null)
{
displayScreen.Draw(spriteBatch);
return;
}

// Test

gunBillboardEffect.Parameters["World"].SetValue(Matrix.Identity);
gunBillboardEffect.Parameters["View"].SetValue(Matrix.Identity);
//gunBillboardEffect.Parameters["Projection"].SetValue(Cameras.CameraManager.ActiveCamera.Projection);
gunBillboardEffect.Parameters["Projection"].SetValue(Matrix.CreateOrthographic(Globals.GameInstance.GraphicsDevice.Viewport.Width, Globals.GameInstance.GraphicsDevice.Viewport.Height, 0, 4000f));

gunBillboardEffect.Parameters["BillboardTexture"].SetValue(tempBillboard);

foreach (EffectPass pass in gunBillboardEffect.CurrentTechnique.Passes)
{
pass.Apply();

DrawBillboard();
}

//Draw the normal HUD.

spriteBatch.Begin();

spriteBatch.End();
}

private void DrawBillboard()
{
VertexBillboard[] billboardVertices = new VertexBillboard[4];

Vector3 v1 = Vector3.Zero;

billboardVertices[0] = new VertexBillboard(new Vector3(v1.X + 10, v1.Y + 10, 0), new Vector2(1, 1));
billboardVertices[1] = new VertexBillboard(new Vector3(v1.X + 10, v1.Y - 10, 0), new Vector2(0, 1));
billboardVertices[2] = new VertexBillboard(new Vector3(v1.X - 10, v1.Y + 10, 0), new Vector2(1, 0));
billboardVertices[3] = new VertexBillboard(new Vector3(v1.X - 10, v1.Y - 10, 0), new Vector2(0, 0));

short[] billboardIndices = new short[] { 3, 2, 0, 3, 0, 1 };

Globals.GameInstance.GraphicsDevice.DrawUserIndexedPrimitives<VertexBillboard>(PrimitiveType.TriangleList, billboardVertices, 0, 4, billboardIndices, 0, 2);
}
[/code]


The code above will draw the image on the screen. However, if I add any rotation to the World matrix, or I specify a Z value for the vertices, the image disappears.
I'm not sure if this is a problem with my code, or if I'm just doing something wrong.

VertexBillboard
[code]

public struct VertexBillboard : IVertexType
{
Vector3 _position;

Vector2 _textureCoordinate;

public static readonly VertexElement[] VertexElements = new VertexElement[]
{
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
};

public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration(VertexElements);
VertexDeclaration IVertexType.VertexDeclaration { get { return VertexDeclaration; } }

public VertexBillboard(Vector3 position, Vector2 texcoords)
{
_position = position;

_textureCoordinate = texcoords;
}

public Vector3 Position { get { return _position; } set { _position = value; } }
public Vector2 TextureCoordinate { get { return _textureCoordinate; } set { _textureCoordinate = value; } }
public static int SizeInBytes { get { return sizeof(float) * 5; } }
}
[/code]


GunBillboard.fx
[code]

float4x4 World;
float4x4 View;
float4x4 Projection;

Texture BillboardTexture;

sampler BillboardSampler = sampler_state
{
texture = <BillboardTexture>;
magfilter = POINT;
minfilter = POINT;
mipfilter = POINT;
AddressU = WRAP;
AddressV = WRAP;
};

struct VertexShaderInput
{
float4 Position : POSITION0;

float2 TextureCoords : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;

float2 TextureCoords : TEXCOORD0;
float4 Color : COLOR0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;

float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

output.TextureCoords = input.TextureCoords;

output.Color.rgb = float3(1, 1, 1);
output.Color.a = 1;

return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 texColor = tex2D(BillboardSampler, input.TextureCoords);

float4 color;

color.rgb = texColor.rgb * input.Color.rgb;
color.a = texColor.a;

if(color.a == 0)
clip(-1);

return color;
}

technique Technique1
{
pass Pass1
{
// TODO: set renderstates here.

VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

[/code]

I'm fairly new to writing my own shaders, so please, be patient with me. :)

Thanks for any help
-Tony

Share this post


Link to post
Share on other sites
When drawing hud elements there is no need for any matrix transformations. You just need to create the polygon for the item in screen space, ie between 0 and 1 for both the x and y axes. What you're doing in your example is treating it as an in-world element thus rotating it is probably moving it away from where your camera is pointing just as if it was any other object in the world.

In your case you just have to set up your vertices with x/y positions something like X = screenPos.X / screenWidth; Y = screenPos.Y / screenHeight; where screenPos is the desired position of the vertex.

After that just pass it through to an effect written to handle 2D objects so it doesn't take in any matrices it just takes the input position and passes it directly to the pixel shader. I think you can actually just avoid having a vertex shader at all if you don't need one and anything that would normally get sent to the vertex shader will get sent straight to the pixel shader but I can't remember if I just made that up or not :) If you do need a vertex shader then it can be as simple as:

Data screenVertexShader( Data in )
{
return in;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this