Posts
Search
Contact
Cookies
About
RSS

libGDX Migrating from GLES 1.0 to GLES 2.0

Added 2 Jan 2013, 10:14 p.m. edited 19 Jun 2023, 3:45 a.m.

To be honest I resisted loosing a fixed function pipeline for sometime, while a fixed function pipeline can be limiting it does provide some very useful and complex functionality, not least for example the global lighting model which can be very complex to reproduce.

Now that GLES 2.0 had matured it is seeming ubiquitous you can run the same shaders on mobile devices, desktops and even in browsers via javascipt, this makes it very attractive when using a library like GDX as you can literally write once and see it running on a wide range of platforms.

This guide will avoid detailed examination of GLES 2.0 itself and concentrate on the differences that GLES 2.0 introduces to someone who at least has some experience with libGDX.

Initially when starting the application you will need a configuration for it, the only change here is you should explicitly state you require GLES 2.0

 config.useGL20 = true;

Like we'd normally do in a platform stub once we have a configuration we can the kick off the application

 new LwjglApplication(new gdxGLES2(), config);

The create method is where we find out first big differences initially with the creation of a simple shader – we won't be detailing how this very simple shader works.

String vertexShader = readFile("data/texture.vert");
String fragmentShader = readFile("data/texture.frag");
shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) {
    Gdx.app.log("Shader error!",shader.getLog());
}

While you can embed the shader source as literal strings I find it more convenient to edit them as distinct files, once a shader is created you can check to see if its compiled ok, assuming everything is fine we can then use it with a 3d model.

mesh1 = ObjLoader.loadObjFromString(readFile("data/sphere.obj"),true);
mesh1.getVertexAttribute(Usage.Position).alias = "a_position";
mesh1.getVertexAttribute(Usage.TextureCoordinates).alias = "a_texCoord";

Having loaded our model we “link” the shaders attributes with attributes of the models vertices, here the attributes “a_position” and “a_texCoord” are actual variables within our shader.

Moving on now to the render method the next thing we have to account for its the removal of all the math from modern OpenGL implementations

I prefer to separate out the various transformations needed to render a 3d scene onto a 2d surface with three main matrices.

Projection matrix – mainly used to make objects smaller as they get further from our notional “camera” you can think of the setting used to create this matrix as the “lens” settings.

View matrix – this is used to represent the orientation and position of the “camera”

Model matrix – just as the “camera” has a rotation and orientation so does each model in the scene

Ok you may have noticed the elephant in the room! - "camera" in quotes - basically the concept of a camera is really for our own convenience, indeed if you search the entire text of the GLES 2.0 man pages you won't find a single occurrence of the word! (I munged all the man pages into one file and if I'm honest I expected one or two occurrences).  However the paradigm of a camera is so conceptually useful, especially for 3d work that its best to stick with it...

Once we have combined all our calculations into a single matrix which we can feed into our simple shader, just a couple of parameters are required for the shader before finally rendering out model.

shader.setUniformi("s_texture1", 0); // first texture unit (0)
shader.setUniformMatrix("u_mvp_mat", combined);
mesh1.render(shader, GL20.GL_TRIANGLES);

Having done our 3d rendering we can also render in 2d just like we would using previous incarnations of OpenGL

Gdx.gl20.glDisable(GL20.GL_CULL_FACE);
spriteBatch.begin();
font.draw(spriteBatch, "Frames Per Second: " + Gdx.graphics.getFramesPerSecond(), 30, 30);
spriteBatch.end();

There is just a couple of potential gotchas first off if you are using multitexturing make sure only texture unit 0 is active and selected before using a spritebatch.

The second potential gotcha could be entirely to do with the way I've set things up (I'm not too sure to be honest) I found that in order for the sprite batch to render I had to switch back face culling OFF.

Next we'll look closer at shaders to provide a textured object with specular lighting (shiny objects with a pure white dot of reflected light), and include some sample source to demonstrate simple lighting with a shader.