2013-03-27 97 views
2

我想實現一個着色器,通過兩個表面計算光折射:對象的背面和前面。 爲此,我需要使用正常深度測試(GL_LESS)和反轉深度測試(GL_GREATER)渲染折射幾何。這將允許我計算從背面到正面的距離。 不幸的是,我只能設法渲染其中的一個,我無法弄清楚如何將深度信息作爲紋理傳遞給着色器。用FBO渲染多個深度信息

着色器本身不應該是一個問題,但我努力設置opengl,以便它提供着色器所需的一切!

要非常清楚,我需要給兩個紋理到我的着色器: - 我的對象

的背面的深度信息的紋理 - 用我的對象 的正面的深度信息的紋理

這裏大概是我所做的(簡化以便代碼不會太亂)。

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: 我首先創建渲染函數的兩個FBO外,請參見init()函數來看看它是如何初始化。 在第一個FBO上,我從前面渲染幾何深度 在第二個FBO上,我從後面渲染幾何深度 然後,我將兩個深度紋理渲染爲全屏四邊形。

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並在我的全屏四邊形上顯示紋理。 下面是結果,如所預期(用於顯示目的,我呈現的第二幾何形狀比第一個較小的):

Front and Back depth

這裏是代碼(幾乎相同的工作圖像,但呈現每幀四)

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(); 
    } 
} 

但是現在,當我呈現到宗教組織,然後嘗試在每一幀顯示四出現我的問題。 我得到一個奇怪的結果,這似乎只考慮了幾何的一小部分:

Only a small wrong part of the geometry

我想不通爲什麼發生這種情況。這絕對是渲染到深度紋理,但似乎由於某種原因渲染全屏四邊形會改變FBO幾何的渲染。

[編輯]我只是想節省OpenGL的狀態,而四後恢復它...

  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(); 

嗯,這工作,我可以在場景中移動對象添加和寄託都沒有任何形式的麻煩。 然而,我仍然好奇哪種狀態改變可能會導致渲染過程失敗太多,任何想法?

回答

1

由於問題是固定的(即使我不明白哪個狀態將所有東西都關閉),下面是我的FBO類和渲染函數的完整代碼,以防某人遇到同樣類型的問題:

/* 
* 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(); 
    } 

} 
0

你想要做的是一種叫做「深度剝離」的技術,它基本上可以被描述爲一種插入到多個深度緩衝層的插入形式。網上有許多演示文稿和論文。

+0

謝謝你,就算什麼我執行是不是真正的深度剝離,這確實挺接近的概念。 我清理了很多我的代碼,並使用兩個分離的FBO渲染了深度緩衝區。它幾乎可以工作,但對於我在編輯的第一條消息中解釋的問題。 – geenux 2013-03-30 16:31:57