首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在OpenGL中正确使用stencil_texturing

在OpenGL中正确使用stencil_texturing
EN

Stack Overflow用户
提问于 2013-05-10 00:03:02
回答 1查看 650关注 0票数 0

我正在尝试实现OpenGL的stencil_texturing扩展,作为一个概念验证。我的显卡最高支持GL 4.3,所以我可以使用stencil_texturing。如果需要更多的说明,这里提供了规范:http://www.opengl.org/registry/specs/ARB/stencil_texturing.txt

所以我测试的目标是将我的颜色缓冲区渲染到帧0中的纹理,然后渲染到帧1中的深度缓冲区,最后渲染到帧2中的模板缓冲区。简单的部分已经完成,我已经很好地渲染了颜色和深度缓冲区纹理。我的问题出在模板缓冲区上,我认为问题要么来自于我对模板缓冲区的理解不足(很可能就是这样),要么就是我对stencil_texturing的滥用。我试着在网上找到一些信息,但几乎没有什么可用的。

为了让您对我在这里渲染的内容有一个概念,这里是我当前的帧捕获:Color bufferDepth bufferStencil buffer

所以我对模板缓冲区的设想是将中间三角形模版出来,这样中间三角形中的所有东西的值都是1,纹理的每个部分都有值0。我不确定渲染时会出现这种情况,但我认为模板值为1的区域与值为0的区域会有所不同。

下面是我的代码。这只是一个测试类,我将其放入我为他们创建的框架中。我认为唯一没有定义的是GLERR(),它基本上调用glGetError()来确保一切都是正确的。

