• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
noodleBowl

The Jump to D3D11: Orthographic projection

16 posts in this topic

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

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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
0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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?

Edited by tonemgub
0

Share this post


Link to post
Share on other sites

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.... ;)

Edited by Tom KQT
0

Share this post


Link to post
Share on other sites

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.

1

Share this post


Link to post
Share on other sites

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).

1

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

Edited by NightCreature83
0

Share this post


Link to post
Share on other sites

What would be the motivation to do this in shaders?

1) To reduce the number of constants that need to be sent to the shader (16 floats for the matrix versus only the 6 floats that can be sent to create the matrix).

2) To reduce the number of calculations in the shader - most of the values (10 of them) in the matrix are constant 1s and 0s, and the HLSL compiler will not generate code for calculating (mostly multiplying) vector or other matrices' components with those values, or it will mix them together with other constant values that are part of the same calculations, into a single constant that is only applied to the calculation once... this and other optimisations that the compiler may do, that I cannot possibly imagine. smile.png

 

 


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.... ;)

Hmmm. I didn't think of it this way. Good point. Please ignore my last comment. smile.png

 

(Though, in my defense, I was thinking of building the projection matrix in a Geometry shader, so only once per primitive...).

Edited by tonemgub
1

Share this post


Link to post
Share on other sites

 


What would be the motivation to do this in shaders?

1) To reduce the number of constants that need to be sent to the shader (16 floats for the matrix versus only the 6 floats that can be sent to create the matrix).

2) To reduce the number of calculations in the shader - most of the values (10 of them) in the matrix are constant 1s and 0s, and the HLSL compiler will not generate code for calculating (mostly multiplying) vector or other matrices' components with those values, or it will mix them together with other constant values that are part of the same calculations, into a single constant that is only applied to the calculation once... this and other optimisations that the compiler may do, that I cannot possibly imagine. smile.png

 

 


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.... ;)

Hmmm. I didn't think of it this way. Good point. Please ignore my last comment. smile.png

 

(Though, in my defense, I was thinking of building the projection matrix in a Geometry shader, so only once per primitive...).

 

You dont need to rebuild a projection matrix at all, just create one and pass it along to the shader you need to set this the per frame cb once a frame that is all. If you start recreating your projection matrix you are just wasting CPU time each frame.

 

Generally you build all projection matrices you need in the code once at application initialise or level initialise and then set it when needed, you can have to update the projection matrix multiple times per frame like for example when you have a cubemap renderer or other post effects in your render pipeline. Generally you use a different projection for this then for the normal game camera.

1

Share this post


Link to post
Share on other sites


You dont need to rebuild a projection matrix at all, just create one and pass it along to the shader you need to set this the per frame cb once a frame that is all. If you start recreating your projection matrix you are just wasting CPU time each frame.

 

Generally you build all projection matrices you need in the code once at application initialise or level initialise and then set it when needed, you can have to update the projection matrix multiple times per frame like for example when you have a cubemap renderer or other post effects in your render pipeline. Generally you use a different projection for this then for the normal game camera.

 

Yep, you don't. Unless you use it to simulate zoom for example.

I wrote originaly my post about the view matrix (I forgot the thread was about projection) and when I noticed the mistake, I only edited "view" to "projection" everywhere in my post, without thinking about it more in depth smile.png But my point still applies and the fact that it's about projection and not view only makes it stronger - because you don't need to rebuild this matrix at all (usually) smile.png

 

Edited by Tom KQT
0

Share this post


Link to post
Share on other sites

Feel free to correct me, but I think this what I need to do

 

I need to build my projection matrix once, so for this I can use the XNA Matrix Lib or D3D Matrix Lib using the OrthographicOffCenterLH functions. Then I need to, I'm assuming, store this information in Constant Buffer (cbuffer). Which will then some how go into my Vertex Shader. Right?

0

Share this post


Link to post
Share on other sites

@Tom KQT, I'd like to mention that I was actually correct:

1) To reduce the number of constants that need to be sent to the shader (16 floats for the matrix versus only the 6 floats that can be sent to create the matrix).
2) To reduce the number of calculations in the shader - most of the values (10 of them) in the matrix are constant 1s and 0s, and the HLSL compiler will not generate code for calculating (mostly multiplying) vector or other matrices' components with those values, or it will mix them together with other constant values that are part of the same calculations, into a single constant that is only applied to the calculation once... this and other optimisations that the compiler may do, that I cannot possibly imagine. smile.png

 

Explanation:

The shader will contain fewer instructions if you just pass the 6 float parameters into the shader and "build" the matrix there... Take a simple mul(matrix, vector) calculation for example... In the case of an orthographic matrix, only 7 values from the matrix will be != 0, and one of them is always 1, so there are actually only 6 variables. In this case, the compiler will optimize the mul(matrix, vector) intrinsic function down to just 9 operations: 6 multiplies, 3 additions. The value from the matrix that is 1 has the effect that the vertex's w value is preserved, so no operation is required for this. To this, you have to add the number of instructions that the compiler will generate for building the 6 variable matrix values from the 6 passed-in values: D3DXMatrixOrthoOffCenterLH does this with 2 additions, 6 subtractions and 6 divisions. Add all these up, and you get a total of 23 operations, though I'm pretty sure there's still room for the HLSL compiler to optimize the D3DXMatrixOrthoOffCenterLH formula.

 

Now, if you pass the ortho matrix as a whole matrix of 4*4=16 floats to the shader, then the mul(matrix, vector) calculation has to treat all of those 16 values as variables, and so the compiler translates it to: 16 multiplies and 12 additions - a total of 28 operations, which is more than the 23 operations requried for the method I proposed. smile.png

 

Keep in mind that you need to do a mul(matrix, vector) at least once per vertex in your vertex shader.

 

 


I need to build my projection matrix once, so for this I can use the XNA Matrix Lib or D3D Matrix Lib using the OrthographicOffCenterLH functions. Then I need to, I'm assuming, store this information in Constant Buffer (cbuffer). Which will then some how go into my Vertex Shader. Right?

 

Yes, this is what you need to do, but instead of D3DXMatrixOrthoOffCenterLH, you can also use this HLSL function directly in your vertex shader, and instead of passing the whole matrix to the shader, you can just pass the values for the function's parameters:

float4x4 ortho_mat(float l, float r, float b, float t, float zn, float zf) {return float4x4(2.0 / (r - l), 0.0, 0.0, 0.0, 0.0, 2.0 / (t - b), 0.0, 0.0, 0.0, 0.0, 1.0 / (zf - zn), 0.0, (l + r) / (l - r), (t + b) / (b - t), zn / (zn - zf), 1.0);}

Edited by tonemgub
0

Share this post


Link to post
Share on other sites

 

The shader will contain fewer instructions if you just pass the 6 float parameters into the shader and "build" the matrix there...

The shader will generate even fewer instructions if you don’t send any matrices at all nor do any matrix math.
 
The whole purpose of the projection matrix is to normalize vertices between -1 and 1 on both axes.
If you simply construct a vertex buffer with vertices already normalized in this way you don’t need to send any matrices at all nor perform any math on them inside the vertex shader.
 
This works exceptionally well for static 2D objects such as the HUD, and it is independent of resolution (meaning your HUD items consume the same amount of screen space as you increase or decrease the screen resolution).  You can regenerate the vertex buffer if you want objects not to physically scale up or down with various resolutions upon resizing, which is reasonable performance-wise (updating a few vertex buffers once only when resizing).
 
For sprites that move, rotate, and scale, you need only send normalized screen offset positions, a rotation in radians, and a single scale value.  This lets you fit the entire transform of the sprite into a single float4 value, decreasing demands on bandwidth substantially.  XY = Normalized Translation, Z = Rotation, W = Scale.
 
 
Vertex shader:
 
float2 fXY = IN.xy * IN_POS_ROT_SCALE.w;
float fCos = cos( IN_POS_ROT_SCALE.z );
float fSin = sin( IN_POS_ROT_SCALE.z );
OUT.x = fXY.x * fCos - fXY.y * fSin;
OUT.y = fXY.y * fCos + fXY.x * fSin;
OUT.xy += IN_POS_ROT_SCALE.xy;
OUT.zw = IN.zw;
The sin/cos calls could be done on the CPU and sent instead of scale (if scale is 1.0) or as a second float4, but since it will only be applied to 4 vertices it will likely be much faster done on the GPU.

The above shows the worst-case scenario but you can make different shaders or shader branches when rotation is 0 or scale is 1 and avoid the sin/cos, an extra multiply, or both.
 
 
 
Not only is this the fastest way to handle 2D (for any platform), it has the advantage that vertex coordinates of X = -1 is always the left of the screen and X = 1 is always the far right, so keeping things proportional to various resolutions is only a matter of a simple normalization multiplier.  If stretching is not desired (and why would it be?) then it only needs to account for the aspect ratio, but it still boils down to a simple X/Y normalization multiplier that can be precomputed once when the resolution changes.


And again, for static HUD images, the vertex shader is this:
OUT = IN;
 
 
L. Spiro

 

 

If my end goal is to create a sprite batcher, since I'm only focusing on 2D, is this the best approach? I would have to update my vertex/index buffer every frame. I am worried that this will take a up lot of CPU time. Where, I believe, sending all the data to the Vertex Shader will do all the calculations on the GPU.

 

I'm not 100% sure how variables get passed into the Vertex Shader as well. I think this is done through the Input Layout right? So for this I would have to set up a Input Layout that looks

D3D11_INPUT_ELEMENT_DESC inputDesc[] =
{

//Pos 0: XY
//Pos 1: Z
//Pos 2: W
{"POSITION0", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"POSITION1", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"POSITION2", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}

};
Edited by noodleBowl
0

Share this post


Link to post
Share on other sites

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  
Followers 0