**2**

# Update up, forward, right vectors.

###
#1
Members - Reputation: **120**

Posted 04 May 2011 - 03:55 AM

My airplane will start out flying level and I will be able to start with up, right, and forward/heading vectors. On each frame the plane will move along the forward vector to its new position. If the user inputs up/down the pitch will be affected by "n" degrees, and the same for left/right and the roll affecting the up vector. I am planning ahead for yaw, though I haven't worked out the user control yet.

So I am trying to figure out how I update the up/right/forward vectors based on the degree of rotation. I have found lots of information about how to calculate the axis or the angle of rotation. Perhaps I am going about this in a harder way than necessary, but I know how I want to use these vectors and am sure it will work once I figure out how to calculate the new vectors.

I am using Opengl (Android) and want to use the gluLookat function. It simply accepts values of eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ. Obviously I will need a new up vector here for each frame, and of course my airplane will not always be aligned with the world up vector. Calculating the other values I have solved, based on knowing the updated vector.

I will simplify my question to just one rotation. I have a forward, right, and up vector. I receive input to move pitch up and I know the number of degrees. My rotation axis is the right vector. Given the rotation axis and amount of rotation (in degrees), how do I find the new up & foward vectors?

Thanks in advance!

###
#2
Crossbones+ - Reputation: **7042**

Posted 04 May 2011 - 04:17 AM

With a rotation axis and angle you have all parameters of the so-called axis/angle rotation representation. The internet (e.g. euclideanspace.com) tells about conversion, e.g. to a rotation matrix.

###
#3
Members - Reputation: **120**

Posted 04 May 2011 - 01:30 PM

I will need to brush up on my matrices before I get going. Several of the sites that I found were leading me toward using rotation matrices and I guess I just was avoiding them. The opengl documentation is what has made me shy away from using matrices. I suppose I can setup a class for the matrix math similar to the one I am using for my 3d vectors.

So if I setup a rotation matrix do you know if I can just apply it to my code with an opengl call? I was looking at glMultimatrix and it seems like that may work. Or would it be better to just compute the matrices and extract the vectors, then use them in my code as I was already intending?

Well, I will get in some studying and probably test out both ways. I will report back if I have any serious struggles. Thanks again for your help.

###
#4
Members - Reputation: **2076**

Posted 04 May 2011 - 05:47 PM

Provided it's arranged in memory the way OpenGL expects (that is, the data occupies a contiguous block of 16 elements and the elements of each basis vector appear consecutively), you can upload the matrix directly using glLoadMatrix*() or glMultMatrix*().So if I setup a rotation matrix do you know if I can just apply it to my code with an opengl call? I was looking at glMultimatrix and it seems like that may work. Or would it be better to just compute the matrices and extract the vectors, then use them in my code as I was already intending?

###
#8
Members - Reputation: **120**

Posted 08 May 2011 - 04:14 AM

So how do I update the actual forward/up/right vectors and rotate around them. I'm sure I can figure out the math behind it, once I know the right steps to take. Also, the matrices I used for rotation seem to be locked to rotate around the world axes. It seems I should be using a matrix that would rotate around an arbitrary axis. I'm just not sure if this would be the right solution, or if more is needed to update the vectors.

###
#9
Members - Reputation: **120**

Posted 10 May 2011 - 03:49 PM

If I only make one rotation, the code works as expected. However, as soon as I make a second rotation the axis is incorrect. (For whichever comes last in the code, pitch or roll)

