之前文章中,我们绘制了三角形、正方形、圆形、立方星,今天我们将回执圆锥、圆柱、体。能够绘制这些基本的常规几何形体后,其他常见的几何形体的绘制对我们来说基本没问题了。
圆锥
由之前的文章,我们应该知道了,OpenGL ES中物体的绘制重点就是在于把这个物体表面分解成三角形,分解成功后,绘制自然不成问题了。圆锥我们很容易就想到把它拆解成一个圆形和一个锥面,锥面的顶点跟圆形的圆点,除了锥面的中心点的坐标有了“高度”,其他的完全相同。圆形在之前文章已经绘制过,那么锥面其实对我们来说也是小事。
锥面顶点坐标
其实锥面顶点坐标也就是圆形中,给圆心相对圆边增加高度,使之形成锥面。
ArrayList data = new ArrayList<>();
data.add(0.0f);
data.add(0.0f);
data.add(2.0f); //给圆心相对圆边增加高度,使之形成锥面
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(0.0f);
}
float[] f = new float[data.size()];
for (int i = 0; i < f.length; i++)
{
f[i] = data.get(i);
}
我们按照绘制圆形的方式,绘制出锥面,然后再在这个锥面的地步绘制一个圆形,这样我们就可以得到一个圆锥了:
从上图中可以看出,我们绘制的并不是同样的颜色,如果使用同样的颜色,很难看出圆锥的立体效果。这种颜色怎么实现的呢?我们来看它的顶点着色器:
private final String vertextShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_Position = vMatrix * vPosition;" +
" if(vPosition.z!=0.0){"+
" vColor=vec4(0.0,0.0,0.0,1.0);"+
" }else{"+
" vColor=vec4(0.9,0.9,0.9,1.0);"+
" }"+
"}";
在顶点着色器中并没有传入颜色,而是在程序中直接判断进行赋值,当然顶点颜色和定边颜色也可以由外面传入。
具体代码:
public class MySixthRender implements GLSurfaceView.Renderer
{
private final String vertextShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_Position = vMatrix * vPosition;" +
" if(vPosition.z!=0.0){"+
" vColor=vec4(0.0,0.0,0.0,1.0);"+
" }else{"+
" vColor=vec4(0.9,0.9,0.9,1.0);"+
" }"+
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private float color[] = {
1.0f, 1.0f, 1.0f, 1.0f
};
private int program;
private FloatBuffer vertexBuffer1;
private FloatBuffer vertexBuffer2;
//投影矩阵
private final float[] mProjectMatrix = new float[16];
//相机位置矩阵
private final float[] mViewMatrix = new float[16];
//计算变换矩阵
private final float[] mMVPMatrix = new float[16];
private float radius = 1.0f; //半径
private int n = 3; //切割份数
private float[] shapePos;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//将背景设置为灰色
GLES20.glClearColor(0.5f,0.2f,1.0f,1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT| GLES20.GL_DEPTH_BUFFER_BIT);
//锥面所有坐标
shapePos = createPositions();
//申请底层空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(shapePos.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer1 = byteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
vertexBuffer1.put(shapePos);
vertexBuffer1.position(0);
//圆形所有坐标
ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(shapePos.length * 4);
byteBuffer2.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer2 = byteBuffer2.asFloatBuffer();
//将三角形坐标传入FloatBuffer
shapePos[2] = 0.0f; //改变锥面顶点高度,变为圆心坐标
vertexBuffer2.put(shapePos);
vertexBuffer2.position(0);
//创建顶点着色器程序
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
//创建片元着色器程序
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
if (vertexShader == 0 || fragmentShader == 0)
{
return;
}
//创建一个空的OpenGL ES程序
program = GLES20.glCreateProgram();
//将顶点着色器加入程序
GLES20.glAttachShader(program, vertexShader);
//将片元着色器加入程序
GLES20.glAttachShader(program, fragmentShader);
//连接到着色器程序中
GLES20.glLinkProgram(program);
//使用程序
GLES20.glUseProgram(program);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
//设置透视矩阵
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
//设置相机位置
Matrix.setLookAtM(mViewMatrix , 0, 1.0f, -10.0f, -4.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl)
{
if (program == 0)
return;
//获取变换矩阵vMatrix成员句柄
int vMatrix = GLES20.glGetUniformLocation(program, "vMatrix");
//设置vMatrix的值
GLES20.glUniformMatrix4fv(vMatrix, 1, false, mMVPMatrix, 0);
//获取顶点着色器的vPosition成员句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//启用vPosition句柄
GLES20.glEnableVertexAttribArray(vPosition);
//传的圆锥所有顶点坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer1);
//绘制
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, shapePos.length / 3);
//传的圆形所有顶点坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer2);
//绘制圆形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, shapePos.length / 3);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(vPosition);
}
public int loadShader(int type, String shaderCode)
{
//创建空的着色器
int shader = GLES20.glCreateShader(type);
//将着色器程序加到着色器中
GLES20.glShaderSource(shader, shaderCode);
//编译色器程序
GLES20.glCompileShader(shader);
return shader;
}
private float[] createPositions()
{
ArrayList data = new ArrayList<>();
data.add(0.0f);
data.add(0.0f);
data.add(2.0f); //给圆心相对圆边增加高度,使之形成锥面
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(0.0f);
}
float[] f = new float[data.size()];
for (int i = 0; i < f.length; i++)
{
f[i] = data.get(i);
}
return f;
}
}
圆柱
圆柱与圆锥类似,我们可以把圆柱拆分成上下圆面,加上一个圆筒。圆筒我们之前也没有画过,它怎么拆解成三角形呢?我们可以如同拆解东思路来理解圆柱,想想正三棱柱,正八棱柱,正一百棱柱。。。棱越多,就越圆滑,与圆柱越接近,然后再把每个棱面(矩形)拆分成两个三角形就ok。圆筒面的所有顶点为:
ArrayList cylinder = new ArrayList<>();
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
float x = (float) (radius * Math.sin(i * Math.PI / 180f));
float y = (float) (radius * Math.cos(i * Math.PI / 180f));
//圆筒坐标
cylinder.add(x);
cylinder.add(y);
cylinder.add(2.0f);
cylinder.add(x);
cylinder.add(y);
cylinder.add(0.0f);
}
cylinderShapePos = new float[cylinder.size()];
for (int i = 0; i < cylinderShapePos.length; i++)
{
cylinderShapePos[i] = cylinder.get(i);
}
顶部圆所有顶点坐标为:
ArrayList top = new ArrayList<>();
top.add(0.0f);
top.add(0.0f);
top.add(2.0f);
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
float x = (float) (radius * Math.sin(i * Math.PI / 180f));
float y = (float) (radius * Math.cos(i * Math.PI / 180f));
//顶部圆形坐标
top.add(x);
top.add(y);
top.add(2.0f);
}
topShapePos = new float[top.size()];
for (int i = 0; i < topShapePos.length; i++)
{
topShapePos[i] = top.get(i);
}
底部圆所有顶点坐标为:
ArrayList bottom = new ArrayList<>();
bottom.add(0.0f);
bottom.add(0.0f);
bottom.add(0.0f);
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
float x = (float) (radius * Math.sin(i * Math.PI / 180f));
float y = (float) (radius * Math.cos(i * Math.PI / 180f));
//底下圆形坐标
bottom.add(x);
bottom.add(y);
bottom.add(0.0f);
}
bottomShapePos = new float[bottom.size()];
for (int i = 0; i < bottomShapePos.length; i++)
{
bottomShapePos[i] = bottom.get(i);
}
这样就可以绘制圆柱了,绘制圆筒面时要注意绘制方式是GL_TRIANGLE_STRIP。这样我们就可以得到一个圆柱了:
具体代码:
public class MySeventhRender implements GLSurfaceView.Renderer
{
private final String vertextShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_Position = vMatrix * vPosition;" +
" if(vPosition.z!=0.0){"+
" vColor=vec4(0.0,0.0,0.0,1.0);"+
" }else{"+
" vColor=vec4(0.7,0.7,0.7,1.0);"+
" }"+
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int program;
private FloatBuffer cylinderVertexBuffer;
private FloatBuffer bottomVertexBuffer;
//投影矩阵
private final float[] mProjectMatrix = new float[16];
//相机位置矩阵
private final float[] mViewMatrix = new float[16];
//计算变换矩阵
private final float[] mMVPMatrix = new float[16];
private float radius = 1.0f; //半径
private int n = 360; //切割份数
private float[] cylinderShapePos;
private float[] bottomShapePos;
private float[] topShapePos;
private FloatBuffer topVertexBuffer;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//将背景设置为灰色
GLES20.glClearColor(0.5f,0.2f,1.0f,1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT| GLES20.GL_DEPTH_BUFFER_BIT);
//顶点坐标
createPositions();
//申请底层空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(cylinderShapePos.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
cylinderVertexBuffer = byteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
cylinderVertexBuffer.put(cylinderShapePos);
cylinderVertexBuffer.position(0);
ByteBuffer bottomByteBuffer = ByteBuffer.allocateDirect(bottomShapePos.length * 4);
bottomByteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
bottomVertexBuffer = bottomByteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
bottomVertexBuffer.put(bottomShapePos);
bottomVertexBuffer.position(0);
ByteBuffer topByteBuffer = ByteBuffer.allocateDirect(topShapePos.length * 4);
topByteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
topVertexBuffer = topByteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
topVertexBuffer.put(topShapePos);
topVertexBuffer.position(0);
//创建顶点着色器程序
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
//创建片元着色器程序
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
if (vertexShader == 0 || fragmentShader == 0)
{
return;
}
//创建一个空的OpenGL ES程序
program = GLES20.glCreateProgram();
//将顶点着色器加入程序
GLES20.glAttachShader(program, vertexShader);
//将片元着色器加入程序
GLES20.glAttachShader(program, fragmentShader);
//连接到着色器程序中
GLES20.glLinkProgram(program);
//使用程序
GLES20.glUseProgram(program);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
//设置透视矩阵
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
//设置相机位置
Matrix.setLookAtM(mViewMatrix , 0, 1.0f, -10.0f, -4.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl)
{
if (program == 0)
return;
//获取变换矩阵vMatrix成员句柄
int vMatrix = GLES20.glGetUniformLocation(program, "vMatrix");
//设置vMatrix的值
GLES20.glUniformMatrix4fv(vMatrix, 1, false, mMVPMatrix, 0);
//获取顶点着色器的vPosition成员句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//启用vPosition句柄
GLES20.glEnableVertexAttribArray(vPosition);
//传的圆筒面的所有坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, cylinderVertexBuffer);
//绘制圆筒面
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, cylinderShapePos.length / 3);
//底部圆形的所有坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, bottomVertexBuffer);
//绘制底部圆形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, bottomShapePos.length / 3);
//顶部圆形的所有坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, topVertexBuffer);
//绘制顶部圆形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, topShapePos.length / 3);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(vPosition);
}
public int loadShader(int type, String shaderCode)
{
//创建空的着色器
int shader = GLES20.glCreateShader(type);
//将着色器程序加到着色器中
GLES20.glShaderSource(shader, shaderCode);
//编译色器程序
GLES20.glCompileShader(shader);
return shader;
}
private void createPositions()
{
ArrayList cylinder = new ArrayList<>();
ArrayList bottom = new ArrayList<>();
ArrayList top = new ArrayList<>();
bottom.add(0.0f);
bottom.add(0.0f);
bottom.add(0.0f);
top.add(0.0f);
top.add(0.0f);
top.add(2.0f);
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan)
{
float x = (float) (radius * Math.sin(i * Math.PI / 180f));
float y = (float) (radius * Math.cos(i * Math.PI / 180f));
//圆筒坐标
cylinder.add(x);
cylinder.add(y);
cylinder.add(2.0f);
cylinder.add(x);
cylinder.add(y);
cylinder.add(0.0f);
//底下圆形坐标
bottom.add(x);
bottom.add(y);
bottom.add(0.0f);
//顶部圆形坐标
top.add(x);
top.add(y);
top.add(2.0f);
}
cylinderShapePos = new float[cylinder.size()];
for (int i = 0; i < cylinderShapePos.length; i++)
{
cylinderShapePos[i] = cylinder.get(i);
}
bottomShapePos = new float[bottom.size()];
for (int i = 0; i < bottomShapePos.length; i++)
{
bottomShapePos[i] = bottom.get(i);
}
topShapePos = new float[top.size()];
for (int i = 0; i < topShapePos.length; i++)
{
topShapePos[i] = top.get(i);
}
}
}
球
相对于圆锥圆柱来说,球体的拆解就复杂许多了,比较常见的拆解方法是将按照经纬度拆解和按照正多面体拆解,下图分别为正多面体和经纬度拆解.
正多面体拆解
经纬度拆解(每一个小块看作一个矩形,再拆成三角形):
由上图可以明显看出,多面体虽然看起来好看点,但是还是按照经纬度方式来拆解计算容易点,毕竟规律那么明显。
球上点的坐标
无论是按照经纬度拆还是多面体拆,都需要知道球上面点的坐标,这算是基本的几何知识了。以球的中心为坐标中心,球的半径为R的话,那么球上点的坐标(x0,y0,z0)为:
x0 = R * cos(a) * sin(b);
y0 = R * sin(a);
z0 = R * cos(a) * cos(b);
其中,a为圆心到点的线段与xz平面的夹角,b为圆心到点的线段在xz平面的投影与z轴的夹角,如图:
得到顶点后,剩下的工作就和之前绘制其他图形一样了。
但是如果继续使用圆锥的着色器,我们会得到这样的一个球:
看起来都不太像个球了,要不是有条白线,这是不是个球就不好说了。我们需要修啊下顶点着色器,让它有立体感。把顶点着色器修改为:
private final String vertextShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"varying vec4 vColor;" +
"float color;" +
"void main() {" +
" gl_Position = vMatrix * vPosition;" +
" if(vPosition.z>0.0){" +
" color=vPosition.z;" +
" }else{" +
" color=-vPosition.z;" +
" }" +
" vColor=vec4(color,color,color,1.0);" +
"}";
运行一下,我们得到的结果如下图:
具体代码:
public class MyEighthRender implements GLSurfaceView.Renderer
{
private final String vertextShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"varying vec4 vColor;" +
"float color;" +
"void main() {" +
" gl_Position = vMatrix * vPosition;" +
" if(vPosition.z>0.0){" +
" color=vPosition.z;" +
" }else{" +
" color=-vPosition.z;" +
" }" +
" vColor=vec4(color,color,color,1.0);" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int program;
private FloatBuffer vertexBuffer;
//投影矩阵
private final float[] mProjectMatrix = new float[16];
//相机位置矩阵
private final float[] mViewMatrix = new float[16];
//计算变换矩阵
private final float[] mMVPMatrix = new float[16];
private float[] shapePos;
private float step = 1f;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//将背景设置为灰色
GLES20.glClearColor(0.5f, 0.2f, 1.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//顶点坐标
createPositions();
//申请底层空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(shapePos.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer = byteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
vertexBuffer.put(shapePos);
vertexBuffer.position(0);
//创建顶点着色器程序
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
//创建片元着色器程序
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
if (vertexShader == 0 || fragmentShader == 0)
{
return;
}
//创建一个空的OpenGL ES程序
program = GLES20.glCreateProgram();
//将顶点着色器加入程序
GLES20.glAttachShader(program, vertexShader);
//将片元着色器加入程序
GLES20.glAttachShader(program, fragmentShader);
//连接到着色器程序中
GLES20.glLinkProgram(program);
//使用程序
GLES20.glUseProgram(program);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
//设置透视矩阵
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 1.0f, -10.0f, -4.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl)
{
if (program == 0)
return;
//获取变换矩阵vMatrix成员句柄
int vMatrix = GLES20.glGetUniformLocation(program, "vMatrix");
//设置vMatrix的值
GLES20.glUniformMatrix4fv(vMatrix, 1, false, mMVPMatrix, 0);
//获取顶点着色器的vPosition成员句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//启用vPosition句柄
GLES20.glEnableVertexAttribArray(vPosition);
//传的圆筒面的所有坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer);
//绘制圆筒面
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, shapePos.length / 3);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(vPosition);
}
public int loadShader(int type, String shaderCode)
{
//创建空的着色器
int shader = GLES20.glCreateShader(type);
//将着色器程序加到着色器中
GLES20.glShaderSource(shader, shaderCode);
//编译色器程序
GLES20.glCompileShader(shader);
return shader;
}
private void createPositions()
{
ArrayList data = new ArrayList<>();
float r1, r2;
float h1, h2;
float sin, cos;
for (float i = -90; i < 90 + step; i += step)
{
r1 = (float) Math.cos(i * Math.PI / 180.0);
r2 = (float) Math.cos((i + step) * Math.PI / 180.0);
h1 = (float) Math.sin(i * Math.PI / 180.0);
h2 = (float) Math.sin((i + step) * Math.PI / 180.0);
// 固定纬度, 360 度旋转遍历一条纬线
float step2 = step * 2;
for (float j = 0.0f; j < 360.0f + step; j += step2)
{
cos = (float) Math.cos(j * Math.PI / 180.0);
sin = (float) Math.sin(j * Math.PI / 180.0);
data.add(r2 * cos);
data.add(h2);
data.add(r2 * sin);
data.add(r1 * cos);
data.add(h1);
data.add(r1 * sin);
}
}
shapePos = new float[data.size()];
for (int i = 0; i < shapePos.length; i++)
{
shapePos[i] = data.get(i);
}
}
}