locked
Rendering a screen aligned quad - how?

    Question

  • This is probably going to seem like a very noob question, but I've been struggling with this for a little while now and haven't found anything through search that directly helps me. I'm trying to render a screen aligned textured quad. The size of the quad is 352x240, the size of the window is the same, and the size of the texture is the same (the texture is a video frame). My problem is I don't know how I should set the vertex positions and the perspective projection matrix and view matrix to achieve the alignment. I basically want to render the texture to the screen, so that each texel maps to the corresponding pixel.

    Can anyone help? It'd be much appreciated! Thanks.
    Friday, October 13, 2006 12:46 PM

Answers

  • http://developer.nvidia.com/object/Mapping_texels_Pixels.html
    and:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Texture_Coordinates.asp

    Generally, you'd want to use an orthographic projection that covers the whole viewport, and an identity view matrix. Then you can specify your vertex positions in screen space, plus the added 1:1 mapping offset...


    Oh, and make sure that your texture is indeed of the size you expect (not sized up to the next powers-of-two during creation).
    Friday, October 13, 2006 3:32 PM
  • Remember that D3D's coordinate system's center is at the center of the screen, not the top left, and the +Y-axis goes up not down as in screen coordinates. Thus, you'll have to subtract Viewport.Width/2 and Viewport.Height/2 from your vertices' positions and for Y do: Y=Viewport.Height-Y
    Sunday, October 15, 2006 12:11 AM

All replies

  • http://developer.nvidia.com/object/Mapping_texels_Pixels.html
    and:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Texture_Coordinates.asp

    Generally, you'd want to use an orthographic projection that covers the whole viewport, and an identity view matrix. Then you can specify your vertex positions in screen space, plus the added 1:1 mapping offset...


    Oh, and make sure that your texture is indeed of the size you expect (not sized up to the next powers-of-two during creation).
    Friday, October 13, 2006 3:32 PM
  • Thanks for the links - I'd read the second already, but was still a bit confused on the nuts and bolts. Here's the code I'm using:


    The quad vertices:

    vertices[0].position = CUSTOMVERTEX::Position(-0.5f,  -0.5f, 0.0f); // top left
    vertices[1].position = CUSTOMVERTEX::Position(-0.5f, 239.5f, 0.0f); // bottom left
    vertices[2].position = CUSTOMVERTEX::Position(351.5f,  -0.5f, 0.0f); // top right
    vertices[3].position = CUSTOMVERTEX::Position(351.5f, 239.5f, 0.0f); // bottom right


    Ortho projection:

    D3DXMATRIX matProj;
    D3DXMatrixOrthoLH(&matProj,352,240,0,1);
    FAIL_RET( d3ddev->SetTransform( D3DTS_PROJECTION, &matProj ) );


    View projection:

    D3DXMATRIX matView;
    D3DXMatrixIdentity(&matView);
    FAIL_RET( d3ddev->SetTransform( D3DTS_VIEW, &matView ) );


    I get a slightly different result than before, but still not right - basically the top right quarter of the screen is rendering the video (as a texture on the quad), but flipped upside down. The orientation doesn't matter to me so much, but I do need it to fill the backbuffer fully.

    I'm probably doing something stupid, but any help would be appreciated again!
    Friday, October 13, 2006 3:46 PM
  • Please post an image of the results...
    Friday, October 13, 2006 7:19 PM
  • Sure, here you go, hope this works:<img src="http://img253.imageshack.us/img253/1561/vmr1pu0.jpg">Thanks for any help, again.

    Oops, that didn't seem to work, but try this link:

    http://img253.imageshack.us/img253/1561/vmr1pu0.jpg
    Friday, October 13, 2006 8:58 PM
  • There are two other ways of going about what you're trying to do.

    1. The ID3DXSprite interface, which is fairly simple to figure out. Check MSDN for more information.

    2. A vertex shader. This is slightly more advanced, but it's a good thing to know how to use, especially since Direct3D 10 will deprecate the fixed function pipeline. Your shader might look something like this:

    struct VS_IN
    {
        float3 position : POSITION0;
        float4 color : COLOR0;
    };

    struct VS_OUT
    {
        float3 position : POSITION0;
        float4 color : COLOR0; 
    };

    void vs(in VS_IN IN, out VS_OUT OUT)
    {
        OUT.position = IN.position;
        OUT.color = IN.color;
    }

    Basically, this shader just outputs the positions and colors as they are, without running them through any perspective or view transformation first.

    I would highly suggest using shaders for this purpose as they're much more flexible than the FFP.
    Saturday, October 14, 2006 8:48 AM
  • Thanks for the tip - you mean to forget about the function calls for the transformations entirely and basically do those transformations in the vertex shader? I guess that'd be one way to do it, but unless my transformation calls are incorrect in some way, it should work this way aswell. Which leads me to wonder if it's my vertex attributes or something else..

    I'd be happy enough to use the function calls if they can work, which I think they should!
    Saturday, October 14, 2006 7:43 PM
  • Remember that D3D's coordinate system's center is at the center of the screen, not the top left, and the +Y-axis goes up not down as in screen coordinates. Thus, you'll have to subtract Viewport.Width/2 and Viewport.Height/2 from your vertices' positions and for Y do: Y=Viewport.Height-Y
    Sunday, October 15, 2006 12:11 AM
  • Thank you! That did the trick. The only niggle now is that there's a thin white line at the top of the video, but I guess that this is just the border between the video and the toolbar rather than a misalignment of the texture.

    For reference, the coordinates should be:

    m_vertices[0].position = CUSTOMVERTEX::Position(-176.5f,  119.5f, 0.0f); // top left
    m_vertices[1].position = CUSTOMVERTEX::Position(-176.5f, -120.5f, 0.0f); // bottom left
    m_vertices[2].position = CUSTOMVERTEX::Position(176.5f,  119.5f, 0.0f); // top right
    m_vertices[3].position = CUSTOMVERTEX::Position(176.5f, -120.5f, 0.0f); // bottom right

    The trick of setting y = viewport.height-y in order to orientate the image the right way up wasn't strictly necessary for me, but I guess I might as well use it since it's easy to do! One note on that is that you need to negate the second and fourth vertices' y co-ordinates, though - the calculation for them will yield a positive y value, but they need to be negative. Asides from that it seems to work perfectly now! Thank you!
    Monday, October 16, 2006 10:19 AM
  •  JohnD74 wrote:
    The only niggle now is that there's a thin white line at the top of the video, but I guess that this is just the border between the video and the toolbar rather than a misalignment of the texture.


    Set your sampler's filtering state to point sampling and see if the line is still there. If it is not, then you're not totally achieving a 1:1 texel-to-pixel mapping. If it is still there even with point sampling, then you're off by one whole texel in your calculations...

    Monday, October 16, 2006 12:26 PM
  • Hey,

       I don't know it may seem an advanced feature or something but it could prove very handy to make an automatic system of stretching the texture when you want to switch between resolutions or resize the Window, thus making the problem you are facing go away, I mean to make the texture cords a variable depending on the resolution of the window. Just set up a matrix a couple of equations and make the math! It's just linear algebra! I'll leave it to you to make it as an excersice! If you face any problems drop a post and I'll give away some tips!!

     

    Kindly,

    ~a.ka. Andr3w

    Tuesday, October 17, 2006 12:27 AM
  • Interesting..I have the following sampler settings at the moment:

    FAIL_RET(hr = d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT));
    FAIL_RET(hr = d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT));
    FAIL_RET(hr = d3ddev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE));

    To show you what exactly I'm getting at, this is the result (with the above settings, still):

    http://img222.imageshack.us/img222/4220/apppicdw4.jpg

    You can see the thin white line between the video and the toolbar..I'm not actually sure how many pixels in height it is. Do you think my calculations are off, or is this just a normal gap that'll exist in a window? Thanks again for your help!

    edit - Checking things..I think setting my window size to be the same as the texture I'm rendering was a bad idea. The video size isn't what it should be, it is too short in height versus the original. Does anyone know how much height I should be adding to the window's height on top of the video height I want?

    Tuesday, October 17, 2006 10:06 AM
  • The Win32 API has the AdjustWindowRect() function to help do this calculation. I'm not sure if .NET has such an equivalent. But somehow you should have the _client_ area set to the size of your video, not the whole window.
    And regarding that white strip, you can find out if it's caused by your drawing by offsetting the verts on Y up a little bit, and see if it goes away...

    Tuesday, October 17, 2006 10:27 AM