Android OpenGL ES 应用(一)

本文介绍了OpenGL作为3D标准的特性及其在Android平台上的应用,包括如何判断设备是否支持OpenGL 2.0、扩展Android的GLSurfaceView类进行图像绘制、封装处理方法、编写顶点着色器和片段着色器、编译和关联OpenGL脚本,以及验证程序错误的过程。最终展示了一个简单的正方形渲染结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


OpenGL已经成了3D的一个"标准" 因为它能跨平台,接口也比较丰富,几乎大部分的手机3D游戏都和OpenGL有关系。

当然还有微软有direct X 但只能在微软平台上使用。

OpenGL底层是c/c++实现,JAVA中使用都是用封装好的类库。Android提供了以下几个接口包 可使用,基本能达到3D技术的要求。

Android平台用OpenGL ES 这个子集来处理图像,现在OpenGL ES基本用2.0的了,很少再用1.0的,3.0还未流行起来。


首先编写判断Android设备是否支持OpenGL 2.0.

GLHelper.java加入一个判断是否支持2.0版本的代码方法。

public static boolean enableOpenGL2(Activity act) {
		
		final ActivityManager mg = (ActivityManager) act.getSystemService(Context.ACTIVITY_SERVICE);
		ConfigurationInfo configuration = mg.getDeviceConfigurationInfo();
		boolean b = configuration.reqGlEsVersion >= 0x20000);
		return b;
	}

我们需要扩展 android.opengl.GLSurfaceView 这个类,让图像绘制在SurfaceView上面,看看源码发现这个类其实是扩展了SurfaceView做了写封装。


public class MyOpenGLView extends GLSurfaceView { //这个类就先空着,这一次没有太多的代码


	public MyOpenGLView(Context context) {
		super(context);
	}

	public MyOpenGLView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

}


我们把处理的各种方法封装一下。

public class GLData {

	public GLData() {
	}

	public static float[] singelTriangles = { //定义了2个三角形,组成了一个正方形,因为openGL ES只能是点,线和三角形
			-0.3f, -0.3f, 
			 0.3f, 0.3f, 
			-0.3f, 0.3f, 
			-0.3f, -0.3f,
			 0.3f, -0.3f, 
			 0.3f, 0.3f

	};

}

OpenGL ES在Android的坐标系是 [-1,1]的区间内




编写2个简单的顶点着色器和片段做色器。


public class GLScript {

	public GLScript() {
	}
	
	public static final String vertex1 = "attribute vec4 mPosition;\n" +
			"void main()\n" +
			"{\n" +
				"gl_Position=mPosition;\n " +
			"}\n";

	public static final String fragment1 = "precision mediump float;\n" +
			"uniform vec4 mColor;\n" +
			"void main(){ gl_FragColor=mColor;\n}";
	
}

vec4 mPosition 这个表示定义了一个4分量(x,y,z,w)的顶点,然后付给gl_Position 内置的变量中,OpenGL会编译并且自动处理。
vec4 mColor 这个表示定义了一个颜色分量RGBA,最后一个是透明度,即是 红绿蓝.

 

脚本语言是OpenGL ES的核心,很多的渲染效果都需要脚本处理。

GLHelper.java添加编译脚本的代码方法.

	public static int compileScript(int type, String script){
		int objID  = GLES20.glCreateShader(type); //创建一个着色器对象,TYPE表示顶点着色器和片段着色器
		if (objID == 0) { //0表示有错误
		    return 0;
		}
		GLES20.glShaderSource(objID, script); //把脚本代码传给OpenGL 引擎
		GLES20.glCompileShader(objID); //开始编译
		int[] status = new int[1];
		GLES20.glGetShaderiv(objID, GLES20.GL_COMPILE_STATUS, status, 0); //看看编译结果是否有错误。
		Log.d("OPENGL","compileScript status info:" + GLES20.glGetShaderInfoLog(objID));
		if (status[0] == 0) {
			GLES20.glDeleteShader(objID);//有错误我们删除这个对象。
			Log.e("OPENGL", "Error Compile Script:" + script);
			return 0;
		}
		return objID;
	}


如果编译成功我们开始关联OpenGL ES程序。


	public static int linkGL(){
		int programId = GLES20.glCreateProgram();//创建一个程序
		if (programId == 0) {
		   Log.e("OPENGL", "Error Create Link Program");
		   return 0;
		}
		return programId;
	}
	
	public static int linkAttach(int vertexsharder,int fragmentsharder){
		int programId = linkGL();
		GLES20.glAttachShader(programId, vertexsharder); //和着色器进行关联
		GLES20.glAttachShader(programId, fragmentsharder);//和着色器进行关联
		GLES20.glLinkProgram(programId); //把program链接起来
		int status[] = new int[1];
		GLES20.glGetProgramiv(programId, GLES20.GL_LINK_STATUS, status, 0); //这地方一样是检查是否有错误发生。
		Log.d("OPENGL","linkAttach link status is " + GLES20.glGetProgramInfoLog(programId));
		if (status[0] == 0) {
			Log.e("OPENGL","link status is error.");
			GLES20.glDeleteProgram(programId);
			return 0;
		}
		return programId;
	}


最后我们验证程序是否有错误

	public static boolean checkProgram(int programId){
		GLES20.glValidateProgram(programId);
		int status[] = new int[1];
		GLES20.glGetProgramiv(programId,GLES20.GL_VALIDATE_STATUS, status,0);
		if (status[0] == 0) {
			Log.e("OPENGL","program is error");
			return false;
		}
		return true;
	}

以上代码都写在 GLHelper.java中,

我们把代码加入到渲染类中Renderer


渲染类

public class MyOpenGLRenderer implements Renderer {
	
	public static FloatBuffer verDataBuffer;
	int colorLocation ;
	int positionLocation ;

	public MyOpenGLRenderer() {
		// 申请直接内存空间,并使用native字节序列
		verDataBuffer = ByteBuffer.allocateDirect(4 * GLData.singelTriangles.length)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		
		verDataBuffer.put(GLData.singelTriangles);  //这是一个正方形,等会贴代码。
	}

	@Override
	public void onDrawFrame(GL10 arg0) { //这个方法会不断的重绘
		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
		GLES20.glUniform4f(colorLocation, 0f, 0f, 0F, 0f); //这里是黑色,颜色将传入给<span style="font-family: Arial, Helvetica, sans-serif;">colorLocation</span>
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);//画三角形,有6个顶点 所以从0,6开始
	}

	@Override
	public void onSurfaceChanged(GL10 arg0, int w, int h) {
		GLES20.glViewport(0, 0, w, h);
	}

	@Override
	public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
		GLES20.glClearColor(1F, 1F, 1F, 0.0F); //下面的代码都是组织起来用我们编写的GLHelper类.
		int vertexsharder = GLHelper.compileScript(GLES20.GL_VERTEX_SHADER, GLScript.vertex1);
		int fragmentsharder = GLHelper.compileScript(GLES20.GL_FRAGMENT_SHADER, GLScript.fragment1);
		int programId = GLHelper.linkAttach(vertexsharder, fragmentsharder);
		boolean isOK = GLHelper.checkProgram(programId);
		if (isOK) {
			Log.d("","start draw..............");
		 GLES20.glUseProgram(programId); //我们开始使用这个程序
		 colorLocation = GLES20.glGetUniformLocation(programId, "mColor");//获得变量位置,可以理解为内存地址,OpenGL 将为在这个地址中取数据
		 positionLocation = GLES20.glGetAttribLocation(programId, "mPosition");
		 verDataBuffer.position(0);//数据开始端读取
		 GLES20.glVertexAttribPointer(positionLocation, 2, GLES20.GL_FLOAT, false, 0, verDataBuffer);//这个地方把顶点数据与变量关联起来
		 GLES20.glEnableVertexAttribArray(positionLocation);//这地方使得能够使用顶点数组
	   }
	}
}

最后Activity部分代码.

	private MyOpenGLView gLView;
	private boolean openGLEnable;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (GLHelper.enableOpenGL2(this)) {
			openGLEnable = true;
		}
		Log.d("","OpenGL is Enable:" + openGLEnable);
		gLView = new MyOpenGLView(this);
		gLView.setEGLContextClientVersion(2);//可以使用OpenGL ES 2.0
		gLView.setRenderer(new MyOpenGLRenderer());
		setContentView(gLView);
	}




运行结果很简单就是中间一个正方形。

OpenGL ES入门相对还是比较复杂的,因为函数的调用和平时用的JAVA,, C++ 库都不太一样

3D的东西复杂不仅仅是多了一个坐标Z,还有很多的渲染技术。


 工程结构:




Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and The Pragmatic Programmers, LLC was aware of a trademark claim, the designations have been printed in initial capital letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic Programming, Pragmatic Bookshelf, PragProg and the linking g device are trademarks of The Pragmatic Programmers, LLC. Every precaution was taken in the preparation of this book. However, the publisher assumes no responsibility for errors or omissions, or for damages that may result from the use of information (including program listings) contained herein. Our Pragmatic courses, workshops, and other products can help you and your team create better software and have more fun. For more information, as well as the latest Pragmatic titles, please visit us at http://pragprog.com. The Android robot is reproduced from work created and shared by Google and is used according to terms described in the Creative Commons 3.0 Attribution License (http://creativecommons.org/licenses/by/3.0/us/legalcode). The unit circle image in Figure 43, from http://en.wikipedia.org/wiki/File:Unit_circle.svg, is used according to the terms described in the Creative Commons Attribution-ShareAlike license, located at http://creativecommons.org/licenses/by-sa/3.0/legalcode. Day skybox and night skybox courtesy of Jockum Skoglund, also known as hipshot, hipshot@zfight.com,http://www.zfight.com. The image of the trace capture button is created and shared by the Android Open Source Project and is used according to terms described in the Creative Commons 2.5 Attribution License.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值