android 地球仪源码,android OpenGL ES 地球仪绘制——球体绘制及纹理映射

支持:

(1) opengl es绘制三角形拼成球体

(2)2的幂次方大小的图片作为纹理映射到整个球面上

(3)双点触控缩放球体

(4) 拖动旋转球体

效果图:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

在 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 alTexture = new ArrayList();// 纹理

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、源码下载:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值