Using sprites for a GUI

Started by
6 comments, last by gabe83 15 years, 4 months ago
I figure sprites would be an easy option for an overlay or GUI. Is there a way to position these into relative screen co-ordinates, so they are in fixed screen position, so they stay in the same place when the camera moves? Something like as follows? SpritePos(0.1,0.1) // Position sprite at 10% from top & left of screen I'd be interested if this could be done with models as well.
Advertisement
If you use XYZRHW for your vertex declaration, it lets DirectX know that your coordinates are already transformed into screen space and it won't change them. I.E. (0,0) will correspond to the top left pixel and (640,480) the bottom right one (For that resolution monitor in fullscreen) to use your percentage based method it's pretty obvious to just multiply the percentage desired by your windows size.
Of course you can.
A sprite is basically a [0, 0]->[1, 1] quad, so everything you have to do is set the corresponding world-view-projection matrix in order to scale, translate (and if needed rotate) its x,y coordinates to the position and size you want it to occupy in clip space.

If you are using ID3DXSprite helper class, you just have to set its WVP matrix with
HRESULT SetTransform(  CONST D3DXMATRIX * pTransform);

that will be something like this
sx 0  0  00  sy 0  00  0  1  0tx ty 0  1([sx, sy] = size in clip space [tx, ty] = position in clip space, in your case [0.1f, 0.1f])

then, during the rendering, inside the BeginScene EndScene couple you first
HRESULT ID3DXSprite::Begin(  DWORD Flags);

with Flags = 0
then declare the texture bound to the sprite with
HRESULT ID3DXSprite::Draw(  LPDIRECT3DTEXTURE9 pTexture,  CONST RECT * pSrcRect,  CONST D3DXVECTOR3 * pCenter,  CONST D3DXVECTOR3 * pPosition,  D3DCOLOR Color);

if you have just one texture per sprite, and don't need to change its color, you can use
pCenter = NULLpPosition = NULLColor = 0xFFFFFFFF

finally you call
HRESULT ID3DXSprite::End();
Quote:Original post by gabe83
sx 0 0 0
0 sy 0 0
0 0 1 0
tx ty 0 1
([sx, sy] = size in clip space
[tx, ty] = position in clip space, in your case [0.1f, 0.1f])

I am unsure of how to implement this. The following code is what I have in my main loop.
// Position and display sprite for GUImSprite->Begin(D3DXSPRITE_OBJECTSPACE|D3DXSPRITE_DONOTMODIFY_RENDERSTATE);D3DXMATRIX mSpritePos;D3DXMatrixTranslation(&mSpritePos,0.1f,0.1f,0);mSprite->SetTransform(&mSpritePos);RECT pRect={0,0,128,128};mSprite->Draw(mSpriteTex,&pRect,&mSpriteCenter,0,D3DCOLOR_XRGB(255,255,255));mSprite->Flush();mSprite->End();

At the moment I am able to display my sprite but it is still in 3D space, not screen space. Could you please give an example of how to implement the matrix you have shown?

Thanks again.
Quote:Original post by gabe83
sx 0 0 0
0 sy 0 0
0 0 1 0
tx ty 0 1
([sx, sy] = size in clip space
[tx, ty] = position in clip space, in your case [0.1f, 0.1f])

I am struggling with this. I understand where sx & sy work but where does tx & ty come from?

Can anyone enlighten me?

You are specifying D3DXSPRITE_OBJECTSPACE in the call to ID3DXSprite::Begin
this means that SetTransform will be ignored, since (taken from the DX Documentation)
Quote:
D3DXSPRITE_OBJECTSPACE :
The world, view, and projection transforms are not modified. The transforms currently set to the device are used to transform the sprites when the batched sprites are drawn (when ID3DXSprite::Flush or ID3DXSprite::End is called). If this flag is not specified, then world, view, and projection transforms are modified so that sprites are drawn in screen-space coordinates.


As for the question about tx, ty they are the x and y coordinates in clip space where you want the top left corner of the quad to be placed.
Those four lines i posted represent a transformation matrix that will be multiplied to the positions in world space of the four vertices of the quad in order to calculate their position in clip space. This means that the four vertexes of the quad whose coordinates are

[0, 0, z, 1],[0, 1, z, 1],[1, 1, z, 1],[1, 0, z, 1](z coordinate is uninfluent)


after this transformation will be at

[tx, ty, 0, 1],[tx, ty + sy, z, 1],[tx + sx, ty + sy, z, 1],[tx + sx, ty, z, 1]


You can get that matrix this way

D3DXMATRIX mSpritePos;D3DXMatrixScale(&mSpritePos, 0.2f, 0.2f, 1.0f);D3DXMATRIX translation;D3DXMatrixTranslation(&translation,0.1f,0.1f,0);D3DXMatrixMultiply(&mSpritePos, &mSpritePos, &translation);mSprite->SetTransform(&mSpritePos);([0.2f, 0.2f]=[sx, sx] that is the size of the sprite in clip space [0.1f, 0.1f]=[tx, ty] the position of the sprite in clip space)

Thanks for that gabe83.

Running through your example I cant see where 'D3DXMatrixScale()' is defined. There seems to be no mention on MSDN either.

The other odd thing is that in you MSDN note where SetTransform is ignored between Sprite begin & end, I seem to be able to move the sprite anywhere around 3D space in all directions x,y,&z using the snippet I supplied. Odd one...
Sorry, typing error, the function is
D3DXMatrixScaling

This topic is closed to new replies.

Advertisement