c++openglglfwglm-mathimgui

How to set to specific scale in OpenGL?


I am using C++ and OpenGL. But I need the object to scale to a certain scale. For a game engine. My goal is just for the scale to be SET not CHANGED.

#define GLFW_INCLUDE_NONE
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GLFW/glfw3.h>
#include <Glad/glad.h>
#include "vendor/ImGui/imgui.h"
#include "vendor/ImGui/backends/imgui_impl_glfw.h"
#include "vendor/ImGui/backends/imgui_impl_opengl3.h"
#include <stdio.h>
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

void error_callback(int error, const char* description)
{
    fprintf(stderr, "Error: %s\n", description);
}

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

const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec2 wsize;\n"
"void main()\n"
"{\n"
" vec2 position = gl_FragCoord.xy;\n"
" FragColor = vec4(position.x/wsize.x, position.x/position.y/wsize.x,position.y/wsize.y, 1.0f);\n"
"}\n\0";

float aspectRatio;
glm::mat4 projection;

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
    aspectRatio = (float)width / (float)height;
    projection = glm::ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
}

int main()
{
    if (!glfwInit())
    {
        // Initialization failed
    }
    glfwSetErrorCallback(error_callback);

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    GLFWwindow* window = glfwCreateWindow(640, 480, "GL YA!", NULL, NULL);
    if (!window)
    {
        // Window or context creation failed
    }

    glfwMakeContextCurrent(window);
    gladLoadGL();

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    float vertices[9 * 2] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.5f, 0.5f, 0.0f,

        0.5f, 0.5f, 0.0f,
        -0.5f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
    };

    glfwSwapInterval(1);

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;    // Enable Keyboard Controls
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;     // Enable Gamepad Controls
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
    io.ConfigDockingWithShift = false;
    ImGui::StyleColorsDark();
    const char* glsl_version = "#version 100";
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);
    float x = 0;
    float y = 0;
    float z = 0;

    while (!glfwWindowShouldClose(window))
    {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);

        framebuffer_size_callback(window, width, height);

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);

        ImGui::Begin("Hello OpenGL!");
        ImGui::InputFloat("X", &x);
        ImGui::InputFloat("Y", &y);
        ImGui::InputFloat("Z", &z);
        ImGui::End();
        ImGui::Render();

        glViewport(0, 0, width, height);

        glClear(GL_COLOR_BUFFER_BIT);

        //Square

        glUseProgram(shaderProgram);
        GLint wsize = glGetUniformLocation(shaderProgram, "wsize");
        glUniform2f(wsize, width, height);
        /*
        glm::mat4 transform = glm::mat4(1.0f); // Start with an identity matrix
        transform = glm::translate(transform, glm::vec3(x, y, z)); // Move the triangle along the x and y axes

        for (int i = 0; i < 9 * 2; i += 3) {
            glm::vec4 vertex = transform * glm::vec4(vertices[i], vertices[i + 1], vertices[i + 2], 1.0f);
            vertices[i] = vertex.x;
            vertices[i + 1] = vertex.y;
            vertices[i + 2] = vertex.z;
        }
        */
        float currentX = 0.0f;
        float currentY = 0.0f;
        float currentZ = 0.0f;

        for (int i = 0; i < 9 * 2; i += 3) {
            currentX += vertices[i];
            currentY += vertices[i + 1];
            currentZ += vertices[i + 2];
        }

        currentX /= 9;
        currentY /= 9;
        currentZ /= 9;

        float tx = x - currentX;
        float ty = y - currentY;
        float tz = z - currentZ;

        for (int i = 0; i < 9 * 2; i += 3) {
            vertices[i] += tx;
            vertices[i + 1] += ty;
            vertices[i + 2] += tz;
        }

        for (int i = 0; i < 9 * 2; i += 3) {
            vertices[i] += x;
            vertices[i + 1] += y;
            vertices[i + 2] += z;
        }

        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        //ImGui
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();
}

I'm not sure what to do. I want to have an exact variable to set, not change the size. I'm looking for a solution using glm and I will later put everything in classes.


Solution

  • If you have vertex data for a mesh and want to scale the object without iterating over the mesh data, then a solution would be to let the shader do it for you.

    For that, we only need to introduce a uniform variable in the vertex shader.

    Before the transformation gets applied, we first have to scale the vertex position, e.g.

    //vertex shader
    
    in vec3 aPos;             //position coords
    uniform vec3 uScale;      //scale factor
    uniform mat4 uProjection; //projection matrix
    
    int main()
    {
        gl_Position = uProjection * vec4(aPos * uScale, 1.0);
    }
    

    Usually, that is done via a transformation matrix which is the result of a projection, view and model matrix (hence mvp matrix).

    Then in the vertex shader one has either a single uniform called uMVP or two uniforms, one for the projection and view (which are modified less frequently, at least not for each object) and a model matrix which could be different for each object (different positions, scales and or rotations).

    e.g.

    //vertex shader
    
    in vec3 aPos;
    uniform mat4 uProjection;
    uniform mat4 uView;
    uniform mat4 uModel;
    
    void main()
    {
        gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);
    }