Android OpenGL ES 开发教程(19):绘制迷你太阳系


前面介绍了3D坐标系统和3D坐标变换以及在OpenGL ES中坐标变换的过程,并与相机拍照片的过程做类比,以便更好的理解这OpenGL中构造3D模型的一部步骤:

本例提供绘制一个迷你太阳系系统作为前面知识的总结,这个迷你太阳系,有一个红色的太阳,一个蓝色的地图和一个白色的月亮构成:

  • 太阳居中,逆时针自转。
  • 地球绕太阳顺时针公转,本身不自转。
  • 月亮绕地球顺时针公转,自身逆时针自转。

为简单起见,使用一个2D五角星做为天体而没有使用球体(绘制球体在后面有介绍),构造一个Star类:

1public class Star {
2 // Our vertices.
3 protected float vertices[];
4  
5 // Our vertex buffer.
6 protected FloatBuffer vertexBuffer;
7  
8 public Star() {
9  
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));
14 vertices=new float[]{
15 0,a,0.5f,cy,-bx,by,bx,by,-0.5f,cy
16 };
17  
18 ByteBuffer vbb
19 = ByteBuffer.allocateDirect(vertices.length * 4);
20 vbb.order(ByteOrder.nativeOrder());
21 vertexBuffer = vbb.asFloatBuffer();
22 vertexBuffer.put(vertices);
23 vertexBuffer.position(0);
24  
25 }
26  
27 /**
28 * This function draws our star on screen.
29 * @param gl
30 */
31 public void draw(GL10 gl) {
32 // Counter-clockwise winding.
33 gl.glFrontFace(GL10.GL_CCW);
34 // Enable face culling.
35 gl.glEnable(GL10.GL_CULL_FACE);
36 // What faces to remove with the face culling.
37 gl.glCullFace(GL10.GL_BACK);
38  
39 // Enabled the vertices buffer for writing
40 //and to be used during
41 // rendering.
42 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
43 // Specifies the location and data format of
44 //an array of vertex
45 // coordinates to use when rendering.
46 gl.glVertexPointer(2, GL10.GL_FLOAT, 0,
47 vertexBuffer);
48  
49 gl.glDrawArrays(GL10.GL_LINE_LOOP, 0,5);
50  
51 // Disable the vertices buffer.
52 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
53 // Disable face culling.
54 gl.glDisable(GL10.GL_CULL_FACE);
55 }
56  
57}

Star定义了五角星的五个顶点,并使用glDrawArrays 来绘制五角星,因此vertices 顶点的顺序比较重要。

然后定义一个DrawSolarSystem 来绘制这个迷你太阳系:

1public class DrawSolarSystem extends OpenGLESActivity
2 implements IOpenGLDemo{
3  
4 private Star sun=new Star();
5 private Star earth=new Star();
6 private Star moon=new Star();
7  
8 private int angle=0;
9  
10 /** Called when the activity is first created. */
11 @Override
12 public void onCreate(Bundle savedInstanceState) {
13 super.onCreate(savedInstanceState);
14  
15 }
16  
17 public void DrawScene(GL10 gl) {
18 super.DrawScene(gl);
19 gl.glLoadIdentity();
20 GLU.gluLookAt(gl,0.0f, 0.0f, 15.0f,
21 0.0f, 0.0f, 0.0f,
22 0.0f, 1.0f, 0.0f);
23 // Star A
24 // Save the current matrix.
25 gl.glPushMatrix();
26 // Rotate Star A counter-clockwise.
27 gl.glRotatef(angle, 0, 0, 1);
28 gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
29 // Draw Star A.
30 sun.draw(gl);
31 // Restore the last matrix.
32 gl.glPopMatrix();
33 // Star B
34 // Save the current matrix
35 gl.glPushMatrix();
36 // Rotate Star B before moving it,
37 //making it rotate around A.
38 gl.glRotatef(-angle, 0, 0, 1);
39 // Move Star B.
40 gl.glTranslatef(3, 0, 0);
41 // Scale it to 50% of Star A
42 gl.glScalef(.5f, .5f, .5f);
43 gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
44 // Draw Star B.
45 earth.draw(gl);
46 // Star C
47 // Save the current matrix
48 gl.glPushMatrix();
49 // Make the rotation around B
50 gl.glRotatef(-angle, 0, 0, 1);
51 gl.glTranslatef(2, 0, 0);
52 // Scale it to 50% of Star B
53 gl.glScalef(.5f, .5f, .5f);
54 // Rotate around it's own center.
55 gl.glRotatef(angle*10, 0, 0, 1);
56 gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
57 // Draw Star C.
58 moon.draw(gl);
59 // Restore to the matrix as it was before C.
60 gl.glPopMatrix();
61 // Restore to the matrix as it was before B.
62 gl.glPopMatrix();
63 // Increse the angle.
64 angle++;
65  
66 }
67  
68}

使用GLU的gluLookAt 来定义modelview Matrix ,把相机放在正对太阳中心(0,0,0),距离15 (0,0,15)。

使用glPushMatrix和glPopMatrix 来将当前Matrix入栈或是出栈。

首先将当前matrix 入栈,以红色绘制太阳,并逆向转动,将当前matrix 入栈的目的是在能够在绘制地球时恢复当前栈。

然后绘制地球,使用局部坐标系来想象地球和太阳之间的相对运动,地球离开一距离绕太阳公转,相当于先旋转地球的局部坐标系,然后再平移地球的局部坐标系。对应到代码为先glRotatef ,然后glTranslate.

最后是绘制月亮,使用类似的空间想象方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值