public class BARenderer implements Renderer { private float[] mArbRotMatrix = new float[16]; private float[] mOrientMatrix = new float[16]; public static boolean moveLeft; public static boolean moveRight; public static boolean moveUp; public static boolean moveDown; private Context mContext; private F22 F22; private Ground Ground1; private Sky Sky1; private GL10 mGl; private int frame; private float pitch; private float yaw; private float roll; public BARenderer(Context context) { mContext = context; Init(); } public void Init() { mOrientMatrix[0] = 1; mOrientMatrix[1] = 0; mOrientMatrix[2] = 0; mOrientMatrix[3] = 0; mOrientMatrix[4] = 0; mOrientMatrix[5] = 1; mOrientMatrix[6] = 0; mOrientMatrix[7] = 0; mOrientMatrix[8] = 0; mOrientMatrix[9] = 0; mOrientMatrix[10] = 1; mOrientMatrix[11] = 0; mOrientMatrix[12] = 0; mOrientMatrix[13] = 0; mOrientMatrix[14] = 0; mOrientMatrix[15] = 1; pitch = 0; yaw = 0; roll = 0; } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { mGl = gl; gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW ) gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading gl.glEnable(GL10.GL_BLEND); gl.glEnable(GL10.GL_DITHER); gl.glShadeModel(GL10.GL_SMOOTH); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //Black Background gl.glClearDepthf(1.0f); //Depth Buffer Setup gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do gl.glEnable(GL10.GL_ALPHA_TEST); // Enable face culling. gl.glEnable(GL10.GL_CULL_FACE); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); } @Override public void onDrawFrame(GL10 gl) { if (gl == null) return; gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Replace the current matrix with the identity matrix gl.glLoadIdentity(); gl.glTranslatef(0, 0, -30); //Plane gl.glPushMatrix(); gl.glScalef(0.5f, 0.5f, 0.5f); if(F22 != null) F22.draw(mGl); gl.glPopMatrix(); gl.glPushMatrix(); gl.glMultMatrixf(mOrientMatrix, 0); //Ground gl.glPushMatrix(); gl.glTranslatef(0, -100, 0); if(Ground1 != null) Ground1.draw(mGl); gl.glPopMatrix(); //Sky gl.glPushMatrix(); gl.glTranslatef(0, -1000, 0); if(Sky1 != null) Sky1.draw(mGl); gl.glPopMatrix(); gl.glPopMatrix(); frame += 1; speedframe += speed; if (moveLeft){ roll += -0.1; } if (moveRight){ roll += 0.1; } if (moveUp){ pitch += 0.1; } if (moveDown){ pitch += -0.1; } setRotPitch(pitch, mOrientMatrix[0], mOrientMatrix[1], mOrientMatrix[2]); mOrientMatrix = mArbRotMatrix; setRotPitch(pitch, mOrientMatrix[8], mOrientMatrix[9], mOrientMatrix[10]); mOrientMatrix = mArbRotMatrix; } public void setRotPitch(double angle, double x, double y, double z) { double c = Math.cos(angle); double s = Math.sin(angle); double t = 1 - Math.cos(angle); mArbRotMatrix[0] = (float) ((t*x*x) + c); mArbRotMatrix[1] = (float) ((t*x*y) - (s*z)); mArbRotMatrix[2] = (float) ((t*x*y) + (s*y)); mArbRotMatrix[3] = 0; mArbRotMatrix[4] = (float) ((t*x*y) + (s*z)); mArbRotMatrix[5] = (float) ((t*y*y) + c); mArbRotMatrix[6] = (float) ((t*y*z) - (s*x)); mArbRotMatrix[7] = 0; mArbRotMatrix[8] = (float) ((t*x*z) - (s*y)); mArbRotMatrix[9] = (float) ((t*y*z) + (s*x)); mArbRotMatrix[10] = (float) ((t*z*z) + c); mArbRotMatrix[11] = 0; mArbRotMatrix[12] = 0; // x movement mArbRotMatrix[13] = 0; // y movement mArbRotMatrix[14] = 0; // z movement mArbRotMatrix[15] = 1; } }

Any suggestions?

###
#10
Members - Reputation: **120**

Posted 17 May 2011 - 06:44 PM

Thanks again for the pointing me in the right direction!

###
#11
Members - Reputation: **100**

Posted 19 May 2011 - 09:36 AM

I got it working now! There were two main problems with the code above. First the pitch/roll values were not needed to be added on every input. They should be =0.01f or =0 dependent on input. (not +=0.01f) The second problem was that I was making the mOrientMatrix = mArbRotMatrix, when I should have been multiplying them together. Though I had tried this, I finally realized that I had transposed my matrix multiplication, therefore getting incorrect values in return. Coupled with the first problem any time I tried a multiplied matrix I was getting very strange rotations. Once I fixed both of these everything fell into place. I actually ended up removing the two rotation on arbitrary axes, and used on combined matrix for rotation on x,y,z axes. I added a translation matrix and got that working as well. Finally I am able to fly around my world, even straight through the ground. I guess I am ready for some collision detection.

Thanks again for the pointing me in the right direction!

Coolness, I'm glad you got it to work!

I have a tremendous favor to ask you... Could you post the code that made it work? I'm stuck on the same thing for my own game and I can't figure out how to get the rotations to work correctly. Right now I'm getting your 'very strange rotations' (I've been stuck on that for a week), and I'm doing the yaw/pitch/roll arbitrary axis matrices while multiplying all the matrices together. Thanks for the info!

###
#12
Members - Reputation: **100**

Posted 19 May 2011 - 10:23 AM

###
#13
Members - Reputation: **120**

Posted 19 May 2011 - 02:14 PM

Well, I thought everything was working right, hopefully you are not running in to this same problem I now have. Hopefully someone is still listening. Everything looks fine except for the speed. I am using a constant value for speed, but of course I want to be able to change the speed. Even with the constant speed, after about 30 seconds I notice speed building up. After about 1 minute it gets really fast and soon its uncontrollable. Maybe I still don't have something quite right.

Here is some code-

At the end of the onDrawFrame I call this sequence to create a newRotMatrix, which is called with glMultMatrixf(newRotmatrix, 0) just before I draw the ground and sky.

setmXYZrotMatrix(); //creates the rotation matrix mXYZrotmatrix dirx = mXYZrotMatrix[8]; //get the forward vector from the rotation matrix diry = mXYZrotMatrix[9]; dirz = mXYZrotMatrix[10]; setTransMatrix(speed, dirx, diry, dirz); //creates the translation matrix mTranslate matrix multMatrix4x4(mXYZrotMatrix, mTranslateMatrix, newRotMatrix2); //combine the rotation and translation matrices into one transform matrix (newRotMatrix2) multMatrix4x4(newRotMatrix, newRotMatrix2, newRotMatrix); //Apply the new transform to the current orientation

My rotation matrix and translation matrix builders:

public void setTransMatrix(double dist, double x, double y, double z) { mTranslateMatrix[0] = 1; mTranslateMatrix[1] = 0; mTranslateMatrix[2] = 0; mTranslateMatrix[3] = 0; mTranslateMatrix[4] = 0; mTranslateMatrix[5] = 1; mTranslateMatrix[6] = 0; mTranslateMatrix[7] = 0; mTranslateMatrix[8] = 0; mTranslateMatrix[9] = 0; mTranslateMatrix[10] = 1; mTranslateMatrix[11] = 0; mTranslateMatrix[12] = (float) (mTranslateMatrix[12] + (x * dist)); mTranslateMatrix[13] = (float) (mTranslateMatrix[13] + (y * dist)); mTranslateMatrix[14] = (float) (mTranslateMatrix[14] + (z * dist)); mTranslateMatrix[15] = 1; } public void setmXYZrotMatrix() { double cA = Math.cos(pitch); double sA = Math.sin(pitch); double cB = Math.cos(yaw); double sB = Math.sin(yaw); double cC = Math.cos(roll); double sC = Math.sin(roll); mXYZrotMatrix[0] = (float) (cB*cC); mXYZrotMatrix[1] = (float) ((sA*sB*cC)+(cA*sC)); mXYZrotMatrix[2] = (float) ((-cA*sB*cC)+(sA*sC)); mXYZrotMatrix[3] = 0; mXYZrotMatrix[4] = (float) (-cB*sC); mXYZrotMatrix[5] = (float) ((-sA*sB*sC) + (cA*cC)); mXYZrotMatrix[6] = (float) ((cA*sB*sC)+(sA*cC)); mXYZrotMatrix[7] = 0; mXYZrotMatrix[8] = (float) sB; mXYZrotMatrix[9] = (float) (-sA*cB); mXYZrotMatrix[10] = (float) (cA*cB); mXYZrotMatrix[11] = 0; mXYZrotMatrix[12] = 0; mXYZrotMatrix[13] = 0; mXYZrotMatrix[14] = 0; mXYZrotMatrix[15] = 1; }

