creating a framebuffer to take an image from external oes - android

I am trying to do multi pass rendering with framebuffer the issue is that the source is the camera so the texInput is not of type GL_TEXTURE_2D it is of type GL_TEXTURE_EXTERNAL_OES tho, if I use the function glTexImage2D it gives a black screen when I use that texture in the future after rendering to it without any errors glErros.
On the other hand if I don't use it(because it does not support GL_TEXTURE_EXTERNAL_OES) it gives me framebuffer status of NOT_COMPLETE
here is my code for creating the framebuffer and the texture that I want to associate to it.
fun prepareFBO() {
val intArray = IntArray(1)
glGenFramebuffers(1, intArray, 0)
fboId = intArray.first()
glGenTextures(1, intArray, 0)
texId = intArray.first()
glBindTexture(GL_TEXTURE_2D, texId)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,1080, 1920, 0, GL_RGBA, GL_UNSIGNED_BYTE, null)
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_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glBindFramebuffer(GL_FRAMEBUFFER, fboId)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0)
val status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
Log.e(TAG, "prepareFBO: ${status == GL_FRAMEBUFFER_COMPLETE}")
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glBindTexture(GL_TEXTURE_2D, 0)
}
the rest is just normal glDrawArrays and glActiveTexture that already works fine when I draw directly to the default framebuffer, if needed please let me know and I will share them.
Thanks for help!
UPDATE:
I found that I need instead of using glTexImage2d I can use eglBindTexImage instead so the final code is:
fun prepareFBO() {
val intArray = IntArray(1)
glGenFramebuffers(1, intArray, 0)
fboId = intArray.first()
glBindFramebuffer(GL_FRAMEBUFFER, fboId)
glGenTextures(1, intArray, 0)
texId = intArray.first()
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId)
checkGlError("Error 1")
eglBindTexImage(eglGetCurrentDisplay(), windowSurface!!.eglSurface, EGL_BACK_BUFFER)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, texId, 0)
val status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
Log.e(TAG, "prepareFBO: is status complete? => ${status == GL_FRAMEBUFFER_COMPLETE}")
}
while this looks like it makes sense, still I am getting the status of the framebuffer as not complete :/

Related

opengl es multi-pass blurring the second pass overrides the first pass

I am not very good with opengl es so any beginner mistake in the code is justified. I have implemented the draw function to execute the same fragment shader with different uniform variable called blurringDirection, if I execute the horizontal blurring alone(by setting the blurringDirection to 0) it works fine, also the same for the vertical but when I try to combine them together the second overrides the first. Here is my draw() function:
fun draw(
mvpMatrix: FloatArray?,
vertexBuffer: FloatBuffer?,
firstVertex: Int,
vertexCount: Int,
coordsPerVertex: Int,
vertexStride: Int,
texMatrix: FloatArray?,
texBuffer: FloatBuffer?,
textureId: Int,
texStride: Int,
) {
//creating an intermediate texture
val intermediateTexIdArr = IntArray(1)
GLES20.glGenTextures(1, intermediateTexIdArr, 0)
glBindTexture(GL_TEXTURE_2D, intermediateTexIdArr[0])
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 640, 360, 0, GL_RGBA, GL_UNSIGNED_BYTE, null)
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_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glBindTexture(GL_TEXTURE_2D, 0)
//creating a framebuffer and attaching the newly created texture to it.
val frameBufferIdArr = IntArray(1)
GLES20.glGenFramebuffers(1, frameBufferIdArr, 0)
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferIdArr[0])
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTexIdArr[0], 0)
val status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
Timber.d("KingArmstring: Framebuffer status is complete? ${status == GL_FRAMEBUFFER_COMPLETE}") //this prints true
if (status != GL_FRAMEBUFFER_COMPLETE) throw Exception("Framebuffer is not setup correctly")
//bind to the framebuffer instead of to the screen.
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferIdArr[0])
glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
// Select the program.
glUseProgram(programHandle)
checkGlError("glUseProgram")
// Set the texture.
glActiveTexture(GL_TEXTURE0)
glBindTexture(textureTarget, textureId) //textureId is the main id that has the original image
// Copy the model / view / projection matrix over.
glUniformMatrix4fv(mvpMatrixLoc, 1, false, mvpMatrix, 0)
checkGlError("glUniformMatrix4fv")
// Copy the texture transformation matrix over.
glUniformMatrix4fv(texMatrixLoc, 1, false, texMatrix, 0)
checkGlError("glUniformMatrix4fv")
// Enable the "aPosition" vertex attribute.
glEnableVertexAttribArray(positionLoc)
checkGlError("glEnableVertexAttribArray")
// Connect vertexBuffer to "aPosition".
glVertexAttribPointer(
positionLoc, coordsPerVertex,
GL_FLOAT, false, vertexStride, vertexBuffer
)
checkGlError("glVertexAttribPointer")
// Enable the "aTextureCoord" vertex attribute.
glEnableVertexAttribArray(textureCoordLoc)
checkGlError("glEnableVertexAttribArray")
// Connect texBuffer to "aTextureCoord".
glVertexAttribPointer(
textureCoordLoc, 2,
GL_FLOAT, false, texStride, texBuffer
)
checkGlError("glVertexAttribPointer")
if (programType == VIDEO_STREAM) {
glUniform1f(brightnessLoc, brightness)
glUniform1f(contrastLoc, contrast)
glUniform1f(saturationLoc, saturation)
glUniform1f(gammaLoc, gamma)
glUniform1f(whiteBalanceTempLoc, whiteBalanceTemp)
glUniform1f(whiteBalanceTintLoc, whiteBalanceTint)
glUniform1f(whiteBalanceEnabledLoc, whiteBalanceEnabled)
glUniform1f(hueAdjLoc, hueAdj)
glUniform1f(hueAdjEnabledLoc, hueAdjEnabled)
glUniform1f(sharpnessLoc, sharpness)
glUniform1f(imageWidthFactorLoc, imageWidthFactor)
glUniform1f(imageHeightFactorLoc, imageHeightFactor)
}
glUniform1i(blurringDirectionLoc, 0)
// Draw the rect.
glDrawArrays(GL_TRIANGLE_STRIP, firstVertex, vertexCount)//rendering to the framebuffer with the blurringDirection = 0
checkGlError("glDrawElements")
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, intermediateTexIdArr[0])
glUniform1i(blurringDirectionLoc, 1)
glDrawArrays(GL_TRIANGLE_STRIP, firstVertex, vertexCount)//drawing on the screen second pass with the blurringDirection = 1.
glDisableVertexAttribArray(positionLoc)
glDisableVertexAttribArray(textureCoordLoc)
GLES20.glDeleteFramebuffers(1, frameBufferIdArr, 0)
GLES20.glDeleteTextures(1, intermediateTexIdArr, 0)
}

