• Advertisement
Sign in to follow this  

Rotating Vertices with a Rotation Matrix

This topic is 4703 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone, I'm new to 3d graphics, and am currently trying to figure out how to define 3d objects (in this case a cube) with a vertex array, and then rotate it on all three axes with a rotation matrix. The problem is, instead of rotating the cube, it is warping it, with opposing pairs of corners rotating about the center, on which ever axis is specified. Can anyone point out what I'm doing wrong? Declaration of the vector arrays and matrix:
[source lang ="C"]
const Vector4 v4Vertices[] = {{-1,-1,-1,1},{1,-1,-1,1},
{1,1,-1,1}, {-1,1,-1,1},{-1,-1,1,1},{1,-1,1,1},
{1,1,1,1}, {-1,1,1,1}};

GLint allIndices[] = {4, 5, 6, 7, 1, 2, 6, 5,
			0, 1, 5, 4, 0, 3, 2, 1,
			0, 4, 7, 3, 2, 3, 7, 6};

Vector4 v4DrawVertices[8];

Matrix4 mRot;

Here I am trying to generate the rotation matrix, and then rotate the original vertex array into a temporary one for drawing
[source lang ="C"]

	mRot = getRotationMatrix(xRotate, yRotate, zRotate);

	int i;
	for (i = 0; i<8; i++)
	{
		v4DrawVertices = mult(v4Vertices, mRot);
	}

	glVertexPointer(3, GL_FLOAT, sizeof(Vector4), &v4DrawVertices[0].e[0]);
	glColorPointer(3, GL_FLOAT, 0, colors);


	glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, allIndices);


Here are the methods I wrote for finding the rotation matrix, and rotating the vertices (as vectors) with the matrix

__inline Matrix4 getRotationMatrix (float xRot, float yRot, float zRot)
{
	float A,B,C,D,E,F;
	float pi = 3.14159265358979323846;
	Matrix4 mOut;

	A = cos(xRot*pi/180);
	B = sin(xRot*pi/180);

	C = cos(yRot*pi/180);
	D = sin(yRot*pi/180);

	E = cos(zRot*pi/180);
	F = sin(zRot*pi/180);

	mOut.e[0] = C*E;
	mOut.e[1] = -C*F;
	mOut.e[2] = D;
	mOut.e[4] = B*D*E + A*F;
	mOut.e[5] = -B*D*F + A*E;
	mOut.e[6] = -B*C;
	mOut.e[8] = -A*D*E + B*F;
	mOut.e[9] = A*D*F + B*E;
	mOut.e[10] = A*C;

	mOut.e[3] = mOut.e[7] = mOut.e[11] = mOut.e[12] = mOut.e[13] = mOut.e[14] = 0;

	mOut.e[15] = 1;

	return mOut;

}


__inline Vector4 mult (const Vector4& v, const Matrix4& m)
{
	Vector4 vOut;
	

	vOut.e[0] = v.e[0] * m.e[0] + v.e[0]* m.e[4] + v.e[0] * m.e[8] + v.e[0] * m.e[12];
	vOut.e[1] = v.e[1] * m.e[1] + v.e[1]* m.e[5] + v.e[1] * m.e[9] + v.e[1] * m.e[13];
	vOut.e[2] = v.e[2] * m.e[2] + v.e[2]* m.e[6] + v.e[2] * m.e[10] + v.e[2] * m.e[14];
	vOut.e[3] = v.e[3] * m.e[3] + v.e[3]* m.e[7] + v.e[3] * m.e[11] + v.e[4] * m.e[15];

	return vOut;
}



Share this post


Link to post
Share on other sites
Advertisement
Nevermind, I noticed that I absolutely butchered the vector*matrix multiplication code.

Now that that's (apparently) fixed, I'm noticing that while rotation on the y and z axes work as I expected, rotating properly on the cubes own y and z axes, while rotation on the x axis seems to rotate on the world's x axis no matter which way the cube is rotated.


Can anyone tell me why, and how I can make it not do that?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Now that that's (apparently) fixed, I'm noticing that while rotation on the y and z axes work as I expected, rotating properly on the cubes own y and z axes, while rotation on the x axis seems to rotate on the world's x axis no matter which way the cube is rotated.

Can anyone tell me why, and how I can make it not do that?
My first question is, are you *sure* the cube is always yawing on its own y axis? As an exercise, try rotating randomly around all three axes for a while until the cube is at some arbitrary orientation. Then try applying a y rotation. I'm pretty sure you'll find that the axis of rotation is neither the local nor world y axis.

What I would expect given your matrix setup is that z rotation would always (appear to) occur about the local z axis, x rotation would always occur about the world x axis (as you observed), and y rotation would occur about an axis which is neither consistently a local or world axis. So you might do some more experiments to see if that is in fact what is happening.

In any case, if you want rotations to always occur about the cube's local axes, that can easily be accomplished with incremental rotations. If you'd like more details on that I'll be happy to provide them.

Share this post


Link to post
Share on other sites
You're completely right about the behaviour of rotations - the y rotation is fine for a little while, but if I rotate too much on both other axes, things get weird.

I've seen Incremental Rotation mentioned numerous times, but I can't seem to find any actual information on how to implement it. If you or anyone else knows of a good place to look, it would be greatly appreciated.

Share this post


Link to post
Share on other sites
Quote:
I've seen Incremental Rotation mentioned numerous times, but I can't seem to find any actual information on how to implement it. If you or anyone else knows of a good place to look, it would be greatly appreciated.
Actually in my experience the info isn't that easy to find. You can find the formulation for constructing a matrix from Euler angles on the web 1000 times, but clear explanations of incremental rotation are rarer.

So anyway, here's some info to get you started.

With the Euler angle construction you're using, the matrix is constructed from scratch each time. With incremental rotation you instead maintain a matrix from frame to frame that represents the current orientation of your object. You update the matrix each frame by applying (usually fairly small) rotations to it.

The axes you want to rotate about are generally not the world axes, but the local axes of the object. If you've played Descent, you know what I'm talking about. Yaw is always relative to the ship's up axis - it has nothing to do with the world up axis.

To do this you need to be able to construct an axis-angle matrix. Here's a bit of code to do that:


template <class T> void Matrix3<T>::FromAxisAngle(T ax, T ay, T az, T angle)
{
T s, c;
Math<T>::SinCos(angle, s, c);
T omc = (T)1.0 - c;

T xxomc = ax * ax * omc;
T yyomc = ay * ay * omc;
T zzomc = az * az * omc;

T xyomc = ax * ay * omc;
T xzomc = ax * az * omc;
T yzomc = ay * az * omc;

T xs = ax * s;
T ys = ay * s;
T zs = az * s;

Set(xxomc + c, xyomc - zs, xzomc + ys,
xyomc + zs, yyomc + c, yzomc - xs,
xzomc - ys, yzomc + xs, zzomc + c);
}





Note that the functions I'm posting here assume a certain set of conventions, specifically column vectors and matching coordinate system and rotation handedness. If your conventions are different you can just transpose everything.

So now you can create a rotation matrix from an arbitrary axis and angle. The axes that you will want to rotate about are the local axes of your object, which are the columns (or rows) of the orientation matrix. Let's say you have a matrix function GetYAxis() that returns a vector constructed from the 2nd column of your matrix. Then, you might apply yaw to your object like this:

Matrix3 yaw;
yaw.FromAxisAngle(m_orientation.GetYAxis(), m_yaw);
m_orientation = yaw * m_orientation;

I'll also mention here that rotating a matrix about one of its own axes can actually be done much more cheaply than the general case. I won't include the function here because this post is already pretty long, but if you're interested I'd be glad to post it.

Lastly, with incremental rotation you will find that your matrix degrades over time due to floating-point error. So you will want to re-orthogonalize it occasionally, which is kind of expensive, but for just a few objects you could do it every frame and not even notice. Here's some code to re-orthogonalize a matrix:


template <class T> void Matrix3<T>::Orthogonalize(unsigned int u)
{
unsigned int v = Math<T>::Next(u, 3); // (u + 1) % 3
unsigned int w = Math<T>::Next(v, 3); // (v + 1) % 3

NormalizeAxis(u);
m_[0][v] = m_[1][w] * m_[2] - m_[2][w] * m_[1];
m_[1][v] = m_[2][w] * m_[0] - m_[0][w] * m_[2];
m_[2][v] = m_[0][w] * m_[1] - m_[1][w] * m_[0];
NormalizeAxis(v);
m_[0][w] = m_[1] * m_[2][v] - m_[2] * m_[1][v];
m_[1][w] = m_[2] * m_[0][v] - m_[0] * m_[2][v];
m_[2][w] = m_[0] * m_[1][v] - m_[1] * m_[0][v];
NormalizeAxis(w);
}

template <class T> inline void Matrix3<T>::NormalizeAxis(unsigned int i)
{
T l = Math<T>::Sqrt(m_[0] * m_[0] + m_[1] * m_[1] + m_[2] * m_[2]);
T invl = (T)1.0 / l;
m_[0] *= invl;
m_[1] *= invl;
m_[2] *= invl;
}




So those are the basics. If anything's not clear, or if you need any further information, please let me know.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement