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

Android OpenGL绘制球体

2016-08-16 18:01 411 查看
创建GLSurfaceView,并调用setRenderer(GLSurfaceView.Renderer)方法注册其渲染器.

GLSurfaceView.Renderer 定义了一个统一图形绘制的接口,它定义了如下三个接口函数: 

onSurfaceCreated:在这个方法中主要用来设置一些绘制时不常变化的参数.

onSurfaceChanged:如果设备支持屏幕横向和纵向切换,这个方法将发生在横向<->纵向互换时。此时可以重新设置绘制的纵横比率。

onDrawFrame:定义实际的绘图操作.

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 设置背景色:白色
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// 启动阴影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 复位深度缓存
gl.glClearDepthf(1f);
// 所做深度测试的类型
gl.glDepthFunc(GL10.GL_LEQUAL);
// 启动深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
// 对透视进行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

//计算球面顶点坐标
makeSphereVertices();
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置输出屏幕大小
gl.glViewport(0, 0, width, height);
// 设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重置投影矩阵
gl.glLoadIdentity();
// 设置视口大小
GLU.gluPerspective(gl, 50, (float) width / (float) height, 0.1f, 100.0f);
// 设置透视图视口大小
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置投影矩阵
gl.glLoadIdentity();
}

@Override
public void onDrawFrame(GL10 gl) {
// 清除屏幕和深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置当前的模型观察矩阵
l.glLoadIdentity();
//设置画笔颜色
gl.glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
//设置视图点
GLU.gluLookAt(gl, 0.0f, 5.0f, 15.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
//画图
draw(gl);
}


makeSphereVertices()是用来计算球面顶点坐标的方法。
球体的绘制,实际上就是绘制一个多面体,当多面体的边数够多,看起来就像是一个球了。

private void makeSphereVertices() {
float altitude;//纬度
float altitudeDelta;//下一层纬度
float azimuth;//经度
float ex;//点坐标x
float ey;//点坐标y
float ez;//点坐标z
//将纬度等分成divide份,这样就能计算出每一等份的纬度值
for(int i = 0; i <= divide; i++) {
//获取当前等份的纬度值
altitude = (float) (Math.PI/2.0 - i * (Math.PI) / divide);
//获取下一等份的纬度值
altitudeDelta = (float) (Math.PI/2.0 - (i + 1) * (Math.PI) / divide);

//当前纬度和下一纬度的点坐标
float[] vertices = new float[divide*6+6];

//将经度等分成divide份,这样就能得到当前纬度值和下一纬度值的每一份经度值
for(int j = 0; j <= divide; j++) {
//计算经度值
azimuth = (float)(j * (Math.PI*2) / divide);

ex = (float) (Math.cos(altitude) * Math.cos(azimuth));
ey = (float)  Math.sin(altitude);
ez = (float) -(Math.cos(altitude) * Math.sin(azimuth));

//此经度值下的当前纬度的点坐标
vertices[6*j+0] = radius * ex;
vertices[6*j+1] = radius * ey;
vertices[6*j+2] = radius * ez;

ex = (float) (Math.cos(altitudeDelta) * Math.cos(azimuth));
ey = (float) Math.sin(altitudeDelta);
ez = (float) -(Math.cos(altitudeDelta) * Math.sin(azimuth));

//此经度值下的下一纬度的点坐标
vertices[6*j+3] = radius * ex;
vertices[6*j+4] = radius * ey;
vertices[6*j+5] = radius * ez;

}
//将点坐标转换成FloatBuffer类型添加到点坐标集合ArrayList<FloatBuffer>里
mVertices.add(makeFloatBufferFromArray(vertices));
}
}


makeFloatBufferFromArray()用来将点坐标数组转换成绘画时声明点坐标的FloatBuffer类型
private FloatBuffer makeFloatBufferFromArray(float[] array) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(array.length * Float.SIZE);
byteBuffer.order(ByteOrder.nativeOrder());
FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
floatBuffer.put(array);
floatBuffer.position(0);
return floatBuffer;
}


最后是draw()方法,当点坐标都获取、所有数据都初始化之后,就可以将球画出来啦。
<pre name="code" class="java"> private void draw(GL10 gl) {
//打开顶点开关
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//每次声明两条临近的纬度线的点坐标并绘制出来
for(int i = 0;i <= divide ; i++){
//将顶点坐标传给 OpenGL 管道
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertices.get(i));
//用画线的方式将点连接并画出来
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, divide*2+2);
}
//关闭顶点开关
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}



最后就长这样啦~~~(✿◡‿◡)



完整代码下载地址:点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: