Android OpenGL ES 简明开发教程 06 <真正的3D图形>
来源:互联网 发布:mvc索引超出数组界限 编辑:程序博客网 时间:2024/05/17 06:24
前面的例子尽管使用了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 简明开发教程 06 <真正的3D图形>
- Android OpenGL ES 简明开发教程六: 真正的3D图形
- Android OpenGL ES 简明开发教程六: 真正的3D图形
- Android OpenGL ES 简明开发教程六: 真正的3D图形
- Android OpenGL ES 简明开发教程六: 真正的3D图形
- Android OpenGL ES 简明开发教程六:真正的3D图形
- Android OpenGL ES 简明开发教程_真正的3D图形
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Android OpenGL ES 简明开发教程四:3D 坐标变换
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Android OpenGL ES 简明开发教程四:3D 坐标变换
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Android OpenGL ES 简明开发教程四:3D 坐标变换
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Android OpenGL ES 简明开发教程四:3D 坐标变换
- Android OpenGL ES 简明开发教程四:3D 坐标变换
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Android OpenGL ES 简明开发教程 03 <3D绘图基本概念>
- Linux命令大全
- Linux系统新手学习建议
- 取类别区分的TOP10 by Access(学习备注)
- 懒惰是金
- 关于sort()的使用
- Android OpenGL ES 简明开发教程 06 <真正的3D图形>
- MySql常用命令总结
- ffmpeg解析
- 关于PHP字符串自动转换数字的一些总结
- linux下查看用户及用户组的方法
- Is -A 与Has - A
- java入门必读(二)
- 查看mysql数据库字符集
- JavaScript alert()函数详细使用说明