前面介绍了OpenGL ES所有能够绘制的基本图形,点,线段和三角形。其它所有复杂的2D或3D图形都是由这些基本图形构成。
本例介绍如何使用三角形构造一个正20面体。一个正20面体,有12个顶点,20个面,30条边构成:
创建一个DrawIcosahedron Activity, 定义20面体的12个顶点,和20个面如下:
static final float X=.525731112119133606f;
static final float Z=.850650808352039932f; static float vertices[] = new float[]{
-X, 0.0f, Z, X, 0.0f, Z, -X, 0.0f, -Z, X, 0.0f, -Z,
0.0f, Z, X, 0.0f, Z, -X, 0.0f, -Z, X, 0.0f, -Z, -X,
Z, X, 0.0f, -Z, X, 0.0f, Z, -X, 0.0f, -Z, -X, 0.0f
}; static short indices[] = new short[]{
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,, };
OpenGL ES缺省使用同一种颜色来绘制图形,为了能够更好的显示3D效果,我们为每个顶点随机定义一些颜色如下:
float[] colors = {
0f, 0f, 0f, 1f,
0f, 0f, 1f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 1f, 1f,
1f, 0f, 0f, 1f,
1f, 0f, 1f, 1f,
1f, 1f, 0f, 1f,
1f, 1f, 1f, 1f,
1f, 0f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 0f, 1f, 1f,
1f, 0f, 1f, 1f };
将顶点,面,颜色存放到Buffer中以提高性能:
private FloatBuffer vertexBuffer; private FloatBuffer colorBuffer; private ShortBuffer indexBuffer; ByteBuffer vbb
= ByteBuffer.allocateDirect(vertices.length * );
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(); ByteBuffer cbb
= ByteBuffer.allocateDirect(colors.length * );
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(); ByteBuffer ibb
= ByteBuffer.allocateDirect(indices.length * );
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position();
看一看DrawScene代码:
public void DrawScene(GL10 gl) {
super.DrawScene(gl); gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glLoadIdentity();
gl.glTranslatef(, , -);
gl.glRotatef(angle, , , ); gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_CULL_FACE); gl.glCullFace(GL10.GL_BACK); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(, GL10.GL_FLOAT, , vertexBuffer); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glColorPointer(, GL10.GL_FLOAT, , colorBuffer); gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, indexBuffer); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisable(GL10.GL_CULL_FACE);
angle++; }
用来绘制20面体使用了gl.glDrawElements:
public abstract void glDrawElements(int mode, int count, int type, Buffer indices) ,可以重新定义顶点的顺序,顶点的顺序由indices Buffer 指定。
本例会显示一个绕Y轴不断旋转的20面体,如何旋转模型将在后面的坐标系统和坐标变换中介绍.
完整代码:
MainActiviy.java
package com.example.gltest; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager; public class MainActivity extends Activity
implements IOpenGLDemo{
private FloatBuffer vertexBuffer; private FloatBuffer colorBuffer; private ShortBuffer indexBuffer; private GLSurfaceView mGLSurfaceView; static final float X=.525731112119133606f;
static final float Z=.850650808352039932f; static float vertices[] = new float[]{
-X, 0.0f, Z, X, 0.0f, Z, -X, 0.0f, -Z, X, 0.0f, -Z,
0.0f, Z, X, 0.0f, Z, -X, 0.0f, -Z, X, 0.0f, -Z, -X,
Z, X, 0.0f, -Z, X, 0.0f, Z, -X, 0.0f, -Z, -X, 0.0f
}; static short indices[] = new short[]{
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,,,
,,, ,,, ,,, ,,, ,, };
float[] colors = {
0f, 0f, 0f, 1f,
0f, 0f, 1f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 1f, 1f,
1f, 0f, 0f, 1f,
1f, 0f, 1f, 1f,
1f, 1f, 0f, 1f,
1f, 1f, 1f, 1f,
1f, 0f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 0f, 1f, 1f,
1f, 0f, 1f, 1f }; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ByteBuffer vbb
= ByteBuffer.allocateDirect(vertices.length * );
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(); ByteBuffer cbb
= ByteBuffer.allocateDirect(colors.length * );
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(); ByteBuffer ibb
= ByteBuffer.allocateDirect(indices.length * );
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(); this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); mGLSurfaceView = new GLSurfaceView(this);
mGLSurfaceView.setRenderer(new OpenGLRenderer(this));
setContentView(mGLSurfaceView);
} // public void DrawScene(GL10 gl) {
// gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
// // Clears the screen and depth buffer.
// gl.glClear(GL10.GL_COLOR_BUFFER_BIT
// | GL10.GL_DEPTH_BUFFER_BIT);
//
// }
public void DrawScene(GL10 gl) {
// super.DrawScene(gl); gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glLoadIdentity();
gl.glTranslatef(, , -); float angle=;
gl.glRotatef(angle, , , ); gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_CULL_FACE); gl.glCullFace(GL10.GL_BACK); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(, GL10.GL_FLOAT, , vertexBuffer); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glColorPointer(, GL10.GL_FLOAT, , colorBuffer); gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, indexBuffer); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisable(GL10.GL_CULL_FACE);
angle++; }
@Override
protected void onResume() {
// Ideally a game should implement
// onResume() and onPause()
// to take appropriate action when the
//activity looses focus
super.onResume();
mGLSurfaceView.onResume();
} @Override
protected void onPause() {
// Ideally a game should implement onResume()
//and onPause()
// to take appropriate action when the
//activity looses focus
super.onPause();
mGLSurfaceView.onPause();
} }
其他类似。