android opengl floatbuffer
16lz
2021-01-23
Android沿用了J2ME的OPENGL ES API.
相比C版本的OpenGL,Opengl ES 没有glu和glut库,而且只能画三角形(多边形需要三角化)。
没有直接的drawXXX 方法,只有通过 glVertiexPointer传入顶点画图。
另外参数上,没有指针和C风格的数组,Java需要用Buffer类来代替这个。
先看android的glVertexPointer :
GL10.glVertexPointer(int size, int type, int stride, Buffer pointer):这个方法为 后面openGL绘图准备顶点数据。
size : 代表每个顶点包含几个坐标参数 ,如pointer的buffer中只含有 x,y坐标, 则传2, OpenGL会默认使用0作为z坐标。如果包含 x,y,z 坐标,则传3。其他值在这里都不适用。 type : 是一个枚举值,可以为 GL_FLOAT和 GL_FIXED,浮点数可对应java 的 float,要求pointer为 FloatBuffer. GL_FIXED意为定点数,长度4字节,高16位表示整数部分,低16位表示小数部分。传入int值前需要先左移16位(即需扩大 0x10000倍)。要求pointer为IntBuffer. stride :指每个元素之间,间隔多少个值。加入buffer中坐标点数值间紧密相连,那么stride就是0,如果点1,点2间还有不用到的值,则stride就是这种值的个数。 pointer:这是最需要注意的一个参数,也是Java版OpenGL特有的。Buffer类型是一个基类,具体的类型是 FloatBuffer还是IntBuffer要根据前面type参数来决定。 Java中的 Buffer分两种,一种direct,一种非direct.这里只支持 DirectBuffer,也就是通过ByteBuffer.allocateDirect(int cap) 分配而来的buffer. 通过allocateDirect 得到的是一个 ByteBuffer,实际使用时,如果要作为FloatBuffer,可以通过 ByteBuffer.asFloatBuffer来得到,IntBuffer也同样。 做到这些当然还不够,ByteOrder也对这个参数有影响。当的ByteBuffer作为FloatBuffer,则float的4字节默认是按照小端排列在directBuffer中,在 某些大端的设备中这个buffer的格式就不正确,需要根据设备设置ByteOrder. 所以以FloatBuffer为例,创建方法如下: FloatBuffer buffer = ByteBuffer.allocateDirect(1024).order(ByteOrder.nativeOrder()).asFloatBuffer(); 有了FloatBuffer,我们还需要将实际顶点坐标传入这个buffer。这只需要调用 FloatBuffer.put(float)的方法即可。 注意放顶点坐标是x,y...的格式,还是x,y,z...的格式要和前面第一个参数 size是2还是3统一。 所有的值放完以后,需要调用 buffer.rewind()或者 buffer.position(0),将buffer内游标置回0,否则OpenGL会从最后一次put的下一个位置开始读取。 关于三角化的算法: Android的OpenGL API 画多边形目前只支持 triangle_fan,triangles, triangle_strip 三种。如果只有简单无洞的凸多边形,只需要将所有点当作triangle_fan的顶点就可以画出。 如果存在凹多边形,就需要进行三角化(当然凸多边形也可以三角化,保持逻辑上的统一)。 有个最简单的三角化算法叫做 ear clipping三角化。几何上非常容易理解: 一个多边形的一个顶点,和它相邻两个顶点可以组成一个三角形,如果这个三角形内部不存在这个多边形的其他顶点,就可以把这个顶点和相邻点组成的三角形当作一个ear. 这个ear可以被切下来(沿两个相邻顶点切)。每切一次,得到一个三角形和一个少了一个顶点的多边形,然后再对这个多边形做同样操作,直到剩下的这个多边形也只剩下3个顶点。 如此一来,这个多边形被完全分解为3角形。 要把把几何上的操作变成代码,只要解决这几个问题: #如何判断多边形的一串顶点是逆时针还是顺时针排列的? - 从某个顶点指向它下一个顶点,可以得到一个向量,多边形有几条边就得到几个向量,如果所有相邻两个向量的叉积(前一个向量和后一个向量的叉积)之和大于0,则排列是逆时针的,反之是顺时针的 (根据右手坐标系判断,一系列逆时针向量围成的面积是指向z轴正向的),为0有两种情况,这串点是直线,或者多边形某两条边交叉,这种多变形不符合这个三角化算法的条件。 #根据顶点顺逆情况,调整顶点排列,保证逆时针排序,则可以得到如下结论: - 如果相邻两个向量,前一个向量和后一个向量叉积,值为正,则两个向量连接点这个顶点是凸点,值为负则为凹点。 - 如果有相邻3个顶点 p1,p2,p3 组成三角形,有另外一个顶点 P,如何判断P是否在三角形内? 分别做如下几个叉积p2P X p1p2, p3P X p2p3 , p1P X p3p1 ,如果这3个叉积同为正或同为负,则这个顶点在三角形内部。 关于 glEnableClientState, glDisableClientState, glEnableClientState(int cap); cap : GL_COLOR_ARRAY GL_EDGE_FLAG_ARRAY GL_FOG_COORD_ARRAY GL_INDEX_ARRAY GL_NORMAL_ARRAY GL_SECONDARY_COLOR_ARRAY GL_TEXTURE_COORD_ARRAY GL_VERTEX_ARRAY 是用来启用或者关闭和这些数组功能。 如同前面的glVertexPointer ,还有别的诸如 glColorPointer, glEdgeFlagPointer等等接口, glVertexPointer描述顶点位置,其他的描述顶点或者平面的属性。 这些数组默认都是disable状态,如果用这两个接口enable了某个数组,那么当glDrawArrays 调用之前必须把相应的数组准备好。否则draw不能成功。 所以如果不准备传入某个数组,draw之前要先 disable这个数组(如果前面enable过)。 反之如果要使用某个数组,也要事先enable。还有Java中缺少的API,比如没有glPerspective的时候如何用glFrustm实现glPerspective,以及没有gluLookAt的时候如何用modelView来得到同样效果。将在之后文章里面解说。
更多相关文章
- Android填充多边形
- Android OpenGL入门示例:绘制三角形和正方形 (附完整源码)
- Android 3D 旋转的三角形(一)
- Android drawable 三角形
- Android下使用OpenGL绘制三角形
- Android svg 绘制三角形
- Android 3D 旋转的三角形(二)
- Android 3D 旋转的三角形(四)
- Android 3D 旋转的三角形(三)