posts | comments
17Jan

Android: 3D tunnel demo with OpenGL ES

18 comments so far

3D tunnel demo (click to zoom)As promised, here is my personal implementation of a small 3D tunnel demo in Android, with support of OpenGL ES. I have never coded in OpenGL ES before and the first impact was negative, shortly: I don’t like it! Compared with OpenGL (standard version), ES has some limitations, in particular on direct vertex handling. Crudely, the glBegin/glEnd and glVertex## functions are missing. The intensive use of “buffers” (java.nio.Buffer) to render textures and primitives, with all it’s subclasses (ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer and ShortBuffer), is a useless waste of time and memory, in my humble opinion. If you must dynamically build your 3D object, for example to make a morphing mesh like my tunnel, you’ll go crazy. In fact you should hold a copy of vertices in Java memory (for example a float[] array) and a copy of vertices in system memory (a ByteBuffer object instantiated with allocateDirect); then for each frame you must re-calculate the vertices and blit them from the array in Java memory to the buffer in system memory. What the fuck… Alternatively you can use the putFloat method directly on the ByteBuffer object, due to eliminate the Java array, but this is fucking slow compared with a single put method call. I haven’t spent so much time on this topic, probably exists a “cool” method to eliminate that blit phase, please leave me a comment if you knows. I am almost sure, to speed-up an OpenGL system on a mobile device, the best way is hold 3D engine data in system memory, that’s the reason of buffers use. An easy task instead, is hooking the OpenGL surface with a View object. You can also render your OpenGL scene and then write some graphics using the Canvas methods on the same surface: COOL 8) Next time I’ll do further experiments on OpenGL ES, maybe I’m wrong.

Ok, attached in this post you’ll find the complete source code of my 3D tunnel. Code is not very clean and commented, but you can take a look if you wish: feel free to download and use it. Please, leave me a comment: your ideas will be appreciated!

Used Eclipse IDE with Android SDK version m3-rc37a (Windows system)

winzip_75x75.jpg Download 3D tunnel demo source code (618 Kb)

Categories: Android, Programming

Thursday, January 17th, 2008 at 10:29 pm and is filed under Android, Programming. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

18 Responses to “Android: 3D tunnel demo with OpenGL ES”

  1. Posted by Jose Cortés 17th November, 2008 at 1:25 pm

    Hello!

    I am working in Android and OpenGL as well, you say in your post that ” An easy task instead, is hooking the OpenGL surface with a View object”. I am looking for that.

    What is the way to put, a view (not drawable, a layout, for example) in the surface (as texture) of the openGL figure?

    Thanks!

  2. Posted by chris 28th February, 2009 at 7:52 pm

    Quit cool… i guess, but i can not compile :) i have Eclipse Classic 3.4.2
    first he said errors in AndroidManifest.xml (for example there was android:value … i changed to android:name also was there class=”.AMain” i changed to Android:Name=”.AMain” … and got less error :) (i am TOTAL java starter).. than he had probs to find the GLSurfaceView stuff.. ok i added a Class folder to src … but now he says: Class com.google.android.tunnel3d.AMain does not exist (but its there).. i really come crazy :)maybe you can give a short step by step how to import that sourcecode.. i really would appreciate :) thanks

  3. Posted by Oli 16th May, 2009 at 1:50 am

    It’s a while since you posted that. I also struggled with the dynamic vertex manipulation on the Java Wrapper. I was working on a classic starfield thing, when it came up to the same issue you described. As I am new to Java (hardly preferring C/C++) I was confused about the direct allocation stuff. So in the first trial I manipulated each vertex in the direct allocated mem using the putFloat-shit. I profiled the section when I “mirrored” the vertices coords by the way you described: Holding a buffer in the JVM mem and copy it after the update to the direct mem. So this gave me a significant performance boost.I made some research but found no better solution than that. Additionally, the crap of rewinding the buffers sucks. How many times I forgot it?!

    Here’s my update code for the pixel stars
    protected final void updatePixelStars(){

    /*
    * we mirrored the direct vertex buffer to VM heap based array.
    * when updating the pixels, the entire update is done on mirror first,
    * and afterwards all new values are copied to direct buffer at once.
    * This significantly speeds up the starfield update
    */

    int n= this.mPixelStarCount;
    if(n==0)
    return;
    int ix=0, p=0;
    int one=Fix.One;
    for(int s=0; s< n; ++s)
    {
    PixelStar star= mPixelStars.get(s);
    ix = s*2;
    mVbMirror[ix]+=star.stepWidthX;
    p = mVbMirror[ix];
    if(pone)
    {
    mVbMirror[ix]=-one;
    mVbMirror[ix+1]=Fix.toX((float)Math.random() * 2 - 1); // new y PosBufition }
    }
    }

    mVertexBuffer.put(mVbMirror);
    mVertexBuffer.rewind();
    }

  4. Posted by Jeremy 25th May, 2009 at 9:40 pm

    Really cool– what’s with the last segment of the circle, where the texture gets squished? It makes kind of a stripe along the ceiling. Any idea why?

  5. Posted by Ryan 26th May, 2009 at 6:17 pm

    Jeremy- that’s because the last segment of each circle is mapping on texture from 0.9 back to 0 (for a ten segment circle). OpenGL maps this backwards, rather than passing over an edge. A solution would be to move the last vertext to overlap the first vertex– this could be done by changing deltax from 360 / nx to 360 / (nx - 1) wherever it occurs. You lose a segment, but you get correct mapping.

  6. Posted by Alex 27th May, 2009 at 12:06 am

    somebody get it working under SDK 1.5 ???

    pls email me under: thediskjoker@gmx.net

    10x a lot

  7. Posted by Jesus 10th June, 2009 at 6:33 pm

    I got it running in 1.5(cup cake) by making the following changes to the AMain and GLView classes.

    public class AMain extends Activity{

    private GLSurfaceView mGLView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFormat(PixelFormat.TRANSLUCENT);

    mGLView = new GLSurfaceView(this);
    mGLView.setEGLConfigChooser(false);
    mGLView.setRenderer(new GLView(this));
    setContentView(mGLView);
    }

    @Override
    protected void onPause() {
    super.onPause();
    mGLView.onPause();
    }

    @Override
    protected void onResume() {
    super.onResume();
    mGLView.onResume();
    }

    ….

    public class GLView implements GLSurfaceView.Renderer{

    private Context mContext;
    private Tunnel3D tunnel;
    private boolean created;
    private GL10 gl;
    private int w;
    private int h;
    private Bitmap bmp;
    private int tex;

    public GLView (Context context)
    {
    mContext = context;

    // Internal members..
    tunnel = new Tunnel3D (10, 20);
    created = false;

    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    created = true;

    // Enabling the state…
    gl.glEnable (GL10.GL_DEPTH_TEST);
    gl.glEnable (GL10.GL_TEXTURE_2D);
    gl.glEnableClientState (GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState (GL10.GL_COLOR_ARRAY);
    gl.glEnableClientState (GL10.GL_TEXTURE_COORD_ARRAY);

    // Loading texture…
    bmp = BitmapFactory.decodeResource (mContext.getResources(), R.drawable.plants03);
    tex = loadTexture (gl, bmp);

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    this.w = width;
    this.h = height;
    }

    @Override
    public void onDrawFrame(GL10 gl) {

    // Check the created flag…
    boolean c = false;
    synchronized (this)
    {
    c = created;
    }
    if (!c) return;

    // Setting up the projection…
    float ratio = (float)w / h;
    gl.glMatrixMode (GL10.GL_PROJECTION);
    gl.glLoadIdentity ();
    gl.glViewport (0, 0, w, h);
    GLU.gluPerspective (gl, 45.0f, ((float)w)/h, 1f, 100f);

    // Setting up the modelview…
    gl.glMatrixMode (GL10.GL_MODELVIEW);
    gl.glLoadIdentity ();

    // Clear the z-buffer…
    gl.glClear (GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    // Render the tunnel…
    tunnel.render (gl, -1.6f);
    tunnel.nextFrame ();

    // OpenGL finish
    gl.glFlush ();
    gl.glFinish ();

    }

    private int loadTexture (GL10 gl, Bitmap bmp)
    {
    ByteBuffer bb = ByteBuffer.allocateDirect(bmp.getHeight()*bmp.getWidth()*4);
    bb.order(ByteOrder.nativeOrder());
    IntBuffer ib = bb.asIntBuffer();

    for (int y=0;y<bmp.getHeight();y++)
    for (int x=0;x<bmp.getWidth();x++) {
    ib.put(bmp.getPixel(x,y));
    }
    ib.position(0);
    bb.position(0);

    int[] tmp_tex = new int[1];

    gl.glGenTextures(1, tmp_tex, 0);
    int tex = tmp_tex[0];
    gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, bmp.getWidth(), bmp.getHeight(), 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    return tex;
    }
    }

  8. Posted by Kay 14th June, 2009 at 7:42 pm

    Hi,

    I got it running as well. But there are some more changes needed:
    An application class is needed and has to be configured in manifest.xml.

    I suggest we should provide a new zip file including all changes. Davide, can I send the zip file to you? Or any other idea.

    Cheers
    Kay

  9. Posted by Kevin 15th July, 2009 at 12:13 pm

    Hi,
    I totally agree with Kay’s point of view and strongly need a NEW package including step by step HOW-TO.
    HOPE someone can HELP!
    My email is kevinseattle2003@yahoo.com.tw

  10. Posted by Maxood 28th August, 2009 at 6:04 am

    I am a newbie in android development. I found this article quite exciting and like to play with the source code. Could someone guide me how to setup a new project in android to run the source code.

    Can someone please tell me how to setup a new project in Eclipse to run this source code.

    Thanks,
    Maxood

  11. Posted by Kay 5th September, 2009 at 4:55 pm

    Hi Maxood,

    just sent me an email to mail-kay at gmx . de

    Then I can provide you a link to a zip file containing the project.

    Kay

  12. Posted by Reni 16th October, 2009 at 5:53 pm

    Hi Kay,
    Can u plz upload the new project with the modifications..so that it vil b vry helpful for the beginners…

    CHEERSSS
    Reni

  13. Posted by Kay 7th December, 2009 at 11:44 am

    Hi,

    I put a running copy of the Anroid Tunnel3D project here:
    http://files.getdropbox.com/u/658954/Tunnel3D_v16-Jul-2009.zip

    As far as I can see, it should be working out of the box - I found no reference to local stuff. At that time I was running Eclipse 3.3.2 and Android SDK 0.9.1 v2009050 under Linux and java 1.6.0_06-b02.

    Because it is some time ago, I don’t remember exactly what I did to get it running ;-)

    Cheers
    Kay

  14. Posted by ScottL 7th January, 2010 at 8:49 pm

    Just got this running on a droid running 2.0.1 with the newish GLSurfaceView. Happy to email you the code, but I’m pretty early along my droid curve…

  15. Posted by sacs 18th January, 2010 at 11:39 pm

    Hi SCottL,
    I tried running the above code and it runs only once , once I stop this and again try to run from the application list it shows a blank screen. I tried to put this App on the DROID Motorola which is 2.0 phone but again it doesnt work. Can u please send me the working code on 2.0 to my mail ID

  16. Posted by sacs 18th January, 2010 at 11:40 pm

    my Mail id is sachin666@gmail.com

  17. Posted by harry 1st February, 2010 at 11:41 pm

    I got tomestone with the above code in android 2.1.
    Anybody post or email me a working copy ?
    life0fun@gmail.com

    Thanks,

  18. Posted by Adam 1st March, 2010 at 5:31 pm

    This would make a great live wallpaper if someone got it working!!!!!!

Leave a reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word