Monday, June 18, 2012

How To Create 3D Graphics In Android



This is a sample application which shows how to create 3D graphics using OpenGL in android.
Underlying Algorithm:
Basic description of algorithm in step by step form:
1.) Create a Project Graphics3d.
2.) Put an image in res/drawable.
3.) Create a custom view MyGLView.java ,which will look like this:
package com.app.Graphics3d;
import android.content.Context;
import android.opengl.GLSurfaceView;
class MyGLView extends GLSurfaceView {
        private final MyGLRenderer renderer;
        MyGLView(Context context) {
                super(context);
                renderer = new MyGLRenderer(context);
                setRenderer(renderer);
        }
}
4.) In OpenGL ES on Android, drawing is separated out into a rendering class which is responsible for initializing and drawing the entire screen.
5.) Create MyGLRenderer.java ,which will look like this:
package com.app.Graphics3d;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;
class MyGLRenderer implements GLSurfaceView.Renderer {
        private static final String TAG = "GLRenderer";
        private final Context context;
        private final MyCube cube = new MyCube();
        private long startTime;
        private long fpsStartTime;
        private long numFrames;
        MyGLRenderer(Context context) {
                this.context = context;
        }
        public void onSurfaceCreated(GL10 gl, EGLConfig config)
        {
                boolean SEE_THRU = true;
                startTime = System.currentTimeMillis();
                fpsStartTime = startTime;
                numFrames = 0;
                // Define the lighting
                float lightAmbient[] = new float[] { 0.2f, 0.2f, 0.2f, 1 };
                float lightDiffuse[] = new float[] { 1, 1, 1, 1 };
                float[] lightPos = new float[] { 1, 1, 1, 1 };
                gl.glEnable(GL10.GL_LIGHTING);
                gl.glEnable(GL10.GL_LIGHT0);
                gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0);
                gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0);
                gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);
                // What is the cube made of?
                float matAmbient[] = new float[] { 1, 1, 1, 1 };
                float matDiffuse[] = new float[] { 1, 1, 1, 1 };
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT,
                                matAmbient, 0);
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE,
                                matDiffuse, 0);
                // Set up any OpenGL options we need
                gl.glEnable(GL10.GL_DEPTH_TEST);
                gl.glDepthFunc(GL10.GL_LEQUAL);
                gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
                if (SEE_THRU) {
                        gl.glDisable(GL10.GL_DEPTH_TEST);
                        gl.glEnable(GL10.GL_BLEND);
                        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
                }
                // Enable textures
                gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
                gl.glEnable(GL10.GL_TEXTURE_2D);
                // Load the cube’s texture from a bitmap
                MyCube.loadTexture(gl, context, R.drawable.one);
        }
        public void onSurfaceChanged(GL10 gl, int width, int height)
        {
                // Define the view frustum
                gl.glViewport(0, 0, width, height);
                gl.glMatrixMode(GL10.GL_PROJECTION);
                gl.glLoadIdentity();
                float ratio = (float) width / height;
                GLU.gluPerspective(gl, 45.0f, ratio, 1, 100f);
        }
        public void onDrawFrame(GL10 gl) {
                // Clear the screen to black
                gl.glClear(GL10.GL_COLOR_BUFFER_BIT
                                | GL10.GL_DEPTH_BUFFER_BIT);
                // Position model so we can see it
                gl.glMatrixMode(GL10.GL_MODELVIEW);
                gl.glLoadIdentity();
                gl.glTranslatef(0, 0, -3.0f);
                // Set rotation angle based on the time
                long elapsed = System.currentTimeMillis() - startTime;
                gl.glRotatef(elapsed * (30f / 1000f), 0, 1, 0);
                gl.glRotatef(elapsed * (15f / 1000f), 1, 0, 0);
                // Draw the model
                cube.draw(gl);
                // Keep track of number of frames drawn
                numFrames++;
                long fpsElapsed = System.currentTimeMillis() - fpsStartTime;
                if (fpsElapsed > 5 * 1000) { // every 5 seconds
                        float fps = (numFrames * 1000.0F) / fpsElapsed;
                        Log.d(TAG, "Frames per second: " + fps + " (" + numFrames
                                        + " frames in " + fpsElapsed + " ms)");
                        fpsStartTime = System.currentTimeMillis();
                        numFrames = 0;
                }
        }
}
6.) Create MyCube.java, which will look like this:
package com.app.Graphics3d;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
class MyCube {
    private final IntBuffer mVertexBuffer;
    private final IntBuffer mTextureBuffer;
    public MyCube() {
                int one = 65536;
                int half = one / 2;
                int vertices[] = {
                                // FRONT
                                -half, -half, half, half, -half, half,
                                -half, half, half, half, half, half,
                                // BACK
                                -half, -half, -half, -half, half, -half,
                                half, -half, -half, half, half, -half,
                                // LEFT
                                -half, -half, half, -half, half, half,
                                -half, -half, -half, -half, half, -half,
                                // RIGHT
                                half, -half, -half, half, half, -half,
                                half, -half, half, half, half, half,
                                // TOP
                                -half, half, half, half, half, half,
                                -half, half, -half, half, half, -half,
                                // BOTTOM
                                -half, -half, half, -half, -half, -half,
                                half, -half, half, half, -half, -half, };
                int texCoords[] = {
                                // FRONT
                                0, one, one, one, 00, one, 0,
                                // BACK
                                one, one, one, 00, one, 00,
                                // LEFT
                                one, one, one, 00, one, 00,
                                // RIGHT
                                one, one, one, 00, one, 00,
                                // TOP
                                one, 000, one, one, 0, one,
                                // BOTTOM
                                0, 0, 0, one, one, 0, one, one, };
     
                ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
                vbb.order(ByteOrder.nativeOrder());
                mVertexBuffer = vbb.asIntBuffer();
                mVertexBuffer.put(vertices);
                mVertexBuffer.position(0);
                // …
                ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
                tbb.order(ByteOrder.nativeOrder());
                mTextureBuffer = tbb.asIntBuffer();
                mTextureBuffer.put(texCoords);
                mTextureBuffer.position(0);
        }
        public void draw(GL10 gl) {
                gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);
                gl.glEnable(GL10.GL_TEXTURE_2D); // workaround bug 3623
                gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, mTextureBuffer);
                gl.glColor4f(1, 1, 1, 1);
                gl.glNormal3f(0, 0, 1);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
                gl.glNormal3f(0, 0, -1);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
                gl.glColor4f(1, 1, 1, 1);
                gl.glNormal3f(-1, 0, 0);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
                gl.glNormal3f(1, 0, 0);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
                gl.glColor4f(1, 1, 1, 1);
                gl.glNormal3f(0, 1, 0);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
                gl.glNormal3f(0, -1, 0);
                gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
        }
        static void loadTexture(GL10 gl, Context context, int resource) {
                Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resource);
                GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
                gl.glTexParameterx(GL10.GL_TEXTURE_2D,
                                GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
                gl.glTexParameterx(GL10.GL_TEXTURE_2D,
                                GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
                bmp.recycle();
        }
}
7.) Run the Application.
Steps to Create:
1.) Open Eclipse. Use the New Project Wizard and select Android Project Give the respective project name i.e. Graphics3d. Enter following information:
Project name: Graphics3d
Build Target: Google APIs
Application name: Graphics3d
Package name: app. Com.app.Graphics3d
Create Activity: Graphics3d
On Clicking Finish Graphics3d code structure is generated with the necessary Android Packages being imported along with Graphics3d.java. Graphics3d class will look like following:
package com.app.Graphics3d;
import android.app.Activity;
import android.os.Bundle;
public class Graphics3d extends Activity {
        MyGLView view;
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                view = new MyGLView(this);
                setContentView(view);
        }
        @Override
        protected void onPause() {
                super.onPause();
                view.onPause();
        }
        @Override
        protected void onResume() {
                super.onResume();
                view.onResume();
        }
}
Output –The final output:

No comments:

Post a Comment