Sign in to follow this  
FortisVenaliter

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


#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)

struct Vertex
{
D3DXVECTOR3 pos;
D3DXVECTOR2 tex;
};

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

LPDIRECT3DVERTEXBUFFER9 lpVertexBuffer=NULL;

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) );
lpVertexBuffer->Unlock();

D3DXMATRIX scale;
D3DXMATRIX rotation;
D3DXMATRIX translate;
D3DXMATRIX combined;

D3DXMatrixIdentity(&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;

D3DXMATRIX proj;
D3DXMatrixOrthoLH(&proj,800.0f,600.0f,1.0f,0.0f);

combined *= proj;

D3DXMATRIX identity;
D3DXMatrixIdentity(&identity);
CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetTransform(D3DTS_PROJECTION,&identity);
CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetTransform(D3DTS_VIEW,&identity);
CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetTransform(D3DTS_WORLD,&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;

CSGD_Direct3D::GetInstance()->GetEffect()->CommitChanges();

// 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
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