Android: 3D tunnel demo with OpenGL ES
18 comments so farAs 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
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)
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.
Download 3D tunnel demo source code (618 Kb)
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!
Quit cool… i guess, but i can not compile
i have Eclipse Classic 3.4.2
(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
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
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();
}
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?
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.
somebody get it working under SDK 1.5 ???
pls email me under: thediskjoker@gmx.net
10x a lot
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;
}
}
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
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
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
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
Hi Kay,
Can u plz upload the new project with the modifications..so that it vil b vry helpful for the beginners…
CHEERSSS
Reni
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
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…
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
my Mail id is sachin666@gmail.com
I got tomestone with the above code in android 2.1.
Anybody post or email me a working copy ?
life0fun@gmail.com
Thanks,
This would make a great live wallpaper if someone got it working!!!!!!