2D Projection Matrix

Started by
3 comments, last by FortisVenaliter 15 years, 8 months ago
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?
Regards,FortisVenaliterLead Developer - Unsignedhttp://www.unsigned-game.com
Advertisement
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.
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 arrayLPDIRECT3DVERTEXBUFFER9		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 spriteD3DXMatrixScaling(&scale, scalex, scaley, 1.0f);combined *= scale;// Rotate sprite by an arbitrary pointD3DXMatrixTranslation(&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 spriteD3DXMatrixTranslation(&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();    }}
Regards,FortisVenaliterLead Developer - Unsignedhttp://www.unsigned-game.com
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.
Little bit of voodoo math on top of that and it worked!

Thanks,
Louis
Regards,FortisVenaliterLead Developer - Unsignedhttp://www.unsigned-game.com

This topic is closed to new replies.

Advertisement