C++ Opengl Rotations and Calculations

c++ OpenGL rotations and calculations

if you use glRotatef from OpenGL do not forget that rotation angle is in Degrees not in radians !!!

for the transformation and confusion part user1118321 is absolutely right.

I thing for your purposes you need only to apply GL_MODELVIEW_MATRIX

if you need coordinates in model space you must multiply inverse modelview matrix by global coordinates vector.

If you need coordinates in global space than you must multiply modelview matrix by model coordinates vector.

coordinates send by vertex are in model space
you can obtain actual modelview matrix with gl functions glGetFlotav/glGetDoublev

double m[16];
glGetDoublev(GL_MODELVIEW_MATRIX,m);

inverse matrix and matrix x vector multiplication is not present in OpenGL so you must code it yourself or use some lib. Do not forget that matrices in OpenGL are column oriented not row oriented and coordinate vectors are homogenuous so x,y,z,w where w=1 for your purposes. Here is code I use for my OpenGL sub-calculations, all vectors are double[4] and matrices are double[16]

void  matrix_mul_vector(double *c,double *a,double *b)
{
double q[3];
q[0]=(a[ 0]*b[0])+(a[ 4]*b[1])+(a[ 8]*b[2])+(a[12]);
q[1]=(a[ 1]*b[0])+(a[ 5]*b[1])+(a[ 9]*b[2])+(a[13]);
q[2]=(a[ 2]*b[0])+(a[ 6]*b[1])+(a[10]*b[2])+(a[14]);
for(int i=0;i<3;i++) c[i]=q[i];
}
void matrix_subdet (double *c,double *a)
{
double q[16];
int i,j;
for (i=0;i<4;i++)
for (j=0;j<4;j++)
q[j+(i<<2)]=matrix_subdet(a,i,j);
for (i=0;i<16;i++) c[i]=q[i];
}
double matrix_subdet ( double *a,int r,int s)
{
double c,q[9];
int i,j,k;
k=0; // q = sub matrix
for (j=0;j<4;j++)
if (j!=s)
for (i=0;i<4;i++)
if (i!=r)
{
q[k]=a[i+(j<<2)];
k++;
}
c=0;
c+=q[0]*q[4]*q[8];
c+=q[1]*q[5]*q[6];
c+=q[2]*q[3]*q[7];
c-=q[0]*q[5]*q[7];
c-=q[1]*q[3]*q[8];
c-=q[2]*q[4]*q[6];
if (int((r+s)&1)) c=-c; // add signum
return c;
}
double matrix_det ( double *a)
{
double c=0;
c+=a[ 0]*matrix_subdet(a,0,0);
c+=a[ 4]*matrix_subdet(a,0,1);
c+=a[ 8]*matrix_subdet(a,0,2);
c+=a[12]*matrix_subdet(a,0,3);
return c;
}
double matrix_det ( double *a,double *b)
{
double c=0;
c+=a[ 0]*b[ 0];
c+=a[ 4]*b[ 1];
c+=a[ 8]*b[ 2];
c+=a[12]*b[ 3];
return c;
}
void matrix_inv (double *c,double *a)
{
double d[16],D;
matrix_subdet(d,a);
D=matrix_det(a,d);
if (D) D=1.0/D;
for (int i=0;i<16;i++) c[i]=d[i]*D;
}

For more info see:

  • Understanding 4x4 homogenous transform matrices

OpenGL translation and rotation object

As you probably know, the basic parametric equation for a circle is, with rad being the radius and phi the angle in the range [0, 2*PI]:

x = rad * cos(phi)
y = rad * sin(phi)

As phi sweeps from 0 to 2 * PI, this starts on the right (positive x-axis), and moves counter-clockwise. Which means that the initial movement is upwards, in the direction of the positive y-axis.

The exact calculation you need depends on whether you want the animation to go clockwise or counter-clockwise, and where it starts. Since it's just a slight variation, I'll cover them in order.

For the counter-clockwise orientation, we can generalize the start point by simply adding a start angle. We'll also express the angle as a function of time t:

x = rad * cos(phiStart + speed * t)
y = rad * sin(phiStart + speed * t)

This gives you the components of the translation. For the rotation of the fish, since its base position is pointing right, but the initial movement of the circular motion is pointing up, we need to rotate it by 90 degrees before applying the circular motion. Which means that 0.5 * PI (90 degrees) are added to the angle used for the translation:

rotAng = 0.5 * PI + phiStart + speed * t

Without being familiar with the matrix library you are using, I hope that it uses the standard order for matrix multiplications. So expressed in code, the above would looks something like:

float phiStart = 0.0f;  // start at right, set different start angle if desired
float phi = phiStart + elapsedTime;
mesh->objectModelMatrix =
glm::translate(glm::mat4(1.0f),
glm::vec3(5.0f * cos(phi), initialY, 5.0f * sin(phi)));
mesh->objectModelMatrix =
glm::rotate(mesh->objectModelMatrix,
0.5f * M_PI + phi, glm::vec3(0.0f, 0.0f, 1.0f));

