Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

OpenGL GLM rotate 2D shape around Z-axis

This is similar to this question, but I have a 2D triangle I’m trying to rotate solely about the z-axis, so I don’t think I have to do any negative rotations. I have intentionally picked a triangle that is centered around the center of the screen (I calculated the centroid with this webpage). Essentially, I want it to look like the triangle is rotating clockwise or counter-clockwise about the center of the window, but by changing around the order I define my vertices, I’ve discovered that it seems to be rotating around the last vertex I define.

Here’s my C++ code; I’ve removed comments for brevity. I don’t have any input handling at the moment – I’m running in vscode so I’ve been terminating it through the IDE.

// Third-party library
#include <SDL2/SDL.h>
// Include GLAD
#include <glad/glad.h>
#include <glm/vec3.hpp>
#include <glm/mat3x3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>

// C++ Standard Libraries
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

// Screen dimensions
int gScreenHeight = 480;
int gScreenWidth  = 640;
SDL_Window* gGraphicsApplicationWindow = nullptr;
SDL_GLContext gOpenGLContext = nullptr;

// Main loop flag
bool gQuit = false;  // if true, we quit

GLuint gGraphicsPipelineShaderProgram = 0;

GLuint gVertexArrayObject = 0;
GLuint gVertexBufferObject  = 0;
GLuint gVertexBufferObject2 = 0;

glm::mat4 gVertexData(
    -0.4f, -0.4f,  0.0f, 0.0f,  // point 1 - bottom left
     0.4f, -0.4f,  0.0f, 0.0f,  // point 2 - bottom right
     0.0f,  0.8f,  0.0f, 0.0f,  // point 3 - top
     0.0f,  0.0f,  0.0f, 1.0f   // 4th dimension
);
const auto gVertexBytes = gVertexData.length() * gVertexData[0].length()
        * sizeof(gVertexData[0][0]);

std::string loadShaderAsString(const std::string& filename) {
    std::string result = "";
    std::string line = "";
    std::ifstream myFile(filename);
    if (myFile.is_open()) {
        while (std::getline(myFile, line)) {
            result += line + '\n';
        }
        myFile.close();
    }
    return result;
}

GLuint compileShader(GLuint type, const std::string& source) {
    GLuint shaderObject;
    if (type == GL_VERTEX_SHADER) {
        shaderObject = glCreateShader(GL_VERTEX_SHADER);
    } else if (type == GL_FRAGMENT_SHADER) {
        shaderObject = glCreateShader(GL_FRAGMENT_SHADER);
    }
    const char* src = source.c_str();
    glShaderSource(shaderObject, 1, &src, nullptr);
    glCompileShader(shaderObject);
    int result;
    glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, &length);
        char* errorMessages = new char[length];  // Could also use alloca here.
        glGetShaderInfoLog(shaderObject, length, &length, errorMessages);
       if (type == GL_VERTEX_SHADER) {
            std::cout << "ERROR: GL_VERTEX_SHADER compilation failed!\n"
                << errorMessages << "\n";
        } else if (type == GL_FRAGMENT_SHADER) {
            std::cout << "ERROR: GL_FRAGMENT_SHADER compilation failed!\n"
                << errorMessages << "\n";
        }
        delete[] errorMessages;
        glDeleteShader(shaderObject);
        return 0;
    }
    return shaderObject;
}

GLuint createShaderProgram(const std::string& vertexShaderSource,
                           const std::string& fragmentShaderSource) {
    GLuint programObject = glCreateProgram();
    GLuint myVertexShader   = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
    GLuint myFragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
    glAttachShader(programObject, myVertexShader);
    glAttachShader(programObject, myFragmentShader);
    glLinkProgram(programObject);
    glValidateProgram(programObject);
    glDetachShader(programObject, myVertexShader);
    glDetachShader(programObject, myFragmentShader);
    glDeleteShader(myVertexShader);
    glDeleteShader(myFragmentShader);
    return programObject;
}

void createGraphicsPipeline() {
    std::string vertexShaderSource   = loadShaderAsString("../shaders/vert.glsl");
    std::string fragmentShaderSource = loadShaderAsString("../shaders/frag.glsl");
    gGraphicsPipelineShaderProgram = createShaderProgram(vertexShaderSource,
                                                        fragmentShaderSource);
}

void getOpenGLVersionInfo() {
    std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;
    std::cout << "Version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "Shading Language: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
}

void vertexSpecification() {
    const std::vector<GLfloat> vertexColors {
         1.0f,  0.0f,  0.0f,  // vertex 1 - Left
         0.0f,  1.0f,  0.0f,  // vertex 2 - Right
         0.0f,  0.0f,  1.0f   // vertex 3 - Top
    };
    glGenVertexArrays(1, &gVertexArrayObject);
    glBindVertexArray(gVertexArrayObject);
    glGenBuffers(1, &gVertexBufferObject);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER,
                 gVertexBytes,
                 &gVertexData[0][0],
                 GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0,
                          gVertexData[0].length(),
                          GL_FLOAT,
                          GL_FALSE,
                          0,
                          nullptr);

    glGenBuffers(1, &gVertexBufferObject2);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBufferObject2);
    glBufferData(GL_ARRAY_BUFFER,
                vertexColors.size() * sizeof(GL_FLOAT),
                vertexColors.data(),
                GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT,
                          GL_FALSE, 0, nullptr);
    glBindVertexArray(0);
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
}

void initializeProgram() {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cout << "SDL could not be initialized: " <<
                  SDL_GetError();
        exit(1);
    }

    std::cout << "SDL video system is ready to go\n";

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    gGraphicsApplicationWindow = SDL_CreateWindow("C++ SDL2 Window",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            gScreenWidth,
            gScreenHeight,
            SDL_WINDOW_OPENGL);
    if (gGraphicsApplicationWindow == nullptr) {
        std::cout << "SDL WIndow was not able to be created" << std::endl;
        exit(1);
    }
    gOpenGLContext = SDL_GL_CreateContext(gGraphicsApplicationWindow);
    if (gOpenGLContext == nullptr) {
        std::cout << "OpenGL context not available" << std::endl;
        exit(1);
    }
    if (!gladLoadGLLoader(SDL_GL_GetProcAddress)) {
        std::cout << "Glad was not initialized" << std::endl;
        exit(1);
    }
    getOpenGLVersionInfo();
}

void predraw() {
    static glm::vec3 zNorm(0.0f, 0.0f, 1.0f);
    gVertexData = glm::rotate(gVertexData, glm::radians(0.10f), zNorm);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER,
                 gVertexBytes,
                 &gVertexData[0][0],
                 GL_DYNAMIC_DRAW);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glViewport(0, 0, gScreenWidth, gScreenHeight);
    glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    glUseProgram(gGraphicsPipelineShaderProgram);
}

void draw() {
    glBindVertexArray(gVertexArrayObject);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBufferObject);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glUseProgram(0);
}

void mainLoop() {
    while (!gQuit) {
        predraw();
        draw();
        SDL_GL_SwapWindow(gGraphicsApplicationWindow);
    }
}

void cleanup() {
    SDL_DestroyWindow(gGraphicsApplicationWindow);
    SDL_Quit();
}

int main(int argc, char* argv[]) {
    initializeProgram();
    vertexSpecification();
    createGraphicsPipeline();
    mainLoop();
    cleanup();
    return 0;
}

Here’s the vertex shader code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#version 410 core

layout(location=0) in vec4 position;
layout(location=1) in vec3 vertexColors;

out vec3 v_vertexColors;

void main()
{
   v_vertexColors = vertexColors;
   
   gl_Position = vec4(position.x, position.y, position.z, 1.0f);
}

And the fragment shader:

#version 410 core

in vec3 v_vertexColors;

out vec4 color;

void main()
{
   color = vec4(v_vertexColors.r, v_vertexColors.g, v_vertexColors.b, 1.0f);
}

I’ve gone through these matrices and rotations tutorials, but I haven’t been able to figure out what I’m doing wrong.

>Solution :

You have to transform the vertex coordinates in the vertex shader. See LearnOpenGL – Transformations (bottom of the page)

Use a uniform variable of type mat4 and transform the vertices in the vertex shader:

#version 410 core

layout(location=0) in vec4 position;
layout(location=1) in vec3 vertexColors;

out vec3 v_vertexColors;
uniform mat4 model_matrix;

void main()
{
   v_vertexColors = vertexColors;
   
   gl_Position = model_matrix * vec4(position.xyz, 1.0f);
}

Set the matrix after installing the program:

int model_loc = glGetUniformLocation(gGraphicsPipelineShaderProgram, "model_matrix")
glm::mat4 rotation_matrix(1.0f);
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(angle), zNorm);
glUseProgram(gGraphicsPipelineShaderProgram);
glUniformMatrix4fv(model_loc, 1, false, glm::value_ptr(rotation_matrix));

The variable angle needs to be increased in every frame. e.g.: angle = 0.1f;

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading