Home > Android, Games Programming, Graphics, My Thoughts, OpenGL > Android terrain test

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 😛 ).

Terrain in landscape mode


  1. Difficulties
  2. Video
  3. Download apk and source
  4. WebGL Version!
  5. Helpful tutorials
  6. notes



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:

  1.  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);
    
  2. 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/

  1. 30/10/2012 at 3:23 am

    “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;

    • Fuchs
      30/10/2012 at 6:23 pm

      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:

      public static ShortBuffer createShortBuffer(int[] data)
      {
      	ByteBuffer bytes = ByteBuffer.allocateDirect(data.length * 2);
      	bytes.order(ByteOrder.nativeOrder());
      	ShortBuffer result = bytes.asShortBuffer();
      
      	for (int i = 0; i < data.length; i++)
      		result.put((short) data[i]);
      
      	result.position(0);
      	return result;
      }
      

      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:

      int index = indices[i] & 0xFFFF;
      

      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!

  2. 30/10/2012 at 6:42 pm

    No worries, am glad to help 🙂

  3. Ollie Stockley
    05/01/2013 at 2:23 pm

    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?

    • Fuchs
      08/01/2013 at 5:26 am

      Strange! anyway I’m trying to figure this out on a friend’s phone which is having the same problem.

    • Fuchs
      08/01/2013 at 1:14 pm

      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

      public void glSetUniformMatrix4fv(int index, float[] value)
      {
      	GLES20.glUniformMatrix4fv(index, 1, false, value, 0);
      }
      

      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!

      • Ollie Stockley
        08/01/2013 at 8:45 pm

        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” >

        • Fuchs
          09/01/2013 at 4:29 am

          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:

          void update()
          { 
          	angle += vel;
          	vel *= 0.99;
          
          	Matrix.rotateM(world, 0, identity, 0, angle, 0, 1, 0);
          
          	int errBefore = GLES20.glGetError();
          	program.glGetEffect().glSetUniformMatrix4fv("World", world);
          	int errWorld = GLES20.glGetError();
          	program.glGetEffect().glSetUniformMatrix4fv("View", view);
          	int errView = GLES20.glGetError();
          	program.glGetEffect().glSetUniformMatrix4fv("Projection", projection);
          	int errProjection = GLES20.glGetError();
          }
          

          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.

          • ollie
            09/01/2013 at 9:45 pm

            errBefore = 1282
            errWorld = 1282
            errView = 0
            errProjection = 0

            hope this helps

        • Fuchs
          09/01/2013 at 7:46 pm

          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?
          WebGL Terrain

          • Ollie Stockley
            09/01/2013 at 8:17 pm

            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

  4. Fuchs
    10/01/2013 at 6:25 am

    ollie :

    errBefore = 1282
    errWorld = 1282
    errView = 0
    errProjection = 0

    hope this helps

    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!

  5. 23/02/2014 at 8:01 pm

    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.

    • Fuchs
      24/02/2014 at 5:18 pm

      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 🙂 .

  6. 23/02/2014 at 8:02 pm

    …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… 😦

  7. 05/08/2016 at 12:44 am

    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

  1. 30/10/2012 at 3:10 am

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: