Android开发之通过渲染纹理展示地球仪

本文涉及的产品
视觉智能开放平台,分割抠图1万点
视觉智能开放平台,图像资源包5000点
视觉智能开放平台,视频资源包5000点
简介: 该文阐述了如何使用OpenGL为三维物体添加纹理,以增强其真实感。纹理坐标是二维的,用于标记摊平后的“布料”对应物体的哪个部位,类似裁缝制作衣服的过程。在OpenGL中,启用纹理和深度测试是关键,还包括设置纹理参数、分配纹理编号、绑定位图材质等步骤。计算材质的纹理坐标后,通过`glDrawArrays`结合顶点和纹理坐标逐个贴图。最终示例展示了将世界地图贴到球体上形成逼真的地球仪效果。通过控制旋转、平移和缩放,能实现简单的三维动画效果。

上一篇文章介绍了如何使用GL10描绘三维物体的线段框架,后面给出的立方体和球体效果图,虽然看起来具备立体的轮廓,可离真实的物体还差得远。因为现实生活中的物体不仅仅有个骨架,还有花纹有光泽(比如衣服),所以若想让三维物体更加符合实际,就得给它加一层皮,也可以说是加一件衣服,这个皮毛大衣用OpenGL的术语称呼则为“纹理”。

三维物体的骨架是通过三维坐标系表示的,每个点都有x、y、z三个方向上的数值大小。那么三维物体的纹理也需要通过纹理坐标系来表达,但纹理坐标并非三维形式而是二维形式,这是怎么回事呢?打个比方,裁缝店给顾客制作一件衣服,首先要丈量顾客的身高、肩宽,以及胸围、腰围、臀围等三围,然后才能根据这些身体数据剪裁布料,这便是所谓的量体裁衣。那做衣服的一匹一匹布料又是什么样子的?当然是摊开来一大片一大片整齐的布匹了,明显这些布匹近似于二维的平面。但是最终的成品衣服穿在顾客身上却是三维的模样,显然中间必定有个从二维布匹到三维衣服的转换过程。转换工作的一系列计算,离不开前面测量得到的身高、肩宽、三围等等,其中身高和肩宽是直线的长度,而三围是曲线的长度。如果把三围的曲线剪断并拉直,就能得到直线形式的三围;同理,把衣服这个三维的曲面剪开,然后把它摊平,得到平面形式的衣服。于是,剪开并摊平后的平面衣服,即可与原始的平面布匹对应起来了。因此,纹理坐标的目的就是标记被摊平衣服的二维坐标,从而将同属二维坐标系的布匹一块一块贴上去。

在OpenGL体系之中,纹理坐标又称UV坐标,通过两个浮点数组合来设置一个点的纹理坐标(U,V),其中U表示横轴,V表示纵轴。纹理坐标不关心物体的三维位置,好比一个人不管走到哪里,不管做什么动作,身上穿的还是那件衣服。纹理坐标所要表述的,是衣服的一小片一小片分别来自于哪块布料,也就是说,每一小片衣服各是由什么材质构成。既可以是棉布材质,也可以是丝绸材质,还可以是尼龙材质,纹理只是衣服的脉络,材质才是最终贴上去的花色。

给三维物体穿衣服的动作,通常叫做给三维图形贴图,更专业地说叫纹理渲染。渲染纹理的过程主要由三大项操作组成,分别说明如下:

一、启用纹理的一系列开关设置,该系列又包括下述步骤:

1、渲染纹理肯定要启用纹理功能了,并且为了能够正确渲染,还需同时启用深度测试。启用深度测试的目的,是只绘制物体朝向观测者的正面,而不绘制物体的背面。上一篇文章的立方体和球体因为没有开启深度测试,所以背面的线段也都画了出来。启用纹理与深度测试的代码示例如下:

        // 启用某功能,对应的glDisable是关闭某功能。
        // GL_DEPTH_TEST指的是深度测试。启用纹理时必须同时开启深度测试,
        // 这样只有像素点前面没有东西遮挡之时,该像素点才会予以绘制。
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 启用纹理
        gl.glEnable(GL10.GL_TEXTURE_2D);
AI 代码解读

2、OpenGL默认的环境光是没有特定光源的散光,如果要实现特定光源的光照效果,则需开启灯照功能,另外至少启用一个光源,或者同时启用多个光源。下面是只开启一处灯光的代码例子:

        // 开启灯照效果
        gl.glEnable(GL10.GL_LIGHTING);
        // 启用光源0
        gl.glEnable(GL10.GL_LIGHT0);
