前面介紹了3D坐標系統和3D坐標變換以及在 OpenGL ES 中坐標變換的過程,并與相機拍照片的過程做類比,以便更好的理解這 OpenGL 中構造3D模型的一部步驟:
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/84.png" alt="" />
本例提供繪制一個迷你太陽系系統作為前面知識的總結,這個迷你太陽系,有一個紅色的太陽,一個藍色的地圖和一個白色的月亮構成:
為簡單起見,使用一個2D五角星做為天體而沒有使用球體(繪制球體在后面有介紹),構造一個 Star 類:
public class Star {
// Our vertices.
protected float vertices[];
// Our vertex buffer.
protected FloatBuffer vertexBuffer;
public Star() {
float a=(float)(1.0f/(2.0f-2f\*Math.cos(72f\*Math.PI/180.f)));
float bx=(float)(a\*Math.cos(18\*Math.PI/180.0f));
float by=(float)(a\*Math.sin(18\*Math.PI/180f));
float cy=(float)(-a \* Math.cos(18\*Math.PI/180f));
vertices=new float[]{
0,a,0.5f,cy,-bx,by,bx,by,-0.5f,cy
};
ByteBuffer vbb
= ByteBuffer.allocateDirect(vertices.length \* 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
/**
* This function draws our star on screen.
* @param gl
*/
public void draw(GL10 gl) {
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL\_CCW);
// Enable face culling.
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 to be used during
// rendering.
gl.glEnableClientState(GL10.GL\_VERTEX\_ARRAY);
// Specifies the location and data format of
//an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(2, GL10.GL\_FLOAT, 0,
vertexBuffer);
gl.glDrawArrays(GL10.GL_LINE_LOOP, 0,5);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL\_VERTEX\_ARRAY);
// Disable face culling.
gl.glDisable(GL10.GL\_CULL\_FACE);
}
}
Star 定義了五角星的五個頂點,并使用 glDrawArrays 來繪制五角星,因此 vertices 頂點的順序比較重要。
然后定義一個 DrawSolarSystem 來繪制這個迷你太陽系:
public class DrawSolarSystem extends OpenGLESActivity
implements IOpenGLDemo{
private Star sun=new Star();
private Star earth=new Star();
private Star moon=new Star();
private int angle=0;
/** Called when the activity is first created. */
\@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void DrawScene(GL10 gl) {
super.DrawScene(gl);
gl.glLoadIdentity();
GLU.gluLookAt(gl,0.0f, 0.0f, 15.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
// Star A
// Save the current matrix.
gl.glPushMatrix();
// Rotate Star A counter-clockwise.
gl.glRotatef(angle, 0, 0, 1);
gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
// Draw Star A.
sun.draw(gl);
// Restore the last matrix.
gl.glPopMatrix();
// Star B
// Save the current matrix
gl.glPushMatrix();
// Rotate Star B before moving it,
//making it rotate around A.
gl.glRotatef(-angle, 0, 0, 1);
// Move Star B.
gl.glTranslatef(3, 0, 0);
// Scale it to 50% of Star A
gl.glScalef(.5f, .5f, .5f);
gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
// Draw Star B.
earth.draw(gl);
// Star C
// Save the current matrix
gl.glPushMatrix();
// Make the rotation around B
gl.glRotatef(-angle, 0, 0, 1);
gl.glTranslatef(2, 0, 0);
// Scale it to 50% of Star B
gl.glScalef(.5f, .5f, .5f);
// Rotate around it's own center.
gl.glRotatef(angle\*10, 0, 0, 1);
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Draw Star C.
moon.draw(gl);
// Restore to the matrix as it was before C.
gl.glPopMatrix();
// Restore to the matrix as it was before B.
gl.glPopMatrix();
// Increse the angle.
angle++;
}
}
使用 GLU 的 gluLookAt 來定義 modelview Matrix ,把相機放在正對太陽中心(0,0,0),距離 15 (0,0,15)。
使用 glPushMatrix 和 glPopMatrix 來將當前 Matrix 入?;蚴浅鰲?。
首先將當前 matrix 入棧,以紅色繪制太陽,并逆向轉動,將當前 matrix 入棧的目的是在能夠在繪制地球時恢復當前棧。
然后繪制地球,使用局部坐標系來想象地球和太陽之間的相對運動,地球離開一距離繞太陽公轉,相當于先旋轉地球的局部坐標系,然后再平移地球的局部坐標系。對應到代碼為先 glRotatef ,然后 glTranslate.
最后是繪制月亮,使用類似的空間想象方法。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/85.png" alt="" />
本例下載