To add more depth to our games, we have to get ready to go 3D. 3D is not complicated at all and rendering 3D graphics is quite easy using OpenGL ES in Android.
In a 3D game, as in the real world, everything happens in space. What we would see is defined by the field of view and the players that we “catch” with our eye. We would look at a 3D scene.
Everything you see in the 3D scene makes up the perspective. Perspective projection scales the final image of the objects according to their distance from the observation point. The farther an object is, the smaller it appears, just like in real life.
This is much like a camera. Let’s see how to implement this. We will use triangles in space.
Let’s create an activity with an OpenGL renderer.
package com.example.dprogramming; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.opengl.EGLConfig; import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU; import android.os.Bundle; import android.util.Log; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity { private GLSurfaceView glView; private Triangle triangle1; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); glView = new GLSurfaceView(this); glView.setRenderer(new MyOpenGLRenderer()); setContentView(glView); } class MyOpenGLRenderer implements Renderer { @Override public void onSurfaceChanged(GL10 gl, int width, int height) { triangle1 = new Triangle(0.5f, 1, 1, 0); gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onDrawFrame(GL10 gl) { gl.glClearColor(0.1f, 0.0f, 0.0f, 1f); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -5.0f); triangle1.draw(gl); } @Override public void onSurfaceCreated(GL10 arg0, javax.microedition.khronos.egl.EGLConfig arg1) { // TODO Auto-generated method stub } } }
The MainActivity will display a triangle with the same size at different positions. The activity’s onCreate method is straightforward but let’s have a recap line by line:
– Call the cunstructor of the super class to handle state.
– Get rid of the window title.
– Makes the window go full-screen.
– Instantiates the GLSurfaceView to access the OpenGL ES API. It is declared as a private member because we need to use it later on.
– Creates a new instance of our own OpenGL renderer (defined as an inner class), and sets it to be the renderer of the newly created view.
– Sets the newly created view to be the view of the activity.
Moving on to the renderer, we created an inner class MyOpenGLRenderer which implements the Renderer interface. It has 3 methods and these methods are triggered by events from the activity:
onSurfaceCreated is called every time the drawing surface is created. This can happen when the application starts, or when it becomes active after being sent to the background or when the orientation changes. Note that all these events are triggered after a context loss, so every asset (think loaded images) will be lost and have to be recreated. This is the place where all assets and application objects should be (re)created.
onSurfaceChangedoccurs when the screen size changes. This can happen when the device’s orientation changes.
onDrawFrame is where the actual drawing happens. It is triggered continuously after every successful draw.
All life-cycle events get passed a GL10 instance through which we can issue commands to OpenGL ES.
We do all our initialisation in the onSurfaceChanged.
Steps:
– Instantiates triangle1 with a yellow color and size 0.5.
– Then Set the actual viewport. The first two parameters define the lower left corner, while the next 2 the width and height of it. Width and height in this case is set with values passed by Android’s onSurfaceChanged event. If orientation is not locked, the width and height will swap values every time the surface changes between portrait and landscape.
– Set the active matrix to be the projection matrix. OpenGL is a state machine and it has 4 internal matrices to work with. It will be discussed in detail, but for now this is how we tell OpenGL to switch to the perspective matrix so we can perform operations on it.
In the onDrawFrame we simply issue a series of commands to draw the scene which will set the clear values for the colour buffer to opaque black. The attributes are (red, green, blue, alpha) taking values between 0 and 1. 1 being the highest intensity while 0 meaning “no” intensity. For the alpha component 0 is transparent and 1 is opaque.
Note that OpenGL does not work with pixels as measures, but with units and fractions of units. We will have to decide how many units an object will have. For example 1 unit in OpenGL can be 1 meter in the real world, so a human can be 1.8 unit tall.
Now Draw triangle1. It will be drawn 5 units into the screen. We instruct OpenGL to move further 5 units INTO the screen (meaning farther) and 2 units to the right. The translation will be made FROM the last position.
The result will show the scaling of the triangles. The green triangle is the same size as the red one but it appears smaller because it is farther away.
When doing orthographic projection, the Z component is completely ignored and there is no scaling effect.
The following listing shows the Triangle used, but you don’t have to worry about understanding it, as I will cover the vertex buffers shortly.
package com.example.dprogramming; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; public class Triangle { private FloatBuffer vertexBuffer; private float base = 1.0f; private float red, green, blue; private float vertices[] = { -0.5f, -0.5f, 0.0f, // V1 - first vertex (x,y,z) 0.5f, -0.5f, 0.0f, // V2 - second vertex 0.0f, 0.5f, 0.0f // V3 - third vertex }; public Triangle(float scale, float red, float green, float blue) { vertices = new float[] { -base * scale, -base * scale, 0.0f, // V1 - first vertex base * scale, -base * scale, 0.0f, // V2 - second vertex 0.0f, base * scale, 0.0f // V3 - third vertex }; this.red = red; this.green = green; this.blue = blue; ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 3 * 4); byteBuffer.order(ByteOrder.nativeOrder()); vertexBuffer = byteBuffer.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.flip(); } public void draw(GL10 gl) { gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // set the colour for the triangle gl.glColor4f(red, green, blue, 0.5f); // Point to our vertex buffer gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // Draw the vertices as triangle strip gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vertices.length / 3); // Disable the client state before leaving gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
Top 15 Best Android Apps For C Programming | 2018 Exclusive
Reveal Animation Example Introduced In Android 5.0
Floating Action Button Example in Android 5.0
ViewStub Example And Use In Android
Include-Merge Example in Android
Sprite Game Example In Android – Step1
Round Rect Example In Android
DialogAppExample In Android