Quaternions and translation question

Hi all,

A quick question concerning translation and quaternions. I am currently using quaternions for my camera rotations and well, I now swear by it. I can look around by moving the mouse about, and this quickly and in a very smooth way. Now for the translation part. I want to move the camera in the direction the cam look towards (just like an fps game) by using the up left bottom right keys. The problem is that the camera translation is “choppy” and I want this to be as smooth as when I look around. Is there a way to combine both translation and quaternion rotation together. From what I have read on the subject, the answer is no. If that is the case, what about “slerping or lerping”?

Any ideas would be appreciated.
Eric

For smooth translations, imagine the 4 keys controls acceleration, then make that into speed, amortize speed with simulated friction, and update your position with that.

I had pretty good results with this procedure. Sorry, comments are in french.

void move_player(repere *pos, vecteur *speed,float dt)
{
	vecteur accel;
	vecteur rspeed;
	float speednorme;

	float xspeednorme = 0.0;
	float yspeednorme = 0.0;

	float speednorme_vert;    //  En fait, abs(speed->z) .
	float zspeednorme = 0.0;	//  Comme z n'est pas comme les autres dimensions, on les
							//  garde separes. Pour generaliser, il faudrait utiliser un type vecteur
	float frottement ;


  frottement = FRICTION * dt;
	//textprintf(screen, font, 10, 40, 255,"frot= %10.8f",frottement);

	init_vecteur(&accel); // accel mis a zero pour .x .y .z
	//_-_-_-_-_-tests touches.-_-_-_-_
	////////   la methode permet de gerer l'appui simultane
	////////   de deux touches contraires "a la quake" (cad. sans effet)
	//avance
	if	(key[KEY_UP])
         accel.y+=  ACCELERATION;

	if 	(key[KEY_DOWN])
         accel.y-=  ACCELERATION;

	//slide
	if	(key[KEY_LEFT])
         accel.x-=  ACCELERATION;

	if 	(key[KEY_RIGHT])
         accel.x+=  ACCELERATION;

	//ascension
	if	(key[KEY_PGUP])
         accel.z+=  ACCELERATION;

	if 	(key[KEY_PGDN])
         accel.z-=  ACCELERATION;

	//vitesse de marche.
	//************

	//relative au perso:
	rspeed.x = accel.x * dt;
	rspeed.y = accel.y * dt;
	rspeed.z = accel.z * dt;

	//absolue : -- tient compte de l'orientation
	speed->x += pos->X.x * rspeed.x - pos->Y.x * rspeed.y;
	speed->y += pos->Y.x * rspeed.x + pos->X.x * rspeed.y;
	speed->z += rspeed.z; // pas de modif de l'axe z
//	textprintf(screen, font, 10, 30, 255,"speed->x = %10.4f",x);

/////////////////////
// pour le plan horizontal :
	speednorme = norme2(speed->x,speed->y);

	if (speednorme > (frottement)) // vitesse non negligeable //////////////
		{
			xspeednorme = speed->x / speednorme; // xspeednorme et yspeednorme varient comme
			yspeednorme = speed->y / speednorme; // cos et sin. la somme de leurs carres vaut tjs 1

			speed->x-= frottement * xspeednorme;
			speed->y-= frottement * yspeednorme;
			if (speednorme > MAX_SPEED)
				{
					speed->x= MAX_SPEED * xspeednorme;
					speed->y= MAX_SPEED * yspeednorme;
				}
		}
	else {   ///// vitesse negligeable :
					 ///// pour eviter les effets de tres petite oscillations quand
					 ///// le joueur est sur le point de s'arreter, on le force a le faire. Pas de chichis !
			speed->x = 0;
			speed->y = 0;
		}

//////////////////////
// axe z vertical, traite separement

	speednorme_vert = fabsf(speed->z);
	if (speednorme_vert > (frottement)) // vitesse non negligeable //////////////
		{
			zspeednorme = speed->z / speednorme_vert;
			speed->z-= frottement * zspeednorme;

			if (speednorme_vert > MAX_SPEED)
				{
					speed->z= MAX_SPEED * zspeednorme;
				}
		}
	else {   ///// vitesse negligeable :
					 ///// pour eviter les effets de tres petite oscillations quand
					 ///// le joueur est sur le point de s'arreter, on le force a le faire. Pas de chichis !
			speed->z = 0;
		}


//		textprintf(screen, font, 10, 30, 255,"end spdnrm = %10.8f",norme2(speed->x,speed->y));


	//effet sur la position

	pos->O.y+=  speed->y * dt;
	pos->O.x+=  speed->x * dt;
	pos->O.z+=  speed->z * dt;
}

Thanks ZbuffeR… that will be of tremendous help! I have started studying the code, and for the french part, that’s not a problem… since I am french, well, french canadian. Will let you know how it goes… merci une autre fois

I have a suspicion that your problem is not just
a velocity/acceleration issue.

I program the OGL in X11, and have coded 3d worl
navigation apps. To move around I use a velocity -
acceleration model. However, I also trap keystroke
events for both press and release of keys. A
poorly implemented velocity - acceleration model is
still likely to be “choppy” if auto-repeat is on.

Velocity - acceleration (and integration) is the
way to go, but trap all keystroke events.

Sorry that it took so long to get back to you, work! Thanks for the replies I appreciate it.

It just happens that I am using an X11 base (Gnome on Solaris) so I will heed your warning on keystrokes handling.

Velocity - acceleration (and integration) is the way to go
That is what I am trying to figure out, i.e. not just to “steal code” but actually understand it.

This is what I got so far:
position function is x(t) = vo + vot

A velocity function describes the 3D velocity of an object as a function of time. Therefore, the velocity function is given by the derivative of the position function with respect to time.

v(t) = d/dt (x(t))

If the velocity is constant then
v(t) = vo

Under constant acceleration then
v(t) = vo + aot

The acceleration function which describes the object’s 3D acceleration as a function of time is given by tbe derivative of the velocity function.

a(t) = second derivative x(t)

So if you integrate everything this is what you get… The position function of a uniformly accelerating object is:

x(t) = x + vt + 1/2 (att)

Is that what you are saying? This would suppose that one has a stable timing function, or I am wrong in this.

What my code was doing is assuming the dt value (time interval between two frame) is small enough to be taken as the infinitesimal dt.

In practice it is not always true, and framerate variations will give slightly different results. But it gets mostly unnoticed by users and seem to be used in games. Apart from some hardcore gamers benchmarking the player speed in Quake3 for several framerates, and showing the optimal was around 90-100fps (authentic).

Some pseudo code describing my code :

if key_is_down then accel = 1 else accel =0;

speed = oldspeed + accel*dt;

position = oldposition + speed *dt;

Then I deal with friction (opposed to speed) to allow slowdown when not accelerating, and I set the speed to 0 if small enough. Else it does funny things, no rest for the heroes :slight_smile: !

Of course, there is some coordinates transformations because speed is a 2D vector (the starting part about orientation).

I hope I made it clearer now.
By the way, the moderators may want to move this thread to the ‘Math and Algos’ forum.

ok… will try that right away. One last question, I see this pos->X.x pos->Y.x pos->O.y ect… and was wondering what they stand for. Thanks again

Sorry for not reading this daily. Little time to browse around.

I would like to point out that there are many ways
to get this done, and the results you get will depend
on the application. I would advise anyone to stick
with physically accurate representations. For this
particular “simulation” of a translating/rotating
object in 3D, you should write the equations of
motion based on Newton’s laws, and keep track of
all the states – such as position, velocity, the
4 quaternion components, and their rates of change.

Do what the “aerospace vehicle dynamics and control”
people would do. You have a system like this:
x_dot = A x + b
where x is the vector of states and x_dot the
rate of change of x. Use any numerical integration
technique you like (Euler’s method, Runge-Kutta).
The matrix A depends on the object, and the vector
b can be time-dependent. You cannot help but
building A based on the simulation (rarely will
you see a situation where A changes with time).
The keystrokes, mouse-motions, and joystick
movement will change the vector b.

I hope this is helpful. Otherwise, make some Google
searches on “equations of motion” to get an idea.

pos is made of 4 vectors, 1 for the origin of the local coordinates system, the 3 others are the local X,Y,and Z vectors. So pos->O represents the position of the player, pos->X should point to the left of the player, pos->Y to forward, and pos->Z to up.

Here are the definition of C structs that are mentionned in my code, as well as some other useful stuff :

/*============================
	ensemble de types pour le reperage dans l'espace :
		- vecteur (coordonnee spatiale ou vertex).
		- face, constituee de trois vecteurs.
		- repere (base relative, constituee de 3 vecteurs unitaires et d'un vecteur origine.
*/
typedef struct
	{
   float x,y,z;
   } vecteur;

inline vecteur add_vect(vecteur v1,vecteur v2)
{
	v1.x+=v2.x;
	v1.y+=v2.y;
	v1.z+=v2.z;

	return v1;
}

inline float norme(vecteur v)
{

	return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
}

inline float norme2(float x,float y)
{
	return sqrtf(x*x + y*y);
}

typedef struct
   {
   unsigned int A,B,C;
   } face;

typedef struct
	{
   vecteur O,X,Y,Z;
   } repere;

// some constants too :
#define BASE_SPEED 6.0

const double M_TWOPI = 2 * M_PI;

/*==============
Les "constantes" sont en USI metrique.
================*/

float SENSITIVITY = 0.004;
/* sensibilité de la souris */

const float PLAYER_HEIGHT = 1.80;

float MAX_SPEED = BASE_SPEED;
/* vitesse absolue maximale. ici: 6 m/s
================*/


float ACCELERATION = 2 * BASE_SPEED;
/* acceleration absolue.

 ===============*/

float FRICTION = BASE_SPEED;
 /* ??pour mettre autant de temps
    ?? a accelerer qu'a ralentir il faut que FRICTION soit la moitie de ACCELERATION */

void set_player_speedaccel(float max_speed, float friction)
{
	MAX_SPEED    = max_speed;
	FRICTION     = friction;
	ACCELERATION = 2.0 * friction;
}

Thanks iznogoud for your replies, even if they seem a bit too complex for me :stuck_out_tongue:

Thanks guys for helping out. I figured out the problem of why my camera was “jerky” when translating it using keyboard keys, in my case w-a-s and d. Simply, after each key press, I called my render camera routine. That was the root of all evil! Now I just call the camera draw routine in the render scene routine and everything is as smooth as can be. Again, thanks