您的位置:首页 > 移动开发 > Android开发

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

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



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

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

为简单起见,使用一个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.

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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: