使用FBO渲染多个深度信息 [英] Rendering multiple depth information with FBOs

查看:128
本文介绍了使用FBO渲染多个深度信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个着色器,用于计算通过两个表面(对象的背面和正面)的光折射. 为此,我需要使用正常深度测试(GL_LESS)和反深度测试(GL_GREATER)渲染折射几何.这将允许我计算从背面到正面的距离. 不幸的是,我一次只能渲染其中一个,并且我不知道如何将两个深度信息作为纹理传递给着色器.

I am trying to implement a shader computing the light refraction through two surfaces: the back and front of the object. To do so, I need to render the refractive geometry with the normal depth test (GL_LESS), and the reversed depth test (GL_GREATER). It would allow me to compute the distance from the back face to the front face. Unfortunately, I only manage to render one of those at a time, and I can't figure out how to pass both depth information as textures to the shader.

着色器本身不应该成为问题,但是我正在努力设置opengl,以便它将所需的一切都提供给着色器!

The shader itself shouldn't be a problem, but I'm struggling with setting up opengl so that it gives everything needed to the shader!

为清楚起见,我需要为着色器提供两个纹理: -具有对象正面的深度信息的纹理 -具有对象背面深度信息的纹理

To be perfectly clear, I need to give two textures to my shader: - A texture with the depth information of the front faces of my object - A texture with the depth information of the back face of my object

这里大致是我所做的(简化后的代码不会太混乱以致于无法阅读).

Here is roughly what I did (simplified so that the code isn't too messy to read).

void FBO::init() {
    initDepthTexture();
    initFBO();
}

void FBO::initDepthTexture() {
    //32 bit depth texture, mWidth*mHeight
    glGenTextures(1, &mDepthTex);
    glBindTexture(GL_TEXTURE_2D, mDepthTex);
    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_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
            GL_COMPARE_R_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

    //NULL means reserve texture memory, but texels are undefined
    //You can also try GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24 for the internal format.
    //If GL_DEPTH24_STENCIL8_EXT, go ahead and use it (GL_EXT_packed_depth_stencil)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, mWidth, mHeight, 0,
            GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}

void FBO::initFBO() {
    glGenFramebuffersEXT(1, &mFrameBuffer);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer);
    //Attach
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
            GL_TEXTURE_2D, mDepthTex, 0);
    //-------------------------
    //Does the GPU support current FBO configuration?
    //Before checking the configuration, you should call these 2 according to the spec.
    //At the very least, you need to call glDrawBuffer(GL_NONE)
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);

    checkFBO();

    renderToScreen();
}


void FBO::renderToFBO() {
    cout << "Render to FBO: " << mFrameBuffer << endl;
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer); // Bind our frame buffer for rendering
    //-------------------------
    //----and to render to it, don't forget to call
    //At the very least, you need to call glDrawBuffer(GL_NONE)
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
}

/**
 * Static
 */
void FBO::renderToScreen() {
    cout << "Render to screen " << endl;
    // Finish all operations
    //glFlush();
    //-------------------------
    //If you want to render to the back buffer again, you must bind 0 AND THEN CALL glDrawBuffer(GL_BACK)
    //else GL_INVALID_OPERATION will be raised
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
    glDrawBuffer(GL_BACK);
    glReadBuffer(GL_BACK);
}

这是我使用FBO的方法: 我首先在render函数之外创建两个FBO,请参阅init()函数以了解如何对其进行初始化. 在第一个FBO上,我从前面渲染几何深度 在第二个FBO上,我从背面渲染几何体深度 然后,我将两个深度纹理都渲染到全屏四边形.

And here is how I use the FBOs: I first create two FBO outside of the render function, see the init() function to see how it is initialized. On the first FBO, I render the geometry depth from the front On the second FBO, I render the geometry depth from the back Then I render both depth texture to a full screen quad.

