View Full Version : About Software Implementation of glRotate()?

suo_alex

02-26-2003, 12:47 PM

Hi everyone, sorry for such a simple question :P

I have implemented glLookAt(), glTranslatef() as well as glScalef() (they are quite simple). But for this one I am not quite sure what I should do.

I tried to do it like this:

given (x, y, z), generate (x, y, 0) and (y, z, 0) to form a basis of the 3D space. Call this matrix A.

then use the matrix series inv(A) * (standard rotation) * A to implement the rotation.

I am wondering if I have done this correctly? The problem is the output is not right now, and I am wondering if this is the problem of my implementation or the idea.

Thank you very much.

Yours Alex

knackered

02-26-2003, 01:46 PM

This is from the mesa source code ( http://www.mesa.org/ )

void

_math_matrix_rotate( GLmatrix *mat,

GLfloat angle, GLfloat x, GLfloat y, GLfloat z )

{

/* This function contributed by Erich Boleyn (erich@uruk.org) */

GLfloat mag, s, c;

GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;

GLfloat m[16];

s = sin( angle * DEG2RAD );

c = cos( angle * DEG2RAD );

mag = GL_SQRT( x*x + y*y + z*z );

if (mag <= 1.0e-4) {

/* generate an identity matrix and return */

MEMCPY(m, Identity, sizeof(GLfloat)*16);

return;

}

x /= mag;

y /= mag;

z /= mag;

#define M(row,col) m[col*4+row]

/*

* Arbitrary axis rotation matrix.

*

* This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied

* like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation

* (which is about the X-axis), and the two composite transforms

* Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary

* from the arbitrary axis to the X-axis then back. They are

* all elementary rotations.

*

* Rz' is a rotation about the Z-axis, to bring the axis vector

* into the x-z plane. Then Ry' is applied, rotating about the

* Y-axis to bring the axis vector parallel with the X-axis. The

* rotation about the X-axis is then performed. Ry and Rz are

* simply the respective inverse transforms to bring the arbitrary

* axis back to it's original orientation. The first transforms

* Rz' and Ry' are considered inverses, since the data from the

* arbitrary axis gives you info on how to get to it, not how

* to get away from it, and an inverse must be applied.

*

* The basic calculation used is to recognize that the arbitrary

* axis vector (x, y, z), since it is of unit length, actually

* represents the sines and cosines of the angles to rotate the

* X-axis to the same orientation, with theta being the angle about

* Z and phi the angle about Y (in the order described above)

* as follows:

*

* cos ( theta ) = x / sqrt ( 1 - z^2 )

* sin ( theta ) = y / sqrt ( 1 - z^2 )

*

* cos ( phi ) = sqrt ( 1 - z^2 )

* sin ( phi ) = z

*

* Note that cos ( phi ) can further be inserted to the above

* formulas:

*

* cos ( theta ) = x / cos ( phi )

* sin ( theta ) = y / sin ( phi )

*

* ...etc. Because of those relations and the standard trigonometric

* relations, it is pssible to reduce the transforms down to what

* is used below. It may be that any primary axis chosen will give the

* same results (modulo a sign convention) using thie method.

*

* Particularly nice is to notice that all divisions that might

* have caused trouble when parallel to certain planes or

* axis go away with care paid to reducing the expressions.

* After checking, it does perform correctly under all cases, since

* in all the cases of division where the denominator would have

* been zero, the numerator would have been zero as well, giving

* the expected result.

*/

xx = x * x;

yy = y * y;

zz = z * z;

xy = x * y;

yz = y * z;

zx = z * x;

xs = x * s;

ys = y * s;

zs = z * s;

one_c = 1.0F - c;

M(0,0) = (one_c * xx) + c;

M(0,1) = (one_c * xy) - zs;

M(0,2) = (one_c * zx) + ys;

M(0,3) = 0.0F;

M(1,0) = (one_c * xy) + zs;

M(1,1) = (one_c * yy) + c;

M(1,2) = (one_c * yz) - xs;

M(1,3) = 0.0F;

M(2,0) = (one_c * zx) - ys;

M(2,1) = (one_c * yz) + xs;

M(2,2) = (one_c * zz) + c;

M(2,3) = 0.0F;

M(3,0) = 0.0F;

M(3,1) = 0.0F;

M(3,2) = 0.0F;

M(3,3) = 1.0F;

#undef M

matrix_multf( mat, m, MAT_FLAG_ROTATION );

}

antipop

02-27-2003, 05:10 AM

I think the formulas are present in the red book or Foley-VanDam. I do not have them at hand, so I cannot check it.

However, rotating about an axis are rather easy if you use quaterniations:

{

float M[16];

float q[4];

float a[3] = /* axis */

float d = /* amount */

create_q( q,a,d );

q_to_glrot_mat( q,m );

/* M contains the matrix */

}

/* q is a quaternion, v is a normalised vector, d is amount */

create_q( *q, *v, d )

{

float s,c;

s = sin( angle/2 );

c = cos( angle/2 );

q[0] = v[0]*s;

q[1] = v[1]*s;

q[2] = v[2]*s;

q[3] = c;

}

/* a slight rewrite of the code

presented in matrix-quat-faq */

q_to_glrot_mat( float *q, float *m)

{

float xx,xy,xz,xw,yy,yz,yw,zz,zw;

int i;

for(i=0; i<16; i++)

m[i] = 0.0;

m[0] = m[5] = m[10] = m[15] = 1.0;

xx = q[0]*q[0];

xy = q[0]*q[1];

xz = q[0]*q[2];

xw = q[0]*q[3];

yy = q[1]*q[1];

yz = q[1]*q[2];

yw = q[1]*q[3];

zz = q[2]*q[2];

zw = q[2]*q[3];

m[ 0] = 1.0-2.0*(yy+zz);

m[ 1] = 2.0*(xy+zw);

m[ 2] = 2.0*(xz-yw);

m[ 4] = 2.0*(xy-zw);

m[ 5] = 1.0-2.0*(xx+zz);

m[ 6] = 2.0*(yz+xw);

m[ 8] = 2.0*(xz+yw);

m[ 9] = 2.0*(yz-xw);

m[10] = 1.0-2.0*(xx+yy);

m[ 3] = 0.0;

m[ 7] = 0.0;

m[11] = 0.0;

m[12] = 0.0;

m[13] = 0.0;

m[14] = 0.0;

m[15] = 1.0;

}

Chuck0

02-27-2003, 11:00 AM

Originally posted by suo_alex:

Hi everyone, sorry for such a simple question :P

I have implemented glLookAt(), glTranslatef() as well as glScalef() (they are quite simple). But for this one I am not quite sure what I should do.

I tried to do it like this:

given (x, y, z), generate (x, y, 0) and (y, z, 0) to form a basis of the 3D space. Call this matrix A.

then use the matrix series inv(A) * (standard rotation) * A to implement the rotation.

I am wondering if I have done this correctly? The problem is the output is not right now, and I am wondering if this is the problem of my implementation or the idea.

Thank you very much.

Yours Alex

the idea sounds correct... i guess your problem is, that the basis for your 3d space isnt perpendicular to each other...

in order to get a perpendicular basis you can do something like this:

a... axis to rotate about

v=(1,0,0) (if a is parallel to this take another value)

x,y,z ... basis vectors for your space

z=a

x=v*z;

y=x*z;

(those * are cross products)

Powered by vBulletin® Version 4.2.2 Copyright © 2014 vBulletin Solutions, Inc. All rights reserved.