球体数据结构
public class Planet {
FloatBuffer m_VertexData;
FloatBuffer m_NormalData;
FloatBuffer m_ColorData;
float m_Scale;// 比例
float m_Squash;// 挤入
float m_Radius; // 半径
int m_Stacks, m_Slices; // 部分
public Planet(int stacks, int slices, float radius, float squash) {
this.m_Stacks = stacks; // 1
this.m_Slices = slices;
this.m_Radius = radius;
this.m_Squash = squash;
init(m_Stacks, m_Slices, radius, squash, "dummy");
}
private void init(int stacks, int slices, float radius, float squash,
String textureFile) {
float[] vertexData;
float[] colorData; // 2
float colorIncrement = 0f;
float blue = 0f;
float red = 1.0f;
int vIndex = 0; // vertex index
int cIndex = 0; // color index
m_Scale = radius;
m_Squash = squash;
colorIncrement = 1.0f / (float) stacks;
m_Scale = radius;
m_Squash = squash;
colorIncrement = 1.0f / (float) stacks;
m_Stacks = stacks;
m_Slices = slices;
// vertices
vertexData = new float[3 * ((m_Slices * 2 + 2) * m_Stacks)]; // 4
// color data
colorData = new float[(4 * (m_Slices * 2 + 2) * m_Stacks)]; // 5
int phiIdx, thetaIdx;
// latitude 纬度
for (phiIdx = 0; phiIdx < m_Stacks; phiIdx++) {
// 从 -90度 - +90度(-1.57-+1.57弧度)
// 第一个圆
float phi0 = (float) Math.PI
* ((float) (phiIdx + 0) * (1.0f / (float) (m_Stacks)) - 0.5f);
// the next, or second one.
// 8
float phi1 = (float) Math.PI
* ((float) (phiIdx + 1) * (1.0f / (float) (m_Stacks)) - 0.5f);
float cosPhi0 = (float) Math.cos(phi0); // 9
float sinPhi0 = (float) Math.sin(phi0);
float cosPhi1 = (float) Math.cos(phi1);
float sinPhi1 = (float) Math.sin(phi1);
float cosTheta, sinTheta;
// longitude经度
for (thetaIdx = 0; thetaIdx < m_Slices; thetaIdx++) {
float theta = (float) (-2.0f * (float) Math.PI
* ((float) thetaIdx) * (1.0 / (float) (m_Slices - 1)));
cosTheta = (float) Math.cos(theta);
sinTheta = (float) Math.sin(theta);
// we're generating a vertical pair of points, such
// as the first point of stack 0 and the first point of
// stack 1
// above it. This is how TRIANGLE_STRIPS work,
// taking a set of 4 vertices and essentially drawing two
// triangles
// at a time. The first is v0-v1-v2 and the next is
// v2-v1-v3. Etc.
// get x-y-z for the first vertex of stack
vertexData[vIndex + 0] = m_Scale * cosPhi0 * cosTheta; // 11
vertexData[vIndex + 1] = m_Scale * (sinPhi0 * m_Squash);
vertexData[vIndex + 2] = m_Scale * (cosPhi0 * sinTheta);
vertexData[vIndex + 3] = m_Scale * cosPhi1 * cosTheta;
vertexData[vIndex + 4] = m_Scale * (sinPhi1 * m_Squash);
vertexData[vIndex + 5] = m_Scale * (cosPhi1 * sinTheta);
colorData[cIndex + 0] = (float) red; // 12
colorData[cIndex + 1] = (float) 0f;
colorData[cIndex + 2] = (float) blue;
colorData[cIndex + 4] = (float) red;
colorData[cIndex + 5] = (float) 0f;
colorData[cIndex + 6] = (float) blue;
colorData[cIndex + 3] = (float) 1.0;
colorData[cIndex + 7] = (float) 1.0;
cIndex += 2 * 4; // 13
vIndex += 2 * 3; // 14
}
blue += colorIncrement; // 15
red -= colorIncrement;
// create a degenerate triangle to connect stacks and maintain
// winding order
// 16
Log.i("hello", "vIndex:" + vIndex);
vertexData[vIndex + 0] = vertexData[vIndex + 3] = vertexData[vIndex - 3];
vertexData[vIndex + 1] = vertexData[vIndex + 4] = vertexData[vIndex - 2];
vertexData[vIndex + 2] = vertexData[vIndex + 5] = vertexData[vIndex - 1];
}
m_VertexData = makeFloatBuffer(vertexData); // 17
m_ColorData = makeFloatBuffer(colorData);
}
protected static FloatBuffer makeFloatBuffer(float[] arr) {
ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer fb = bb.asFloatBuffer();
fb.put(arr);
fb.position(0);
return fb;
}
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CW); // 1
// 第一个参数表示坐标的维数,可以是2或者3,如果是2,则坐标为(x,y),z轴默认为0;如果是3,则坐标为(x,y,z)
// 第二个参数可以是GL10.GL_FIXED或者GL10.GL_FLOAT,如果是GL10.GL_FIXED,则第四个参数为IntBuffer类
// 型,如果为GL10.GL_FLOAT,则第四个参数为FloatBuffer类型
// 第三个参数表示步长
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, m_VertexData); // 2
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, m_ColorData);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 3
// GL10.GL_LINE_STRIP 显示线条
// 第一个参数有三种类型GL10.GL_TRIANGLES、GL10.GL_TRIANGLE_FAN、GL10.GL_TRIANGLE_STRIP
// GL_TRIANGLES:每三个顶之间绘制三角形,之间不连接
// GL_TRIANGLE_FAN:以V0V1V2,V0V2V3,V0V3V4,……的形式绘制三角形
// GL_TRIANGLE_STRIP:顺序在每三个顶点之间均绘制三角形。这个方法可以保证从相同的方向上所有以三角形均被绘制。以V0V1V2,V1V2V3,V2V3V4……的形式绘制三角形
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, (m_Slices + 1) * 2
* (m_Stacks - 1) + 2);
}
}
renderer
public class SolarSystemRenderer implements GLSurfaceView.Renderer {
private Planet mPlanet;
private float mAngle;
private float mTransY;
public SolarSystemRenderer() {
mPlanet = new Planet(10, 10, 1.0f, 1.0f);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// (x,y,z)
gl.glTranslatef(0.0f, (float) Math.sin(mTransY), -4.0f);
gl.glRotatef(mAngle, 1, 0, 0);
gl.glRotatef(mAngle, 0, 1, 0);
mPlanet.draw(gl);
mTransY += .075f;
mAngle += .4;
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置OpenGL场景的大小
gl.glViewport(0, 0, width, height); // 12
float ratio = (float) width / height;
// 设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION); // 13
gl.glLoadIdentity();
// 设置视图的大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER); // 16
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, // 17
GL10.GL_FASTEST);
gl.glClearColor(1, 1, 1, 1);
gl.glEnable(GL10.GL_CULL_FACE); // 19
gl.glShadeModel(GL10.GL_SMOOTH); // 20
gl.glEnable(GL10.GL_DEPTH_TEST);
}
}