void Viewer::onRender() {
        FBO::renderToScreen();

            // XXX: Need of Z-Depth sorting to get alpha blending right!!
            glEnable(GL_DEPTH_TEST);

            glClearColor(0., 0., 0.2, 1.);
            glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

            glClearDepth(1.);
            glDepthFunc(GL_LESS);

            // set the projection transformation
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluPerspective(45.0f, (GLdouble) m_width / (GLdouble) m_height,
                    m_scale * 5.0, m_scale * 10000.0);


            // set the model transformation
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glm::vec3 pos = mCamera->getPosition();
            glm::vec3 view = mCamera->getView();
            glm::vec3 up = mCamera->getUp();
            gluLookAt(pos.x, pos.y, pos.z, view.x, view.y, view.z, up.x, up.y,
                    up.z);


            static float rotationAngle = 0;
            rotationAngle+=5;

            static int i = 0;
            if(i++ < 200) {
            /**
             * Render geometry twice to FBOs
             */
            mFBO->renderToFBO();
            glClear(GL_DEPTH_BUFFER_BIT);
            glClearDepth(0.);
            glDepthFunc(GL_LESS);
            glPushMatrix();
            glRotatef(1, 1, 0, 120);
            glColor3f(0., 1., 0.);
            // Draw teapot
            glutSolidTeapot(1.8);
            glPopMatrix();

            mFBO2->renderToFBO();
            glClear(GL_DEPTH_BUFFER_BIT);
            glClearDepth(0.);
            glDepthFunc(GL_GREATER);
            glPushMatrix();
            glColor3f(0., 1., 0.);
            // Draw teapot
            glutSolidTeapot(3.5);
            glPopMatrix();


            /**
             * Render the same geometry to the screen
             */
            FBO::renderToScreen();
            } else {
            mShader->enable();
            mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
            mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
            glBegin(GL_QUADS); // Draw A Quad
            glTexCoord2f(0, 1);
            glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
            glTexCoord2f(1, 1);
            glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
            glTexCoord2f(1, 0);
            glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
            glTexCoord2f(0, 0);
            glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
            glEnd(); // Done Drawing The Quad
            mShader->disable();
        }
    }

如果渲染到FBO,然后在四边形上渲染,这将非常有效.在上面的示例中,我向FBO渲染了200次,然后停止向FBO渲染,并在我的全屏四边形上显示纹理. 这是预期的结果(出于显示目的,我使第二个几何图形小于第一个几何图形):

This is working perfectly if render to the FBO and then render on the quad. In the example above, I render 200 times to the FBO, then stop rendering to the FBO and display the texture on my fullscreen quad. Here is the result, as expected (for display purposes, I rendered the second geometry smaller than the first one):

这是代码(与工作图像几乎相同,但是每帧渲染四边形)

Here is the code (nearly the same as for the working image, but rendering the quad for every frame)

void Viewer::onRender() {
            FBO::renderToScreen();

        // XXX: Need of Z-Depth sorting to get alpha blending right!!
        glEnable(GL_DEPTH_TEST);

        glClearColor(0., 0., 0.2, 1.);
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        glClearDepth(1.);
        glDepthFunc(GL_LESS);

        // set the projection transformation
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, (GLdouble) m_width / (GLdouble) m_height,
                m_scale * 5.0, m_scale * 10000.0);


        // set the model transformation
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glm::vec3 pos = mCamera->getPosition();
        glm::vec3 view = mCamera->getView();
        glm::vec3 up = mCamera->getUp();
        gluLookAt(pos.x, pos.y, pos.z, view.x, view.y, view.z, up.x, up.y,
                up.z);


        static float rotationAngle = 0;
        rotationAngle+=5;


        /**
         * Render geometry twice to FBOs
         */
        mFBO->renderToFBO();
        glClear(GL_DEPTH_BUFFER_BIT);
        glClearDepth(0.);
        glDepthFunc(GL_LESS);
        glPushMatrix();
        glRotatef(1, 1, 0, 120);
        glColor3f(0., 1., 0.);
        // Draw teapot
        glutSolidTeapot(1.8);
        glPopMatrix();

        mFBO2->renderToFBO();
        glClear(GL_DEPTH_BUFFER_BIT);
        glClearDepth(0.);
        glDepthFunc(GL_GREATER);
        glPushMatrix();
        glColor3f(0., 1., 0.);
        // Draw teapot
        glutSolidTeapot(3.5);
        glPopMatrix();


            /**
             * Render both depth texture on a fullscreen quad
             **/
        FBO::renderToScreen();
        mShader->enable();
        mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
        mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
        glBegin(GL_QUADS); // Draw A Quad
        glTexCoord2f(0, 1);
        glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
        glTexCoord2f(1, 1);
        glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
        glTexCoord2f(1, 0);
        glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
        glTexCoord2f(0, 0);
        glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
        glEnd(); // Done Drawing The Quad
        mShader->disable();
    }
}

