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

前言

目前只有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 stub
		setEGLContextClientVersion(2);
		this.setRenderer(_render);
		setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
	}

	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		float 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
	}

	@Override
	public 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);
	}

	@Override
	public void onSurfaceChanged(GL10 gl_unused, int width, int height) {
		// TODO Auto-generated method stub
		float ratio = (float) width / height;
		
		//设置OPENGL视口
		GLES30.glViewport(0, 0, width, height);
		
		//设置矩阵投影参数
		Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// TODO Auto-generated method stub
		
		//black background
		GLES30.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 stub
		this.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;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mGL30View = new MySurfaceView(this);
		setContentView(mGL30View);
	}

	@Override
	public 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;
	}
	
	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		this.mGL30View.onResume();
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		this.mGL30View.onPause();
	}

}

OpenGL ES 3.0 英文版 第1章——OpenGL ES 3.0简介   第1章简单介绍OpenGL ES,概述了OpenGL ES 3.0图形管线,讨论了OpenGL ES 3.0的设计理念和限制,最后介绍了OpenGL ES 3.0中使用的些约定和类型。   第2章——你好,三角形:OpenGL ES 3.0示例   第2章介绍制三角形的个简单OpenGL ES 3.0示例。我们的目的是说明OpenGL ES 3.0程序的样子,向读者介绍些API概念,并说明如何构建和运行OpenGL ES 3.0示例程序。   第3章——EGL简介   第3章介绍EGL——为OpenGL ES 3.0创建表面和渲染上下文的API。我们说明与原生窗口系统通信、选择配置和创建EGL渲染上下文及表面的方法,传授足够多的EGL知识,你可以了解到启动OpenGL ES 3.0进行渲染所需的所有知识。   第4章——着色器和程序   着色器对象和程序对象是OpenGL ES 3.0中最基本的对象。第4章介绍创建着色器对象、编译着色器和检查编译错误的方法。这章还说明如何创建程序对象、将着色器对象连接到程序对象以及链接最终程序对象的方法。我们讨论如何查询程序对象的信息以及加载统变量(uniform)的方法。此外,你将学习有关源着色器和程序二进制代码之间的差别以及它们的使用方法。   第5章——OpenGL ES着色语言   第5章介绍编写着色器所需的着色语言的基础知识。这些着色语言基础知识包括变量和类型、构造器、结构、数组、统变量、统变量块(uniform block)和输入/输出变量。该章还描述着色语言的某些更细微的部分,例如精度限定符和不变性。   第6章——顶点属性、顶点数组和缓冲区对象   从第6章开始(到第11章为止),我们将详细介绍管线,教授设置和编程图形管线各个部分的方法。这旅程从介绍几何形状输入图形管线的方法开始,包含了对顶点属性、顶点数组和缓冲区对象的讨论。   第7章——图元装配和光栅化   在前章讨论几何形状输入图形管线的方法之后,第7章将讨论几何形状如何装配成图元,介绍OpenGL ES 3.0中所有可用的图元类型,包括点精灵、直线、三角形、三角形条带和三角扇形。此外,我们还说明了在顶点上进行坐标变换的方法,并简单介绍了OpenGL ES 3.0管线的光栅化阶段。   第8章——顶点着色器   我们所介绍的管线的下部分是顶点着色器。第8章概述了顶点着色器如何融入管线以及OpenGL ES 着色语言中可用于顶点着色器的特殊变量,介绍了多个顶点着色器的示例,包括逐像素照明和蒙皮(skinning)。我们还给出了用顶点着色器实现OpenGL ES 1.0(和1.1)固定功能管线的示例。   第9章——纹理   第9章开始介绍片段着色器,描述OpenGL ES 3.0中所有可用的纹理功能。该章提供了创建纹理、加载纹理数据以及纹理渲染的细节,描述了纹理包装模式、纹理过滤、纹理格式、压缩纹理、采样器对象、不可变纹理、像素解包缓冲区对象和Mip贴图。该章介绍了OpenGL ES 3.0支持的所有纹理类型:2D纹理、立方图、2D纹理数组和3D纹理。   第10章——片段着色器   第9章的重点是如何在片段着色器中使用纹理,第10章介绍编写片段着色器所需知道的其他知识。该章概述了片段着色器和所有可用的特殊内建变量,还演示了用片段着色器实现OpenGL ES 1.1中所有固定功能技术的方法。多重纹理、雾化、Alpha测试和用户裁剪平面的例子都使用片段着色器实现。   第11章——片段操作   第11章讨论可以适用于整个帧缓冲区或者在OpenGL ES 3.0片段管线中执行片段着色器后适用于单个片段的操作。这些操作包括剪裁测试、模板测试、深度测试、多重采样、混合和抖动。本章介绍OpenGL ES 3.0图形管线的最后阶段。   第12章——帧缓冲区对象   第12章讨论使用帧缓冲区对象渲染屏幕外表面。帧缓冲区对象有多种用法,最常见的是渲染到个纹理。本章提供API帧缓冲区对象部分的完整概述。理解帧缓冲区对象对于实现许多高级特效(如反射、阴影贴图和后处理)至关重要。   第13章——同步对象和栅栏   第13章概述同步对象和栅栏,它们是在OpenGL ES 3.0主机应用和GPU执行中同步的有效图元。我们讨论同步对象和栅栏的使用方法,并以个示例作为结束。   第14章——OpenGL ES 3.0高级编程   第14章是核心章节,将本书介绍的许多主题串联在起。我们已经选择了高级渲染技术的个样本,并展示了实现这些功能的示例。该章包含使用法线贴图的逐像素照明、环境贴图、粒子系统、图像后处理、程序纹理、阴影贴图、地形渲染
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值