rotation after translation

So I’ve been racking my brain over this for a couple hours and I just can’t seem to figure it out.

Essentially, I just want an object (an image) to move diagonally while it rotates around it’s own axis (in the center of the image). How would the matrix transformation for this look like in modern openGL? (without using glPushMatrix, glTranslatef, etc) What would the vertex shader have to look like and what kind of values would I have to supply to it?

Since I’m probably not explaining myself too well, let me demonstrate with images (i hope imgur is okay, embedded doesn’t allow for .gif):
https://imgur.com/a/4YFx6Na

my vector shader has this math in it:
gl_Position = transform * vec4(aPos.x+offsetX, aPos.y+offsetY, aPos.z, 1.0);

my main function has this relevant code in it:


float xOffset = 0.0f; //starting X position of the image
float yOffset = 0.3f; //same but for Y
float velX = (1.0f / 800.0f) * 2.5f; // velocity vector normalized to 0,1 from 0, window_width = 800
float velY = (1.0f / 600.0f) * 2.5f; // same here but with window_height = 600
float rots = 0.1f; // rotation speed abbreviated as rots
glm::mat4 rot(0.f);

while(running) {
  
  xOffset += velX;
  yOffset += velY;


  shader.setFloat("offsetX", xOffset); 
  shader.setFloat("offsetY", yOffset); 
// i made a generic shader class that loads my shaders from a file
// it has a set<type>() function where you supply the name of a 
// uniform and a value and it changes that uniform to the value
// think of this as glUniform1f(programID, value)

  rot = glm::rotate(rot, glm::radians(rots), glm::vec3(0.0, 0.0, 1.0)); 
// this rotates the matrix (rot) by rotation speed

  unsigned int transformLoc = glGetUniformLocation(shader.ID, "transform");
  glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(rot)); 
// and then modifies the "transform" uniform of the vector shader

// after that is done, render the image
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

shader.use(); 
// my generic shader class has a .use method which just uses the loaded and linked shader program
// which is created in the Shader() constructor
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

glfwSwapBuffers(window);
glfwPollEvents();

// some math for "bouncing" the image off the walls
if (xOffset + velX > 0.8 || xOffset + velX < -0.8) {
velX *= -1;
state *= -1;
}
if (yOffset + velY > 0.8 || yOffset + velY < -0.8) {
	velY *= -1;
	state *= -1;
	}
}


I tried using glm::translate() for the translation part of the math, but then I changed it to use the offsetX,Y values as uniforms in the vector shader which i just modify before each rendering. Somehow, I thought this would change something but it didn’t.

Rotation matrices always rotate around the coordinate origin (0,0,0). If you have a rectangle where the bottom left corner has the x/y-values (0,0) and you multiply a rotation matrix with it, it will rotate around the bottom left corner. If you want to rotate it around the centre, you have to translate the rectangle first so that the centre ends up in the coordinate origin. Then rotate it. Afterwards you translate it back or to any other location that you want to move it. Just keep in mind, that you are now in a coordinate system that has is origin in the centre of the rectangle.

yes so how do i make it so the next translation is based on the window origin (0,0,0) and not the rectangle origin?

okay some operations can be done at once, but I will write it down step by step.

You are in model space were your texture is a rectangle with bottom left corner at (0,0) and your top right corner is at (1,1). Now translate it to the centre with the transformation vector TC. For each Vertex V do:

V + TC

In our case TC is vec3(-0.5,-0.5,0). Now your rectangle has its centre at the coordinate origin. Now apply the rotation matrix R:

R * (V+TC)

If you would render the rotated rectangle with no further transformations it should end up in the middle of the screen since OpenGL defines the location (0,0) to be in the screens centre. The bottom left corner is (-1,-1) and top right(1,1). So if you want to get the rectangle to the bottom left corner, you have to translate it there with the translation Vector TO = vec3(-1,-1,0).

R * (V + TC) + TO

Now the centre of the rotated rectangle is in the bottom left corner of the screen causing you to see it only partially. Undo the first translation which you did for the rotation by subtracting TC:

R * (V + TC) + TO - TC

The rectangle should now be more or less be fully visible in the left bottom corner. Only the parts that are rotated over the borders should be cut off. Now you can translate it everywhere to the screen by applying another arbitrary translation T:

R * (V + TC) + TO - TC + T

Just keep in mind that the value 2 equals the whole screens size! If you want to do it in pixels you have to divide your input values by half of the screens resolution. You can change the order of the last 3 translations as you like, it wont change the result.

[QUOTE=ProgrammerX;1293223]okay some operations can be done at once, but I will write it down step by step.

You are in model space were your texture is a rectangle with bottom left corner at (0,0) and your top right corner is at (1,1). Now translate it to the centre with the transformation vector TC. For each Vertex V do:

V + TC

In our case TC is vec3(-0.5,-0.5,0). Now your rectangle has its centre at the coordinate origin. Now apply the rotation matrix R:

R * (V+TC)

If you would render the rotated rectangle with no further transformations it should end up in the middle of the screen since OpenGL defines the location (0,0) to be in the screens centre. The bottom left corner is (-1,-1) and top right(1,1). So if you want to get the rectangle to the bottom left corner, you have to translate it there with the translation Vector TO = vec3(-1,-1,0).

R * (V + TC) + TO

Now the centre of the rotated rectangle is in the bottom left corner of the screen causing you to see it only partially. Undo the first translation which you did for the rotation by subtracting TC:

R * (V + TC) + TO - TC

The rectangle should now be more or less be fully visible in the left bottom corner. Only the parts that are rotated over the borders should be cut off. Now you can translate it everywhere to the screen by applying another arbitrary translation T:

R * (V + TC) + TO - TC + T

Just keep in mind that the value 2 equals the whole screens size! If you want to do it in pixels you have to divide your input values by half of the screens resolution. You can change the order of the last 3 translations as you like, it wont change the result.[/QUOTE]

If I don’t do any transformations, my “rectangle” is in the middle of the screen, and the middle of the rectangle is exactly at 0,0 - the centre of the screen. If I rotate now, it will look just like it is supposed to.
If I translate once, and then rotate, it works like it is supposed to.
But if I translate after I’ve already rotated, the second translation will be rotated by the rotation matrix.
How do I make it so that even if I rotated the matrix, the second translation will follow the original matrix- without any rotation? Clearly, the order of the transformations greatly affects the final rendered result! Just adding more translations does not fix my problem, which is clearly what your formula is doing- Applying the rotation to the (vector + central translation) - in my case this is just rotation * vector, because I am already centered. Then you apply further translations- but these are applied to the rotated matrix, not the original one.

[QUOTE=nemolionak3;1293225]If I don’t do any transformations, my “rectangle” is in the middle of the screen, and the middle of the rectangle is exactly at 0,0 - the centre of the screen. If I rotate now, it will look just like it is supposed to.
If I translate once, and then rotate, it works like it is supposed to.
But if I translate after I’ve already rotated, the second translation will be rotated by the rotation matrix.
How do I make it so that even if I rotated the matrix, the second translation will follow the original matrix- without any rotation? Clearly, the order of the transformations greatly affects the final rendered result! Just adding more translations does not fix my problem, which is clearly what your formula is doing- Applying the rotation to the (vector + central translation) - in my case this is just rotation * vector, because I am already centered. Then you apply further translations- but these are applied to the rotated matrix, not the original one.[/QUOTE]

Okay here I am, a few hours after the problem arose, and I finally have a solution!

I remember from programming in processing, each time I drew something, I first created a matrix using pushMatrix(); then I did translate(x,y) and rotate(rot)
The difference between what I was trying to do today and what I did before was that I wasn’t actually saving any values, I was adding to the initial matrix!

Let me clarify: At the start of my program, before the while(running) loop, I declared a matrix: glm::mat4 transformation
then, each frame, I “translated” and “rotated” this matrix. This would very obviously form an “additive” effect, where each transformation would affect the next- including the rotations!
So, all I had to do was “re-create” the matrix each frame (reset it in some way), and then translate and rotate the matrix by X,Y and ANGLE, where X, Y, ANGLE are variables which I modify each frame.
This means that the matrix is “reset” each frame, and it is translated and rotated from scratch, thus it no longer has an “additive” effect, and works perfectly!

Thank you for your answer, though, I really appreciate it!

EDIT: I just found out there’s an even better way to do it.

Each time your object moves or rotates, you do:

matrix = glm::translate(glm::mat4 (1), glm::vec3(x,y,z)) * glm::rotate(glm::mat4(1), glm::radians(ROTATION_ANGLE), glm::vec3(choose the axis of rotation));

which is essentially

TRANSFORMATION_MATRIX = TRANSLATION_MATRIX * ROTATION_MATRIX;

or

M = T*R

which is probably what you were trying to tell me, but only now do I understand it

Glad you found a solution. :wink: