The Jump to D3D11: Orthographic projection

Started by
15 comments, last by noodleBowl 10 years, 4 months ago

I'm trying to make the switch to DirectX11 and I'm having some trouble with some things. One thing that I need to be solved is how I can set up an orthographic projection?

My focus is on 2D and I feel like this is pretty important

I know from Direct X 9 you could do this and you have an Orthographic Projection


D3DXMATRIX out;
D3DXMatrixOrthoOffCenterLH(&out, 0.0f, 800.0f, 600.0f, 0.0f, 0.0f, 1.0f);
device->SetTransform(D3DTS_PROJECTION, &out);

But how is this done in DirectX11? I'm having trouble finding resources that can explain this properly

Advertisement

Can you be clearer on what part of this you're having trouble with? The old SetTransform calls and D3DTS_* states are gone in D3D11, but otherwise things work much the same (with the exception of cbuffers versus standalone constants) as they did with shaders in D3D9. Have you experience using shaders in D3D9? Are you looking for a matrix library to build the ortho matrix? It's difficult to provide a meaningful answer without an understanding of what concepts you do or do not already know about here.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

quote

Honestly, when it comes to DirectX 11 there is not a lot I know in terms of the API.
I have never used shaders in DirectX 9, so with them being mandatory in DirectX 11 I'm not sure what to expect.

When it comes to setting up projections and other matrices I'm not even sure where to start. I definitely need a solid explanation or tutorial for setting up projections and matrix manipulation in DirectX 11

Hi. Theres one in xna math file

There are a few functions that are part of the XNA Math library that are used to build projection matrices, . XMMatrixOrthographicOffCenterLH

there is I think a directmath header and lib for DX11.

I would just write a shader function that does the same thing as D3DXMatrixOrthoOffCenterLH. It would take the parameters directly from a constant buffer. The formula is at the bottom of the page: http://msdn.microsoft.com/en-us/library/windows/desktop/bb205347(v=vs.85).aspx. This way you don't have to bother with matrix row/column ordering.

And for 2D, maybe an identity matrix would suffice?

I would just write a shader function that does the same thing as D3DXMatrixOrthoOffCenterLH. It would take the parameters directly from a constant buffer. The formula is at the bottom of the page: http://msdn.microsoft.com/en-us/library/windows/desktop/bb205347(v=vs.85).aspx. This way you don't have to bother with matrix row/column ordering.

And for 2D, maybe an identity matrix would suffice?

What would be the motivation to do this in shaders? Projection matrix is usually the same for all objects in the scene (sometimes you need two, maybe three, but still the number is smaller than the number of objects). Even if your camera moves a lot, you need to build the proj matrix once per frame. If you move the code to a vertex shader, you will be building the matrix once per VERTEX. Once per very single vertex in your scene. Or you can also put it to a pixel shader.... ;)

You can always download the June 2012 DirectX SDK, and continue using the older deprecated D3DX matrix functions.

I haven't played with it myself, but DirectXMath looks like it is a replacement for the D3DX matrix functions, if you want to stick with something that is actively supported.

Eric Richards

SlimDX tutorials - http://www.richardssoftware.net/

Twitter - @EricRichards22

Yes, the old D3DX matrix functions work perfectly fine with D3D11 - they're just a matrix library so there's really no dependencies on which D3D version you use them with (I've even successfully used them with OpenGL in the past).

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Just to add, you do not necessarily need an orthographic projection for 2d in DX11. You can do the transform yourself pretty easily on the CPU:


size_t Sprite::Draw(const Texture& d3dTexture, const math::Vector3& vPosition, const math::Vector3& /*vOrigin*/, const RECT& rSrcRect, const math::Vector2f& vScale, float /*fAngle*/)
{
    RECT rSrc(rSrcRect);

    const math::Vector2& vTextureSize(d3dTexture.GetSize());

    const math::Vector2 vSrcSize(rSrcRect.right - rSrcRect.left, rSrcRect.bottom - rSrcRect.top);
    const math::Vector2 vSize((int)(vSrcSize.x*vScale.x), (int)(vSrcSize.y*vScale.y));

    // calculate the sprites vertices in screen space
    // to speed up calculations, we multiply by 1.0 / screen size, which is calculated offline
    float leftVertex = vPosition.x  * m_vInvHalfScreenSize.x - 1.0f;
    float rightVertex = leftVertex + vSize.x * m_vInvHalfScreenSize.x;
    float topVertex = -vPosition.y * m_vInvHalfScreenSize.y + 1.0f;
    float bottomVertex = topVertex - vSize.y * m_vInvHalfScreenSize.y;

    const float leftCoord = rSrc.left / (float)vTextureSize.x;
    const float rightCoord = rSrc.right / (float)vTextureSize.x;
    const float topCoord = rSrc.top / (float)vTextureSize.y;
    const float bottomCoord = rSrc.bottom / (float)vTextureSize.y;

    SpriteVertex Vertices[] =
    {
        { leftVertex, topVertex, vPosition.z, leftCoord, topCoord, 1.0f, 1.0f, 1.0f, 1.0f },
        { rightVertex, topVertex, vPosition.z, rightCoord, topCoord, 1.0f, 1.0f, 1.0f, 1.0f },
        { rightVertex, bottomVertex, vPosition.z, rightCoord, bottomCoord, 1.0f, 1.0f, 1.0f, 1.0f },
        { leftVertex, bottomVertex, vPosition.z, leftCoord, bottomCoord, 1.0f, 1.0f, 1.0f, 1.0f }
    };

    SpriteVertex* pBuffer = static_cast<SpriteVertex*>(m_mapped.pData);
    memcpy(pBuffer + m_nextFreeId * 4, Vertices, sizeof(SpriteVertex)* 4);

    return m_nextFreeId++;
}

This way, the vertices are already transformed, and you can simply pass them through in your vertex shader. This example works when you draw sprites with pixel coordinates, if you have them already in relative screen space (from 0.0f to 1.0f) the conversion is even simplier. Of course it depends whether this makes sense, but depending on your programs structure, it can make things easier if you don't have to have a orthogonal matric available for every shader that eigther draws a sprite or performs a fullscreen pass.

You have to look into cbuffers to be able to set the matrices on the pipeline however unlike in D3D9 there is no longer a Fixed Function pipeline which does transformations for VBs for you.

You will have to write a vertex shader to accomplish this in D3D11 and they arent that hard to write, there are enough sample out there to give you a basic tranform vertex shader and pixel shader.

The rastertek tutorials are a good way to get into D3D11 shaders and how the whole pipeline works: http://www.rastertek.com/tutindex.html If you want to work of familiar D3D9.c concepts use the http://www.codesampler.com/dx9src.htm D3D9 tutorials as they ease you into shader programming as well, since you know D3D9 skip to the part where they start using shaders.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

This topic is closed to new replies.

Advertisement