Использование OpenGL ES 2.0 FrameBuffer (FBO) и трафарета в Android нативный код (ndk)
Я пытаюсь сгенерировать объект frambuffer и использовать трафарет внутри собственного приложения для Android, используя NDK (r5b). Целевое устройство работает под управлением froyo 2.2, поддерживает OpenGL ES 2.0.
Итак, я кодировал много кода gl в своих родных библиотеках C++ и не прошел ни одной проблемы, кроме этой. Кажется, я просто не могу заставить это работать.
Вот фрагмент кода для создания кадрового буфера. Полнота все хорошо, но экран остается полностью черным. Это похоже на то, что созданное мной fbo на самом деле не связано с поверхностью gl, созданной Java-частью приложения. Остальная часть кода моего приложения хороша, если я удаляю создание и привязку fbo, все работает отлично, за исключением того, что у меня не работают трафареты, которые мне нужны для моего приложения.
GLint backingWidth = 1024;
GLint backingHeight = 1024;
//Create the FrameBuffer and binds it
glGenFramebuffers(1, &_defaultFramebuffer);
checkGlError("glGenFramebuffers");
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer);
checkGlError("glBindFramebuffer");
//Create the RenderBuffer for offscreen rendering // Color
glGenRenderbuffers(1, &_colorRenderbuffer);
checkGlError("glGenRenderbuffers color");
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer);
checkGlError("glBindRenderbuffer color");
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, backingWidth, backingHeight);
checkGlError("glRenderbufferStorage color");
//Create the RenderBuffer for offscreen rendering // Depth
glGenRenderbuffers(1, &_depthRenderbuffer);
checkGlError("glGenRenderbuffers depth");
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer);
checkGlError("glBindRenderbuffer depth");
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, backingWidth, backingHeight);
checkGlError("glRenderbufferStorage depth");
//Create the RenderBuffer for offscreen rendering // Stencil
glGenRenderbuffers(1, &_stencilRenderbuffer);
checkGlError("glGenRenderbuffers stencil");
glBindRenderbuffer(GL_RENDERBUFFER, _stencilRenderbuffer);
checkGlError("glBindRenderbuffer stencil");
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, backingWidth, backingHeight);
checkGlError("glRenderbufferStorage stencil");
// bind renderbuffers to framebuffer object
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderbuffer);
checkGlError("glFramebufferRenderbuffer depth");
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderbuffer);
checkGlError("glFramebufferRenderbuffer color");
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _stencilRenderbuffer);
checkGlError("glFramebufferRenderbuffer stencil");
//Test for FrameBuffer completeness
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
checkGlError("glCheckFramebufferStatus");
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE: LOGI("\n\n\nFLIPBOOM : FBO complete GL_FRAMEBUFFER_COMPLETE %x\n\n\n", status);break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: LOGI("\n\n\nFLIPBOOM : FBO GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT %x\n\n\n", status);break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: LOGI("\n\n\nFLIPBOOM : FBO FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT %x\n\n\n", status);break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: LOGI("\n\n\nFLIPBOOM : FBO FRAMEBUFFER_INCOMPLETE_DIMENSIONS %x\n\n\n", status);break;
case GL_FRAMEBUFFER_UNSUPPORTED: LOGI("\n\n\nFLIPBOOM : FBO GL_FRAMEBUFFER_UNSUPPORTED %x\n\n\n", status);break;
default : LOGI("\n\n\nFLIPBOOM : failed to make complete framebuffer object %x\n\n\n", status);
}
Я также попробовал рендеринг в 2D текстуру вместо рендеринга буфера... тоже не сработало.
Итак, есть ли способ, как я могу это исправить? Я что-то здесь не так понимаю? Если у кого-то есть идеи, пожалуйста, дайте мне знать.... слишком много времени потратил на поиск этой проблемы... хе-хе;)
Заранее спасибо!
Ура!
РЕДАКТИРОВАТЬ:
Хорошо, мне удалось заставить работать трафаретный буфер, но FBO просто не работают. Я думаю, что OpenGL ES 2.0 не полностью поддерживается Android (используя R5B здесь, кстати). Я думаю, что заглушки метода определены, но не полностью реализованы. Или созданный GlSurfaceView неправильно связывается с FBO.
Что касается буфера трафарета, я должен был сделать
glEnable(GL_DEPTH_TEST);
и удалите использование glDepthMask, чтобы они работали правильно.
1 ответ
@ Zennichimaro, для использования буфера трафарета!
Во время инициализации:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
Во время рендеринга:
glViewport(0, 0, GetViewWidth(), GetViewHeight());
checkGlError("glViewport");
if (_firstRenderDone == false)
{
glClearDepthf( 0.9f );
glDepthMask( GL_TRUE );
glClear( GL_DEPTH_BUFFER_BIT );
glDepthMask( GL_FALSE );
_firstRenderDone = true;
}
glClearColor(M_channelToFloat(_backgroundColor.r),
M_channelToFloat(_backgroundColor.g),
M_channelToFloat(_backgroundColor.b),
M_channelToFloat(_backgroundColor.a));
checkGlError("glClearColor");
glClearStencil( 0 );
checkGlError("glClearStencil");
glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
checkGlError("glClear");
_stencilLayer = 1;
//use our custom shaders
if( _program )
{
glUseProgram(_program);
if( transformMatrix3x3 != NULL )
{
glUniformMatrix3fv( _uniforms[OGL_UNIFORM_TRANSFORM], 1, false, transformMatrix3x3 );
}
// reset the shading.
glUniform1f( _uniforms[ OGL_UNIFORM_SHADE ], 0.0f );
}
//Do the actual drawing (Triangle Slip)
if( object )
{
_isRender = true;
object->OglDraw(this);
_isRender = false;
}
Когда мне нужно использовать трафарет, я использую следующие методы в зависимости от того, что мне нужно:
void GlEs2Renderer::StencilStartMask()
{
if (!USE_STENCIL) //For debugging purpose
return;
glEnable(GL_STENCIL_TEST);
//Turn off writing to the Color Buffer and Depth Buffer
//We want to draw to the Stencil Buffer only
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
//Set 1 into the stencil buffer
glStencilFunc( GL_ALWAYS, NewStencilLayer(), 0xFFFFFFFF );
glStencilOp( GL_ZERO, GL_ZERO, GL_REPLACE );
}
void GlEs2Renderer::StencilUseMask()
{
if (!USE_STENCIL) //For debugging purpose
return;
//Turn back on Color Buffer and Depth Buffer
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
//Only write to the Stencil Buffer where 1 is set
glStencilFunc( GL_EQUAL, StencilLayer(), 0xFFFFFFFF);
//Keep the content of the Stencil Buffer
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
}
void GlEs2Renderer::StencilOverlayMask()
{
if (!USE_STENCIL) //For debugging purpose
return;
//Turn back on Color Buffer and Depth Buffer
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glDepthMask(true);
//Only write to the Stencil Buffer where 1 is set
glStencilFunc( GL_EQUAL, StencilLayer(), 0xFFFFFFFF);
//Keep the content of the Stencil Buffer and increase when z passed
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
}
И, наконец, я делаю технику двойного прохода, чтобы рисовать внутри трафарета... Вот пример:
glVertexAttribPointer(OGL_ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, _triangles);
glEnableVertexAttribArray(OGL_ATTRIB_VERTEX);
glVertexAttribPointer(OGL_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, _colors);
glEnableVertexAttribArray(OGL_ATTRIB_COLOR);
glContext->StencilStartMask();
glDrawArrays(GL_TRIANGLE_STRIP, 0, _nPoints);
glContext->StencilUseMask();;
glDrawArrays(GL_TRIANGLE_STRIP, 0, _nPoints);
glContext->StencilEndMask();
Мой код довольно сложный, поэтому сложно публиковать только то, что связано с трафаретом, но я надеюсь, что это поможет;)