0.

天空盒这个效果最早是在腾讯的实景地图里看到的,当时觉得很牛逼,但是没有想过自己去实现以下。最近这段时间对opengl很有兴趣,顺便就搞了这个天空盒,话不多说,先上效果。

天空盒的原理就是在三维空间中放置一个正方体,然后将我们的相机放置在正方体内,当我们的视点转动,相机跟着转动。我们就可以看到相应的景色的变换了,天空盒本质上是一个立方体。

1.

关于什么是OpenGL,什么是OpenGLES就不细说了,不了解的就自行百度吧,我们主要是关注代码。整个项目采用了Kotlin + Ndk的形式进行的开发。现在NDK的环境搭建比以前容易了,而且现在是使用CMakeList来构建C++代码的,不熟悉的可以去查看一下。整个项目就两个关键类,SkyBoxView和SkyBoxRender。下面分别来看一下。

2.

SkyBoxView继承了GLSurfaceView,为什么要继承GLSurfaceView,因为在使用OpenGLES需要建立一个窗口和一个上下文,GLSurfaceView帮我们做了这些工作。下面是SkyBoxView的主要代码:

class SkyBoxView(context: Context, attributeSet: AttributeSet?) : GLSurfaceView(context, attributeSet)
{private lateinit var skyBoxRender: SkyBoxRenderprivate var lastX=0Fprivate var lastY=0Fprivate var yaw=0fprivate var pitch=0fprivate var screenWidth=0private var screenHeight=0private var horSensity=0.03fprivate var verSensity=0.03fconstructor(context: Context) : this(context, null)init
{
//  initSensor()initSensity()initConfig()
}private fun initSensity()
{screenWidth=resources.displayMetrics.widthPixelsscreenHeight=resources.displayMetrics.heightPixelshorSensity= 360.0f/screenWidthverSensity=180.0f/screenHeight
}private fun rotate(pitch:Float,yaw:Float)
{queueEvent {skyBoxRender.rotate(pitch,yaw)}
}
private fun initConfig()
{setEGLContextClientVersion(3)skyBoxRender=SkyBoxRender(context)setRenderer(skyBoxRender)renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY}override fun onTouchEvent(event: MotionEvent?): Boolean
{when(event?.action){MotionEvent.ACTION_DOWN->{lastX=event.xlastY=event.yreturn true}MotionEvent.ACTION_MOVE->{val offsetX=event.x-lastXval offsetY=lastY-event.yyaw+=offsetX*horSensitypitch+=offsetY*verSensitylastX=event.xlastY=event.yskyBoxRender.rotate(pitch,yaw)}}return true
}}
复制代码

在initConfig方法里,设置了render为SkyBoxRender,真正的绘制是在这里进行的。在initSensity方法里设置了旋转精度, horSensity和verSensity,水平和数值旋转时的精度,就像你玩fps游戏设置的鼠标灵敏度一样。在onTouchEvent则根据手指滑动的距离设置俯仰角pitch和偏移脚yaw,调用skyBoxRender进行相机的旋转。另外如果你看github可能发现我注释掉了很多代码,那是用传感器旋转的尝试,但是觉得麻烦,也没继续做,有兴趣的读者可以自己搞一下。

3.

SkyboxRender的主要工作就是加载贴在正方体表面的6个图片纹理,从文件读取着色器语言,而真正创建opengles program和绘制是用C++代码来写的,所以主要看一下这里。

#include <jni.h>
#include <string>
#include <GLUtils/GLUtils.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>extern "C" {JNIEXPORT jint JNICALL
Java_com_skateboard_skybox_SkyBoxRender_genProgram(JNIEnv *env, jobject thiz, jstring vertexPath,jstring fragmentPath) {
//load program
const char *cVertexPath = env->GetStringUTFChars(vertexPath, nullptr);
const char *cFragmentPath = env->GetStringUTFChars(fragmentPath, nullptr);
int program = glutils::loadProgram(cVertexPath, cFragmentPath);
return program;}JNIEXPORT jint JNICALL
Java_com_skateboard_skybox_SkyBoxRender_preparePos(JNIEnv *env, jobject thiz, jfloatArray pos) {
//gen vao vbounsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
int posSize = env->GetArrayLength(pos);
float* p=env->GetFloatArrayElements(pos, nullptr);
glBufferData(GL_ARRAY_BUFFER, posSize* sizeof(float), p,GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glBindVertexArray(0);
return VAO;
}JNIEXPORT jint JNICALL
Java_com_skateboard_skybox_SkyBoxRender_prepareTexture(JNIEnv *env, jobject thiz) {
//gen texture
unsigned int TEXTURE;
glGenTextures(1, &TEXTURE);
glBindTexture(GL_TEXTURE_CUBE_MAP, TEXTURE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return 1;
}glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);JNIEXPORT void JNICALL
Java_com_skateboard_skybox_SkyBoxRender_draw(JNIEnv *env, jobject thiz, jint program, jint VAO,jint texture,jfloat width,jfloat height) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 1.0, 0.0, 1.0);
glUseProgram(program);glEnable(GL_DEPTH_TEST);
glm::mat4 viewMatrix = glm::mat4(1.0f);
glm::mat4 projectionMatrix = glm::mat4(1.0f);
glm::vec3 v = glm::vec3(cameraFront.x - cameraPos.x, cameraFront.y - cameraPos.y,cameraFront.z - cameraPos.z);
viewMatrix = glm::lookAt(cameraPos, v, glm::vec3(0.0f, 1.0f, 0.0f));
projectionMatrix = glm::perspective(glm::radians(45.0f), width / height, 0.1f,100.0f);
int viewMatrixLocation = glGetUniformLocation(program, "view");
int projectMatrixLocation = glGetUniformLocation(program, "projection");
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(projectMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]);glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
glDrawArrays(GL_TRIANGLES, 0, 36);
复制代码

}

JNIEXPORT void JNICALL
Java_com_skateboard_skybox_SkyBoxRender_rotate(JNIEnv *env, jobject thiz,jfloat pitch,jfloat yaw) {if(pitch>89)
{pitch=89.0;
}
if(pitch<-89)
{pitch=-89.0;
}
cameraFront.x=glm::cos(glm::radians(pitch))*glm::cos(glm::radians(yaw));
cameraFront.y=glm::sin(glm::radians(pitch));
cameraFront.z=glm::cos(glm::radians(pitch))*glm::sin(glm::radians(yaw));
cameraFront=glm::normalize(cameraFront);
}}
复制代码

genProgram主要是用来产生opengl es的program的,如果对这个概念不太理解请参考C++编译过程。 preparePos是将java层顶点位置数组传入进来并写入顶点着色器。 prepareTexture用来生成纹理。 draw用来进行绘制。 旋转的时候就是通过改变cameraFront的单位向量的方向来做到的。

4.

最后附上 github

公众号:滑板上的老砒霜,定期分享技术原创文章。

Android OpenGLES绘制天空盒相关推荐

  1. opengles绘制天空盒

    效果图 核心代码 //纹理矩形 public class TextureRect { int mProgram;//自定义渲染管线程序idint muMVPMatrixHandle;//总变换矩阵引用 ...

  2. android命令行 gles,Android利用OpenGLES绘制天空盒实例教程

    前言 天空盒这个效果最早是在腾讯的实景地图里看到的,当时觉得很牛逼,但是没有想过自己去实现以下.最近这段时间对opengl很有兴趣,顺便就搞了这个天空盒,话不多说,先上效果. 天空盒的原理就是在三维空 ...

  3. Android opengles 实现触碰屏幕,根据运动轨迹画直线的功能

    Android opengles 实现触碰屏幕,根据运动轨迹画直线的功能 目录 引言 第一步,先自己学会绘制一条固定坐标的直线 第二步,动态的绘制一条直线 第三步,坐标转换 第四步,绘制多条直线 代码 ...

  4. 《Android 美颜类相机开发汇总》第五章 Android OpenGLES 美颜定制实现

    在介绍美颜定制之前,我们先来复习一下OpenGL中图像绘制原理.OpenGL的图像绘制,是由许许多多三角形构成的.OpenGL的绘制离不开三角形的绘制.通常对于不需要对图像细节进行处理的时候,我们一般 ...

  5. android 过度绘制

    1.概述   UI渲染操作通常依赖于两个核心组件:CPU与GPU.CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作 ...

  6. 【Android View绘制之旅】Draw过程

    出效果:绘制 经过前面的准备工作 :[Android View绘制之旅]Measure过程,[Android View绘制之旅]Layout过程 我们的视图具备了宽高数据,位置数据,现在到了激动人心的 ...

  7. 【Android View绘制之旅】Layout过程

    1.为什么要进行Layout? 在[Android View绘制之旅]View之测量Measure过程后,View我们得到View的宽高,但光只有宽高值是不足以反映视图的,更需要知道View所在的位置 ...

  8. 【Android View绘制之旅】主脉络

    没搞清楚View绘制原理会怎么样? 只会玩玩初级的组件 看不懂哪些绚丽效果组件实现的原理,即使你有源码 PM会对你很失望,因为有点高级特性你就跪了 当然好的工作机会是没有你的份的 View绘制之旅该怎 ...

  9. 【开源项目----Android OPenGLES渲染YUV视频文件】

    [开源项目----Android OPenGLES渲染YUV视频文件] OpenGLES对YUV渲染相关文章参考

最新文章

  1. Java编程基础04——流程控制语句
  2. IOS4.x下UIWebView的显示问题
  3. [elixir! #0037] Agent 小传
  4. java 传递脚本给c_java – JNI将参数传递给c的方法
  5. Android--xml布局文件中使用include
  6. powerdesign使用手册
  7. 三维立体图的原理和欣赏方法
  8. 计算机桌面的文件拒绝访问,文件或文件夹拒绝访问的解决方法
  9. qq大厅连连看外挂:c++实现
  10. 平凡程序员一年又一年的感悟(2019)
  11. 老马闲评数字化(4)做数字化会不会被供应商拿捏住
  12. java 多线程(四)—— 线程同步/互斥=队列+锁
  13. 防雷工程专业术语及雷电浪涌保护器名词解释
  14. FTPClientUtil FTP客户端工具
  15. Python的自省函数
  16. J-LINK 重刷固件库步骤
  17. 【linux】nfs挂载错误wrong fs type, bad option, bad superblock
  18. 佛山科学技术学院计算机期末试题,佛山科学技术学院 2002-2003学年第一学期概率与数理统计试卷(A卷)...
  19. TECPLOT画流固耦合的流场图--学习笔记
  20. 面试常见基础知识点及问题

热门文章

  1. cas113995-55-4/花菁染料1,1,2-三甲基-1H-苯并吲哚-7-磺酸
  2. win10---血战上海滩
  3. 《Java 核心技术 卷1》 笔记 第11章 异常、日志、断言和调试
  4. mysql mmm write vip_MySQLHAbyusingMysql-mmm
  5. 海报设计之色彩搭配与均衡构图
  6. 乐鑫开发工具链之国内镜像gitee飞起
  7. 【数据结构】---时间复杂度与空间复杂度
  8. 华为便携机修改服务器密码,华为随身WiFi如何修改WiFi密码 华为随身WiFi修改WiFi密码方法【介绍】...
  9. 贴片电阻0603、1206之间的区别是什么
  10. 线性时不变系统——信号系统学习笔记