OpenGL ES 2.0 Drawing Quad Crashes - android

I am having trouble rendering a quad in Android with OpenGL ES 2.0 using VBOs.
For some reason when I run the program, it crashes the emulator. I am using Andy for the emulator. I have tried using the default emulator that comes with android, and in this case the app simply won't run. I am using eclipse as my ide.
I have managed to narrow down the problem to the render method of the Quad class.
I guess I am wondering is there a problem with the way I am setting up the VBOs and rendering them?
Here is my code:
Quad render method:
#TargetApi(Build.VERSION_CODES.GINGERBREAD)
public void render()
{
mat.useMaterial();
GLES20.glFrontFace(GLES20.GL_CW);
//Generate VBO Buffer Handles and assign it to 'buffers'
GLES20.glGenBuffers(4, buffers, 0);
GLES20.glGenBuffers(1, ibo, 0);
//Positions
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glEnableVertexAttribArray(0);
GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
//GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer);
//Normals
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, normalBuffer.capacity() * 4, normalBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glEnableVertexAttribArray(1);
GLES20.glVertexAttribPointer(1, 3, GLES20.GL_FLOAT, false, 0, normalBuffer);
//GLES10.glNormalPointer(GLES10.GL_FLOAT, 0, normalBuffer);
//Texcoords
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[2]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, texcoordBuffer.capacity() * 4, texcoordBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glEnableVertexAttribArray(2);
GLES20.glVertexAttribPointer(2, 2, GLES20.GL_FLOAT, false, 0, texcoordBuffer);
//GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, texcoordBuffer);
//Colors
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, colorBuffer.capacity() * 4, colorBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glEnableVertexAttribArray(3);
GLES20.glVertexAttribPointer(3, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);
//GLES10.glColorPointer(4, GLES10.GL_FLOAT, 0, colorBuffer);
//Indices
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * 4, indexBuffer, GLES20.GL_STATIC_DRAW);
//Draw
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indexBuffer.capacity(), GLES20.GL_UNSIGNED_INT, indexBuffer);
//GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertices.length / 3);
//Unbind buffers
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
Also here is the Material class:
package com.game.shading;
import android.opengl.GLES20;
public class Material
{
private final String vertexShaderCode =
"attribute vec3 vPosition;" +
"attribute vec3 vNormal;" +
"attribute vec2 vTexcoord" +
"" +
"void main()" +
"{" +
" gl_Position = vec4(vPosition, 0);" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"" +
"void main()" +
"{" +
" gl_FragColor = vColor;" +
"}";
private int vertShader;
private int fragShader;
private int shaderProgram;
public Material()
{
vertShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertShader);
GLES20.glAttachShader(shaderProgram, fragShader);
GLES20.glLinkProgram(shaderProgram);
}
public void useMaterial()
{
GLES20.glUseProgram(shaderProgram);
}
public void cleanupMaterial()
{
GLES20.glDetachShader(shaderProgram, vertShader);
GLES20.glDetachShader(shaderProgram, fragShader);
GLES20.glDeleteShader(vertShader);
GLES20.glDeleteShader(fragShader);
GLES20.glDeleteProgram(shaderProgram);
}
private int loadShader(int type, String source)
{
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
return shader;
}
}

You have a problem with the way you set up the attributes. Taking one of them as an example (the same thing applies to all of them, as well as the index buffer):
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
In ES 2.0, there are two variations of the glVertexAttribPointer() call. They have different signatures in the Java bindings:
One of them takes a Buffer as the last argument. It is used to specify that the vertex data should be pulled directly from the memory of the buffer passed in. This is commonly called a "client side vertex array".
The other one takes an int as the last argument. It is used for attribute values stored in a VBO. The argument is then an offset relative to the start of the VBO.
You're using the first version of the call, while you have in fact a VBO bound. In this case, you need to use the second version. Since your attribute data starts at the beginning of the VBO, the offset value is 0:
GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, 0);
Then correct the same problem for the other attributes and the indices.
I also don't see code that associates the vertex attribute locations with the attributes in the vertex shader. One option to add that is to use glBindAttribLocation() calls before linking the program.