AI 代码解读

3、就像人可以穿着多件衣服那样,三维物体也能接连描绘多种纹理,于是每次渲染纹理都得分配一个纹理编号。这个纹理编号的分配操作有点拗口,开发者不用太在意,只管按照下面例行公事便成:

        int[] textures = new int[1];
        // 告诉OpenGL去生成textures.textures中存放了创建的Texture ID
        gl.glGenTextures(1, textures, 0);
        //通知OpenGL库使用这个Texture
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
AI 代码解读

4、如同衣服有很宽松的款式,也有很紧身的款式,对于这些不是那么合身的情况,OpenGL要怎么去渲染放大或者缩小了的纹理?此时就要指定下述的纹理参数设置了:

        //用来渲染的Texture可能比要渲染的区域大或者小,所以需要设置Texture需要放大或是缩小时OpenGL的模式
        //GL_TEXTURE_MAG_FILTER表示放大的情况,GL_TEXTURE_MIN_FILTER表示缩小的情况
        //常用的两种模式为GL10.GL_LINEAR和GL10.GL_NEAREST。
        //需要比较清晰的图像使用GL10.GL_NEAREST,而使用GL10.GL_LINEAR则会得到一个较模糊的图像
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
        //当定义的材质坐标点超过UV坐标定义的大小(UV坐标为0,0到1,1),这时需要告诉OpenGL库如何去渲染这些不存在的Texture部分。
        //有两种设置:GL_REPEAT 重复Texture。GL_CLAMP_TO_EDGE 只靠边线绘制一次。
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
AI 代码解读

5、最后还要声明一个位图对象绑定该纹理,表示后续的纹理渲染动作将使用该位图包裹三维物体,绑定位图材质的代码如下所示:

        // 将Bitmap资源和Texture绑定起来,即指定一个具体的材质
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
AI 代码解读

二、计算材质的纹理坐标

三维物体的每个顶点坐标都以(x,y,z)构成,因此若要表达三个顶点的空间位置,就需要大小为33=9的浮点数组。本文开头提到纹理坐标是二维的,因此表达三个顶点的纹理坐标只需大小为32=6的浮点数组。至于详细的纹理坐标计算,则依据具体物体的形状以及材质的尺寸来决定,这里不再赘述。

三、在三维图形上根据纹理点坐标逐个贴上对应的材质

渲染纹理除了要打开顶点开关,还要打开材质开关。同理,绑定顶点坐标的时候,也要绑定纹理坐标。因为材质是一片一片的花色,所以调用glDrawArrays绘制方法时,要指定采取GL10.GL_TRIANGLE_STRIP方式,表示本次绘图画的是一个三角形的平面,这样从位图对象裁剪出来的花纹就贴图完成了。

下面是进行材质贴图的绘制代码例子:

    private void drawGlobe(GL10 gl) {
   
   
        //打开材质开关
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //打开顶点开关
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        for(int i= 0;i<=divide; i++){
   
   
            //绑定每片皮肤的顶点坐标
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertices.get(i));
            //绑定每片皮肤的纹理坐标,第一个参数为2表示纹理坐标是二维的
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureCoords.get(i));
            //GL_LINE_STRIP只绘制线条,GL_TRIANGLE_STRIP才是画三角形的面
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, divide*2+2);
        }
        //关闭顶点开关
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //关闭材质开关
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }
AI 代码解读

最后观察一下把世界地图贴到球体上面形成地球仪的效果,下面是原始的世界地图平面,可以看到底部的南极洲被拉得很大:

earth_plain.jpg

下面是利用OpenGL贴图成功的三维地球仪转动动画,看起来就逼真多了:

earth_gl.gif

话说上面竟然是三维动画,其实OpenGL绘制三维动画很简单,由于GLSurfaceView的渲染器会持续调用onDrawFrame函数,因此只要在该函数中设置渐变的变换数值,即可轻松实现以下动画效果:

1、调用glRotatef方法设置渐变的角度,可实现三维物体的旋转动画;

2、调用glTranslatef方法设置渐变的位移,可实现三维物体的平移动画;

3、调用glScalef方法设置渐变的放大或缩小倍率,可实现三维物体的缩放动画;

aqi00
+关注
目录
打赏
0
2
2
0
71
分享
相关文章
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
31 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
132 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
43 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
84 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
36 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
79 19
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
94 14
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
175 3
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等