OpenglES2.0 for Android:来做个地球吧

前言

上两节中我们说了纹理映射,也利用纹理给我们的平面图形以及立方体穿上了漂亮的衣服,在继续学习其他知识之前,让我们先来用纹理映射以及我们前面做的球
来实现一个地球的贴图。整体效果如下 图所示:
素材资源下载 :http://download.csdn.net/detail/cassiepython/9551772
里面放了两张图片,都是可以用的,我们用其中一张就可以。

Ok , 现在回到我们前面绘制球的项目(http://blog.csdn.net/cassiepython/article/details/51620114),前面我们已经完成了球的绘制,而且使用了棋盘纹理,

这次我们需要使用上面的图片来做纹理贴图,所以我们先删除掉原来的关于棋盘纹理的代码。然后将纹理工具类copy到工具类目录下,准备工作完成。

(最后会给出整个项目的代码,如果你不想从原来的开始改的话可以直接看这个)

看下我们的步骤 :

1 修改着色器代码加入纹理

这个在上两节已经说过,直接看更改后的代码:

<span style="font-size:12px;">//vertex_shader_ball.glsl
uniform mat4 u_Matrix;//最终的变换矩阵
attribute vec4 a_Position;//顶点位置
attribute vec2 a_TextureCoordinates;
varying vec2 v_TextureCoordinates;
void main()
{                              gl_Position = u_Matrix * a_Position;v_TextureCoordinates = a_TextureCoordinates;
} </span>
<span style="font-size:12px;">//fragment_shader_ball.glsl
precision mediump float;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;
void main()
{gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
}   </span>

2 纹理坐标计算

前面我们说过做纹理贴图最关键的地方是确定我们的顶点坐标与纹理坐标的对应关系。对于二维的图像以及比较规则的三维图像比较容易确定,但是对于球该如何处理呢?看我们原先是如何计算球的顶点坐标的。我们通过半径r (确定量)和两个角度 θ (范围0到180)和φ(范围0到360)来计算绘制球时的一个小方格的左上角顶点的坐标,同时知道分割的间距singleSpan  ,由此可以确定这个小方格的其余三个顶点坐标。同理我们如何能确定左上角顶点坐标的对应的纹理坐标,其余的也就容易求了。于是问题转化成这样:要求一个球的纹理坐标只需要确定绘制球的某个小方格的四个顶点对应的纹理坐标,进一步讲如何确定小方格的左上角顶点与相应纹理坐标的关系。

现在我们以及清楚了问题,下面考虑具体的。我们绘制球时是一个个的小方格(矩形),纹理应该也是分成一个个的小方格(矩形),然后与球的一个个的小方格一一对应。绘制球的确定小方格位置的两个变量(θ 和φ)的范围分别为 0 到180 ,0到360 ,对应纹理的T (1到0 ,注意为什么不是0到1 见上一节最后)和 S ( 0到1), 于是通过比例g关系我们有如下:

当前角度 θ /  180  = 1– 纹理 t坐标 / 1

当前角度φ / 360 = 纹理 s坐标 / 1

通过这两个角度我们确定了顶点坐标也确定了相应的纹理坐标,由此我们就知道了顶点对应的纹理坐标。下面我们就可以具体编码实现了。

此时Ball.java代码如下 :

package com.cumt.shape;import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glUniform1i;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import android.content.Context;
import android.opengl.GLES20;
import com.cumt.openglesearth.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import com.cumt.utils.TextureHelper;public class Ball {private Context context;private static final float UNIT_SIZE = 1.0f;// 单位尺寸private float r = 0.6f; // 球的半径final int angleSpan = 10;// 将球进行单位切分的角度private FloatBuffer vertexBuffer;// 顶点坐标int vCount = 0;// 顶点个数,先初始化为0// float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数private static final int COORDS_PER_VERTEX = 3;// **********************************************************************private static final int TEXTURE_COORDIANTES_COMPONENT_COUNT = 2; // 每个纹理坐标为 S T两个private static final String A_TEXTURE_COORDINATES = "a_TextureCoordinates";//纹理private static final String U_TEXTURE_UNIT = "u_TextureUnit";//纹理private FloatBuffer textureBuffer;// 纹理坐标private int uTextureUnitLocation;private int aTextureCoordinates;private int texture;// ***********************************************************************private int program;private static final String A_POSITION = "a_Position";private static final String U_MATRIX = "u_Matrix";private int uMatrixLocation;private int aPositionLocation;public Ball(Context context){this.context = context;initVertexData();getProgram();aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);// ***********************************************************************initTexture();// **********************************************************************//---------传入顶点数据数据GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false, 0, vertexBuffer);GLES20.glEnableVertexAttribArray(aPositionLocation);// ***********************************************************************GLES20.glVertexAttribPointer(aTextureCoordinates, TEXTURE_COORDIANTES_COMPONENT_COUNT,GLES20.GL_FLOAT, false, 0, textureBuffer);GLES20.glEnableVertexAttribArray(aTextureCoordinates);// **********************************************************************}public void initVertexData() {ArrayList<Float> alVertix = new ArrayList<Float>();// 存放顶点坐标的ArrayList// ***************************************ArrayList<Float> textureVertix = new ArrayList<Float>();// 存放纹理坐标的ArrayList// ***************************************for (int vAngle = 0; vAngle < 180; vAngle = vAngle + angleSpan)// 垂直方向angleSpan度一份{for (int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)// 水平方向angleSpan度一份{// 纵向横向各到一个角度后计算对应的此点在球面上的坐标float x0 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math.toRadians(hAngle)));float y0 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math.toRadians(hAngle)));float z0 = (float) (r * UNIT_SIZE * Math.cos(Math.toRadians(vAngle)));// Log.w("x0 y0 z0","" + x0 + "  "+y0+ "  " +z0);float x1 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math.toRadians(hAngle + angleSpan)));float y1 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math.toRadians(hAngle + angleSpan)));float z1 = (float) (r * UNIT_SIZE * Math.cos(Math.toRadians(vAngle)));float x2 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math.cos(Math.toRadians(hAngle + angleSpan)));float y2 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math.sin(Math.toRadians(hAngle + angleSpan)));float z2 = (float) (r * UNIT_SIZE * Math.cos(Math.toRadians(vAngle + angleSpan)));// Log.w("x2 y2 z2","" + x2 + "  "+y2+ "  " +z2);float x3 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math.cos(Math.toRadians(hAngle)));float y3 = (float) (r * UNIT_SIZE* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math.sin(Math.toRadians(hAngle)));float z3 = (float) (r * UNIT_SIZE * Math.cos(Math.toRadians(vAngle + angleSpan)));// Log.w("x3 y3 z3","" + x3 + "  "+y3+ "  " +z3);// 将计算出来的XYZ坐标加入存放顶点坐标的ArrayListalVertix.add(x1);alVertix.add(y1);alVertix.add(z1);alVertix.add(x3);alVertix.add(y3);alVertix.add(z3);alVertix.add(x0);alVertix.add(y0);alVertix.add(z0);// *****************************************************************float s0 = hAngle / 360.0f;float s1 = (hAngle + angleSpan)/360.0f ;float t0 = 1 - vAngle / 180.0f;float t1 = 1 - (vAngle + angleSpan) / 180.0f;textureVertix.add(s1);// x1 y1对应纹理坐标textureVertix.add(t0);textureVertix.add(s0);// x3 y3对应纹理坐标textureVertix.add(t1);textureVertix.add(s0);// x0 y0对应纹理坐标textureVertix.add(t0);// *****************************************************************alVertix.add(x1);alVertix.add(y1);alVertix.add(z1);alVertix.add(x2);alVertix.add(y2);alVertix.add(z2);alVertix.add(x3);alVertix.add(y3);alVertix.add(z3);// *****************************************************************textureVertix.add(s1);// x1 y1对应纹理坐标textureVertix.add(t0);textureVertix.add(s1);// x2 y3对应纹理坐标textureVertix.add(t1);textureVertix.add(s0);// x3 y3对应纹理坐标textureVertix.add(t1);// *****************************************************************}}vCount = alVertix.size() / COORDS_PER_VERTEX;// 顶点的数量// 将alVertix中的坐标值转存到一个float数组中float vertices[] = new float[vCount * COORDS_PER_VERTEX];for (int i = 0; i < alVertix.size(); i++) {vertices[i] = alVertix.get(i);}vertexBuffer = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();// 把坐标们加入FloatBuffer中vertexBuffer.put(vertices);// 设置buffer,从第一个坐标开始读vertexBuffer.position(0);// *****************************************************************float textures[] = new float[textureVertix.size()];for(int i=0;i<textureVertix.size();i++){textures[i] = textureVertix.get(i);}textureBuffer = ByteBuffer.allocateDirect(textures.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();// 把坐标们加入FloatBuffer中textureBuffer.put(textures);// 设置buffer,从第一个坐标开始读textureBuffer.position(0);// *****************************************************************}//获取programprivate void getProgram(){//获取顶点着色器文本String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.vertex_shader_ball);//获取片段着色器文本String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.fragment_shader_ball);//获取program的idprogram = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);GLES20.glUseProgram(program);}// *******************************************************//初始化加载纹理private void initTexture(){aTextureCoordinates = GLES20.glGetAttribLocation(program, A_TEXTURE_COORDINATES);uTextureUnitLocation = GLES20.glGetAttribLocation(program, U_TEXTURE_UNIT);texture = TextureHelper.loadTexture(context, R.drawable.logo,false);// Set the active texture unit to texture unit 0.glActiveTexture(GL_TEXTURE0);// Bind the texture to this unit.glBindTexture(GL_TEXTURE_2D, texture);// Tell the texture uniform sampler to use this texture in the shader by// telling it to read from texture unit 0.glUniform1i(uTextureUnitLocation, 0);}// *******************************************************public void draw(){//将最终变换矩阵写入GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);}
}

其中 //****************************与 //**********************************之间的内容是我们相比原来绘制球新增加的内容。

相比前面的知识并没有新增什么,只是要注意纹理坐标的求法。
运行结果就如我们开头处展示的那样,这样使用原来会只球的代码,点击屏幕会绕y轴旋转,大家可以自由发挥

增添一些额外的变换。

3 源码下载

最后给出源码下载

http://download.csdn.net/detail/cassiepython/9551962

OpenglES2.0 for Android:来做个地球吧相关推荐

  1. OpenglES2.0 for Android:第一个OpenglES应用

    OpenglES2.0 for Android:第一个OpenglES应用 首先我们新建一个Android工程:com.opengl.openglestest 打开MainActivity,定义一个G ...

  2. OpenglES2.0 Android:画矩形

    OpenglES2.0 for Android:来画个矩形吧 原文链接:https://blog.csdn.net/cassiePython/article/details/51553842 OK,开 ...

  3. Android OpenGLES2.0(十六)——3D模型贴图及光照处理(obj+mtl)

    转自:http://blog.csdn.net/junzia/article/details/58272305 在Android OpenGLES2.0(十四)--Obj格式3D模型加载中实现了Obj ...

  4. Android OpenGLES2.0(五)——绘制立方体

    上篇博客中我们提到了OpenGLES中绘制的两种方法,顶点法和索引法.之前我们所使用的都是顶点法,这次绘制立方体使用索引法来绘制立方体. 构建立方体 上篇博客讲到正方形的绘制,立方体是是由六个正方形组 ...

  5. Android OpenGLES2.0(十七)——球形天空盒VR效果实现

    在3D游戏中通常都会用到天空盒,在3D引擎中也一般会存在天空盒组件,让开发者可以直接使用.那么天空盒是什么?天空盒又是如何实现的呢?本篇博客主要介绍如何在Android中利用OpenGLES绘制一个天 ...

  6. Android OpenGLES2.0(三)——等腰直角三角形和彩色的三角形

    上一篇博客中我们已经绘制出了一个直角三角形,虽然我们相对于坐标,我们设置的直角三角形的两腰是相等的,但是实际上展示出来的却并不是这样,虽然通过计算,我们可以把三角形的两腰计算一下比例,使它们在坐标上不 ...

  7. Android OpenGLES2.0(十八)——轻松搞定Blend颜色混合

    Blend是OpenGL中的一个非常重要的部分,它可以让每个输出的源和目的颜色以多种方式组合在一起,以呈现出不同的效果,满足不同的需求. Blend相关函数及意义 在OpenGLES1.0中,Blen ...

  8. Android解码输出yuv,Android OpenGLES2.0 直接导出YUV420数据

    Android OpenGLES2.0中提供的glReadPixels方法提供的格式只有RGB的几种格式,但是这并不妨碍我们导出YUV格式的数据,因为不管是RGBA还是YUV,都不是glReadPix ...

  9. Android OpenGLES2.0(十四)——Obj格式3D模型加载

    转自:http://blog.csdn.net/junzia/article/details/54300202 在博主<OpenGLES系列>文章中,最开始的几篇讲的就是OpenGL世界中 ...

最新文章

  1. 【Android 逆向】获取安装在手机中的应用的 APK 包 ( 进入 adb shell | 获取 root 权限 | 进入 /data/app/ 目录 | 拷贝 base.apk 到外置存储 )
  2. Linux内核调试方法总结之sysrq
  3. 编程方法学19:接口
  4. linux redis release.c:37:10: fatal error: release.h: No such file or directory
  5. php://input和php://output
  6. 电子邮箱里面的服务器,搭建电子邮件服务器
  7. 《编写高质量代码:改善c程序代码的125个建议》——建议14-2:在右移中合理地选择0或符号位来填充空出的位...
  8. 英特尔AMD竞相为笔记本处理器添加图形功能
  9. DWR2学习笔记(一)
  10. Go36-13-结构体及其方法
  11. MFC 教程【3_CObject类】
  12. 大数据可视化dataease(有所帮助)
  13. r语言html爬虫,如何用R语言爬取网页中的表格
  14. Scrapy ImportError: No module named items
  15. ActiveMQ(19):高级特性之独有消费者(Exclusive Consumer)
  16. phpnow升级mysql_PHPnow更新PHP版本后连接数据库错误(mysql_connect报错)
  17. 图像处理之opencv图片几何变化操作大全
  18. python+OpenCV笔记(二十四):Shi-Tomasi角点检测
  19. java 蓝桥杯 天干地支
  20. 【免费毕设】JSP旅游网站建设设计与实现(源代码+论文)

热门文章

  1. Youth means limitless possibilities.
  2. CRI HITFM 88.7的网络电台
  3. 使用CSS实现悬停显示二维码
  4. 网站制作系列教程--前端代码
  5. CTFHub技能树 Web-SSRF 302跳转 Bypass
  6. PCF8591模块测试
  7. 建立Baseline之repo,manifest
  8. ar8171 linux网卡驱动,ar8171 8175网卡驱动(ar8171网卡驱动下载)V1.0.1 官方最新版
  9. html5播放器的示例代码
  10. Arcgis正方形缓冲工具