代码语言:javascript
复制
   typedef struct
   {
     GLuint program;
     GLuint vshader;
     GLuint fshader;
   } StencilTexturingState;

   class TestStencilTexturing : public TestInfo
   {
    public:
    TestStencilTexturing(TestConfig& config, int argc, char** argv) 
        :width(config.windowWidth), height(config.windowHeight)
    { 
        state = (StencilTexturingState*) malloc(sizeof(StencilTexturingState));
    }

    ~TestStencilTexturing() 
    {
        destroyTestStencilTexturing();
    }

    void loadFBOShaders()
    {
        const char* vshader = "assets/stencil_texturing/fbo_vert.vs";
        const char* fshader = "assets/stencil_texturing/fbo_frag.fs";

        state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
        GLERR();
        state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
        GLERR();
        state->program = Link(state->vshader, state->fshader, 1, "inPosition");
        GLERR();

        glUseProgram(state->program);
    }

    void loadTextureShaders()
    {
        const char* vshader = "assets/stencil_texturing/tex_vert.vs";
        const char* fshader = "assets/stencil_texturing/tex_frag.fs";

        state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
        GLERR();
        state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
        GLERR();
        state->program = Link(state->vshader, state->fshader, 1, "inPosition");
        GLERR();

        glUseProgram(state->program);
    }

    void destroyTestStencilTexturing()
    {
        glUseProgram(0);
        glDeleteShader(state->vshader);
        glDeleteShader(state->fshader);
        glDeleteProgram(state->program);
        free(state);
    }

    void RenderToTexture(GLuint renderedTexture, int frame)
    {
        GLint  posId, colId;
        GLuint fboId, depth_stencil_rb;

        const float vertexFBOPositions[] = 
        {
            -0.7f, -0.7f,  0.5f,  1.0f,
            0.7f,  -0.7f,  0.5f,  1.0f,
            0.6f,  0.7f,   0.5f,  1.0f,
        };

        const float vertexFBOColors[] = 
        {
            1.0f, 1.0f, 0.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f,
        };

        // Load shaders for the FBO
        loadFBOShaders();

        // Setup the FBO
        glGenFramebuffers(1, &fboId);
        glBindFramebuffer(GL_FRAMEBUFFER, fboId);
        glViewport(0, 0, width, height);

        // Set up renderbuffer for depth_stencil formats.
        glGenRenderbuffers(1, &depth_stencil_rb);
        glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 
                                  GL_RENDERBUFFER, depth_stencil_rb);

        // Depending on the frame bind the 2D texture differently.
        // Frame 0 - Color, Frame 1 - Depth, Frame 2 - Stencil
        glBindTexture(GL_TEXTURE_2D, renderedTexture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        // Create our RGBA texture to render our color buffer into.
        if (frame == 0)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
        }

        // Create our Depth24_Stencil8 texture to render our depth buffer into.
        if (frame == 1)
        {
            glEnable(GL_DEPTH_TEST); 

            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0); 
        }

        // Create our Depth24_Stencil8 texture and change depth_stencil_texture mode
        // to render our stencil buffer into.
        if (frame == 2)
        {
            glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0); 
            glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
        }

        GLERR();

        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (status != GL_FRAMEBUFFER_COMPLETE)
        {
            printf("There is an error with the Framebuffer, fix it!\n");
        }
        GLERR();

        // Give the values of the position and color of our triangle to the shaders.
        posId = glGetAttribLocation(state->program, "position");
        colId = glGetAttribLocation(state->program, "color");
        GLERR();

        glVertexAttribPointer(posId, 4, GL_FLOAT, 0, 0, vertexFBOPositions);
        glEnableVertexAttribArray(posId);
        glVertexAttribPointer(colId, 4, GL_FLOAT, 0, 0, vertexFBOColors);
        glEnableVertexAttribArray(colId);

        // Clear the depth buffer back to 1.0f to draw our RGB stripes far back.
        glClearDepth(1.0f);
        glClear(GL_DEPTH_BUFFER_BIT);

        if (frame == 2)
        {
            glStencilFunc(GL_NEVER, 1, 0xFF); // never pass stencil test
            glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // replace stencil buffer values to ref=1
            glStencilMask(0xFF); // stencil buffer free to write
            glClear(GL_STENCIL_BUFFER_BIT);  // first clear stencil buffer by writing default stencil value (0) to all of stencil buffer.
            glDrawArrays(GL_TRIANGLES, 0, 3); // at stencil shape pixel locations in stencil buffer replace stencil buffer values to ref = 1

            // no more modifying of stencil buffer on stencil and depth pass.
            glStencilMask(0x00);
            // can also be achieved by glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

            // stencil test: only pass stencil test at stencilValue == 1 (Assuming depth test would pass.) and write actual content to depth and color buffer only at stencil shape locations.
            glStencilFunc(GL_EQUAL, 1, 0xFF);
        }

        // Use the Scissors to clear the FBO with a RGB stripped pattern.
        glEnable(GL_SCISSOR_TEST);
        glScissor(width * 0/3, 0, width * 1/3, height);
        glClearColor(0.54321f, 0.0f, 0.0f, 0.54321f); // Red
        glClear(GL_COLOR_BUFFER_BIT);
        glScissor(width * 1/3, 0, width * 2/3, height);
        glClearColor(0.0f, 0.65432f, 0.0f, 0.65432f); // Green
        glClear(GL_COLOR_BUFFER_BIT);
        glScissor(width * 2/3, 0, width * 3/3, height);
        glClearColor(0.0f, 0.0f, 0.98765f, 0.98765f); // Blue
        glClear(GL_COLOR_BUFFER_BIT);
        glDisable(GL_SCISSOR_TEST);
        GLERR();

        glDrawArrays(GL_TRIANGLES, 0, 3);

        glDisable(GL_DEPTH_TEST);

        GLERR();

        // Remove FBO and shaders and return to original viewport.
        glUseProgram(0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glDeleteShader(state->vshader);
        glDeleteShader(state->fshader);
        glDeleteProgram(state->program);
        glDeleteFramebuffers(1, &fboId);
        glViewport(0, 0, width, height);
        GLERR();
    }

    void drawFrameTestStencilTexturing(int frame)
    {
        GLint  posLoc, texLoc;
        GLuint renderedTexture;

        const GLubyte indxBuf[] = {0, 1, 2, 1, 3, 2};

        const float positions[] = 
        {
            -0.8f, -0.8f,
            -0.8f,  0.8f,
            0.8f, -0.8f,
            0.8f, 0.8f,
        };

        const float texCoords[] = 
        {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
        };

        // Allocate and initialize the texture that will be rendered to, and then
        // textured onto a quad on the default framebuffer.
        glGenTextures(1, &renderedTexture);

        // Render to the texture using FBO.
        RenderToTexture(renderedTexture, frame);

        // Create and load shaders to draw the texture.
        loadTextureShaders();

        // Draw texture to the window.
        glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        posLoc = glGetAttribLocation(state->program, "position");
        texLoc = glGetAttribLocation(state->program, "a_texCoords");

        glVertexAttribPointer(posLoc, 2, GL_FLOAT, 0, 0, positions);
        glEnableVertexAttribArray(posLoc);
        glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, texCoords);
        glEnableVertexAttribArray(texLoc);

        // Draw our generated texture onto a quad.
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indxBuf);
        glFlush();

        glDeleteTextures(1, &renderedTexture);
        GLERR();
    }

    void renderTest(int frame)
    {   
        drawFrameTestStencilTexturing(frame);
    }

private:
    StencilTexturingState* state;
    const int height, width;
};

RUN_TEST(StencilTexturing, "stencil_texturing", 2);
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-10 03:12:17

这条线

代码语言:javascript
复制
glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);

是不会工作的,GL启用枚举不是位值,而只是枚举,所以你可能会启用其他东西,或者只是得到一些GL_INVALID_ENUM错误,但你不会在这里启用模具测试。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16466125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档