Archived

This topic is now archived and is closed to further replies.

Stupendous

C: Losing precision problem

Recommended Posts

First a little code:
  
typedef struct vec3_type{
  float x, y, z;
} vec3_t;

typedef struct cam_type{
  vec3_t position;
  vec3_t lookAt;
} cam_t;

/*
  Performs the transformation on v, given by the matrix m.
*/
Vec3_Transform(vec3_t *v, mat4x4_t *m)
  
What I have is a camera looking at the origin of my world. At the center of the origin is a cube. I want to rotate my camera around the cube, while it is looking at the center. Right now I do,
  
Vec3_Transform(&(my_cam.position), my_rot_matrix);
  
nonstop and eventually my camera is in the center of the world because of the loss of precision. I know this because I print out the length of my_cam''s position vector. It gradually approaches 0 from starting at 4.0. How can I stop this? The only thing I have thought of so far is to not compound my calculations on my.position. Instead what I would do is keep updating my_rot_matrix with a new angle of rotation. So first I rotate by 0.5 degrees, then 1.0, then 1.5, etc. . . Oh, and I don''t want to use OpenGL''s rotation functions. Thanks.

Share this post


Link to post
Share on other sites
Compared to other things in the rendering pipeline, compounding your rotations like this is not really saving you any CPU time.

You''re right to think that calculating from scratch per frame will solve your problem.

Share this post


Link to post
Share on other sites
Your solution of continuously changing the angle of rotation is most likely the best. That's what I do

Just remember that if you go past 360 (or some higher number that is within the bounds of what float can hold) you should reduce the rotation angle (IE 360 degrees is the same as 0 degrees in terms of instantaneous rotation). This is because if you just keep increasing the number you will run into problems when you reach the max number that float can hold.

I also agree with you -- in this case, don't use openGL rotation functions.

Edit: Alternatively, you could multiply direction/distance vector from the center to the newposition by the distance you want over the current distance everytime the position is updated, though the former would still be the more efficient choice.

--------------------
Matthew Calabrese
Realtime 3D Orchestra:
Programmer, Composer,
and 3D Artist/Animator
"I can see the music..."

[edited by - Matt Calabrese on March 17, 2002 4:24:27 PM]

Share this post


Link to post
Share on other sites
You don't have enough information in your camera struct for one thing. And you always need to clean your camera every now and then. Floats get dirty.

Here's camera code that I wrote:


            
// camera.c


#ifndef _CAMERA_C_
#define _CAMERA_C_

#include <camera/camera.h>
#include <windows.h>

#define CAM_SERVICE_SCHEDULE 16

static CAMERA defCamera = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
45.0f
};

static CAMERA *camera = &defCamera;

static unsigned long camMoves = 0;

static float camZShift = 0.01f;
static float camXShift = 0.01f;
static float camYShift = 0.01f;

static float camRollAngle = 0.1f;
static float camPitchAngle = 0.1f;
static float camYawAngle = 0.1f;

// key binding functions


void camSetForwardKey (unsigned char keyCode)
{
camForwardKey = keyCode;
}

void camSetBackKey (unsigned char keyCode)
{
camBackKey = keyCode;
}

void camSetLeftKey (unsigned char keyCode)
{
camLeftKey = keyCode;
}

void camSetRightKey (unsigned char keyCode)
{
camRightKey = keyCode;
}

void camSetUpKey (unsigned char keyCode)
{
camUpKey = keyCode;
}

void camSetDownKey (unsigned char keyCode)
{
camDownKey = keyCode;
}

void camSetRollLeftKey (unsigned char keyCode)
{
camRollLeftKey = keyCode;
}

void camSetRollRightKey (unsigned char keyCode)
{
camRollRightKey = keyCode;
}

void camSetPitchUpKey (unsigned char keyCode)
{
camPitchUpKey = keyCode;
}

void camSetPitchDownKey (unsigned char keyCode)
{
camPitchDownKey = keyCode;
}

void camSetYawLeftKey (unsigned char keyCode)
{
camYawLeftKey = keyCode;
}

void camSetYawRightKey (unsigned char keyCode)
{
camYawRightKey = keyCode;
}

void camSetZShift (float v)
{
camZShift = v;
}

void camSetXShift (float v)
{
camXShift = v;
}

void camSetYShift (float v)
{
camYShift = v;
}

void camSetRollAngle (float angle)
{
camRollAngle = angle;
}

void camSetPitchAngle (float angle)
{
camPitchAngle = angle;
}

void camSetYayAngle (float angle)
{
camYawAngle = angle;
}

#define keyDown(k) ( GetAsyncKeyState (k) & (0x0001 << 15) )

void camKeyProcess (float frameRate)
{
float s;

if (frameRate < 0.0001f)
s = 1.0f;
else
s = 60.0f / frameRate;

if (keyDown (camForwardKey))
camForward (camZShift * s);

if (keyDown (camBackKey))
camBack (camZShift * s);

if (keyDown (camLeftKey))
camLeft (camXShift * s);

if (keyDown (camRightKey))
camRight (camXShift * s);

if (keyDown (camUpKey))
camUp (camYShift * s);

if (keyDown (camDownKey))
camDown (camYShift * s);

if (keyDown (camRollLeftKey))
camRoll (-camRollAngle * s);

if (keyDown (camRollRightKey))
camRoll (camRollAngle * s);

if (keyDown (camPitchUpKey))
camPitch (-camPitchAngle * s);

if (keyDown (camPitchDownKey))
camPitch (camPitchAngle * s);

if (keyDown (camYawLeftKey))
camYaw (camYawAngle * s);

if (keyDown (camYawRightKey))
camYaw (-camYawAngle * s);
}

