前面介绍了3D坐标系统和3D坐标变换以及在OpenGLES中坐标变换的过程,并与相机拍照片的过程做类比,以便更好的理解这OpenGL中构造3D模型的一部步骤:
本例提供绘制一个迷你太阳系系统作为前面知识的总结,这个迷你太阳系,有一个红色的太阳,一个蓝色的地图和一个白色的月亮构成:
太阳居中,逆时针自转。
地球绕太阳顺时针公转,本身不自转。
月亮绕地球顺时针公转,自身逆时针自转。
为简单起见,使用一个2D五角星做为天体而没有使用球体(绘制球体在后面有介绍),构造一个Star类:
查看源代码
打印帮助
3 | protected
float vertices[];
|
6 | protected
FloatBuffervertexBuffer; |
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 | *Thisfunctiondrawsourstaronscreen.
|
31 | public
void draw(GL10gl){
|
32 | //Counter-clockwisewinding.
|
33 | gl.glFrontFace(GL10.GL_CCW); |
35 | gl.glEnable(GL10.GL_CULL_FACE); |
36 | //Whatfacestoremovewiththefaceculling.
|
37 | gl.glCullFace(GL10.GL_BACK); |
39 | //Enabledtheverticesbufferforwriting
|
42 | gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); |
43 | //Specifiesthelocationanddataformatof
|
45 | //coordinatestousewhenrendering.
|
46 | gl.glVertexPointer( 2 ,GL10.GL_FLOAT, 0 , |
49 | gl.glDrawArrays(GL10.GL_LINE_LOOP, 0 , 5 ); |
51 | //Disabletheverticesbuffer.
|
52 | gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); |
54 | gl.glDisable(GL10.GL_CULL_FACE); |
Star定义了五角星的五个顶点,并使用glDrawArrays来绘制五角星,因此vertices顶点的顺序比较重要。
然后定义一个DrawSolarSystem来绘制这个迷你太阳系:
查看源代码
打印帮助
1 | public class DrawSolarSystem extends
OpenGLESActivity |
4 | private
Starsun= new Star();
|
5 | private
Starearth= new Star();
|
6 | private
Starmoon= new Star();
|
10 | /**Calledwhentheactivityisfirstcreated.*/ |
12 | public
void onCreate(BundlesavedInstanceState){
|
13 | super .onCreate(savedInstanceState); |
17 | public
void DrawScene(GL10gl){
|
20 | GLU.gluLookAt(gl, 0 .0f, 0 .0f, 15 .0f, |
24 | //Savethecurrentmatrix.
|
26 | //RotateStarAcounter-clockwise.
|
27 | gl.glRotatef(angle, 0 , 0 , 1 ); |
28 | gl.glColor4f( 1 .0f, 0 .0f, 0 .0f, 1 .0f); |
31 | //Restorethelastmatrix.
|
36 | //RotateStarBbeforemovingit, |
37 | //makingitrotatearoundA.
|
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); |
49 | //MaketherotationaroundB
|
50 | gl.glRotatef(-angle, 0 , 0 , 1 ); |
51 | gl.glTranslatef( 2 , 0 , 0 ); |
53 | gl.glScalef(.5f,.5f,.5f); |
54 | //Rotatearoundit'sowncenter.
|
55 | gl.glRotatef(angle* 10 , 0 , 0 , 1 ); |
56 | gl.glColor4f( 1 .0f, 1 .0f, 1 .0f, 1 .0f); |
59 | //RestoretothematrixasitwasbeforeC.
|
61 | //RestoretothematrixasitwasbeforeB.
|
使用GLU的gluLookAt来定义modelviewMatrix,把相机放在正对太阳中心(0,0,0),距离15(0,0,15)。
使用glPushMatrix和glPopMatrix来将当前Matrix入栈或是出栈。
首先将当前matrix入栈,以红色绘制太阳,并逆向转动,将当前matrix入栈的目的是在能够在绘制地球时恢复当前栈。
然后绘制地球,使用局部坐标系来想象地球和太阳之间的相对运动,地球离开一距离绕太阳公转,相当于先旋转地球的局部坐标系,然后再平移地球的局部坐标系。对应到代码为先glRotatef,然后glTranslate.
最后是绘制月亮,使用类似的空间想象方法。