OpenGL ES系列(5--3D立体图形)
转自:http://www.guidebee.info/wordpress/archives/1554
前面的例子尽管使用了OpenGL ES 3D图形库,但绘制的还是二维图形(平面上的正方形)。Mesh(网格,三角面)是构成空间形体的基本元素,前面的正方形也是有两个Mesh构成的。本篇将介绍使用Mesh构成四面体,椎体等基本空间形体。
Design设计
在使用OpenGL 框架时一个好的设计原则是使用“Composite
Pattern”,本篇采用如下设计:
Mesh
首先定义一个基类 Mesh,所有空间形体最基本的构成元素为Mesh(三角形网格) ,其基本定义如下:
|
|
private FloatBuffer
verticesBuffer = null;
|
|
|
private ShortBuffer
indicesBuffer = null;
|
|
|
//
The number of indices.
|
|
|
private int numOfIndices
= -1;
|
|
|
= new float[]
{ 1.0f, 1.0f, 1.0f, 1.0f
};
|
|
|
private FloatBuffer
colorBuffer = null;
|
|
|
public void draw(GL10
gl) {
|
|
|
//
Counter-clockwise winding.
|
|
|
gl.glFrontFace(GL10.GL_CCW);
|
|
|
gl.glEnable(GL10.GL_CULL_FACE);
|
|
|
//
What faces to remove with the face culling.
|
|
|
gl.glCullFace(GL10.GL_BACK);
|
|
|
//
Enabled the vertices buffer for writing and
|
|
|
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
|
|
|
//
Specifies the location and data format
|
|
|
//
coordinates to use when rendering.
|
|
|
gl.glVertexPointer(3,
GL10.GL_FLOAT, 0,
verticesBuffer);
|
|
|
gl.glColor4f(rgba[0],
rgba[1],
rgba[2],
rgba[3]);
|
|
|
if (colorBuffer
!= null)
{
|
|
|
//
Enable the color array buffer to be
|
|
|
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
|
|
|
gl.glColorPointer(4,
GL10.GL_FLOAT, 0,
colorBuffer);
|
|
|
gl.glTranslatef(x,
y, z);
|
|
|
gl.glRotatef(rx, 1, 0, 0);
|
|
|
gl.glRotatef(ry, 0, 1, 0);
|
|
|
gl.glRotatef(rz, 0, 0, 1);
|
|
|
//
Point out the where the color buffer is.
|
|
|
gl.glDrawElements(GL10.GL_TRIANGLES,
numOfIndices,
|
|
|
GL10.GL_UNSIGNED_SHORT,
indicesBuffer);
|
|
|
//
Disable the vertices buffer.
|
|
|
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
|
|
|
gl.glDisable(GL10.GL_CULL_FACE);
|
|
|
protected void setVertices(float[]
vertices) {
|
|
|
//
a float is 4 bytes, therefore
|
|
|
//we
multiply the number if
|
|
|
=
ByteBuffer.allocateDirect(vertices.length * 4);
|
|
|
vbb.order(ByteOrder.nativeOrder());
|
|
|
verticesBuffer
= vbb.asFloatBuffer();
|
|
|
verticesBuffer.put(vertices);
|
|
|
verticesBuffer.position(0);
|
|
|
protected void setIndices(short[]
indices) {
|
|
|
//
short is 2 bytes, therefore we multiply
|
|
|
=
ByteBuffer.allocateDirect(indices.length * 2);
|
|
|
ibb.order(ByteOrder.nativeOrder());
|
|
|
indicesBuffer
= ibb.asShortBuffer();
|
|
|
indicesBuffer.put(indices);
|
|
|
indicesBuffer.position(0);
|
|
|
numOfIndices
= indices.length;
|
|
|
protected void setColor(float red, float green,
|
|
|
float blue, float alpha)
{
|
|
|
//
Setting the flat color.
|
|
|
protected void setColors(float[]
colors) {
|
|
|
=
ByteBuffer.allocateDirect(colors.length * 4);
|
|
|
cbb.order(ByteOrder.nativeOrder());
|
|
|
colorBuffer
= cbb.asFloatBuffer();
|
-
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类的定义如下:
|
|
public class Plane extends Mesh
{
|
|
|
public Plane(float width, float height)
{
|
|
|
this(width,
height, 1, 1);
|
|
|
public Plane(float width, float height, int widthSegments,
|
|
|
= new float[(widthSegments
+ 1)
|
|
|
*
(heightSegments + 1)
* 3];
|
|
|
= new short[(widthSegments
+ 1)
|
|
|
*
(heightSegments + 1)* 6];
|
|
|
float xOffset
= width / -2;
|
|
|
float yOffset
= height / -2;
|
|
|
float xWidth
= width / (widthSegments);
|
|
|
float yHeight
= height / (heightSegments);
|
|
|
short w
= (short)
(widthSegments + 1);
|
|
|
for (int y
= 0;
y < heightSegments + 1;
y++) {
|
|
|
for (int x
= 0;
x < widthSegments + 1;
x++) {
|
|
|
vertices[currentVertex]
= xOffset + x * xWidth;
|
|
|
vertices[currentVertex
+ 1]
= yOffset + y * yHeight;
|
|
|
vertices[currentVertex
+ 2]
= 0;
|
|
|
int n
= y * (widthSegments + 1)
+ x;
|
|
|
if (y
< heightSegments && x < widthSegments) {
|
|
|
indices[currentIndex]
= (short)
n;
|
|
|
indices[currentIndex
+ 1]
= (short)
(n + 1);
|
|
|
indices[currentIndex
+ 2]
= (short)
(n + w);
|
|
|
indices[currentIndex
+ 3]
= (short)
(n + 1);
|
|
|
indices[currentIndex
+ 4]
= (short)
(n + 1 +
w);
|
|
|
indices[currentIndex
+ 5]
= (short)
(n + 1 +
w - 1);
|
Cube
下面来定义一个正方体(Cube),为简单起见,这个四面体只可以设置宽度,高度,和深度,没有和Plane一样提供Segments支持。
|
|
public class Cube extends Mesh
{
|
|
|
public Cube(float width, float height, float depth)
{
|
|
|
float vertices[]
= { -width, -height, -depth, //
0
|
|
|
width,
-height, -depth, //
1
|
|
|
width,
height, -depth, //
2
|
|
|
-width,
height, -depth, //
3
|
|
|
-width,
-height, depth, //
4
|
|
|
width,
-height, depth, //
5
|
|
|
width,
height, depth, //
6
|
|
|
-width,
height, depth, //
7
|
|
|
short indices[]
= { 0, 4, 5,
|
Group
Group可以用来管理多个空间几何形体,如果把Mesh比作Android的View ,Group可以看作Android的ViewGroup,Android的View的设计也是采用的“Composite Pattern”。
Group的主要功能是把针对Group的操作(如draw)分发到Group中的每个成员对应的操作(如draw)。
Group定义如下:
|
|
public class Group extends Mesh
{
|
|
|
private Vector<Mesh>
children = new Vector<Mesh>();
|
|
|
public void draw(GL10
gl) {
|
|
|
int size
= children.size();
|
|
|
for( int i
= 0;
i < size; i++)
|
|
|
children.get(i).draw(gl);
|
|
|
*
@see java.util.Vector#add(int, java.lang.Object)
|
|
|
public void add(int location,
Mesh object) {
|
|
|
children.add(location,
object);
|
|
|
*
@see java.util.Vector#add(java.lang.Object)
|
|
|
public boolean add(Mesh
object) {
|
|
|
return children.add(object);
|
|
|
*
@see java.util.Vector#clear()
|
|
|
*
@see java.util.Vector#get(int)
|
|
|
public Mesh
get(int location)
{
|
|
|
return children.get(location);
|
|
|
*
@see java.util.Vector#remove(int)
|
|
|
public Mesh
remove(int location)
{
|
|
|
return children.remove(location);
|
|
|
*
@see java.util.Vector#remove(java.lang.Object)
|
|
|
public boolean remove(Object
object) {
|
|
|
return children.remove(object);
|
|
|
*
@see java.util.Vector#size()
|
其它建议
上面我们定义里Mesh, Plane, Cube等基本空间几何形体,对于构造复杂图形(如人物),可以预先创建一些通用的几何形体,如果在组合成较复杂的形体。除了上面的基本形体外,可以创建如Cone,Pryamid, Cylinder等基本形体以备后用。
本例示例代码下载,显示结果如下:
