OpenGL 3.0, cannot draw textured quad - android

I am trying to modify a sample from the OpenGL ES 3.0 programming guide book, but I cannot figure out why I can't draw a textured quad.
here is the main drawing loop (extracted from the book, with minor modifications):
void DrawTexturedQuad(ESContext *esContext)
{
UserData *userData = static_cast<UserData *>(esContext->userData);
GLfloat vVertices[] =
{
-0.5f, 0.5f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-0.5f, -0.5f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
0.5f, -0.5f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
0.5f, 0.5f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
// Use the program object
glUseProgram ( userData->programObjectMultiTexture );
// Load the MVP matrix
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE,(GLfloat *) &userData->grid.mvpMatrix.m[0][0]);
#define LOCATION_VERT (7)
#define LOCATION_TEXT (8)
// Load the vertex position
glVertexAttribPointer ( LOCATION_VERT, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof ( GLfloat ), vVertices );
// Load the texture coordinate
glVertexAttribPointer ( LOCATION_TEXT, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof ( GLfloat ), &vVertices[3] );
glEnableVertexAttribArray ( LOCATION_VERT );
glEnableVertexAttribArray ( LOCATION_TEXT );
// Bind the base map
glActiveTexture ( GL_TEXTURE0 );
glBindTexture ( GL_TEXTURE_2D, userData->baseMapTexId );
// Set the base map sampler to texture unit to 0
glUniform1i ( userData->baseMapLoc, 0 );
// Bind the light map
glActiveTexture ( GL_TEXTURE1 );
glBindTexture ( GL_TEXTURE_2D, userData->lightMapTexId );
// Set the light map sampler to texture unit 1
glUniform1i ( userData->lightMapLoc, 1 );
glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
glDisableVertexAttribArray ( LOCATION_VERT );
glDisableVertexAttribArray ( LOCATION_TEXT );
}
The vertex shader:
#version 300 es
uniform mat4 u_mvpMatrix;
layout(location = 7) in vec3 a_position;
layout(location = 8) in vec2 a_texCoord;
out vec2 v_texCoord;
void main()
{
//gl_Position = vec4(a_position, 1.f);
gl_Position = u_mvpMatrix * vec4(a_position, 1.f);
v_texCoord = a_texCoord;
}
the Fragment shader:
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_baseMap;
uniform sampler2D s_lightMap;
void main()
{
vec4 baseColor;
vec4 lightColor;
baseColor = texture( s_baseMap, v_texCoord );
lightColor = texture( s_lightMap, v_texCoord );
outColor = baseColor * (lightColor + 0.25);
//outColor = vec4(1.f, 1.f, 1.f, 1.f);
}
I did three tests, but they all look incorrect although the setup and shaders look right to me.
1st test (top window of the picture). The code is as shown above.
2nd test (middle window of the picture). I by passed the samplers and hard-coded the color on the fragment shader like so:
outColor = vec4(1.f, 1.f, 1.f, 1.f);
This proved that my matrices are correct, since I see a white quad properly tranformed on the screen.
3rd test (bottom window). I bypassed the matrix tranform to test if the samplers are correct. I do see the textured quad rendered but no transformation. like so:
// this is so odd, I can see the textures!!!!
// why the transform can mess things up?
gl_Position = vec4(a_position, 1.f);
v_texCoord = a_texCoord;
Anyway, if anyone can spot the issue, I'd really appraciated. I am using the Mali ARM emulator and there is no way to debug the shader, I have no idea what is going on inside. Yet, the code setup looks correct but they don't seem to work all together for some reason.

Related

Android NDK OpenGL ES 3.0 glDrawArrays and glDrawElements throws GL_INVALID_OPERATION

Here's my vertex shader code
#version 300 es
precision mediump float;
precision mediump int;
layout (location = 0) in vec3 pos;
void main(){
gl_Position = vec4(pos, 1);
}
Here's my fragment shader code
#version 300 es
precision mediump float;
precision mediump int;
out vec4 FragColor;
void main(){
FragColor = vec4(0.6, 0.5, 0.7, 1.0);
}
I created VAO, VBO and EBO like this:
GLCall(glGenVertexArrays(1, &vao));
GLCall(glGenBuffers(1, &vbo));
GLCall(glGenBuffers(1, &ebo));
GLfloat vertices[] = {
// first triangle
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, 0.5f, 0.0f, // top left
// second triangle
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
GLuint indices[] = { // note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
GLCall(glBindVertexArray(vao));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, vbo));
GLCall(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo));
GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
GLCall(glEnableVertexAttribArray(0));
GLCall(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, (void*)0));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCall(glBindVertexArray(0));
Here's how I call it in render loop
void World::render(double dt) {
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.6f, 0.8f, 0.7f, 1.f);
getShader("Shader").Use();
GLCall(glBindVertexArray(vao));
GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr)); // world.cpp line 59
}
GLCall() is used to check OpenGL errors on function calls.
I use GLSurfaceView to create a surface as the examples do https://github.com/android/ndk-samples/blob/main/hello-gl2/app/src/main/java/com/android/gl2jni/GL2JNIView.java.
I tried so many methods online and I still didn't solve the problem, everything is fine after I called glDrawArrays or glDrawElements:
06-10 19:12:33.457 2044-2059/com.example.bricks D/GLRenderer: onSurfaceChanged() called with: gl = [com.google.android.gles_jni.GLImpl#ecf0382], width = [1440], height = [769]
06-10 19:12:33.465 2044-2059/com.example.bricks E/NativeRenderer: OpenGL Error: GL_INVALID_OPERATION in E:/Projects/Android/Bricks/app/src/main/cpp/World.cpp line 59
06-10 19:12:33.466 2044-2059/com.example.bricks E/AndroidRuntime: FATAL EXCEPTION: GLThread 108
Process: com.example.bricks, PID: 2044
java.lang.RuntimeException: OpenGL Error: GL_INVALID_OPERATION in E:/Projects/Android/Bricks/app/src/main/cpp/World.cpp line 59
at com.example.bricks.NativeRenderer.putExceptionString(NativeRenderer.java:70)
at com.example.bricks.NativeRenderer.nativeRendererOnDrawFrame(Native Method)
at com.example.bricks.GLRenderer.onDrawFrame(GLRenderer.java:122)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1535)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
Please give me a help, Salute!!

Draw multiple objects in one glDrawElements()

I'm practicing in basic things in OpenGL ES2.0 using this 2d tutorial:
http://androidblog.reindustries.com/a-real-opengl-es-2-0-2d-tutorial-part-2/
Basically it just draws a rect with a texture.
Now I would like to draw multiple rects in one glDrawElements() call on different positions but with the same texture. So I add more items to the vertices and indices arrays. However texture coords (uvs array) are the same for every rect and there's no sense to stretch it by copying the same values. Can I somehow reuse it or perhaps set it as a constant somewhere inside the shader code?
Vertex shader:
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = uMVPMatrix * vPosition;
v_texCoord = a_texCoord;
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture;
void main() {
gl_FragColor = texture2D( s_texture, v_texCoord );
}
Arrays (used in buffers):
vertices = new float[]
{ 10.0f, 200f, 0.0f,
10.0f, 100f, 0.0f,
100f, 100f, 0.0f,
100f, 200f, 0.0f,
};
indices = new short[] {0, 1, 2, 0, 2, 3};
uvs = new float[] {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
Render code:
private void Render() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
int mPositionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
int mTexCoordLoc = GLES20.glGetAttribLocation(program, "a_texCoord" );
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);
int mtrxhandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
int mSamplerLoc = GLES20.glGetUniformLocation (program, "s_texture" );
GLES20.glUniform1i ( mSamplerLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}

VBO, Shader C++ Android Confusion

I'm having trouble understanding where/how to setup buffers for a native android application in VS 2015. I apologize if this isn't the best way to ask a question. I appreciate any help/insight.
This is what I have so far:
(in engine_init_display)
GLint vShaderLength = vertex_shader.length();
const GLchar* vcode = vertex_shader.c_str();
GLint fShaderLength = fragment_shader.length();
const GLchar* fcode = fragment_shader.c_str();
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vcode, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fcode, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
GLint pos_id = glGetAttribLocation(shader_programme, "position");
//Set vertex data
glUseProgram(shader_programme);
glVertexAttribPointer(pos_id, 0, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(pos_id, //GLuint
3, //GLint size
GL_FLOAT, //GLenum type
GL_FALSE, //GLboolean
(sizeof(float) * 5), //GLsizei stride
points //const GLvoid *pointer
);
glEnableVertexAttribArray(pos_id);
(in engine_draw_frame)
glClearColor(1.0f, 0.41f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
eglSwapBuffers(engine->display, engine->surface);
With this, I get a pink (clear colour) background. I'm not sure what I'm doing wrong.
Here are my vertex data and shaders
float points[] =
{
-0.2f, 0.6f, 0.0f,
0.0f, 1.0f,
0.5f, 0.5f, 0.0f,
1.0f, 1.0f,
-0.5f, -0.5f, 0.0f,
0.0f, 0.0f,
0.5f, -0.5f, 0.0f,
1.0f, 0.0f
};
unsigned short indices[] =
{
0, 2, 1, 2, 3, 1
};
std::string vertex_shader =
"#version 300 es \n"
"in vec3 position; \n"
"void main () { \n"
" gl_Position = vec4 (position, 1.0); \n"
"} \n";
std::string fragment_shader =
"#version 300 es \n"
"precision highp float; \n"
"out vec4 frag_colour; \n"
"void main () { \n"
" frag_colour = vec4 (0.5, 0.0, 0.5, 1.0); \n"
"} \n";
OK, I figured it out. There isn't anything wrong with my shaders or vertex array. The problem was that I didn't specify EGL to create an OpenGLES2 context using EGL_CONTEXT_CLIENT_VERSION.
Check here -> Khronos Specification, page 43 (of pdf) for more info
Sample from specification:
EGLContext eglCreateContext(EGLDisplay dpy,
EGLConfig config, EGLContext share_context,
const EGLint *attrib_list);
if the *attrib_list is left null, the default is OpenGLES1 and shaders will not work in that context.
So, what you need to do is create an attribute list. Something along the lines of:
EGLint contextAttributes[]=
{
EGL_CONTEXT_CLIENT_VERSION,2,
EGL_NONE
}
and pass that to the create context
p_context = eglCreateContext(display, config, NULL, contextAttributes);
Basically, I was too unsure of my ability with vertex buffers that I focused on that for a long time.

shaders not causing any effect - opengl

I'm trying to render on a Texture which resides in another class and I can't look at the code. I just have the access to it's pointer which is created by glGenTextures.
I'm trying to render on this texture. I'm creating my own shaders and linking to it but they don't affect anything. I just see a white screen on my phone. I've put opengl error check after every statement, and it passes without any error.
I wanted to ask, could there be any previously attached shaders to that texture or something like that which are hindering my own shaders. (I don't even know if this statement makes any sense.)
I'm using the utility class from grafika for program and shaders creation - https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/GlUtil.java . That's why I'm pretty much sure my shaders related code is okay.
This is my main drawing loop -
log("Receiving frame");
GLES20.glUseProgram(programHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mainTexture.glName);
//
// Copy the model / view / projection matrix over.
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, GlUtil.IDENTITY_MATRIX, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Copy the texture transformation matrix over.
/*
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv"); */
// Enable the "aPosition" vertex attribute.
GLES20.glEnableVertexAttribArray(maPositionLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect vertexBuffer to "aPosition".
GLES20.glVertexAttribPointer(maPositionLoc, 2,
GLES20.GL_FLOAT, false, 2 * GlUtil.SIZEOF_FLOAT, GlUtil.FULL_RECTANGLE_BUF);
GlUtil.checkGlError("glVertexAttribPointer");
// Enable the "aTextureCoord" vertex attribute.
GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect texBuffer to "aTextureCoord".
GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
GLES20.GL_FLOAT, false, 2 * GlUtil.SIZEOF_FLOAT, GlUtil.FULL_RECTANGLE_TEX_BUF);
GlUtil.checkGlError("glVertexAttribPointer");
GLES20.glViewport(0, 0, parameters.getPreviewSize().width, parameters.getPreviewSize().height);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
This is my fragment shader code -
public static final String FRAGMENT_SHADER_2D =
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"void main() {\n" +
" gl_FragColor[0] = 1.0;gl_FragColor[1] = 0.0;gl_FragColor[2] = 0.0;gl_FragColor[3] = 1.0;\n" +
"}\n";
These are the coordinate matrices -
private static final float FULL_RECTANGLE_COORDS[] = {
-1.0f, -1.0f, // 0 bottom left
1.0f, -1.0f, // 1 bottom right
-1.0f, 1.0f, // 2 top left
1.0f, 1.0f, // 3 top right
};
private static final float FULL_RECTANGLE_TEX_COORDS[] = {
0.0f, 0.0f, // 0 bottom left
45.0f, 0.0f, // 1 bottom right
0.0f, 1.0f, // 2 top left
56.0f, 344.0f // 3 top right
};
There doesn't seem to be any code for connecting your texture to "sTexture". You are using texture slot 2 for your texture, so you need tell the shader this:
GLES20.glActiveTexture(GLES20.GL_TEXTURE2); // using texture slot 2
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mainTexture.glName);
int mSamplerLoc = GLES20.glGetUniformLocation (programHandle, "sTexture" );
GLES20.glUniform1i ( mSamplerLoc2, 2); // connect sTexture to texture slot 2

FBO texture copy not working on Android - rendered texture filled with whatever is at texture coord 0, 0

The problem is that the result of the FBO copy is filled with whatever pixel is at texture coordinate 0,0 of the source texture.
If I edit the shader to render a gradient based on texture coordinate position, the fragment shader fills the whole result as if it had texture coordinate 0, 0 fed into it.
If I edit the triangle strip vertices, things behave as expected, so I think the camera and geometry is setup right. It's just that the 2-tri quad is all the same color when it should reflect either my input texture or at least my position-gradient shaders!
I've ported this code nearly line for line from a working iOS example.
This is running alongside Unity3D, so don't assume any GL settings are default, as the engine is likely fiddling with them before my code starts.
Here's the FBO copy operation
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer);
checkGlError("glBindFramebuffer");
GLES20.glViewport(0, 0, TEXTURE_WIDTH*4, TEXTURE_HEIGHT*4);
checkGlError("glViewport");
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(false);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glPolygonOffset(0.0f, 0.0f);
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
checkGlError("fbo setup");
// Load the shaders if we have not done so
if (mProgram <= 0) {
createProgram();
Log.i(TAG, "InitializeTexture created program with ID: " + mProgram);
if (mProgram <= 0)
Log.e(TAG, "Failed to initialize shaders!");
}
// Set up the program
GLES20.glUseProgram(mProgram);
checkGlError("glUseProgram");
GLES20.glUniform1i(mUniforms[UNIFORM_TEXTURE], 0);
checkGlError("glUniform1i");
// clear the scene
GLES20.glClearColor(0.0f,0.0f, 0.1f, 1.0f);
checkGlError("glClearColor");
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Bind out source texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
checkGlError("glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mSourceTexture);
checkGlError("glBindTexture");
GLES20.glFrontFace( GLES20.GL_CW );
// Our object to render
ByteBuffer imageVerticesBB = ByteBuffer.allocateDirect(8 * 4);
imageVerticesBB.order(ByteOrder.nativeOrder());
FloatBuffer imageVertices = imageVerticesBB.asFloatBuffer();
imageVertices.put(new float[]{
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f}
);
imageVertices.position(0);
// The object's texture coordinates
ByteBuffer textureCoordinatesBB = ByteBuffer.allocateDirect(8 * 4);
imageVerticesBB.order(ByteOrder.nativeOrder());
FloatBuffer textureCoordinates = textureCoordinatesBB.asFloatBuffer();
textureCoordinates.put(new float[]{
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f}
);
textureCoordinates.position(0);
// Update attribute values.
GLES20.glEnableVertexAttribArray(ATTRIB_VERTEX);
GLES20.glVertexAttribPointer(ATTRIB_VERTEX, 2, GLES20.GL_FLOAT, false, 0, imageVertices);
GLES20.glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);
GLES20.glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GLES20.GL_FLOAT, false, 0, textureCoordinates);
// Draw the quad
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
If you want to dive in, I've put up a nice gist with the update loop, setup and shaders here: https://gist.github.com/acgourley/7783624
I'm checking the result of this as an Android port to UnityFBO (MIT License) so all help is both appreciated and will be shared more broadly.
The declaration of your vertex shader output and fragment shader input do not mach for the texture coordinate varying (different precision qualifiers). Ordinarily this would not be an issue, but for reasons I will discuss below using highp in your fragment shader may come back to bite you in the butt.
Vertex shader:
attribute vec4 position;
attribute mediump vec4 textureCoordinate;
varying mediump vec2 coordinate;
void main()
{
gl_Position = position;
coordinate = textureCoordinate.xy;
}
Fragment shader:
varying highp vec2 coordinate;
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture, coordinate);
}
In OpenGL ES 2.0 highp is an optional feature in fragment shaders. You should not declare anything highp in a fragment shader unless GL_FRAGMENT_PRECISION_HIGH is defined by the pre-processor.
GLSL ES 1.0 Specification - 4.5.4: Available Precision Qualifiers - pp. 36
The built-in macro GL_FRAGMENT_PRECISION_HIGH is defined to one on systems supporting highp precision in the fragment language
#define GL_FRAGMENT_PRECISION_HIGH 1
and is not defined on systems not supporting highp precision in the fragment language. When defined, this macro is available in both the vertex and fragment languages. The highp qualifier is an optional feature in the fragment language and is not enabled by #extension.
The bottom line is you need to check whether the fragment shader supports highp precision before declaring something highp or re-write your declaration in the fragment shader to use mediump. I cannot see much reason for arbitrarily increasing the precision of the vertex shader coordinates in the fragment shader, I would honestly expect to see it written as highp in both the vertex shader and fragment shader or kept mediump.

Categories

Resources