Search code examples
c++openglglfwglm-mathglad

Rotating/Translating Object In OpenGL


I'm currently using OpenGL(Glad, GLFW, GLM). I just started learning and can't find the correct way to take a translation and actually render it. For example, I want to rotate 1 degree every frame. I've seen tutorials on how to use GLM to make those translations but I can't seem to figure out how to take something like this: glm::mat4 translate = glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, 0.f)); and apply it to an object rendered like this:

glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES,3, GL_UNSIGNED_INT, 0);

I'm really not sure what I'm not understanding and any help would be appreciated.

Edit: I know you can just change the vertices and rebind the array, but that seems like it would be pretty slow. Would that work?


Solution

  • I am assuming that you are somewhat familiar with the concept of the different coordinate systems and transformations like the projection, view and model matrix. If not, you should read up on them here https://learnopengl.com/Getting-started/Coordinate-Systems.

    In short, the model matrix transforms the object as a whole in the world. In most cases it contains translation, rotation and scaling. It is important to note that the order of matrix multiplication is generally defined as

    glm::mat4 model = translate * rotate * scale;
    

    The view matrix is needed to get the view of the camera and the projection matrix adds perspective and is used to determine what is on the screen and will be rendered.

    To apply the transformation to the object that you want to draw with your shader, you will need to load the matrix into the shader first.

    glm::mat4 model = glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, 0.f));
    
    unsigned int modelMatrixLoc = glGetUniformLocation(ourShader.ID, "model");
    glUniformMatrix4fv(modelMatrixLoc , 1, GL_FALSE, glm::value_ptr(model));
    

    Here, the model matrix would be loaded into the shader under the name "model". You can then use this matrix in your shader to transform the vertices on the GPU.

    A simple shader would then look like this

    #version 460 core
    layout (location = 0) in vec3 position_in;
    
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(position_in, 1.0);
    }
    

    To ensure that your normal vectors do not get skewed, you can calculate another matrix

    glm::mat3 model_normal = glm::transpose(glm::inverse(model));
    

    If you were to add this to the shader, it would look something like this

    #version 460 core
    layout (location = 0) in vec3 position_in;
    layout (location = 1) in vec3 normal_in;
    
    uniform mat4 model;
    uniform mat3 model_normal;
    uniform mat4 view;
    uniform mat4 projection;
    
    out vec3 normal;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(position_in, 1.0);
        normal = model_normal * normal_in;
    }
    

    Notice how we can now use a mat3 instead of a mat4? This is because we do not want to translate the normal vector and the translation part of the matrix is located in the fourth column, which we cut away here. This also means that it is important to set the last component of the 4d vector to 1 if we want to translate and to 0 if we do not.


    Edit: I know you can just change the vertices and rebind the array, but that seems like it would be pretty slow. Would that work?

    You can always edit your model if you want to change its looks. However, the transformations are going to be way slower on the CPU. Remember that the GPU is highly optimized for this kind of task. So I would advise to do most transformations on the GPU.

    If you only need to change a part of the vertices of your object, updating the vertices will work better in most cases.


    How would I constantly rotate as a function of time?

    To rotate as a function of time, there are multiple approaches. To clarify, transformations that are applied to an object in the shader are not permanent and will be reset for the next draw call. If the rotation is performed with the same axis, it is a good idea to specify the angle somewhere and then calculate a single rotation (matrix) for that angle. To do this with GLFW, you can use

    const double radians_per_second = ... ;
    const glm::vec3 axis = ... ;
    
    // rendering loop start
    
    double time_seconds = glfwGetTime();
    float angle = radians_per_second * time_seconds;
    glm::mat4 rotation = glm::rotate(glm::mat4(1.f), angle, axis);
    

    On the other hand, if the rotations are not performed on the same axis, you will have to multiply both rotation matrices together.

    rotation = rotation * additional_rotation;
    

    In both cases, you need to set the rotation for your model matrix like I explained above.


    Also, if I wanted to make a square follow the mouse, would I have to rebuild the vertices every time the mouse moves?

    No you do not need to do that. If you just want to move the square to the position of the mouse, you can use a translation. To get the mouse position in world space, it seems that you can use glm::unProject( ... );. I have not tried this yet, but it looks like it could solve your problem. You can take a look at it here

    https://glm.g-truc.net/0.9.2/api/a00245.html#gac38d611231b15799a0c06c54ff1ede43.

    If you need more information on this topic, you can take a look at this thread where it has already been answered

    Using GLM's UnProject.


    what's the GLFW/GLAD function to change the camera's position and rotation?

    That is just the view matrix. Look here again.


    I'm basically trying to create the FPS camera. I figured out movement but I can't figure out rotation.

    You can take a look here learnopengl.com/Getting-started/Camera. Just scroll down until you see the section "Look around". I think that the explanation there is pretty good.


    I already looked at that but was confused about one thing. If each rendered cube has view, perspective, and model, how would I change the camera's view, perspective, and model?

    Ok, I think that I understand the misconception here. Not all 3 matrices are per object. The model matrix is per object, the view matrix per camera and the projection matrix per viewing mode (e.g. perspective with fov of 90° or orthogonal) so usually only once.