direct3d

Vertex coordinates in pixel cordinates


By default

Direct3D assumes that the viewport clipping volume ranges from -1.0 to 1.0 in X, and from 1.0 to -1.0 in Y.

https://learn.microsoft.com/en-gb/windows/win32/direct3d9/viewports-and-clipping

I'm just wanting to do 2D rendering, and I'd like to provide vertex buffer data such that the top left of a pixel is a an integral coordinate i.e. the centres of pixels are at (*.5, *.5)

That is for a viewport size of 1280x720 I'd like the X to range from 0 to 1280 and Y to range from 0 to 720.

Currently the hello triangle sample gives the coordinates as

Vertex triangleVertices[] =
{
    { { 0.0f, 0.25f, 0.0f }, color1 },
    { { 0.25f, -0.25f, 0.0f }, color2 },
    { { -0.25f, -0.25f, 0.0f }, color3 }
};

What changes are necessary get the same result while providing the following coordinates

Vertex triangleVertices[] =
{
    { { width/2 + 0.00f * width/2, height/2 + 0.25f * height/2, 0.0f }, color1 },
    { { width/2 + 0.25f * width/2, height/2 - 0.25f * height/2, 0.0f }, color2 },
    { { width/2 - 0.25f * width/2, height/2 - 0.25f * height/2, 0.0f }, color3 }
};

Here's how they did it in Direct3D 9 https://learn.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline but it seems like things have changed.


Solution

  • For 2D rendering, you just need to use an orthographic projection that is based on the screen pixel dimensions.

    Matrix proj = Matrix::CreateScale( 2.f/float(backBufferWidth),
       -2.f/float(backBufferHeight), 1.f)
       * Matrix::CreateTranslation( -1.f, 1.f, 0.f );
    

    or

    Matrix proj = Matrix::CreateOrthographicOffCenter(
        0.f, float(backBufferWidth), float(backBufferHeight), 0.f, 0.f, 1.f);
    

    or using DirectXMath instead of the SimpleMath wrapper:

    XMMATRIX proj = XMMatrixOrthographicOffCenterRH(
        0.f, float(backBufferWidth), float(backBufferHeight), 0.f, 0.f, 1.f));
    
    // Use XMMatrixOrthographicOffCenterLH for a left-handed projection instead of right-handed.
    // Which of course largely doesn't matter for 2D rendering without
    // a z-buffer.
    

    Then you use that projection in a standard vertex shader with a transformation matrix:

    cbuffer ConstantBuffer : register( b0 )
    {
        matrix Projection;
    }
    
    float4 main( float4 Pos : POSITION ) : SV_POSITION
    {
        float4 Pos = mul( Pos, Projection );
        return Pos;
    }
    

    See DirectX Tool Kit SpriteBatch on GitHub