【Android学习系列】 OpenGL开发教程一

之前一直想去看看OPEN-GL的文章,也想了解下在Android平台下是如何利用它去开发一个3D场景,比如游戏,或虚拟场景。看了gongziya的博客,他记录自己学习Android平台的OPENGL开发的过程,于是也想记录下自己的一些轨迹,也算是对学习的一个总结。

本文基本上是参考gongziya的文章(http://gongziya.com/721/android%E7%9A%84opengl%E6%95%99%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE%EF%BC%9A%E5%88%9B%E5%BB%BA%E7%AA%97%E5%8F%A3/)

在对该文进行测试,理解的基础上,逐渐加入自己的一些困惑和想法,希望能最终形成一个适合自己的文档。


【目的】

了解OPENGL的开发过程,通过学习系列教程,能顺利开发常规的3D游戏,能了解OPENGL的机理;如果能将OPENGL和meeting中的PD,AS结合起来,那更是一件美妙的事情。

【计划】

9.10-14,学习完gongziya的教程;每日作出总结。

9.17-21,。。。【更新中】

***********************开始吧**********************************

【准备工作】

Android下OPENGL的开发,并不需要特别的环境,只要Android的SDK即可。gongziya是熟悉OPENGL,而不大了解Andrroid,我则刚好相反,个人感觉应该对OPENGL有一定的了解,才能很好的理解设计的思路。

【第一部分 GLSurfaceView】

Android为我们提供了GLSurfaceView,能方便地显示自己的OPENGL视图,在GLSurfaceView类中包含了一个专门用于渲染3D的接口Renderer。所以想要使用OPENGL渲染,必要创建一个OPENGLRender类,实现这个接口:

class OpenGLRender implements Renderer
    {
		@Override
		public void onDrawFrame(GL10 gl) {
			// draw what you want to draw	
		}

		@Override
		public void onSurfaceChanged(GL10 gl, int width, int height) {
			// when the screen changed, do the things here. For example, rotate the screen.
		}

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			// do the initialize work here.	
		}
    }

这个接口中的三个方法作用分别如下:

onDrawFrame:绘图的代码;

onSurfaceChanged:屏幕发生变化时的操作,旋转等;

onSurfaceCreated: 初始化工作

将这个Render应用到Activity的代码很简单:


Renderer render = new OpenGLRenderer();//创建render
 
public void onCreate(Bundle savedInstanceState)
{
 	super.onCreate(savedInstanceState);
 
 	GLSurfaceView glView = new GLSurfaceView(this);//创建GLSurfaceView

 	glView.setRenderer(render);//设置render,使之生效

 setContentView(glView);//把glview设置为屏幕内容
}

这样,如何实现Render中的三个方法,就成为了重中之重,也是我们发挥想象力的地方。

【第二部分 Renderer 基本方法】

(1) onSurfaceCreated

在这里进行初始化工作,设置各个参数:

gl.glClearColor: 设置屏幕背景;

gl.glShadeModel: 设置阴影平滑;

//设置深度缓存,通过深度缓存可以让OpenGL知道场景中物体的深度关系,这样我们在绘制物体时,不会把后面的物体绘制到前面的物体上。

gl.glClearDepthf, gl.glEnable, gl.glDepthFunc,主要由这三个方法控制。

gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); //设置透视性能----这个有什么好处?

Q1:初始化中,要进行哪些必要的设置?

(2) onSurfaceChanged

当屏幕发生改变的时候,需要在这里进行相关的操作,不管如何,该方法至少调用一次。

// 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
gl.glFrustumf(-ratio, ratio, -1,1,1,10);---设置视口大小 参考http://gongziya.com/693/opengl中的投影和视口变换/
// Select the modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW); -----------选择模型观察矩阵
// Reset the modelview matrix
gl.glLoadIdentity();---------------------------重置模型观察矩阵

Q2:选择和重置投影矩阵,模型观察矩阵,有什么作用?窗口,视口的概念是什么?

(3) onDrawFrame

绘制屏幕中的图形。

// 重置当前的模型观察矩阵
gl.glLoadIdentity();
// 左移 1.5 单位,并移入屏幕 6.0
gl.glTranslatef(-1.5f,0.0f, -6.0f);-------------------设置图形位置?
//启用定点数组
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);----------顶点数组是什么概念?
// 设置三角形顶点 (int size, int type, int stride, Buffer pointer)
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,TrianBuffer);---3:xyz三维;type表明是浮点型;stride连续顶点之间的偏移量??pointer是顶点坐标数据的顶点缓存。strider和pointer如何理解?
//绘制三角形glDrawArrays(intmode,intfirst,intcount) ---count标明数组个数,从索引为0开始,总共有3个
gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
/* 渲染正方形 */
// 重置当前的模型观察矩阵
gl.glLoadIdentity();
// 左移 1.5 单位,并移入屏幕 6.0
gl.glTranslatef(1.5f,0.0f, -6.0f);
//设置和绘制正方形
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, QuaterBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
//取消顶点数组
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

调用glLoadIdentity()之后,您实际上将 当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。


glTranslatef(x,y,z)沿着 X,Y 和 Z 轴移动。根据前面的次序,下面的代码沿着X轴左移1.5个单位,Y轴不动(0.0f),最后移入屏幕6.0f个单位。注意在glTranslatef(x,y,z)中当您移动的时候,您并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置


【第三部分 添加颜色和动画效果】

颜色和动画,都是属于onDrawFrame里面的内容,也就是实际上在屏幕上要显示出来的东西。

(1) 添加颜色

添加颜色的逻辑比较简单,主要分为四步:构造颜色数组(你要给该图形填充什么颜色);启用颜色数组;绘画;关闭颜色数组;

A. 构建颜色数组

//三角形的顶点颜色值(r,g,b,a)
private float colorvertices[] =
 {
	 1.0f,0.0f,0.0f,1.0f,
	 0.0f,1.0f,0.0f,1.0f,
	 0.0f,0.0f,1.0f,1.0f,
 };
private FloatBuffer ColorBuffer;
//给colorBuffer赋值,这个操作同之前构造三角形,四边形的动作是一样,需要构造一个能被OPENGL接收的数据类型Buffer
//下面设置三角形颜色数据
ByteBuffer cbb = ByteBuffer.allocateDirect(colorvertices.length * 4);
cbb.order(ByteOrder.nativeOrder());
ColorBuffer = cbb.asFloatBuffer();
ColorBuffer.put(colorvertices);
ColorBuffer.position(0);

B. 启用颜色数组

gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
C. 绘画
gl.glColorPointer(4, GL10.GL_FLOAT, 0, ColorBuffer);
D. 关闭颜色数组
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

【注意】启用和关闭的动作是成对出现的;如果是单色填充,则不需要启用颜色数组这个操作。直接填充即可。 gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f);

(2) 添加动画

动画旋转的操作,主要通过glRotatef(Angle,Xvector,Yvector,Zvector)来实现,它负责让对象绕某个轴旋转。这个命令有很多用处(用处体现在哪儿?)

Angle 通常是个变量代表对象转过的角度。

Xvector,Yvector和Zvector三个参数则共同决定旋转轴的方向。形象地理解,可以根据这三个参数画一个轴,图形就是围绕该轴转动。

//设置旋转
gl.glRotatef(rotateTri, 0.0f, 1.0f, 0.0f);

【注意】通过该例子明白,onDrawFrame是每帧都会调用的,不断刷新;gl.glRotatef的动作,要放置在gl.glTranslatef 动作之后,即先定位置,再旋转;


我们说了很久的顺时针,逆时针画图,到底有什么用呢
gl.glEnable(GL10.GL_CULL_FACE);
//设置openggl有剔除效果,就是看不到的面就不画,当然可以增加效率
gl.glFrontFace(GL10.GL_CCW);
//设置逆时针方向为正面
gl.glCullFace(GL10.GL_BACK);
//设置背面被剔除,不画
Cull就是剔除的意思


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值