Matrix multiplication is done here

public void multMatrix4x4(float[] mat1, float[] mat2, float[] newMat) { newMat [0] = (mat1[0] * mat2[0]) + (mat1[1] * mat2[1]) + (mat1[2] * mat2[2]) + (mat1[3] * mat2[3]); newMat [1] = (mat1[0] * mat2[4]) + (mat1[1] * mat2[5]) + (mat1[2] * mat2[6]) + (mat1[3] * mat2[7]); newMat [2] = (mat1[0] * mat2[8]) + (mat1[1] * mat2[9]) + (mat1[2] * mat2[10]) + (mat1[3] * mat2[11]); newMat [3] = (mat1[0] * mat2[12]) + (mat1[1] * mat2[13]) + (mat1[2] * mat2[14]) + (mat1[3] * mat2[15]); newMat [4] = (mat1[4] * mat2[0]) + (mat1[5] * mat2[1]) + (mat1[6] * mat2[2]) + (mat1[7] * mat2[3]); newMat [5] = (mat1[4] * mat2[4]) + (mat1[5] * mat2[5]) + (mat1[6] * mat2[6]) + (mat1[7] * mat2[7]); newMat [6] = (mat1[4] * mat2[8]) + (mat1[5] * mat2[9]) + (mat1[6] * mat2[10]) + (mat1[7] * mat2[11]); newMat [7] = (mat1[4] * mat2[12]) + (mat1[5] * mat2[13]) + (mat1[6] * mat2[14]) + (mat1[7] * mat2[15]); newMat [8] = (mat1[8] * mat2[0]) + (mat1[9] * mat2[1]) + (mat1[10] * mat2[2]) + (mat1[11] * mat2[3]); newMat [9] = (mat1[8] * mat2[4]) + (mat1[9] * mat2[5]) + (mat1[10] * mat2[6]) + (mat1[11] * mat2[7]); newMat [10] = (mat1[8] * mat2[8]) + (mat1[9] * mat2[9]) + (mat1[10] * mat2[10]) + (mat1[11] * mat2[11]); newMat [11] = (mat1[8] * mat2[12]) + (mat1[9] * mat2[13]) + (mat1[10] * mat2[14]) + (mat1[11] * mat2[15]); newMat [12] = (mat1[12] * mat2[0]) + (mat1[13] * mat2[1]) + (mat1[14] * mat2[2]) + (mat1[15] * mat2[3]); newMat [13] = (mat1[12] * mat2[4]) + (mat1[13] * mat2[5]) + (mat1[14] * mat2[6]) + (mat1[15] * mat2[7]); newMat [14] = (mat1[12] * mat2[8]) + (mat1[13] * mat2[9]) + (mat1[14] * mat2[10]) + (mat1[15] * mat2[11]); newMat [15] = (mat1[12] * mat2[12]) + (mat1[13] * mat2[13]) + (mat1[14] * mat2[14]) + (mat1[15] * mat2[15]); }

The resulting values of my mTranslatematrix give constant values based on the speed. However, when they are combined with the current orientation they multiply slowly, but exponentially.. I logged the value of each, just to make sure I wasn't imagining something, and found the [12],[13],[14] values for the transform matrix to be constant with the speed. The values of the newRotMatrix do increase over time as I was seeing in the application. Everything I have read is telling me to do it this way, and I can't find anything on the web with a similar problem. I'll keep trying but so far everything I change makes something else stop working right.

###
#14
Members - Reputation: **100**

Posted 19 May 2011 - 04:17 PM

// Orthogonalize the orientation matrix! var rfx, rfy, rfz, rfMag; var rux, ruy, ruz, ruMag; var rx, ry, rz, rMag; // Cross-product of right/forward vectors (store in 'up')... rfx = matrix[5]*matrix[6] - matrix[8]*matrix[3]; rfy = matrix[8]*matrix[0] - matrix[2]*matrix[6]; rfz = matrix[2]*matrix[3] - matrix[5]*matrix[0]; rfMag = sqrt(rfx*rfx + rfy*rfy + rfz*rfz); rfx = rfx/rfMag; rfy = rfy/rfMag; rfz = rfz/rfMag; // Cross-product of right/up vectors (store in 'forward')... rux = rfz*matrix[3] - rfy*matrix[6]; ruy = rfx*matrix[6] - rfz*matrix[0]; ruz = rfy*matrix[0] - rfx*matrix[3]; ruMag = sqrt(rux*rux + ruy*ruy + ruz*ruz); rux = rux/ruMag; ruy = ruy/ruMag; ruz = ruz/ruMag; // Normalize 'x' vector... rMag = sqrt(matrix[0]*matrix[0] + matrix[3]*matrix[3] + matrix[6]*matrix[6]); rx = matrix[0]/rMag; ry = matrix[3]/rMag; rz = matrix[6]/rMag; // All's orthaganlized! Store new values into // ship's 'ma' matrix... matrix[0] = rx; matrix[1] = rfx; matrix[2] = rux; matrix[3] = ry; matrix[4] = rfy; matrix[5] = ruy; matrix[6] = rz; matrix[7] = rfz; matrix[8] = ruz;

If you plug in this code and notice nothing except your speed errors are gone, then it worked! If the visuals go all over the place, I probably got a couple of matrix elements inverted or something like that and some simple tweaking should get it to work (I translated from my own variables to something more understandable before posting the code). Anyway, I was told that this code doesn't have to be executed on every frame, so you can make a call to this code every now and then (every ten frames?) or perform some low-cost calculations to see if an axis has gone out of tolerance.

Hope that helps! I'm still pretty new to this, so please let me know if it works!

EDIT: I plugged in this code after I updated the old orientation matrix with the new values, just before I put things on the screen.

###
#15
Members - Reputation: **120**

Posted 19 May 2011 - 06:46 PM

Thanks again, I'll update with my results later.

###
#16
Members - Reputation: **120**

Posted 20 May 2011 - 04:54 AM

The new code would look like mTranslateMatrix[12] = (float) (x * dist);

The same for [13] & [14], with y,z values. (All other values are just from the identity matrix). I believe the addition I thought needed to be there is actually happening when I multiply the matrix by the current orientation.

The re-orthoganalize code doesn't work if I just plug it in. I think you may be using row major matrices, while mine are column major (openGL). I tried some simple adjustments but no luck. Like I said I'll just rewrite it, its just a matter of multiplication order and matrix order and I'm sure it'll go easier if i do it by hand myself.

Thanks again and happy coding!

###
#17
Crossbones+ - Reputation: **7042**

Posted 20 May 2011 - 05:35 AM

*may*consider to switch from concatenating rotation matrices to concatenating quaternions. The are less prone to failure accumulation and their re-orthonormalization (yes, just that) is much more simple. However, it comes with the costs to do a conversion.

Just to clarify: Rotation matrices need not only be "re-orthogonalized" (i.e. their vectors need to be enforced to be pairwise orthogonal) but "re-orthonormalized" (i.e. they also need to be enforced to have unit length). Only a orthonormal matrix is guaranteed to be a pure rotation matrix. The code snippet actually does a re-orthonormalization (AFAIS), and I just wanted to clarify that the term used for it is not exact.

Also for clarification: "Row major" and "column major" are terms to describe how the elements of the 2D matrix are arranged when stored in linear (i.e. 1D) memory. Hence you probably mean "row vector use" (e.g. D3D, like in...

The re-orthoganalize code doesn't work if I just plug it in. I think you may be using row major matrices, while mine are column major (openGL). I tried some simple adjustments but no luck. Like I said I'll just rewrite it, its just a matter of multiplication order and matrix order and I'm sure it'll go easier if i do it by hand myself.

...

**v***

**M**) or "column vector use" (e.g. OpenGL, like in

**M***

**v**) instead, what plays a role how the terms of a matrix product are to be arranged.