Sign in to follow this  

Issue Rendering Full Screen Quad in Screen Space

This topic is 3295 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Your texture coordinates appear to be incorrect. Shouldn't


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)),
};



be


readonly VertexPositionTexture[] vertices = new VertexPositionTexture[]
{
new VertexPositionTexture(new Vector3(-1f, -1f, 1f), new Vector2(0f, 0f)),
new VertexPositionTexture(new Vector3(-1f, 1f, 1f), new Vector2(0f, 1f)),
new VertexPositionTexture(new Vector3(1f, -1f, 1f), new Vector2(1f, 0f)),
new VertexPositionTexture(new Vector3(1f, 1f, 1f), new Vector2(1f, 1f)),
};



?

Share this post


Link to post
Share on other sites
Actually you'd want the texture coordinates like this:


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, 1f)),
new VertexPositionTexture(new Vector3(1f, 1f, 1f), new Vector2(1f, 0f)),
};
[


Also...don't forget about this.

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
Quote:
Original post by Mike.Popoloski
Ah, you're right. I was going to say something about the texels to pixels issue, but forgot to. The XNA SpriteBatch handles it in the shader.

From now I'm just pointing to Drillian's Understanding half-pixel and half-texel offsets. Looks like Nick needs it too :)


Ahh, that's a good one to add to my bookmarks. [smile]

Share this post


Link to post
Share on other sites
I figured while I was home from work I'd post my own code for this, just for sake of completeness.

-Making the VB for the quad (I also store an in index for retrieving the location of the corresponding frustum corner, so don't worry about the third component of texCoordAndCornerIndex)

protected VertexBuffer CreateFullScreenQuad(VertexDeclaration vertexDeclaration)
{
// Create a vertex buffer for the quad, and fill it in
VertexBuffer vertexBuffer = new VertexBuffer(graphicsDevice, typeof(QuadVertex), vertexDeclaration.GetVertexStrideSize(0) * 4, BufferUsage.None);
QuadVertex[] vbData = new QuadVertex[4];

// Upper right
vbData[0].position = new Vector3(1, 1, 1);
vbData[0].texCoordAndCornerIndex = new Vector3(1, 0, 1);

// Lower right
vbData[1].position = new Vector3(1, -1, 1);
vbData[1].texCoordAndCornerIndex = new Vector3(1, 1, 2);

// Upper left
vbData[2].position = new Vector3(-1, 1, 1);
vbData[2].texCoordAndCornerIndex = new Vector3(0, 0, 0);

// Lower left
vbData[3].position = new Vector3(-1, -1, 1);
vbData[3].texCoordAndCornerIndex = new Vector3(0, 1, 3);


vertexBuffer.SetData(vbData);
return vertexBuffer;
}



-Vertex shader (does proper screen/texel alignment)

void PostProcessVS ( in float3 in_vPositionOS : POSITION,
in float3 in_vTexCoord : TEXCOORD0,
out float4 out_vPositionCS : POSITION,
out float2 out_vTexCoord : TEXCOORD0,
out float3 out_vFrustumPlaneVS : TEXCOORD1 )
{
out_vPositionCS.x = in_vPositionOS.x - (1.0f / g_vDestinationDimensions.x);
out_vPositionCS.y = in_vPositionOS.y + (1.0f / g_vDestinationDimensions.y);
out_vPositionCS.z = in_vPositionOS.z;
out_vPositionCS.w = 1.0f;
out_vTexCoord = in_vTexCoord.xy;
out_vFrustumPlaneVS = g_vFrustumCornersVS[in_vTexCoord.z];
}


Share this post


Link to post
Share on other sites
I can't imagine how it's a half-texel issue. While that is something I didn't take into account, that should just blur things a little. What I'm seeing is a distinct skewing of the texture, more so on one axis than the other.

Anyway, I was on a deadline and when I couldn't figure this out quickly I rearranged some code so that I could just use SpriteBatch and be done with it. But thanks for the help anyway.

Share this post


Link to post
Share on other sites
Actually, the half-pixel part was the topic being sidetracked (because we spotted another issue in your code). The general understanding was simply that the texture coords were incorrect, though I guess you're the only one who can say if that was indeed the issue [smile].

Share this post


Link to post
Share on other sites
While I know you've completed your project, I also wanted to point out that there is an Effect file containing the vertex and pixel shaders required to render sprites now available on the Creators Club website Here.

You'd still need to set up the data side of the equation and any render states you want to set, but that's a decent head-start for anyone else wanting a home-brew sprite implementation.

Cheers!

Share this post


Link to post
Share on other sites

This topic is 3295 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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