但是,现在,当我渲染到FBO,然后尝试在每帧显示四边形时,就会出现我的问题. 我得到一个奇怪的结果,似乎只考虑了几何的一小部分:

But now, my problem occurs when I render to the FBOs, and then try to display the quad at every frame. I get a weird result, which seems to take into account only a small part of the geometry:

我不知道为什么会这样.它肯定是对深度纹理的渲染,但似乎出于某种原因渲染全屏四边形会更改FBO几何的渲染.

I can't figure out why this is happening. It's definitely rendering to the depth texture, but it seems that for some reason rendering a full screen quad alters the rendering of the FBO geometry.

我只是尝试保存opengl状态,并在四边形之后恢复它...

I just tried saving opengl state, and restoring it after the quad...

            FBO::renderToScreen();
    glPushAttrib(GL_ALL_ATTRIB_BITS);

        mShader->enable();
        mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
        mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
        glBegin(GL_QUADS); // Draw A Quad
        glTexCoord2f(0, 1);
        glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
        glTexCoord2f(1, 1);
        glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
        glTexCoord2f(1, 0);
        glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
        glTexCoord2f(0, 0);
        glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
        glEnd(); // Done Drawing The Quad
        mShader->disable();
            glPopAttrib();

好吧,那行得通,我可以在场景中四处移动并添加对象和其他所有东西,而不会遇到任何麻烦. 但是,我仍然对哪个状态更改可能导致渲染过程失败太多有任何想法吗?

Well, that works, I can move around the scene add objects and everthing without any kind of trouble. However I'm still curious as to which state change could have cause the rendering process to fail so much, any idea?

推荐答案

由于问题已解决(即使我不知道哪个状态推迟了一切),所以这里是我的FBO类和render函数的完整代码,以防有人遇到相同类型的问题:

Since the problem is fixed (even if I don't understand which state was putting everything off), here is the full code of my FBO class and render function, in case someone runs into the same kind of problem:

    /*
 * FBO.cpp
 *
 *  Created on: 28 Mar 2013
 *      Author: arnaud
 */

// Include GLEW
#include <GL/glew.h>
#include "FBO.h"
#include <GL/glext.h>
#include <iostream>
#include "FBOException.h"

using namespace std;

FBO::FBO(int width, int height) {
    mWidth = width;
    mHeight = height;
    // TODO Auto-generated constructor stubc
    init();

}

FBO::~FBO() {
    // TODO Auto-generated destructor stub
    glDeleteFramebuffersEXT(1, &mFrameBuffer);
}

void FBO::init() {
    initDepthTexture();
    initFBO();
}

void FBO::initDepthTexture() {
    //32 bit depth texture, mWidth*mHeight
    glGenTextures(1, &mDepthTex);
    glBindTexture(GL_TEXTURE_2D, mDepthTex);
    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_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
            GL_COMPARE_R_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

    //NULL means reserve texture memory, but texels are undefined
    //You can also try GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24 for the internal format.
    //If GL_DEPTH24_STENCIL8_EXT, go ahead and use it (GL_EXT_packed_depth_stencil)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, mWidth, mHeight, 0,
            GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}

void FBO::initFBO() {
    glGenFramebuffersEXT(1, &mFrameBuffer);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer);
    //Attach
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
            GL_TEXTURE_2D, mDepthTex, 0);
    //-------------------------
    //Does the GPU support current FBO configuration?
    //Before checking the configuration, you should call these 2 according to the spec.
    //At the very least, you need to call glDrawBuffer(GL_NONE)
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);

    checkFBO();

    renderToScreen();
}

void FBO::checkFBO() throw () {
    GLenum status;
    status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch (status) {
    case GL_FRAMEBUFFER_COMPLETE_EXT:
        cout << "Good Framebuffer" << endl;
        break;
    case GL_FRAMEBUFFER_UNDEFINED:
        throw new FBOException(
                "Framebuffer undefined. Usually returned if  returned if target is the default framebuffer, but the default framebuffer does not exist.");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        throw new FBOException(
                "Incomplete Attachement: is returned if any of the framebuffer attachment points are framebuffer incomplete.");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        throw new FBOException(
                "Incomplete Missing Attachment: is returned if the framebuffer does not have at least one image attached to it.");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
        throw new FBOException(
                "Incomplete Draw Buffer: is returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point(s) named by GL_DRAWBUFFERi");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
        throw new FBOException(
                "Incomplete Read Buffer: is returned if GL_READ_BUFFER is not GL_NONE and the value of\\"
                        " GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER");
        break;
    case GL_FRAMEBUFFER_UNSUPPORTED:
        throw new FBOException(
                "Framebuffer Unsupported: is returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
        throw new FBOException("Incomplete Multisample");
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
        throw new FBOException("Incomplete Layer Targets");
        break;
    default:
        throw new FBOException("Bad Framebuffer");
    }
}


/****
 * PUBLIC Functions
 */

void FBO::renderToFBO() {
    cout << "Render to FBO: " << mFrameBuffer << endl;
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer); // Bind our frame buffer for rendering
    //-------------------------
    //----and to render to it, don't forget to call
    //At the very least, you need to call glDrawBuffer(GL_NONE)
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
}

/**
 * Static
 */
void FBO::renderToScreen() {
    cout << "Render to screen " << endl;
    // Finish all operations
    //glFlush();
    //-------------------------
    //If you want to render to the back buffer again, you must bind 0 AND THEN CALL glDrawBuffer(GL_BACK)
    //else GL_INVALID_OPERATION will be raised
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
    glDrawBuffer(GL_BACK);
    glReadBuffer(GL_BACK);
}

这是渲染功能

void Viewer::onRender() {
    // Get elapsed time since last loop
    sf::Time time = mClock.getElapsedTime();
    float ellapsedTime = time.asMilliseconds();
    if (time.asMilliseconds() > 1000 / 60) {

        // XXX: Need of Z-Depth sorting to get alpha blending right!!
        glEnable(GL_DEPTH_TEST);

        glClearColor(0., 0., 0.2, 1.);
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        glClearDepth(1.);
        glDepthFunc(GL_LESS);

        // set the projection transformation
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, (GLdouble) m_width / (GLdouble) m_height,
                m_scale * 5.0, m_scale * 10000.0);


        // set the model transformation
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glm::vec3 pos = mCamera->getPosition();
        glm::vec3 view = mCamera->getView();
        glm::vec3 up = mCamera->getUp();
        gluLookAt(pos.x, pos.y, pos.z, view.x, view.y, view.z, up.x, up.y,
                up.z);


        static float rotationAngle = 0;
        rotationAngle+=5;

        /**
         * Render geometry twice to FBOs
         */
        mFBO->renderToFBO();
        glClear(GL_DEPTH_BUFFER_BIT);
        glClearDepth(0.);
        glDepthFunc(GL_LESS);
        glPushMatrix();
        glColor3f(0., 1., 0.);
        // Draw teapot
        glutSolidTeapot(3.5);
        glPopMatrix();

        mFBO2->renderToFBO();
        glClear(GL_DEPTH_BUFFER_BIT);
        glClearDepth(0.);
        glDepthFunc(GL_GREATER);
        glPushMatrix();
        glColor3f(0., 1., 0.);
        // Draw teapot
        glutSolidTeapot(3.5);
        glPopMatrix();


        /**
         * Render the same geometry to the screen
         */
        FBO::renderToScreen();
        // XXX: Save attribs bits to fix FBO problem... (why is this needed!?)
        glPushAttrib(GL_ALL_ATTRIB_BITS);
        mShader->enable();
        mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
        mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
        glBegin(GL_QUADS); // Draw A Quad
        glTexCoord2f(0, 1);
        glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
        glTexCoord2f(1, 1);
        glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
        glTexCoord2f(1, 0);
        glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
        glTexCoord2f(0, 0);
        glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
        glEnd(); // Done Drawing The Quad
        mShader->disable();
        glPopAttrib();
    }

}

这篇关于使用FBO渲染多个深度信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