How to do frame rate independent mouse?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
alexionne
Posts: 55
Joined: Fri Jun 22, 2007 9:55 am
Location: Novi Sad, Serbia

Post by alexionne »

We had similar problem in our game: on high frame rate, you had feel that mouse sensitivity is very low; and on low frame rate, you had feel that mouse sensitivity is high.

The trick was to divide the distance from the last mouse position by the time last frame took to execute. Something like:

Code: Select all

u32 lastTime;
core::position2d<f32> lastCursorPosition;
[...]
u32 currentTime = os::Timer::getTime();
core::position2d<f32> cursorPosition = Device->getCursorControl()->getRelativePosition();

core::position2d<f32> deltaPosition = cursorPosition - lastCursorPosition;
u32 deltaTime = currentTime - lastTime;

if (deltaTime == 0)
{
  deltaPosition.x = 0;
  deltaPosition.y = 0;
}
else
{
  const float COEF = ...;
  float scale = COEF / (float)deltaTime;
  deltaPosition.x *= scale;
  deltaPosition.y *= scale;
}
Now you use deltaPosition in your calculations. Also, you'll have to play a little with value of COEF to get some useful behaviour. Hope this helps :-)
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

rogerborg wrote:How are you retrieving and interpreting the mouse position/movement?
interpreting ?
I get it with getRelativePosition().

@alexionne:
Thanks, I'll try that code.
One question though, well, two ^^:
1. What does COEF suppose to stand for?
2. Values of which scale? -1 to 1, -255 to 255, or what?
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
alexionne
Posts: 55
Joined: Fri Jun 22, 2007 9:55 am
Location: Novi Sad, Serbia

Post by alexionne »

1. It is distance that mouse should be moved over some time. But, you shouldn't bother much about it's concrete meaning (if you really don't want to!), just...

2. ... use this algorithm:

10 COEF = 1000.0f
20 Test how well it works
30 IF mouse is too fast, make COEF smaller
40 IF mouse is too slow, make COEF larger
50 GOTO 20

Eventually, you'll get something useful :-)
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

MasterGod wrote:
rogerborg wrote:How are you retrieving and interpreting the mouse position/movement?
interpreting ?
I get it with getRelativePosition().
OK, I'm done trying to guess at what the problem is from a drip feed of info.

Remember this?

Image

Good luck! Wheeee!
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
karx11erx
Posts: 42
Joined: Wed Mar 05, 2008 1:28 pm

Post by karx11erx »

alexionne has pretty much given the solution. You need to scale the movement with the time that has passed between two subsequent samples of the mouse position.

Additionally it is a good idea to limit the number of mouse samples per second to 30 to 60. That helps to avoid problems due to numerical errors for very high framerates and evens the playing field for players in multiplayer games with vastly different system performance.

To do that, you could create some semaphore coupled to a timer, and every time let's say 25 ms have passed (that would be equivalent to 40 samples/sec) you sample the mouse.
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

I've just got home after few days, I hope I'll get to it today and try alexionne code.

P.S
Good to see you're still here karx11erx :wink:
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

rogerborg wrote:Remember this?

Image

Good luck! Wheeee!
lol!! My friend in the army is gonna jump like that on Monday!! - He just told me that.. :shock: :D

EDIT:
OMG he just said they're doing it without a close guide and they have 9 seconds before hitting ground! :shock:

P.S
It's his first time too..
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
wyrmmage
Posts: 204
Joined: Sun Mar 16, 2008 3:12 am
Contact:

Post by wyrmmage »

If you could, please post the code...I'm having a problem that's similiar to yours and it may or may not be related.

I don't know if this is your problem, but if you're just moving the mesh every time the mouse event happens (and you're using the getRelativePosition to check whether it moved up or down), then it you'll have this problem. Basically you just want to have two variables that represent the last stage of the mouse, then move your mouse based on how far it moved.
global variables:

Code: Select all

int mouseX;
actual file:

Code: Select all

int distanceMovedX = (howeverYouAreGettingTheMousePosition - mouseX);
meshSphere.rotateY(distanceMoved * whateverConstantYouAreUsing);
mouseX = howeverYouAreGettingTheMousePosiiton;
Of course, this could be entirely unrelated, and I think getRelativePosition returns a float, so you'll have to modify the code to suit your needs.

Hope that helped :)
-wyrmmage
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

alexionne, I'm trying your code and what I get is that the mouse has no effect at all:

Code: Select all

void CSceneNodeControllerAnimator::animateNode(ISceneNode* node, u32 timeMs)
		{
			if (!node)
				return;

			// Lock the mouse cursor's position to the center of the screen

			if(m_IsCursorUsed)
				m_pCursorControl->setPosition(m_CenterPosition);

			f32 timeDiff = 0.f;

			// so timeDiff will be 0.f on first time
			if(m_LastAnimationTime)
				timeDiff = (f32) ( timeMs - m_LastAnimationTime );

			m_LastAnimationTime = timeMs;

			f32 MovementSpeed = m_MoveSpeed/1000.f * timeDiff;
			f32 RotationSpeed = m_RotateSpeed/1000.f * timeDiff;

			// Calculate Mouse Movement

			position2df CursorPosition = m_pCursorControl->getRelativePosition();
			m_DeltaMousePos = CursorPosition - m_LastMousePos;

			if (timeDiff == 0)
			{
				m_DeltaMousePos.X = 0;
				m_DeltaMousePos.Y = 0;
			}
			else
			{
				const f32 factor = 1000.f;
				f32 scale = factor / (f32)timeDiff;
				m_DeltaMousePos.X *= scale;
				m_DeltaMousePos.Y *= scale;
			}

			// Calculate Movement

			vector3df VelocityVector;

			if (m_Input[EKOP_MOVE_FORWARD])
			{
				VelocityVector = vector3df(0.f,0.f,1.f);
			}
			if (m_Input[EKOP_MOVE_BACKWARD])
			{
				VelocityVector = vector3df(0.f,0.f,-1.f);
			}
			if (m_Input[EKOP_STRAFE_LEFT])
			{
				VelocityVector = vector3df(-1.f,0.f,0.f);
			}
			if (m_Input[EKOP_STRAFE_RIGHT])
			{
				VelocityVector = vector3df(1.f,0.f,0.f);
			}

			moveNode(node, VelocityVector * MovementSpeed);

			// Calculate Rotation

			if (m_RotUp || m_Input[EKOP_ROTATE_UP])
			{
				rotateNode(node, vector3df(-1.f,0.f,0.f) * RotationSpeed);

				m_RotUp = !m_RotUp;
			}
			if (m_RotDown || m_Input[EKOP_ROTATE_DOWN])
			{
				rotateNode(node, vector3df(1.f,0.f,0.f) * RotationSpeed);

				m_RotDown = !m_RotDown;
			}
			if (m_Input[EKOP_ROTATE_LEFT])
			{
				rotateNode(node, vector3df(0.f,0.f,1.f) * RotationSpeed);
			}
			if (m_Input[EKOP_ROTATE_RIGHT])
			{
				rotateNode(node, vector3df(0.f,0.f,-1.f) * RotationSpeed);
			}
			if ( m_RotLeft || m_Input[EKOP_YAW_LEFT])
			{
				if(!m_IsInvertY)
				{
					rotateNode(node, vector3df(0.f,-1.f,0.f) * RotationSpeed);
				}
				else
				{
					rotateNode(node, vector3df(0.f,1.f,0.f) * RotationSpeed);
				}

				m_RotLeft = !m_RotLeft;
			}
			if ( m_RotRight || m_Input[EKOP_YAW_RIGHT] )
			{
				if(!m_IsInvertY)
				{
					rotateNode(node, vector3df(0.f,1.f,0.f) * RotationSpeed);
				}
				else
				{
					rotateNode(node, vector3df(0.f,-1.f,0.f) * RotationSpeed);
				}

				m_RotRight = !m_RotRight;
			}
		}
In OnEvent()

Code: Select all

switch(event.MouseInput.Event)
						{
						case EMIE_MOUSE_MOVED:
							{
								if(m_DeltaMousePos.X > 0)
								{
									if(m_IsInvertY)
									{
										m_RotLeft = true;
										m_RotRight  = false;
									}
									else
									{
										m_RotLeft = false;
										m_RotRight  = true;
									}
								}
								else if(m_DeltaMousePos.X < 0)
								{
									if(m_IsInvertY)
									{
										m_RotLeft = false;
										m_RotRight  = true;
									}
									else
									{
										m_RotLeft = true;
										m_RotRight  = false;
									}
								}

								if(m_DeltaMousePos.Y > 0)
								{
									if(m_IsInvertX)
									{
										m_RotUp = true;
										m_RotDown  = false;
									}
									else
									{
										m_RotUp = false;
										m_RotDown  = true;
									}
								}
								else if(m_DeltaMousePos.Y < 0)
								{
									if(m_IsInvertX)
									{
										m_RotUp = false;
										m_RotDown  = true;
									}
									else
									{
										m_RotUp = true;
										m_RotDown  = false;
									}
								}
								break;
							}
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
karx11erx
Posts: 42
Joined: Wed Mar 05, 2008 1:28 pm

Post by karx11erx »

You need to make f_timeDiff static or it will be set to 0.0 everytime the function is called.
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

karx11erx wrote:You need to make f_timeDiff static or it will be set to 0.0 everytime the function is called.
It doesn't matter..

Code: Select all

f32 timeDiff = 0.f;

			// so timeDiff will be 0.f on first time
			if(m_LastAnimationTime)
				timeDiff = (f32) ( timeMs - m_LastAnimationTime );
But I also tried making it static and it still doesn't help.
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
karx11erx
Posts: 42
Joined: Wed Mar 05, 2008 1:28 pm

Post by karx11erx »

I was wrong anyway. I overlooked your using this m_LastAnimationTime var.
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

But it still doesn't work.. :(
Weird cause alexionne's explanation sounds totally right.. I should re-examine my implementation.. :?
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
karx11erx
Posts: 42
Joined: Wed Mar 05, 2008 1:28 pm

Post by karx11erx »

Well, after having taken another look at your code I think it should be "timeDiff / factor" and not the other way round.
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

karx11erx wrote:Well, after having taken another look at your code I think it should be "timeDiff / factor" and not the other way round.
I did what that guy suggested:
float scale = COEF / (float)deltaTime;
By the way, here's the code that Does work but has that problem all over again.
http://nusoftwarege.svn.sourceforge.net ... iew=markup

P.S
In case I weren't clear. The mouse doesn't change anything at all and before, it made the scene node move but with the rez problem:
We had similar problem in our game: on high frame rate, you had feel that mouse sensitivity is very low; and on low frame rate, you had feel that mouse sensitivity is high.
== what I have with the original code which I'm trying to fix.

I hope I'm clear now.

P.P.S
rogerborg, enough info now? :wink:
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Post Reply