Related

Black rectangle on top of android camera preview

I am working on android app that uses NDK camera2API with opengl.
When I launch the application on the device, a black rectangle appears on top, although the application should run in full screen.
The architecture of the application from the java side uses the navigation graph.
To fullscreen mode, I use this:
class MainActivity : AppCompatActivity() {
...
...
companion object {
/** Combination of all flags required to put activity into immersive mode */
const val FLAGS_FULLSCREEN=
View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
/** Milliseconds used for UI animations */
const val ANIMATION_FAST_MILLIS = 50L
const val ANIMATION_SLOW_MILLIS = 100L
private const val IMMERSIVE_FLAG_TIMEOUT = 100L
}
On android side I create texture for usage in cpp:
GLES30.glGenTextures(1, textures, 0)
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0])
surfaceTexture = SurfaceTexture(textures[0])
Shaders:
static const char* vertex_shader_src = R"(
attribute vec3 vertexPosition;
attribute vec2 uvs;
uniform mat4 texMatrix; // this from surfaceTexture getTransformMatrix
varying vec2 varUvs;
void main()
{
varUvs = (texMatrix * vec4(uvs.x, uvs.y, 0, 1.0)).xy;
gl_Position = vec4(vertexPosition, 1.0);
}
)";
static const char* fragment_shader_src = R"(
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES texSampler;
varying vec2 varUvs;
void main()
{
gl_FragColor = texture2D(texSampler, varUvs);
}
)";
Vertex and index
static float vertices[] {
// x, y, z, u, v
-1, -1, 0, 0, 0,
-1, 1, 0, 0, 1,
1, 1, 0, 1, 1,
1, -1, 0, 1, 0
};
static GLuint indices[] { 2, 1, 0, 0, 3, 2 };
This is render code
void ogl::draw_frame(const float texMat[]) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearColor(0,0,0,1);
glUseProgram(program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(tex_sampler, 0);
glUniformMatrix4fv(tex_matrix, 1, false, texMat);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glEnableVertexAttribArray(vertex_position);
glVertexAttribPointer(vertex_position, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
glEnableVertexAttribArray(uvs);
glVertexAttribPointer(uvs, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void *)(3 * sizeof(float)));
glViewport(0, 0, width, height);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
Closed.
the problem was that I used the dimensions that the camera used (for example, the camera resolution is 480x640, and the actual window size is 480 x 752, the difference is 112 pixels)

OpenGl error 1281 after setting gl_fragColor

I just started programming opengl-es 2.0 and I'm currently struggling to find an issue concerned with setting the color of a wavefront object im drawing (https://pastebin.com/cEvpj8rt). The drawing is working just fine until I start to manipulate the color at which point im being confronted with opengl error 1281 and I'm unable to pinpoint the cause in my code. I've broken down the shader code to what I believe is the bare minimum required for the fragment shader to work:
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
To eliminate any additional source of error I am setting the color with a constant value as can be seen above. I doubt the error lies with the simple code above but is concerned with the code in my adapted renderer implementation. (it is based on the renderer that came with a sample from the ar-core github repo. The full code of the initial renderer can be found here: https://github.com/google-ar/arcore-android-sdk/blob/master/samples/java_arcore_hello_ar/app/src/main/java/com/google/ar/core/examples/java/helloar/rendering/ObjectRenderer.java while the adapted version can be seen here: https://pastebin.com/9cmKVnLV) Below you can find an excerpt of the code responsible for setting up and drawing the object. I reckoned the issue to be connected to the texturing which is why I removed the code.
I know its a bit much to ask for help given my lack of understanding on the matter at hand but I'd be glad for any hint/advice at this point. The error occurs after the first draw in the following method:
public void draw(float[] cameraView, float[] cameraPerspective) {
multiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0);
multiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0);
glUseProgram(mProgram);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBufferId);
glVertexAttribPointer(mPositionAttribute, COORDS_PER_VERTEX,
GL_FLOAT, false, 0, mVerticesBaseAddress);
glVertexAttribPointer(mNormalAttribute, 3,
GL_FLOAT, false, 0, mNormalsBaseAddress);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Set the ModelViewProjection matrix in the shader.
glUniformMatrix4fv(mModelViewUniform, 1,
false, mModelViewMatrix, 0);
glUniformMatrix4fv(mModelViewProjectionUniform, 1,
false, mModelViewProjectionMatrix, 0);
glEnableVertexAttribArray(mPositionAttribute);
glEnableVertexAttribArray(mNormalAttribute);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferId);
glDrawElements(GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(mPositionAttribute);
glDisableVertexAttribArray(mNormalAttribute);
// this is where the error is detected
OpenGlHelper.checkGLError(TAG, "After draw");
}
Here the method which is used for initialization:
public void createOnGlThread(Context context) throws IOException {
InputStream objInputStream = context.getAssets()
.open(OBJ_ASSET_NAME);
Obj obj = ObjReader.read(objInputStream);
obj = ObjUtils.convertToRenderable(obj);
IntBuffer wideIndices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
FloatBuffer texCoords = ObjData.getTexCoords(obj, 2);
FloatBuffer normals = ObjData.getNormals(obj);
ShortBuffer indices = ByteBuffer.allocateDirect(2 * wideIndices.limit())
.order(ByteOrder.nativeOrder()).asShortBuffer();
while (wideIndices.hasRemaining()) {
indices.put((short) wideIndices.get());
}
indices.rewind();
int[] buffers = new int[2];
glGenBuffers(2, buffers, 0);
mVertexBufferId = buffers[0];
mIndexBufferId = buffers[1];
// Load vertex buffer
mVerticesBaseAddress = 0;
mTexCoordsBaseAddress = mVerticesBaseAddress + 4 * vertices.limit();
mNormalsBaseAddress = mTexCoordsBaseAddress + 4 * texCoords.limit();
final int totalBytes = mNormalsBaseAddress + 4 * normals.limit();
glBindBuffer(GL_ARRAY_BUFFER, mVertexBufferId);
glBufferData(GL_ARRAY_BUFFER, totalBytes, null, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, mVerticesBaseAddress,
4 * vertices.limit(), vertices);
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordsBaseAddress,
4 * texCoords.limit(), texCoords);
glBufferSubData(GL_ARRAY_BUFFER, mNormalsBaseAddress,
4 * normals.limit(), normals);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Load index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferId);
mIndexCount = indices.limit();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * mIndexCount,
indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
OpenGlHelper.checkGLError(TAG, "OBJ buffer load");
mProgram = glCreateProgram();
glAttachShader(mProgram, OpenGlHelper.loadGLShader(TAG, context,
GL_VERTEX_SHADER, R.raw.sphere_vertex));
glAttachShader(mProgram, OpenGlHelper.loadGLShader(TAG, context,
GL_FRAGMENT_SHADER, R.raw.sphere_fragment));
glLinkProgram(mProgram);
glUseProgram(mProgram);
OpenGlHelper.checkGLError(TAG, "Program creation");
mModelViewUniform = glGetUniformLocation(mProgram, "u_ModelView");
mModelViewProjectionUniform =
glGetUniformLocation(mProgram, "u_ModelViewProjection");
mPositionAttribute = glGetAttribLocation(mProgram, "a_Position");
mNormalAttribute = glGetAttribLocation(mProgram, "a_Normal");
OpenGlHelper.checkGLError(TAG, "Program parameters");
setIdentityM(mModelMatrix, 0);
}

Android subset of OpenGLES 2.0 triangles from VBOs don't show up on one test device vs works as intended on other

I'm rendering some super resolution nexrad radar data with a GLSurfaceView. There are 1377156 vertices in my test file. XY with type GL_FLOAT for the position, RGBA with type GL_UNSIGNED_BYTE for the color. 12 bytes total per vertex.
On the new Moto X, everything looks exactly as intended. But on a Nexus 7, it only renders about 3/4 of the triangles in the correct place. There are also some triangles that are showing up where they aren't supposed to.
Nexus 7 : http://i.imgur.com/cRvpa5I.png
Moto X 2014: http://i.imgur.com/YhX5AgU.png
GLES20.glGetError returns GLES20.GL_NO_ERROR. I have an iOS version sharing approximately the same rendering code and vertex/shader program with the exact same test file that works too (on iPad 2).
Draw code
if(renderVertices) {
int numVertices = 1377156;
if(loadVertices){
GLES20.glGenBuffers(1, radarVBO, 0);
GLES20.glGenBuffers(1, colorVBO, 0);
myBuffer.position(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, radarVBO[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, numVertices*8 , myBuffer, GLES20.GL_STATIC_DRAW);
colorBuffer.position(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorVBO[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, numVertices*4 , colorBuffer, GLES20.GL_STATIC_DRAW);
loadVertices = false;
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, radarVBO[0]);
GLES20.glVertexAttribPointer(positionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorVBO[0]);
GLES20.glVertexAttribPointer(colorHandle, VERTEX_COLOR_SIZE, GLES20.GL_UNSIGNED_BYTE, true, 0,0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,numVertices);
}
Fragment program
varying lowp vec4 colorVarying;
void main()
{
gl_FragColor = colorVarying.rgba;
}
Vertex program
attribute vec2 position;
attribute vec4 color;
varying lowp vec4 colorVarying;
uniform mat4 modelViewProjectionMatrix;
void main()
{
colorVarying = color;
gl_Position = modelViewProjectionMatrix * vec4(position, 0.0, 1.0);
}

OpenglES 2.0 PNG alpha texture overlap

I'm trying to draw multiple hexagons on the screen that have an alpha channel. the image is this:
So, I load the texture into the program and that's ok. When it runs, the alpha channel is blended with the background color and that's ok but, when two hexagons overlap themselves, the overlapped part becomes the color of the background! Below the picture:
Of course, this is not the effect that I expected.. I want them to overlap without this background being drawn over the other texture. Here is my code for drawing:
GLES20.glUseProgram(Program);
hVertex = GLES20.glGetAttribLocation(Program,"vPosition");
hColor = GLES20.glGetUniformLocation(Program, "vColor");
uTexture = GLES20.glGetUniformLocation(Program, "u_Texture");
hTexture = GLES20.glGetAttribLocation(Program, "a_TexCoordinate");
hMatrix = GLES20.glGetUniformLocation(Program, "uMVPMatrix");
GLES20.glVertexAttribPointer(hVertex, 3, GLES20.GL_FLOAT, false, 0, bVertex);
GLES20.glEnableVertexAttribArray(hVertex);
GLES20.glUniform4fv(hColor, 1, Color, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, hTexture);
GLES20.glUniform1i(uTexture, 0);
GLES20.glVertexAttribPointer(hTexture, 2, GLES20.GL_FLOAT, false, 0, bTexture);
GLES20.glEnableVertexAttribArray(hTexture);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnable(GLES20.GL_BLEND);
x=-1;y=0;z=0;
for (int i=0;i<10;i++) {
Matrix.setIdentityM(ModelMatrix, 0);
Matrix.translateM(ModelMatrix, 0, x, y, z);
x+=0.6f;
Matrix.multiplyMM(ModelMatrix, 0, ModelMatrix, 0, ProjectionMatrix, 0);
GLES20.glUniformMatrix4fv(hMatrix, 1, false, ModelMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, DrawOrder.length, GLES20.GL_UNSIGNED_SHORT, bDrawOrder);
}
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisableVertexAttribArray(hVertex);
}
And My fragment shader:
public final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);" +
"}";
and my renderer code:
super(context);
setEGLContextClientVersion(2);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setEGLConfigChooser(8, 8, 8, 8, 8, 8);
renderer = new GLRenderer(context);
setRenderer(renderer);
I already tried to use diferent functions on glBlendFunc but nothing seems to work.. Does Anyone knows what the problem is? I'm really lost.. If needs anymore code just ask!
Thank you!
My guess is that you need to disable the depth test when drawing these. Since they all appear at the same depth, when you draw your leftmost ring, it writes into the depth buffer for every pixel in the quad, even the transparent ones.
Then when you draw the next quad to the right, the pixels which overlap don't get drawn because they fail the depth test, so you just get a blank area where it intersects with the first quad.

Not working OpenGL ES shader, call glLinkProgram every frame?

I'm trying to make transparent object in OpenGL ES 2.0. It's a live wallpaper, I'm using GLWallpaperService as a base class for this. I'm setting up OpenGL in this way:
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthFunc(GLES20.GL_GEQUAL);
GLES20.glClearDepthf(0.0f);
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
Shaders I use are taken from PowerVR sample OGLES2AlphaTest for alpha testing, which works fine on my HTC Desire device.
Here is the code for shaders:
private final String mVertexShader = "uniform highp mat4 uMVPMatrix;\n" +
"attribute highp vec4 aPosition;\n" +
"attribute highp vec2 aTextureCoord;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = aTextureCoord;\n" +
"}\n";
private final String mFragmentShader = "precision mediump float;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"void main() {\n" +
" vec4 base = texture2D(sTexture, vTextureCoord);\n" +
" if(base.a < 0.5){ discard; }\n" +
" gl_FragColor = base;\n" +
"}\n";
private int createProgram(String vertexSource, String fragmentSource) {
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return 0;
}
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (pixelShader == 0) {
return 0;
}
int program = GLES20.glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
GLES20.glAttachShader(program, pixelShader);
checkGlError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
Log.e(TAG, "Could not link program: ");
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
private int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e(TAG, "Could not compile shader " + shaderType + ":");
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
Code for rendering frame:
public void onDrawFrame(GL10 glUnused) {
//GLES20.glLinkProgram(mProgram);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
checkGlError("glUseProgram");
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maPosition");
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glEnableVertexAttribArray(maPositionHandle);
checkGlError("glEnableVertexAttribArray maPositionHandle");
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maTextureHandle");
GLES20.glEnableVertexAttribArray(maTextureHandle);
checkGlError("glEnableVertexAttribArray maTextureHandle");
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
time = SystemClock.uptimeMillis();// % 4000L;
angle = 0.030f * ((int) time);
// Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
Matrix.setRotateM(mMMatrix, 0, angle, 0, 1.0f, 0);
Matrix.scaleM(mMMatrix, 0, 0.075f, 0.075f, 0.075f);
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, numPolys);
checkGlError("glDrawArrays");
}
Without GLES20.glLinkProgram(mProgram); in the start of onDrawFrame() I get incorrect result (with incorrect transparency): http://imgur.com/kESeO
When I add GLES20.glLinkProgram(mProgram); in the start of onDrawFrame() it renders correctly, but the performance is bad, glLinkProgram() is time-consuming function. Here is screenshot of correct rendering: http://imgur.com/sw83z
Please explain what am I doing wrong, apparently I don't have to call glLinkProgram() on every frame redraw.
You don't need to link your program each frame, link it once and store its id somewhere. Then call GLES20.glUseProgram(_programId); before you issue drawing calls that correspond to that program.
Check this for an already implemented approach: https://github.com/TraxNet/ShadingZen/blob/master/library/src/main/java/org/traxnet/shadingzen/core/ShadersProgram.java (The bindProgram method is what you are after).
The cause of this misbehavior was not related to glLinkProgram(). I've modified some other GL init parameters (can't recall which at the moment) and now it works just fine.

Categories

Resources