Search code examples
copenglglslglfw

Artifact in one of the triangles in basic OpenGL texture quadrilateral


I am trying to make the https://learnopengl.com/Getting-started/Textures example in pure C (hate C++) and found this weird problem in my quadrilateral when one of their conforming triangles is being rendered well and the other looks like the vertical texture coordinate has been fixed meanwhile the horizontal is perfectly well. Example

meson.build:

project('snake', 'c',
  version : '0.1',
  default_options : ['warning_level=3'])

cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : true)
openGl = dependency('gl')
glfw3 = dependency('glfw3')

executable('snake',
           'src/main.c',
           'src/shaders.c',
           'src/stb_image.c',
           dependencies : [ m_dep, openGl, glfw3 ],
           install : true)

src/main.h:

#include <stdlib.h>
#include <stdio.h>
#include <GLFW/glfw3.h>
#include <sys/stat.h>
#include "shaders.h"
#include "stb_image.h"

// https://learnopengl.com/Getting-started/Transformations

static void error_callback(int error, const char* description) {
  fprintf(stderr, "ERROR: Beschreibung: %s und Code: %i\n", description, error);
}

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

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

int main(int argc, char **args) {
  GLFWwindow* window;
  glfwSetErrorCallback(error_callback);

  if (!glfwInit()) {
    return EXIT_FAILURE;
  }

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  // sk_init();
  window = glfwCreateWindow(1024, 720, "SNAKE", NULL, NULL);

  if (!window) {
    perror("Failed to create GLFW\n");
    glfwTerminate();
    return EXIT_FAILURE;
  }

  printf("Ein GLFW Fenster habt geschaffen\n");

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

  glViewport(0, 0, 1024, 702);

  GLint shaderProgram;
  shader_from_path("../shaders/ve1.glsl", "../shaders/fr1.glsl", &shaderProgram);

  float vertices[] = {
    // positions          // colors           // texture coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   0.0f, 1.0f, 1.0f,   0.0f, 1.0f  // top left
  };

  unsigned int indices[] = {  // note that we start from 3!
    3, 2, 0,
    2, 1, 0,
  };

  unsigned int VBO, EBO, VAO;
  glGenVertexArrays(1, &VAO);
  glGenBuffers(1, &VBO);
  glGenBuffers(1, &EBO);

  glBindVertexArray(VAO);

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

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3* sizeof(float)));
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6* sizeof(float)));
  glEnableVertexAttribArray(2);

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

  GLuint texture;
  glGenTextures(1, &texture);
  glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture
  glBindTexture(GL_TEXTURE_2D, texture);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

  int width, height, nrChannels;

  unsigned char *data = stbi_load("wall.jpg", &width, &height, &nrChannels, 0);

  if (data) {
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, width, height);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
    //glGenerateMipmap(GL_TEXTURE_2D);
  } else {
    fprintf(stderr, "Failed to load texture\n");
  }

  stbi_image_free(data);

  glMatrixMode(GL_PROJECTION);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  //glfwSetKeyCallback(window, onKey);

  while (!glfwWindowShouldClose(window)) {
    processInput(window);

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

    glUseProgram(shaderProgram);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glfwPollEvents();
    glfwSwapBuffers(window);
  }

  glDeleteVertexArrays(1, &VAO);
  glDeleteBuffers(1, &VBO);
  glDeleteBuffers(1, &EBO);
  glDeleteProgram(shaderProgram);

  glfwTerminate();
  return EXIT_SUCCESS;
}

src/shaders.h:

#ifndef SHADERS_H_
#define SHADERS_H_

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <GLFW/glfw3.h>

void shader_from_path(const char* vertexPath, const char* fragmentPath, GLuint* ID);

#endif // SHADERS_H_

src/shaders.c:

#include "shaders.h"
#include <sys/stat.h>

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";


struct TextBuffer {
  char* inhalt;
  size_t size;
};

static void checkCompileErrors(const GLint handler) {
  int success;
  char infoLog[512];
  for (int i = 0; i < 512; i++) {
    infoLog[i] = 0;
  }

  glGetShaderiv(handler, GL_COMPILE_STATUS, &success);
  if (&success) {
    glGetShaderInfoLog(handler, 512, NULL, infoLog);
    fwrite(infoLog, sizeof(char), 512, stderr);
  }
}

static int openAndReadPath(const char* path, struct TextBuffer* store) {
  struct stat st;
  FILE *file = fopen(path, "r");
  if (!file) {
    printf("Konnt nicht lesen: %s\n", path);
    return 0;
  }

  stat(path, &st);
  store->size = st.st_size;

  store->inhalt = (char*) malloc(sizeof(char) * (store->size + 1));
  fread(store->inhalt, sizeof(char), store->size, file);
  fwrite(store->inhalt, sizeof(char), store->size, stdout);
  fclose(file);

  return 1;
}

void shader_from_path(const char* vertexPath, const char* fragmentPath, GLuint* ID) {
  struct TextBuffer vertexTextBuffer;
  struct TextBuffer fragmentTextBuffer;

  openAndReadPath(vertexPath, &vertexTextBuffer);
  openAndReadPath(fragmentPath, &fragmentTextBuffer);

  GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertexShader, 1, &vertexTextBuffer.inhalt, &vertexTextBuffer.size);
  glCompileShader(vertexShader);
  checkCompileErrors(vertexShader);

  GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragmentShader, 1, &fragmentTextBuffer.inhalt, &fragmentTextBuffer.size);
  glCompileShader(fragmentShader);
  checkCompileErrors(fragmentShader);

  *ID = glCreateProgram();
  glAttachShader(*ID, vertexShader);
  glAttachShader(*ID, fragmentShader);
  glLinkProgram(*ID);
  checkCompileErrors(*ID);

  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);

  if (vertexTextBuffer.inhalt) {
    free(vertexTextBuffer.inhalt);
  }
  if (fragmentTextBuffer.inhalt) {
    free(fragmentTextBuffer.inhalt);
  }
}

src/stb_image.c:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

src/stb_image.h: https://raw.githubusercontent.com/nothings/stb/master/stb_image.h shaders/fr1.glsl:

#version 330 core
out vec4 FragColor;

in vec3 vertexColor;
in vec2 TexCoord;
// uniform vec4 ourColor;

uniform sampler2D ourTexture;

void main()
{
    FragColor = texture(ourTexture, TexCoord); // vec4(vertexColor, 1.0);
}

shaders/ve1.glsl:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 vertexColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = aColor;
    TexCoord = aTexCoord;
}

Solution

  • The second parameter of glVertexAttribPointer specifies how many elements should be read. Since the uv coordinates consist of two elements only, the line

    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6* sizeof(float)));
    

    needs to be replaced with

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6* sizeof(float)));
    

    Please also check for OpenGL errors, either by calling glGetError(), or by setting up a debug callback. Since you are using a 3.3 core profile, methods like glMatrixMode are deprecated and should result in an GL_INVALID_OPERATION error.