OpenGL FBO с записью MRT в задний буфер
У меня запутанная ситуация в OpenGL 3.3 на Mac. Я создал FBO с пятью точками крепления размером 512x512 за штуку. Я создал шейдер, который пишет в gl_FragData[0-4] для diffuse, normal, position, specular и emissive для моей геометрии. Когда я отрисовываю сцену, обновляется задний буфер и цели рендеринга, хотя я ограничил только FBO!
Вот некоторый код:
void OpenGLESDriver::setFrameBufferAttachments( u32 nAttachments, const u32* aAttachments ){
pushText( "setFrameBufferAttachments" );
#if USE_MRT
GLint max;
glGetIntegerv( GL_MAX_DRAW_BUFFERS, &max );
GLenum aBuffers[max];
if( nAttachments > max ){
nAttachments = max;
}
for( u32 i=0; i<nAttachments; ++i ){
aBuffers[i] = GL_COLOR_ATTACHMENT0+aAttachments[i];
}
for( u32 i=nAttachments; i<max; ++i ){
aBuffers[i] = GL_NONE;
}
glDrawBuffers( max, aBuffers );
glAssert();
#else
glDrawBuffer( GL_COLOR_ATTACHMENT0+aAttachments[0] );
glAssert();
#endif
popText();
}
И связующее FBO:
bool OpenGLESDriver::setFrameBuffer( const FrameBuffer::handle& hFrameBuffer ){
if( hFrameBuffer ){
pushText( "setFrameBuffer" );
glBindFramebuffer( GL_FRAMEBUFFER, hFrameBuffer->toFBO() );
glAssert();
if( !hFrameBuffer->toColorTargets().empty() ){
u32 nAttachments = hFrameBuffer->toColorTargets().size();
u32 aAttachments[nAttachments];
for( u32 i=0; i<nAttachments; ++i ){
aAttachments[i] = i;
}
setFrameBufferAttachments( nAttachments, aAttachments );
}else{
setFrameBufferAttachments( 0, 0 );
}
int w = hFrameBuffer->toDepthTexture()->toWidth();
int h = hFrameBuffer->toDepthTexture()->toHeight();
glViewport( 0, 0, w, h );
glAssert();
//clear out all texture stages because we don't want a left over
//frame buffer texture being bound to the shader.
for( u32 i=0; i<Material::kMaxSamplers; ++i ){
setTextureStage( i, 0 );
}
popText();
return true;
}
return false;
}
Я создаю FBO с:
FrameBuffer::handle OpenGLESDriver::createFrameBuffer( const FrameBuffer::ColorTargets& vColorTargets, const DepthTarget::handle& hDT ){
//--------------------------------------------------------------------
// Save off default FBO.
//--------------------------------------------------------------------
if( s_iFBOMaster < 0 ){
glGetIntegerv( GL_FRAMEBUFFER_BINDING, &s_iFBOMaster );
glAssert();
}
//--------------------------------------------------------------------
// Generate frame buffer object.
//--------------------------------------------------------------------
GLuint fbo;
glGenFramebuffers( 1, &fbo );
glAssert();
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
glAssert();
//--------------------------------------------------------------------
// Attach color RBO.
//--------------------------------------------------------------------
FrameBuffer::ColorTargets::const_iterator itCT = vColorTargets.getIterator();
u32 mrtIndex = 0;
while( itCT ){
const ColorTarget::handle& hCT = itCT++;
if( !hCT ){
continue;
}
if( hCT->toTexID() ){
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+mrtIndex,
GL_TEXTURE_2D,
hCT->toTexID(),
0 );
}else if( hCT->toRBO() ){
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+mrtIndex,
GL_RENDERBUFFER,
hCT->toRBO() );
}else{
DEBUG_ASSERT_ALWAYS( "No color texture or RBO to attach!" );
}
glAssert();
++mrtIndex;
if( !checkFBStatus() ){
e_log( "GL", "Couldn't create color attachment!" );
hCT.as<ColorTarget>()->toFlags()->bFailed = true;
}
}
//--------------------------------------------------------------------
// Attach depth RBO.
//--------------------------------------------------------------------
if( hDT ){
if( hDT->toTexID() ){
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D,
hDT->toTexID(),
0 );
}else if( hDT->toRBO() ){
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
hDT->toRBO() );
}else{
DEBUG_ASSERT_ALWAYS( "No depth texture or RBO to attach!" );
}
glAssert();
if( !checkFBStatus() ){
e_log( "GL", "Couldn't create depth attachment!" );
hDT.as<DepthTarget>()->toFlags()->bFailed = true;
}
}
//--------------------------------------------------------------------
// New handle.
//--------------------------------------------------------------------
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glAssert();
FrameBuffer::handle hFrameBuffer = e_new( FrameBuffer );
hFrameBuffer->setColorTargets( vColorTargets );
hFrameBuffer->setDepthTarget( hDT );
hFrameBuffer->setFBO( u32( fbo ));
return hFrameBuffer;
}
И я возвращаюсь в задний буфер с:
void OpenGLESDriver::setDefaultTarget(){
pushText( "setDefaultTarget" );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );//s_iFBOMaster );
glAssert();
glViewport( 0, 0, IEngine::cxView(), IEngine::cyView() );
glAssert();
popText();
}
Итак, окончательный код рендеринга выглядит так:
pushText( "Render MRT pass" );
if( setFrameBuffer( m_tPostFx.buffers[0] )){
setColorMask( true, true, true, true );
clearZ();
enableZBuffer( false );
setColor( color );
clearMRT( m_tPostFx.clearMRTShader );
enableZBuffer( true );
drawMRTPass();
}
popText();
И по какой-то причине обратный буфер обрабатывается так же, как и FBO. Должно быть, я что-то упустил, но понятия не имею, что. Кто-нибудь может увидеть, что я делаю не так?
1 ответ
После некоторого возни я наконец нашел ответ. Мой рендерер использует вектор объектов RenderNode, который я заполняю при рендеринге. Я не очищал этот вектор после того, как закончил свой пост-эффект. По какой-то причине этот незаполненный вектор рендерился со следующей целью FBO, которая снова рисовала всю первую серию геометрии во втором FBO. Очистив вектор в начале прохода рендеринга и в конце я избавился от проблемы. Я все еще пытаюсь отследить, кто совершал все узлы рендеринга снова. Надеюсь, что код, который я вставил, поможет всем, кто хочет работать с FBO, потому что в конце концов он работает.:)