Android YUV-RGB conversion in OpenGL ES 2.0 fragment shader [duplicate] - android

I've a problem with convertion of camera preview in Android from YUV format to RGB. The purpose of conversion is to apply some effects. I try to convert by fragment shader because convertion by native code is slow (about 14fps). The reference which I've used is http://jyrom.tistory.com/m/post/view/id/187. I try to port this code to Android platform, but the result is black-green rectangles. But, I can watch some form through the output which I get. Could you please try to help me to resolve this issue. I believe this is popular problem: apply effects to camera preview. I also give a link to my project for testing: https://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip.
Thank you.
UPDATED:
This is my onPreviewFrame method:
public void onPreviewFrame(byte[] data, Camera camera) {
yBuffer.put(data);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4 * 2);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
This is how I bind byte arrays to OpenGL texture in onDrawFrame method:
GLES20.glUniform1i(yTexture, 1);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glUniform1i(uTexture, 2);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glUniform1i(vTexture, 3);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
And this is my fragment shader code:
#ifdef GL_ES
precision highp float;
#endif
varying vec2 v_texCoord;
uniform sampler2D y_texture;
uniform sampler2D u_texture;
uniform sampler2D v_texture;
void main()
{
float nx,ny,r,g,b,y,u,v;
nx=v_texCoord.x;
ny=v_texCoord.y;
y=texture2D(y_texture,v_texCoord).r;
u=texture2D(u_texture,v_texCoord).r;
v=texture2D(v_texture,v_texCoord).r;
y=1.1643*(y-0.0625);
u=u-0.5;
v=v-0.5;
r=y+1.5958*v;
g=y-0.39173*u-0.81290*v;
b=y+2.017*u;
gl_FragColor = vec4(r,g,b,1.0);
}

I don't know if you solved your problem.
I used your code and I solved in this mode.
public class MyRenderer implements Renderer{
public static final int recWidth = Costanti.recWidth;
public static final int recHeight = Costanti.recHeight;
private static final int U_INDEX = recWidth*recHeight;
private static final int V_INDEX = recWidth*recHeight*5/4;
private static final int LENGTH = recWidth*recHeight;
private static final int LENGTH_4 = recWidth*recHeight/4;
private int previewFrameWidth = 256;
private int previewFrameHeight = 256;
private int[] yTextureNames;
private int[] uTextureNames;
private int[] vTextureNames;
private MainActivity activity;
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private int mProgramObject;
private int mPositionLoc;
private int mTexCoordLoc;
private int yTexture;
private int uTexture;
private int vTexture;
private final float[] mVerticesData = { -1.f, 1.f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.f, -1.f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.f, -1.f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.f, 1.f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };
private ByteBuffer yBuffer;
private ByteBuffer uBuffer;
private ByteBuffer vBuffer;
private IntBuffer frameBuffer;
private IntBuffer renderBuffer;
private IntBuffer parameterBufferWidth;
private IntBuffer parameterBufferHeigth;
byte[] ydata = new byte[LENGTH];
byte[] uData = new byte[LENGTH_4];
byte[] vData = new byte[LENGTH_4];
public MyRenderer(MainActivity activity) {
this.activity = activity;
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
yBuffer = MyGraphUtils.makeByteBuffer(LENGTH);
uBuffer = MyGraphUtils.makeByteBuffer(LENGTH_4/* * 2*/);
vBuffer = MyGraphUtils.makeByteBuffer(LENGTH_4);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.d("debug", "on surface created");
// Define a simple shader program for our point.
final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);
frameBuffer = IntBuffer.allocate(1);
renderBuffer= IntBuffer.allocate(1);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glGenFramebuffers(1, frameBuffer);
GLES20.glGenRenderbuffers(1, renderBuffer);
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer.get(0));
GLES20.glClear(0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
320, 240);
parameterBufferHeigth = IntBuffer.allocate(1);
parameterBufferWidth = IntBuffer.allocate(1);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_WIDTH, parameterBufferWidth);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_HEIGHT, parameterBufferHeigth);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!=GLES20.GL_FRAMEBUFFER_COMPLETE){
Log.d("debug", "gl frame buffer status != frame buffer complete");
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glClear(0);
mProgramObject = loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int yTextureName = yTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int uTextureName = uTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
vTexture = GLES20.glGetUniformLocation(mProgramObject, "v_texture");
vTextureNames = new int[1];
GLES20.glGenTextures(1, vTextureNames, 0);
int vTextureName = vTextureNames[0];
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
#Override
public final void onDrawFrame(GL10 gl) {
Log.d("debug", "on Draw frame");
// Clear the color buffer
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Use the program object
GLES20.glUseProgram(mProgramObject);
// Load the vertex position
mVertices.position(0);
GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5*4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5*4, mVertices);
GLES20.glEnableVertexAttribArray(mPositionLoc);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glUniform1i(yTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1+2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glUniform1i(uTexture, 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1+1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glUniform1i(vTexture, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
}
public void setPreviewFrameSize(int realWidth, int realHeight) {
previewFrameHeight = realHeight;
previewFrameWidth = realWidth;
}
public static String readTextFileFromRawResource(final Context context, final int resourceId) {
final InputStream inputStream = context.getResources().openRawResource(resourceId);
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String nextLine;
final StringBuilder body = new StringBuilder();
try {
while ((nextLine = bufferedReader.readLine()) != null) {
body.append(nextLine);
body.append('\n');
}
} catch (IOException e) {
return null;
}
return body.toString();
}
public static int loadShader(int type, String shaderSrc) {
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES20.glCreateShader(type);
if (shader == 0) {
return 0;
}
// Load the shader source
GLES20.glShaderSource(shader, shaderSrc);
// Compile the shader
GLES20.glCompileShader(shader);
// Check the compile status
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
return shader;
}
public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
if (vertexShader == 0) {
return 0;
}
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
if (fragmentShader == 0) {
GLES20.glDeleteShader(vertexShader);
return 0;
}
// Create the program object
programObject = GLES20.glCreateProgram();
if (programObject == 0) {
return 0;
}
GLES20.glAttachShader(programObject, vertexShader);
GLES20.glAttachShader(programObject, fragmentShader);
// Link the program
GLES20.glLinkProgram(programObject);
// Check the link status
GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0) {
Log.e("ESShader", "Error linking program:");
Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
GLES20.glDeleteProgram(programObject);
return 0;
}
// Free up no longer needed shader resources
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
return programObject;
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
System.arraycopy(data, 0, ydata, 0, LENGTH);
yBuffer.put(ydata);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
}

Not sure if you have already fixed this problem.My answer
By default Camera output is NV12, but in fragment shader YUV to RGB you are using YV12 -> RGB.
You will have to do
setPreviewFormat(ImageFormat.YV12);, or may be use some other shader
There are 3 textures , make sure you do
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, muTextureName)
before call to any glTexImage2D. and glTexSubImage2D
You can also use glTexSubImage2D with every frame and glTexImage2D once.
size of U and V is same , atleast for YV12,
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4 * 2);
should be
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
change the size accordingly in the code.

