I wanted to use quaternions to have rotations at a specific axis regardless of the position of the cube but when I rotate 90 degrees along x axis then try to rotate along y axis instead of rotating at y it rotates at z axis any idea how to solve this? my code is the following:
quaternion permquat;
permquat.x = 0;
permquat.y = 0;
permquat.z = 0;
permquat.w = 1;
quaternion permquat2;
permquat2.x = 0;
permquat2.y = 0;
permquat2.z = 0;
permquat2.w = 1;
quaternion local_rotation;
local_rotation.w = cosf( beta/(2.0*180.0));
local_rotation.x = 1.0 * sinf( beta/(2.0*180.0) );
local_rotation.y = 0.0 * sinf( beta/(2.0*180.0) );
local_rotation.z = 0.0 * sinf( beta/(2.0*180.0) );
quaternion local_rotation2;
local_rotation2.w = cosf( gamma/(2.0*180.0));
local_rotation2.x = 0.0 * sinf( gamma/(2.0*180.0));
local_rotation2.y = 1.0 * sinf( gamma/(2.0*180.0));
local_rotation2.z = 0.0 * sinf( gamma/(2.0*180.0));
permquat = mult(local_rotation, permquat);
normalize(permquat);
permquat2 = mult(local_rotation2, permquat2);
normalize(permquat);
matTransl3D = matrix(permquat);
glMultMatrixf(*matTransl3D);
matTransl3D = matrix(permquat2);
glMultMatrixf(*matTransl3D);
glTranslatef(-9, -9, -9); // bottom left
drawcube();
glPopMatrix();
Beta and Gamma are incremented by 2 for each key press.
Related
The following code will create a new semicircular using openGL:
glPointSize(2);
glBegin(GL_POINTS);
for (float i = p; i <= (2 * p); i += 0.001) {
x = 50.0 * cos(i) + 20;
y = 50.0 * sin(i) + 20;
glVertex2f(x, y);
}
glEnd();
Now I want to know how to change this code and create a quarter circle using this format?
Also, is this possible to rotate the shape using this format and without of using GLrotateEF?
Here i is the angle in radians. The loop goes from π to 2π—this is a semicircle (but the second half of it - a bit ill-defined).
To turn it into a quarter circle loop from 0 to π/2. To rotate the circle by x degrees, convert it to radians and add to the angle.
Alternatively you can draw a portion of a circle by simply defining where it should start, and where it should stop, in angles:
double start_angle = 30;
double stop_angle = 30 + 180;
for (double a = start_angle; a <= stop_angle; a += 0.001) {
double a_rad = a / 180.0 * p;
x = 50.0 * cos(a_rad) + 20;
y = 50.0 * sin(a_rad) + 20;
glVertex2f(x, y);
}
I get different results when scaling objects.
The objects have four different glm::vec3 values
1) Position , Rotation , Scaling , Center Point
This is the Transformation Matrix of the object
TransformationMatrix = PositionMatrix() * RotationMatrix() * ScalingMatrix();
The rotation and scaling Matrix looks like this.
glm::vec3 pivotVector(pivotx, pivoty, pivotz);
glm::mat4 TransPivot = glm::translate(glm::mat4x4(1.0f), pivotVector);
glm::mat4 TransPivotInverse = glm::translate(glm::mat4x4(1.0f), -pivotVector);
glm::mat4 TransformationScale = glm::scale(glm::mat4(1.0), glm::vec3(scax, scay, scaz));
return TransPivot * TransformationScale * TransPivotInverse;
In the first case.
I move the rectangle object to 200 units in x.
Than i scale the group which is at position x = 0.0
so the final matrix for the rectangle object is
finalMatrix = rectangleTransformationMatrix * groupTransformationMatrix
The result i what i expected.The rectangle scales and moves towards the center of the screen.
Now if i do the same thing with three containers.
Here i move the group container to 200 and scale the Top container which is at position 0.0
finalMatrix = rectangleTransformationMatrix * groupTransformationMatrix * TopTransformationMatrix
the rectangle scales at its own position as if the center point of the screen has also moved 200 units.
If i add -200 units to the pivot point x of the top container than i get the result what i expected.
where rectangle moves towards the center of the screen and scales.
If someone can please explain me why i need to add -200 units to the center point of the Top container.Whereas in the first case i did not need to add any value to the pivot point of the scaling container.
when both the operations are identical in nature.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
First case
Rectangle - > position( x = 200 , y = 0, z = 0) , scaling( 1.0 , 1.0 , 1.0 ) , Rotation( 0.0 , 0.0 , 0.0 )
glm::mat4 PositionMatrix = glm::position( // fill the values);
glm::mat4 ScalingMatrix = glm::scaling( // fill the values);
glm::mat4 RotationMatrix = glm::rotate( // fill the values);
RectangleMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
the matrix for group
froup - > position( x = 0.0 , y = 0, z = 0) , scaling( 0.5 , 1.0 , 1.0 ) , Rotation( 0.0 , 0.0 , 0.0 )
groupMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
final result
finalMatrix = RectangleMatrix * groupMatrix
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Second case
Rectangle - > position( x = 0 , y = 0, z = 0) , scaling( 1.0 , 1.0 , 1.0 ) , Rotation( 0.0 , 0.0 , 0.0 )
glm::mat4 PositionMatrix = glm::position( // fill the values);
glm::mat4 ScalingMatrix = glm::scaling( // fill the values);
glm::mat4 RotationMatrix = glm::rotate( // fill the values);
RectangleMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
the matrix for group
group - > position( x = 200.0 , y = 0, z = 0) , scaling( 1.0 , 1.0 , 1.0 ) , Rotation( 0.0 , 0.0 , 0.0 )
groupMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
the matrix for Top
Top - > position( x = 0.0 , y = 0, z = 0) , scaling( 0.5 , 1.0 , 1.0 ) , Rotation( 0.0 , 0.0 , 0.0 )
TopMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
final result
finalMatrix = RectangleMatrix * groupMatrix * TopMatrix
Matrix operations are not Commutative. scale * translate is not the same as translate * scale
If you have a translation of 200 and and a scale of 0.2, then
translate(200) * scale(0.2)
gives object scaled by 0.2 and translated by 200. But
scale(0.2) * translate(200)
gives object scaled by 0.2 and translated by 40 (0.2*200).
If you have 2 matrices:
groupMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
TopMatrix = PositionMatrix() * RotationMtrix() * ScalingMatrix();
Then groupMatrix * TopMatrix is the same as
groupPositionMatrix * groupRotationMtrix * groupScalingMatrix * topPositionMatrix * topRotationMtrix * topScalingMatrix
The result is different if the scale is encoded in groupScalingMatrix or topScalingMatrix respectively the translation is encoded in groupPositionMatrix or topPositionMatrix.
I cannot understand the math behind this problem, I am trying to create an FPS camera where I can look freely with my mouse input.
I am trying to rotate and position my lookat point with 180 degrees of freedom. I understand the easier solution is to glRotate the world to fit my perspective, but I do not want this approach. I am fairly unfamiliar with the trigonometry involved here and cannot figure out how to solve this problem the way I want to...
here is my attempt to do this so far...
code to get mouse coordinates relative to the center of the window, then process it in my camera object
#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
f speed = 0.2f;
f oldX = mouseX; f oldY = mouseY;
mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians
f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame
if (mouseX != 0 || mouseY != 0) {
mainCamera->Rotate(diffX, diffY);
}
Code to rotate the camera
void Camera::Rotate(f angleX, f angleY) {
Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};
Camera::refrence is our lookat point, processing the lookat point is handled as follows
void Camera::LookAt(void) {
gluLookAt(
Camera::position.x, Camera::position.y, Camera::position.z,
Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
);
};
The camera is defined by a position point (position) a target point (refrence) and a up-vector upVector. If you want to change the orientation of the camera, then you've to rotate the direction vector from the position (position) to the target (refrence) rather then the target point by a Rotation matrix.
Note, since the 2 angles are angles which should change an already rotated view, you've to use a rotation matrix, to rotate the vectors which point in an arbitrary direction.
Write a function which set 3x3 rotation matrix around an arbitrary axis:
void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
float c = cos(angle_radians);
float s = sin(angle_radians);
m[0] = x*x*(1.0f-c)+c; m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c; m[5] = y*z*(1.0f-c)-x*s;
m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}
Write a function which rotates a 3 dimensional vector by the matrix:
Vector3D Rotate(float m[], const Vector3D &v)
{
Vector3D rv;
rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
return rv;
}
Calculate the vector form the position to the target:
Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);
Rotate all the vectors around the z axis of the world by angleX:
float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));
los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);
Rotate all the vectors around the current y axis of the view by angleY:
float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));
los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);
Calculate the new target point:
refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);
U_Cam_X_angle is left right rotation.. U_Cam_Y_angle is up down rotation.
view_radius is the view distance (zoom) to U_look_point_x, U_look_point_y and U_look_point_z.
This is ALWAYS a negative number! This is because you are always looking in positive direction. Deeper in the screen is more positive.
This is all in radians.
The last three.. eyeX, eyeY and eyeZ is where the camera is in 3D space.
This code is in VB.net. Find a converter online for VB to C++ or do it manually.
Public Sub set_eyes()
Dim sin_x, sin_y, cos_x, cos_y As Single
sin_x = Sin(U_Cam_X_angle + angle_offset)
cos_x = Cos(U_Cam_X_angle + angle_offset)
cos_y = Cos(U_Cam_Y_angle)
sin_y = Sin(U_Cam_Y_angle)
cam_y = Sin(U_Cam_Y_angle) * view_radius
cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius
Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)
eyeX = cam_x + U_look_point_x
eyeY = cam_y + U_look_point_y
eyeZ = cam_z + U_look_point_z
End Sub
I am trying to display a 360 panorama using an IMU for head tracking.
Yaw works correctly but the roll and pitch are reverse. I also notice that the pitch contains some roll (and maybe vice-versa).
I am receiving (W, X, Y, Z) coordinate from the IMU that I am storing in an array as X, Y, Z, W.
The next step is converting the quaternion to a rotation matrix. I have looked at many examples, and can't seem to find anything wrong with the following code:
static GLfloat rotation[16];
// Quaternion (x, y, z, w)
static void quaternionToRotation(float* quaternion)
{
// Normalize quaternion
float magnitude = sqrt(quaternion[0] * quaternion[0] +
quaternion[1] * quaternion[1] +
quaternion[2] * quaternion[2] +
quaternion[3] * quaternion[3]);
for (int i = 0; i < 4; ++i)
{
quaternion[i] /= magnitude;
}
double xx = quaternion[0] * quaternion[0], xy = quaternion[0] * quaternion[1],
xz = quaternion[0] * quaternion[2], xw = quaternion[0] * quaternion[3];
double yy = quaternion[1] * quaternion[1], yz = quaternion[1] * quaternion[2],
yw = quaternion[1] * quaternion[3];
double zz = quaternion[2] * quaternion[2], zw = quaternion[2] * quaternion[3];
// Column major order
rotation[0] = 1.0f - 2.0f * (yy + zz);
rotation[1] = 2.0f * (xy - zw);
rotation[2] = 2.0f * (xz + yw);
rotation[3] = 0;
rotation[4] = 2.0f * (xy + zw);
rotation[5] = 1.0f - 2.0f * (xx + zz);
rotation[6] = 2.0f * (yz - xw);
rotation[7] = 0;
rotation[8] = 2.0f * (xz - yw);
rotation[9] = 2.0f * (yz + xw);
rotation[10] = 1.0f - 2.0f * (xx + yy);
rotation[11] = 0;
rotation[12] = 0;
rotation[13] = 0;
rotation[14] = 0;
rotation[15] = 1;
}
The rotation matrix is then used in the draw call as such:
static void draw()
{
// Get IMU quaternion
float* quaternion = tracker.getTrackingData();
if (quaternion != NULL)
{
quaternionToRotation(quaternion);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
// TODO: Multiply initialRotation quaternion with IMU quaternion
glMultMatrixf(initialRotation); // Initial rotation to point forward
glMultMatrixf(rotation); // Rotation based on IMU
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
gluSphere(quad, 0.1, 50, 50);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
I tried to set all but one fields in the quaternion to 0, and I notice that they all work individually, except roll and pitch is swapped around. I tried swapping X and Y but this does not seem to help.
Any help would be really appreciated. Please let me know as well if you have any steps that can let me debug my issue. Thanks!
I have the following code to draw an arbitrary arc:
void CenteredArc::drawPolygonArc(float radius, float thickness, float startAngle, float arcAngle) {
float num_segments = 360.0;
float radiusOuter = radius + thickness / 2;
float radiusInner = radius - thickness / 2;
float theta = arcAngle / num_segments;
float tangetial_factor = tanf(theta);//calculate the tangential factor
float radial_factor = cosf(theta);//calculate the radial factor
float xxOuter = radiusOuter * cosf(startAngle);
float yyOuter = radiusOuter * sinf(startAngle);
float xxInner = radiusInner * cosf(startAngle);
float yyInner = radiusInner * sinf(startAngle);
float prevXXOuter = -1;
float prevYYOuter = -1;
float prevXXInner = -1;
float prevYYInner = -1;
glPolygonMode(GL_FRONT, GL_FILL);
for(int ii = 0; ii < num_segments; ii++)
{
if (prevXXOuter != -1) {
glBegin(GL_POLYGON);
glVertex2f(prevXXOuter, prevYYOuter);
glVertex2f(xxOuter, yyOuter);
glVertex2f(xxInner, yyInner);
glVertex2f(prevXXInner, prevYYInner);
glEnd();
}
//calculate the tangential vector
//remember, the radial vector is (x, y)
//to get the tangential vector we flip those coordinates and negate one of them
float txOuter = -yyOuter;
float tyOuter = xxOuter;
float txInner = -yyInner;
float tyInner = xxInner;
//add the tangential vector
prevXXOuter = xxOuter;
prevYYOuter = yyOuter;
prevXXInner = xxInner;
prevYYInner = yyInner;
xxOuter += txOuter * tangetial_factor;
yyOuter += tyOuter * tangetial_factor;
xxInner += txInner * tangetial_factor;
yyInner += tyInner * tangetial_factor;
//correct using the radial factor
xxOuter *= radial_factor;
yyOuter *= radial_factor;
xxInner *= radial_factor;
yyInner *= radial_factor;
}
}
However, I would like for the arc to start off with the specified thickness on one end and gradually decrease to a thickness of zero on the other end. Any suggestions?
Edit: I am not using GL_LINE_STRIP because I am trying to avoid having overlapping lines and gaps like so:
I would use a line strip with decreasing glLineWidth.
This is my implementation, it doesn't gradially reduce the lineWidth but it could be modified to do so. Sorry for the extra stuff, it's from my game engine.
for(int i=0;i<arcs().size();i++)
{
Entities::Arc temp = arcs().at(i);
glLineWidth(temp.LW.value); // change LWidth
glColor3f( temp.CL.R, temp.CL.G, temp.CL.B );
// theta is now calculated from the arc angle instead, the
// - 1 part comes from the fact that the arc is open
float theta = temp.A.value*DEG2RAD / float(WW_SPLINE_ACCURACY - 1);
float tan = tanf(theta);
float cos = cosf(theta);
// we are now at the starting angle
double x = temp.R.value * cosf(temp.A.value*DEG2RAD);
double y = temp.R.value * sinf(temp.A.value*DEG2RAD);
// since the arc is not a closed curve, this is a strip now
glBegin(GL_LINE_STRIP);
for(int ii = 0; ii < WW_SPLINE_ACCURACY; ii++)
{
glVertex2d(x + temp.C.X, y + temp.C.Y);
double tx = -y;
double ty = x;
x += tx * tan;
y += ty * tan;
x *= cos;
y *= cos; //y = ( y + (ty*tan) )*cos;
}
glEnd();
glLineWidth(WW_DEFAULT_LWIDTH); // reset LWidth
}
I also used these values
#define WW_SPLINE_ACCURACY 72 // 72 for extra smooth arcs/circles, 32 minimum
#define WW_BEZIER_ACCURACY 20
/* Math stuff */
#define DEG2RAD 3.14159/180
#define PI 3.1415926535897932384626433832795;
...
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glEnable (GL_LINE_SMOOTH);
glEnable (GL_BLEND);
//glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glEnable(GL_POLYGON_SMOOTH);
glClearColor(0.188f, 0.169f, 0.329f, 1.0f); //#302b54
I'm not allowed to release the full source since I wrote it for a company but sharing a part or two wont hurt anybody :D