c++openglglsl2dglfw

OpenGL viewport is of incorrect dimensions compared to window set to same dimension


I have a window of 600x400, the viewport on which OpenGL is rendering appears to be much smaller (pictured below).

Picture of the viewport I'm expecting and the viewport I'm getting, note most of the square is clipped out.

The below code is able to reproduce what I am seeing. This code is also almost the exact same as the sprite renderer shown by learnopengl.com in their In Practice section.

main.cpp

#include <iostream>
#include <fstream>
#include <sstream>

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


int main() {
  if (glfwInit()) { // initialise GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  } else {
    std::cout << "glfw failed to initialise" << std::endl;
  }
  
  GLFWwindow *window = glfwCreateWindow(600, 400, "window", NULL, NULL); // creates window of 600x400

  if (window == NULL) {
    std::cout << "Window creation failed" << std::endl;
  }

  glfwMakeContextCurrent(window);

  if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { // load glad
    std::cout << "Failed to initialise glad" << std::endl;
  }

  glViewport(0, 0, 600, 400); // set viewport to 600x400 with (0,0) on the lower left corner

  // initialise the rendering objects
  unsigned int VAO, VBO;

  float vertices[] = {
    0.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.0f,

    0.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 1.0f, 1.0f, 1.0f,
    1.0f, 0.0f, 1.0f, 0.0f
  };

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

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

  glBindVertexArray(VAO);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);

  // Unbind the VAO and VBO
  glBindVertexArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);

  // load the vertex and fragment shdaer
  unsigned int shaderID;

  std::string vertexCode;
  std::string fragmentCode;
  std::ifstream vertexShaderFile;
  std::ifstream fragmentShaderFile;

  vertexShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  fragmentShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

  try {
    vertexShaderFile.open(".../SpriteShader.vs");
    fragmentShaderFile.open(".../SpriteShader.fs");

    std::stringstream vertexShaderStream, fragmentShaderStream;

    vertexShaderStream << vertexShaderFile.rdbuf();
    fragmentShaderStream << fragmentShaderFile.rdbuf();

    vertexShaderFile.close();
    fragmentShaderFile.close();

    vertexCode = vertexShaderStream.str();
    fragmentCode = fragmentShaderStream.str();
  } catch (std::ifstream::failure e) {
    std::cout << "Shader file could not be successfully read " << e.what() << std::endl;
  }

  const char *vertexShaderCode = vertexCode.c_str();
  const char *fragmentShaderCode = fragmentCode.c_str();

  unsigned int vertexShader, fragmentShader;

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

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

  int success;
  char infoLog[512];

  glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

  if (!success) {
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);

    std::cout << "Vertex Shader could not be compiled " << infoLog << std::endl;
  }

  glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);

  if (!success) {
    glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);

    std::cout << "Fragment Shader could not be compiled " << infoLog
              << std::endl;
  }

  shaderID = glCreateProgram();
  glAttachShader(shaderID, vertexShader);
  glAttachShader(shaderID, fragmentShader);
  glLinkProgram(shaderID);

  glGetProgramiv(shaderID, GL_LINK_STATUS, &success);

  if (!success) {
    glGetProgramInfoLog(shaderID, 512, NULL, infoLog);

    std::cout << "Could not link program " << infoLog << std::endl;
  }

  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);

  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

  while (!glfwWindowShouldClose(window)) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(shaderID);

    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(580.0f, 380.0f, 0.0f));
    model = glm::scale(model, glm::vec3(50.0f, 50.0f, 1.0f));

    glUniformMatrix4fv(glGetUniformLocation(shaderID, "model"), 1, GL_FALSE,
                   glm::value_ptr(model));

    glm::mat4 projection = glm::ortho(0.0f, 600.0f, 0.0f, 400.0f, -1.0f, 1.0f);

    glUniformMatrix4fv(glGetUniformLocation(shaderID, "projection"), 1, GL_FALSE,
                   glm::value_ptr(projection));

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

    glBindVertexArray(0);

    glfwPollEvents();
    glfwSwapBuffers(window);
  }

  glfwDestroyWindow(window);
  glfwTerminate();

  std::cout << "Destroyed" << std::endl;
}

SpriteShader.vs

#version 400 core
layout (location = 0) in vec4 vertex; 

out vec2 TexCoords;

uniform mat4 model;
uniform mat4 projection;

void main()
{
    TexCoords = vertex.zw;
    gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}

SpriteShader.fs

#version 400 core

in vec2 TexCoords;
out vec4 FragColour;

void main()
{    
    FragColour = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

I am using GLFW for window management and glad as my library for OpenGL. This was done on a Linux (KDE Neon) system using wayland.

I believe this is likely a problem with one of my matrices, be it the projection or model. I am however unsure of what the problem is or how to fix it.


Solution

  • The window can be scaled. You have to use the size of the frame buffer for the size of the viewport:

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);