Android遊戲之頂點索引

Android遊戲之頂點索引

OpenGL均採用三角形列表進行渲染.每個三角形都有三個頂點.在有些情況下兩個或多個三角形會共用頂點.如上圖有兩個頂點具有相同『位置』『顏色』『紋理座標』.但甘浪費空間.更好解卻方法是將所有頂點保存在列表.而三角形頂點保存索引.OpenGL ES要求索引值使用短整數或字節.即OpenGL ES每次最多渲染65536個頂點.

我地需要一個Vertices類,用於存儲每個頂點『位置』『顏色』與『紋理座標』,並且它需要兩個選項.頂點是否『顏色』與『紋理座標』

public class VERTICES {

boolean color_have = false;//  擁有顏色

boolean texture_have =false;// 擁有紋理坐標

int vertex_size = 0;// 每個頂點所占大小

使用FloatBuffer保存頂點

FloatBuffer  vertex_array = null;

使用ShortBuffer頂點索引

ShortBuffer index_array = null;

頂點隊列分配記憶體,vertex_max為最大頂點量, index_max為最大索引量

VERTICES(int vertex_max,int index_max,boolean color_have,boolean texture_have){

this.color_have  = color_have;//  擁有頂點顏色

this.texture_have = texture_have;// 擁有紋理坐標

計算每頂點所占大小.顏色占4單元.紋理座標占2單元.2D座標占2單元.每個整數占4字節

int vertex_size = (2 + (color_have?4:0) + (texture_have?2:0) ) * 4;

因為OpenGL ES是以C API結口提供.無法直接使用JAVA數組.因此你需要C數組系統堆棧記憶體.而非JAVA虛擬機記憶體.需要 FloatBuffer分配頂點記憶體.

vertex_max為最大頂點量.

ByteBuffer buffer = ByteBuffer.allocateDirect(vertex_size * vertex_max);

將『網絡字節』改為『主機字節』或稱為『CPU字節』

buffer.order(ByteOrder.nativeOrder());

獲取整數數組

vertex_array = buffer.asIntBuffer();

每個短整形占兩個字節.index_max為最大索引量

buffer = ByteBuffer.allocateDirect(index_max * Short.SIZE/8);

將『網絡字節』改為『主機字節』

buffer.order(ByteOrder.nativeOrder());

頂點短整數數組

index_array = buffer.asShortBuffer();

}

將頂點提交給OpenGL數組並觸發

public void SetVertices(float[] vertices,int offset,int count){

vertex_array.clear();// 清空緩存.設定當前位置

int len = offset + count;

for(int i=offset, j=0; i < len; i++, j++)

vertex_Buffer[j] = Float.floatToRawIntBits(vertices[i]);

vertex_array.put(vertex_Buffer, 0, count); // 寫入數據.移動當前位置

vertex_array.flip();// 觸發

}

將頂點索引提交給OpenGL數組

public void SetIndices(short[] indices,int offset,int count) {

index_array.clear();// 清空緩存.設定當前位置

index_array.put(indices, offset, count); // 寫入數據.移動當前位置

index_array.flip();// 觸發

}

綁定數據

public void Bind(){

GL10  gl = GRAPHICS.gl;

啟用頂點數組

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

設置當前寫入位置0

vertex_array.position(0);

設置頂點指針,每個頂點兩個元素.xy兩分量

gl.glVertexPointer(2, GL10.GL_FLOAT, vertex_size, vertex_array);

if(color_have == true){//顏色

啟用頂點顏色數組

gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

設置當前寫入位置2

vertex_array.position(2);

設置顏色指針,RGBA四分量

gl.glColorPointer(4, GL10.GL_FLOAT, vertex_size, vertex_array);

}

if(texture_have ){// 紋理坐標

啟用紋理坐標數組

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

vertex_array.position(color_have?6:2);// 寫入位置

設置紋理坐標指針,UV兩分量

gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertex_size, vertex_array);

}

}

取消綁定數據

public void Unbind(){

GL10 gl = GRAPHICS.gl;

關閉頂點紋理數組

if(color_have)

gl.glDisableClientState(GL10.GL_COLOR_ARRAY );

關閉頂點顏色數組

if(texture_have)

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

}

繪畫三角形

public void Draw(int mode,int offset,int count){

GL10 gl = GRAPHICS.gl;

繪畫頂點

if(index_array != null){// 繪畫

index_array.position(offset);//

gl.glDrawElements(mode, count, GL10.GL_UNSIGNED_SHORT, index_array);

}

else{

gl.glDrawArrays(mode, offset, count);

}

}

}

評論