Sign in to follow this  

2D Projection Matrix

Recommended Posts

What would be a standard projection transform matrix for 2D? Right now I am using the DirectX D3DXMatrixOrthoLH and the results are... not favorable. I am trying to convert my code from D3DXSPRITE to shader code. The code looks fine when run with the Sprite, but with the new code it seems to be offset and flipped. At first I thought it was a 0.5 offset, but when I manually tried to fix it, that isn't right. What would be the best view/proj matrix configuration to use?

Share this post

Link to post
Share on other sites
Evil Steve    2017
Original post by FortisVenaliter
What would be the best view/proj matrix configuration to use?
D3DXMatrixOrthoLH() for projection and an identity matrix for view (Or maybe a XY translation to move around).

If that's not working, you'll have to show us your code, it sounds like you're setting the matrix up wrongly.

Share this post

Link to post
Share on other sites
Okay, here's my C++ code:
I have abridged some parts in attempts to simplify it (I don't really create a VB every frame).


struct Vertex

//int id: the texture ID for info from the texture array


CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->CreateVertexBuffer( 4*sizeof(Vertex), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &lpVertexBuffer, NULL );

Vertex quadVertices[] =
{ D3DXVECTOR3(0.0f, 1.0f, 0.0f), D3DXVECTOR2(0.0f,1.0f)},//, 1.0f,1.0f,1.0f,1.0f },
{ D3DXVECTOR3(1.0f, 1.0f, 0.0f), D3DXVECTOR2(1.0f,1.0f)},//, 1.0f,1.0f,1.0f,1.0f },
{ D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR2(0.0f,0.0f)},//, 1.0f,1.0f,1.0f,1.0f },
{ D3DXVECTOR3(1.0f, 0.0f, 0.0f), D3DXVECTOR2(1.0f,0.0f)},//, 1.0f,1.0f,1.0f,1.0f }

quadVertices[1].pos.x = GetTextureWidth(id);
quadVertices[3].pos.x = GetTextureWidth(id);
quadVertices[0].pos.y = GetTextureHeight(id);
quadVertices[1].pos.y = GetTextureHeight(id);

void *pVertices = NULL;

lpVertexBuffer->Lock( 0, sizeof(quadVertices), (void**)&pVertices, 0 );
memcpy( pVertices, quadVertices, sizeof(quadVertices) );

D3DXMATRIX rotation;
D3DXMATRIX translate;
D3DXMATRIX combined;


// Scale the sprite
D3DXMatrixScaling(&scale, scalex, scaley, 1.0f);
combined *= scale;

// Rotate sprite by an arbitrary point
D3DXMatrixTranslation(&translate, -rotx*scalex, -roty*scaley, 0.0f);
combined *= translate;
D3DXMatrixRotationZ(&rotation, rot);
combined *= rotation;
D3DXMatrixTranslation(&translate, rotx*scalex, roty*scaley, 0.0f);
combined *= translate;

// Translate the sprite
D3DXMatrixTranslation(&translate, (float)x, (float)y, 0.0f);
combined *= translate;


combined *= proj;

D3DXMATRIX identity;

int error = 0;
// Apply the transform.
if(FAILED((CSGD_Direct3D::GetInstance()->GetEffect()->SetMatrix( "wvp", &combined ))))
error = 1;
if(FAILED(CSGD_Direct3D::GetInstance()->GetEffect()->SetTexture( "tex", m_Textures[id].texture )))
error = 2;


// Draw the sprite.
if(FAILED(CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetStreamSource( 0, lpVertexBuffer, 0, sizeof(Vertex) )))
error = 3;
if(FAILED(CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetFVF( D3DFVF_CUSTOMVERTEX )))
error = 4;
if(FAILED(CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 )))
error = 5;

And the shader code:

float4x4 wvp;

texture tex : Diffuse;
sampler TextureSampler = sampler_state
Texture = (tex);
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
AddressU = mirror;
AddressV = mirror;

struct VertexIn
float3 pos : POSITION;
float2 texCoord : TEXCOORD0;
struct VertexOut
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
float4 color : COLOR0;
struct PixelIn
float2 texCoord : TEXCOORD0;
float4 color : COLOR0;

VertexOut VertexShaderFunction(VertexIn inval)
VertexOut outval = (VertexOut)0;
outval.pos = mul(float4((inval.pos).xyz,1),wvp);
outval.texCoord = inval.texCoord;
outval.color = float4(1.0f,1.0f,1.0f,1.0f);
return outval;

float4 PixelShaderFunction(PixelIn inval) : COLOR0
return tex2D(TextureSampler, inval.texCoord);

technique Lighter
pass pass0
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();

Share this post

Link to post
Share on other sites
MJP    19786
When you use an orthographics or perspective projection, the Y-axis will increase towards the top of the screen and decrease towards the bottom. This is opposite of ID3DXSprite, which uses traditional screen coordinates. This is a very simple fix, you just need to reverse swap the V coordinates in your vertices. It should look like this instead:

Vertex quadVertices[] =
{ D3DXVECTOR3(0.0f, 1.0f, 0.0f), D3DXVECTOR2(0.0f,0.0f)},
{ D3DXVECTOR3(1.0f, 1.0f, 0.0f), D3DXVECTOR2(1.0f,0.0f)},
{ D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR2(0.0f,1.0f)},
{ D3DXVECTOR3(1.0f, 0.0f, 0.0f), D3DXVECTOR2(1.0f,1.0f)},

Notice how with these the upper vertices with a Y-coordinate of 1 have a V coordinate of 0, since 0 is the top of the texture.

As for the offset, I believe ID3DXSprite does indeed add a -0.5 offset to the position you give it. This is so that the sprite exactly aligns with screen coordinates. You can duplicate this effect yourself very easily by adding an extra translation to the world matrix, or you can just offset the vertex positions in the vertex shader.

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