GATAV 9. Goodby flatland Welcome to 3D!
TOC 1. OpenGL ES the 3D-API 2. The buffer concept - a technical necessity 3. Introducing GLSurfaceView the 3D-View 4. GLSurfaceView.Renderer the interface to 3D-content 5. Hello World 3D 6. Add Motion and Interaction 7. Add freaky Viewing 8. Highly-skilled construction worker 9. Distinguished architect Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 2
OpenGL ES the 3D-API for embedded accelerated 3D graphics low-level 3D-API to process graphics on a dedicated GPU consists of well-defined subsets of desktop OpenGL main differences to OpenGL: no glbegin/glend; everything (coordinates, colors, textures,...) is handled by arrays no quad or polygon primitives; nothing but triangles, triangle strips, triangle fans absence of higher primitives (cube, sphere, cylinder,...); neither GLU nor GLUT assistance a lot of must be... Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 3
OpenGL ES - Versions OpenGL ES 1.X for fixed function hardware OpenGL 1.5 specifications OpenGL ES 2.X: for programmable hardware OpenGL 2.0 specifications ability to create vertex and fragment shaders no glpushmatrix/glpopmatrix,... you have to write everything yourself! warning: not compatible with Open GL ES 1.X! precise specifications: http://www.khronos.org/opengles/ Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 4
OpenGL ES Connection to Java EGL is an interface between Khronos rendering APIs (such as OpenGL ES) and the underlying native platform windowing system import javax.microedition.khronos.egl.eglconfig; OpenGL ES is implemented in C! access to C-library functions via wrapper class GL10 import javax.microedition.khronos.opengles.gl10; an implementation of the GL interface big problem: C extensivly uses pointers to arrays, Java doesn t have such evil properties solution: use new objects named buffers Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 5
The buffer concept - a technical necessity A ByteBuffer is a fixed-capacity buffer that holds byte values ByteBuffers are used to create and transport arrays of values of various datatypes to OpenGL ES ByteBuffers must be placed on a particular part of the heap to hide from the garbage collector FloatBuffer, ShortBuffer, IntBuffer,... are used to wrap and fill the underlying ByteBuffer Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 6
The buffer concept Example FloatBuffer vertexbuffer; v0 y v1 float geometry[] = { x -0.5f, 0.5f, 0.5f, // v0-0.5f, -0.5f, 0.5f, // v2 z 0.5f, 0.5f, 0.5f }; // v1 v2 // Buffers with multi-byte datatypes (e.g., short, int, float) // must have their byte order (big oder little endian) // set to native order v3 ByteBuffer vertexbb = ByteBuffer.allocateDirect(geometry.length*4); vertexbb.order(byteorder.nativeorder()); vertexbuffer = vertexbb.asfloatbuffer(); // creation from the ByteBuffer vertexbuffer.put(geometry); // fill it vertexbuffer.position(0); // rewind it Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 7
Introducing GLSurfaceView the 3D-View an API class that: manages an EGL display enabling OpenGL ES to render into a surface provides the glue code to connect OpenGL ES to the View system provides the glue code to make OpenGL ES work with the Activity life-cycle Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 8
Introducing GLSurfaceView creates and manages a separate dedicated rendering thread to enable smooth animation supports both on-demand and continuous rendering mode accepts and holds a user-provided Renderer object that does the actual rendering is usually subclassed to handle touch events by overriding the appropriate methods be carefull: you may need to communicate with the Renderer object running in the rendering thread! standard Java cross-thread communication call queueevent(runnable) Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 9
GLSurfaceView.Renderer the interface to 3D-content Create your own Renderer class implementing this interfaces methods: public void onsurfacecreated(gl10 gl, EGLConfig config) called whenever the drawing context has to be (re)created public void onsurfacechanged(gl10 gl, int width, int height) called when the surface changes size public void ondrawframe(gl10 gl) called every frame responsible for drawing the whole scene Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 10
Hello World 3D Example public class GLES01 extends Activity { private GLSurfaceView touchableglsurfaceview; @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); touchableglsurfaceview = new TouchableGLSurfaceView(this); setcontentview(touchableglsurfaceview); } @Override protected void onresume() { super.onresume(); touchableglsurfaceview.onresume(); } @Override protected void onpause() { super.onpause(); touchableglsurfaceview.onpause(); } } Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 11
Hello World 3D Example class TouchableGLSurfaceView extends GLSurfaceView { private OurRenderer ourrenderer; public TouchableGLSurfaceView(Context context) { super(context); ourrenderer = new OurRenderer(); setrenderer(ourrenderer); } // the implementation of the renderer interface private class OurRenderer implements GLSurfaceView.Renderer { private FloatBuffer vertexbuffer; public OurRenderer() { float geometry[] = { -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; ByteBuffer vertexbb = ByteBuffer.allocateDirect(geometry.length*4); vertexbb.order(byteorder.nativeorder()); vertexbuffer = vertexbb.asfloatbuffer(); vertexbuffer.put(geometry); vertexbuffer.position(0); } Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 12 v0 v2 y v3 v1 x z
Hello World 3D Example // the implementation of the renderer interface (cont.) // creation of viewport // initialization of some opengl features public void onsurfacecreated(gl10 gl, EGLConfig config) { gl.gldisable(gl10.gl_dither); gl.glhint(gl10.gl_perspective_correction_hint, GL10.GL_FASTEST); } gl.glclearcolor(0, 0, 0, 1); gl.glenable(gl10.gl_cull_face); //gl.glshademodel(gl10.gl_flat); gl.glshademodel(gl10.gl_smooth); gl.glenable(gl10.gl_depth_test); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 13
Hello World 3D Example // the implementation of the renderer interface (cont.) // resize of viewport // set projection matrix public void onsurfacechanged(gl10 gl, int width, int height) { gl.glviewport(0, 0, width, height); } float aspectratio = (float) width / height; gl.glmatrixmode(gl10.gl_projection); gl.glloadidentity(); GLU.gluPerspective(gl, 45.0f, aspectratio, 1.0f, 1000.0f); GLU.gluLookAt(gl,0.0f,0.0f,5.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f); gl.glmatrixmode(gl10.gl_modelview); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 14
Hello World 3D Example // the implementation of the renderer interface (cont.) public void ondrawframe(gl10 gl) { // the first thing to do: clear screen and depth buffer gl.glclear(gl10.gl_color_buffer_bit GL10.GL_DEPTH_BUFFER_BIT); // reset modelview matrix gl.glmatrixmode(gl10.gl_modelview); gl.glloadidentity(); } }} gl.glcolor4f(1.0f, 0.0f, 0.0f, 0.0f); gl.glenableclientstate(gl10.gl_vertex_array); gl.glvertexpointer(3, GL10.GL_FLOAT, 0, vertexbuffer); gl.gldrawarrays(gl10.gl_triangles, 0, 3); gl.gldisableclientstate(gl10.gl_vertex_array); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 15
Hello World 3D the result amazing? Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 16
Add Motion and Interaction Motion private long milsecperrotation=5*1000; private double angle=0.0f; private long lasttime;... // create an automatic rotation long time = System.currentTimeMillis(); long deltatime = time - lasttime; lasttime = time; angle = (float) (angle + 360.0 / milsecperrotation * deltatime); gl.glrotatef((float) angle, 0.0f, 1.0f, 0.0f); gl.glcolor4f(1.0f, 0.0f, 0.0f, 0.0f);... Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 17
Add Motion and Interaction Interaction Random ran = new Random();... @Override public boolean ontouchevent(motionevent event) { switch (event.getaction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: ourrenderer.r=ran.nextfloat(); ourrenderer.g=ran.nextfloat(); ourrenderer.b=ran.nextfloat(); break; } return true; }... Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 18
Add freaky Viewing adults only Introduce: virtual trackball viewing concept (pretty cool but freaking massive mathematics quaternions ) in combination with sophisticated touch handling and options menu to drastically uprade your viewing experience (roll, zoom, pan)! Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 19
Highly-skilled construction worker building higher primitives gldrawarrays (int mode, int first, int count) reads vertex data from the enabled arrays by marching straight through the array without skipping or hopping because gldrawarrays() does not allows hopping around the arrays, you still have to repeat the shared information once per face gldrawelements (int mode, int count, int type, Buffer indices) draws a sequence of primitives by hopping around arrays with the associated array indices reduces both the number of function calls and the number of information to transfer makes reuse of information by OpenGL caching possible Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 20
Highly-skilled construction worker - front FloatBuffer frontvertexbuffer; v4 v5 // front side, two triangles, without // individual color // drawarrays v0 y v1 float geometryfront[] = { -0.5f, 0.5f, 0.5f, // v0 v6 x -0.5f, -0.5f, 0.5f, // v2 0.5f, 0.5f, 0.5f, // v1 z v7 0.5f, 0.5f, 0.5f, // v1-0.5f, -0.5f, 0.5f, // v2 v2 0.5f, -0.5f, 0.5f };// v3 v3 ByteBuffer frontvertexbb = ByteBuffer.allocateDirect(geometryFront.length*4); frontvertexbb.order(byteorder.nativeorder()); frontvertexbuffer = frontvertexbb.asfloatbuffer(); frontvertexbuffer.put(geometryfront); frontvertexbuffer.position(0); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 21
Highly-skilled construction worker - front v4 v5 v0 y v1 v6 x z v7 v2 // draw front side gl.glcolor4f(1.0f, 0.0f, 0.0f, 0.0f); gl.glenableclientstate(gl10.gl_vertex_array); gl.glvertexpointer(3, GL10.GL_FLOAT, 0, frontvertexbuffer); gl.gldrawarrays(gl10.gl_triangles, 0, 6); gl.gldisableclientstate(gl10.gl_vertex_array); v3 Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 22
Highly-skilled construction worker - right FloatBuffer rightvertexbuffer; v4 v5 // right side, two triangles, with // individual vertex color // drawarrays v0 y v1 float geometryright[] = { 0.5f, 0.5f, 0.5f, // v1 v6 x 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, -0.5f, // v3 // v5 z v7 0.5f, -0.5f, 0.5f, // v3 0.5f, -0.5f, -0.5f, // v7 v2 0.5f, 0.5f, -0.5f }; // v5 v3 ByteBuffer rightvertexbb = ByteBuffer.allocateDirect(geometryRight.length*4); rightvertexbb.order(byteorder.nativeorder()); rightvertexbuffer = rightvertexbb.asfloatbuffer(); rightvertexbuffer.put(geometryright); rightvertexbuffer.position(0); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 23
Highly-skilled construction worker - right FloatBuffer rightcolorbuffer; v4 v5 float colorright[] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // v1 // v3 v0 y v1 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // v5 // v3 v6 x 1.0f, 1.0f, 1.0f, 0.0f, // v7 0.0f, 0.0f, 1.0f, 0.0f }; // v5 z v7 v2 ByteBuffer rightcolorbb = ByteBuffer.allocateDirect(colorRight.length * 4); rightcolorbb.order(byteorder.nativeorder()); rightcolorbuffer = rightcolorbb.asfloatbuffer(); rightcolorbuffer.put(colorright); rightcolorbuffer.position(0); v3 Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 24
Highly-skilled construction worker - right v4 v5 v0 y v1 v6 x z v7 // draw right side gl.glenableclientstate(gl10.gl_vertex_array); gl.glenableclientstate(gl10.gl_color_array); gl.glvertexpointer(3, GL10.GL_FLOAT, 0, rightvertexbuffer); gl.glcolorpointer(4, GL10.GL_FLOAT, 0, rightcolorbuffer); gl.gldrawarrays(gl10.gl_triangles, 0, 6); gl.gldisableclientstate(gl10.gl_color_array); gl.gldisableclientstate(gl10.gl_vertex_array); v2 v3 Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 25
Highly-skilled construction worker - top // top side, two triangles, with individual // vertex color v4 v5 // drawelements using topology float geometrytop[] = { -0.5f, 0.5f, -0.5f, // v4 v0 y v1 0.5f, 0.5f, -0.5f, // v5-0.5f, 0.5f, 0.5f, // v0 v6 x 0.5f, 0.5f, 0.5f }; // v1 z v7 float colortop[] = { 0.0f, 0.0f, 1.0f, 0.0f, // v4 1.0f, 1.0f, 1.0f, 0.0f, // v5 1.0f, 0.0f, 0.0f, 0.0f, // v0 0.0f, 1.0f, 0.0f, 0.0f};// v1 v2 v3 short topologytop[] = { 2, 3, 0, // v0, v1, v4 3, 1, 0};// v1, v5, v4 Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 26
Highly-skilled construction worker - top ByteBuffer topvertexbb = ByteBuffer.allocateDirect(geometryTop.length*4); topvertexbb.order(byteorder.nativeorder()); topvertexbuffer = topvertexbb.asfloatbuffer(); topvertexbuffer.put(geometrytop); topvertexbuffer.position(0); ByteBuffer topcolorbb = ByteBuffer.allocateDirect(colorTop.length * 4); topcolorbb.order(byteorder.nativeorder()); topcolorbuffer = topcolorbb.asfloatbuffer(); topcolorbuffer.put(colortop); topcolorbuffer.position(0); ByteBuffer toptopologybb = ByteBuffer.allocateDirect(topologyTop.length*2); toptopologybb.order(byteorder.nativeorder()); toptopologybuffer = toptopologybb.asshortbuffer(); toptopologybuffer.put(topologytop); toptopologybuffer.position(0); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 27 v0 v2 v4 v6 z y v1 v3 x v5 v7
Highly-skilled construction worker - top v4 v5 v0 y v1 v6 x z v7 // draw top side gl.glenableclientstate(gl10.gl_vertex_array); gl.glenableclientstate(gl10.gl_color_array); gl.glvertexpointer(3, GL10.GL_FLOAT, 0, topvertexbuffer); gl.glcolorpointer(4, GL10.GL_FLOAT, 0, topcolorbuffer); gl.gldrawelements(gl10.gl_triangles, toptopologybuffer.limit(), GL10.GL_UNSIGNED_SHORT, toptopologybuffer); gl.gldisableclientstate(gl10.gl_color_array); gl.gldisableclientstate(gl10.gl_vertex_array); Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 28 v2 v3
Highly-skilled construction worker - result v4 v5 v0 y v1 v6 x z v7 v2 v3 Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 29
Distinguished architect modular design principle Use higher primitives and matrix arithmetic for modelling! Cube(float size) Cylinder(float baseradius, float topradius, float height, int stacks, int slices, boolean basecap, boolean topcap) Disk(float innerradius, float outerradius, int stacks) Sphere(float newradius, int slices, int stacks) Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 30
Distinguished architect - ingredients Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 31
Lesson learned: The fun isn t over yet! The suprises of the ANDROID API get even bigger with 3D! THANK YOU FOR YOUR ATTENTION! Graphical Apps - The Android View: Prof. Dr. Bender, Prof. Dr. Tronnier 32