To move clockwise instead, we can simply invert the sign of the angle. The only other difference is that since the initial movement is downwards now, the initial rotation of the fish is also 90 degrees clockwise, which corresponds to -0.5 * PI:

float phiStart = 0.5f * M_PI;  // start at top, set different start angle if desired
float phi = phiStart - elapsedTime;
mesh->objectModelMatrix =
glm::translate(glm::mat4(1.0f),
glm::vec3(5.0f * cos(phi), initialY, 5.0f * sin(phi)));
mesh->objectModelMatrix =
glm::rotate(mesh->objectModelMatrix,
-0.5f * M_PI + phi, glm::vec3(0.0f, 0.0f, 1.0f));

I couldn't find clear documentation for the matrix library you are using. It's possible that the second argument to glm::rotate() is the angle in degrees instead of radians. If that's true,
those calls for the two cases become:

    glm::rotate(mesh->objectModelMatrix,
90.0f + phi * (180.0f / M_PI), glm::vec3(0.0f, 0.0f, 1.0f));

glm::rotate(mesh->objectModelMatrix,
-90.0f + phi * (180.0f / M_PI), glm::vec3(0.0f, 0.0f, 1.0f));

rotation calculation in GLM

What glm::rotate actually does is to set up a rotation matrix and multiply the input matrix by the roation. It computes m*r in the meaning of GLSL Vector and Matrix Operations.

It operates in the same way as it is discussed for glm::translate in one of your previous questions: How does GLM handle translation.

The input parameters angle (the rotation angle) and v (the rotation axis), define a 3x3 rotation matrix as described in the wikipedia article Rotation matrix from axis and angle:

(the mathematical explanation to this formula would be a question for Mathematics)

c = cos(angle); s = sin(angle)
x = v.x; y = v.y; z = v.z

| x*x*(1-c)+c x*y*(1-c)-z*s x*z*(1-c)+y*s |
Rotate = | y*x*(1-c)+z*s y*y*(1-c)+c y*z*(1-c)-x*s |
| z*x*(1-c)-y*s z*y*(1-c)+x*s z*z*(1-c)+c |

This matrix is implicitly extended to a 4x4 matrix. FInally the input matrix (m) is multiplied by Roatate and assigned to Result:

Result = m * Roatate

How to calculate a position offset based on an object's rotation, openGL, C++

that feels like an order of multiplication problem. you need to rotate first, and then apply the offset, not the other way around.

Calculating a camera's normal in OpenGL?

You're actually quite close and cameraPos should be correct. Given that you have the inverse view matrix, then the camera's normal/direction is just the column prior to the camera's position.

Here's some pseudo GLSL-like code:

mat4 inv = inverse(view);

vec3 pos = vec3(inv[3]);
vec3 dir = -vec3(inv[2]);

Where view is the camera's view matrix (mat4).

OpenGL application rotate Camera

The math for the second rotation would be slightly more complicated because you want to apply it relative to the current position. But I think you can make this whole thing much simpler if you keep track of the current angles, and add/subtract from them when rotating the camera. Essentially, you primarily operate in spherical coordinate space, and only calculate cartesian coordinates when it's time to apply the rotation.

To do this, you need two angles. I'll use the following nomenclature:

  • yawAng: Current rotation angle around the y-axis, measured relative to the z-axis.
  • pitchAng: Angle relative to the xz-plane. Positive for up (in direction of positive y, negative for down).

With this, the basic camera rotations simply become increments/decrements to these angles. For an increment of angInc:

  • Left: yawAng += angInc
  • Right: yawAng -= angInc
  • Up: pitchAng += angInc
  • Down: pitchAng -= angInc

Then, when it's time to apply the gluLookAt() transformation, you convert the spherical coordinates to cartesian coordinates using the standard formula. With distance d between camera and center:

cx = eyex + d * sin(yawAng) * cos(pitchAng);
cy = eyey + d * sin(pitchAng)
cz = eyez + d * cos(yawAng) * cos(pitchAng);

Calculate object rotation angle from mouse movement in OpenGL drawing in Qt5

Everything about the code in question smells like someone who simply had no real idea what they're doing.

The effect of what they've done is this. They scaled the input angle by 8, relative to the mouse delta. This causes the eventual angle to be 8x larger. But then they divide this angle by 16 before getting matrices with it. Therefore, the effect of what they've done is scale the input angle by 0.5.

The clamping to the range [0, 360 * 16] is just a part of that nonsense. They're really clamping to [0, 360], just in a really obtuse and insane way.

Overall, I'd say you should avoid Qt's example code like the plague.



Related Topics



Leave a reply



Submit