Android开发 之 OpenGL ES系列(5--3D立体图形)
OpenGL ES系列(5--3D立体图形)
转自:http://www.guidebee.info/wordpress/archives/1554
前面的例子尽管使用了OpenGL ES 3D图形库,但绘制的还是二维图形(平面上的正方形)。Mesh(网格,三角面)是构成空间形体的基本元素,前面的正方形也是有两个Mesh构成的。本篇将介绍使用Mesh构成四面体,椎体等基本空间形体。
Design设计
在使用OpenGL 框架时一个好的设计原则是使用“Composite Pattern”,本篇采用如下设计:
Mesh
首先定义一个基类 Mesh,所有空间形体最基本的构成元素为Mesh(三角形网格) ,其基本定义如下:
1
|
public class Mesh {
|
2
|
// Our vertex buffer.
|
3
|
private FloatBuffer verticesBuffer = null ;
|
4
|
5
|
// Our index buffer.
|
6
|
private ShortBuffer indicesBuffer = null ;
|
7
|
8
|
// The number of indices.
|
9
|
private int numOfIndices = - 1 ;
|
10
|
11
|
// Flat Color
|
12
|
private float [] rgba
|
13
|
= new float [] { 1 .0f, 1 .0f, 1 .0f, 1 .0f };
|
14
|
15
|
// Smooth Colors
|
16
|
private FloatBuffer colorBuffer = null ;
|
17
|
18
|
// Translate params.
|
19
|
public float x = 0 ;
|
20
|
21
|
public float y = 0 ;
|
22
|
23
|
public float z = 0 ;
|
24
|
25
|
// Rotate params.
|
26
|
public float rx = 0 ;
|
27
|
28
|
public float ry = 0 ;
|
29
|
30
|
public float rz = 0 ;
|
31
|
32
|
public void draw(GL10 gl) {
|
33
|
// Counter-clockwise winding.
|
34
|
gl.glFrontFace(GL10.GL_CCW);
|
35
|
// Enable face culling.
|
36
|
gl.glEnable(GL10.GL_CULL_FACE);
|
37
|
// What faces to remove with the face culling.
|
38
|
gl.glCullFace(GL10.GL_BACK);
|
39
|
// Enabled the vertices buffer for writing and
|
40
|
//to be used during
|
41
|
// rendering.
|
42
|
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
|
43
|
// Specifies the location and data format
|
44
|
//of an array of vertex
|
45
|
// coordinates to use when rendering.
|
46
|
gl.glVertexPointer( 3 , GL10.GL_FLOAT, 0 , verticesBuffer);
|
47
|
// Set flat color
|
48
|
gl.glColor4f(rgba[ 0 ], rgba[ 1 ], rgba[ 2 ], rgba[ 3 ]);
|
49
|
// Smooth color
|
50
|
if (colorBuffer != null ) {
|
51
|
// Enable the color array buffer to be
|
52
|
//used during rendering.
|
53
|
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
|
54
|
gl.glColorPointer( 4 , GL10.GL_FLOAT, 0 , colorBuffer);
|
55
|
}
|
56
|
57
|
gl.glTranslatef(x, y, z);
|
58
|
gl.glRotatef(rx, 1 , 0 , 0 );
|
59
|
gl.glRotatef(ry, 0 , 1 , 0 );
|
60
|
gl.glRotatef(rz, 0 , 0 , 1 );
|
61
|
62
|
// Point out the where the color buffer is.
|
63
|
gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices,
|
64
|
GL10.GL_UNSIGNED_SHORT, indicesBuffer);
|
65
|
// Disable the vertices buffer.
|
66
|
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
|
67
|
// Disable face culling.
|
68
|
gl.glDisable(GL10.GL_CULL_FACE);
|
69
|
}
|
70
|
71
|
protected void setVertices( float [] vertices) {
|
72
|
// a float is 4 bytes, therefore
|
73
|
//we multiply the number if
|
74
|
// vertices with 4.
|
75
|
ByteBuffer vbb
|
76
|
= ByteBuffer.allocateDirect(vertices.length * 4 );
|
77
|
vbb.order(ByteOrder.nativeOrder());
|
78
|
verticesBuffer = vbb.asFloatBuffer();
|
79
|
verticesBuffer.put(vertices);
|
80
|
verticesBuffer.position( 0 );
|
81
|
}
|
82
|
83
|
protected void setIndices( short [] indices) {
|
84
|
// short is 2 bytes, therefore we multiply
|
85
|
//the number if
|
86
|
// vertices with 2.
|
87
|
ByteBuffer ibb
|
88
|
= ByteBuffer.allocateDirect(indices.length * 2 );
|
89
|
ibb.order(ByteOrder.nativeOrder());
|
90
|
indicesBuffer = ibb.asShortBuffer();
|
91
|
indicesBuffer.put(indices);
|
92
|
indicesBuffer.position( 0 );
|
93
|
numOfIndices = indices.length;
|
94
|
}
|
95
|
96
|
protected void setColor( float red, float green,
|
97
|
float blue, float alpha) {
|
98
|
// Setting the flat color.
|
99
|
rgba[ 0 ] = red;
|
100
|
rgba[ 1 ] = green;
|
101
|
rgba[ 2 ] = blue;
|
102
|
rgba[ 3 ] = alpha;
|
103
|
}
|
104
|
105
|
protected void setColors( float [] colors) {
|
106
|
// float has 4 bytes.
|
107
|
ByteBuffer cbb
|
108
|
= ByteBuffer.allocateDirect(colors.length * 4 );
|
109
|
cbb.order(ByteOrder.nativeOrder());
|
110
|
colorBuffer = cbb.asFloatBuffer();
|
111
|
colorBuffer.put(colors);
|
112
|
colorBuffer.position( 0 );
|
113
|
}
|
114
|
}
|
- setVertices 允许子类重新定义顶点坐标。
- setIndices 允许子类重新定义顶点的顺序。
- setColor /setColors允许子类重新定义颜色。
- x,y,z 定义了平移变换的参数。
- rx,ry,rz 定义旋转变换的参数。
Plane
有了Mesh定义之后,再来构造Plane,plane可以有宽度,高度和深度,宽度定义为沿X轴方向的长度,深度定义为沿Z轴方向长度,高度为Y轴方向。
Segments为形体宽度,高度,深度可以分成的份数。 Segments在构造一个非均匀分布的Surface特别有用,比如在一个游戏场景中,构造地貌,使的Z轴的值随机分布在-0.1到0.1之间,然后给它渲染好看的材质就可以造成地图凹凸不平的效果。
上面图形中Segments为一正方形,但在OpenGL中我们需要使用三角形,所有需要将Segments分成两个三角形。为Plane 定义两个构造函数:
// Let you decide the size of the plane but still only one segment.
public Plane(float width, float height)
// For alla your settings.
public Plane(float width, float height, int widthSegments, int heightSegments)
比如构造一个1 unit 宽和 1 unit高,并分成4个Segments,使用图形表示如下:
左边的图显示了segments ,右边的图为需要创建的Face(三角形)。
Plane类的定义如下:
1
|
public class Plane extends Mesh {
|
2
|
public Plane() {
|
3
|
this ( 1 , 1 , 1 , 1 );
|
4
|
}
|
5
|
6
|
public Plane( float width, float height) {
|
7
|
this (width, height, 1 , 1 );
|
8
|
}
|
9
|
10
|
public Plane( float width, float height, int widthSegments,
|
11
|
int heightSegments) {
|
12
|
float [] vertices
|
13
|
= new float [(widthSegments + 1 )
|
14
|
* (heightSegments + 1 ) * 3 ];
|
15
|
short [] indices
|
16
|
= new short [(widthSegments + 1 )
|
17
|
* (heightSegments + 1 )* 6 ];
|
18
|
19
|
float xOffset = width / - 2 ;
|
20
|
float yOffset = height / - 2 ;
|
21
|
float xWidth = width / (widthSegments);
|
22
|
float yHeight = height / (heightSegments);
|
23
|
int currentVertex = 0 ;
|
24
|
int currentIndex = 0 ;
|
25
|
short w = ( short ) (widthSegments + 1 );
|
26
|
for ( int y = 0 ; y < heightSegments + 1 ; y++) {
|
27
|
for ( int x = 0 ; x < widthSegments + 1 ; x++) {
|
28
|
vertices[currentVertex] = xOffset + x * xWidth;
|
29
|
vertices[currentVertex + 1 ] = yOffset + y * yHeight;
|
30
|
vertices[currentVertex + 2 ] = 0 ;
|
31
|
currentVertex += 3 ;
|
32
|
33
|
int n = y * (widthSegments + 1 ) + x;
|
34
|
35
|
if (y < heightSegments && x < widthSegments) {
|
36
|
// Face one
|
37
|
indices[currentIndex] = ( short ) n;
|
38
|
indices[currentIndex + 1 ] = ( short ) (n + 1 );
|
39
|
indices[currentIndex + 2 ] = ( short ) (n + w);
|
40
|
// Face two
|
41
|
indices[currentIndex + 3 ] = ( short ) (n + 1 );
|
42
|
indices[currentIndex + 4 ] = ( short ) (n + 1 + w);
|
43
|
indices[currentIndex + 5 ] = ( short ) (n + 1 + w - 1 );
|
44
|
45
|
currentIndex += 6 ;
|
46
|
}
|
47
|
}
|
48
|
}
|
49
|
50
|
setIndices(indices);
|
51
|
setVertices(vertices);
|
52
|
}
|
53
|
}
|
Cube
下面来定义一个正方体(Cube),为简单起见,这个四面体只可以设置宽度,高度,和深度,没有和Plane一样提供Segments支持。
1
|
public class Cube extends Mesh {
|
2
|
public Cube( float width, float height, float depth) {
|
3
|
width /= 2 ;
|
4
|
height /= 2 ;
|
5
|
depth /= 2 ;
|
6
|
7
|
float vertices[] = { -width, -height, -depth, // 0
|
8
|
width, -height, -depth, // 1
|
9
|
width, height, -depth, // 2
|
10
|
-width, height, -depth, // 3
|
11
|
-width, -height, depth, // 4
|
12
|
width, -height, depth, // 5
|
13
|
width, height, depth, // 6
|
14
|
-width, height, depth, // 7
|
15
|
};
|
16
|
17
|
short indices[] = { 0 , 4 , 5 ,
|
18
|
0 , 5 , 1 ,
|
19
|
1 , 5 , 6 ,
|
20
|
1 , 6 , 2 ,
|
21
|
2 , 6 , 7 ,
|
22
|
2 , 7 , 3 ,
|
23
|
3 , 7 , 4 ,
|
24
|
3 , 4 , 0 ,
|
25
|
4 , 7 , 6 ,
|
26
|
4 , 6 , 5 ,
|
27
|
3 , 0 , 1 ,
|
28
|
3 , 1 , 2 , };
|
29
|
30
|
setIndices(indices);
|
31
|
setVertices(vertices);
|
32
|
}
|
33
|
}
|
Group
Group可以用来管理多个空间几何形体,如果把Mesh比作Android的View ,Group可以看作Android的ViewGroup,Android的View的设计也是采用的“Composite Pattern”。
Group的主要功能是把针对Group的操作(如draw)分发到Group中的每个成员对应的操作(如draw)。
Group定义如下:
1
|
public class Group extends Mesh {
|
2
|
private Vector<Mesh> children = new Vector<Mesh>();
|
3
|
4
|
@Override
|
5
|
public void draw(GL10 gl) {
|
6
|
int size = children.size();
|
7
|
for ( int i = 0 ; i < size; i++)
|
8
|
children.get(i).draw(gl);
|
9
|
}
|
10
|
11
|
/**
|
12
|
* @param location
|
13
|
* @param object
|
14
|
* @see java.util.Vector#add(int, java.lang.Object)
|
15
|
*/
|
16
|
public void add( int location, Mesh object) {
|
17
|
children.add(location, object);
|
18
|
}
|
19
|
20
|
/**
|
21
|
* @param object
|
22
|
* @return
|
23
|
* @see java.util.Vector#add(java.lang.Object)
|
24
|
*/
|
25
|
public boolean add(Mesh object) {
|
26
|
return children.add(object);
|
27
|
}
|
28
|
29
|
/**
|
30
|
*
|
31
|
* @see java.util.Vector#clear()
|
32
|
*/
|
33
|
public void clear() {
|
34
|
children.clear();
|
35
|
}
|
36
|
37
|
/**
|
38
|
* @param location
|
39
|
* @return
|
40
|
* @see java.util.Vector#get(int)
|
41
|
*/
|
42
|
public Mesh get( int location) {
|
43
|
return children.get(location);
|
44
|
}
|
45
|
46
|
/**
|
47
|
* @param location
|
48
|
* @return
|
49
|
* @see java.util.Vector#remove(int)
|
50
|
*/
|
51
|
public Mesh remove( int location) {
|
52
|
return children.remove(location);
|
53
|
}
|
54
|
55
|
/**
|
56
|
* @param object
|
57
|
* @return
|
58
|
* @see java.util.Vector#remove(java.lang.Object)
|
59
|
*/
|
60
|
public boolean remove(Object object) {
|
61
|
return children.remove(object);
|
62
|
}
|
63
|
64
|
/**
|
65
|
* @return
|
66
|
* @see java.util.Vector#size()
|
67
|
*/
|
68
|
public int size() {
|
69
|
return children.size();
|
70
|
}
|
71
|
72
|
}
|
其它建议
上面我们定义里Mesh, Plane, Cube等基本空间几何形体,对于构造复杂图形(如人物),可以预先创建一些通用的几何形体,如果在组合成较复杂的形体。除了上面的基本形体外,可以创建如Cone,Pryamid, Cylinder等基本形体以备后用。
本例示例代码下载,显示结果如下:
Android开发 之 OpenGL ES系列(5--3D立体图形)相关推荐
- Android 开发使用OpenGL ES绘制三棱锥并进行纹理贴图
效果图: 直接上代码 MainActivity.java的代码 package com.zzu.shiyan3;import androidx.appcompat.app.AppCompatActiv ...
- 在Android中使用OpenGL ES开发第(五)节:GLSL基础语法
一.前期基础储备 笔者之前的四篇文综述了Android中使用OpenGL ES绘制基本图形和实现了简单的相机预览,初次接触OpenGL ES开发的读者可能对其中新的概念比较迷惑,尤其是其中的顶点着色器 ...
- android平台下OpenGL ES 3.0从零开始
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0绘制圆点、直线和三角形
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0绘制纯色背景
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0使用GLSurfaceView对相机Camera预览实时处理
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0实例详解顶点属性、顶点数组
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0绘制立方体的几种方式
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- Android Camera使用OpenGL ES 2.0和TextureView对预览进行实时二次处理(黑白滤镜)
本系列教程会有三篇文章讲解Android平台滤镜的实现方式,希望在阅读本文之前先阅读下述第一篇文档,因为第一篇讲过的知识,本文并不会细讲了. 第一篇 Android Camera使用OpenGL ES ...
最新文章
- skiller v3 beta2_S10全球总决赛:赛前叫嚣却遭打脸!V3被LGD踢出S10,日本撸友彻底炸锅:真是悲哀...
- show status 优化mysql_mysql优化--show status
- jsch设置代理_Java使用JSch组件实现SSH协议代理服务
- 谷歌大佬花了半年整理的Leetcode刷题笔记
- 鲁尼禁赛萨哈一射一传领风骚 曼联客场3-0查尔顿
- s5pv210开发板、原理图、刷机和数据手册
- Linux CentOS 7 安装 Redis
- [计算机系统] - 链接
- 小小的 Python 编程故事
- 统计学习(二):统计推断
- 如何检索综述类文献?
- DTU是什么,什么是工业4G DTU?
- thinkpadt410接口介绍_联想t410配置参数详解
- 邮件群发工具使用说明​
- PAT初级1031(C++)查验身份证
- php拼车网源码,PHP拼车网源码 微信拼车源码 手机拼车源码 PC+微信双终端
- 阿里云ECS服务器被DDoS无解攻击,我改怎么办
- 计算机空格键作用,电脑空格键有哪些作用?你知道几个?
- 亚马逊云(AWS)、微软云(Azure)、阿里云性能对比之哪家好?
- 解决Xubuntu任务栏(Panel)消失的问题
热门文章
- 微信前台WEUI前台实例+EXCEL导出,SSM框架完整流程
- 一台计算机两个硬盘怎么设置密码,怎样给硬盘加密码? 两招解决硬盘加密难题...
- CorelDraw论坛cdr2022V24.0.0301简体中文包
- 微信开放平台开源_开源需要开放徽章的3个原因
- 【数字IC】深入浅出理解I2C协议
- linux centos数据备份,centOS系统的备份与还原
- 移动最快apn服务器,中国移动修改APN为CMTDS提高4G网速
- GB28181系列笔记-语音对讲功能
- c++判断某一天是这一年的第几天
- Oracle数据库-函数总结