I'm using OpenGL for display YUV420P frames on screen in Android.
With some resolution, my frame looks good, but with big resolution (on the same screen), it still looks like my original frame (with colors and all), but with some green lines hatching it (depending to the orientation, 4 lines, 30 lines?).
Here is an example (an 1080x607 frame):
Is it a alignment problem? A texture binding problem? Here is my code:
private final short[] INDICES_DATA = {0, 1, 2, 0, 2, 3};
private final float[] VERTICES_DATA = new float[] {
-1f, 1f, 0f,
0f, 0f,
-1f, -1f, 0f,
0f, 1f,
1f, -1f, 0f,
1f, 1f,
1f, 1f, 0f,
1f, 0f
};
private final String szVertexShaderCode =
"attribute vec4 aPosition;\n" +
"attribute vec2 aTexCoord;\n" +
"varying vec2 vTexCoord;\n" +
"void main() {\n" +
" gl_Position = aPosition;\n" +
" vTexCoord = aTexCoord;\n" +
"}\n";
private final String szYUV420PFragmentShaderCode =
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n" +
" precision highp float;\n" +
"#else\n" +
" precision mediump float;\n" +
"#endif\n" +
"varying vec2 vTexCoord;\n" +
"uniform sampler2D yTexture;\n" +
"uniform sampler2D uTexture;\n" +
"uniform sampler2D vTexture;\n" +
"void main() {\n" +
" float r, g, b, y, u, v;\n" +
" y = texture2D(yTexture, vTexCoord).r;\n" +
" u = texture2D(uTexture, vTexCoord).r - 0.5;\n" +
" v = texture2D(vTexture, vTexCoord).r - 0.5;\n" +
" r = y + (1.13983 * v);\n" +
" g = y - (0.39465 * u) - (0.58060 * v);\n" +
" b = y + (2.03211 * u);\n" +
" gl_FragColor = vec4(r, g, b, 1.0);\n" +
"}\n";
Function on surface created:
//initShadersAndProgram();
iPositionLoc = GLES20.glGetAttribLocation(iProgram, "aPosition");
iTexCoordLoc = GLES20.glGetAttribLocation(iProgram, "aTexCoord");
// Is this line useful?
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
iYTexture = GLES20.glGetUniformLocation(iProgram, "yTexture");
int[] yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int iYTextureName = yTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iYTextureName);
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.glEnable(GLES20.GL_TEXTURE_2D);
iUTexture = GLES20.glGetUniformLocation(iProgram, "uTexture");
int[] uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int iUTextureName = uTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iUTextureName);
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.glEnable(GLES20.GL_TEXTURE_2D);
iVTexture = GLES20.glGetUniformLocation(iProgram, "vTexture");
int[] vTextureNames = new int[1];
GLES20.glGenTextures(1, vTextureNames, 0);
int iVTextureName = vTextureNames[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iVTextureName);
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.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Function on draw frame:
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(iProgram);
verticesBuffer.position(0);
GLES20.glVertexAttribPointer(iPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, verticesBuffer);
verticesBuffer.position(3);
GLES20.glVertexAttribPointer(iTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, verticesBuffer);
GLES20.glEnableVertexAttribArray(iPositionLoc);
GLES20.glEnableVertexAttribArray(iTexCoordLoc);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glUniform1i(iYTexture, 1);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth(),
pixmap.getHeight(),
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer Y */);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glUniform1i(iUTexture, 2);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth() / 2,
pixmap.getHeight() / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer U */);
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glUniform1i(iVTexture, 3);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
pixmap.getWidth() / 2,
pixmap.getHeight() / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
/* buffer V */);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);
What do I miss?
EDIT: Frames are provided from two different decoders and all works find with an other render process.
EDIT2: I displayed only the Y plane and the result is a grey frame (as expected) but there is no hatch lines!!
I just replaced these lines in my fragment shader to display it:
" r = texture2D(yTexture, vTexCoord).r;\n" +
" g = texture2D(yTexture, vTexCoord).g;\n" +
" b = texture2D(yTexture, vTexCoord).b;\n" +
So problem comes from U/V planes?
Related
I am trying to render the contents of an external texture (which gets its data from android MediaCodec) to a framebuffer with a texture atttachment (first pass) and then using that texture to render to display (second pass)
My overall goal is to do some operation in the shader in the first pass and some more operation in the second pass. But I am getting GL_INVALID_OPERAION in the first pass and hence texture associated with the Framebuffer is not populated.
Below is the summary of the code
OpenGL environment initialization
GLES20.glGenFramebuffers(1,frameBufferHandles,0);
GLES20.glGenBuffers(2, bufferHandles, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferHandles[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Utils.VERTICES.length * FLOAT_SIZE_BYTES, Utils.getVertexBuffer(), GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferHandles[1]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, Utils.INDICES.length * FLOAT_SIZE_BYTES, Utils.getIndicesBuffer(), GLES20.GL_DYNAMIC_DRAW);
GLES20.glGenTextures(2, textureHandles, 0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureHandles[0]);
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.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.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBufferHandles[0]);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[1]);
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.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,width,height,0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE,null); //width.height are of that viewport and are initialized properly
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D,textureHandles[1],0);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if(status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
Log.d(TAG,"Frame Buffer Incomplete : " + status);
} else
Log.d(TAG,"Frame Buffer Complete");
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
Vertex Shader setup
public static final String DEFAULT_VERTEX_SHADER = "uniform mat4 uMVPMatrix;\n"
+ "uniform mat4 uSTMatrix;\n"
+ "attribute vec4 aPosition;\n"
+ "attribute vec4 aTextureCoord;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " gl_Position = uMVPMatrix * aPosition;\n"
+ " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n"
+ "}\n";
Fragment shader setup
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTextureCoord;
uniform samplerExternalOES sTexture;
uniform sampler2D sTextureSampler;
uniform float r;
uniform int pass;
void main() {
if(pass == 0) {
gl_FragColor = texture2D(sTexture, vTextureCoord);
//gl_FragColor = vec4(1.0,1.0,0.0,1.0);
}
else if(pass == 1) {
gl_FragColor = texture2D(sTextureSampler, vTextureCoord);
}
}
Vertex Attributes and Index buffer are defined like below
public static float[] VERTICES = {
-1.0f, -1.0f, 0.0f, 0f, 0f,
-1.0f, 1.0f, 0.0f, 0f, 1f,
1.0f, 1.0f, 0.0f, 1f, 1f,
1.0f, -1.0f, 0.0f, 1f, 0f
};
public static int[] INDICES = {
2, 1, 0, 0, 3, 2
};
And finally my draw() function looks like this
protected void draw() {
Matrix.setIdentityM(mvpMatrix, 0);
if(mProgram != -1)
mProgram = createProgram();
int vertexHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
int uvsHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
int texMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
int mvpMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
int textureHandle = GLES20.glGetUniformLocation(mProgram, "sTextureSampler");
int pass = GLES20.glGetUniformLocation(mProgram, "pass");
GLES20.glUseProgram(mProgram);
GLES20.glUniformMatrix4fv(texMatrixHandle, 1, false, texMatrix, 0);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferHandles[0]);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferHandles[1]);
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT, false, 4 * 5, 0);
GLES20.glEnableVertexAttribArray(uvsHandle);
GLES20.glVertexAttribPointer(uvsHandle, 2, GLES20.GL_FLOAT, false, 4 * 5, 3 * 4);
//Pass 0 - Render to framebuffer , gives GL_INVALID_OPERAION error
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,frameBufferHandles[0]);
GLES20.glUniform1i(pass, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
//Pass 1 - Render to display
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
GLES20.glUniform1i(textureHandle, 2);
GLES20.glUniform1i(pass, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
}
I am guessing it is related to vTextureCoord, because if I dont use vTextureCoord and render a constant color to the framebuffer during first pass , then I can read it back during the second pass from the texture associated with the framebuffer.
I'm encoding a video using this example EncodeAndMuxTest.java. Instead of generate surface frame by GLES20.glScissor(), i'm drawing a texture (by GLES20.glActiveTexture(), GLES20.glBindTexture(), GLES20.glDrawElements()). But the output video always having black screen.
I recogize that the output video only display color in GLES20.glClear() and it doesn't display image texture. I guess that having some problem with texture when using EGL14.eglSwapBuffers but i cann't figure it out.
Please kindly help me solve my problem. Thanks so much!
Update Code use for example
public void testEncodeVideoToMp4() {
// QVGA at 2Mbps
mWidth = 320;
mHeight = 240;
mBitRate = 2000000;
try {
prepareEncoder();
setupTexture(); // insert new function to setup opengles
mInputSurface.makeCurrent();
for (int i = 0; i < NUM_FRAMES; i++) {
drainEncoder(false);
// Generate a new frame of input.
// generateSurfaceFrame(i);
drawTexture(); // insert new function to draw texture
mInputSurface.setPresentationTime(computePresentationTimeNsec(i));
if (VERBOSE)
Log.d(TAG, "sending frame " + i + " to encoder");
mInputSurface.swapBuffers();
}
drainEncoder(true);
} finally {
releaseEncoder();
}
}
setupTexture() function:
public void setupTexture() {
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);
String vShaderStr = "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
String fShaderStr = "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_baseMap; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_baseMap, v_texCoord ); \n"
+ "} \n";
// Load the shaders and get a linked program object
mProgramObject = ESShader.loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
// Get the sampler locations
mBaseMapLoc = GLES20.glGetUniformLocation(mProgramObject, "s_baseMap");
// Load the texture
mBaseMapTexId = loadTexture();
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glViewport(0, 0, 720, 1280);
}
loadTexture() function
private int loadTexture() {
int[] textureId = new int[1];
Bitmap bitmap;
bitmap = BitmapFactory.decodeFile(mFilePath); // please change mFilePath to image file in sdcard
if (bitmap == null) {
return -1;
}
GLES20.glGenTextures(1, textureId, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
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.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);
bitmap.recycle();
return textureId[0];
}
drawTexture() function:
public void drawTexture() {
GLES20.glClearColor(TEST_R0 / 255.0f, TEST_G0 / 255.0f, TEST_B0 / 255.0f, 1.0f); // green color
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);
// Bind the base map
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBaseMapTexId);
// Set the base map sampler to texture unit to 0
GLES20.glUniform1i(mBaseMapLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
}
Variables use for openGL ES
// Handle to a program object
private int mProgramObject;
// Attribute locations
private int mPositionLoc;
private int mTexCoordLoc;
// Sampler location
private int mBaseMapLoc;
// Texture handle
private int mBaseMapTexId;
// Additional member variables
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private final float[] mVerticesData = { -1f, 1f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1f, -1f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1f, -1f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1f, 1f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };
And the video output only display green screen
I'm trying to texture map some quads. I can render the quads with solid colors just fine. I've been following this page:
http://www.learnopengles.com/android-lesson-four-introducing-basic-texturing/
Everything compiles and runs, but the texture is simply not being applied.
The only difference between my code and the page linked is that I do not do glBindAttribLocation, and I use glDrawElements instead of glDrawArrays.
EDIT: Converting my vertex and tex coord data to use glDrawArrays did not fix anything.
All of my shader handles seem correct. The problem must be in one of my draws. If anyone can help me debug this, that would be great. I've tried setting gl_FragColor = vec4(texCoord[0], texCoord[1], 1.0f, 1.0f) just to see if tex coordinates are making it to the shader but that crashes.
Initialization of vertex data:
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
static float textureCoords[] = { 0.0f, 1.0f, // top left
0.0f, 0.0f, // bottom left
1.0f, 0.0f, // bottom right
1.0f, 1.0f}; // top right
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); // (# of coordinate values * 4 bytes per float)
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
ByteBuffer tcbb = ByteBuffer.allocateDirect(textureCoords.length * 4);
tcbb.order(ByteOrder.nativeOrder());
texCoordBuffer = tcbb.asFloatBuffer();
texCoordBuffer.put(textureCoords);
texCoordBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
In my attach shader code:
// get handle to texture coords
mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "texCoord");
MyGLRenderer.checkGlError("glGetAttribLocation");
Log.i("TEXCOORD SHADER HANDLE", " " + mTexCoordHandle);
//get handle to texture
mTexHandle = GLES20.glGetUniformLocation(mProgram, "u_texture");
MyGLRenderer.checkGlError("glGetUniformLocation");
Log.i("TEX SHADER HANDLE", " " + mTexHandle);
In my main (ParticleEngine) draw:
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
GLES20.glEnableVertexAttribArray(mTexCoordHandle);
GLES20.glVertexAttribPointer(mTexCoordHandle, TEX_COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
0, texCoordBuffer);
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTexHandle, 0);
for (int t=0;t<mChildsCount;t++) {
Particle child = (Particle)mChilds[t];
child.draw(mVMatrix, mProjMatrix);
}
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordHandle);
In an individual particles draw:
//... calculate model-view-projection matrix, send to shader
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mPEngine.drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, mPEngine.drawListBuffer);
In my load_texture:
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
if (bitmap == null) {
throw new RuntimeException("Error decoding bitmap");
}
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
In my shaders:
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 texCoord;" +
"varying vec2 texCoordOut;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
" texCoordOut = texCoord; \n" +
" gl_Position = uMVPMatrix * vPosition; \n" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec2 texCoordOut;" +
"uniform sampler2D u_texture;" +
"void main() {" +
" vec4 texColor = texture2D(u_texture, texCoordOut);\n" +
" gl_FragColor = texColor;" +
"}";
SOLVED:
Android OpenGL2.0 showing black textures
NEEDED TO ADD 2 LINES TO LOAD_TEXTURE:
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);
Turns out that is required if your texture sizes are not powers of 2.
For anyone who is coming here for the iOS side of this, the other answer provided here also applies. Only difference is the commands are like this:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
Also, make sure that you enable filtering:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
which I didn't think was so practical in 2D, but you need them
I am trying to draw textures onto quads in OpenGL2.0. So far I got the quads to show up and everything, but the textures are not there - the quads are all black.
My main suspicion is that i'm not mapping the textures correctly - my textures are not powers of 2, nor are they square - their width is in the field mWidth and their height in mRowHeight.
The quads are drawn in a vertical list, which is done with a translate matrix.
I'll be very grateful if anyone can go over this cause I'm desperate!
Here's related code:
Initializing the buffers:
void initBuffers() {
float r = (float) mRowHeight / (mHeight / 2f);
ByteBuffer bb;
float[] bounds = { // X Y Z
/* 0 - TL */-1f, 1f, 0f,
/* 1 - BL */-1f, 1 - r, 0f,
/* 2 - BR */ 1f, 1 - r, 0f,
/* 3 - TR */ 1f, 1f, 0f };
bb = ByteBuffer.allocateDirect(bounds.length * 4);
bb.order(ByteOrder.nativeOrder());
mVertBuffer = bb.asFloatBuffer();
mVertBuffer.put(bounds).position(0);
short[] indices = { 0, 1, 2, 0, 2, 3 };
bb = ByteBuffer.allocateDirect(indices.length * 2);
bb.order(ByteOrder.nativeOrder());
mIndBuffer = bb.asShortBuffer();
mIndBuffer.put(indices).position(0);
float[] texture = {
/* 0 - BL */-1f, 1f,
/* 1 - TL */-1f, 1 - r,
/* 2 - BR */1f, 1 - r,
/* 3 - TR */1f, 1f };
bb = ByteBuffer.allocateDirect(texture.length * 4);
bb.order(ByteOrder.nativeOrder());
mTexBuffer = bb.asFloatBuffer();
mTexBuffer.put(texture).position(0);
}
Drawing the frame:
#Override
public void drawFrame() {
long startTime = System.currentTimeMillis();
if (!mLayoutComplete) {
return;
}
final float halfw = mHeight / 2f;
final int rowHeight = mRowHeight;
final float r = (float) rowHeight / halfw;
int i = mFirstRow;
final float initial = (float) ((i * rowHeight) - mScroll) / halfw;
Matrix.setIdentityM(mTMatrix, 0);
Matrix.translateM(mTMatrix, 0, 0, -initial, 0);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 0, mVertBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
final int l = mLastRow;
for (; i <= l; i++) {
ThumbRow thr = mCache.get(i);
if (thr != null) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
if (thr.mDirty) {
thr.loadTexture(null, null);
thr.mDirty = false;
} else {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, thr.mRow + 1);
}
GLES20.glUniform1i(msTextureHandle, 0);
GLES20.glVertexAttribPointer(maTextureHandle, 2,
GLES20.GL_FLOAT, false, 0, mTexBuffer);
GLES20.glEnableVertexAttribArray(maTextureHandle);
GLES20.glUniformMatrix4fv(muTMatrixHandle, 1, false,
mTMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6,
GLES20.GL_UNSIGNED_SHORT, mIndBuffer);
Log.i(TAG, GLES20.glGetProgramInfoLog(mProgram));
}
Matrix.translateM(mTMatrix, 0, 0, -r, 0); // Shift drawing
// window to next
// row.
}
GLES20.glDisableVertexAttribArray(maPositionHandle);
GLES20.glDisableVertexAttribArray(maTextureHandle);
Log.d(TAG, "onDrawFrame(): "
+ (System.currentTimeMillis() - startTime));
}
Loading the textures:
public void loadTexture(GL10 gl, Context c) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mRow + 1);
// Create Nearest Filtered Texture
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);
// Different possible texture parameters, e.g.
// GLES20.GL_CLAMP_TO_EDGE
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
Bitmap bitmap = mBitmap;
if (bitmap == null) {
bitmap = mEmptyBitmap;
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}
Vertex Shader:
uniform mat4 uTMatrix;
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
gl_Position = uMVPMatrix * uTMatrix * aPosition;
vTextureCoord = aTextureCoord;
}
Fragment Shader:
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D sTexture;
void main() {
gl_FragColor = texture2D(sTexture, vTextureCoord);
}
Any help will be much appreciated.
This is a quite common issue of texturing on OpenGL ES 2.0 which caused a lot of headache to me in the past.
In OpenGL ES 2.0, in caso of no-power of 2 textures, the wrap mode can only be GL_CLAMP_TO_EDGE.
There are restrictions as well on the filter you can use which can be only GL_NEAREST or GL_LINEAR (in other words no MIPMAPPING)
In simple words, checking you loadtexture function, change these 2 code lines from:
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
to
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);
I hope this fix the problem, let me know :)
Maurizio Benedetti
I'm trying to get some textures rendered on quads, but the screen turns out empty.
(Open GL 2.0)
I formerly used a static color shader on the quads, and the quads did appear on screen, so the positioning is fine.
UPDATE: Now I can see black textures only...
Here is my code:
Vertex Shader:
uniform mat4 uTMatrix;
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec4 vTex;
attribute vec4 inputTextureCoordinate;
varying vec2 TexCoord0;
void main(){
TexCoord0 = inputTextureCoordinate.xy;
gl_Position = uMVPMatrix * uTMatrix * vPosition;
}
Frag Shader:
varying highp vec2 TexCoord0;
uniform sampler2D colorMap;
void main(){
gl_FragColor = texture2D(colorMap, TexCoord0);
}
onDrawFrame():
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
final float halfw = mWidth / 2f;
final int rowHeight = mRowHeight;
final float r = (float) rowHeight / halfw;
int i = mFirstRow;
final float initial = (float) ((i * rowHeight) - mScroll) / halfw;
Matrix.setIdentityM(mTMatrix, 0);
Matrix.translateM(mTMatrix, 0, 0, -initial, 0);
GLES20.glFrontFace(GLES20.GL_CW);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 0, mVertBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glVertexAttribPointer(maTexHandle, 3, GLES20.GL_FLOAT,
false, 0, mTexBuffer);
GLES20.glEnableVertexAttribArray(maTexHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
final int l = mLastRow;
for (; i <= l; i++) {
if (\*A check to see if the bitmap is cached*\) {
GLES20.glUniform1i(muTextureHandle, i);
GLES20.glUniformMatrix4fv(muTMatrixHandle, 1, false,
mTMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
Matrix.translateM(mTMatrix, 0, 0, -r, 0);
}
GLES20.glDisableVertexAttribArray(maPositionHandle);
GLES20.glDisableVertexAttribArray(maTexHandle);
loadTexture:
public void loadTexture(GL10 gl, Context c) {
int[] texture = new int[1];
texture[0] = mRow;
GLES20.glDeleteTextures(1, texture, 0);
texture[0] = mRow;
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
// Create Nearest Filtered Texture
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);
// Different possible texture parameters, e.g.
// GLES20.GL_CLAMP_TO_EDGE
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
Bitmap bitmap = mBitmap;
if (bitmap == null) {
bitmap = mEmptyBitmap;
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}
Additionally there's this one line I'm not sure what it's supposed to do;
if (\*A check to see if the bitmap is cached*\) {
GLES20.glUniform1i(muTextureHandle, i); // ??
...
}
I'm guessing your goal is to update GL_TEXTURE0 constantly though, in which case you should put constant value 0 into muTextureHandle. Or remove this line all together as zero is the default.