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 , |