For the fastest and most optimized way, just use the common GL Extention
//Fragment Shader
#extension GL_OES_EGL_image_external : require
uniform samplerExternalOES u_Texture;
Than in Java
surfaceTexture = new SurfaceTexture(textureIDs[0]);
try {
someCamera.setPreviewTexture(surfaceTexture);
} catch (IOException t) {
Log.e(TAG, "Cannot set preview texture target!");
}
someCamera.startPreview();
private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
In Java GL Thread
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureIDs[0]);
GLES20.glUniform1i(uTextureHandle, 0);
The color conversion is already done for you.
You can do what ever you want right in the Fragment shader.
Hope that saves you some time in your research.

Finally made your project display camera previews.
I found 2 problems:
1. Before binding and changing surface characteristics you have to call GLES20.glActiveTexture(GLES20.surfacenumber);
2. More important and hidden problem is that
GLES20.glTexImage2D() does not work with width and height, which are not power of 2 numbers.
After loading texture with size, for example, 1024X1024, you should call GLES20.glTexSubImage2D()
Good luck!

I applied the solution form How to render Android's YUV-NV21 camera image on the background in libgdx with OpenGLES 2.0 in real-time? to the project shared in the question and got a working project. If you are like me searching for tutorial code that does YUV to RGB conversion by fragment shader, you can simply do the following steps to get a working example.
Download the project https://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip and unzip.
Replace file GLRenderer.java and res/raw/f_convert.glsl entirely by the code shared below.
Open the project in Eclipse, or import the project to Android Studio.
The main issues of the code in the question are:
without GLES20.glActiveTexture(GLES20.GL_TEXTURE1);, yBuffer is not passed to GL.
the YUV data takes YUV-NV21 format, and u_texture and v_texture wasn't passed and handled correctly in the shader. Refer to this post for more information.
Now the corrected code: please replace GLRenderer.java with
package com.filtergl.shader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
public class GLRenderer
implements Renderer, PreviewCallback {
private static final int LENGTH = 76800;
private static final int LENGTH_2 = 38400;
private ActivityFilterGL activity;
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private int previewFrameWidth = 256;
private int previewFrameHeight = 256;
private int mProgramObject;
private int mPositionLoc;
private int mTexCoordLoc;
// private int mSamplerLoc;
private int yTexture;
private int uTexture;
private int vTexture;
private final float[] mVerticesData = { -1.f, 1.f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.f, -1.f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.f, -1.f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.f, 1.f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };
private ByteBuffer frameData = null;
private ByteBuffer yBuffer;
private ByteBuffer uBuffer;
public GLRenderer(ActivityFilterGL activity) {
this.activity = activity;
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
yBuffer = GraphicsUtil.makeByteBuffer(LENGTH);
uBuffer = GraphicsUtil.makeByteBuffer(LENGTH_2);
}
#Override
public final void onDrawFrame(GL10 gl) {
// Clear the color buffer
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Use the program object
GLES20.glUseProgram(mProgramObject);
// Load the vertex position
mVertices.position(0);
GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
GLES20.glEnableVertexAttribArray(mPositionLoc);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glUniform1i(yTexture, 1);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glUniform1i(uTexture, 2);
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA,
160, 120, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, uBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Define a simple shader program for our point.
final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);
// Load the shaders and get a linked program object
mProgramObject = loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
int[] yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int yTextureName = yTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureName);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
int[] uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int uTextureName = uTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureName);
// Set the background clear color to black.
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
public void setPreviewFrameSize(int realWidth, int realHeight) {
previewFrameHeight = realHeight;
previewFrameWidth = realWidth;
// frameData = GraphicsUtil.makeByteBuffer(previewFrameHeight * previewFrameWidth * 3);
}
public static String readTextFileFromRawResource(final Context context, final int resourceId) {
final InputStream inputStream = context.getResources().openRawResource(resourceId);
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String nextLine;
final StringBuilder body = new StringBuilder();
try {
while ((nextLine = bufferedReader.readLine()) != null) {
body.append(nextLine);
body.append('\n');
}
} catch (IOException e) {
return null;
}
return body.toString();
}
public static int loadShader(int type, String shaderSrc) {
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES20.glCreateShader(type);
if (shader == 0) {
return 0;
}
// Load the shader source
GLES20.glShaderSource(shader, shaderSrc);
// Compile the shader
GLES20.glCompileShader(shader);
// Check the compile status
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
return shader;
}
public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
if (vertexShader == 0) {
return 0;
}
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
if (fragmentShader == 0) {
GLES20.glDeleteShader(vertexShader);
return 0;
}
// Create the program object
programObject = GLES20.glCreateProgram();
if (programObject == 0) {
return 0;
}
GLES20.glAttachShader(programObject, vertexShader);
GLES20.glAttachShader(programObject, fragmentShader);
// Link the program
GLES20.glLinkProgram(programObject);
// Check the link status
GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0) {
Log.e("ESShader", "Error linking program:");
Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
GLES20.glDeleteProgram(programObject);
return 0;
}
// Free up no longer needed shader resources
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
return programObject;
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
yBuffer.put(data, 0, LENGTH);
yBuffer.position(0);
uBuffer.put(data, LENGTH, LENGTH/2);
uBuffer.position(0);
}
}
and replace f_convert.glsl with
#ifdef GL_ES
precision highp float;
#endif
varying vec2 v_texCoord;
uniform sampler2D y_texture;
uniform sampler2D u_texture;
void main()
{
float r, g, b, y, u, v;
//We had put the Y values of each pixel to the R,G,B components by
//GL_LUMINANCE, that's why we're pulling it from the R component,
//we could also use G or B
y = texture2D(y_texture, v_texCoord).r;
//We had put the U and V values of each pixel to the A and R,G,B
//components of the texture respectively using GL_LUMINANCE_ALPHA.
//Since U,V bytes are interspread in the texture, this is probably
//the fastest way to use them in the shader
u = texture2D(u_texture, v_texCoord).a - 0.5;
v = texture2D(u_texture, v_texCoord).r - 0.5;
//The numbers are just YUV to RGB conversion constants
r = y + 1.13983*v;
g = y - 0.39465*u - 0.58060*v;
b = y + 2.03211*u;
gl_FragColor = vec4(r,g,b,1.0);
}

Related

Can see any image

I try to display a texture on OpenGLES 3.0 but I can see any image from it.
The GLRenderer is :
public class CameraGLRenderer implements GLSurfaceView.Renderer{
public static final String TAG = "com.example.CameraGLRenderer";
private CameraImage mCameraImage;
public CameraGLRenderer(int width, int heigh) {
mCameraImage = new CameraImage(width,heigh);
}
#Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
// Set the background frame color
GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
#Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES30.glActiveTexture(GLES30.GL_ACTIVE_TEXTURE);
GLES30.glViewport(0, 0, width, height);
// float ratio = (float) width / height;
//
// // this projection matrix is applied to object coordinates
// // in the onDrawFrame() method
// Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl10) {
mCameraImage.draw();
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES30.GL_VERTEX_SHADER)
// or a fragment shader type (GLES30.GL_FRAGMENT_SHADER)
int shader = GLES30.glCreateShader(type);
// add the source code to the shader and compile it
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
public void onPreviewFrame(byte[] data) {
mCameraImage.onPreviewFrame(data);
}
}
And my camera image class:
public CameraImage(int width,int height) {
Log.d(TAG,"CameraImage constructor");
mWidth = width;
mHeight = height;
U_INDEX = width*height;
V_INDEX = width*height*5/4;
LENGTH = width*height;
LENGTH_4 = width*height/4;
yData = new byte[LENGTH];
uData = new byte[LENGTH_4];
vData = new byte[LENGTH_4];
yBuffer = ByteBuffer.allocate(LENGTH);
uBuffer = ByteBuffer.allocate(LENGTH_4);
vBuffer = ByteBuffer.allocate(LENGTH_4);
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
// prepare shaders and OpenGL program
int vertexShader = CameraGLRenderer.loadShader(
GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = CameraGLRenderer.loadShader(
GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES30.glCreateProgram(); // create empty OpenGL Program
GLES30.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
CameraGLRenderer.checkGlError("glAttachShader");
GLES30.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
CameraGLRenderer.checkGlError("glAttachShader");
GLES30.glLinkProgram(mProgram); // create OpenGL program executables
CameraGLRenderer.checkGlError("glLinkProgram");
// Get the attribute locations
mPositionLoc = GLES30.glGetAttribLocation(mProgram, "a_position");
CameraGLRenderer.checkGlError("glGetAttribLocation");
mTexCoordLoc = GLES30.glGetAttribLocation(mProgram, "a_texCoord");
CameraGLRenderer.checkGlError("glGetAttribLocation");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glEnable");
yTexture = GLES30.glGetUniformLocation(mProgram, "y_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
yTextureNames = new int[1];
GLES30.glGenTextures(1, yTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int yTextureName = yTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glEnable");
uTexture = GLES30.glGetUniformLocation(mProgram, "u_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
uTextureNames = new int[1];
GLES30.glGenTextures(1, uTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int uTextureName = uTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE2);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glBindTexture");
vTexture = GLES30.glGetUniformLocation(mProgram, "v_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
vTextureNames = new int[1];
GLES30.glGenTextures(1, vTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int vTextureName = vTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE2);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
//
//
// // Set the background clear color to black.
GLES30.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
CameraGLRenderer.checkGlError("glClearColor");
}
public void draw() {
Log.d(TAG, "Draw");
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
CameraGLRenderer.checkGlError("glClear"); ///ERROR !!!!
// Add program to OpenGL environment
GLES30.glUseProgram(mProgram);
CameraGLRenderer.checkGlError("glUseProgram");
// Load the vertex position
mVertices.position(0);
GLES30.glVertexAttribPointer(mPositionLoc, 3, GLES30.GL_FLOAT, false, 5*4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES30.glVertexAttribPointer(mTexCoordLoc, 2, GLES30.GL_FLOAT, false, 5*4, mVertices);
// Enable a handle to the triangle vertices
GLES30.glEnableVertexAttribArray(mPositionLoc);
GLES30.glEnableVertexAttribArray(mTexCoordLoc);
CameraGLRenderer.checkGlError("glEnableVertexAttribArray");
CameraGLRenderer.checkGlError("glEnableVertexAttribArray");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
1920, 1080, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, yBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+1);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureNames[0]);
GLES30.glUniform1i(yTexture, 1);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
960, 540, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, uBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+2);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureNames[0]);
GLES30.glUniform1i(uTexture, 2);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
960, 540, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, vBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+3);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureNames[0]);
GLES30.glUniform1i(vTexture, 3);
// Draw the square
GLES30.glDrawElements(
GLES30.GL_TRIANGLES, mIndicesData.length,
GLES30.GL_UNSIGNED_SHORT, mVertices);
}
public void onPreviewFrame(byte[] data) {
System.arraycopy(data, 0, yData, 0, LENGTH);
yBuffer.put(yData);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
}
The program goes through the draw function of the CameraImage class but the image is still black.
According to the fragmentShaderCode the image should be red but the image are still black.
The program doesn't seem to execute the shader.
Edit:
I modify the code according to message you send me. I also add glerror analyse.
I get an error on that line :
Log.d(TAG, "Draw");
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
CameraGLRenderer.checkGlError("glClear"); ///ERROR !!!!
This is the error I get:
08-21 07:12:03.644 6604-6622/com.example E/AndroidRuntime: FATAL EXCEPTION: GLThread 426
Process: com.example, PID: 6604
java.lang.RuntimeException: glClear: glError 1282
at com.example.CameraGLRenderer.checkGlError(CameraGLRenderer.java:90)
Edit2:
I mixe the CameraGLRenderer and the CameraImage into one Class MyRenderer I found on stackoverflow:
public class MyRenderer implements GLSurfaceView.Renderer {
public static final int recWidth = 1920;
public static final int recHeight = 1080;
private static final int U_INDEX = recWidth * recHeight;
private static final int V_INDEX = recWidth * recHeight * 5 / 4;
private static final int LENGTH = recWidth * recHeight;
private static final int LENGTH_4 = recWidth * recHeight / 4;
private int previewFrameWidth = 1920;
private int previewFrameHeight = 1080;
private int[] yTextureNames;
private int[] uTextureNames;
private int[] vTextureNames;
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private int mProgramObject;
private int mPositionLoc;
private int mTexCoordLoc;
private int yTexture;
private int uTexture;
private int vTexture;
private final float[] mVerticesData = {-1.f, 1.f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.f, -1.f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.f, -1.f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.f, 1.f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = {0, 1, 2, 0, 2, 3};
private ByteBuffer yBuffer;
private ByteBuffer uBuffer;
private ByteBuffer vBuffer;
private IntBuffer frameBuffer;
private IntBuffer renderBuffer;
private IntBuffer parameterBufferWidth;
private IntBuffer parameterBufferHeigth;
byte[] ydata = new byte[LENGTH];
byte[] uData = new byte[LENGTH_4];
byte[] vData = new byte[LENGTH_4];
public MyRenderer() {
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
yBuffer = ByteBuffer.allocateDirect(LENGTH);//MyGraphUtils.makeByteBuffer(LENGTH);
uBuffer = ByteBuffer.allocateDirect(LENGTH_4);//MyGraphUtils.makeByteBuffer(LENGTH_4/* * 2*/);
vBuffer = ByteBuffer.allocateDirect(LENGTH_4);//MyGraphUtils.makeByteBuffer(LENGTH_4);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl10, javax.microedition.khronos.egl.EGLConfig eglConfig) {
// public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.d("debug", "on surface created");
// Define a simple shader program for our point.
// final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
// final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);
//Our vertex shader code; nothing special
String vShaderStr =
"attribute vec4 a_position; \n" +
"attribute vec2 a_texCoord; \n" +
"varying vec2 v_texCoord; \n" +
"void main(){ \n" +
" gl_Position = a_position; \n" +
" v_texCoord = a_texCoord; \n" +
"} \n";
//Our fragment shader code; takes Y,U,V values for each pixel and calculates R,G,B colors,
//Effectively making YUV to RGB conversion
String fShaderStr =
"#ifdef GL_ES \n" +
"precision highp float; \n" +
"#endif \n" +
"varying vec2 v_texCoord; \n" +
"uniform sampler2D y_texture; \n" +
"uniform sampler2D u_texture; \n" +
"uniform sampler2D v_texture; \n" +
//
"void main (void){ \n" +
" float r, g, b, y, u, v; \n" +
//We had put the Y values of each pixel to the R,G,B components by GL_LUMINANCE,
// //that's why we're pulling it from the R component, we could also use G or B
" y = texture2D(y_texture, v_texCoord).r; \n" +
//We had put the U and V values of each pixel to the A and R,G,B components of the
//texture respectively using GL_LUMINANCE_ALPHA. Since U,V bytes are interspread
//in the texture, this is probably the fastest way to use them in the shader
" u = texture2D(u_texture, v_texCoord).a - 0.5; \n" +
" v = texture2D(v_texture, v_texCoord).r - 0.5; \n" +
//The numbers are just YUV to RGB conversion constants
" r = y + 1.13983*v;\n" +
" g = y - 0.39465*u - 0.58060*v;\n" +
" b = y + 2.03211*u;\n" +
//We finally set the RGB color of our pixel
" gl_FragColor = vec4(r, g, b, 1.0);\n" +
"} \n";
frameBuffer = IntBuffer.allocate(1);
renderBuffer = IntBuffer.allocate(1);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glGenFramebuffers(1, frameBuffer);
GLES20.glGenRenderbuffers(1, renderBuffer);
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer.get(0));
GLES20.glClear(0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
1920, 1080);
parameterBufferHeigth = IntBuffer.allocate(1);
parameterBufferWidth = IntBuffer.allocate(1);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_WIDTH, parameterBufferWidth);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_HEIGHT, parameterBufferHeigth);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) {
Log.d("debug", "gl frame buffer status != frame buffer complete");
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glClear(0);
mProgramObject = loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int yTextureName = yTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int uTextureName = uTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
vTexture = GLES20.glGetUniformLocation(mProgramObject, "v_texture");
vTextureNames = new int[1];
GLES20.glGenTextures(1, vTextureNames, 0);
int vTextureName = vTextureNames[0];
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
#Override
public final void onDrawFrame(GL10 gl) {
Log.d("debug", "on Draw frame");
// Clear the color buffer
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Use the program object
GLES20.glUseProgram(mProgramObject);
CameraGLRenderer.checkGlError("toto");
// Load the vertex position
mVertices.position(0);
GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
CameraGLRenderer.checkGlError("toto");
GLES20.glEnableVertexAttribArray(mPositionLoc);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
1920, 1080, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glUniform1i(yTexture, 0);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
960, 540, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1 + 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glUniform1i(uTexture, 2);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
960, 540, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1 + 1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glUniform1i(vTexture, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
CameraGLRenderer.checkGlError("toto");
}
public void setPreviewFrameSize(int realWidth, int realHeight) {
previewFrameHeight = realHeight;
previewFrameWidth = realWidth;
}
// public static String readTextFileFromRawResource(final Context context, final int resourceId) {
// final InputStream inputStream = context.getResources().openRawResource(resourceId);
// final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
// final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//
// String nextLine;
// final StringBuilder body = new StringBuilder();
//
// try {
// while ((nextLine = bufferedReader.readLine()) != null) {
// body.append(nextLine);
// body.append('\n');
// }
// } catch (IOException e) {
// return null;
// }
//
// return body.toString();
// }
public static int loadShader(int type, String shaderSrc) {
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES20.glCreateShader(type);
if (shader == 0) {
return 0;
}
// Load the shader source
GLES20.glShaderSource(shader, shaderSrc);
// Compile the shader
GLES20.glCompileShader(shader);
// Check the compile status
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
return shader;
}
public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
if (vertexShader == 0) {
return 0;
}
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
if (fragmentShader == 0) {
GLES20.glDeleteShader(vertexShader);
return 0;
}
// Create the program object
programObject = GLES20.glCreateProgram();
if (programObject == 0) {
return 0;
}
GLES20.glAttachShader(programObject, vertexShader);
GLES20.glAttachShader(programObject, fragmentShader);
// Link the program
GLES20.glLinkProgram(programObject);
// Check the link status
GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0) {
Log.e("ESShader", "Error linking program:");
Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
GLES20.glDeleteProgram(programObject);
return 0;
}
// Free up no longer needed shader resources
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
return programObject;
}
public void onPreviewFrame(byte[] data) {
System.arraycopy(data, 0, ydata, 0, LENGTH);
yBuffer.put(ydata);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
}
Now it draws one frame and then I get a glerror on the second draw :
glError 1280

How can make watermark Renderer?

I want to make customized watermark renderer on Android.
I am going to add watermark at bottom right corner above current camera preview screen.
Here is the source code what I made. this code does not work.
Please help me. Thank you.
Function call sequence is :
-setWatermarkTexture
-createBuffers
-configureOpenGL
-draw
public class WatermarkRenderer implements Renderer {
private int[] textureHandles = new int[1];
float vertices[] = {
-1, 0.5f,
-0.5f, -0.5f,
-1, 1,
-0.5f, 1,
};
float texCoords[] = {
0, 0,
1, 0,
0, 1,
1, 1,
};
private Bitmap watermark;
private int[] buffers = new int[2];
private float[] projectionMatrix = new float[16];
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
#Override
public void configureOpenGL() {
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glGenBuffers(buffers.length, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, vertexBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, textureBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
#Override
public void createBuffers() {
vertexBuffer = FloatBuffer.allocate(8);
vertexBuffer.put(vertices);
vertexBuffer.position(0);
textureBuffer = FloatBuffer.allocate(8);
textureBuffer.put(texCoords);
textureBuffer.position(0);
}
#Override
public void draw() {
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
//GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
//GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
if (watermark != null) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
watermark.recycle();
watermark = null;
}
/*
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glEnableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glVertexAttribPointer(AttributeLocations.POSITION, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glEnableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES );
GLES20.glVertexAttribPointer(AttributeLocations.TEXTURE_COORDINATES, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4 );
GLES20.glDisableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glDisableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES);
*/
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
this.projectionMatrix = projectionMatrix;
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}
I solved my issue.
Here is the source code.
public class WatermarkRenderer implements Renderer {
private final float[] TEX_VERTICES = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
private final float[] POS_VERTICES = {
0.2f, -1.0f,
1.0f, -1.0f,
0.2f, -0.9f,
1.0f, -0.9f
};
private static final String VERTEX_SHADER =
"attribute vec4 a_position;\n" +
"attribute vec2 a_texcoord;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_Position = a_position;\n" +
" v_texcoord = a_texcoord;\n" +
"}\n";
private static final String FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D tex_sampler;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
"}\n";
private final int FLOAT_SIZE_BYTES = 4;
private Bitmap watermark;
private int shaderProgram;
private int texSamplerHandle;
private int texCoordHandle;
private int posCoordHandle;
private FloatBuffer texVertices;
private FloatBuffer posVertices;
private int[] textureHandles = new int[1];
#Override
public void configureOpenGL() {
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER));
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER));
GLES20.glLinkProgram(shaderProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(shaderProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
String info = GLES20.glGetProgramInfoLog(shaderProgram);
GLES20.glDeleteProgram(shaderProgram);
shaderProgram = 0;
throw new RuntimeException("Could not link program: " + info);
}
texSamplerHandle = GLES20.glGetUniformLocation(shaderProgram, "tex_sampler");
texCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_texcoord");
posCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_position");
}
#Override
public void createBuffers() {
ByteBuffer byteBuffer;
byteBuffer = ByteBuffer.allocateDirect(TEX_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
texVertices = byteBuffer.asFloatBuffer();
texVertices.put(TEX_VERTICES);
texVertices.position(0);
byteBuffer = ByteBuffer.allocateDirect(POS_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
posVertices = byteBuffer.asFloatBuffer();
posVertices.put(POS_VERTICES);
posVertices.position(0);
}
#Override
public void draw() {
// Select the program.
GLES20.glUseProgram(shaderProgram);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
// Set the vertex attributes
GLES20.glVertexAttribPointer(texCoordHandle, 2, GLES20.GL_FLOAT, false, 0, texVertices);
GLES20.glEnableVertexAttribArray(texCoordHandle);
GLES20.glVertexAttribPointer(posCoordHandle, 2, GLES20.GL_FLOAT, false, 0, posVertices);
GLES20.glEnableVertexAttribArray(posCoordHandle);
// Set the input texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLES20.glUniform1i(texSamplerHandle, 0);
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
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);
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.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(texCoordHandle);
GLES20.glDisableVertexAttribArray(posCoordHandle);
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glUseProgram(0);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}

How to get "rendered" image with glReadPixels from FrameBuffer after calling glDrawElements

I modified brightness, contrast, and saturation of some image by fragment shader of OpenGL ES 2.0. And... to save modified image, I used this method.
public static Bitmap saveTexture(int texture, int width, int height) {
int[] frame = new int[1];
GLES20.glGenFramebuffers(1, frame, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frame[0]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture, 0);
ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glDeleteFramebuffers(1, frame, 0);
return bitmap;
}
But, this method return the original image, not modified. What is wrong?
Please advise me how to resolve this. :/
I added more information.
This code is my GLSurfaceView.Renderer's code.
#Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
mTextureID = OpenGLTools.loadImageTexture(mBitmap, true);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
mProgram = OpenGLTools.loadProgram(VERTEX_SHADER, FRAGMENT_SHADER);
}
#Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onDrawFrame(GL10 gl10) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
draw();
}
public void draw() {
if (!GLES20.glIsProgram(mProgram)) OpenGLTools.loadProgram(VERTEX_SHADER, FRAGMENT_SHADER);
GLES20.glUseProgram(mProgram);
int positionHandle = GLES20.glGetAttribLocation(mProgram, "position");
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
int textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
GLES20.glVertexAttribPointer(textureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);
GLES20.glEnableVertexAttribArray(textureCoordinateHandle);
int brightness = GLES20.glGetUniformLocation(mProgram, "brightness");
GLES20.glUniform1f(brightness, mEditParams.mBrightness / 200.0f);
int contrast = GLES20.glGetUniformLocation(mProgram, "contrast");
GLES20.glUniform1f(contrast, mEditParams.mContrast / 200.0f);
int saturation = GLES20.glGetUniformLocation(mProgram, "saturation");
GLES20.glUniform1f(saturation, (mEditParams.mSaturation + 100) / 100.0f);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer);
GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(textureCoordinateHandle);
}
public Bitmap getBitmap() {
return OpenGLTools.saveTexture(mTextureID, mBitmap.getWidth(), mBitmap.getHeight());
}
And... this is the code in OpenGLTools class.
public static int loadImageTexture(final Bitmap bitmap, final boolean recycle) {
int[] textureNames = new int[1];
GLES20.glGenTextures(1, textureNames, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureNames[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
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);
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);
if (recycle) {
bitmap.recycle();
}
return textureNames[0];
}
public static int loadProgram(final String vsc, final String fsc) {
int[] success = new int[1];
int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vshader, vsc);
GLES20.glCompileShader(vshader);
GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, success, 0);
if (success[0] == 0) {
Log.e("CheckLog", "Could not compile vertex shader : " + GLES20.glGetShaderInfoLog(vshader));
GLES20.glDeleteShader(vshader);
return 0;
}
int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fshader, fsc);
GLES20.glCompileShader(fshader);
GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, success, 0);
if (success[0] == 0) {
Log.e("CheckLog", "Could not compile fragment shader : " + GLES20.glGetShaderInfoLog(fshader));
GLES20.glDeleteShader(fshader);
return 0;
}
int program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vshader);
GLES20.glAttachShader(program, fshader);
GLES20.glLinkProgram(program);
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, success, 0);
if (success[0] <= 0) {
Log.e("CheckLog", "Could not link OpenGLES program :" + GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
return 0;
} else {
Log.i("CheckLog", "Linked OpenGLES program");
}
return program;
}
public static Bitmap saveTexture(int texture, int width, int height) {
int[] frame = new int[1];
GLES20.glGenFramebuffers(1, frame, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frame[0]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture, 0);
ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glDeleteFramebuffers(1, frame, 0);
return bitmap;
}
If I touch save button, getBitmap method is called in the OpenGLES context. I can change the Bitmap's parameters(brightness, contrast and saturation) and it shows up on display in real time. However, changed parameters are not applied the saved image when I touch the save button. I want to save the image with changed parameters.
You're passing the original texture handle as the texture parameter input into saveTexture(), so it's no surprise that that is the data you are saving back to disk.
You don't actually want to save a texture - you want to save the contents of the active framebuffer - so that function isn't what your code needs. Try this one:
public static Bitmap saveTexture(int width, int height) {
ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
return bitmap;
}

Android OpenGL ES 2.0 black textures

I'm learning gles2.0 (I'm a new-bite :)) on Android, and I want to draw a textured square, but I can't. I googled a lot, but I can't figure out the answer, i get only a black square.
I set up a GLSurfaceView, then a Renderer:
public class MySurfaceRenderer implements GLSurfaceView.Renderer {
private Context context;
private Sprite sprite1;
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
sprite1.Draw();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glClearColor(0.0f, 0.3f, 0.0f, 1.0f);
sprite1 = new Sprite(context, R.drawable.test);
}
}
Sprite class:
public class Sprite {
private static String TAG = "SpriteRender";
private Context context;
private FloatBuffer databuffer;
private FloatBuffer texturebuffer;
// x, y,
float data[] = {-0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f};
// u,v
float texturedata[] = {0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f};
private int mProgram;
private int vertexShader;
private int fragmentShader;
private int texture;
private int positionHandler;
private int texCoordHandler;
private int textureHandler;
public Sprite(Context context, int textureid){
this.context = context;
ByteBuffer bb_data = ByteBuffer.allocateDirect(data.length * 4);
bb_data.order(ByteOrder.nativeOrder());
ByteBuffer bb_texture = ByteBuffer.allocateDirect(texturedata.length * 4);
bb_texture.order(ByteOrder.nativeOrder());
databuffer = bb_data.asFloatBuffer();
databuffer.put(data);
databuffer.position(0);
texturebuffer = bb_texture.asFloatBuffer();
texturebuffer.put(texturedata);
texturebuffer.position(0);
vertexShader = ShaderLoader.loadShader(GLES20.GL_VERTEX_SHADER, ShaderLoader.readFromAssert(context, R.raw.tvs));
fragmentShader = ShaderLoader.loadShader(GLES20.GL_FRAGMENT_SHADER, ShaderLoader.readFromAssert(context, R.raw.tfs));
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glLinkProgram(mProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0){
// Displays error message
}
positionHandler = GLES20.glGetAttribLocation(mProgram, "a_Position");
texCoordHandler = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
textureHandler = GLES20.glGetUniformLocation(mProgram, "u_Texture");
texture = TextureLoader.loadTexture(context, textureid);
}
public void Draw(){
GLES20.glUseProgram(mProgram);
databuffer.position(0);
texturebuffer.position(0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(textureHandler, 0);
GLES20.glEnableVertexAttribArray(texCoordHandler);
GLES20.glEnableVertexAttribArray(positionHandler);
GLES20.glVertexAttribPointer(positionHandler, 2, GLES20.GL_FLOAT, false, 8, databuffer);
GLES20.glVertexAttribPointer(texCoordHandler, 2, GLES20.GL_FLOAT, false, 8, texturebuffer);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
}
}
ShaderLoader.loadShader loads a shader from a file (in res/raw),
TextureLoader.loadTexture loads a texture from a resource:
public static int loadTexture(Context context, int resource){
int[] texture = new int[1];
GLES20.glGenTextures(1, texture, 0);
BitmapFactory.Options bo = new BitmapFactory.Options();
bo.inScaled = false;
Bitmap tex = BitmapFactory.decodeResource(context.getResources(), resource, bo);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, tex, 0);
tex.recycle();
if(texture[0] == 0){
// Displays error
}
return texture[0];
}
Vertex shader:
attribute vec4 a_Position;
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoordinate;
void main() {
v_TexCoordinate = a_TexCoordinate;
gl_Position = a_Position;
}
Fragment shader:
precision mediump float;
varying vec2 v_TexCoordinate;
uniform sampler2D u_Texture;
void main() {
gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
}
I looked some stuff:
Tested with png, jpg, bmp(565), resolution: 32x32 and 64x64
In draw function after all line glGetError()​ returns 0
When loading a texture, Sprite.texture is not 0 (its about 70001)
If I change fragment shader to gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5); it's working.
Thanks for help!
I've figured out the answer:
When I loaded the texture, I didn't pass it to OpenGL correctly.
I added TextureLoader.loadTexture a GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); line like this:
...
Bitmap tex = BitmapFactory.decodeResource(context.getResources(), resource, bo);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
...
Now it's working.

Black screen instead of multi-texturing

I have checked the textures individually, they work fine.
Each of the textures are 128*128 pixels, I am working on Motorola MILESTONE mobile,
and have tested all basic examples (from line to cubemap), got stuck while multitexturing
rectangle.
The shader works well if I do not bind any one of the textures, but the problem starts with two textures for multitexturing.
private float[] myRotateMatrix = new float[16];
private float[] myViewMatrix = new float[16];
private float[] myProjectionMatrix = new float[16];
private float[] myMVPMatrix = new float[16];
private int aPositionLocation;
private int uMVPLocation;
private int aTextureCoordLocation;
private FloatBuffer rectangleVFB;
private ShortBuffer rectangleISB;
private FloatBuffer textureCFB;
private int program;
private int textureId1;
private int textureId2;
private int uSampler1Location;
private int uSampler2Location;
private void initShapes() {
float[] rectangleVFA = {-1,-1,0, 1,-1,0, 1,1,0, -1,1,0};
short[] rectangleISA = {0,1,2, 0,3,2};
float[] textureCFA = {0,0, 1,0, 1,1, 0,1};
ByteBuffer rectangleVBB = ByteBuffer.allocateDirect(rectangleVFA.length * 4);
rectangleVBB.order(ByteOrder.nativeOrder());
rectangleVFB = rectangleVBB.asFloatBuffer();
rectangleVFB.put(rectangleVFA);
rectangleVFB.position(0);
ByteBuffer rectangleIBB = ByteBuffer.allocateDirect(rectangleISA.length * 2);
rectangleIBB.order(ByteOrder.nativeOrder());
rectangleISB = rectangleIBB.asShortBuffer();
rectangleISB.put(rectangleISA);
rectangleISB.position(0);
ByteBuffer textureCBB = ByteBuffer.allocateDirect(textureCFA.length * 4);
textureCBB.order(ByteOrder.nativeOrder());
textureCFB = textureCBB.asFloatBuffer();
textureCFB.put(textureCFA);
textureCFB.position(0);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
checkError("glViewport");
float ratio = (float) width / height;
Matrix.setLookAtM(myViewMatrix, 0, 0, 0, 6, 0, 0, 0, 0, 1, 0);
Matrix.frustumM(myProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
aPositionLocation = GLES20.glGetAttribLocation(program, "aPosition");
checkError("glGetAttribLocation");
uMVPLocation = GLES20.glGetUniformLocation(program, "uMVP");
checkError("glGetUniformLocation");
aTextureCoordLocation = GLES20.glGetAttribLocation(program, "aTextureCoord");
checkError("glGetAttribLocation");
uSampler1Location = GLES20.glGetUniformLocation(program, "uSampler1");
checkError("glGetUniformLocation");
uSampler2Location = GLES20.glGetUniformLocation(program, "uSampler2");
checkError("glGetUniformLocation");
int[] textures = new int[2];
GLES20.glGenTextures(2, textures, 0);
checkError("glGenTextures");
textureId1 = textures[0];
textureId2 = textures[1];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId1);
checkError("glBindTexture");
InputStream is1 = context.getResources().openRawResource(R.drawable.brick1);
Bitmap img1;
try {
img1 = BitmapFactory.decodeStream(is1);
}finally {
try {
is1.close();
}catch (IOException ioe) {
}
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img1, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId2);
checkError("glBindTexture");
InputStream is2 = context.getResources().openRawResource(R.drawable.brick2);
Bitmap img2;
try {
img2 = BitmapFactory.decodeStream(is2);
}finally {
try {
is2.close();
}catch (IOException ioe) {
}
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img2, 0);
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
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);
}
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
checkError("glClear");
GLES20.glUseProgram(program);
checkError("glUseProgram");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
checkError("glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId1);
checkError("glBindTexture");
GLES20.glUniform1i(uSampler1Location, 0);
checkError("glUniform1i");
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
checkError("glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId2);
checkError("glBindTexture");
GLES20.glUniform1i(uSampler2Location, 1);
checkError("glUniform1i");
Matrix.setIdentityM(myRotateMatrix, 0);
Matrix.rotateM(myRotateMatrix, 0, touchX, 0, 1, 0);
Matrix.rotateM(myRotateMatrix, 0, touchY, 1, 0, 0);
Matrix.multiplyMM(myMVPMatrix, 0, myViewMatrix, 0, myRotateMatrix, 0);
Matrix.multiplyMM(myMVPMatrix, 0, myProjectionMatrix, 0, myMVPMatrix, 0);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 12, rectangleVFB);
checkError("glVertexAttribPointer");
GLES20.glEnableVertexAttribArray(aPositionLocation);
checkError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8, textureCFB);
checkError("glVertexAttribPointer");
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
checkError("glEnableVertexAttribArray");
GLES20.glUniformMatrix4fv(uMVPLocation, 1, false, myMVPMatrix, 0);
checkError("glUniformMatrix4fv");
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, rectangleISB);
checkError("glDrawElements");
}
In OpenGL ES 2.0, after every call to glBindTexture and before texImage2D the parameters for that texture have to be specified seperately.
So, if there are 2 textures (as in multitexturing) then it will require 4 glTexParameterf each for texture 1 and 2, total 8.

Categories

Resources