Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: FBOs for color picking

  1. #1
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    8

    FBOs for color picking

    Hi all, I would like to use the color method for picking with a separate FBO. I have run into the problem that, even though AFAICT I have setup the FBO identically to the default framebuffer, which renders fine, the underlying FBO rendering is not correct.

    In an attempt to make a MWE, I ran into another problem where my simple triangle renders white instead of colored. I am not particularly concerned with this issue, but really I am wondering if the workflow I am employing is sensible and if there are any obvious problems. Thank you for your help.

    The boilerplate from an existing simple triangle example:

    Code :
    #include <iostream>
    #include <vector>
    #include <GL/glew.h> // include GLEW and new version of GL on Windows
    #include <GLFW/glfw3.h> // GLFW helper library
    #include <stdio.h>
     
    int main() {
     
      // start GL context and O/S window using the GLFW helper library
      if (!glfwInit()) {
        fprintf(stderr, "ERROR: could not start GLFW3\n");
        return 1;
      }
     
      int width = 640;
      int height = 480;
     
      GLFWwindow* window = glfwCreateWindow(width, height, "Hello Triangle", NULL, NULL);
      if (!window) {
        fprintf(stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
      }
      glfwMakeContextCurrent(window);
     
      // start GLEW extension handler
      glewExperimental = GL_TRUE;
      glewInit();
     
      // get version info
      const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
      const GLubyte* version = glGetString(GL_VERSION); // version as a string
      printf("Renderer: %s\n", renderer);
      printf("OpenGL version supported %s\n", version);
     
      // tell GL to only draw onto a pixel if the shape is closer to the viewer
      glEnable(GL_DEPTH_TEST); // enable depth-testing
      glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
      glDepthMask(GL_TRUE); // Enable depth test (z-buffer)

    The FBO, VAO, and Program setup:
    Code :
      ////////////////// Setup VBO ///////////////////
      float points[] = {
       0.0f,  0.5f,  0.0f,
       0.5f, -0.5f,  0.0f,
      -0.5f, -0.5f,  0.0f
      };
     
      uint8_t colors[] = {
       100,  100,  0,
       100,  100,  0,
       100,  100,  0
      };
     
      uint8_t colors_fbo[] = {
       100,  0,  100,
       100,  0,  100,
       100,  0,  100
      };
     
      uint32_t indices[] = {0, 1, 2}; // one triangle
     
     
      GLuint vao = 0;
      std::vector<GLuint> vbos;
      glGenVertexArrays(1, &vao);
      glBindVertexArray(vao);
     
      vbos.resize(3); // xyz, colors, indices
      glGenBuffers(3, vbos.data());
     
      glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
      glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);
      glEnableVertexAttribArray(0);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
     
      glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
      glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(uint8_t), colors, GL_STATIC_DRAW);
      glEnableVertexAttribArray(1);
      glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
     
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[2]);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(uint32_t), indices, GL_STATIC_DRAW);
      //  glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindVertexArray(0);
      /////////////////////////////////////////
     
      //////////////////// Setup FBO //////////
      GLuint fbo = 0;
      GLuint color = 0;
      GLuint depth = 0;
      GLuint fbo_vao = 0;
      std::vector<GLuint> fbo_vbos;
     
      glGenFramebuffers(1, &fbo);
      glBindFramebuffer(GL_FRAMEBUFFER, fbo);
      glGenTextures(1, &color);
      glBindTexture(GL_TEXTURE_2D, color);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                             color, 0);
     
      glGenRenderbuffers(1, &depth);
      glBindRenderbuffer(GL_RENDERBUFFER, depth);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
      GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
      if (status != GL_FRAMEBUFFER_COMPLETE){
        std::cerr<<"Framebuffer fail, :"<<status<<std::endl;
      }
     
      // same points, different colors
      glGenVertexArrays(1, &fbo_vao);
      glBindVertexArray(fbo_vao);
      fbo_vbos.resize(3);
      glGenBuffers(3, fbo_vbos.data());
      glBindBuffer(GL_ARRAY_BUFFER, fbo_vbos[0]);
      glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);
      glEnableVertexAttribArray(0);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
     
      glBindBuffer(GL_ARRAY_BUFFER, fbo_vbos[1]);
      glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(uint8_t), colors_fbo, GL_STATIC_DRAW);
      glEnableVertexAttribArray(1);
      glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
     
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, fbo_vbos[2]);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(uint32_t), indices, GL_STATIC_DRAW);
     
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
      ////////////////////////////////////////
     
     
      /////////////////// Setup Program ///////
      const char* vertex_shader =
        "#version 330 core\n"
        "layout (location = 0) in vec3 position;"
        "layout (location = 1) in vec3 color;"
        "flat out vec3 vColor;"
        "void main() {"
        "  vColor = color;"
        "  gl_Position = vec4(vp, 1.0);"
        "}";
     
      const char* fragment_shader =
        "#version 330 core\n"
        "flat in vec3 vColor;"
        "out vec4 fColor;"
        "void main() {"
        "  fColor = vec4(vColor, 1.0f);"
        "}";
     
      GLuint vs = glCreateShader(GL_VERTEX_SHADER);
      glShaderSource(vs, 1, &vertex_shader, NULL);
      glCompileShader(vs);
      GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
      glShaderSource(fs, 1, &fragment_shader, NULL);
      glCompileShader(fs);
     
      GLuint shader_programme = glCreateProgram();
      glAttachShader(shader_programme, fs);
      glAttachShader(shader_programme, vs);
      glLinkProgram(shader_programme);
      ///////////////////////////////////////////

    The render loop:
    Code :
      float pixel_value[3];
      while(!glfwWindowShouldClose(window)) {
        // wipe the drawing surface clear
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(shader_programme);
     
        // write to, read from default buffer
        glBindVertexArray(vao);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
        glReadPixels(320, 240, 1, 1, GL_RGB, GL_FLOAT, pixel_value);
        std::cout<<" Pixel value default buffer: "<<pixel_value[0]<<" "<<pixel_value[1]<<" "<<pixel_value[2]<<std::endl;
        glBindVertexArray(0);
     
        // write to, read from fbo
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glBindVertexArray(fbo_vao);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
        glReadPixels(320, 240, 1, 1, GL_RGB, GL_FLOAT, pixel_value);
        std::cout<<" Pixel value fbo: "<<pixel_value[0]<<" "<<pixel_value[1]<<" "<<pixel_value[2]<<std::endl;
        glBindVertexArray(0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
        glfwPollEvents();
        // put the stuff we've been drawing onto the display
        glfwSwapBuffers(window);
      }
     
      // close GL context and any other GLFW resources
      glfwTerminate();
      return 0;
    }

    Simple makefile:
    Code :
    OBJS = fbo_mwe.o
     
    minimalfbo: $(OBJS)
    	$(CC) -o fbo_mwe $(OBJS) -lm -lGL -lGLU -lGLEW -lglut -lglfw -lstdc++

  2. #2
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    453
    error checking is crucial, i dont see that in your code
    https://sites.google.com/site/john87...er/error-check

    having a GL debug context can help you much more because instead of simple error codes you get detailed descriptions for the error
    https://sites.google.com/site/john87.../debug-context

    instead of "color" picking, you can render exact integers into an separate FBO attachment (integer texture). and instead of stalling the pipeline when reading back pixels of the FBO, you can use a double-buffered GL_PIXEL_PACK_BUFFER and read from the one that isnt used in the current frame.

  3. #3
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    8
    Thanks for the tip on the debug context (I have appropriate error checking in my actual program), that will be very helpful going forward.

    Quote Originally Posted by john_connor View Post
    instead of "color" picking, you can render exact integers into an separate FBO attachment (integer texture).
    This would be perfect for my project. So, please tell me if I am understanding correctly. In the FBO, I will still have my renderbuffer for point locations, but now in the texture2D buffer I will directly set labels as integers instead of color vecs, where the integers are still output by the fragment shader. Then, calling readpixels will give me the original integer value I set in the shader. Saying it now, it makes complete sense, I was still thinking of rendering from a visual perspective rather than simply as generic data.

    Quote Originally Posted by john_connor View Post
    and instead of stalling the pipeline when reading back pixels of the FBO, you can use a double-buffered GL_PIXEL_PACK_BUFFER and read from the one that isnt used in the current frame.
    This is something I had planned on but have no experience with. I will look to gain some, but particularly helpful links* are always appreciated!

    * I thought I had thoroughly scoured for all decent opengl material and tutorials, but somehow had not seen yours. They look outstanding and invaluable to me, thank you for putting them all together!
    Last edited by phil0stine; 12-26-2017 at 09:13 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •