前面介绍了3D坐标系统和3D坐标变换以及在OpenGL ES中坐标变换的过程,并与相机拍照片的过程做类比,以便更好的理解这OpenGL中构造3D模型的一部步骤:
本例提供绘制一个迷你太阳系系统作为前面知识的总结,这个迷你太阳系,有一个红色的太阳,一个蓝色的地图和一个白色的月亮构成:
- 太阳居中,逆时针自转。
- 地球绕太阳顺时针公转,本身不自转。
- 月亮绕地球顺时针公转,自身逆时针自转。
为简单起见,使用一个2D五角星做为天体而没有使用球体(绘制球体在后面有介绍),构造一个Star类:
3 | protected float vertices[]; |
6 | protected FloatBuffer vertexBuffer; |
10 | float a=( float )( 1 .0f/( 2 .0f-2f*Math.cos(72f*Math.PI/ 180 .f))); |
11 | float bx=( float )(a*Math.cos( 18 *Math.PI/ 180 .0f)); |
12 | float by=( float )(a*Math.sin( 18 *Math.PI/180f)); |
13 | float cy=( float )(-a * Math.cos( 18 *Math.PI/180f)); |
15 | 0 ,a, 0 .5f,cy,-bx,by,bx,by,- 0 .5f,cy |
19 | = ByteBuffer.allocateDirect(vertices.length * 4 ); |
20 | vbb.order(ByteOrder.nativeOrder()); |
21 | vertexBuffer = vbb.asFloatBuffer(); |
22 | vertexBuffer.put(vertices); |
23 | vertexBuffer.position( 0 ); |
28 | * This function draws our star on screen. |
31 | public void draw(GL10 gl) { |
33 | gl.glFrontFace(GL10.GL_CCW); |
35 | gl.glEnable(GL10.GL_CULL_FACE); |
37 | gl.glCullFace(GL10.GL_BACK); |
42 | gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); |
46 | gl.glVertexPointer( 2 , GL10.GL_FLOAT, 0 , |
49 | gl.glDrawArrays(GL10.GL_LINE_LOOP, 0 , 5 ); |
52 | gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); |
54 | gl.glDisable(GL10.GL_CULL_FACE); |
Star定义了五角星的五个顶点,并使用glDrawArrays 来绘制五角星,因此vertices 顶点的顺序比较重要。
然后定义一个DrawSolarSystem 来绘制这个迷你太阳系:
1 | public class DrawSolarSystem extends OpenGLESActivity |
2 | implements IOpenGLDemo{ |
4 | private Star sun= new Star(); |
5 | private Star earth= new Star(); |
6 | private Star moon= new Star(); |
10 | /** Called when the activity is first created. */ |
12 | public void onCreate(Bundle savedInstanceState) { |
13 | super .onCreate(savedInstanceState); |
17 | public void DrawScene(GL10 gl) { |
20 | GLU.gluLookAt(gl, 0 .0f, 0 .0f, 15 .0f, |
27 | gl.glRotatef(angle, 0 , 0 , 1 ); |
28 | gl.glColor4f( 1 .0f, 0 .0f, 0 .0f, 1 .0f); |
38 | gl.glRotatef(-angle, 0 , 0 , 1 ); |
40 | gl.glTranslatef( 3 , 0 , 0 ); |
42 | gl.glScalef(.5f, .5f, .5f); |
43 | gl.glColor4f( 0 .0f, 0 .0f, 1 .0f, 1 .0f); |
50 | gl.glRotatef(-angle, 0 , 0 , 1 ); |
51 | gl.glTranslatef( 2 , 0 , 0 ); |
53 | gl.glScalef(.5f, .5f, .5f); |
55 | gl.glRotatef(angle* 10 , 0 , 0 , 1 ); |
56 | gl.glColor4f( 1 .0f, 1 .0f, 1 .0f, 1 .0f); |
使用GLU的gluLookAt 来定义modelview Matrix ,把相机放在正对太阳中心(0,0,0),距离15 (0,0,15)。
使用glPushMatrix和glPopMatrix 来将当前Matrix入栈或是出栈。
首先将当前matrix 入栈,以红色绘制太阳,并逆向转动,将当前matrix 入栈的目的是在能够在绘制地球时恢复当前栈。
然后绘制地球,使用局部坐标系来想象地球和太阳之间的相对运动,地球离开一距离绕太阳公转,相当于先旋转地球的局部坐标系,然后再平移地球的局部坐标系。对应到代码为先glRotatef ,然后glTranslate.
最后是绘制月亮,使用类似的空间想象方法。