今天我们将实现绘制一个球体,并为其添加材质效果。
效果图:
下面是我在网上找的代码,稍微有改动一下的。
Sphere.java
package test.Sphere;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class Sphere extends Activity {
/** Calledwhen the activity is first created. */
private GLSurfaceView mGLSurfaceView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mGLSurfaceView=new GLSurfaceView(this);
mGLSurfaceView.setRenderer(new Renderer());
setContentView(mGLSurfaceView);
}
protected void onResume() {
// Ideally a game should implement onResume() andonPause()
// to take appropriate action when the activity loosesfocus
super.onResume();
mGLSurfaceView.onResume();
}
@Override
protected void onPause() {
// Ideally a game should implement onResume() andonPause()
// to take appropriate action when the activity loosesfocus
super.onPause();
mGLSurfaceView.onPause();
}
}
Renderer.java
package test.Sphere;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
public class Renderer implementsGLSurfaceView.Renderer{
DrawSphere mSphere;
public void onSurfaceChanged(GL10 gl, int width, int height){
// Setsthe current view port to the new size.
gl.glViewport(0, 0, width, height);
// Selectthe projection matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
// Resetthe projection matrix
gl.glLoadIdentity();
//Calculate the aspect ratio of the window
GLU.gluPerspective(gl, 45.0f,
(float) width / (float) height,
0.1f, 100.0f);
// Selectthe modelview matrix
//gl.glMatrixMode(GL10.GL_MODELVIEW);
// Resetthe modelview matrix
//gl.glLoadIdentity();
}
public void onSurfaceCreated(GL10 gl, EGLConfig config){
gl.glClearColor(0.0f, 0.0f,0.0f, 0.5f);
// EnableSmooth Shading, default not really needed.
gl.glShadeModel(GL10.GL_SMOOTH);
// Depthbuffer setup.
gl.glClearDepthf(1.0f);
// Enablesdepth testing.
gl.glEnable(GL10.GL_DEPTH_TEST);
// Thetype of depth testing to do.
gl.glDepthFunc(GL10.GL_LEQUAL);
// Reallynice perspective calculations.
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_NICEST);
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
//gl.glClearColor(0.0f, 0.0f, 0.0f,0.0f);
//gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glClearColor(0.0f, 0.0f,0.0f, 0.0f);
// Clearsthe screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//gl.glTranslatef(0,0, -3.0f);
mSphere=new DrawSphere();
mSphere.initSphere(gl);
mSphere.draw(gl);
}
}
DrawSphere.java
package test.Sphere;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
public class DrawSphere{
/** Calledwhen the activity is first created. */
public void initSphere(GL10 gl){
float[] mat_amb = {0.2f* 1.0f, 0.2f * 0.4f, 0.2f* 0.4f, 1.0f,};
float[] mat_diff= {1.0f, 0.4f, 0.4f, 1.0f,};
float[] mat_spec= {1.0f, 1.0f, 1.0f, 1.0f,};
ByteBuffer mabb = ByteBuffer.allocateDirect(mat_amb.length*4);
mabb.order(ByteOrder.nativeOrder());
FloatBuffer mat_ambBuf =mabb.asFloatBuffer();
mat_ambBuf.put(mat_amb);
mat_ambBuf.position(0);
ByteBuffer mdbb = ByteBuffer.allocateDirect(mat_diff.length*4);
mdbb.order(ByteOrder.nativeOrder());
FloatBuffer mat_diffBuf =mdbb.asFloatBuffer();
mat_diffBuf.put(mat_diff);
mat_diffBuf.position(0);
ByteBuffer msbb = ByteBuffer.allocateDirect(mat_spec.length*4);
msbb.order(ByteOrder.nativeOrder());
FloatBuffer mat_specBuf =msbb.asFloatBuffer();
mat_specBuf.put(mat_spec);
mat_specBuf.position(0);
gl.glClearColor(0.8f, 0.8f, 0.8f,0.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT,mat_ambBuf);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE,mat_diffBuf);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR,mat_specBuf);
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 64.0f);
gl.glLoadIdentity();
GLU.gluLookAt(gl,0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
}
public void draw(GL10 gl) {
float theta, pai;
float co, si;
float r1, r2;
float h1, h2;
float step = 2.0f;
float[][] v = new float[32][3];
ByteBuffervbb;
FloatBuffervBuf;
vbb = ByteBuffer.allocateDirect(v.length * v[0].length * 4);
vbb.order(ByteOrder.nativeOrder());
vBuf = vbb.asFloatBuffer();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
for (pai = -90.0f;pai < 90.0f; pai +=step) {
int n = 0;
r1 = (float)Math.cos(pai* Math.PI / 180.0);
r2= (float)Math.cos((pai + step) * Math.PI / 180.0);
h1= (float)Math.sin(pai * Math.PI / 180.0);
h2= (float)Math.sin((pai + step) * Math.PI / 180.0);
for (theta = 0f;theta <= 360.0f; theta+= step) {
co= (float)Math.cos(theta * Math.PI / 180.0);
si= -(float)Math.sin(theta * Math.PI / 180.0);
v[n][0]= (r2 * co);
v[n][1]= (h2);
v[n][2]= (r2 * si);
v[n+ 1][0] = (r1 * co);
v[n+ 1][1] = (h1);
v[n+ 1][2] = (r1 * si);
vBuf.put(v[n]);
vBuf.put(v[n+ 1]);
n+= 2;
if(n>31){
vBuf.position(0);
gl.glVertexPointer(3,GL10.GL_FLOAT, 0, vBuf);
gl.glNormalPointer(GL10.GL_FLOAT, 0, vBuf);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, n);
n= 0;
theta-= step;
}
}
vBuf.position(0);
gl.glVertexPointer(3,GL10.GL_FLOAT, 0, vBuf);
gl.glNormalPointer(GL10.GL_FLOAT, 0, vBuf);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, n);
}
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
}
这里的注释比较少,相关的方法可以参照我gl10方法解析中的内容。
下面主要讲一下球体的绘制方法。
由于在OpenGL ES中并没有可供直接绘制球体的方法,所以我们需要绘制一个很多面对多面体,它看起来像是一个球。
我们这里draw方法就是用来画这个多面体的。它主要由两层循环。它绘制的顺序是自底向上一层一层绘制的。第一层循环就是确定要绘制的是哪一层。
第二层循环是在确定的层上绘制多个三角形。
值得注意的是这些三角形并不在同一个平面上。它们共同组成这个多面体。
我将在下篇中讲下gl.glDrawArrays。