Hi everyone; I have this project for school where i need to create a software that manipulates 3D objects , i'm using OpenGL 2.1 along side with SDL 1.2.
I'm now trying to implement some kind of rotation on the objects , this way : The user selects the needed object , once it's done , he can access the rotation mode by hitting "R" , then he hits X ,Y or Z to select the desired rotation axis; at first i went with something like this :
glrotated(angles.x,1,0,0);
glrotated(angles.y,0,1,0);
glrotated(angles.z,0,0,1);
//Drawing my object
but of course it didn't work; the first rotations worked ok , but then it started to turn around an invisible axis every time ( i think it is the axis of the universe , the global one). Let me show you the video i have taken , to illustrate what i'm saying :
after looking on the net for a while , i found that quaternion could solve my problem ... Here's what my code looks like now :
The method that displays my teapot to the screen :
void Teapot::PrintObj()
{
glLoadName(_NameStack);
glPushMatrix();
Translated(axeX,axeY,axeZ);
RotatedX(angles.x);
RotatedY(angles.y);
RotatedZ(angles.z);
glScaled(ObjSize.x,ObjSize.y,ObjSize.z);
glColor3ub(_Color.red,_Color.green,_Color.blue);
glutSolidTeapot(2);
if(_Selected){WiredTeapot();Guizmo();}
glPopMatrix();
};
the angles.x , angles.y and angles.z are stored within the class ; they are modified by an other method this way :
void Scene::ProjRotation(SDL_MouseMotionEvent &event,int X,int Y,int Z)
{
int a;
int b;
int c;
for(_compt=_OjebctScene.begin();_compt!=_OjebctScene.end();_compt++)
{
if ((*_compt)->IsSelected())
{
if(X==1 && Y==0 && Z==0)
{
a=event.y % 360;
if(a % 5 == 0)
{
(*_compt)->setAlpha(a);
}
}
else if(Y==1 && X==0 && Z==0)
{
b=event.y % 360;
if(b % 5 == 0)
{
(*_compt)->setBeta(b);
}
}
else if(Z==1 && Y==0 && X==0)
{
c=event.y % 360;
if(c % 5 == 0)
{
(*_compt)->setGamma(c);
}
}
}
}
}
the ObjScene vector contains pointers to all the objects on the scene , i first try to find the selected item ; then with an event on the mouse , i send the input to the angles.x , angles.y or angles.z;
all of this leads us now to the RotatedX() , RotatedY() and RotatedZ() methods , that are charged with handling the rotation ; here's the code of RotatedX() to show you what i have done :
void Object3D::RotatedX(double angle)
{
rotZ=vector_normalize(rotZ);//I normalize the 3 vectors : rotX , rotY and rotZ are the 3 axis , stored in the class too
rotX=vector_normalize(rotX);
rotY=vector_normalize(rotY);
rotX.x=1;
rotX.y=0;
rotX.z=0;
quaternion Q = make_rotation_quaternion_from_axis_and_angle(rotX,angle);// I create a quaternion based on the axis and angle
quaternion_fill_opengl_rotation_matrix(Q,mat);// i create the equivalent matrix to the quaternion
glm::mat4 RotationMatrix = glm::make_mat4(mat);
glm::vec4 vecRoty = glm::vec4(rotY.x,rotY.y,rotY.z,0)*RotationMatrix ;// i rotate the rotY vector , so next time the rotation won't be done around the (0,1,0) vector , but around the new position of Y;
rotY.x = vecRoty[0];
rotY.y = vecRoty[1];
rotY.z = vecRoty[2];// I update the new value of rotY so it is stored;
rotY=vector_normalize(rotY);// i think this is useless , but just to be cautious
glm::vec4 vecRotz = glm::vec4(rotZ.x,rotZ.y,rotZ.z,0)*RotationMatrix; // same thing with the Z axis , i rotate it to get a rotation around the new position of Z , not the (0,0,1) axis;
rotZ.x = vecRotz[0];
rotZ.y = vecRotz[1];
rotZ.z = vecRotz[2];// I store the new value in rotZ;
rotZ=vector_normalize(rotZ);//same , normalizing rotZ;
glMultMatrixf(mat); // then i apply the rotation to the scene to update the displaying of the teapot
}
i hope all of this is clear for you , i'm just getting started with openGL and had till yesterday no idea about quaternions , i don't know if the algorithm behind my code is wrong , but there's obviously something i am missing.