一、提要

       偶然在Android developers看到这篇教程,遍一步步做了下来,下面是一点记录。


二、在Android中绘制OpenGL es的方法

     为了在Android应用中使用OpenGL绘制图形,我们必须创建一个View容器。一个最直接的方法就是implement GLSurfaceView 和a GLSurfaceView.Renderer前者就是容器,后者控制View中渲染的内容。

    还有两种方法是SurfaceView和TextureView,但有点小复杂。

    最终效果:




三、必要的声明

在manifest文件中添加下面的代码:

            


前面是声明OpenGL的版本,后两行是声明贴图的类型。


四、主Activity类

package com.example.opengles;  import android.opengl.GLSurfaceView; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.view.Menu;  public class OpenGLActivity extends Activity {  	private GLSurfaceView mGLView; 	@Override 	public void onCreate(Bundle savedInstanceState) { 		super.onCreate(savedInstanceState); 		mGLView = new MyGLSurfaceView(this); 		setContentView(mGLView); 	}  	@Override 	public boolean onCreateOptionsMenu(Menu menu) { 		getMenuInflater().inflate(R.menu.activity_open_gl, menu); 		return true; 	} 	@Override 	protected void onPause() { 		super.onPause(); 		// The following call pauses the rendering thread. 		// If your OpenGL application is memory intensive, 		// you should consider de-allocating objects that 		// consume significant memory here. 		mGLView.onPause(); 	}  	@Override 	protected void onResume() { 		super.onResume(); 		// The following call resumes a paused rendering thread. 		// If you de-allocated graphic objects for onPause() 		// this is a good place to re-allocate them. 		mGLView.onResume(); 	} }  class MyGLSurfaceView extends GLSurfaceView {  	public MyGLSurfaceView(Context context){ 		super(context);    		// Create an OpenGL ES 2.0 context. 		setEGLContextClientVersion(2);  		// Set the Renderer for drawing on the GLSurfaceView 				setRenderer(new MyRender()); 		// Render the view only when there is a change in the drawing data 		setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 		 	}   } 


四、渲染器类

package com.example.opengles;   import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer;  import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;  import android.opengl.GLES20; import android.opengl.GLSurfaceView;  public class MyRender implements GLSurfaceView.Renderer {  	private Triangle mTriangle; 	@Override 	public void onDrawFrame(GL10 gl) { 		// TODO Auto-generated method stub         // Draw background color         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);         // Draw triangle        mTriangle.draw(); 	}  	@Override 	public void onSurfaceChanged(GL10 gl, int width, int height) { 		// TODO Auto-generated method stub 		  // Adjust the viewport based on geometry changes,         // such as screen rotation         GLES20.glViewport(0, 0, width, height); 	}     public static int loadShader(int type, String shaderCode){          // create a vertex shader type (GLES20.GL_VERTEX_SHADER)         // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)         int shader = GLES20.glCreateShader(type);          // add the source code to the shader and compile it         GLES20.glShaderSource(shader, shaderCode);         GLES20.glCompileShader(shader);          return shader;     }   	@Override 	public void onSurfaceCreated(GL10 gl, EGLConfig config) { 		// TODO Auto-generated method stub 	    // Set the background frame color         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);         mTriangle = new Triangle(); 	} 	  }  class Triangle {      private final String vertexShaderCode =         "attribute vec4 vPosition;" +         "void main() {" +         "  gl_Position = vPosition;" +         "}";      private final String fragmentShaderCode =         "precision mediump float;" +         "uniform vec4 vColor;" +         "void main() {" +         "  gl_FragColor = vColor;" +         "}";      private final FloatBuffer vertexBuffer;     private final int mProgram;     private int mPositionHandle;     private int mColorHandle;      // number of coordinates per vertex in this array     static final int COORDS_PER_VERTEX = 3;     static float triangleCoords[] = { // in counterclockwise order:          0.0f,  0.622008459f, 0.0f,   // top         -0.5f, -0.311004243f, 0.0f,   // bottom left          0.5f, -0.311004243f, 0.0f    // bottom right     };     private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;     private final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex      // Set color with red, green, blue and alpha (opacity) values     float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };      public Triangle() {         // initialize vertex byte buffer for shape coordinates         ByteBuffer bb = ByteBuffer.allocateDirect(                 // (number of coordinate values * 4 bytes per float)                 triangleCoords.length * 4);         // use the device hardware's native byte order         bb.order(ByteOrder.nativeOrder());          // create a floating point buffer from the ByteBuffer         vertexBuffer = bb.asFloatBuffer();         // add the coordinates to the FloatBuffer         vertexBuffer.put(triangleCoords);         // set the buffer to read the first coordinate         vertexBuffer.position(0);          // prepare shaders and OpenGL program         int vertexShader = MyRender.loadShader(GLES20.GL_VERTEX_SHADER,                                                    vertexShaderCode);         int fragmentShader = MyRender.loadShader(GLES20.GL_FRAGMENT_SHADER,                                                      fragmentShaderCode);          mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program         GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program         GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program         GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables      }      public void draw() {         // Add program to OpenGL environment         GLES20.glUseProgram(mProgram);          // get handle to vertex shader's vPosition member         mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");          // Enable a handle to the triangle vertices         GLES20.glEnableVertexAttribArray(mPositionHandle);          // Prepare the triangle coordinate data         GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,                                      GLES20.GL_FLOAT, false,                                      vertexStride, vertexBuffer);          // get handle to fragment shader's vColor member         mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");          // Set color for drawing the triangle         GLES20.glUniform4fv(mColorHandle, 1, color, 0);          // Draw the triangle         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);          // Disable vertex array         GLES20.glDisableVertexAttribArray(mPositionHandle);     } }

       这个类中最重要的三个函数是

  • onSurfaceCreated() - 初始化OpenGL环境
  • onDrawFrame() - 绘制View
  • onSurfaceChanged() - 当View发生改变的时候掉用是不是很熟悉,就是Qt的OpenGL中的paintGL() ,resizeGL() ,initializeGL() 。

          最后运行的时候会在屏幕上绘制一个三角形,用的是ShaderLanguage,这个就直接copy了,当然也可以用那种比较原始的一个个定义点定义颜色来绘图。

         注意:OpenGL的程序在模拟器中没办法跑起来,需要真机调试。



    五、参考资料

    android develop:http://developer.android.com/training/graphics/opengl/environment.html