为什么我在使用 GL_R32I 渲染缓冲区格式的 OpenGL 中得到浮点数而不是整数像素值?

问题描述 投票:0回答:0

在 nVidia GPU 上使用 OpenGL 4.5。我需要生成一个具有 32 位整数像素的图像,但我得到的是浮点值。

我正在使用以内部格式 GL_R32I 创建的渲染缓冲区。这被记录为非规范化整数格式; OGL 运行时报告它完全支持写入和读取。

OpenGL 将读取缓冲区内部格式报告为 GL_RED_INTEGER,将像素类型报告为 GL_INT。我可以通过在 glClearColor() 中将一个 int 转换为浮点数来在渲染缓冲区中放置不同的整数值,并且 glReadPixels() 完整地返回这些位模式。

为了测试,我将缓冲区初始化为 -1。片段着色器为每个三角形输出一个整数,但输出图像包含等效的浮点值。

代码如下:

/* render a triangle index image 
*  vertex coords on pixel grid
*  origin upper left
*  pixel value is triangle id
*/

static const char* index_vs_text =
"#version 450\n"
"uniform mat4 MVP;\n"
"layout(location = 0) in vec2 vPos;\n"
"layout(location = 1) in int Tdx;\n"
"out flat int tid;\n"
"void main()\n"
"{\n"
"    gl_Position = MVP * vec4(vPos, -1.0, 1.0);\n"
"    tid = Tdx;\n"
"}\n";

static const char* index_fs_text =
"#version 450\n"
"layout(origin_upper_left) in vec4 gl_FragCoord;\n"
"in flat int tid;\n"
"out unsigned int color;\n"
"void main()\n"
"{\n"
"   color = tid;\n"
"}\n";

bool GLops::tridx_image(
    int width,
    int height,
    int* pixels,    // result array
    int ntris,      // number of triangles
    int* pvtids,    // vertex indices, 3 per tri
    int nverts,     // number of vertices
    float* verts    // 2D vertex coordinates
) {
    if (window == 0)
        return false;

    /* convert input to canonical arrays that can be
       rendered with glDrawArrays:
    * vpos  3 {x, y} coords per triangle (y inverted)
    * vtid  triangle id 3 times per tri
    */
    int nv = 3 * ntris,
        nc = 2 * nv;
    vector<float> vvpos(nc);
    vector<int> vvtid(nv);
    float* vpos = vvpos.data(),
        * pos = vpos;
    int* vtid = vvtid.data(),
       * pid = vtid,
       * pdx = pvtids;
    for (int itri = 0; itri < ntris; itri++, pid += 3, pdx += 3 ) {
        pid[0] = pid[1] = pid[2] = itri;
        for (int i = 0; i < 3; i++, pos += 2) {
            int j = 2 * pdx[i];
            pos[0] = verts[j++];
            pos[1] = verts[j];
        }
    }

    /* model/view/projection matrix */
    glm::mat4 mvp = glm::ortho(
        0.f, float(width),
        0.f, float(height),
        0.5f, 1.5f
    );

    GLuint vao, fbo, rbo,
        vertex_buffer, tid_buffer,
        vertex_shader, fragment_shader, program;
    GLint mvp_loc, vpos_loc, tid_loc;

    glfwMakeContextCurrent(window);
    gladLoadGL(glfwGetProcAddress);

    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &index_vs_text, NULL);
    glCompileShader(vertex_shader);
    if (compile_error(vertex_shader, "tridx vs"))
        return false;

    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &index_fs_text, NULL);
    glCompileShader(fragment_shader);
    if(compile_error(fragment_shader, "tridx fs"))
        return false;

    program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glBindFragDataLocation(program, 0, "fragcolor");
    glLinkProgram(program);
    if (program_error(program, "tridx"))
        return false;

    mvp_loc = glGetUniformLocation(program, "MVP");
    vpos_loc = glGetAttribLocation(program, "vPos");
    tid_loc = glGetAttribLocation(program, "Tdx");

    glUseProgram(program);
    glUniformMatrix4fv(mvp_loc, 1, GL_FALSE, (const GLfloat*)&mvp);

    if (ogl_error("tridx link"))
        return false;

    if (pixels == 0)
        return false;

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vertex_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, nv * 2 * sizeof(float), vpos, GL_STATIC_DRAW);
    glEnableVertexAttribArray(vpos_loc);
    glVertexAttribPointer(vpos_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glGenBuffers(1, &tid_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, tid_buffer);
    glBufferData(GL_ARRAY_BUFFER, nv * sizeof(int), vtid, GL_STATIC_DRAW);
    glEnableVertexAttribArray(tid_loc);
    glVertexAttribPointer(tid_loc, 1, GL_INT, GL_FALSE, 0, 0);

    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    GLenum RBfmt = GL_R32I;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(
        GL_RENDERBUFFER,
        RBfmt,
        width,
        height
    );
    glFramebufferRenderbuffer(
        GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0,
        GL_RENDERBUFFER,
        rbo
    );

    if (ogl_error("tridx buffers"))
        return false;

    /* check validity of renderbuffer format */
    GLint RBparms[4] = { 0,0,0,0 };
    GLenum supp_full = GL_FULL_SUPPORT,
        supp_caveat = GL_CAVEAT_SUPPORT,
        supp_none = GL_NONE;
    glGetInternalformativ(
        GL_RENDERBUFFER,
        RBfmt,
        GL_INTERNALFORMAT_SUPPORTED,
        4,
        RBparms
    );
    glGetInternalformativ(
        GL_RENDERBUFFER,
        RBfmt,
        GL_COLOR_RENDERABLE,
        3,
        RBparms + 1
    );
    glGetInternalformativ(
        GL_RENDERBUFFER,
        RBfmt,
        GL_FRAMEBUFFER_RENDERABLE,
        2,
        RBparms + 2
    );
    glGetInternalformativ(
        GL_RENDERBUFFER,
        RBfmt,
        GL_READ_PIXELS,
        1,
        RBparms + 3
    );

    GLenum fbs = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
    if (fbs != GL_FRAMEBUFFER_COMPLETE)
        return false;

    glViewport(0, 0, width, height);
    int bg = -1;
    glClearColor(*(float*)&bg, 0.f, 0.f, 0.f);
    glClear(GL_COLOR_BUFFER_BIT);

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glDisable(GL_SCISSOR_TEST);
    glDisable(GL_STENCIL_TEST);

    glDrawArrays(
        GL_TRIANGLES, 0, nv
    );

    glFinish();
 
    if(ogl_error("tridx render"))
        return false;

    GLint 
        rdfmt,  // gets GL_RED or GL_RED_INTEGER
        rdtyp;  // gets GL_FLOAT or GL_UNSIGNED_INT
    glGetFramebufferParameteriv(
        GL_READ_FRAMEBUFFER,
        GL_IMPLEMENTATION_COLOR_READ_FORMAT,
        &rdfmt  
    );
    glGetFramebufferParameteriv(
        GL_READ_FRAMEBUFFER,
        GL_IMPLEMENTATION_COLOR_READ_TYPE,
        &rdtyp  
    );

    glReadPixels(0, 0, width, height, rdfmt, rdtyp, pixels);

    if (ogl_error("tridx read"))
        return false;

    return true;
}

c++ opengl pixel
© www.soinside.com 2019 - 2024. All rights reserved.