What is this: This tutorial shows how to create colored 3D Objects using the OpenGL® ES cross-platform API.
What you learn: You will learn how easy it is, to create a Colored 3D Pyramid, using OpenGL® ES.
Read before: Colored 3D Cube
Difficulty: 1.5 of 5

What it will look like:

Introduction:
Lets quote wikipedia first:
OpenGL ES (OpenGL for Embedded Systems) is a subset of the OpenGL 3D graphics API designed for embedded devices such as mobile phones, PDAs, and video game consoles. It is defined and promoted by the Khronos Group, a graphics hardware and software industry consortium interested in open APIs for graphics and multimedia.
Description:
What we will do is, create a custom view and using OpenGL ES in it to draw a colored pyramid.
The Main steps are:
- 1. Setup the view and create a 3DObject (A rectangle based Pyramid with four sides)
(1.1. Start/Stop the animation if we are (not) viewing it)
2. Do some trigonometry (rotation)
3. Make the Pyramid paint itself
Most interesting:
The main difference compared to the Colored 3D Cube is that we created an abstract ThreeDObject.
Cube and the new Class Pyramid extend this Object. So we can easily replace the Cube with a Pyramid!
Using java Syntax Highlighting
- abstract class ThreeDObject{
- public abstract void draw(GL10 gl);
- }
- ...
- private ThreeDObject mThreeDObj;
- ...
- ...
- mThreeDObj = new Pyramid();
- ...
Parsed in 0.031 seconds, using GeSHi 1.0.8.4
As in the Colored 3D Cube before, we have to set up some vertices of the pyramid.
As we are creating a rectangle based one, we will need 4+1 vertices.
Using java Syntax Highlighting
- int one = 0x10000;
- /* Every vertex got 3 values, for
- * x / y / z position in the kartesian space.
- */
- int vertices[] = { -one, -one, -one, // The four floor vertices of the pyramid
- one, -one, -one,
- one, one, -one,
- -one, one, -one,
- 0, 0, one, }; // The top of the pyramid
Parsed in 0.031 seconds, using GeSHi 1.0.8.4
Remember the Cube

Using java Syntax Highlighting
- /* Every vertex has got its own color, described by 4 values
- * R(ed)
- * G(green)
- * B(blue)
- * A(lpha) <-- Opticacy
- */
- int colors[] = { 0, 0, one, one,
- one, 0, 0, one,
- one, one, 0, one,
- one, 0, one, one, };
Parsed in 0.034 seconds, using GeSHi 1.0.8.4
In this code-block the color of all the 8 vertices are described, as '4' each: R(ed) G(reen) B(lue) A(lpha). (Alpha means Opticacy)
OpenGL SE will create the color-flows automatically!
Using java Syntax Highlighting
- /* The last thing is that we need to describe some Triangles.
- * A triangle got 3 vertices.
- * The confusing thing is, that it is important in which order
- * the vertices of each triangle are described.
- * So describing a triangle through the vertices: "0, 3, 4"
- * will not result in the same triangle as: "0, 4, 3"
- * You probably ask: Why the hell isn't that the same ???
- * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
- * which means, that we have to describe the "visible" side of the
- * triangles by naming its vertices in a ClockWise order!
- * From the other side, the triangle will be 100% lookthru!
- * You can create a kind of magic mirror with that <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />.
- */
- byte indices[] = { 0, 4, 1, // The four side-triangles
- 1, 4, 2,
- 2, 4, 3,
- 3, 4, 0,
- 1, 2, 0, // The two bottom-triangles
- 0, 2, 3};
Parsed in 0.038 seconds, using GeSHi 1.0.8.4
This is the tricky part. I think that I described it good enough in them comment.
Take a look at this "clockwise"-visualization-example with the cube we did before:

