VertexBuffer Translation

Started by
8 comments, last by GameDev.net 19 years, 7 months ago
Hi, I'm trying to reposition a VertexBuffer based on If I press up down left or right. I have a Vertexbuffer class and a move function. I create two different VB's and try to move one and both of them move. Since I am Transforming the world matrix is that causing everything on the screen to move? If thats why thats happening how do I only move the Object i am trying to move? Any help would be greatly appreciated, thanks.


BOOL c2DRect::Move(float x, float y, float z){

 m_X += x; 
 m_Y += y; 
 m_Z += z;

 D3DXMatrixTranslation(&m_matPosition, m_X, m_Y, m_Z);
 m_pD3DDevice->SetTransform(D3DTS_WORLD, &m_matPosition);

 return TRUE;

}


Advertisement
For each set of vertices you want to move, you'll need to set the world matrix again.

Every time you set the world matrix, it says "move everything to here in the world". So you can see that you need to do this once for each model you want to draw.

ie.

Move(x, y, z)
RenderVertices();
Move(x1, y1, z1);
RenderVertices();
Now it only shows one Rectangle.
Here is my scene

 m_Rect.Move(0.0f, 0.0f, 0.0f); if(m_Keyboard.KeyState(DIK_UP) == TRUE){	m_Rect.Move(0.0f, -10.0f, 0.0f); } if(m_Keyboard.KeyState(DIK_DOWN) == TRUE){	m_Rect.Move(0.0f, 10.0f, 0.0f); } if(m_Keyboard.KeyState(DIK_LEFT) == TRUE){	m_Rect.Move(-10.0f, 0.0f, 0.0f); } if(m_Keyboard.KeyState(DIK_RIGHT) == TRUE){	m_Rect.Move(10.0f, 0.0f, 0.0f); } m_Rect.Render(); m_Rect2.Move(0.0f, 0.0f, 0.0f); m_Rect2.Render();
Does anyone know the reason this is doing this?
This is because your move function doesn't actually move the rect to the specified point - it just adds the position on.

If I were you I'd have two move functions:

MoveRelative(float x, float y, float z) - This would do exactly what your current Move() function does (move the rect relative to its current position).

MoveAbsolute(float x, float y, float z) - This will actually move the rect to the specified coordinates.

Also, make sure your rect constructor initialises its members m_X, m_Y and m_Z to something sensible (like 0.0f).

For a simple test, do something like this:

// Move the rect to the origin and renderm_Rect.MoveAbsolute(0.0f, 0.0f, 0.0f);m_Rect.Render();// Move the second rect up a bit and renderm_Rect2.MoveAbsolute(0.0f, 10.0f, 0.0f);m_Rect2.Render();

Oh, also check which coordinate system you are using. You may be rendering using screen coordinates (where one unit equals one pixel on screen), or you may be using homogenous screen coordinates.

Homogenous screen coordinates are usually something like (-1, -1, 0) for the bottom left of the screen at near clip and (1, 1, 1) for the top right at far clip.

This is actually what all vertices get transformed to before they are converted to the final raster coordinates. This means that if you are using a vertex shader to do your 2d rendering and you are using these homogenous screen coordinates then you don't need to do any transformation of the vertices in the shader - you can just pass them straight through.
Ok now the 2 rects show up so how would I move them, my first problems was they would both move and I only wanted one to move. I tried this and now the one rect move and the other stays where it is but when I release the key it goes back to where it used to be. And by the way Im really new to this and all i know is from the forums and msdn.

if(m_Keyboard.KeyState(DIK_UP) == TRUE){			m_Rect.MoveRelative(0.0f, -10.0f, 0.0f);		}		if(m_Keyboard.KeyState(DIK_DOWN) == TRUE){			m_Rect.MoveRelative(0.0f, 10.0f, 0.0f);		}		if(m_Keyboard.KeyState(DIK_LEFT) == TRUE){			m_Rect.MoveRelative(-10.0f, 0.0f, 0.0f);		}		if(m_Keyboard.KeyState(DIK_RIGHT) == TRUE){			m_Rect.MoveRelative(10.0f, 0.0f, 0.0f);		}		//m_Rect.MoveAbsolute(0.0f, 0.0f, 0.0f);		m_Rect.Render();		m_Rect2.MoveAbsolute(0.0f, 0.0f, 0.0f);		m_Rect2.Render();		m_Graphics.EndScene();


And this is how I display the screen so 0,0 would be at the top left.

D3DXMATRIX mProjectionMatrix, mViewMatrix, mWorldMatrix, mTextureMatrix;	D3DXMatrixOrthoOffCenterLH(&mProjectionMatrix, 0.0f, 800, 600, 0.0f, 0.0f, 1.0f);    D3DXMatrixIdentity(&mViewMatrix);    D3DXMatrixIdentity(&mWorldMatrix);    D3DXMatrixIdentity(&mTextureMatrix);    m_pD3DDevice->SetTransform(D3DTS_PROJECTION,     &mProjectionMatrix);    m_pD3DDevice->SetTransform(D3DTS_VIEW,           &mViewMatrix      );    m_pD3DDevice->SetTransform(D3DTS_WORLDMATRIX(0), &mWorldMatrix     );    m_pD3DDevice->SetTransform(D3DTS_TEXTURE0,       &mTextureMatrix   );


[Edited by - andyb716 on September 1, 2004 6:24:03 PM]
OK. Well we are nearly there then!

First... We are moving the rects absolutely each frame which is causing them to flick back to the original position. Since we don't want this, we should probably only do this once, before we get into the main loop.

So after we create the rects, we move them into their initial positions. Lets say the intial position for m_Rect is (x1, y1, z1) and the initial position fro m_Rect2 is (x2, y2, z2).

So after you have created the rects (in the constructor or wherever, but before you get into the main loop!):

m_Rect.MoveAbsolute(x1, y1, z1);m_Rect2.MoveAbsolute(x2, y2, z2);


Now you want to be able to move them each frame. So now you would do relative movement:

if(m_Keyboard.KeyState(DIK_UP) == TRUE){m_Rect.MoveRelative(0.0f, -10.0f, 0.0f);}if(m_Keyboard.KeyState(DIK_DOWN) == TRUE){m_Rect.MoveRelative(0.0f, 10.0f, 0.0f);}if(m_Keyboard.KeyState(DIK_LEFT) == TRUE){m_Rect.MoveRelative(-10.0f, 0.0f, 0.0f);}if(m_Keyboard.KeyState(DIK_RIGHT) == TRUE){m_Rect.MoveRelative(10.0f, 0.0f, 0.0f);}m_Rect.Render();m_Rect2.Render();m_Graphics.EndScene();


So this would now intialise the rects to the correct position for the first frame, and then you could move m_Rect by 10 pixels each frame thereafter.

A couple of side notes which you can ignore if you want:

You should really make the movement relative to time rather than relative to a frame. The way you have it at the moment, if the frame rate drops then the rect movement appears slower. You should query a timer for the time between the last frame and the current frame, and then multiply the movement amount by that.

In your c2DRect move functions, you don't need to create the matrix and set the D3D transform. This is actually wasteful. You should only do this just before you call DrawPrimitive (ie. in your c2DRect::Render() function. If you want to continue to cache the translation matrix, then you should have a bool in the class to mark it as 'dirty'. In the move functions you set the dirty flag to true. When you render, if the dirty flag is true, then you recompute the translation matrix and set the dirty flag to false.

e.g.
// Inside your c2DRect::Render function...if (m_Dirty){D3DXMatrixTranslation(&m_matPosition, m_X, m_Y, m_Z);m_Dirty = false;}m_pD3DDevice->SetTransform(D3DTS_WORLD, &m_matPosition);...


Thanks alot for the help it works now. I can move the one rect without changing the other position. So could I say if I made alot of these rects then I could move anyone seperatly from the rest?
Yes. That's the beauty of making them completely self-contained. The only resource that they share is the d3ddevice. If you've moved the SetTransform call into the Render function then you've reduced the dependancy on the device to one function so you can be sure that you can make as many rects as you want now and move them independently.

This topic is closed to new replies.

Advertisement