Rotation around axis?

Post everything that hasn't to do with MOHAA or MOHPA here, including site feedback/suggestions.

Moderator: Moderators

Post Reply
Rookie One.pl
Site Admin
Posts: 2752
Joined: Fri Jan 31, 2003 7:49 pm
Location: Nowa Wies Tworoska, Poland
Contact:

Rotation around axis?

Post by Rookie One.pl »

I haven't been able to find a solution on the net and I don't really get the function Quake has:

Code: Select all

/*
===============
RotatePointAroundVector

This is not implemented very well...
===============
*/
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,
							 float degrees ) {
	float	m[3][3];
	float	im[3][3];
	float	zrot[3][3];
	float	tmpmat[3][3];
	float	rot[3][3];
	int	i;
	vec3_t vr, vup, vf;
	float	rad;

	vf[0] = dir[0];
	vf[1] = dir[1];
	vf[2] = dir[2];

	PerpendicularVector( vr, dir );
	CrossProduct( vr, vf, vup );

	m[0][0] = vr[0];
	m[1][0] = vr[1];
	m[2][0] = vr[2];

	m[0][1] = vup[0];
	m[1][1] = vup[1];
	m[2][1] = vup[2];

	m[0][2] = vf[0];
	m[1][2] = vf[1];
	m[2][2] = vf[2];

	memcpy( im, m, sizeof( im ) );

	im[0][1] = m[1][0];
	im[0][2] = m[2][0];
	im[1][0] = m[0][1];
	im[1][2] = m[2][1];
	im[2][0] = m[0][2];
	im[2][1] = m[1][2];

	memset( zrot, 0, sizeof( zrot ) );
	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;

	rad = DEG2RAD( degrees );
	zrot[0][0] = cos( rad );
	zrot[0][1] = sin( rad );
	zrot[1][0] = -sin( rad );
	zrot[1][1] = cos( rad );

	MatrixMultiply( m, zrot, tmpmat );
	MatrixMultiply( tmpmat, im, rot );

	for ( i = 0; i < 3; i++ ) {
		dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
	}
}
Could any of our .map matrix-enabled brainiacs (*cough* jv *cough*) explain to me how to rotate a point around another point and an axis in 3D space? :) Specifically, I'd like to have a point with absolute coords rotated by a (pitch, yaw, roll) vector with the rotation centre in another point. C or pseudo code will be much appreciated. :)

I'm doing this project of real physics implementation in Quake 3 for the Culture & Science week at school. :P
Admin
Image
Image
Honour guide me.

here's my stuff - inequation.org | here's where I work - thefarm51.com
lizardkid
Windows Zealot
Posts: 3672
Joined: Fri Mar 19, 2004 7:16 pm
Location: Helena MT

Post by lizardkid »

This is going to be lengthy :oops:

The way i implemented it was like this. (in Java, but it should port well enough)

i made a Transform class, which held rotation, translation, and scaling data for a Polygon class, which held a list of Vectors that made up the poly. A poly that would move around a lot (such as a door or other entity) was given it's own Transform instance and the hierchy went on from there. (Polyhedrons would hold Poly lists as well as a master Transform, etc)

So then, i precomputed rotation values for that sort of thing;

In a nutshell, when i created a Transform it's constructor was passed the x y and z variables that it's Vector had. Then it went about creating cosine and sine values for the angles passed.

Code snippets use 'this' to emphasize it's a member variable...

Code: Select all

public Transform(float x, float y, float z)
{
      this.cosX = Math.cos(x);
      this.cosY = Math.cos(y); // Math.cos gets the cosine of the var.
      this.cosZ = Math.cos(z);

      //... same for Sine values
}
Simple enough.

So now, every update, the Vector class takes it's Transform instance and does this. (Sorry for the messiness, but it's a direct copy-paste)

Code: Select all


    
    // where it all starts
    public void addRotation(Transform t)
    {
        rotateX(t.getCosX(), t.getSinX());
        rotateZ(t.getCosZ(), t.getSinZ());
        rotateY(t.getCosY(), t.getSinY());
    }

    // GET ANGLES
    public float getAngleX()
    {return ((float)Math.atan2(sinX, cosX));}
    
    public float getAngleY()
    {return ((float)Math.atan2(sinY, cosY));}
    
    public float getAngleZ()
    {return ((float)Math.atan2(sinZ, cosZ));}
    

    // SET ANGLES
    public void setAngleX(float angleX)
    {
        cosX = (float)Math.cos(angleX);
        sinX = (float)Math.sin(angleX);
    }
    
    public void setAngleY(float angleY)
    {
        cosY = (float)Math.cos(angleY);
        sinY = (float)Math.sin(angleY);
    }
    
    public void setAngleZ(float angleZ)
    {
        cosZ = (float)Math.cos(angleZ);
        sinZ = (float)Math.sin(angleZ);
    }

    
    // ROTATE AXIS    
    public void rotateX(float cos, float sin)
    {// rotate this vector around the X AXIS
           
        y = y*cos - z*sin;
        z = y*sin + z*cos;
    }
    
    public void rotateY(float cos, float sin)
    {
        x = z*sin + x*cos;
        z = z*cos - x*sin;
    }
    
    public void rotateZ(float cos, float sin)
    {
        x = x*cos - y*sin;
        y = x*sin + y*cos;
    }
    
    

    public void rotateAngle(float angleX, float angleY, float angleZ)
    {
        rotateX(angleX);
        rotateY(angleY);
        rotateZ(angleZ);
    }

So pretty much, this rotates a Vector around a point. I had to collaborate with my math prof for most of this, so it uses the right-hand rule. Not totally sure what it'd look like with the normal MOH-style ruling.

If you wanted to rotate around an "alien" point, you'd just pass the Transform different values for x, y, and z so it would precompute sine and cosine differently.

sorry i couldn't give you C++ code, not used to it myself. You know how it goes when you get in a roll with one language, don't really want to reinvent the wheel...
Last edited by lizardkid on Tue Jan 30, 2007 7:52 pm, edited 1 time in total.
Moderator

۞
Abyssus pro sapientia
Olympus pro Ignarus
۞

AND STUFF™ © 2006
jv_map
Site Admin
Posts: 6521
Joined: Tue Sep 03, 2002 2:53 pm
Location: The Netherlands
Contact:

Post by jv_map »

Hmm that's interesting liz... rotateX takes 1 argument yet you're sending 2 :P

Anyway, Rookie, I'm not totally sure what you want... the code snippet from Q3 looks like an application of Rodrigues' formula (Note: <u,v> on this page is simply the dot product) which rotates a vector (i.e. a point) around a unit vector (i.e. an axis) for a given angle (float degrees). Yet you say you want to rotate by a (pitch, yaw, roll) vector (like angles in moh) so I'm a bit confused.

The first 50% of solving a problem is finding out what you want :)
Image
Rookie One.pl
Site Admin
Posts: 2752
Joined: Fri Jan 31, 2003 7:49 pm
Location: Nowa Wies Tworoska, Poland
Contact:

Post by Rookie One.pl »

Thanks, Lizard. :) I have just skimmed your solution as I'm in a bit of a hurry right now, so I'll read it carefully later on, OK? ;) Don't be sorry for the language, this code snippet could be ported almost directly to C++. ;)

Yeah, JV, I know that function is different, that's why I asked for another way. ;) I just wasn't sure of what exactly does this Quake function do. However, after reading the Wikipedia article you posted the link to I think I figured it out right. ;) The thing is, the point around which it will be rotated is ( 0 0 0 ), right? If so, would this code be valid for what I want to do (rotate point by angles around centre)?

Code: Select all

void RotatePointAroundVectorByAngles(vec3_t dst, vec3_t point, vec3_t angles, vec3_t centre) {
	vec3_t axis;
	// absolute -> relative
	if (centre)
		VectorSubtract(point, centre, dst);
	// pitch
	axis[0] = 1.f;
	axis[1] = axis[2] = 0.f;
	RotatePointAroundVector(dst, axis, dst, angles[0]);
	// yaw
	axis[0] = axis[1] = 0.f;
	axis[2] = 1.f;
	RotatePointAroundVector(dst, axis, dst, angles[1]);
	// roll
	axis[0] = axis[2] = 0.f;
	axis[1] = 1.f;
	RotatePointAroundVector(dst, axis, dst, angles[2]);
	// relative -> absolute
	if (centre)
		VectorAdd(dst, centre, dst);
}
VectorSubtract(a, b, c) is c = a - b, VectorAdd(a, b, c) is c = a + b. The if (centre) lines are there in case I'll ever want to rotate around ( 0 0 0 ) I can just send NULL. ;)
Admin
Image
Image
Honour guide me.

here's my stuff - inequation.org | here's where I work - thefarm51.com
jv_map
Site Admin
Posts: 6521
Joined: Tue Sep 03, 2002 2:53 pm
Location: The Netherlands
Contact:

Post by jv_map »

Yah that looks great :) .. getting the hang of it I can see 8-) .. the 'centering' is implemented correctly. :D

The only thing is, if you want them to be true pitch, yaw and roll angles, you have to rotate yaw first and then pitch (this is what moh does too). What you have now will work too, but it gives a different result... e.g. in your case if you pitch down say 45 degrees first and then yaw 45 degrees you'll end up in a 'rolled' position (the y-axis is not horizontal). If you do yaw first and then pitch the y-axis will be horizontal. Always tricky stuff with angles :wink:
Image
Rookie One.pl
Site Admin
Posts: 2752
Joined: Fri Jan 31, 2003 7:49 pm
Location: Nowa Wies Tworoska, Poland
Contact:

Post by Rookie One.pl »

Ah, OK, good to know. :) Thanks! :)
Admin
Image
Image
Honour guide me.

here's my stuff - inequation.org | here's where I work - thefarm51.com
lizardkid
Windows Zealot
Posts: 3672
Joined: Fri Mar 19, 2004 7:16 pm
Location: Helena MT

Post by lizardkid »

looks like i posted the wrong overloaded set... it's what i get for only taking half of a class' code i suppose. Fixed now.
Moderator

۞
Abyssus pro sapientia
Olympus pro Ignarus
۞

AND STUFF™ © 2006
Rookie One.pl
Site Admin
Posts: 2752
Joined: Fri Jan 31, 2003 7:49 pm
Location: Nowa Wies Tworoska, Poland
Contact:

Post by Rookie One.pl »

Your implementation seems to be much more efficient than my half-assed solution, I'll use it when I get to the point of code optimization. ;)
Admin
Image
Image
Honour guide me.

here's my stuff - inequation.org | here's where I work - thefarm51.com
Post Reply