void chooseCam (CAMERA *c)
{
camera = c;
cleanCam ();
}

CAMERA *getCam ()
{
return camera;
}

void chooseDefCam ()
{
camera = &defCamera;

cleanCam ();
}

void initCam (float posX, float posY, float posZ,
float viewX, float viewY, float viewZ,
float upX, float upY, float upZ)
{
p3setf (posX, posY, posZ, camera->pos);
v3setf (viewX, viewY, viewZ, camera->view);
v3setf (upX, upY, upZ, camera->up);
v3crossv3ccwrhs (camera->up, camera->view, camera->left);

cleanCam ();
}

void cleanCam ()
{
// renormalize view and up

v3normm (camera->view);
v3normm (camera->up);

// straighten left vector

v3crossv3ccwrhs (camera->up, camera->view, camera->left);
v3normm (camera->left);

// straighten up vector

v3crossv3ccwrhs (camera->view, camera->left, camera->up);
v3normm (camera->up);
}

void camForward (float step)
{
POINT3 V;

v3mulf (camera->view, step, V);
v3addv3m (camera->pos, V);
}

void camBack (float step)
{
POINT3 V;

v3mulf (camera->view, step, V);
v3subv3m (camera->pos, V);
}

void camLeft (float step)
{
POINT3 V;

v3mulf (camera->left, step, V);
v3addv3m (camera->pos, V);
}

void camRight (float step)
{
POINT3 V;

v3mulf (camera->left, step, V);
v3subv3m (camera->pos, V);
}

void camUp (float step)
{
POINT3 V;

v3mulf (camera->up, step, V);
v3addv3m (camera->pos, V);
}

void camDown (float step)
{
POINT3 V;

v3mulf (camera->up, step, V);
v3subv3m (camera->pos, V);
}

// not implemented yet


//camShiftXY (float x, float y)


//camShiftXZ (float x, float z)


//camShiftYZ (float y, float z)


//camShiftArb (float x, float y, float z)


void camRoll (float angle)
{
MATRIX44 M;
VECTOR3 V;

M44rot (camera->view, degtorad (angle), M);
v3trans (camera->up, M, V);
v3copv3 (V, camera->up);
v3trans (camera->left, M, V);
v3copv3 (V, camera->left);

if (!(camMoves++ % CAM_SERVICE_SCHEDULE));
cleanCam ();
}

void camPitch (float angle)
{
MATRIX44 M;
VECTOR3 V;

M44rot (camera->left, degtorad (angle), M);
v3trans (camera->view, M, V);
v3copv3 (V, camera->view);
v3trans (camera->up, M, V);
v3copv3 (V, camera->up);

if (!(camMoves++ % CAM_SERVICE_SCHEDULE));
cleanCam ();
}

void camYaw (float angle)
{
MATRIX44 M;
VECTOR3 V;

M44rot (camera->up, degtorad (angle), M);
v3trans (camera->view, M, V);
v3copv3 (V, camera->view);
v3trans (camera->left, M, V);
v3copv3 (V, camera->left);

if (!(camMoves++ % CAM_SERVICE_SCHEDULE));
cleanCam ();
}


And the camera.h file:


        
// camera.h


#ifndef _CAMERA_H_
#define _CAMERA_H_

#include <vec/vec.h>

typedef struct _camera {
POINT3 pos;
VECTOR3 view;
VECTOR3 up;
VECTOR3 left;
float fov;
} CAMERA;

void camSetForwardKey (unsigned char keyCode);

void camSetBackKey (unsigned char keyCode);

void camSetLeftKey (unsigned char keyCode);

void camSetRightKey (unsigned char keyCode);

void camSetUpKey (unsigned char keyCode);

void camSetDownKey (unsigned char keyCode);

void camSetRollLeftKey (unsigned char keyCode);

void camSetRollRightKey (unsigned char keyCode);

void camSetPitchUpKey (unsigned char keyCode);

void camSetPitchDownKey (unsigned char keyCode);

void camSetYawLeftKey (unsigned char keyCode);

void camSetYawRightKey (unsigned char keyCode);

void camSetZShift (float v);

void camSetXShift (float v);

void camSetYShift (float v);

void camSetRollAngle (float angle);

void camSetPitchAngle (float angle);

void camSetYayAngle (float angle);

void camKeyProcess ();

void chooseCam (CAMERA *c);

CAMERA *getCam ();

void chooseDefCam ();

void initCam (float posX, float posY, float posZ,
float viewX, float viewY, float viewZ,
float upX, float upY, float upZ);

void cleanCam ();

void camForward (float step);

void camBack (float step);

void camLeft (float step);

void camRight (float step);

void camUp (float step);

void camDown (float step);

void camRoll (float angle);

void camPitch (float angle);

void camYaw (float angle);

#endif // _CAMERA_H_



[edited by - bishop_pass on March 18, 2002 1:16:31 AM]

Share this post


Link to post
Share on other sites