I am new to OpenGL, work on Android. Found good code example in Web with possibility to record everything. But I found one big problem: depth test doesn't work, so in my models all faces that opposite to camera are lighted even if they are behind another faces:
I think some mistakes could be in this part of code:
/**
* Prepares the off-screen framebuffer.
*/
private void prepareFramebuffer(int width, int height) {
GlUtil.checkGlError("prepareFramebuffer start");
int[] values = new int[1];
// Create a texture object and bind it. This will be the color buffer.
GLES20.glGenTextures(1, values, 0);
GlUtil.checkGlError("glGenTextures");
mOffscreenTexture = values[0]; // expected > 0
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mOffscreenTexture);
GlUtil.checkGlError("glBindTexture " + mOffscreenTexture);
// Create texture storage.
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
// Set parameters. We're probably using non-power-of-two dimensions, so
// some values may not be available for use.
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GlUtil.checkGlError("glTexParameter");
// Create framebuffer object and bind it.
GLES20.glGenFramebuffers(1, values, 0);
GlUtil.checkGlError("glGenFramebuffers");
mFramebuffer = values[0]; // expected > 0
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFramebuffer);
GlUtil.checkGlError("glBindFramebuffer " + mFramebuffer);
// Create a depth buffer and bind it.
GLES20.glGenRenderbuffers(1, values, 0);
GlUtil.checkGlError("glGenRenderbuffers");
mDepthBuffer = values[0]; // expected > 0
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, mDepthBuffer);
GlUtil.checkGlError("glBindRenderbuffer " + mDepthBuffer);
// Allocate storage for the depth buffer.
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
width, height);
GlUtil.checkGlError("glRenderbufferStorage");
// Attach the depth buffer and the texture (color buffer) to the framebuffer object.
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_RENDERBUFFER, mDepthBuffer);
GlUtil.checkGlError("glFramebufferRenderbuffer");
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, mOffscreenTexture, 0);
GlUtil.checkGlError("glFramebufferTexture2D");
// See if GLES is happy with all this.
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
// throw new RuntimeException("Framebuffer not complete, status=" + status);
}
// Switch back to the default framebuffer.
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GlUtil.checkGlError("prepareFramebuffer done");
}
Another important things that I have already done:
/**
* Prepares window surface and GL state.
*/
private void prepareGl(Surface surface) {
Log.d(TAG, "prepareGl");
EglCore.logCurrent("before creating");
GlUtil.checkGlError("debug");
if (mWindowSurface == null)
mWindowSurface = new WindowSurface(mEglCore, surface, false);
mWindowSurface.makeCurrent();
EglCore.logCurrent("after creation");
glClearColor(0f, 0f, 0f, 1f); //glClearColor(0.15f, 0.15f, 0.15f, 1f);
GlUtil.checkGlError("debug");
glEnable(GL_DEPTH_TEST);
GlUtil.checkGlError("debug");
glEnable(GL_CULL_FACE);
GlUtil.checkGlError("debug");
glCullFace(GL_BACK);
GlUtil.checkGlError("debug");
glShadeModel(GL_SMOOTH);
GlUtil.checkGlError("debug");
glEnable(GL_BLEND);
GlUtil.checkGlError("debug");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
What am I doing wrong? Where can be the mistake?
Add onDraw code:
private void draw() {
GlUtil.checkGlError("draw start");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LESS);
if (leftEye != null) {
resetMatrices();
setModelViewMatrix();
translateMEyes();
eyeTextureProgram.useProgram();
eyeTextureProgram.setViewAndTexture(modelViewProjectionMatrix, textureEye);
setProgramParams(eyeTextureProgram, textureEye);
leftEye.bindData(eyeTextureProgram);
leftEye.draw();
}
if (rightEye != null) {
rightEye.bindData(eyeTextureProgram);
rightEye.draw();
}
glDepthFunc(GL_LEQUAL);
resetMatrices();
setModelViewMatrix();
setProgramParams(faceTextureProgram, textureFace);
headBase.bindData(faceTextureProgram);
headBase.draw();
GlUtil.checkGlError("draw done");
}
Set the clearing value of the depth buffer to 1.0. Clearing value of the depth buffer should be the max value of the depth range which by default is 0.0 - 1.0.
glClearDepth(1.0)
Also, ensure that you clear both the depth and color buffer before your drawing.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
Related
I am using following method to create OpenGL ES texture on android.
private int createTexture(int width, int height, int i) {
int[] mTextureHandles = new int[1];
GLES20.glGenTextures(1, mTextureHandles, 0);
int textureID = mTextureHandles[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
return textureID;
}
Then uploading a bitmap to this texture and simply rendering it using GLSurfaceView's Renderer.
Most of the times it is working as expected,
But randomly the texture is displayed like this. (here GL_TEXTURE_WRAP_S mode is GLES20.GL_CLAMP_TO_EDGE
After changing wrap mode.
If GL_TEXTURE_WRAP_S = GLES20.GL_REPEAT then (again randomly) texture is displayed like this(notice the color change).
I have already tried using power of 2 texture.
Code for vertex buffer
private FloatBuffer createVertexBuffer(RectF glCoords) {
// RectF glCoords contains gl vertices.
// current Rect read from Logcat.
// left = -0.5833333, top = 0.5, right = 0.5833334, bottom = -0.5
float[] vertices = new float[]{glCoords.left, glCoords.top, 0, 1, // V1 - top left
glCoords.left, glCoords.bottom, 0, 1, // V2 - bottom left
glCoords.right, glCoords.bottom, 0, 1, // V3 - bottom right
glCoords.right, glCoords.top, 0, 1 // V4 - top right
};
FloatBuffer vBuffer = ByteBuffer.allocateDirect(vertices.length * bytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
vBuffer.put(vertices);
vBuffer.position(0);
return vBuffer;
}
IndicesBuffer is not used as I am using Triangle-Fan to render triangles.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
It would be really helpful if someone can point out as to what could be causing this
Your geometry seems to be a 4-vertex rectangle (quad), but the code wants to draw a fan with 6 vertices - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
Those extra 2 vertices aren't initialized, not specified in the vertex array. OpenGL will read beyond the defined part of the array. The results would be random, and I'd even expect crashes.
Replace 6 with 4 in glDrawArrays() call, this should fix the problem.
I develop video app on Android and use OpenGL for render and filtering video from camera via shaders. One of my shaders use two textures - one is live frame from camera and another is the previous render pass result. So I need to render picture twice - to screen for preview and to separate Texture for next render pass. To achieve it I use Frame Buffer object. Here is my code:
For init frame buffer:
private void initPredrawBuffer() {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
prevBuffer = new int[1];
GLES20.glGenFramebuffers(1, prevBuffer, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
prevTexture = new int[1];
GLES20.glGenTextures(1, prevTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mFrameWidth, mFrameHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, prevTexture[0], 0);
int[] depthRenderbuffers = new int[1];
GLES20.glGenRenderbuffers(1, depthRenderbuffers, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, mFrameWidth, mFrameHeight);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Incomplete buffer");
}
}
and for render:
private void draw(boolean offScreen, float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex,
int vertexCount, int coordsPerVertex, int vertexStride,
float[] texMatrix, FloatBuffer texBuffer, int textureId, int texStride) {
GlUtil.checkGlError("draw start");
if (offScreen)
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
else
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
// Select the program.
GLES20.glUseProgram(firstFrame && firstFrameProgram > 0 ? firstFrameProgram : mProgramHandle);
GlUtil.checkGlError("glUseProgram");
// Set the texture.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
// Copy the model / view / projection matrix over.
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Copy the texture transformation matrix over.
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Enable the "aPosition" vertex attribute.
GLES20.glEnableVertexAttribArray(maPositionLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect vertexBuffer to "aPosition".
GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Enable the "aTextureCoord" vertex attribute.
GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect texBuffer to "aTextureCoord".
GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
GLES20.GL_FLOAT, false, texStride, texBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Setting Light Trails filter params
if (mProgramType == ProgramType.TEXTURE_LIGHT_TRAILS && !firstFrame) {
GLES20.glUniform1i(muTextureNew, 0);
GlUtil.checkGlError("glUniform1i muTextureNew");
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GlUtil.checkGlError("temp glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GlUtil.checkGlError("temp glBindTexture");
GLES20.glUniform1i(muTexturePrev, 1);
GlUtil.checkGlError("glUniform1i muTexturePrev");
GLES20.glUniform1f(muLightTrailsExposure, lightTrailsKernel[0]);
GlUtil.checkGlError("glUniform1f muLightTrailsExposure");
GLES20.glUniform1f(muLightTrailsEcho, lightTrailsKernel[1]);
GlUtil.checkGlError("glUniform1f muLightTrailsEcho");
GLES20.glUniform1f(muLightTrailsLimit, lightTrailsKernel[2]);
GlUtil.checkGlError("glUniform1f muLightTrailsLimit");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GlUtil.checkGlError("temp glActiveTexture");
}
// Draw the rect.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
GlUtil.checkGlError("glDrawArrays");
GLES20.glFinish();
}
The problem is that render to frame buffer not working, and glReadPixels always return an empty array. Render to screen works fine.
On Android - ES 2. Reading from the framebuffer by calling glReadPixels + FBO. However, the byte array is 0. Interesting enough is that when I remove the binding code (leave the glReadPixels) it works.
Made me wonder if I didn't bind the buffer correctly, although when I check the framebuffer status (glCheckFramebufferStatus) I get GLES20.GL_FRAMEBUFFER_COMPLETE.
Any idea what I've done wrong?
int frameIdIndex=0,renderIdIndex=1,textureIdIndex=2;
int[] bufferId=new int[3];
Bitmap takeOne(Context cntxt) {
DisplayMetrics dm = cntxt.getResources().getDisplayMetrics();
int width = dm.widthPixels;
int height = dm.heightPixels;
//id index 0 frameId, 1 renderId 2 textureId;
GLES20.glGenFramebuffers(1,bufferId,frameIdIndex);
GLES20.glGenRenderbuffers(1, bufferId, renderIdIndex);
GLES20.glGenTextures(1, bufferId, textureIdIndex);
// bind texture and load the texture mip-level 0
// texels are RGB565
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,bufferId[textureIdIndex]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height,0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_SHORT_5_6_5,null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
// bind renderbuffer and create a 16-bit depth buffer
// width and height of renderbuffer = width and height of
// the texture
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, bufferId[renderIdIndex]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,GLES20.GL_DEPTH_COMPONENT16,width,height);
//bind the frameBuffer;
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,bufferId[frameIdIndex]);
//specify texture as color attachment
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D,bufferId[textureIdIndex],0);
//specify renderbuffer as depth_attachment
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,GLES20.GL_DEPTH_ATTACHMENT,GLES20.GL_RENDERBUFFER,bufferId[renderIdIndex]);
//check for framebuffer complete
int status= GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if(status !=GLES20.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("status:"+status+", hex:"+Integer.toHexString(status));
}
int screenshotSize = width * height;
ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
bb.order(ByteOrder.nativeOrder());
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, bb);
int pixelsBuffer[] = new int[screenshotSize];
bb.asIntBuffer().get(pixelsBuffer);
final Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
bitmap.setPixels(pixelsBuffer, screenshotSize - width, -width,
0, 0, width, height);
pixelsBuffer = null;
short sBuffer[] = new short[screenshotSize];
ShortBuffer sb = ShortBuffer.wrap(sBuffer);
bitmap.copyPixelsToBuffer(sb);
// Making created bitmap (from OpenGL points) compatible with
// Android
// bitmap
for (int i = 0; i < screenshotSize; ++i) {
short v = sBuffer[i];
sBuffer[i] = (short) (((v & 0x1f) << 11) | (v & 0x7e0) | ((v & 0xf800) >> 11));
}
sb.rewind();
bitmap.copyPixelsFromBuffer(sb);
// cleanup
GLES20.glDeleteRenderbuffers(1, bufferId,renderIdIndex);
GLES20.glDeleteFramebuffers(1, bufferId ,frameIdIndex);
GLES20.glDeleteTextures(1, bufferId,textureIdIndex);
return bitmap;
}
Your formats and types are somewhat mixed up. This glTexImage2D() should already give you a GL_INVALID_OPERATION call if you check with glGetError():
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,
GLES20.GL_RGBA, width, height, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);
GL_UNSIGNED_SHORT_5_6_5 can only be used with a format of GL_RGB. From the documentation:
GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_5_6_5 and format is not GL_RGB.
To avoid this error condition, the call needs to be:
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,
GLES20.GL_RGB, width, height, 0,
GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);
The glReadPixels() call itself looks fine to me, so I believe that should work once you got a valid texture to render to.
The bitmap.setPixels() call might be problematic. The documentation says that it expects ARGB colors, and you will have RGBA here. But that's beyond the main scope of your question.
This is just to share something that took me a long time to figure out. If you don't need your Depthbuffer or don't have a Depth Buffer Attachment Point setup in EGL this might help.
For some reason I couldn't get rendering to texture to work setting the render buffer object RBO to depth buffer: like so
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
Causes error status == GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
If I change render buffer storage to GLES20.GL_RGBA4, as opposed to GLES20.DEPTH_COMPONENT16 and change GLES20.GL_DEPTH_ATTACHMENT to GLES20.GL_COLOR_ATTACHMENT0 then the error goes away,
Change this
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, juliaRBO[0]);
rain.checkGlError("glBindRenderBuffer");
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.DEPTH_COMPONENT16,
rain.width, rain.height);
to this
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, juliaRBO[0]);
rain.checkGlError("glBindRenderBuffer");
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_RGBA4,
rain.width, rain.height);
And the original code to this:
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
then status == GLES20.GL_FRAMEBUFFER_COMPLETE
But the texture is empty.
here is the call to create storage texture
// bind texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, juliaTex[0]);
// clamp texture to edges
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
rain.checkGlError("glTexParameter JuliaTex");
// create it
/*
int[] buf = new int[rain.width * rain.height];
juliaTexBuff = ByteBuffer.allocateDirect(buf.length
* rain.FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asIntBuffer();
*/
// generate the textures
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
rain.width, rain.height, 0, GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_SHORT_4_4_4_4, null);
To get this to work in addition to attaching the render buffer to the color attachment point I swapped the order of the Framebuffer attachments:
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,
juliaRBO[0]);
rain.checkGlError("glFramebufferRenderbuffer");
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
juliaTex[0], 0);
rain.checkGlError("glFramebufferTexture2D");
So that Texture2D is attached to the Framebuffer color layer after Renderbuffer. I assume the last connection point is the point OpenGL ES uses.
I am rendering to a frame buffer, and then I want to use that as a texture.
I can save the frame buffer to a file using glReadPixels so I am sure that I am rendering OK.
I can bind to fixed texture and render that OK.
But I cannot bind to the frame buffer to render that in place of the fixed texture.
//setup:
private void setupRenderToTexture() {
fb = new int[numberOfBuffers];
depthRb = new int[numberOfBuffers];
renderTex = new int[numberOfBuffers];
texBuffer = new IntBuffer[numberOfBuffers];
// generate
GLES20.glGenFramebuffers(fb.length, fb, 0);
GLES20.glGenRenderbuffers(depthRb.length, depthRb, 0);
GLES20.glGenTextures(renderTex.length, renderTex, 0);
GLErrorHandler.checkGlError("glGenFramebuffers");
for (int i = 0; i < fb.length; i++) {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[i]);
// generate color texture
GLState.Instance.bindTexture(0, renderTex[i]);
// parameters
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
// create it
// create an empty intbuffer first?
int[] fileData = new int[width * height];
texBuffer[i] = IntBuffer.wrap(fileData);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width,
height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
texBuffer[i]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
renderTex[i], 0);
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[i]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,
GLES20.GL_DEPTH_COMPONENT16, width, height);
GLErrorHandler.checkGlError("glRenderbufferStorage or above");
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
}
Use the frame buffer:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
Save the frame buffer (for testing):
GLES20.glReadPixels(sourceX, sourceY, width, height, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, ib);
Then to render to screen:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture); //some simple texture works but:
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[0]); //frame buffer texture does not work
All I get is a black screen if I bind to renderTex[0]
You are mis-using the FBO. You have to attach an empty texture so that it can render into it.
See this page