一個三角形扇以一箇中心頂點做爲起始,使用相鄰的兩個頂點建立第一個三角形,接下來的每一個頂點都會建立一個三角形,圍繞起始的中心點按扇形展開。爲了使這個扇形閉合,咱們只須要在最後重複第二個點。(以長方形爲例)數組
構建三角形扇的步驟,以下圖所示:app
要使用OpenGL繪製這個三角形扇,須要在渲染類的onDrawFrame()中,使用以下方法:函數
GLES20.glDrawArray(GLES20.GL_TRIANGLE_FAN,0,6);性能
第一個參數是告訴OpenGL要繪製一個三角形扇,第二參數是告訴OpenGL從本地頂點數據的第幾個位置開始取頂點座標,第三個參數是告訴OpenGL要取多少個頂點座標。
ui
根據上面的6個點,就能夠繪製一個長方形了。this
三角形扇在OpenGL的應用:長方形,正方形,圓等。spa
一個三角形帶的前三個頂點定義了第一個三角形。這以後的每一個額外的頂點都定義了另外的一個三角形。.net
構建三角形帶的步驟,以下圖所示:對象
要使用OpenGL繪製這個三角形帶,須要在渲染類的onDrawFrame()中,使用以下方法:接口
GLES20.glDrawArray(GLES20.GL_TRIANGLE_STRIP,0,6);
第一個參數是告訴OpenGL要繪製一個三角形帶,第二參數是告訴OpenGL從本地頂點數據的第幾個位置開始取頂點座標,第三個參數是告訴OpenGL要取多少個頂點座標。
三角形帶在OpenGL的應用:長方形,圓柱的側面等。
想象一下在本身的手機上構建的圓柱體,而且以一個角度觀察它,假如咱們把圓柱放在桌面上,從側面觀察它,你會發現,圓柱體是一個由一個頂部的圓加上側面捲起來的長方形構成。結合本文前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
附上效果圖: