OpenGL ES for Android 绘制旋转的地球

18 篇文章 51 订阅
订阅专栏

No 图 No Code,我们先来欣赏下旋转的地球:

是不是很酷炫,要想绘制出上面酷炫的效果需要3个步骤:

  1. 计算球体顶点数据
  2. 地球纹理贴图
  3. 通过MVP矩阵旋转地球

计算球体顶点数据

我们知道OpenGL中最基本的图元是三角形,任何复杂的图形都可以分解为一个个的三角形,球体也不例外,假设球体上有“经纬度”,通过“经纬度”将球体分割为一个个的四边形,如下图:

在把这些四边形分割为2个三角形,所以绘制球体的关键是计算“经纬度”相交的点的坐标。

假设球体的中心在坐标的原点(方便计算),半径为radius,n个经度,m个纬度,计算顶点坐标、索引、纹理坐标方法如下:

fun generateSphere(radius: Float, rings: Int, sectors: Int) {
            val PI = Math.PI.toFloat()
            val PI_2 = (Math.PI / 2).toFloat()

            val R = 1f / rings.toFloat()
            val S = 1f / sectors.toFloat()
            var r: Short
            var s: Short
            var x: Float
            var y: Float
            var z: Float

            val numPoint = (rings + 1) * (sectors + 1)
            val vertexs = FloatArray(numPoint * 3)
            val texcoords = FloatArray(numPoint * 2)
            val indices = ShortArray(numPoint * 6)

            var t = 0
            var v = 0
            r = 0
            while (r < rings + 1) {
                s = 0
                while (s < sectors + 1) {
                    x =
                        (Math.cos((2f * PI * s.toFloat() * S).toDouble()) * Math.sin((PI * r.toFloat() * R).toDouble())).toFloat()
                    y = -Math.sin((-PI_2 + PI * r.toFloat() * R).toDouble()).toFloat()
                    z =
                        (Math.sin((2f * PI * s.toFloat() * S).toDouble()) * Math.sin((PI * r.toFloat() * R).toDouble())).toFloat()

                    texcoords[t++] = s * S
                    texcoords[t++] = r * R

                    vertexs[v++] = x * radius
                    vertexs[v++] = y * radius
                    vertexs[v++] = z * radius
                    s++
                }
                r++
            }

            var counter = 0
            val sectorsPlusOne = sectors + 1
            r = 0
            while (r < rings) {
                s = 0
                while (s < sectors) {
                    indices[counter++] = (r * sectorsPlusOne + s).toShort()       //(a)
                    indices[counter++] = ((r + 1) * sectorsPlusOne + s).toShort()    //(b)
                    indices[counter++] = (r * sectorsPlusOne + (s + 1)).toShort()  // (c)
                    indices[counter++] = (r * sectorsPlusOne + (s + 1)).toShort()  // (c)
                    indices[counter++] = ((r + 1) * sectorsPlusOne + s).toShort()    //(b)
                    indices[counter++] = ((r + 1) * sectorsPlusOne + (s + 1)).toShort()  // (d)
                    s++
                }
                r++
            }

            vertexBuffer = GLTools.array2Buffer(vertexs)
            texBuffer = GLTools.array2Buffer(texcoords)
            mIndicesBuffer = GLTools.array2Buffer(indices)
            indicesNum = indices.size
        }

这个顶点的数据计算需要有比较好的立体感。最难的顶点坐标和纹理坐标已经完成。

顶点shader代码如下:

attribute vec4 a_Position;
attribute vec2 a_TexCoord;
uniform mat4 mvpMatrix;
varying vec2 v_TexCoord;
void main()
{
    v_TexCoord = a_TexCoord;
    gl_Position = mvpMatrix * a_Position;
}

片段shader代码如下:

precision mediump float;

uniform sampler2D u_Texture;
varying vec2 v_TexCoord;

void main()
{
    gl_FragColor = texture2D(u_Texture, v_TexCoord);
}

创建program、取参数句柄并生成顶点数据:

 override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
            GLES20.glClearColor(0F, 0F, 0F, 1F)
            createProgram()
            generateSphere(2F,75,150)
            //获取vPosition索引
            vPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_Position")
            texCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoord")
            mvpMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "mvpMatrix")
            textureLoc= GLES20.glGetUniformLocation(mProgramHandle, "u_Texture")

        }

private fun createProgram() {
            var vertexCode =
                AssetsUtils.readAssetsTxt(
                    context = context,
                    filePath = "glsl/sphere_vs.glsl"
                )
            var fragmentCode =
                AssetsUtils.readAssetsTxt(
                    context = context,
                    filePath = "glsl/sphere_fs.glsl"
                )
            mProgramHandle = GLTools.createAndLinkProgram(vertexCode, fragmentCode)
        }

sphere_vs.glsl 和 sphere_fs.glsl分别表示顶点shader和片段shader的文件,存放于assets/glsl目录下,readAssetsTxt为读取assets目录下文件的公用方法。generateSphere方式就是开始介绍的顶点数据生成的方法。

地球纹理贴图

地球纹理图片如下:

将地球图片转为纹理,代码如下:

override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
            ...

            var bitmap =
                BitmapFactory.decodeResource(context.resources, R.drawable.earth)
            textureId = GLTools.loadTexture(bitmap)
        }

GLTools.loadTexture为封装的工具类方法,在 OpenGL ES for Android 绘制纹理文章中已经详细介绍,图片纹理的相关内容也可以参考此文章。

MVP矩阵

初始化MVP矩阵

var modelMatrix = FloatArray(16)
var viewMatrix = FloatArray(16)
var projectionMatrix = FloatArray(16)

override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
            GLES20.glViewport(0, 0, width, height)

            Matrix.setIdentityM(viewMatrix, 0)
            Matrix.setLookAtM(
                viewMatrix, 0,
                0F, 5F, 10F,
                0F, 0F, 0F,
                0F, 1F, 0F
            )

            Matrix.setIdentityM(projectionMatrix, 0)
            val ratio = width.toFloat() / height
            //设置透视投影
            Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 20f)
        }

绘制并通过MVP矩阵旋转地球

override fun onDrawFrame(p0: GL10?) {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)

            GLES20.glUseProgram(mProgramHandle)
            //设置顶点数据
            vertexBuffer.position(0)
            GLES20.glEnableVertexAttribArray(vPositionLoc)
            GLES20.glVertexAttribPointer(vPositionLoc, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)

            //设置纹理顶点数据
            texBuffer.position(0)
            GLES20.glEnableVertexAttribArray(texCoordLoc)
            GLES20.glVertexAttribPointer(texCoordLoc, 2, GLES20.GL_FLOAT, false, 0, texBuffer)

            //设置纹理
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
            GLES20.glUniform1i(textureLoc, 0)

            updateMvpMatrix()
            GLES20.glUniformMatrix4fv(mvpMatrixLoc, 1, false, mMvpMatrix, 0)

            GLES20.glDrawElements(
                GLES20.GL_TRIANGLES,
                indicesNum,
                GLES20.GL_UNSIGNED_SHORT,
                mIndicesBuffer
            )
        }

var currentRotateDegree = 0F
fun updateMvpMatrix(){
            Matrix.setIdentityM(modelMatrix, 0)
            Matrix.rotateM(modelMatrix, 0, currentRotateDegree++, 0F, 1F, 0F)

            var mTempMvMatrix = FloatArray(16)
            Matrix.setIdentityM(mTempMvMatrix, 0)
            Matrix.multiplyMM(mTempMvMatrix, 0, viewMatrix, 0, modelMatrix, 0)
            Matrix.multiplyMM(mMvpMatrix, 0, projectionMatrix, 0, mTempMvMatrix, 0)
        }

到此地球的绘制就结束了,我们经常听说的天空穹、全景(VR)球体模式和地球的绘制基本一样,只不过是相机位置的不同而已。

更多相关阅读:

  • OpenGL ES for Android 总览

  • OpenGL ES for Android 环境搭建

  • OpenGL ES for Android 绘制纹理

  • OpenGL ES for Android 绘制立方体

android实现3D地球转动组件,Rajawali3D基础教程-一个地球旋转的例子
weixin_42120563的博客
05-25 1326
转载此译文请注明出处。这篇文章将帮助你在安卓中使用Rajawali 3D库实现一个基本的3D场景。关于最新版本的教程不是很多,有一些改动是需要注意的。在过去,Rajawali是在一个activity子类和fragment子类中渲染3D和2D场景。自从上一个官方版本0.9的发布之后,Rajawali是使用RajawaliSurfaceView 和 RajawaliTextureView 为用户显示渲...
Android OpenGL ES球体
yarkey09
07-03 8360
Android OpenGL ES球体
OpenGL ES for Android 视频缩放、旋转、平移
老孟Flutter
02-11 4110
在上一篇文章中我们介绍了如何使用OpenGL ES预览视频,在文章的末尾提到如果渲染视频的窗口宽高比和视频宽高比不一致会导致视频拉伸,这篇文章将会介绍如何通过视频的缩放来解决这个问题。 我们希望当视频的比例和窗口的比例不一样时,其中一边占满全屏,另一边等比缩放并居中,其余部分显示黑色,这个效果和我们平时使用的视频播放器的效果是一样的,效果如图: 我们在OpenGL ES for Android...
Android VR Player(全景视频播放器) [10]: VR全景视频渲染播放的实现(exoplayer,glsurfaceview,opengl es
热门推荐
山城过雨
05-13 1万+
前言 此博客的大部分内容来自我的毕业设计论文,因此语言上会偏正式一点,如果您有任何问题或建议,欢迎留言。在此感谢实验室的聂师兄,全景视频render部分的代码设计主要参考了他所编写的代码来完成,他对视频渲染过程的讲解也让我对此部分有了更好的理解! 为了能播放MEPG-DASH标准的视频,我使用了ExoPlayer来作为播放器,而非之前的MediaPlayer ,如有需要,请参考后续的博客,...
android openGL ES详解
最新发布
星空物语
04-23 955
Android之所以这样设计,是因为开发者在开发程序的时候不必关心特定的CPU或者机器架构,也不必关心底层的内存管理。在java层完成顶点的定义后,但是,在OpenGL可以存取它们之前,我们仍然需要完成另外一步。主要的问题是这些代码运行的环境与OpenGL运行的环境使用了不同的语言,我们需要理解如下两个主要的概念。第二种技术是改变内存分配的方式,Java 有一个特殊的类集合,它们可以分配本地内存块,并且把 Java 的数据复制到本地内存。本地内存可以被本地环境存取,而不受垃圾回收器的管控。
安卓VR相关-OpenGLes2.0小行星展示全景图demo.rar
07-29
OpenGL es2.0 小行星展示全景图demo.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
OpenGL.ESAndroid上的简单实践:14-全景(惯性滑动球体
vx number:zzr_admin,拉入技术交流群。
04-03 1110
OpenGL.ESAndroid上的简单实践: 14-全景(惯性滑动球体) 1、整理封装全景球 现在,我们的地球已经能正确的显示出来,我们来增加必要的交互,使得我们左右滑动屏幕的时候,地球旋转起来,而且是像一个地球仪一样,手指离开屏幕后,能随着惯性的操作延后旋转。 第一步,我们现在测试页面PanoramaActivity添加对GLSurfaceView的触摸事件监听,...
Android OpenGL ES 学习(三) -- 绘制平面图形
夏至的稻穗的博客
11-26 3408
上一章中,已经对 OpenGL 的编程语言 GLSL 和渲染模式有了一定的了解,今天,将运用之前的知识,完成一些平面图形的操作。效果如下:如果你对 OpenGL 的基本概念或者渲染流程不清晰,建议先看和这两篇文章。先直接上两张图:可以看到,我们需要先编写着色器的代码,才能把 OpenGL 的数据,传递到渲染管线上。
Android平台OpenGL实现全景图片视频播放
Contex_A17的博客
03-01 1260
Android平台OpenGL ES实现全景图片和视频播放
Android OpenGL ES学习笔记之绘制
Dennis-Android的博客
08-10 6879
一些基本概念 世界坐标系 世界坐标系就是3D绘图中像素的坐标。在3D绘图中,坐标轴遵循右手法则,让你右手手心正对自己,大拇指指向X轴正方向,拇指指向Y轴正方向,中指指向Z轴正方向。如下图所示点的表示 空间中一个点具有(x,y,z)坐标。在Android系统中,可以用一个float数组、int数组等来表示一个点,比如private float[] mArray = { 0f, 0f, 0f };而在
android OpenGL ES 地球绘制——球体绘制及纹理映射——源码
09-03
支持如下: (1)opengl es绘制三角形拼成球体 (2)图片作为纹理映射到整个球面上 (3)双点触控缩放球体 (4)拖动旋转球体
opengl es 全景显示模式触屏操作示例demo
04-30
opengl es 全景显示模式示例demo 分球内显示和球外显示的触屏操作
Android平台下的全景视频播放器配套教程——1.3 用OpenGL ES 2.0显示一张图片
01-12
Android平台下的全景视频播放器配套教程——1.3 用OpenGL ES 2.0显示一张图片
OpenGLES20_Lesson07_primitive3_基本图元的绘制之正方形平移、旋转、缩放_
10-03
基本图元绘制,实现对正方形的平移,旋转,缩放
[OpenGL]从零开始写一个Android平台下的全景视频播放器——3.1 全景视频是如何实现的
Martin的博客
12-17 7740
Github项目地址为了方便没有准备好梯子的同学,我把项目在CSDN上打包下载,不过更新会慢一些回到目录恭喜Martin同学获得由CSDN颁发的“更新慢慢慢”荣誉称号全景视频有很多种类,例如Sphere全景,Skybox(Cubemap),Cylinder等,我们以最为常见的Sphere全景视频为例进行说明。原理其实要说明这个问题,只需要几张图 360全景视频截图 仔细观察我们会发现,视频的底
游戏界面制作---旋转地球
虾米仔的博客
02-17 1071
做游戏的都希望玩家能够被自己的游戏吸引,所以一般进入游戏的第一个界面也就是首页,都会经过精心的设计,除了精美的画面外还要有一定数量的动画,这样才能更吸引玩家。 我最近参与的一款游戏也是在首页UI部分下足了功夫,但是传统上用太多复杂的动画的话会非常考验低配置机器的体验,就顺便研究了市面上流行的游戏设计。发现类似于转动的地球的动画元素被很多游戏用到,比如去年非常火的找你妹,还有一直排在排行榜上的捕鱼
调正opengles渲染坐标将图像旋转问题
wangzhicheng2013的专栏
02-09 320
调正opengles渲染坐标将图像旋转问题
OpenGL.ESAndroid上的简单实践:16-全景(视野变换 完结)
vx number:zzr_admin,拉入技术交流群。
04-08 1147
OpenGL.ESAndroid上的简单实践:16-全景(视野变换 完结)   让我们继续完成视野变换,先回顾一下之前我们所做的内容: 当我们在屏幕上双击测试页面的glsurfaceview,会触发渲染器的双击事件,进而向全景球模型请求下一个模型的变换。在全景球模型中,我们定义了两个观察视口CameraViewport,一个是当前的,另外一个是目标的;还有两个模型模式的标志位RENDER_...
android opengl图片,Android平台openGL ES实现全景图片
weixin_39710106的博客
05-27 489
全景又被称为3D实景,是一种新兴的富媒体技术,其与视频,声音,图片等传统的流媒体最大的区别是“可操作,可交互”。 全景分为虚拟现实和3D实景两种。虚拟现实是利用maya等软件,制作出来的模拟现实的场景,代表有虚拟紫禁城等;3D实景是利用单反相机或街景车拍摄实景照片,经过特殊的拼合,处理,让作者立于画境中,让最美的一面展现出来。全景顾名思义就是给人以三维立体感觉的实景360度全方位图像~此图像最大的...
android opengl es2.0图片旋转
12-01
Android中使用OpenGL ES 2.0进行图片旋转可以通过以下步骤实现。首先,需要创建一个OpenGL ES 2.0的渲染器,并将图片作为纹理加载到OpenGL中。然后,在渲染器的绘制方法中,通过修改矩阵来实现图片的旋转效果。 在OpenGL ES 2.0中,可以使用矩阵操作来进行图形的变换,包括平移、旋转和缩放等。要实现图片旋转,可以通过修改旋转矩阵来实现。可以使用以下代码来创建一个旋转矩阵: Matrix.setRotateM(rotationMatrix, 0, angle, 0, 0, 1); 其中,rotationMatrix是一个float类型的数组,angle是旋转的角度。然后,在绘制图片的时候,将这个旋转矩阵应用到图片的变换矩阵中: Matrix.multiplyMM(modelMatrix, 0, rotationMatrix, 0, modelMatrix, 0); 最后,在顶点着色器中将变换矩阵应用到顶点坐标上,就可以实现图片的旋转效果了。 除了使用矩阵操作来实现图片旋转,还可以通过修改顶点坐标的方式来实现。可以在顶点着色器中加入一个uniform变量来控制旋转角度,然后在顶点坐标计算的时候将其应用到顶点坐标上。 总之,通过OpenGL ES 2.0的矩阵操作和顶点坐标变换,可以很方便地实现Android平台上图片的旋转效果。

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • react native FlatList 使用详解 44909
  • Flutter 修改App的名称和图标 35982
  • react native Image ImageBackground详解 24505
  • Flutter 启动页 消除白屏 23201
  • 2020年20个Flutter最漂亮的UI库和项目 22360

分类专栏

  • Flutter Widgets 付费 103篇
  • Flutter 110篇
  • OpenGL ES for Android 18篇
  • react native 学习之旅 44篇
  • Kotlin 11篇

最新评论

  • Flutter 中不得不会的 mixin

    哇哇 · 刘: 请问 PB 是怎麽通过 super.init 调用到了 GB 中的 init 方法的呀?

  • Flutter 中不得不会的 mixin

    As.Kai: 如果本身(FG)也存在相同的方法那么优先级:(G > F > H) > FG。

  • Flutter 拖拽排序组件 ReorderableListView

    竹北: 必须长按才可以排序嘛

  • 2020年20个Flutter最漂亮的UI库和项目

    无尽之思: 摸鱼kik 纯flutter开发,可以体验一下,很流畅

  • 《Flutter 控件大全》第一零一:ValueListenableBuilder

    属实是没办法: _name = ValueNotifier<String>('老孟'); 这样的方法为啥是错的啊表情包 导师让看这方面的东西,一直看不懂....

大家在看

  • 【大模型应用开发 动手做AI Agent】思维链
  • 【大模型应用开发 动手做AI Agent】思维树 95
  • DHCP(Cisco)
  • 【大模型应用开发 动手做AI Agent】什么是Functions
  • 【大模型应用开发 动手做AI Agent】计划与执行 339

最新文章

  • 【Flutter】仿 Element 样式 Progress 进度条
  • 【老孟Flutter】Flutter 2的新功能
  • 【老孟Flutter】Flutter 2.0 重磅更新
2021年9篇
2020年240篇
2019年7篇
2018年44篇
2017年60篇

目录

目录

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老孟Flutter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值

哆哆女性网孙权劝学原文朗读中国取名起名大全网免费取名起名预测打评分金世豪娱乐属狗宝宝起名宜用字大全日用品店铺起名郭姓起人名路由器默认密码bajieyingyuan权财最新章节张学友和张家辉到底是什么关系迷茫的管家与懦弱的我waste是什么意思柏男孩起名重生军婚之肥妻翻身超级终端下载拔丝红薯的做法起名字为什么不能用睿字不负韶华的励志句子雷霆加速下载器下载长相思李白魔鬼恋人第二季只因单身在一起电视剧零食店起名字logo设计欣赏男孩起名字库cad2014注册机给小说起名驾驶员安全培训张姓龙男宝宝起名淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化