The Code
Based on the following Source:
code.google.com
Modified by: Nicolas 'plusminus' Gramlich
Using java Syntax Highlighting
- package org.anddev.android.threedcolorobjects;
- import java.nio.ByteBuffer;
- import java.nio.ByteOrder;
- import java.nio.IntBuffer;
- import javax.microedition.khronos.opengles.GL10;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.OpenGLContext;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.os.SystemClock;
- import android.view.View;
- /**
- * Example of how to use OpenGL|ES in a custom view
- *
- */
- public class ThreeDColorObjects extends Activity {
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(new GLView(getApplication()));
- }
- @Override
- protected void onResume() {
- super.onResume();
- //android.os.Debug.startMethodTracing("/tmp/trace/GLView1.dmtrace",
- // 8 * 1024 * 1024);
- }
- @Override
- protected void onStop() {
- super.onStop();
- //android.os.Debug.stopMethodTracing();
- }
- }
- class GLView extends View {
- private OpenGLContext mGLContext;
- private ThreeDObject mThreeDObj;
- private float mAngle;
- private long mNextTime;
- private boolean mAnimate;
- /**
- * The View constructor is a good place to allocate our OpenGL context
- */
- public GLView(Context context) {
- super(context);
- /*
- * Create an OpenGL|ES context. This must be done only once, an
- * OpenGL contex is a somewhat heavy object.
- */
- mGLContext = new OpenGLContext(0);
- mThreeDObj = new Pyramid();
- mAnimate = false;
- }
- /*
- * Start the animation only once we're attached to a window
- * @see android.view.View#onAttachedToWindow()
- */
- @Override
- protected void onAttachedToWindow() {
- mAnimate = true;
- Message msg = mHandler.obtainMessage(INVALIDATE);
- mNextTime = SystemClock.uptimeMillis();
- mHandler.sendMessageAtTime(msg, mNextTime);
- super.onAttachedToWindow();
- }
- /*
- * Make sure to stop the animation when we're no longer on screen,
- * failing to do so will cause most of the view hierarchy to be
- * leaked until the current process dies.
- * @see android.view.View#onDetachedFromWindow()
- */
- @Override
- protected void onDetachedFromWindow() {
- mAnimate = false;
- super.onDetachedFromWindow();
- }
- /**
- * Draw the view content
- *
- * @see android.view.View#onDraw(android.graphics.Canvas)
- */
- @Override
- protected void onDraw(Canvas canvas) {
- if (true) {
- /*
- * First, we need to get to the appropriate GL interface.
- * This is simply done by casting the GL context to either
- * GL10 or GL11.
- */
- GL10 gl = (GL10) (mGLContext.getGL());
- /*
- * Before we can issue GL commands, we need to make sure all
- * native drawing commands are completed. Simply call
- * waitNative() to accomplish this. Once this is done, no native
- * calls should be issued.
- */
- mGLContext.waitNative(canvas, this);
- int w = getWidth();
- int h = getHeight();
- /*
- * Set the viewport. This doesn't have to be done each time
- * draw() is called. Typically this is called when the view
- * is resized.
- */
- gl.glViewport(0, 0, w, h);
- /*
- * Set our projection matrix. This doesn't have to be done
- * each time we draw, but usualy a new projection needs to be set
- * when the viewport is resized.
- */
- float ratio = (float) w / h;
- gl.glMatrixMode(gl.GL_PROJECTION);
- gl.glLoadIdentity();
- gl.glFrustumf(-ratio, ratio, -1, 1, 2, 12);
- /*
- * dithering is enabled by default in OpenGL, unfortunattely
- * it has a significant impact on performace in software
- * implementation. Often, it's better to just turn it off.
- */
- gl.glDisable(gl.GL_DITHER);
- /*
- * Usually, the first thing one might want to do is to clear
- * the screen. The most efficient way of doing this is to use
- * glClear(). However we must make sure to set the scissor
- * correctly first. The scissor is always specified in window
- * coordinates:
- */
- gl.glClearColor(1, 1, 1, 1);
- gl.glEnable(gl.GL_SCISSOR_TEST);
- gl.glScissor(0, 0, w, h);
- gl.glClear(gl.GL_COLOR_BUFFER_BIT);
- /*
- * Now we're ready to draw some 3D object
- */
- gl.glMatrixMode(gl.GL_MODELVIEW);
- gl.glLoadIdentity();
- gl.glTranslatef(0, 0, -3.0f);
- gl.glScalef(0.5f, 0.5f, 0.5f);
- gl.glRotatef(mAngle, 0, 1, 0);
- gl.glRotatef(mAngle * 0.25f, 1, 0, 0);
- gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
- gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
- gl.glEnableClientState(gl.GL_COLOR_ARRAY);
- gl.glEnable(gl.GL_CULL_FACE);
- mThreeDObj.draw(gl);
- mAngle += 1.2f;
- /*
- * Once we're done with GL, we need to flush all GL commands and
- * make sure they complete before we can issue more native
- * drawing commands. This is done by calling waitGL().
- */
- mGLContext.waitGL();
- }
- }
- // ------------------------------------------------------------------------
- private static final int INVALIDATE = 1;
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (mAnimate && msg.what == INVALIDATE) {
- invalidate();
- msg = obtainMessage(INVALIDATE);
- long current = SystemClock.uptimeMillis();
- if (mNextTime < current) {
- mNextTime = current + 20;
- }
- sendMessageAtTime(msg, mNextTime);
- mNextTime += 20;
- }
- }
- };
- }
- abstract class ThreeDObject{
- public abstract void draw(GL10 gl);
- }
- class Cube extends ThreeDObject{
- private IntBuffer mVertexBuffer;
- private IntBuffer mColorBuffer;
- private ByteBuffer mIndexBuffer;
- public Cube() {
- int one = 0x10000;
- /* Every vertex got 3 values, for
- * x / y / z position in the kartesian space.
- */
- int vertices[] = { -one, -one, -one,
- one, -one, -one,
- one, one, -one,
- -one, one, -one,
- -one, -one, one,
- one, -one, one,
- one, one, one,
- -one, one, one, };
- /* Every vertex has got its own color, described by 4 values
- * R(ed)
- * G(green)
- * B(blue)
- * A(lpha) <-- Opticacy
- */
- int colors[] = { 0, 0, 0, one,
- one, 0, 0, one,
- one, one, 0, one,
- 0, one, 0, one,
- 0, 0, one, one,
- one, 0, one, one,
- one, one, one, one,
- 0, one, one, one, };
- /* The last thing is that we need to describe some Triangles.
- * A triangle got 3 vertices.
- * The confusing thing is, that it is important in which order
- * the vertices of each triangle are described.
- * So describing a triangle through the vertices: "0, 3, 4"
- * will not result in the same triangle as: "0, 4, 3"
- * You probably ask: Why the hell isn't that the same ???
- * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
- * which means, that we have to describe the "visible" side of the
- * triangles by naming its vertices in a ClockWise order!
- * From the other side, the triangle will be 100% lookthru!
- * You can create a kind of magic mirror with that <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />.
- */
- byte indices[] = { 0, 4, 5,
- 0, 5, 1,
- 1, 5, 6,
- 1, 6, 2,
- 2, 6, 7,
- 2, 7, 3,
- 3, 7, 4,
- 3, 4, 0,
- 4, 7, 6,
- 4, 6, 5,
- 3, 0, 1,
- 3, 1, 2 };
- // Buffers to be passed to gl*Pointer() functions
- // must be direct, i.e., they must be placed on the
- // native heap where the garbage collector cannot
- // move them.
- //
- // Buffers with multi-byte datatypes (e.g., short, int, float)
- // must have their byte order set to native order
- ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); // * 4 becuase of int
- vbb.order(ByteOrder.nativeOrder());
- mVertexBuffer = vbb.asIntBuffer();
- mVertexBuffer.put(vertices);
- mVertexBuffer.position(0);
- ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); // * 4 becuase of int
- cbb.order(ByteOrder.nativeOrder());
- mColorBuffer = cbb.asIntBuffer();
- mColorBuffer.put(colors);
- mColorBuffer.position(0);
- mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
- mIndexBuffer.put(indices);
- mIndexBuffer.position(0);
- }
- public void draw(GL10 gl) {
- gl.glFrontFace(gl.GL_CW);
- gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
- gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
- gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
- }
- }
- class Pyramid extends ThreeDObject{
- private IntBuffer mVertexBuffer;
- private IntBuffer mColorBuffer;
- private ByteBuffer mIndexBuffer;
- public Pyramid() {
- int one = 0x10000;
- /* Every vertex got 3 values, for
- * x / y / z position in the kartesian space.
- */
- int vertices[] = { -one, -one, -one, // The four floor vertices of the pyramid
- one, -one, -one,
- one, one, -one,
- -one, one, -one,
- 0, 0, one, }; // The top of the pyramid
- /* Every vertex has got its own color, described by 4 values
- * R(ed)
- * G(green)
- * B(blue)
- * A(lpha) <-- Opticacy
- */
- int colors[] = { 0, 0, one, one,
- one, 0, 0, one,
- one, one, 0, one,
- 0, one, 0, one,
- one, 0, one, one, };
- /* The last thing is that we need to describe some Triangles.
- * A triangle got 3 vertices.
- * The confusing thing is, that it is important in which order
- * the vertices of each triangle are described.
- * So describing a triangle through the vertices: "0, 3, 4"
- * will not result in the same triangle as: "0, 4, 3"
- * You probably ask: Why the hell isn't that the same ???
- * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
- * which means, that we have to describe the "visible" side of the
- * triangles by naming its vertices in a ClockWise order!
- * From the other side, the triangle will be 100% lookthru!
- * You can create a kind of magic mirror with that <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />.
- */
- byte indices[] = { 0, 4, 1, // The four side-triangles
- 1, 4, 2,
- 2, 4, 3,
- 3, 4, 0,
- 1, 2, 0, // The two bottom-triangles
- 0, 2, 3};
- // Buffers to be passed to gl*Pointer() functions
- // must be direct, i.e., they must be placed on the
- // native heap where the garbage collector cannot
- // move them.
- //
- // Buffers with multi-byte datatypes (e.g., short, int, float)
- // must have their byte order set to native order
- ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); // * 4 becuase of int
- vbb.order(ByteOrder.nativeOrder());
- mVertexBuffer = vbb.asIntBuffer();
- mVertexBuffer.put(vertices);
- mVertexBuffer.position(0);
- ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); // * 4 becuase of int
- cbb.order(ByteOrder.nativeOrder());
- mColorBuffer = cbb.asIntBuffer();
- mColorBuffer.put(colors);
- mColorBuffer.position(0);
- mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
- mIndexBuffer.put(indices);
- mIndexBuffer.position(0);
- }
- public void draw(GL10 gl) {
- gl.glFrontFace(gl.GL_CW);
- gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
- gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
- gl.glDrawElements(gl.GL_TRIANGLES, 18, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
- }
- }
Parsed in 0.070 seconds, using GeSHi 1.0.8.4
I hope you succeeded and understood this tutorial.
Please vote and/or leave a comment
.See you soon







) I wrote my own parser to read in the file and all vertices are represented in float. It looks ugly as I didn't put in correct normal and color yet. But it gives some idea of how an object model can be loaded in Android. 
