2013-03-27 4 views
2

저는 두 개의 서페이스 (객체의 앞과 뒤)를 통해 빛의 굴절을 계산하는 셰이더를 구현하려고합니다. 이렇게하려면 보통 깊이 테스트 (GL_LESS) 및 역 깊이 테스트 (GL_GREATER)로 굴절 형상을 렌더링해야합니다. 그것은 내가 뒤쪽면에서 앞면까지의 거리를 계산할 수있게 해준다. 불행히도, 나는 한 번에 그 중 하나만 렌더링 할 수 있습니다. 두 깊이 정보를 텍스처로 텍스처 셰이더에 전달하는 방법을 알 수 없습니다.FBO로 여러 깊이 정보 렌더링하기

쉐이더 자체는 문제가되지 않지만, 쉐이더에 필요한 모든 것을 제공 할 수 있도록 OpenGL을 설정하는 데 어려움을 겪고 있습니다!

완벽하게 명확하게하기 위해, 나는 내 쉐이더에 두 개의 텍스처를 제공해야합니다 - 내 객체

의 뒷면의 깊이 정보와 텍스처 - 내 객체 의 정면 얼굴의 깊이 정보와 텍스처를

여기 대략 대략 내가 한 것입니다 (코드가 너무 복잡해서 읽기가 쉽지 않습니다). 내가 먼저 초기화 방식을 볼 수 초기화() 함수를 참조하십시오 렌더링 기능이 개 FBO의 외부를 만들 : 여기

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에서 뒤쪽에서 기하학적 깊이를 렌더링합니다. 그런 다음 두 텍스처를 전체 화면 쿼드로 렌더링합니다.

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로 렌더링을 중단하고 전체 화면 쿼드에 텍스처를 표시합니다. 여기 이 결과, 예상대로 (표시 목적, I는 먼저보다 작은 제 기하학적 표현)

여기 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

관련 문제