Android开发 之 OpenGL ES系列(2--基本概念)
来源:互联网 发布:昆山宏观数据库 编辑:程序博客网 时间:2024/06/06 01:45
基本概念
前面介绍了使用Android 编写OpenGL ES应用的程序框架,本篇介绍3D绘图的一些基本构成要素,最终将实现一个多边形的绘制。
一个3D图形通常是由一些小的基本元素(顶点,边,面,多边形)构成,每个基本元素都可以单独来操作。
一个3D图形通常是由一些小的基本元素(顶点,边,面,多边形)构成,每个基本元素都可以单独来操作。
顶点:
在Android系统中可以使用一个浮点数数组来定义一个顶点,浮点数数组通常放在一个Buffer(java.nio)中来提高性能。
比如:下图中定义了四个顶点和对应的Android 顶点定义:坐标系是三维的x,y,z
比如:下图中定义了四个顶点和对应的Android 顶点定义:坐标系是三维的x,y,z
private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, Top Left -1.0f, -1.0f, 0.0f, // 1, Bottom Left 1.0f, -1.0f, 0.0f, // 2, Bottom Right 1.0f, 1.0f, 0.0f, // 3, Top Right};这里z轴都是0.0。为了提高性能,通常将这些数组存放到java.io 中定义的Buffer类中:
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);vbb.order(ByteOrder.nativeOrder());FloatBuffer vertexBuffer = vbb.asFloatBuffer();vertexBuffer.put(vertices);vertexBuffer.position(0);
有了顶点的定义,下面一步就是如何将它们传给OpenGL ES库,OpenGL ES提供一个成为”管道Pipeline”的机制,这个管道定义了一些“开关”来控制OpenGL ES支持的某些功能,缺省情况这些功能是关闭的,如果需要使用OpenGL ES的这些功能,需要明确告知OpenGL “管道”打开所需功能。因此对于我们的这个示例,需要告诉OpenGL库打开 Vertex buffer以便传入顶点坐标Buffer。要注意的使用完某个功能之后,要关闭这个功能以免影响后续操作:
//启用用于写入的顶点缓冲区,并在渲染期间使用。 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //指定渲染时要使用的顶点坐标数组的位置和数据格式。 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); gl.glDrawElements(GL10.GL_TRIANGLES, drawOrder.length, GL10.GL_UNSIGNED_SHORT, drawListBuffer); // 禁用顶点缓冲区。 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 禁用脸部剔除。 gl.glDisable(GL10.GL_CULL_FACE);
Edge(边)
边定义为两个顶点之间的线段。边是面和多边形的边界线。在3D模型中,边可以被相邻的两个面或是多边形形共享。对一个边做变换将影响边相接的所有顶点,面或多边形。在OpenGL中,通常无需直接来定义一个边,而是通过顶点定义一个面,从而由面定义了其所对应的三条边。可以通过修改边的两个顶点来更改一条边
边定义为两个顶点之间的线段。边是面和多边形的边界线。在3D模型中,边可以被相邻的两个面或是多边形形共享。对一个边做变换将影响边相接的所有顶点,面或多边形。在OpenGL中,通常无需直接来定义一个边,而是通过顶点定义一个面,从而由面定义了其所对应的三条边。可以通过修改边的两个顶点来更改一条边
Face (面)
在OpenGL ES中,面特指一个三角形,由三个顶点和三条边构成,对一个面所做的变化影响到连接面的所有顶点和边,面多边形。下图黄色区域代表一个面。
在OpenGL ES中,面特指一个三角形,由三个顶点和三条边构成,对一个面所做的变化影响到连接面的所有顶点和边,面多边形。下图黄色区域代表一个面。
定义面的顶点的顺序很重要 在拼接曲面的时候,用来定义面的顶点的顺序非常重要,因为顶点的顺序定义了面的朝向(前向或是后向),为了获取绘制的高性能,一般情况不会绘制面的前面和后面,只绘制面的“前面”。虽然“前面”“后面”的定义可以应人而易,但一般为所有的“前面”定义统一的顶点顺序(顺时针或是逆时针方向)。
下面代码设置逆时针方法为面的“前面”gl.glFrontFace(GL10.GL_CCW);打开 忽略“后面”设置:gl.glEnable(GL10.GL_CULL_FACE);明确指明“忽略“哪个面的代码如下:gl.glCullFace(GL10.GL_BACK);
Polygon (多边形)
多边形由多个面(三角形)拼接而成,在三维空间上,多边形并一定表示这个Polygon在同一平面上。这里我们使用缺省的逆时针方向代表面的“前面Front),下图黄色区域为一个多边形。
来看一个多边形的示例在Android系统如何使用顶点和buffer 来定义,如下图定义了一个正方形:
对应的顶点和buffer 定义代码:
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // 画顶点 // 初始化字节缓冲区的画 ByteBuffer dlb = ByteBuffer.allocateDirect( // 坐标值(# * 2字节/短) drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0);
Render (渲染)
我们已定义好了多边形,下面就要了解如和使用OpenGL ES的API来绘制(渲染)这个多边形了。OpenGL ES提供了两类方法来绘制一个空间几何图形:
public abstract void glDrawArrays(int mode, int first, int count) 使用VetexBuffer 来绘制,顶点的顺序由vertexBuffer中的顺序指定。
public abstract void glDrawElements(int mode, int count, int type, Buffer indices) ,可以重新定义顶点的顺序,顶点的顺序由indices Buffer 指定。
前面我们已定义里顶点数组,因此我们将采用glDrawElements 来绘制多边形。
同样的顶点,可以定义的几何图形可以有所不同,比如三个顶点,可以代表三个独立的点,也可以表示一个三角形,这就需要使用mode 来指明所需绘制的几何图形的基本类型。
GL_POINTS
绘制独立的点。
GL_LINE_STRIP
绘制一系列线段。
GL_LINE_LOOP
类同上,但是首尾相连,构成一个封闭曲线。
GL_LINES
顶点两两连接,为多条线段构成。
GL_TRIANGLES
每隔三个顶点构成一个三角形,为多个三角形组成。
GL_TRIANGLE_STRIP
每相邻三个顶点组成一个三角形,为一系列相接三角形构成。
GL_TRIANGLE_FAN
以一个点为三角形公共顶点,组成一系列相邻的三角形。
public class OpenGlActivity extends AppCompatActivity { private GLSurfaceView mGLView; private MyGLRenderer mRenderer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new GLSurfaceView(this); mRenderer = new MyGLRenderer(); mGLView.setRenderer(mRenderer);//设置glview的监听。 mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);//仅在绘图数据发生更改时渲染视图 setContentView(mGLView); }}
public class MyGLRenderer implements GLSurfaceView.Renderer { private Square square; //调用一次以建立视图的OpenGL ES的环境。 public void onSurfaceCreated(GL10 gl, EGLConfig config) { square = new Square(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 启用平滑着色,默认不是真的需要。 gl.glShadeModel(GL10.GL_SMOOTH); // 深度缓冲区设置。 gl.glClearDepthf(1.0f); // 启用深度测试。 gl.glEnable(GL10.GL_DEPTH_TEST); // 深度测试的类型要做。 gl.glDepthFunc(GL10.GL_LEQUAL); // 真的很好的透视计算。 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); } //被叫为视图的每个重绘。 public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //防止每次都再向后移动4个单位,需要加上重置Matrix的代码。 gl.glLoadIdentity(); //这是因为OpenGL ES从当前位置开始渲染,缺省坐标为(0,0,0),和View port 的坐标一样,相当于把画面放在眼前, // 对应这种情况OpenGL不会渲染离view Port很近的画面,因此我们需要将画面向后退一点距离: gl.glTranslatef(0,0,-4); square.draw(gl); } //如果认为变化的几何形状,例如,设备的屏幕取向的改变时 public void onSurfaceChanged(GL10 gl, int width, int height) { // 将当前视图端口设置为新大小。 gl.glViewport(0, 0, width, height);// OpenGL docs. // 选择投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION);// OpenGL docs. // 重置投影矩阵 gl.glLoadIdentity();// OpenGL docs. // 计算窗口的宽高比 GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f); // 选择modelview矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW);// OpenGL docs. // 重置modelview矩阵 gl.glLoadIdentity();// OpenGL docs. }}
public class Square { private FloatBuffer vertexBuffer; private ShortBuffer drawListBuffer; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f }; // top right private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // 画顶点 public Square() { ByteBuffer bb = ByteBuffer.allocateDirect( squareCoords.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); // 初始化字节缓冲区的画 ByteBuffer dlb = ByteBuffer.allocateDirect( // 坐标值(# * 2字节/短) drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); } /** * This function draws our square on screen. * @param gl */ public void draw(GL10 gl) { // Counter-clockwise winding.逆时针绕组。 gl.glFrontFace(GL10.GL_CCW); // Enable face culling.启用脸部剔除。 gl.glEnable(GL10.GL_CULL_FACE); // 面部剔除 gl.glCullFace(GL10.GL_BACK); //启用用于写入的顶点缓冲区,并在渲染期间使用。 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //指定渲染时要使用的顶点坐标数组的位置和数据格式。 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); //渲染图像 gl.glDrawElements(GL10.GL_TRIANGLES, drawOrder.length, GL10.GL_UNSIGNED_SHORT, drawListBuffer); // 禁用顶点缓冲区。 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 禁用脸部剔除。 gl.glDisable(GL10.GL_CULL_FACE); }}
阅读全文
0 0
- Android开发 之 OpenGL ES系列(2--基本概念)
- OpenGL ES之Android 3D系列基本概念
- Android开发 之 OpenGL ES系列(3--坐标系)
- Android开发 之 OpenGL ES系列(4--添加颜色)
- Android开发 之 OpenGL ES系列(1--创建显示环境)
- Android开发 之 OpenGL ES系列(5--3D立体图形)
- Android OpenGL ES 绘图基本概念
- Android OpenGL ES 简明开发教程_3D绘图基本概念
- Android OpenGL ES 开发教程(2):关于OpenGL ES
- Android OpenGL ES 开发教程(2):关于OpenGL ES
- Android OpenGL ES 开发教程(2):关于OpenGL ES
- Android OpenGL ES 开发(二): OpenGL ES 环境搭建
- Android开发之OpenGL+ES教程
- Android开发之OpenGL+ES教程
- Android OpenGL ES 2.0之开发流程
- android OpenGL ES开发之前世今生
- android OpenGL ES开发之shader
- Android基础系列-----------OpenGL ES(一)
- 高二&高一模拟赛12 总结
- 《嵌入式开发探秘》之第二章 开发环境搭建(1)
- python实现自编码器autoencode
- C#中的Builder模式
- 老毛桃啊老毛桃
- Android开发 之 OpenGL ES系列(2--基本概念)
- Qt模型/视图
- 牛顿迭代法 && 高斯牛顿法
- [编程题] 买苹果
- TCP的三次握手和四次挥手,以及两次握手为什么不行?
- bzoj 5018: [Snoi2017]英雄联盟
- C语言函数可变参数处理简介
- centos详细命令(自己收藏)
- 学生选课系统数据库SQL语句考试题