copenglglslglfwstb-image

OpenGL fails to draw textured triangle?


In this program the 3 triangles aren't drawn, even when I replace the texture by vec4(0.0f, 0.5f, 0.0f, 1.0f);, trying to draw the third triangle in green:

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glad/gl.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <errno.h>

#define STB_IMAGE_IMPLEMENTATION
#include "./stb/stb_image.h"

void checkGLError(char * a) {
  GLenum err;
  while((err = glGetError()) != GL_NO_ERROR){
    printf("GL_ERROR: %d (%s)\n",err,a);
  }  
}

const char * vsprog_core =
"#version 330 core\n"
"layout (location = 0) in vec3 vPos;\n"
"layout (location = 1) in vec2 vTexCoords;\n"
"\n"
"out vec2 TexCoords;\n"
"flat out int TexID;\n"
"\n"
"uniform int s;\n"
"\n"
"void main()\n"
"{\n"
"    TexCoords = vTexCoords;\n"
"    TexID = s;\n"
"    gl_Position = vec4(vPos, 1.0f); \n"
"}\n";

const char * fsprog_core =
"#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec2 TexCoords;\n"
"flat in int TexID;\n"
"\n"
"uniform sampler2DArray Textures;\n"
"\n"
"void main()\n"
"{\n"
"      vec2 uv = TexCoords;\n"
"      vec4 t = texture(Textures, vec3(uv, TexID));\n"
"      if(TexID == 2) t = vec4(0.0f, 0.5f, 0.0f, 1.0f);\n"
"      FragColor = t;\n"
"}\n";


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

int main( int argc, char *argv[ ], char *envp[ ] ) { 
  glfwInit();
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  
  glfwWindowHint(GLFW_SAMPLES, 4);
  int width = 800;
  int height = 600;
  GLFWwindow* window = glfwCreateWindow(width, height, "DE", NULL, NULL);
  if (window == NULL) {
    printf("\nFailed to create GLFW window.\n");
    glfwTerminate();
    exit(EXIT_FAILURE);
  }
  glfwMakeContextCurrent(window);
  glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 

  // glad: load all OpenGL function pointers
  if (!gladLoadGL(glfwGetProcAddress)) {
      printf("\nFailed to initialize GLAD.\n");
      glfwTerminate();
      exit(EXIT_FAILURE);
  }
  
  const GLubyte* renderer;
  const GLubyte* version;
  renderer = glGetString(GL_RENDERER);
  version = glGetString(GL_VERSION);
  printf("\nRenderer: %s", renderer);
  printf("\nOpenGL version supported %s\n", version);
  GLint value;
  glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &value);
  printf("\nGL_MAX_ARRAY_TEXTURE_LAYERS: %d\n", value);
  
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  
  glEnable(GL_MULTISAMPLE);
  
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  int texturecnt = 0;
  
  GLuint texture_array;
  glGenTextures(1,&texture_array);
  glBindTexture(GL_TEXTURE_2D_ARRAY,texture_array);
  glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4096, 4096, 8,
               0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  int iwidth, iheight, nrChannels;
  //stbi_set_flip_vertically_on_load(1);
  unsigned char *data = stbi_load("./rock.png", &iwidth, &iheight, &nrChannels, 0);
  if(data) {
    int mode = GL_RED;
    if(nrChannels == 2) mode = GL_RG;
    if(nrChannels == 3) mode = GL_RGB;
    if(nrChannels == 4) mode = GL_RGBA;
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, texturecnt,
                    iwidth, iheight, 1, mode, GL_UNSIGNED_BYTE, data);
    checkGLError("load texture");
  } else {
    printf("\nFailed to load texture: %d.\n",texturecnt);
  }
  stbi_image_free(data);
  
  texturecnt++;
  
  data = stbi_load("./ship.jpg", &iwidth, &iheight, &nrChannels, 0);
  if(data) {
    int mode = GL_RED;
    if(nrChannels == 3) mode = GL_RGB;
    if(nrChannels == 4) mode = GL_RGBA;
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, texturecnt, 
                    iwidth, iheight, 1, mode, GL_UNSIGNED_BYTE, data);
    checkGLError("load texture");
  } else {
    printf("\nFailed to load texture: %d.\n",texturecnt);
  }
  stbi_image_free(data);
  
  texturecnt++;
  
  glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  
  GLfloat vertices[3][3*3] = {
      { -0.5f, -0.5f, 0.0f, // left  
         0.5f, -0.5f, 0.0f, // right 
         0.0f,  0.5f, 0.0f }, // top  
      { -0.5f-1.0, -0.5f, 0.0f, // left  
         0.5f-1.0, -0.5f, 0.0f, // right 
         0.0f-1.0,  0.5f, 0.0f }, // top   
      { -0.5f+1.0, -0.5f, 0.0f, // left  
         0.5f+1.0, -0.5f, 0.0f, // right 
         0.0f+1.0,  0.5f, 0.0f } // top    
    }; 
  
  GLfloat texcoords[3*2] = {
       0.0,  1.0,
       1.0,  1.0,
       0.5,  0.0
  };
  
  GLuint vao[3];  
  GLuint vbo[3];  
  GLuint vbotex[3];
  for(int i=0; i<3; i++) {
    // VAO:
    glGenVertexArrays(1, &(vao[i]));
    glBindVertexArray(vao[i]);

    // VBO:
    glGenBuffers(1,&(vbo[i]));
    glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
    glBufferData(GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), &(vertices[i][0]), GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);

    // VBO:
    glGenBuffers(1,&(vbotex[i]));
    glBindBuffer(GL_ARRAY_BUFFER,vbotex[i]);
    glBufferData(GL_ARRAY_BUFFER, 2 * 3 * sizeof(GLfloat), &texcoords[0], GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER,0);
  }
  // End VAO:
  glBindVertexArray(0);
  
  //////////////////////////////////////////////////////////
  //
  // Shaders:
  //
  GLint params;
  GLint len;

  GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vscore, 1, &vsprog_core, NULL);
  glCompileShader(vscore);
  glGetShaderiv(vscore,GL_COMPILE_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetShaderInfoLog(vscore,100000,&len,log);
    printf("\n\n%s\n\n",log);
    exit(EXIT_FAILURE);
  }

  GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fscore, 1, &fsprog_core, NULL);
  glCompileShader(fscore);
  glGetShaderiv(fscore,GL_COMPILE_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetShaderInfoLog(fscore,100000,&len,log);
    printf("\n\n%s\n\n",log);
    exit(EXIT_FAILURE);
  }

  GLuint shader_program_core = glCreateProgram();
  glAttachShader(shader_program_core, fscore);
  glAttachShader(shader_program_core, vscore);

  glLinkProgram(shader_program_core);
  glGetProgramiv(shader_program_core,GL_LINK_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetProgramInfoLog(shader_program_core,100000,&len,log);
    printf("\n\n%s\n\n",log);
    fflush(stdout);
    exit(EXIT_FAILURE);
  }
  glDeleteShader(vscore);
  glDeleteShader(fscore);
  
  GLuint sloc = glGetUniformLocation(shader_program_core,"s");
  
  
  while(!glfwWindowShouldClose(window)) {
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glUseProgram(shader_program_core);
    glBindTexture(GL_TEXTURE_2D_ARRAY, texture_array);
    
    glBindVertexArray(vao[0]);
    glUniform1i(sloc,0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    glBindVertexArray(vao[1]);
    glUniform1i(sloc,1);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    glBindVertexArray(vao[2]);
    glUniform1i(sloc,2);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
    
    checkGLError("draw");
    
    glfwSwapBuffers(window);
    glfwPollEvents();    
  }
  
  glfwDestroyWindow(window);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}

What am I doing wrong?


Solution

  • The issue in your code, is that you are not clearing the depth buffer, along with the color buffer in your render loop. Since you have depth testing enabled (glEnable(GL_DEPTH_TEST)), the first triangle you draw (at z = 0.0) will write to the depth buffer, causing subsequent triangles to fail the depth test and not be rendered.

    How fix:

    1. Clear the depth buffer along with the color buffer:
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
    2. Disable depth testing if you dont need it:
      glDisable(GL_DEPTH_TEST);
      

    Why this happens:

    Also, i added line in while loop to clear depth too:

    while(!glfwWindowShouldClose(window)) {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Fixed: Clear depth