Android terrain test
Hello :), a while ago I decided to learn OpenGL ES 2.0 in Android, so I decided to make a simple terrain, and now I want to share my thoughts about this experience :D.
Edit: after reading this post please take a look at Android Terrain Test 2 : Clouds where the code is better and bugs are fixed (clouds were added too 😛 ).
1. Difficulties:
Coming from a Microsoft XNA background (where everything is wrapped nicely) I found some difficulties learning OpenGL ES 2.0, the things I missed the most were classes like VertexPositionNormal, GraphicsDevice.
Things I hated during the process:
- Java doesn’t have out parameters, it doesn’t have pointers either, so I had to pass an array of length 1 whenever an out parameter is required 😦
int[] id = new int[1]; GLES20.glGenBuffers(1, id, 0);
- Java doesn’t support unsigned primitives, so if you’re using short for the index buffer creation (is there another option?) you’ll be limited to 32,767 different vertices per draw call, in other words you can only have 2^15 -1 different vertices indexed in your index buffer, that might seem like enough vertices for a single draw call, I just hate to not be able to use half of the range of the type short.
Update 30\10\2012 : please check this comment for a really easy solution to this issue.
2. Video:
Here’s a short video of the final result of the terrain
3. The files:
I tried to wrap OpenGL ES 2.0 a little, you can find the classes in the package com.fuchsgl.framework.
Here’s the apk (Android 2.3.3+) : FuchsGL.apk (562 KB)
And here’s the source code (eclipse project) : FuchsGL Source.zip (621 KB).
4. The WebGL version:
Since WebGL is built on OpenGL ES 2.0, I decided to make a web version of the terrain, unfortunately the code conversion process wasn’t that easy, I was new to javascript and I didn’t check the WebGL Specification until it was a little too late.
The awesome thing about WebGL is that the user doesn’t have to install anything, all the user needs is the url of your game (you still need to host the HTML page somewhere), here’s mine for the terrain:
https://drive.google.com/open?id=0B-9zlOMgWVtKd3gzWHVodDM3cms
All you need is to open the HTML page in a browser that supports WebGL like Firefox or Chrome (not IE ;)).
I just put the HTML page with the scripts in my Dropbox folder and it works!. (Dropbox no longer supports direct links, Thanks a lot Dropbox!)
Here’s the source code for the web version of the terrain : WebGlLab.zip (530 KB), the code here is organized in folders similar to the Android version.
I tested the web version on many browsers:
PC:
Firefox 15.0.1
Chrome 22.0.1229.79 m
Android 2.3.4:
Browser
Opera Mobile 12
Dolphin Browser 8.8.2
if it’s not working on your browser then maybe WebGL is disabled, you can enable it by following the steps here.
There’s a 3D library for javascript called three.js, I didn’t use it but you might want to check it out.
5. Helpful tutorials & websites:
http://www.learnopengles.com/android-lesson-one-getting-started/
http://db-in.com/blog/2011/01/all-about-opengl-es-2-x-part-13/
6. Notes
- Terrain texture and height map generated using L3DT Standard, amazing tool for terrain generation with lots of options even for the free standard edition!.
- Android screen recording done using Screencast Video Recorder, the demo version allows you to record 20 seconds max.
I hope you like my terrain :D.
https://ghoshehsoft.wordpress.com/2013/02/26/android-terrain-test-2-clouds/
“Java doesn’t support unsigned primitives” I wonder if it works if you use unsigned math. You could always use char, which basically is an unsigned short. Otherwise I also think you can do something like this: putShort((short) (index)); where index is an int that ranges from 0 to 65535. This works because the narrowing conversion just discards the extra bits.
If you want to get the value back then you do int unsignedShort = getShort() & 0xFFFF;
Wow! the second solution worked great! I created the indices array as int[] and calculated normals as usual, then when creating the byte buffer I casted each int into short like this:
another way I tried is to keep the indices array as short, and whenever I needed to use a value from the array I would do what you said:
this way less changes were made to the code!
Thanks for your help :), it’s really appreciated :).
BTW: great job you’re doing in your website!
No worries, am glad to help 🙂
The apk file doesn’t seem to work on my galaxy Nexus – it shows the splash screen and then the screen just goes blue. Any idea what’s up?
Strange! anyway I’m trying to figure this out on a friend’s phone which is having the same problem.
Here’s what I know so far:
So I tracked the issue, and came to the conclusion that an OpenGL ES2 error is happening, and after lots of logging I found the line that’s causing the error is in the method glSetUniformMatrix4fv in the class Effect.java
I checked the parameters and all of them were correct!
Debugging is hard since my friend lives far away and I’m sending him the apks to try them on his phone.
Let me know if anything comes up!
Cool. I could test, send you logcat etc. as well if you like?
On Tue, Jan 8, 2013 at 11:14 AM, Ghoshehsoft’s Blog wrote:
> ** > Fuchs commented: “Here’s what I know so far: So I tracked the issue, > and came to the conclusion that an OpenGL ES2 error is happening, and after > lots of logging I found the line that’s causing the error is in the method > glSetUniformMatrix4fv in the class Effect.java [sour” >
After more testing it appears that the problem is when calling Effect.glSetUniformMatrix4fv on the World matrix, I tried re-ordering the lines of code to update the View matrix first and no problem was caused until the code tied to update the World matrix! for some reason only the World matrix is causing problems when updating it in the shader!
Just to make sure the same problem is happening on your device you can try and modify the MyRenderer.update() to look like this:
If you debug the previous code only the errWorld should have a non-zero value, probably 1282, if not then there’s another problem!
I’ve seen other OpenGL Es apps defining one matrix in the shader called modelViewProjection, I defined this matrix as three independent matrices, I’ll try to modify the app to make it one matrix and see if it works.
errBefore = 1282
errWorld = 1282
errView = 0
errProjection = 0
hope this helps
Still not working on my friend’s device! this is driving me crazy!

One strange thing is that the WebGL version worked on the device! the WebGL version is just a port of the same code to WebGL!
can you please try the WebGL version on your phone?
I tried it on both the stock browser and on chrome on my gnex, both came up with the same error:
The page at https://dl.dropbox.com says:
Uncaught Could not initialise WebGL https://dl.dropbox.com/u/12942790/FuchsWebGL/renderer.js 21
On Wed, Jan 9, 2013 at 5:46 PM, Ghoshehsoft’s Blog wrote:
> ** > Fuchs commented: “Still not working on my friend’s device! this is > driving me crazy! One strange thing is that the WebGL version worked on the > device! the WebGL version is just a port of the same code to WebGL! can you > please try the WebGL version on your phone? ” > Respond to this comment by replying above this line > New comment on *Ghoshehsoft’s Blog > * > > > *Fuchs* commentedon Android > terrain test. > > > in response to *Ollie Stockley*: > > Cool. I could test, send you logcat etc. as well if you like? On Tue, Jan > 8, 2013
Actually it does help a bit, this means that an error is happening before & after modifying the world matrix in the shader, but I really have no idea what to do from here!
Thankyou very much for this tutorial, it has been very usefull.
There is just an issue: to make it work on my Nexus 7 (Android 4.4.2), I’ve had to add these lines in “glLoadTexture”
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);
Without this fix, the textures appeared as plain black.
Hi, thanks for the tip, the two lines you provided are added in the newer terrain demo (Android Terrain Test 2 : Clouds) which contains other fixes and improvments 🙂 .
…BTW, can you tell me which modifications are needed to handle bigger heightmaps (like 1000px X 1000px) ?
Your program crashes with an OutOfRangeException when using heightmaps of 512px X 512 px… 😦
The limit comes from the limited range of the type short used in indexing vertices.
Even if this limit didn’t exist it’s not practical to draw the whole terrain.
For larger terrains you should consider some advanced terrain techniques like LOD (Level of detail) and Quad Trees
Here are some links:
http://www.gamasutra.com/view/feature/3434/continuous_lod_terrain_meshing_.php
http://vterrain.org/LOD/Papers/
You can find lot’s of papers and tutorials on those two techniques.
Thank you very much. I have improved it to infinity Terrain including simple Collision detection. Look on PlayStore:
https://play.google.com/store/apps/details?id=com.neoexpert.world