I have a project for which I have to render a fullscreen, background image. Based on the methods we use for rendering, using SpriteBatch is not an option. So I chose what I figured was the easiest method: render a quad using screen space.
So first I created this class to be my class for screen space quads (since I also will later need to render background images that aren't full screen):
public class ScreenSpaceQuad : IDisposable
{
VertexDeclaration vd;
Effect effect;
Texture2D texture;
readonly Rectangle? location;
readonly VertexPositionTexture[ vertices = new VertexPositionTexture[
{
new VertexPositionTexture(new Vector3(-1f, -1f, 1f), new Vector2(0f, 1f)),
new VertexPositionTexture(new Vector3(-1f, 1f, 1f), new Vector2(0f, 0f)),
new VertexPositionTexture(new Vector3(1f, -1f, 1f), new Vector2(1f, 0f)),
new VertexPositionTexture(new Vector3(1f, 1f, 1f), new Vector2(1f, 1f)),
};
public ScreenSpaceQuad(
ContentManager content,
GraphicsDevice device,
Texture2D texture)
{
location = null;
this.texture = texture;
load(content, device);
}
public ScreenSpaceQuad(
ContentManager content,
GraphicsDevice device,
Texture2D texture,
Rectangle location)
{
this.texture = texture;
this.location = location;
load(content, device);
}
void load(ContentManager content, GraphicsDevice device)
{
effect = content.Load<Effect>("ScreenSpaceQuad");
vd = new VertexDeclaration(device, VertexPositionTexture.VertexElements);
}
public void Draw()
{
GraphicsDevice d = effect.GraphicsDevice;
d.VertexDeclaration = vd;
int sWidth = d.Viewport.Width;
int sHeight = d.Viewport.Height;
int tWidth = texture.Width;
int tHeight = texture.Height;
if (location.HasValue)
{
float x1 = (float)location.Value.X / sWidth;
float y1 = (float)location.Value.Bottom / sHeight;
float x2 = (float)location.Value.Right / sWidth;
float y2 = (float)location.Value.Y / sHeight;
x1 = x1 * 2f - 1f;
x2 = x2 * 2f - 1f;
y1 = y1 * 2f - 1f;
y2 = y2 * 2f - 1f;
vertices[0].Position = new Vector3(x1, y1, 1f);
vertices[1].Position = new Vector3(x1, y2, 1f);
vertices[2].Position = new Vector3(x2, y1, 1f);
vertices[3].Position = new Vector3(x2, y2, 1f);
}
else
{
float wScale = (float)tWidth / sWidth;
float hScale = (float)tHeight / sHeight;
float x = Math.Max(wScale, 1);
float y = Math.Max(hScale, 1);
vertices[1].Position = new Vector3(-1f, y, 1f);
vertices[2].Position = new Vector3(x, -1f, 1f);
vertices[3].Position = new Vector3(x, y, 1f);
}
effect.Parameters["DiffuseTexture"].SetValue(texture);
effect.Begin();
foreach (EffectPass p in effect.CurrentTechnique.Passes)
{
p.Begin();
d.DrawUserPrimitives(PrimitiveType.TriangleStrip, vertices, 0, 2);
p.End();
}
effect.End();
}
public void Dispose()
{
vd.Dispose();
effect = null;
texture = null;
}
}
So for my full screen quad, I call the first constructor, setting location to null and thus running the code path in Draw that should set up vertices for rendering in full screen. As a note here, I'm well aware there will be scaling issues if the texure is smaller than the viewport being that I don't scale equally on both axis, but since my current texture is larger than the viewport, that's not the current issue.
The shader I load in the code above is this:
texture DiffuseTexture;
sampler2D diffuseSampler = sampler_state
{
Texture = <DiffuseTexture>;
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
AddressU = wrap;
AddressV = wrap;
};
struct VertexInput
{
float3 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct VertexOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
VertexOutput VertexShaderFunction(VertexInput input)
{
VertexOutput output = (VertexOutput)0;
output.Position = float4(input.Position, 1);
output.TexCoord = input.TexCoord;
return output;
}
float4 PixelShaderFunction(VertexOutput input) : COLOR0
{
return tex2D(diffuseSampler, input.TexCoord);
}
technique Technique1
{
pass Pass1
{
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
Yet, when I go to render, the image appears skewed. It's not just scaling improperly, but it appears as though the texturing is simply wrong and is being skewed (e.g. one horizontal line in the image winds up on an angle when rendered). Is there some trick to this that I'm missing?