0

In OpenGL i want to rotate a Model around a global Axis.

The object I am trying to rotate looks like this:

class Object {
public:
    inline Object()
        : vao(0),
        positionBuffer(0),
        colorBuffer(0),
        indexBuffer(0),
        elements(0)
    {}

    inline ~Object() { // GL context must exist on destruction
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &indexBuffer);
        glDeleteBuffers(1, &colorBuffer);
        glDeleteBuffers(1, &positionBuffer);
    }
    GLuint vao;        // vertex-array-object ID
    GLuint positionBuffer; // ID of vertex-buffer: position
    GLuint colorBuffer;    // ID of vertex-buffer: color
    GLuint indexBuffer;    // ID of index-buffer
    GLuint elements; // Number of Elements
    glm::mat4x4 model; // model matrix
};

The function to initiate an object looks like:

void initObject(Object &obj, vector<glm::vec3> &vertices, vector<glm::vec3> &colors, vector<GLushort> &indices, glm::vec3 offset)
{
    GLuint programId = program.getHandle();
    GLuint pos;

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Step 0: Create vertex array object.
    glGenVertexArrays(1, &obj.vao);
    glBindVertexArray(obj.vao);

    // Step 1: Create vertex buffer object for position attribute and bind it to the associated "shader attribute".
    glGenBuffers(1, &obj.positionBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, obj.positionBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

    // Bind it to position.
    pos = glGetAttribLocation(programId, "position");
    glEnableVertexAttribArray(pos);
    glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Step 2: Create vertex buffer object for color attribute and bind it to...
    glGenBuffers(1, &obj.colorBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, obj.colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_STATIC_DRAW);

    // Bind it to color.
    pos = glGetAttribLocation(programId, "color");
    glEnableVertexAttribArray(pos);
    glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Step 3: Create vertex buffer object for indices. No binding needed here.
    glGenBuffers(1, &obj.indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), indices.data(), GL_STATIC_DRAW);

    // Unbind vertex array object (back to default).
    glBindVertexArray(0);

    // Modify model matrix.
    obj.model = glm::translate(glm::mat4(1.0f), offset);
}

Now I got an instance of that which is tessellated octahedron acting as a sphere, which i want to rotate around a global Axis, specifically the X axis. The center of that Object is at (3, 1, 0) so that a rotation around 90 degrees should the origin be at (3, 0, 1).

I tried to do this with the glm::rotate Method:

glm::vec3 axis;
axis = { 1.0, 0.0f, 0.0f };
sphere.model = glm::rotate(sphere.model, glm::radians(90.0f), axis);

But that only rotates the object around it's local Axis.

Another solution I tried was this one:

glm::vec3 axis;
axis = glm::inverse(sphere.model) * glm::vec4(1.0, 0.0, 0.0, 0.0f);
sphere.model = glm::rotate(sphere.model, (2.0f*3.1415f)/48.0f, axis);

This one the other hand act's like the global axis is in the center of the model. So the rotation would be right if the center of the object would be equal to the origin of the global coordinate system.

vMysterion
  • 102
  • 11
  • What's the value contained in the model matrix before the transformation? It sounds like that the model matrix is an identity matrix, and you simply rotate the identity matrix. Also it sounds like that another transformation is applied after the model matrix (maybe the camera one), could it be? – Stefano Buora Jun 04 '20 at 16:17
  • If you are using standard 4x4 transformation matrices, you can simply undo the translation component by negating the top 3 elements in the last column in matrix multiplication, then do your rotation, then put the object origin back where you want it. You simply have to extract the translation component properly, which I assume GLM has a function call for. – robotsfoundme Jun 04 '20 at 16:29
  • 2
    [tag:glm] != [tag:glm-math]. – genpfault Jun 04 '20 at 16:34
  • @StefanoBuora This is how i am calculating the model: ``` obj.model = glm::translate(glm::mat4(1.0f), offset); ``` Where the offset is the Point (3,1,0) on which the sphere is located. The other attributes are the vertices where all points are and the indices which construct the sphere, stored in positionBuffer and indexBuffer. – vMysterion Jun 04 '20 at 16:43
  • @thatrobotguy I am sorry, i don't quite understand how that is working. Could you provide some article or something which explains how that calculation works? – vMysterion Jun 04 '20 at 16:43

3 Answers3

0

I would give Kudos to @genpfault. It sounds like the implementation of glm::rotate is that one:https://github.com/g-truc/glm/blob/1498e094b95d1d89164c6442c632d775a2a1bab5/glm/ext/matrix_transform.inl

Hence it doesn't touch the translation, it changes only the rotation part of the matrix, like to set the things up. In order to perform animations or combine different transformation you need to use another API.

Stefano Buora
  • 1,012
  • 6
  • 11
0

retMat = glm::rotate(curMat, ...) calculates the rotation matrix and multiply it with the given curMat matrix.

The returned matrix retMat can be used with any point that was defined in the same coordinates-system (aka "space") as curMat to calculate the new coordinates, again in the same space: newXYZ = retMat * oldXYZ.

The axis of rotation given to glm::rotate always goes through the origin of the space.
If you need another line of rotation (not containing the origin) then you must do the sequence "translate to some point on line ==> rotate ==> translate back"

For your case, I guess your sphere is defined such way its center is the origin 0,0,0. This means that "model space" is the same as "global space". So, you don't need to translate the sphere before the rotation.


Once you have rotated the object then translate it to the point you wish.

Ripi2
  • 6,098
  • 1
  • 12
  • 28
0

In your model+view+projection (MVP) matrix (or quaternion) operations, you are mixing your model and view matrices. You need to rotate the model from the identity matrix to the desired RPY matrix. Then, you move and/or rotate the object to the location you want in XYZ space. Finally, you apply your orthogonal projection or your perspective projection, whichever you want.

The point is that you should keep track of where the origin of the OBJECT is relative to the GLOBAL origin separately. In other words, you have where you want the centroid of the object to be, but also the centers of rotations (which aren't necessarily the global origin).

In order to rotate an object in the object centroid's local frame, you need to first get rid of the translation component. This is the Model+View part. You can do this by doing the inverse matrix of just he XYZ elements in the last column of the 4x4 matrix. You then apply your 4x4 rotation matrix to the centroid. You then move the object back to the desired centroid location.

Does this make sense?

I suggest you study more into the MVP model more. The OGL 4 shading language cookbook (by Packt) is a great resource. There is also this link and this one.

I should note, however, that you should be familiar with the backend of the glm matrix library. I have use a custom matrix library that showed the implementation of the rotate() function.

robotsfoundme
  • 281
  • 1
  • 12