Thread: 3D rotation problem, help please!

  1. #16
    Registered User
    Join Date
    Nov 2007
    Posts
    34
    Here goes another problem.

    I have something like:
    Code:
    //if 'a' key is hold.
    if(aHold)
    {
    		Quaternion temp = Quaternion(30, 0, -1, 0);
    		player->ori *= temp;
    		player->ori.normalise();
    }
    This bit does the rotation, then in the display method, or rather, draw mathod, the code looks like:
    Code:
    void spaceship::draw()
    {
    	if (alive)
    	{
    		glPushMatrix();
    			glTranslated(position.x, position.y, position.z);
    			glRotated(ori.r, ori.i, ori.j, ori.k);
    			glCallList(starfighter);
    			glCallList(engine_glow);
    		glPopMatrix();
    	}
    }
    what happens now is that when I hold 'a' key, the ship will rotate to the left, however after a small amount of ratation, it resets to the original orientation. Then it start rotating to the left again. This keeps going very fast and looks like vibration.

    Any idea where I might have done wrong?

  2. #17
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Are you sure you want 30 degrees (assuming your quaternions are in degrees, which I shouldn't assume)? That means that in 12 frames your spaceship goes all the way around, and 12 frames is approximately 1/5 of a second.

  3. #18
    Registered User
    Join Date
    Nov 2007
    Posts
    34
    I'm using a quaternion class found on the web. It's like this:
    Code:
    #ifndef QUATERNION_H
    #define QUATERNION_H
    
    #include <math.h>
    #include "physics.h"
    
    class Quaternion
    {
    	public:
    		union {
    			struct {
    				double r;
    
    				double i;
    
    				double j;
    
    				double k;
    			};
    
    			double data[4];
    		};
    
    		/**
    		 * The default constructor creates a quaternion representing
    		 * a zero rotation.
    		 */
    		Quaternion() : r(1), i(0), j(0), k(0) {}
    
    		
    		Quaternion(const double r, const double i, const double j, const double k) 
    			: r(r), i(i), j(j), k(k) 
    		{
    		}
    	    
    
    		void normalise()
    		{
    			double d = r*r+i*i+j*j+k*k;
    
    			// Check for zero length quaternion, and use the no-rotation
    			// quaternion in that case.
    			if (d == 0) { 
    				r = 1; 
    				return;
    			}
    
    			d = ((double)1.0)/sqrt(d);
    			r *= d;
    			i *= d;
    			j *= d;
    			k *= d;
    		}
    
    		void operator *=(const Quaternion &multiplier)
    		{
    			Quaternion q = *this;
    			r = q.r*multiplier.r - q.i*multiplier.i - 
    				q.j*multiplier.j - q.k*multiplier.k;
    			i = q.r*multiplier.i + q.i*multiplier.r + 
    				q.j*multiplier.k - q.k*multiplier.j;
    			j = q.r*multiplier.j + q.j*multiplier.r + 
    				q.k*multiplier.i - q.i*multiplier.k;
    			k = q.r*multiplier.k + q.k*multiplier.r + 
    				q.i*multiplier.j - q.j*multiplier.i;
    		}
    
    
    		void addScaledVector(const Vector3& vector, double scale)
    		{
    			Quaternion q(0,
    				vector.x * scale,
    				vector.y * scale,
    				vector.z * scale);
    			q *= *this;
    			r += q.r * ((double)0.5);
    			i += q.i * ((double)0.5);
    			j += q.j * ((double)0.5);
    			k += q.k * ((double)0.5);
    		}
    
    		void rotateByVector(const Vector3& vector)
    		{
    			Quaternion q(0, vector.x, vector.y, vector.z);
    			(*this) *= q;
    		}
    };
    
    #endif

    I'm not sure if degree or radian should be used here. Although either way I do agree that the value I put in there was way to big. However, in what format would you suggest me to represent the angle and could you give me an example?

  4. #19
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Okay I got it to work. The idea here is to use a 6 element float array to represent the current state of an object, which I'm using a cube (eight sides!), not a spaceship:
    Code:
    typedef struct {
            float x;
            float y;
            float z;
            float xR;
            float yR;
            float zR;
    } Thing;
    
    Thing Cube={0.0f}  /* we begin at the origin */
    I have two functions to deal with Cube, both of which get called in my glutDisplayFunc() if you want to learn with glut. Anyway, the second one builds a cube, bells, whistles, textures, rocket launchers, what have you, using the Cube coordinates. The first one is what's important here, because it controls the position of the cube:
    Code:
    void movecube () {      /* think borg ;) */
            float trix[16];
            glPushMatrix(); /* reserve current state */
    
            glTranslatef(Cube.x,Cube.y,Cube.z);      /* move to   */
            glRotatef(Cube.xR, 1.0f, 0.0f, 0.0f);    /* where we  */
            glRotatef(Cube.yR, 0.0f, 1.0f, 0.0f);    /* should be */
            glRotatef(Cube.zR, 0.0f, 0.0f, 1.0f);      /* INCLUDE ROTATION */
    
            glTranslatef(0.0f,0.0f,0.5f);   /* now move FORWARD slowly... */
    
            glGetFloatv(GL_MODELVIEW_MATRIX,trix);
            Cube.x=trix[12];        /* this saves the new position of the Cube */
            Cube.y=trix[13];
            Cube.z=trix[14];
    
            glPopMatrix();  /* restore state (IMPORTANT) */
    }
    Like I said, this gets called before the routine which uses the Cube.elements to draw the cube in the right place.

    You control the xR, yR, zR with arrow keys + pgup/pgdown (glut handles this mostly). You have no choice about the acceleration, it is constant (nice simple demo), but it is relative to the cube; ie, it always moves front face forward, so you can steer it around all three dimensions (and notice, the forward is always because of a Z translation, just what you wanted!!).

    So it works fine. I can keep it spiralling around the viewport perpetually, but of course steering an object you are watching from the ground is tricky (get the camera to follow: next step). Sorry there are no quaternions.

    ps. That is some crazy C++ tish found by the OP! I thot it was supposed to be better! "Object oriented" AHAHAHA!!
    Last edited by MK27; 03-08-2009 at 08:50 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #20
    Registered User
    Join Date
    Nov 2007
    Posts
    34
    hey MK27! That's a nice example you just wrote. I actually thought about similar thing. But a little different.

    I had a vector to store ship position, and had another vector to store rotation. while I press 'a', it goes:
    Code:
    	if(aHold)
    	{
    		player->rotation.y+=1;
    	}
    then in the draw method of the player class, I had:

    Code:
    void spaceship::draw()
    {
    	if (alive)
    	{
    		glPushMatrix();
    			glTranslated(position.x, position.y, position.z);
    			glRotated(rotation.x, 1, 0, 0);
    			glRotated(rotation.y, 0, 1, 0);
    			glRotated(rotation.z, 0, 0, 1);
    
    			glCallList(spaceship);
    			glCallList(engine);
    		glPopMatrix();
    	}
    }
    Is it similiar to yours? What I failed to do was set the camera to follow the ship. Now I actually prefer your suggestion as it is more understandable to me. But could you tell me how can I set the camera to follow the ship? I have something like:

    Code:
    			glPushMatrix();
    
    				gluLookAt(0, 20, -80,										
    							0, 0, 1,										
    								0, 1, 0);									
    
    				
    
    				glRotated(player->getRotation().x, -1, 0, 0);
    				glRotated(player->getRotation().y, 0, -1, 0);
    				glRotated(player->getRotation().z, 0, 0, -1);
    				
    			
    				glTranslated(	0 - player->getPosition().x, 
    								0 - player->getPosition().y, 
    								0 - player->getPosition().z);
                                   
                                      //------------draw scene---------------//
    But it does not quite 'follow' the ship. As after few key presses, the ship can eventually face the screen which is something i dont want.

  6. #21
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I would just put glutLookAt in the renderscene() function or What-You-Call-It after you have both the camera and Cube position:
    Code:
            update_cam();
            arrangelamp();
            movecube();
            gluLookAt(Cam.x,Cam.y,Cam.z,Cube.x,Cube.y,Cube.z,0.0f,1.0f,0.0f);
    Which my camera is still stationary, but having it follow the cube is sweet; I have the lighting set up and a point to represent it so I can actually fly the cube directly into the light, it looks very nice. gluLookAt is part of the main API, too, not GLUT (so it needn't be a crutch).

    "GLUT" itself sort of restricts the form of the functions you can use which I resented at first, my prologue list was like a string of void ()s, but now I am beginning to think it was all (openGL) intended to work in a very streamlined way, lots of simple parts. A function call with little to no stack (key use of globals) is, I believe (perhaps wrongly?) very low stress on the all important processor.

    As after few key presses, the ship can eventually face the screen which is something i dont want.
    Ah! Yeah I'm getting tired, actually, I've been here all day. But if I do find another simple way to finish this one I'll post it here sometime this week...

    ps. the last time I thought of trying, the camera starts a few units behind the ship, and it's position is always determined that way (as a negative value on the z axis of the ship object). Don't even bother with the xR, yR, and zR of the camera Thing, because gluLookAt settles it.
    Last edited by MK27; 03-08-2009 at 09:23 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #22
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by MK27 View Post
    ps. the last time I thought of trying, the camera starts a few units behind the ship, and it's position is always determined that way (as a negative value on the z axis of the ship object). Don't even bother with the xR, yR, and zR of the camera Thing, because gluLookAt settles it.
    This idea does work, altho you do need to "bother with" and match the rotation as well as using gluLookAt.
    Code:
    void update_cam() {
            float trix[16];
            glLoadIdentity();
            glPushMatrix();
        
            glTranslatef(Cube.x,Cube.y,Cube.z);    //match cube   
            glRotatef(Cube.xR, 1.0f, 0.0f, 0.0f);   
            glRotatef(Cube.yR, 0.0f, 1.0f, 0.0f);    
            glRotatef(Cube.zR, 0.0f, 0.0f, 1.0f);   
    
            glTranslatef(0.0f,0.0f,-50.0f);    // behind cube 
     
            glGetFloatv(GL_MODELVIEW_MATRIX,trix);
            Cam.x=trix[12];         // save position of cam
            Cam.y=trix[13];
            Cam.z=trix[14];
            glPopMatrix();  
    }
    Obviously movecube() should be called before updatecam() now.

    One significant factor is that the z rotation of the Cube has to occur before the other rotations in order to "bank correctly", so the relevant part movecube() should look like this:
    Code:
            glTranslatef(Cube.x,Cube.y,Cube.z);
            glRotatef(Cube.zR, 0.0f, 0.0f, 1.0f);   /*  z first to allow banking */
            glRotatef(Cube.xR, 1.0f, 0.0f, 0.0f);
            glRotatef(Cube.yR, 0.0f, 1.0f, 0.0f);
    Whilst the camera determination needs to be in the proper order. Not including the rotations in updatecam() will cause the object to turn toward the camera, as the OP complained about, so that you are now going backward.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #23
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    If you want to follow the ship with the camera or do a 'chase camera' it's a simple matter of setting your camera's up, look and right vectors to the ship's up, look, and right. Then translate along the negative look vector of the ship for the desired zoom distance and this is where you place your camera. As long as the up, look, and right vectors match between camera and ship you can roll, pitch, and yaw the ship however you want and the camera will stay fixed right behind the ship.

    I find it convenient to also translate a bit along the ship's up vector to put the camera above and behind the ship rather than just directly behind it.

    If you want to get more complex and have the camera swing back and forth you will need quaternions as well as some simple spring mechanics to make it look right.

    Hooke's law for springs is:

    F = -kx

    Where:
    F = force in newton/meters
    k = spring constant in newton/meters
    x = distance between equilibrium of the spring and the stretch point of the spring (the stretch of the spring in meters)

    Notice this does not take into account friction which is really what makes a spring lose it's force over time. You will need another equation that will tell you how far the spring can stretch. At that point you can then compute the return force of the spring or the magnitude of the force that is causing the spring to retract by using the above formula.
    Last edited by VirtualAce; 03-13-2009 at 04:41 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. camera rotation matrix
    By Vick jr in forum Game Programming
    Replies: 5
    Last Post: 05-26-2009, 08:16 AM
  2. Bin packing problem....
    By 81N4RY_DR460N in forum C++ Programming
    Replies: 0
    Last Post: 08-01-2005, 05:20 AM
  3. rotation in 3d
    By DavidP in forum Game Programming
    Replies: 3
    Last Post: 11-04-2003, 10:06 PM
  4. 3D SDK for C++ programmers
    By chand in forum Game Programming
    Replies: 2
    Last Post: 05-20-2003, 07:38 AM
  5. 3d engines
    By Unregistered in forum Game Programming
    Replies: 7
    Last Post: 12-17-2001, 11:19 AM