Search code examples
c++openglviewportglfwopengl-3

Is there a way to prevent the contents of my window from "moving" when i resize the window in OpenGL


I would like my window contents to stay centered when my window resizes. OpenGL (or GLFW) - I'm not sure which - does give this desired effect when resizing horizontally, however when i resize the window vertically the window appears to show the more of the bottom of the cube. I expected it to cut off the cube like when resizing horizontally,

This is the horizontal resize Horizontal Resize

And this is the vertical resize Vertical Resize

Note: I do not make any glViewPort() otherwise the window contents would adjust to the new width and height.

Is there any way to change this behaviour? This question may be related but i don't believe that is solves my problem. How to keep the OpenGL viewport in an SDL window stationary ...

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

#include "../includes/Shader.h"
#include "../includes/Texture.h"
#include "../includes/glm/glm.hpp"


const int SCR_WIDTH = 800;
const int SCR_HEIGHT = 600;

void framebuffer_size_callback(GLFWwindow *window, int width, int height);

void processInput(GLFWwindow *window);

int main() {

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL", nullptr, nullptr);
    if (window == nullptr) {
        std::cout << "Failed to create window! " << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        std::cout << "Failed to initialize GLEW! " << std::endl;
        glfwTerminate();
        return -1;
    }

    float vertices[] = {
            ...
    };

    unsigned int VAO, VBO;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (GLvoid *) nullptr);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (GLvoid *) (sizeof(float) * 3));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    Texture texture1("../images/container.jpg");
    Texture texture2("../images/awesomeface.png");

    Shader shader("../shaders/shader.vs", "../shaders/shader.fs");

    shader.use();
    shader.setUniform1i("texture1", 0);
    shader.setUniform1i("texture2", 1);


    while (!glfwWindowShouldClose(window)) {

        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glEnable(GL_DEPTH_TEST);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        texture1.bind(0);
        texture2.bind(1);

        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = glm::mat4(1.0f);
        glm::mat4 projection = glm::mat4(1.0f);

        model = glm::rotate(model, (float) glfwGetTime(), glm::vec3(1.0f, 0.5f, 0.5f));
        view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
        projection = glm::perspective(glm::radians(45.0f), 800.0f/600.0f, 0.1f, 100.0f);

        shader.setUniformMat4("model", model);
        shader.setUniformMat4("view", view);
        shader.setUniformMat4("projection", projection);

        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
    //glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

Solution

  • Note: I do not make any glViewPort() otherwise the window contents would adjust to the new width and height.

    This is the problem. You need to adjust the viewport. Adjust the field of view depending on the viewport:

    const float defaultHeight = 600.0f;
    const float defaultFov = glm::radians(45.0f);
    
    while (!glfwWindowShouldClose(window)) {
    
        // [...]
    
        int vpSize[2];
        glfwGetFramebufferSize(window, &vpSize[0], &vpSize[1]);
        glViewport(0, 0, vpSize[0], vpSize[1]);
    
        float aspect = (float)vpSize[0] / (float)vpSize[1];
        float fov = asin(sin(defaultFov / 2.0f) * vpSize[1] / defaultHeight) * 2.0f;
        glm::mat4 projection = glm::perspective(fov, aspect, 0.1f, 100.0f);
    
        // [...]
    }