I'm using libgdx but this is pretty much vanilla opengl es 2.0 stuff. Just try and ignore the Gdx.gl prefix everywhere ^^ I'm testing it on my desktop as well as android device and it's the same story in both cases.
I have the following code in my window resize event. It is supposed to delete the frame buffer and associated textures if they already were created, and then make some new ones the right size. I'm not sure if this is even correct to delete the textures and framebuffer like i am doing.
if (depthTexture >= 0)
{
Gdx.gl.glDeleteTexture(depthTexture);
depthTexture = -1;
}
if (colorTexture >= 0)
{
Gdx.gl.glDeleteTexture(colorTexture);
colorTexture = -1;
}
if (depthBuffer >= 0)
{
Gdx.gl.glDeleteFramebuffer(depthBuffer);
depthBuffer = -1;
}
IntBuffer intBuffer = BufferUtils.newIntBuffer(16); // See http://lwjgl.org/forum/index.php?topic=1314.0;wap2
intBuffer.clear();
Gdx.gl.glGenFramebuffers(1, intBuffer);
frameBuffer = intBuffer.get(0);
intBuffer.clear();
Gdx.gl.glGenTextures(1, intBuffer);
colorTexture = intBuffer.get(0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, colorTexture);
Gdx.gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, width, height
, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, null);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, 0);
intBuffer.clear();
Gdx.gl.glGenTextures(1, intBuffer);
depthTexture = intBuffer.get(0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, depthTexture);
Gdx.gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_DEPTH_COMPONENT, width, height
, 0, GL20.GL_DEPTH_COMPONENT, GL20.GL_UNSIGNED_SHORT, null);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, 0);
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, frameBuffer);
Gdx.gl.glFramebufferTexture2D(GL20.GL_FRAMEBUFFER, GL20.GL_COLOR_ATTACHMENT0
, GL20.GL_TEXTURE_2D, colorTexture, 0);
Gdx.gl.glFramebufferTexture2D(GL20.GL_FRAMEBUFFER, GL20.GL_DEPTH_ATTACHMENT
, GL20.GL_TEXTURE_2D, depthTexture, 0);
int status = Gdx.gl.glCheckFramebufferStatus(GL20.GL_FRAMEBUFFER);
if (status != GL20.GL_FRAMEBUFFER_COMPLETE)
{
System.out.println("frame buffer not complete. status " + Integer.toHexString(status));
System.exit(0);
}
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0);
status = Gdx.gl.glCheckFramebufferStatus(GL20.GL_FRAMEBUFFER);
if (status != GL20.GL_FRAMEBUFFER_COMPLETE)
{
System.out.println("default buffer not complete. status " + Integer.toHexString(status));
System.exit(0);
}
I am not sure at all if i have made mistakes in setting up the render buffer or either the color texture or depth texture attachments. Anyway, on to the rendering loop
// update cameras and things
// setup rendering to off screen framebuffer
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, frameBuffer);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// draw things
// setup rendering to default framebuffer
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shader.begin();
// setup shader stuff
Gdx.gl.glActiveTexture(0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, depthTexture);
shader.setUniformi("u_fbDepth", 0);
Gdx.gl.glActiveTexture(1);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, colorTexture);
shader.setUniformi("u_fbColor", 1);
// draw things with shader
shader.end();
Again i am not sure i am setting things up the right way. The idea here is hopefully pretty clear. Render to the off screen frame buffer then use the depth and color textures from that frame buffer as textures to sample in the final shader that renders to the default framebuffer.
The depth and color textures that end up in my fragment shader are just empty however. Black screen. I know the fragment shader is not the problem - if i sample a different texture i see the texture as expected. I know that the drawing its self is not the problem - if i render what i would want to render to the off screen frame buffer directly to the default frame buffer i see what i expect.
I got it. There's a bit of a gotcha with setting active textures. The function glActiveTexture expects one of the GL_TEXTURE0 type constants, but the shader uniform just wants to be the integer in the constant name.
basically
Gdx.gl.glActiveTexture(0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, depthTexture);
shader.setUniformi("u_fbDepth", 0);
Gdx.gl.glActiveTexture(1);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, colorTexture);
shader.setUniformi("u_fbColor", 1);
needed to be
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, depthTexture);
shader.setUniformi("u_fbDepth", 0);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE1);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, colorTexture);
shader.setUniformi("u_fbColor", 1);
Related
Given a textureId, I need to extract pixel data from the texture.
glReadPixels works, but it is extremely slow on some devices, even with FBO/PBO. (On Xiaomi MI 5, it is 65 ms, and even slower with PBO). So I decided to use Hardwarebuffer and eglImageKHR, which should be much faster. However, I cannot get it to work. The screen goes black, and nothing is read into the data.
//attach inputTexture to FBO
glBindFrameBuffer(GL_FRAMEBUFFER, fbo)
glFrameBufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0)
//allocate hardware buffer
AHardwareBuffer* buffer = nullptr;
AHardwareBuffer_Desc desc = {};
desc.width = width;
desc.height = height;
desc.layers = 1;
desc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER
| AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT ;
desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
//create eglImageKHR
EGLint eglAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
EGLImageKHR eglImageKhr = eglCreateImageKHR(eglDisplay, eglContext,
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, eglAttributes);
//read pixels to hardware buffer ????
glBindTexture(GL_TEXTURE_2D, textureId);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImageKhr);
//copy pixels into memory
void *readPtr;
AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, (void**)&readPtr);
memcpy(writePtr, readPtr, width * 4);
AHardwareBuffer_unlock(buffer, nullptr);
This is my code with glReadPixels, and it just can get the pixels after attaching the texture to framebuffer.
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fboBuffer!![0])
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
inputTextureId,
0)
GLES30.glReadPixels(0, 0, width, height, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, byteBuffer)
Please tell me where I did wrong :(
//read pixels to hardware buffer ????
glBindTexture(GL_TEXTURE_2D, textureId);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImageKhr);
This doesn't do any reading of data. This is just setting up the texture to refer to the EGLImage. If you want data to be copied into it you need to either do glCopyTexImage2D() or bind it to a framebuffer and render in to it.
I am very new in OpenGL.
How can I create an offscreen texture, so that I can get some Informations of it (e.g. PixelColor by clicking on view texture) ?
I tried many many things for example FBO, but it did't work. I have no imagination how to load the Bitmap to a offscreen texture and get information of it. I am very frustated :/
Edit:
Took this Tutorial as Example, don't know if it fits to my problem. createFramebuffer
public void createFramebuffer(GL10 gl) {
FloatBuffer uvBuffer2;
int texture[] = new int[1];
GLES20.glGenTextures(1, texture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE0, texture[0]);
float uvs2[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
ByteBuffer bb = ByteBuffer.allocateDirect(uvs2.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer2 = bb.asFloatBuffer();
uvBuffer2.put(uvs2);
uvBuffer2.position(0);
gl.glTexCoordPointer(2, GLES20.GL_BYTE, 0, uvBuffer2);
//load image
int idTest = mContext.getResources().getIdentifier("drawable/testgroesse", null, mContext.getPackageName());
Bitmap wood = BitmapFactory.decodeResource(mContext.getResources(), idTest);
GLES20.glTexParameterf(GLES20.GL_TEXTURE0, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE0, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE0, 0, wood, 0);
GLES20.glEnable(GLES20.GL_TEXTURE0);
gl.glEnableClientState(GLES20.GL_TEXTURE0);
//color picking background start
ByteBuffer bytePickedColor = ByteBuffer.allocate(4);
bytePickedColor.order(ByteOrder.nativeOrder());
GLES20.glFlush();
GLES20.glReadPixels(touchXint, touchYint, 1, 1, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bytePickedColor);
byte b[] = new byte[4];
bytePickedColor.get(b);
String key = "" + b[0] + " " + b[1] + " " + b[2] + " " + b[3];
Log.d("Color_Farbe: ", key);
bytePickedColor.rewind();
//color picking background end
}
To oversimplify:
The FBO you created is a BUFFER that contains RGBA + 16-bit depth. By attaching a texture to it you can then reuse the texture as it will have the same RGBA data as the FBO. At the beginning the buffer itself is still empty, you still need to clear it and draw to it as with any other render buffer.
So to put the image/texture on to that buffer you need to create the texture (with that image) and draw a textured rectangle on this FBO.
It would seem this is not what you are after:
"How can I create a offscreen texture?" What is an onscreen texture? All textures are offscreen.
"get some Informations of it"? Of what, the texture?! There are basically 2 ways of creating the texture: first is with an image in which case rather lookup the texel from the source image. Second is by drawing which is the FBO procedure where you need to read pixels (try glReadPixels).
"e.g. PixelColor by clicking on view texture" Clicking on what?! You can click on view/screen but not the texture. If you again need the sample of the rendered view that you see before you then all you need to do is read the pixels as described before.
It looks like all you are looking for is glReadPixels to get the colour values from the current buffer. If this is not the case please rephrase your question and explain what is your goal here.
I am trying to switch my application over to using framebuffer/renderbuffer objects (looking to render to texture later) but whenever I use the framebuffer/renderbuffer, nothing renders. When the default framebuffer is left on, as is the default, it renders fine; All colour, depth and stencil related features work exactly as expected.
Initialisation code:
if(frameBuffer == 0 || !GLES20.glIsFramebuffer(frameBuffer)){
int[] retVal = new int[1];
GLES20.glGenFramebuffers(1, retVal, 0);
frameBuffer = retVal[0];
retVal[0] = 0;
if(renderBufferColour != 0 || !GLES20.glIsRenderbuffer(renderBufferColour)){
GLES20.glGenRenderbuffers(1, retVal, 0);
renderBufferColour = retVal[0];
}
if(renderBufferDepth != 0 || !GLES20.glIsRenderbuffer(renderBufferDepth)){
GLES20.glGenRenderbuffers(1, retVal, 0);
renderBufferDepth = retVal[0];
}
if(renderBufferStencil != 0 || !GLES20.glIsRenderbuffer(renderBufferStencil)){
GLES20.glGenRenderbuffers(1, retVal, 0);
renderBufferStencil = retVal[0];
}
}
Framebuffer enabling code (commenting this out allows rendering using the default buffer):
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferColour);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_RGBA4, width, height);
GLES20.glFramebufferRenderbuffer(
GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_RENDERBUFFER,
renderBufferColour);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferDepth);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height);
GLES20.glFramebufferRenderbuffer(
GLES20.GL_FRAMEBUFFER,
GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_RENDERBUFFER,
renderBufferDepth);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferStencil);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_STENCIL_INDEX8, width, height);
GLES20.glFramebufferRenderbuffer(
GLES20.GL_FRAMEBUFFER,
GLES20.GL_STENCIL_ATTACHMENT,
GLES20.GL_RENDERBUFFER,
renderBufferStencil);
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE)
throw new RuntimeException(String.format("Failed to make complete framebuffer object %x", GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)));
The exception at the end is not thrown and when checking glGetError() after each step, no error is returned. Am I missing something here?
Ok, after reading the OpenGLES 2.0 manual, I came across this paragraph:
By allowing the images of a renderbuffer to be attached to a framebuffer,
OpenGL ES provides a mechanism to support off-screen rendering. Further, by
allowing the images of a texture to be attached to a framebuffer, OpenGL ES provides
a mechanism to support render to texture.
It appears to me that application render buffers are always off-screen not on-screen as I had expected. This, if I have read correctly, is why there is no image on the screen.
I started writing a game for Android using OpenGL-ES and just finished the draw code which uses the glDrawTexfOES extension. When I tested it on the emulator it works fine but testing it on my Samsung Galaxy S2 it seems all the textures are drawn white.
To make sure I didn't make any mistakes I copied the source from a tutorial and ran it with the same results. The tutorial code I am using can be seen here.
My textures are .PNG format and power of two and I am loading from the R.drawable folder although I have tried some other locations such as drawable-nodpi as I have seen suggested.
I have also checked the result of glGenTextures which I have read can give odd values for certain phones but seems to be giving the correct values (1,2,3..).
Does anybody know why this could be happening or suggest some other checks I can do to figure out what is going wrong?
Here is a slightly modified version of the example code I linked above to keep things simple.
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
gl10.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// Set the background colour to black ( rgba ).
gl10.glClearColor(0.0f, 0.0f, 0.0f, 1);
// Enable Flat Shading.
gl10.glShadeModel(GL10.GL_FLAT);
// We don't need to worry about depth testing!
gl10.glDisable(GL10.GL_DEPTH_TEST);
// Set OpenGL to optimise for 2D Textures
gl10.glEnable(GL10.GL_TEXTURE_2D);
// Disable 3D specific features.
gl10.glDisable(GL10.GL_DITHER);
gl10.glDisable(GL10.GL_LIGHTING);
gl10.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
// Initial clear of the screen.
gl10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Test for draw texture
// Test for device specific extensions
String extensions = gl10.glGetString(GL10.GL_EXTENSIONS);
boolean drawTexture = extensions.contains("draw_texture");
Log.i("OpenGL Support - ver.:",
gl10.glGetString(GL10.GL_VERSION) + " renderer:" +
gl10.glGetString(GL10.GL_RENDERER) + " : " +
(drawTexture ? "good to go!" : "forget it!!"));
// LOAD TEXTURE
mTextureName = new int[1];
// Generate Texture ID
gl10.glGenTextures(1, mTextureName, 0);
assert gl10.glGetError() == GL10.GL_NO_ERROR;
// Bind texture id / target (we want 2D of course)
gl10.glBindTexture(GL10.GL_TEXTURE_2D, mTextureName[0]);
// Open and input stream and read the image
InputStream is = mContext.getResources().openRawResource(R.drawable.asteroid);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Build our crop region to be the size of the bitmap (ie full image)
mCrop = new int[4];
mCrop[0] = 0;
mCrop[1] = imageHeight = bitmap.getHeight();
mCrop[2] = imageWidth = bitmap.getWidth();
mCrop[3] = -bitmap.getHeight();
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
assert gl10.glGetError() == GL10.GL_NO_ERROR;
bitmap.recycle();
}
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
gl10.glViewport(0, 0, i, i1);
/*
* Set our projection matrix. This doesn't have to be done each time we
* draw, but usually a new projection needs to be set when the viewport
* is resized.
*/
float ratio = (float) i / i1;
gl10.glMatrixMode(GL10.GL_PROJECTION);
gl10.glLoadIdentity();
gl10.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
public void onDrawFrame(GL10 gl) {
// Just clear the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Begin drawing
//--------------
// These function calls can be experimented with for various effects such as transparency
// although certain functionality maybe device specific.
gl.glShadeModel(GL10.GL_FLAT);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
// Setup correct projection matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glOrthof(0.0f, mWidth, 0.0f, mHeight, 0.0f, 1.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glEnable(GL10.GL_TEXTURE_2D);
// Draw all Textures
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureName[0]);
((GL11)gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCrop, 0);
((GL11Ext)gl).glDrawTexfOES(0, 0, 0, imageWidth, imageHeight);
// Finish drawing
gl.glDisable(GL10.GL_BLEND);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glPopMatrix();
}
Have you tried to have all the images on drawable-nodpi and nowhere else?
I don't think it may be important but try these lines just before attaching the rendering.
glSurfaceView.setZOrderOnTop(true);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
glSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
The error can be related with transparency and PNG format.
If it doesn't work, could you please paste the code related with GLSurfaceView and the Renderer?
Thanks!
I am trying to generate a frambuffer object and use stencil inside a native android application using the NDK (r5b). Target device is running froyo 2.2, supporting OpenGL ES 2.0.
So, I've been coding lots of gl code in my c++ native libs and havent got through any problem except for this. I just can't seems to make it work.
Here's a code snipplet for the framebuffer creation. Completness is all good, but screen remains completly black. It's like the fbo I am creating is not really bound to the gl surface that is created by the Java part of the app. The rest of my app code is all good, if I remove the fbo creation and binding, everything works perfectly fine except that I don't have the stencils working which I need for my app.
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);
}
I've also tried rendering to a 2D texture instead of the renderbuffer...didn't worked either.
So, Is there a way I can fix this ? Am I getting something wrong here ? If anyone has any ideas please lemme know....been spending way too much time looking up this problem...hehe ;)
Thanks in advance !
Cheers !
EDIT :
Ok, I've manage to make the stencil buffer work but the FBO are just not working. I think OpenGL ES 2.0 is not fully supported by android (using r5b here btw). I think method stubs are defined, but not fully implemented. Or the GlSurfaceView created doesn't link correctly with the FBOs.
As for the stencil buffer, I had to do
glEnable(GL_DEPTH_TEST);
and remove the usage of glDepthMask in order for them to work correctly.
# Zennichimaro, For the stencil buffer usage !
During Initialisation :
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
During the rendering :
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;
}
When I need to use stencil I use the following methods depending on what I need :
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);
}
And Finally I do the double pass technic to draw inside the stencil ... Here's an example :
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();
My code is fairly complex so it's hard to only post what's related to the stencil, But I hope It'll help ;)