OpenGL 3.3 - Different rotation for 2 triangles

4 min read 07-10-2024
OpenGL 3.3 - Different rotation for 2 triangles


Spinning Triangles: Implementing Independent Rotations in OpenGL 3.3

The Problem: Imagine you're building a simple 3D scene with two triangles. You want them to rotate independently, one spinning around the X-axis and the other around the Y-axis. How do you achieve this in OpenGL 3.3?

Rephrasing: This article will guide you through implementing separate rotations for two triangles in OpenGL 3.3, providing a clear understanding of how to control individual object movements within a scene.

Scenario and Original Code:

Let's start with a basic OpenGL 3.3 setup. We'll have two triangles, defined as vertex arrays, and a shader program for rendering them.

#include <GL/glew.h>
#include <GLFW/glfw3.h>

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos, 1.0);\n"
"}\0";

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\0";

int main() {
    // ... (GLFW initialization) ...

    // Create and compile shaders
    // ...

    // Create Vertex Array Objects (VAOs) and Vertex Buffer Objects (VBOs)
    GLuint VAOs[2], VBOs[2];
    glGenVertexArrays(2, VAOs);
    glGenBuffers(2, VBOs);

    // Triangle 1: Rotating around X-axis
    GLfloat triangle1[] = {
        -0.5f, -0.5f, 0.0f,  
         0.5f, -0.5f, 0.0f, 
         0.0f,  0.5f, 0.0f
    };
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle1), triangle1, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    // Triangle 2: Rotating around Y-axis
    GLfloat triangle2[] = {
        -0.5f, 0.5f, 0.0f, 
        -0.5f, -0.5f, 0.0f, 
         0.5f, -0.5f, 0.0f
    };
    glBindVertexArray(VAOs[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    // ... (GLFW render loop) ...
        
    // Render triangles
    glBindVertexArray(VAOs[0]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindVertexArray(VAOs[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // ... (GLFW swap buffers) ...
    
    // ... (GLFW termination) ...
}

The Missing Link: Transformations

Currently, the code lacks the necessary transformations for the rotation. We need to introduce rotation matrices and apply them to each triangle independently.

Solution: Introducing Model Matrices

To achieve independent rotations, we need to introduce a separate model matrix for each triangle. These matrices will handle the transformations for each object.

  1. Create Model Matrices: Create two 4x4 matrices, one for each triangle. Initialize them with identity matrices.
  2. Update Matrices in the Render Loop: In the render loop, update the model matrices based on the desired rotation angles. For example, rotate the first matrix around the X-axis and the second around the Y-axis.
  3. Pass Matrices to the Shader: Pass the model matrices to the vertex shader as uniform variables.
  4. Transform Vertices in the Shader: In the vertex shader, multiply each vertex position by the corresponding model matrix before calculating the final gl_Position.

Modified Code:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// ... (Shader sources) ...

int main() {
    // ... (GLFW initialization) ...

    // ... (Shader creation) ...

    // ... (VAO and VBO creation) ...

    // ... (Triangle data) ...

    // Model matrices for triangles
    glm::mat4 modelMatrices[2];
    modelMatrices[0] = glm::mat4(1.0f);
    modelMatrices[1] = glm::mat4(1.0f);

    // ... (GLFW render loop) ...

    // Update model matrices (example: rotating around X and Y axes)
    float angle = glfwGetTime();
    modelMatrices[0] = glm::rotate(modelMatrices[0], glm::radians(angle), glm::vec3(1.0f, 0.0f, 0.0f));
    modelMatrices[1] = glm::rotate(modelMatrices[1], glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f));

    // Render triangles with updated model matrices
    for (int i = 0; i < 2; ++i) {
        glBindVertexArray(VAOs[i]);
        glUseProgram(shaderProgram);

        // Pass model matrix to shader
        GLint modelLoc = glGetUniformLocation(shaderProgram, "model");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrices[i]));

        glDrawArrays(GL_TRIANGLES, 0, 3);
    }

    // ... (GLFW swap buffers) ...

    // ... (GLFW termination) ...
}

Modified Vertex Shader:

#version 330 core\n
layout (location = 0) in vec3 aPos;\n
uniform mat4 model; // Model matrix

void main()\n
{
    gl_Position = model * vec4(aPos, 1.0); // Apply model matrix to vertex
}

Explanation:

  • glm: We're using the GLM (OpenGL Mathematics) library for matrix operations. Include its header files in your code.
  • Model Matrices: We've created two model matrices, modelMatrices[0] and modelMatrices[1], to control each triangle's transformations.
  • Rotation: We use glm::rotate to rotate the model matrices around their respective axes.
  • Shader Uniform: The model uniform is passed to the shader to access the model matrix.
  • Vertex Transformation: In the vertex shader, gl_Position is calculated by multiplying the vertex position by the model matrix.

Key Points:

  • This approach allows for independent transformations on multiple objects in the scene.
  • Model matrices provide a convenient way to handle transformations at the object level.
  • You can use other transformation functions from GLM (translation, scaling, etc.) to further manipulate objects.

Additional Resources:

By implementing these techniques, you can create dynamic 3D scenes where objects can move and interact independently, bringing your OpenGL creations to life.