For my current project, CPU Information I wanted to create a 3D representation for a Battery to indicate the remaining charge of it to the user in a visually appealing way.
Initially I used a 3D battery model but after playing around with it some time, I decided to build the Battery model in code instead. All that was required for it was to find a algo I could easily adjust for my program.
After searching for a few hours ( yes hours ) I came to realize that there was no good example for OpenGL ES 2.0 and I had to write my own.
It seems that there are plenty of examples for OpenGL 1.x or examples in many other different shapes and forms but none that I could find which simply creates a GL_TRAINGLE_STRIP – buffer and passing it to OpenGL ES 2.x.
Algolite
The algorithm will create a cylinder in one buffer by first creating the top circle, then the cylinder and finally the bottom circle. The OpenGL Drawing mode is GL_TRIANGLE_STRIP.
You only have to provide radius, height, and number of segments to create the cylinder. Once the floating point buffer with the vertices is created we have to convert it to OpenGL digestible FloatBuffer and the pass the information to OpenGL for rendering … Done.
Decomplexify
The passing of the data to OpenGL is cookie-cutter OpenGL code which you can find easily. I do not want to complexify this sample here by cookie cutting.
// Creating a cylinder object to be rendered in OpenGL Object3DData createCylinder ( float radius, float height, int segments, float yOffset, float clr[] ) { float buffer[] = createCylinderBuffer ( radius, height, segments ); FloatBuffer vertices = makeFloatBuffer ( buffer, buffer.length ); Object3DData obj = new Object3DData( vertices ); obj.setDrawMode ( GLES20.GL_TRIANGLE_STRIP ); obj.setColor ( clr[0], clr[1], clr[2], clr[3] ); obj.setPosition ( 0.0f, yOffset, 0.0f ); return obj; } // GL_TRIANGLE_STRIP -=> Standing cylinder float[] createCylinderBuffer ( float radius, float height, int segments ) { int iBuffSize = segments * 3 * 3 + (int)( ((float)segments/3.0f+1.0f )) * 3 * 2 + 6; float buffer[] = new float[ iBuffSize ]; int t, idx = 0; float increment = (float)( 360.0f / (float)( segments - 1 ) ); //create the top int iZeroCounter = 2; float hh = height / 2.0f; for ( t=0; t<segments; t++ ) { float angle = (float)( Math.PI/180.0f * t * increment ); float cos = (float) ( radius * Math.cos ( angle ) ); float sin = (float) ( radius * Math.sin ( angle ) ); if ( iZeroCounter++ >= 2 ) { buffer[idx++] = 0.0f; buffer[idx++] = +hh; buffer[idx++] = 0.0f; iZeroCounter = 0; } buffer[idx++] = cos; buffer[idx++] = +hh; buffer[idx++] = sin; } // create the cylinder for ( t=0; t<segments+2; t++ ) { float angle = (float)( Math.PI/180.0f * t * increment ); float cos = (float) ( radius * Math.cos ( angle ) ); float sin = (float)-( radius * Math.sin ( angle ) ); buffer[idx++] = cos; buffer[idx++] = hh; buffer[idx++] = sin; hh *= -1.0f; } hh = height / 2.0f; for ( t=0; t<segments; t++ ) { float angle = (float)( Math.PI/180.0f * t * increment ); float cos = (float)-( radius * Math.cos ( angle ) ); float sin = (float) ( radius * Math.sin ( angle ) ); if ( iZeroCounter++ >= 2 ) { buffer[idx++] = 0.0f; buffer[idx++] = -hh; buffer[idx++] = 0.0f; iZeroCounter = 0; } buffer[idx++] = cos; buffer[idx++] = -hh; buffer[idx++] = sin; } return buffer; } public static FloatBuffer makeFloatBuffer ( float[] arr, int iSize ) { if ( iSize == 0 ) iSize = arr.length; ByteBuffer bb = ByteBuffer.allocateDirect ( iSize * 4 ); // Size of Float is 4 bytes bb.order ( ByteOrder.nativeOrder( ) ); FloatBuffer fb = bb.asFloatBuffer ( ); fb.put ( arr ); fb.position ( 0 ); return fb; }
Promising results
Here is the result in all its glory after stacking a few cylinders on top of each other, coloring them and give the battery a heart beat. Yeah, I think you can’t enough Special effect this one.
Please feel free to install CPU Information onto your Android device and try it out in action.