支持:(1) opengl es绘制三角形拼成球体
(2)2的幂次方大小的图片作为纹理映射到整个球面上
(3)双点触控缩放球体
(4) 拖动旋转球体
效果图:
![](https://img-my.csdn.net/uploads/201210/17/1350478902_5237.jpg)
在 android openGL 提供了绘制三角形(面)的函数
// 绑定点的坐标
gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);
// 按三角形模式(vCount个点中,每三个点作为一组)绘制多个三角形
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vCount);
绘制球体:
1、将球体横着切成N层,然后按弧线竖着切M份,就得到了N*M个长方形
2、在按对角戏切分就得到了2*N*M个三角形,当然也可以有其他的方法划分成三角形
3、然后计算每个三角形的顶点坐标
计算三角形顶点坐标:
final int angleSpan = 9;// 将球进行单位切分的角度
for (int rowAngle = -90; rowAngle <= 90; rowAngle += angleSpan) {
for (int colAngleAngle = 0; colAngleAngle < 360; colAngleAngle += angleSpan) {
double xozLength = R * Math.cos(Math.toRadians(rowAngle));
int x = (int) (xozLength * Math.cos(Math.toRadians(colAngleAngle)));
int z = (int) (xozLength * Math.sin(Math.toRadians(colAngleAngle)));
int y = (int) (R * Math.sin(Math.toRadians(rowAngle)));
alVertix.add(x);
alVertix.add(y);
alVertix.add(z);
}
}
4、准备纹理
纹理图的大小一定要是2的幂次方的,如果不是,可以长宽缩放成这个规格大小的图片。
public int initTexture(GL10 gl, int resourceId) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
int currTextureId = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
InputStream is = this.getResources().openRawResource(resourceId);
Bitmap bitmapTmp;
try {
bitmapTmp = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);
bitmapTmp.recycle();
return currTextureId;
}
bitmap和纹理绑定:
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);
5、计算每个三角形的坐标与其对应这张二维纹理图的坐标
按比例计算:
vCount = alVertix.size() / 3;// 顶点的数量为坐标值数量的1/3,因为一个顶点有3个坐标
// 将alVertix中的坐标值转存到一个int数组中
int vertices[] = new int[vCount * 3];
for (int i = 0; i < alVertix.size(); i++) {
vertices[i] = alVertix.get(i);
}
alVertix.clear();
ArrayList<Float> alTexture = new ArrayList<Float>();// 纹理
int row = (180 / angleSpan) + 1;// 球面切分的行数
int col = 360 / angleSpan;// 球面切分的列数
float splitRow = row;
float splitCol = col;
for (int i = 0; i < row; i++)// 对每一行循环
{
if (i > 0 && i < row - 1) {// 中间行
for (int j = 0; j < col; j++) {// 中间行的两个相邻点与下一行的对应点构成三角形
int k = i * col + j;
// 第1个三角形顶点
alVertix.add(vertices[(k + col) * 3]);
alVertix.add(vertices[(k + col) * 3 + 1]);
alVertix.add(vertices[(k + col) * 3 + 2]);
// 纹理坐标
alTexture.add(j / splitCol);
alTexture.add((i + 1) / splitRow);
// 第2个三角形顶点
int tmp = k + 1;
if (j == col - 1) {
tmp = (i) * col;
}
alVertix.add(vertices[(tmp) * 3]);
alVertix.add(vertices[(tmp) * 3 + 1]);
alVertix.add(vertices[(tmp) * 3 + 2]);
// 纹理坐标
alTexture.add((j + 1) / splitCol);
alTexture.add(i / splitRow);
// 第3个三角形顶点
alVertix.add(vertices[k * 3]);
alVertix.add(vertices[k * 3 + 1]);
alVertix.add(vertices[k * 3 + 2]);
// 纹理坐标
alTexture.add(j / splitCol);
alTexture.add(i / splitRow);
}
for (int j = 0; j < col; j++) {// 中间行的两个相邻点与上一行的对应点构成三角形
int k = i * col + j;
// 第1个三角形顶点
alVertix.add(vertices[(k - col) * 3]);
alVertix.add(vertices[(k - col) * 3 + 1]);
alVertix.add(vertices[(k - col) * 3 + 2]);
alTexture.add(j / 40f);
alTexture.add((i - 1) / splitRow);
int tmp = k - 1;
if (j == 0) {
tmp = i * col + col - 1;
}
// 第2个三角形顶点
alVertix.add(vertices[(tmp) * 3]);
alVertix.add(vertices[(tmp) * 3 + 1]);
alVertix.add(vertices[(tmp) * 3 + 2]);
alTexture.add((j - 1) / splitCol);
alTexture.add(i / splitRow);
// 第3个三角形顶点
alVertix.add(vertices[k * 3]);
alVertix.add(vertices[k * 3 + 1]);
alVertix.add(vertices[k * 3 + 2]);
alTexture.add(j / splitCol);
alTexture.add(i / splitRow);
}
}
}
6、画笔绑定纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
7、绘制
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vCount);
8、控制旋转和缩放:
给ball实体设置三个旋转变量 :
public float mAngleX = 0;// 沿x轴旋转角度
public float mAngleY = 0;// 沿y轴旋转角度
public float mAngleZ = 0;// 沿z轴旋转角度
给ball实体设置缩放变量 :
public float zoom = -3f;
public final float maxZoom = -2f;
public final float minZoom = -4f;
9、ball每次draw之前变换坐标系:
gl.glTranslatef(0f, 0f, zoom);
gl.glRotatef(mAngleX, y_axis[0], y_axis[1], y_axis[2]);
10、重写OnTouch函数
控制手指拖动和多点缩放
private OnTouchListener onTouchListener = new OnTouchListener() {
float lastX, lastY;
private int mode = 0; // 触控点的个数
float oldDist = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = 1;
lastX = event.getRawX();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;
oldDist = caluDist(event);
break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_UP:
mode = 0;
break;
case MotionEvent.ACTION_MOVE:
if (mode >= 2) {
float newDist = caluDist(event);
if (Math.abs(newDist - oldDist) > 2f) {
zoom(newDist, oldDist);
}
} else {
float dx = event.getRawX() - lastX;
float dy = event.getRawY() - lastY;
float a = 180.0f / 320;
ball.mAngleX += dx * a;
ball.mAngleY += dy * a;
}
break;
}
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
return true;
}
};
mode是用来记录当前屏幕上按下了几个点。
11、源码下载:
点击打开链接 : http://download.csdn.net/detail/newfar1991/4657846