DirectX sprite movement seems 'glitchy'

Started by
34 comments, last by Interminable 11 years, 8 months ago
I've got a sprite that moves across the screen, slowly. I've noticed as it moves, there appear to be 'imperfections', by that I mean it looks like it changes size by about single pixel in width as it moves along, then changing back, then doing it again, etc.

I can paste code if needed, but I'm wondering if there may simply be some 'fundamental' aspect of drawing sprites in DirectX that I may have missed.
Advertisement
Nope, you haven't missed anything. Thankfully, sprites do move very smoothly :)

I am currently writing a game with sprites alone and initially had poor movement. It was jumpy and ugly, and not smooth. But, it turned out it was the way I was calculating movement speed against framerate and I was using INT for positioning (which sounds logical as I was working in screenspace).

How did I fix it?

  • Multiply the sprites movement speed against the time since last frame
  • Position the sprites using float instead of int

Not having seen any of your code I would check these two things. I would love to know how you go (and happy to help where I can) :)

And if you can share more info on your timers etc, that would be great.

Nope, you haven't missed anything. Thankfully, sprites do move very smoothly smile.png

I am currently writing a game with sprites alone and initially had poor movement. It was jumpy and ugly, and not smooth. But, it turned out it was the way I was calculating movement speed against framerate and I was using INT for positioning (which sounds logical as I was working in screenspace).

How did I fix it?

  • Multiply the sprites movement speed against the time since last frame
  • Position the sprites using float instead of int

Not having seen any of your code I would check these two things. I would love to know how you go (and happy to help where I can) smile.png

And if you can share more info on your timers etc, that would be great.


Here's what I was using to test it:


void Object::Update()
{
coordinates.x += (20 * frameRenderTime);
}


coordinates is an instance of D3DXVECTOR3. Update() is called from another Update() function in my main Engine class, whose Update() function is called from main, inside the message loop:


try
{
GetSystemTime(&systemTime);
milliseconds = systemTime.wMilliseconds;
if(milliseconds != prevMilliseconds && milliseconds%10 == 0)
{
if(milliseconds<prevMilliseconds)
{
prevMilliseconds -= 1000;
// This will update roughly once every second.
}
frameRenderTime = milliseconds - prevMilliseconds;
frameRenderTime /= 1000;
prevMilliseconds = milliseconds;
mainWindow.enginePointer()->Update();
}

mainWindow.enginePointer()->rendererPointer()->Render();
}
catch(std::exception e)
{
e.what();
return 1;
}
This might help the issue.

http://msdn.microsof...0(v=vs.85).aspx

This might help the issue.

http://msdn.microsof...0(v=vs.85).aspx


What the article describes sounds like it could be related to the issue I'm having.

The problem is, I'm not drawing a 2D texture to a surface. It's a standalone sprite. I'm unsure how I can deal with this.

[quote name='JWBaker' timestamp='1342195376' post='4958828']
This might help the issue.

http://msdn.microsof...0(v=vs.85).aspx


What the article describes sounds like it could be related to the issue I'm having.

The problem is, I'm not drawing a 2D texture to a surface. It's a standalone sprite. I'm unsure how I can deal with this.
[/quote]

Do you mean you are using the Sprite class?

What you need to do is shift your Projection Matrix to account for the issue. This is how i setup mine and it seems to work. I'm not a DX master by any means but give it a shot and see if it helps. My Coordinate system has 0,0 at the center of the screen and +Y is up.

Device.SetTransform(TransformState.Projection, Matrix.Translation(-0.5f, 0.5f, 0.0f) * Matrix.OrthoLH(_form.ClientSize.Width, _form.ClientSize.Height, 0, 1));

[quote name='Interminable' timestamp='1342209934' post='4958898']
[quote name='JWBaker' timestamp='1342195376' post='4958828']
This might help the issue.

http://msdn.microsof...0(v=vs.85).aspx


What the article describes sounds like it could be related to the issue I'm having.

The problem is, I'm not drawing a 2D texture to a surface. It's a standalone sprite. I'm unsure how I can deal with this.
[/quote]

Do you mean you are using the Sprite class?

What you need to do is shift your Projection Matrix to account for the issue. This is how i setup mine and it seems to work. I'm not a DX master by any means but give it a shot and see if it helps. My Coordinate system has 0,0 at the center of the screen and +Y is up.

Device.SetTransform(TransformState.Projection, Matrix.Translation(-0.5f, 0.5f, 0.0f) * Matrix.OrthoLH(_form.ClientSize.Width, _form.ClientSize.Height, 0, 1));
[/quote]

I was just altering the coordinates I was drawing it at with Id3DDevice::Draw(). ><

But I recall some of this transformation stuff now, I have a feeling I made a thread on here a while back which involved those but was to do with rotations...

Anyway, in trying to look at how you're doing that particular line, I am unsure how you're doing 'TransformState.Projection'. It doesn't seem to be possible with D3DTRANSFORMSTATETYPE. And that's the required first argument for iD3DXDevice::SetTransform().

In addition I assume there's some specific function for filling the D3DTRANSFORMSTATETYPE struct, but I can't seem to find it. ><


I have altered my code to how I was using SetTransform() in the past. First I have a PrepareTransform() function:



void Renderer::PrepareTransform(int input)
{
transformStateType->Projection;
d3dXSprite->SetTransform(
D3DXMatrixTransformation2D(&d3dMatrix,
NULL,
0.0,
&D3DXVECTOR2(1.0,1.0),
&D3DXVECTOR2(texturesToRender[input].objectPointer->originPointer()->x,texturesToRender[input].objectPointer->originPointer()->y),
0.0f,
&D3DXVECTOR2(texturesToRender[input].objectPointer->coordinatesPointer()->x,texturesToRender[input].objectPointer->coordinatesPointer()->y));

d3dXSprite->SetTransform(&d3dMatrix);
}


And I draw after that function is called:



if(FAILED(hResult = d3dXSprite->Draw(*texturesToRender.objectPointer->texturePointer()->texturePointer(), NULL, NULL, NULL, 0xffffffff)))
{


Unfortunately the issue still exists, but I would assume this is because I'm not dealing with this projection matrix stuff you're mentioning.
I still think it is to do with your timer. GetSystemTime() seems to be only accurate to the millisecond.

If you have a basic scene you might be rendering faster than 1000 fps, so your scene will be choppy as the timer wont be acurate enough.

On my 3 year old video card my application (that also uses sprites) is rendering at 8000 FPS. This is why I had the same problems that your are experiencing. I had to re-think my timer.

Give my timer a try smile.png


#pragma once
class Timer
{
public:
Timer()
{
liCurrent.QuadPart=0;
liPrevious.QuadPart=0;
}
~Timer()
{
}
long double TimeSinceLastFrame()
{
QueryPerformanceFrequency(&liPerfFreq);
QueryPerformanceCounter(&liCurrent);
ddFrameTime=(liCurrent.QuadPart-liPrevious.QuadPart)/long double(liPerfFreq.QuadPart)*1000;
liPrevious.QuadPart=liCurrent.QuadPart;
return ddFrameTime;
}
private:
LARGE_INTEGER liCurrent;
LARGE_INTEGER liPrevious;
LARGE_INTEGER liPerfFreq;
LARGE_INTEGER liStart;
long double ddFrameTime;
};
TimeSinceLastFrame() will return exactly that (but using the performance counters)

I would love to know how you go smile.png

I still think it is to do with your timer. GetSystemTime() seems to be only accurate to the millisecond.

If you have a basic scene you might be rendering faster than 1000 fps, so your scene will be choppy as the timer wont be acurate enough.

On my 3 year old video card my application (that also uses sprites) is rendering at 8000 FPS. This is why I had the same problems that your are experiencing. I had to re-think my timer.

Give my timer a try smile.png


#pragma once
class Timer
{
public:
Timer()
{
liCurrent.QuadPart=0;
liPrevious.QuadPart=0;
}
~Timer()
{
}
long double TimeSinceLastFrame()
{
QueryPerformanceFrequency(&liPerfFreq);
QueryPerformanceCounter(&liCurrent);
ddFrameTime=(liCurrent.QuadPart-liPrevious.QuadPart)/long double(liPerfFreq.QuadPart)*1000;
liPrevious.QuadPart=liCurrent.QuadPart;
return ddFrameTime;
}
private:
LARGE_INTEGER liCurrent;
LARGE_INTEGER liPrevious;
LARGE_INTEGER liPerfFreq;
LARGE_INTEGER liStart;
long double ddFrameTime;
};
TimeSinceLastFrame() will return exactly that (but using the performance counters)

I would love to know how you go smile.png


I'll give it a try...but I'm also updating how far they should move using the time it takes to render the last frame. They appear to move smoothly already, just with minute changes in size as they go. Anyway, I'll EDIT this post with how I get on (or reply in a new post if there have been further responses).

EDIT: TimeSinceLastFrame()'s first return value is insanely high (eg 9029811) and screws up anything that relies on it for moving etc at the very beginning of the program. It eventually settles down to values of hundreds.

EDIT2: It appears to do this regardless of when the first call to it was, so I call it a few times needlessly at the beginning of my program to make it settle down a little before I start actually needing to use it.

Unfortunately the issue I am experiencing with the minute changes in size remains.
I'll give it a try...but I'm also updating how far they should move using the time it takes to render the last frame.


No probs, but all you need to do is multiply your movement speed against TimeSinceLastFrame() smile.png

This topic is closed to new replies.

Advertisement