I am having a problem with rendering a quad in opengl via 4 lines (5 vertices via GL_LINE_STRIP). The rendering is generally working fine in terms of connecting the lines into a quad. The problem is, that the lines in the bottom left corner are not connected. Following screenshot shows what I am talking about. Left is a screenshot from the entire scene, right a close up zoom in where one can see that the lines do not connect correctly.

The coordinates for the corner vertices in NDC are (x,y)
top left -0.5, 0.5
bottom left -0.5, -0.5
bottom right 0.5, -0.5
top right 0.5, 0.5
I really tried to wrap my head around where this is coming from but I couldn't figure it out and I also didn't find any helpful information on the internet.
I included a working minimal example in c++. Maybe someone can help me find out where this is coming from. I am using Visual Studio 2017, OpenGL 460 core, glfw3 and glad 0.1.29.
Main program:
//cpp
#include <iostream>
#include <vector>
#include <cstdio>
//opengl, etc.
#include <glad/glad.h>
#include <glfw/glfw3.h>
//own
#include <shader.h>
//forward declarations
GLFWwindow* initOpenGL(const int pScreenWidth, const int pScreenHeight);
void framebufferSizeCallback(GLFWwindow *window, int width, int height);
int main(int argc, char *args[])
{
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 800;
GLFWwindow *window = initOpenGL(SCREEN_WIDTH, SCREEN_HEIGHT);
Shader shader("shader_code/vertex_shader_quad.glsl", "shader_code/fragment_shader_quad.glsl");
shader.use();
glfwSwapInterval(1);
std::vector<float> quadVertices;
quadVertices.push_back(-0.5f);
quadVertices.push_back(0.5f);
quadVertices.push_back(-0.5f);
quadVertices.push_back(-0.5f);
quadVertices.push_back(0.5f);
quadVertices.push_back(-0.5f);
quadVertices.push_back(0.5f);
quadVertices.push_back(0.5f);
quadVertices.push_back(-0.5f);
quadVertices.push_back(0.5f);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
unsigned int vbo, vao;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, quadVertices.size() * sizeof(float), &quadVertices.front(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_LINE_STRIP, 0, (quadVertices.size() / 2));
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwSwapBuffers(window);
glfwPollEvents();
//let program run until button is pressed
std::getchar();
}
GLFWwindow* initOpenGL(const int pScreenWidth, const int pScreenHeight)
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(pScreenWidth, pScreenHeight, "OpenGLRenderer", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create glfw window" << std::endl;
glfwTerminate();
return NULL;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return NULL;
}
return window;
}
void framebufferSizeCallback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
Shaders:
vertex shader:
#version 460 core
layout (location=0) in vec2 inPos;
out vec3 vertexColor;
void main()
{
gl_Position = vec4(inPos, 0.0f, 1.0f);
vertexColor = vec3(0.91f, 0.84f, 0.42f);
}
fragment shader
#version 460 core
in vec3 vertexColor;
out vec4 color;
void main()
{
color = vec4(vertexColor, 1.0f);
}
Custom Shader Class:
#include <shader.h>
Shader::Shader(const char *pVertexPath, const char *pFragmentPath)
{
std::string vertexCodeInput, fragmentCodeInput;
std::ifstream vertexFile, fragmentFile;
vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
vertexFile.open(pVertexPath);
fragmentFile.open(pFragmentPath);
std::stringstream vertexFileStream, fragmentFileStream;
vertexFileStream << vertexFile.rdbuf();
fragmentFileStream << fragmentFile.rdbuf();
vertexFile.close();
fragmentFile.close();
vertexCodeInput = vertexFileStream.str();
fragmentCodeInput = fragmentFileStream.str();
}
catch(std::fstream::failure eX)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderSource = vertexCodeInput.c_str();
const char* fShaderSource = fragmentCodeInput.c_str();
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vShaderSource, NULL);
glCompileShader(vertexShader);
//check compilation result
int success;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
char vShaderInfoLog[1024];
glGetShaderInfoLog(vertexShader, 1024, NULL, vShaderInfoLog);
std::cout << "Error::SHADER::VERTEX::COMPILATION_FAILED" << std::endl << vShaderInfoLog << std::endl;
}
success = 0;
//FRAGMENT SHADER
//create shader, load shader code, compile shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
char fShaderInfoLog[1024];
glGetShaderInfoLog(fragmentShader, 1024, NULL, fShaderInfoLog);
std::cout << "Error::SHADER::FRAGMENT::COMPILATION_FAILED" << std::endl << fShaderInfoLog << std::endl;
}
success = 0;
//create shader program, attach shaders
id = glCreateProgram();
glAttachShader(id, vertexShader);
glAttachShader(id, fragmentShader);
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success)
{
char shaderProgramInfoLog[1024];
glGetProgramInfoLog(id, 1024, NULL, shaderProgramInfoLog);
std::cout << "Error::SHADER::PROGRAM::COMPILATION_FAILED" << std::endl << shaderProgramInfoLog << std::endl;
}
success = 0;
//already linked shaders can be deleted
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void Shader::use()
{
glUseProgram(id);
}
void Shader::setBoolUniform(const std::string pUniformName, const bool pValue) const
{
glUniform1i(glGetUniformLocation(id, pUniformName.c_str()), (int)pValue);
}
void Shader::setFloatUniform(const std::string pUniformName, const float pValue) const
{
glUniform1f(glGetUniformLocation(id, pUniformName.c_str()), pValue);
}
void Shader::setIntUniform(const std::string pUniformName, const unsigned int pValue) const
{
unsigned int uniformLocation = glGetUniformLocation(id, pUniformName.c_str());
glUniform1i(glGetUniformLocation(id, pUniformName.c_str()), pValue);
}
Thanks in advance!