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

来源:互联网 发布:淘宝网高领羊毛衫 编辑:程序博客网 时间:2024/04/26 05:35

之前一直想去看看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    {@Overridepublic void onDrawFrame(GL10 gl) {// draw what you want to draw}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// when the screen changed, do the things here. For example, rotate the screen.}@Overridepublic 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 matrixgl.glMatrixMode(GL10.GL_PROJECTION);     -----设置投影矩阵// Reset the projection matrixgl.glLoadIdentity();--------------------------重置投影矩阵// Calculate the aspect ratio of the windowgl.glFrustumf(-ratio, ratio, -1,1,1,10);---设置视口大小 参考http://gongziya.com/693/opengl中的投影和视口变换/// Select the modelview matrixgl.glMatrixMode(GL10.GL_MODELVIEW); -----------选择模型观察矩阵// Reset the modelview matrixgl.glLoadIdentity();---------------------------重置模型观察矩阵

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

(3) onDrawFrame

绘制屏幕中的图形。

// 重置当前的模型观察矩阵gl.glLoadIdentity();// 左移 1.5 单位,并移入屏幕 6.0gl.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.0gl.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就是剔除的意思


原创粉丝点击