上一篇介绍了OpenGL ES能够绘制的几种基本几何图形:点,线,三角形。将分别介绍这几种基本几何图形的例子。为方便起见,暂时在同一平面上绘制这些几何图形,在后面介绍完OpenGL ES的坐标系统和坐标变换后,再介绍真正的3D图形绘制方法。
在Android OpenGL ES(六):创建实例应用OpenGLDemos程序框架 创建了示例应用的程序框架,并提供了一个“Hello World”示例。
为避免一些重复代码,这里定义一个所有示例代码的基类OpenGLESActivity,其定义如下:
package com.example.drawpointer; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity implements IOpenGLDemo{ /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); mGLSurfaceView = new GLSurfaceView(this); mGLSurfaceView.setRenderer(new OpenGLRenderer(this)); setContentView(mGLSurfaceView); } public void DrawScene(GL10 gl) { gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Clears the screen and depth buffer. gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); } @Override protected void onResume() { // Ideally a game should implement onResume() and onPause() // to take appropriate action when the activity looses focus super.onResume(); mGLSurfaceView.onResume(); } @Override protected void onPause() { // Ideally a game should implement onResume() and onPause() // to take appropriate action when the activity looses focus super.onPause(); mGLSurfaceView.onPause(); } protected GLSurfaceView mGLSurfaceView; }
- 在onCreate 方法中创建一个GLSurfaceView mGLSurfaceView,并将屏幕设置为全屏。并为mGLSurfaceView设置Render.
- onResume ,onPause 处理GLSurfaceView 的暂停和恢复。
- DrawScene 使用黑色清空屏幕。
OpenGL ES 内部存放图形数据的Buffer有COLOR ,DEPTH (深度信息)等,在绘制图形只前一般需要清空COLOR 和 DEPTH Buffer。
本例在屏幕上使用红色绘制3个点。创建一个DrawPoint 作为 OpenGLESActivity 的子类,并定义3个顶点的坐标:
package com.example.drawpointer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; import android.os.Bundle; public class DrawPoint extends MainActivity implements IOpenGLDemo{ float[] vertexArray = new float[]{ -0.8f , -0.4f * 1.732f , 0.0f , 0.8f , -0.4f * 1.732f , 0.0f , 0.0f , 0.4f * 1.732f , 0.0f , }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public void DrawScene(GL10 gl) { super.DrawScene(gl); ByteBuffer vbb = ByteBuffer.allocateDirect(vertexArray.length*4); vbb.order(ByteOrder.nativeOrder()); FloatBuffer vertex = vbb.asFloatBuffer(); vertex.put(vertexArray); vertex.position(0); gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); gl.glPointSize(8f); gl.glLoadIdentity(); gl.glTranslatef(0, 0, -4); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex); gl.glDrawArrays(GL10.GL_POINTS, 0, 3); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
- 首先是使用FloatBuffer 存放三个顶点坐标。
- 使用glColor4f(float red, float green, float blue, float alpha) 将当前颜色设为红色。
- glPointSize(float size) 可以用来设置绘制点的大小。
- 使用glEnableClientState 打开Pipeline 的Vectex 顶点“开关”
- 使用glVertexPointer 通知OpenGL ES图形库顶点坐标。
- 使用GL_POINTS 模式使用glDrawArrays绘制3个顶点。
其他必须的类
IOpenGLDemo.java
package com.example.drawpointer; import javax.microedition.khronos.opengles.GL10; public interface IOpenGLDemo { public void DrawScene(GL10 gl); }
OpenGLRenderer.java
package com.example.drawpointer; import javax.microedition.khronos.opengles.GL10; import android.opengl.EGLConfig; import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU; public class OpenGLRenderer implements Renderer { private final IOpenGLDemo openGLDemo; public OpenGLRenderer(IOpenGLDemo demo){ openGLDemo=demo; } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Set the background color to black ( rgba ). gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Enable Smooth Shading, default not really needed. gl.glShadeModel(GL10.GL_SMOOTH); // Depth buffer setup. gl.glClearDepthf(1.0f); // Enables depth testing. gl.glEnable(GL10.GL_DEPTH_TEST); // The type of depth testing to do. gl.glDepthFunc(GL10.GL_LEQUAL); // Really nice perspective calculations. gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); } public void onDrawFrame(GL10 gl) { if(openGLDemo!=null){ openGLDemo.DrawScene(gl); } } public void onSurfaceChanged(GL10 gl, int width, int height) { // Sets the current view port to the new size. gl.glViewport(0, 0, width, height); // Select the projection matrix gl.glMatrixMode(GL10.GL_PROJECTION); // Reset the projection matrix gl.glLoadIdentity(); // Calculate the aspect ratio of the window GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f); // Select the modelview matrix gl.glMatrixMode(GL10.GL_MODELVIEW); // Reset the modelview matrix gl.glLoadIdentity(); } @Override public void onSurfaceCreated(GL10 arg0, javax.microedition.khronos.egl.EGLConfig arg1) { // TODO Auto-generated method stub } }
最终结果: