Android OpenGL ES(九)----构建几何物体

1.三角形扇


一个三角形扇以一个中心顶点做为起始,使用相邻的两个顶点建立第一个三角形,接下来的每一个顶点都会建立一个三角形,围绕起始的中心点按扇形展开。为了使这个扇形闭合,咱们只须要在最后重复第二个点。(以长方形为例)数组


构建三角形扇的步骤,以下图所示:app

使用OpenGL绘制这个三角形扇,须要在渲染类的onDrawFrame()中,使用以下方法:函数


GLES20.glDrawArray(GLES20.GL_TRIANGLE_FAN,0,6);性能


第一个参数是告诉OpenGL要绘制一个三角形扇,第二参数是告诉OpenGL从本地顶点数据的第几个位置开始取顶点坐标,第三个参数是告诉OpenGL要取多少个顶点坐标。
ui


根据上面的6个点,就能够绘制一个长方形了。this


三角形扇在OpenGL的应用:长方形,正方形,圆等。spa


2.三角形带


一个三角形带的前三个顶点定义了第一个三角形。这以后的每一个额外的顶点都定义了另外的一个三角形。.net


构建三角形带的步骤,以下图所示
对象

 

 



 

使用OpenGL绘制这个三角形带,须要在渲染类的onDrawFrame()中,使用以下方法:接口


GLES20.glDrawArray(GLES20.GL_TRIANGLE_STRIP,0,6);


第一个参数是告诉OpenGL要绘制一个三角形带,第二参数是告诉OpenGL从本地顶点数据的第几个位置开始取顶点坐标,第三个参数是告诉OpenGL要取多少个顶点坐标。


三角形带在OpenGL的应用:长方形,圆柱的侧面等。


3.圆柱体


 

想象一下在本身的手机上构建的圆柱体,而且以一个角度观察它,假如咱们把圆柱放在桌面上,从侧面观察它,你会发现,圆柱体是一个由一个顶部的圆加上侧面卷起来的长方形构成。结合本文前2节的讲解,就能够知道其实就是一个三角形带和三角形扇构建一个圆柱体。


要构建三角形扇,咱们首先定义一个圆心顶点,接着,咱们围绕圆心的点按扇形展开,并把第一个点绕圆周重复两次使其圆闭合。咱们接下来使用三角函数和单位圆的概念生成那个点。



了生成沿一个圆周边的点,咱们首先须要一个循环,它的覆盖范围从0到360度的整个圆,或者0到2π弧度。要找到圆周上的一个点的X的位置,咱们须要调用cos(angle),若是你是放在Z-X平面那么,Z的位置咱们就须要调用sin(angle);咱们用圆的半径缩放这两个位置。这是圆柱上的圆的绘画过程。


若是是圆柱的侧面,咱们就须要看图了解一下,咱们假设圆柱垂直方向以Y为中心,圆柱高height,获得以下图:


 

咱们该怎么用程序绘画出来这个圆柱体呢?其实在OpenGL若是想绘制的图像越清晰,那么它绘制的点就会越多越密集,因此由咱们本身决定绘制这个圆柱体须要多少个顶点。


咱们要计算圆柱体顶部顶点数量的方法做为开始,咱们定义一个求圆柱体上面圆的顶点数的方法,以下:


private static int sizeOfCricleInVertices(int numPoint){

return 1+(numPoint+1);

}


一个圆柱体的顶部是一个用三角形扇构造的圆;它有一个顶点在圆心,围着圆的每一个顶点点都有一个顶点,而且围着圆的顶点要重复两次,才能使圆闭合。


下面是计算圆柱体侧面顶点的数量:


private static int sizeOfOpenCylinderInVertices(int numPoint){

return (numPoints+1)*2;

}


一个圆柱体侧面是一个卷起来的长方形,由一个三角形带构造,围着顶部圆的每一个点都须要两个顶点,而且前两个顶点要重复两次才能使这个管闭合。看三角形带,咱们直指定了上面的点的数量,天然下面的点也要计算进去,因此都须要两个顶点。


添加几何图形的类


咱们要构建几何物体,其实能够分解成几个类,这样便于管理和重用。建立一个新的类,为Geometry,在该类的内部咱们定义一个坐标类,也就是点类:


public static class Point(){

public final float x,y,z;

public Point(float x,float y,float z){

this.x=x;

this.y=y;

this.z=z;

}


public Point translateY(float distance){

return new Point(x,y+distance,z);

}

}


其中有一个辅助函数用于把这个点沿着Y轴平移。咱们也须要给,下面咱们也给圆一个定义,以下,也为Geometry的内部类:


public static class Circle{

private final Point center;

private final float radius;


public Circle(Point center,float radius){

this.center=center;

this.radius=radius;

}


public Circle scale(float scale){

return new Circle(center,radius*scale);

}

}


咱们一样在圆的类里面定义了一个辅助函数,用于缩放圆的半径,最后是给圆柱一个定义,以下:


public static class Cylinder{

public final Point center;

public final float radius;

public finla float height;


public Cylinder(Point center,float radius,float height){

this.center=center;

this.radius=radius;

this.height=height;

}

}


一个圆柱体就像一个扩展的圆,它有一个中心,一个半径和一个高度。

 

你可能注意到了咱们已经把这几个几何物体定义的类定义为不可变的;不管何时改动它,都会返回一个新的对象。这有助于使代码更容易使用和理解。可是当你须要提升性能时,你也许想一直用简单的浮点数组,并用静态函数改变它们。


添加物体构建器


咱们如今能够开始写物体构建器了,在你的objects包中建立一个名为“ObjectBuilder”的类,在类的内部,如下面的代码做为开始:


private static final int FLOATS_PER_VERTEX=3;

private final float[] vertexData;

private int offset=0;


private ObjectBuilder(int sizeInVertices){

this.vertexData=new float[sizeInVertices*FLOATS_PER_VERTEX];

}


 咱们定义了一个常量用来保存椒一个顶点须要多少浮点数,一个数组用于保存这些顶点,以及一个变量用于记录数组中下一个顶点的位置。这个构造函数基于须要的顶点数量初始化数组。


用三角形扇构建圆


在ObjectBuilder类中建立一个名为appendCircle的新方法,并加入以下代码:


private void appendCircle(Circle circle,int numPoint){

final int startVertex=offset/FLOATS_PER_VERTEX;

final int numVertices=sizeOfCircleInVertices(numPoint);


this.vertexData[offset++]=circle.center.x;

this.vertexData[offset++]=circle.center.y;

this.vertexData{offset++}=circle.center.z;


for(i=0;i<numPoint;i++){

float angleInRadians=(float)i/(float numPoints)*((float)Math.PI*2f);

 

this.vertexData[offset++]=circle.center.x+circle.radius*FloatMath.cos(angleInRadians);

this.vertexData[offset++]=circle.center.y;

this.vertexData[offset++]=circle.center.z+circle.radius*FloatMath.sin(angleInRadians);

}

}


咱们知道咱们想要使用本地存储的顶点,必须设置偏移量,也就是多少个顶点才是正确的坐标,好比咱们如今在绘画一个圆柱体,把圆的顶点和侧面的顶点都存储在本地,若是咱们开始绘画圆,那么天然偏移是0,可是圆的顶点都绘完后,咱们总不能仍是从开始的顶点开始取值把,因此跳过取顶点,跳过的就是偏移值startVertex。而numVertices就是要取顶点的长度。


接着咱们在ObjectBuilder类的开始处定义一个绘画的接口,顺便也加入一个变量,以下:


static interface DrawCommand{

void draw();

}

 

private final List<DrawCommand> drawList=new ArrayList<DrawCommand>();


这个常量用于保存绘画命令,以下:


this.drawList.add(new Command(){

public void draw(){

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN,startVertex,numVertices);

}

});

 

 

用三角形带构造圆柱体的侧面,为了代码的重用,咱们额外定义了一个绘制侧面的方法appendOpenCylinder(),它也须要偏移量和长度,并且,看第二节的图片,你发现没有,上面一排和下面一排的顶点Y值是同样的,因此首先咱们在appendOpenCylinder()加入下面四个常量:


private void appendOpenCylinder(Cylinder cylinder,int numPoints){

final int startVertex=offset/FLOATS_PER_VERTEX;

final int numVertices=sizeOfOpenCylinderInVertices(numPoints);

final float yStart=cylinder.center.y-(cylinder.height/2f);

final float yEnd=cylinder.center.y+(cylinder.height/2f);

}


而后加入以下代码生成实际的三角形带:


for(int i=0;i<=numPoints;i++){

float angleInRadians=(float)i/(float numPoints)*((float)Math.PI*2F);

 

float xPosition=cylinder.center.x+cylinder.radius*FloatMath.cos(angleInRadians);

float zPosition=cylinder.center.z+cylinder.radius*FloatMath.sin(angleInRadians);


this.vertexData[offset++]=xPosition;

this.vertexData[offset++]=yStart;

this.vertexData[offset++]=zPosition;


 

this.vertexData[offset++]=xPosition;

this.vertexData[offset++]=yEnd;

this.vertexData[offset++]=zPosition;


}


最后在该方法中加入以下代码完成:


this.drawList.add(new Command(){

public void draw(){

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,startVertex,numVertices);

}

});


咱们在ObjectBuilder类中实现了构造圆和圆柱侧面的方法。是否是还少了什么,没错,你得到的顶点和数据怎么传递给其余的类呢?因此咱们在ObjectBuilder里面定义了一个包装类,将存储的绘制命令和顶点数据都传递给它,以下:

 

static class GenerateData{

final float[] vertexData;

final List<Command> drawList;

 

GenerateData(float[] vertexData,List<DrawCommand> drawList){

this.drawList=drawList;

this.vertexData=vertexData;

}

}


最后就是将圆和侧面叠加成一个圆柱体,咱们ObjectBuilder加入以下的代码:


static GeneratedData createCylindrical(Cylinder cylinder,int numPoints){

int size=sizeOfCricleInVertices()+sizeOfOpenCylinderInVertices(numPoints);//计算总的顶点数


ObjectBuilder builder=new ObjectBuilder(size);//根据顶点数实例化vertexData;


Circle circle=new Circle(cylinder.center.translateY(cylinder.height/2f),cylinder.radius);


builder.appendCircle(circle,numPoints);

builder.appendOpenCylinder(cylinder,numPoints);


return builder.build();

}


private GenerateData build(){

return new GenerateData(this.vertexData,this.drawList);

}


这样一个圆柱体绘制类就完成了。


源代码以下:http://download.csdn.net/detail/liyuanjinglyj/8859411


附上效果图:


相关文章
相关标签/搜索