android opengles 3.0 学习(一):顶点绘制法 VBOs(Vertex Buffer Objects)

来源:互联网 发布:首届全球程序员节logo 编辑:程序博客网 时间:2024/05/20 17:25

前言

目前只有android系统中只有android 4.3或以上支持opengles 3.0,但目前很多运行android 4.3系统的硬件能支持opengles 3.0的也是非常少的。不过幸好,opengles 3.0是向后兼容的,当程序发现硬件不支持opengles 3.0时则会自动调用opengles 2.0的API。废话不多说了,开始进入正题,首先看看本例子的结果:



实现过程:

1. 在manifest中声明程序中使用opengles 3.0

<!-- Tell the system this app requires OpenGL ES 3.0. --><uses-feature android:glEsVersion="0x00030000" android:required="true" />
如果程序中使用了纹理压缩的话,还需进行如下声明,以防止不支持这些压缩格式的设备尝试运行程序。

<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" /><supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />

2.实现两个必不可少的类:GLSurfaceView和GLSurfaceView.Renderer

继承GLSurfaceView类的MySurfaceView.java

package com.gl.gl30_vbos02;import android.content.Context;import android.opengl.GLSurfaceView;import android.util.AttributeSet;import android.view.MotionEvent;public class MySurfaceView extends GLSurfaceView {private final float TOUCH_SCALE_FACOTOR = 180.0f / 320;private GLRender _render = new GLRender();private float _preX = 0.0f;private float _preY = 0.0f;public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubsetEGLContextClientVersion(2);this.setRenderer(_render);setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);}public MySurfaceView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubfloat x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_MOVE:float dx = x - _preX;float dy = y - _preY;_render.zrot = dx * TOUCH_SCALE_FACOTOR;_render.xrot = dy * TOUCH_SCALE_FACOTOR;this.requestRender();break;default:break;}_preX = x;_preY = y;return true;}}

实现GLSurfaceView.Renderer的GLRender.java:

package com.gl.gl30_vbos02;import java.nio.FloatBuffer;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLES30;import android.opengl.GLSurfaceView.Renderer;import android.opengl.Matrix;import android.util.Log;//@TargetApi(18)public class GLRender implements Renderer {public float xrot, yrot, zrot;private static final String TAG = "GLRender";private final float[] mProjMatrix = new float[16];private final float[] mVMatrix = new float[16];private final float[] mMVPMatrix = new float[16];private final float[] mRotationMatrix = new float[16];//private volatile float mAngle;private CirclePlane _circlePlane;//定义环境光private FloatBuffer lightAmbient = FloatBuffer.wrap(new float[]{0.5f, 0.5f, 0.5f, 1.0f});//定义漫散射private FloatBuffer lightDiffuse = FloatBuffer.wrap(new float[]{1.0f, 1.0f, 1.0f, 1.0f});//光源的位置private FloatBuffer lightPosition = FloatBuffer.wrap(new float[]{0.0f, 0.0f, 2.0f, 1.0f});public GLRender() {// TODO Auto-generated constructor stub}@Overridepublic void onDrawFrame(GL10 gl_unused) {// TODO Auto-generated method stub//清楚屏幕和深度缓存GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);this._circlePlane.Draw(mMVPMatrix);}@Overridepublic void onSurfaceChanged(GL10 gl_unused, int width, int height) {// TODO Auto-generated method stubfloat ratio = (float) width / height;//设置OPENGL视口GLES30.glViewport(0, 0, width, height);//设置矩阵投影参数Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// TODO Auto-generated method stub//black backgroundGLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); this._circlePlane = new CirclePlane(10, 20, 1.0f);}public static int loadShader(int type, String shaderCode){// create a shader type (GLES30.GL_VERTEX_SHADER)// or a fragment shader type (GLES30.GL_FRAGMENT_SHADER)int shader = GLES30.glCreateShader(type);GLES30.glShaderSource(shader, shaderCode);GLES30.glCompileShader(shader);return shader;} public static void checkGLError(String glOperation){int error;while((error = GLES30.glGetError()) != (GLES30.GL_NO_ERROR)){Log.e(TAG, glOperation + ": glError " + error);throw new RuntimeException(glOperation + ": glError " + error);}}}


要完成Opengl es工程,最重要是实现上面两个类。另外本程序为了绘制出图中的图案,还有四个类,可在附件中查看。:

CirclePlane.java //实现图案中顶点缓存,这个类有比较多的数学知识,不过只为了实现图案的话,不用理解其中数学算法问题也没关系。只要修改此类就可以绘制出不同的图案

Vertex3f.java //定义了顶点类型

Until.java //生成顶点缓存的公共工具类

OpenGLES30.java //工程的主类



附录

CirclePlane.java

package com.gl.gl30_vbos02;import java.nio.FloatBuffer;import android.opengl.GLES30;//@TargetApi(18)public class CirclePlane {static final int COORDS_PRE_VERTEX = 3;private final int vertexStride = COORDS_PRE_VERTEX * 4;private int vertexCount = 0;private int mRow = 10;private int mColumn = 20;private float mRadius = 1.0f;private FloatBuffer mPlaneBuffer;private final int mProgram;private int mPositionHandle;private int mColorHandle;private int mMVPMatrixHandle;// Set color with red, green, blue and alpha (opacity) values    float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //白色不透明private final String vertexShaderCode = "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main()" +"{" +"gl_Position = vPosition * uMVPMatrix;" +"}";private final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main()" +"{" +"gl_FragColor = vColor;" +"}";public CirclePlane(int row, int column, float radius) {// TODO Auto-generated constructor stubthis.mRow = row;this.mColumn = column;this.mRadius = radius;this.createGraphics();int vertexShader = GLRender.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode);int fragmentShader = GLRender.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode);        this.mProgram = GLES30.glCreateProgram();             // create empty OpenGL Program        GLES30.glAttachShader(this.mProgram, vertexShader);   // add the vertex shader to program        GLES30.glAttachShader(this.mProgram, fragmentShader); // add the fragment shader to program        GLES30.glLinkProgram(this.mProgram);                  // create OpenGL program executables}private void createGraphics(){Vertex3f vertexs[][] = new Vertex3f[this.mRow][this.mColumn];float intervalR = this.mRadius / this.mRow;Vertex3f centralPos = new Vertex3f(0.0f, 0.0f, 0.0f);for(int i=0;i<this.mRow;i++){float tmpR = intervalR * i;for(int j=0;j<this.mColumn;j++){double angle = 2 * j * Math.PI / (this.mColumn - 1);vertexs[i][j] = new Vertex3f((float)(tmpR * Math.cos(angle)), (float)(tmpR * Math.sin(angle)), centralPos.z);}}//创建三角形顶点int len = 2 * (this.mRow -1) * (this.mColumn - 1) * 3;this.vertexCount = len;Vertex3f tri[] = new Vertex3f[len];int index = 0;for(int i=0;i<this.mRow-1;i++){for(int j=0;j<this.mColumn-1;j++){tri[index] = vertexs[i][j];tri[index+1] = vertexs[i+1][j];tri[index+2] = vertexs[i+1][j+1];tri[index+3] = vertexs[i][j];tri[index+4] = vertexs[i+1][j+1];tri[index+5] = vertexs[i+1][j];index += 6;}}//设置顶点缓存float[] plane = new float[len*3];for(int i=0;i<len;i++){int vertexI = 3 * i;plane[vertexI] = tri[i].x;plane[vertexI+1] = tri[i].y;plane[vertexI+2] = tri[i].z;}this.mPlaneBuffer = Util.getFloatBuffer(plane);//plane = null;} public void Draw(float[] mvpMatrix){GLES30.glUseProgram(this.mProgram);this.mPositionHandle = GLES30.glGetAttribLocation(this.mProgram, "vPosition");GLES30.glEnableVertexAttribArray(this.mPositionHandle);GLES30.glVertexAttribPointer(this.mPositionHandle, COORDS_PRE_VERTEX, GLES30.GL_FLOAT, false, this.vertexStride, this.mPlaneBuffer);this.mColorHandle = GLES30.glGetUniformLocation(this.mProgram, "vColor");GLES30.glUniform4fv(this.mColorHandle, 1, this.color, 0);this.mMVPMatrixHandle = GLES30.glGetUniformLocation(this.mProgram, "uMVPMatrix");GLRender.checkGLError("glGetUniformLocation");GLES30.glUniformMatrix4fv(this.mMVPMatrixHandle, 1, false, mvpMatrix, 0);GLRender.checkGLError("glUniformMatrix4fv");GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, this.vertexCount);GLES30.glDisableVertexAttribArray(this.mPositionHandle);//gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//gl.glVertexPointer(3, GL10.GL_FLOAT, 0, this.mPlaneBuffer);//gl.glDrawArrays(GL10.GL_TRIANGLES, 0, (this.mRow-1)*(this.mColumn-1)*2*3);////gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);//gl.glFinish();}}


Vertex3f.java

package com.gl.gl30_vbos02;public class Vertex3f {public float x = 0.0f;public float y = 0.0f;public float z = 0.0f;public Vertex3f(float x, float y, float z){this.x = x;this.y = y;this.z = z;}}

Until.java

package com.gl.gl30_vbos02;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.nio.IntBuffer;public class Util {//获取整形缓冲数据public static IntBuffer getIntBuffer(int[] vertexs){IntBuffer buffer;ByteBuffer qbb = ByteBuffer.allocateDirect(vertexs.length * 4);qbb.order(ByteOrder.nativeOrder());buffer = qbb.asIntBuffer();buffer.put(vertexs);buffer.position(0);return buffer;}//获取浮点形缓冲数据public static FloatBuffer getFloatBuffer(float[] vertexs){FloatBuffer buffer;ByteBuffer qbb = ByteBuffer.allocateDirect(vertexs.length * 4);qbb.order(ByteOrder.nativeOrder());buffer = qbb.asFloatBuffer();buffer.put(vertexs);buffer.position(0);return buffer;}//获取字节型缓冲数据public static ByteBuffer getByteBuffer(byte[] vertexs){ByteBuffer buffer = null;buffer = ByteBuffer.allocateDirect(vertexs.length);buffer.put(vertexs);buffer.position(0);return buffer;}}

OpenGLES30.java

package com.gl.gl30_vbos02;import android.opengl.GLSurfaceView;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class OpenGLES30 extends Activity {private GLSurfaceView mGL30View;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGL30View = new MySurfaceView(this);setContentView(mGL30View);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.open_gles30, menu);return true;}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();this.mGL30View.onResume();}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();this.mGL30View.onPause();}}

原创粉丝点击