I've written a small sprite shader which is a clone of the sprite shader from here http://learnopengl.com/#!In-Practice/2D-Game/Rendering-Sprites
The only difference between straightforward OpenGL and OpenGL ES 3.1 would be a few lines in the shaders. You need to change the version in both shaders from:
#version 330 core
to
#version 300 es
And, to the fragment shader, add the line
precision mediump float;
somewhere near the top.
Then, assuming your shader has a model and projection matrix uniforms, you just use a 2d vector position to create a 4d vector, substituting 0.0 and 1.0 for the last two parameters in your vertex shader:
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
I feel this is explained better in Joey's LearnOpenGL tutorials than I can explain in detail here.
Your draw function might look something like this (if you use C++11):
mShader( [ & ] ( ) // Same as glUseProgram( shaderID ) but automatically un-Uses it when it goes out of scope
{
glm::mat4 model;
model = glm::translate( model, glm::vec3( xPosition, 0.0f ) );
model = glm::translate( model, glm::vec3( 0.5f * xSize.x, 0.5f * xSize.y, 0.0f ) );
model = glm::rotate( model, xRotate, glm::vec3( 0.0f, 0.0f, 1.0f ) );
model = glm::translate( model, glm::vec3( -0.5f * xSize.x, -0.5f * xSize.y, 0.0f ) );
model = glm::scale( model, glm::vec3( xSize, 1.0f ) );
mShader.getUniforms( ).setUniformMatrix4fv( "model", model );
mShader.getUniforms( ).setUniformVector3f( "spriteColor", xColor );
glActiveTexture( GL_TEXTURE0 );
xTexture( [ & ]( ) // Does the same as glBindTexture but automatically unbinds when out of scope
{
glBindVertexArrayOES( mQuadVAO );
glDrawArrays( GL_TRIANGLES, 0, 6 );
glBindVertexArrayOES( 0 );
} );
} );
The only difference in my implementation from the tutorial that is I use SDL to get an OpenGL ES 3.0 context (for portability and other functions, such as keyboard, mouse). I can confirm that Joey's tutorial runs on Android, embedded Linux Intel integrated graphics and Windows with the AMD GLES3 SDK with just the few minor changes I mentioned above.
You might want to augment the implementation by using a PBO; an OpenGL version is in the same repo.
It uses PBOs. This can be used to update the quad textures more rapidly than glTexImage2D
. I don't know if PBOs are supported in OpenGL ES but they might be by extension. If you just need to load a bunch of quads ahead of time and render them, you don't need to go that far.
To update the quad in the straightforward way, it's just:
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, mW, mH, GL_RGBA, GL_UNSIGNED_BYTE, xData );
Using the PBOs, you can use two PBOs to enable a "double buffering feature" where you clear a PBO and map the other PBO each turn. See the OpenGL ES specifications for glBindBufferARB
, glBufferDataARB
, glMapBufferARB
, glUnmapBufferARB
for more information. Apparently, as of 3.0, OpenGL ES does support PBOs so if you need to update the textures rapidly, this is the way to go.