Android12 opengles3.0 glTexImage2D 0x502 error

I have 5 textures, such as diffuse specular normal roughness ao, roughness and ao are 8bit jpg.
I got glError 0x502 while loading rouggness/ao texture after call glTexImage2D, but other three texture is OK.
And this issue just occured with android 12, android 11/10/9/8 is no error. How I can fix this issue?
code:
GLuint textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
GLenum format;
if (nrComponents == 1) {
format = GL_RED;
} else if (nrComponents == 3) {
format = GL_RGB;
} else {
format = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
According to https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml, GL_RED is not an acceptable value for internalFormat (parameter 3 in glTexImage2D).
I think you need internalFormat=GL_R8 and format=GL_RED. Or you could use GL_LUMINANCE for both.

Render to texture attached to Frame Buffer Object (texture appears black)

I have generated a frame buffer object(FBO), bind it, attached a texture to its GL_COLOR_ATTACHMENT0. Then ensure that I get its status as GL_FRAMEBUFFER_COMPLETE. I have another texture(which is displaying on display), let's call it workingTexture. Now I want to render this workingTexture onto FBO, so I bind this FBO and then render workingTexture.
Then I bind default frame buffer(reserved for display) and try to render the texture attached to FBO, thinking that I will get my texture onto display, but I get black texture.
Relevant code
code to generate workingTexture...
int[] workingTexture = new int[1];
glGenTextures(1, workingTexture, 0); // generate workingTexture
glActiveTexture(GL_TEXTURE0); // attach it to TEXTURE_UNIT0
glBindTexture(GL_TEXTURE_2D, workingTexture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
code to generate fbo
int[] fboName = new int[1];
int[] fboTextureName = new int[1];
final int fboTextureUnit = 1; // attach this texture to texture unit GL_TEXTURE1
glGenFramebuffers(1, fboName, 0);
int generatedTextureNameForFBO =
generateTextureForFBO(fboTextureUnit,
width, height);
fboTextureName[0] = generatedTextureNameForFBO;
glBindFramebuffer(GL_FRAMEBUFFER, fboName[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, generatedTextureNameForFBO, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
// created FBO is not complete
throw new RuntimeException("FBO status INCOMPLETE 😔😔");
}
method used to generate texture attached to fbo
private int generateTextureForFBO(#IntRange(from = 0) final int textureUnit,
#IntRange(from = 1) final int width,
#IntRange(from = 1) final int height) {
int[] textureName = new int[1];
glGenTextures(1, textureName, 0);
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, textureName[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
// glBindTexture(GL_TEXTURE_2D, 0);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
// glBindTexture(GL_TEXTURE_2D, 0);
return textureName[0];
}
Now coming to drawing part...
#Override
public void onDrawFrame(GL10 unused) {
glClear(GL_COLOR_BUFFER_BIT);
//renderTex(mViewMatrix, 0, texProgram); // this texture is drawing on screen
glBindFramebuffer(GL_FRAMEBUFFER, fboName[0]);
renderTex(mViewMatrix, 0, texProgram); // rendering workingTexture onto FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
renderTex(mViewMatrix, fboTextureUnit[0], texProgram); // texture appears black
}
renderTex is a simple method to render texture. It is working fine.
Also I have checked for GL_ERROR but there is no error.
My understanding of application created FBO is that every read and write glCall will happen on currently bound FBO, so is my understanding of FBO incorrect, or is there some error in my code.
Platform OpenGL|es 20 on Android
The texture which is generated in generateTextureForFBO is mipmap incomplete.
If you do not generate mipmaps (by glGenerateMipmap), then setting the GL_TEXTURE_MIN_FILTER is important. Since the default filter is GL_NEAREST_MIPMAP_LINEAR the texture would be mipmap incomplete, if you don not change the minifying function to GL_NEAREST or GL_LINEAR.
Set the texture minifying function (GL_TEXTURE_MIN_FILTER) by glTexParameter:
glBindTexture(GL_TEXTURE_2D, textureName[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Cubemap texture with bitmap in OpenGL ES 2.0/3.0

When I create a cubemap texture with simple colors, this works well:
#JvmStatic
fun createSimpleTextureCubemap() {
val textureId = IntArray(1)
val cubeFace0 = byteArrayOf(127, 127, 127)
val cubeFace1 = byteArrayOf(0, 127, 0)
... // create other cube faces with simple color
val cubeFaces = ByteBuffer.allocateDirect(3)
glGenTextures(1, textureId, 0)
glBindTexture(GL_TEXTURE_CUBE_MAP, textureId[0])
cubeFaces.put(cubeFace0).position(0)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB,
1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, cubeFaces)
cubeFaces.put(cubeFace1).position(0)
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB,
1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, cubeFaces)
...
return textureId[0]
}
But when I try to create a cubemap texture with bitmap:
#JvmStatic
fun createTextureCubemap(context: Context, rowID: Int) {
val input = context.resources.openRawResource(rowID)
val bitmap = BitmapFactory.decodeStream(input)
val textureId = IntArray(1)
glGenTextures(1, textureId, 0)
glBindTexture(GL_TEXTURE_CUBE_MAP, textureId[0])
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, bitmap, 0)
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, bitmap, 0)
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, bitmap, 0)
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, bitmap, 0)
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, bitmap, 0)
GLUtils.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, bitmap, 0)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
return textureId[0]
}
Then the object turns black. Someone may suggest why the cubemap with the bitmap does not work (black color)?
Thanks for any comment/answer.
Textures for Cubemaps need to be square. As mentioned in the comments, the bitmap used was not square.
From glTexImage2D reference (GLUtils.texImage2D is a convenience wrapper around glTexImage2D)
GL_INVALID_VALUE is generated if target is one of the six cube map 2D image targets and the width and height parameters are not equal.

Load Texture From File problem Android NDK and OpenGL

I am trying to load an image through OpenGL and stbi_load on android ndk. The problem is that it is generating an invalid texture (equal to zero).
LoadTextureFromFile("/storage/emulated/0/Download/BPV/mic_close.jpg", &my_image_texture, &my_image_width, &my_image_height);
bool CGUI::LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_width, int* out_height)
{
// Load from file
int image_width = 0;
int image_height = 0;
unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4);
if (image_data == NULL)
return false;
// Create a OpenGL texture identifier
GLuint image_texture;
glGenTextures(1, &image_texture);
glBindTexture(GL_TEXTURE_2D, image_texture);
// Setup filtering parameters for display
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(0x0CF2, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
stbi_image_free(image_data);
*out_texture = image_texture; // Receive zero
*out_width = image_width;
*out_height = image_height;
return true;
}
I use libGLESv2
GLuint image_texture;
glGenTextures(1, &image_texture);
...
*out_texture = image_texture; // Receive zero
glGenTextures() just allocates new object and practically never fails, save when called without active OpenGL context.
On Android platform, OpenGL rendering is usually done in dedicated working thread (different from GUI thread), so most likely you call the method from the wrong thread or before OpenGL context initialization (which cannot be deduced from the given code sample).

Categories

Resources