android命令行 gles,Android利用OpenGLES绘制天空盒实例教程
前言
天空盒这个效果最早是在腾讯的实景地图里看到的,当时觉得很牛逼,但是没有想过自己去实现以下。最近这段时间对opengl很有兴趣,顺便就搞了这个天空盒,话不多说,先上效果。
天空盒的原理就是在三维空间中放置一个正方体,然后将我们的相机放置在正方体内,当我们的视点转动,相机跟着转动。我们就可以看到相应的景色的变换了,天空盒本质上是一个立方体。
OpenGL
关于什么是OpenGL,什么是OpenGLES就不细说了,不了解的就自行百度吧,我们主要是关注代码。整个项目采用了Kotlin + Ndk的形式进行的开发。现在NDK的环境搭建比以前容易了,而且现在是使用CMakeList来构建C++代码的,不熟悉的可以去查看一下。整个项目就两个关键类,SkyBoxView和SkyBoxRender。下面分别来看一下。
第一步
SkyBoxView继承了GLSurfaceView,为什么要继承GLSurfaceView,因为在使用OpenGLES需要建立一个窗口和一个上下文,GLSurfaceView帮我们做了这些工作。下面是SkyBoxView的主要代码:
class SkyBoxView(context: Context, attributeSet: AttributeSet?) : GLSurfaceView(context, attributeSet)
{
private lateinit var skyBoxRender: SkyBoxRender
private var lastX=0F
private var lastY=0F
private var yaw=0f
private var pitch=0f
private var screenWidth=0
private var screenHeight=0
private var horSensity=0.03f
private var verSensity=0.03f
constructor(context: Context) : this(context, null)
init
{
// initSensor()
initSensity()
initConfig()
}
private fun initSensity()
{
screenWidth=resources.displayMetrics.widthPixels
screenHeight=resources.displayMetrics.heightPixels
horSensity= 360.0f/screenWidth
verSensity=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.x
lastY=event.y
return true
}
MotionEvent.ACTION_MOVE->
{
val offsetX=event.x-lastX
val offsetY=lastY-event.y
yaw+=offsetX*horSensity
pitch+=offsetY*verSensity
lastX=event.x
lastY=event.y
skyBoxRender.rotate(pitch,yaw)
}
}
return true
}
}
在initConfig方法里,设置了render为SkyBoxRender,真正的绘制是在这里进行的。在initSensity方法里设置了旋转精度, horSensity和verSensity,水平和数值旋转时的精度,就像你玩fps游戏设置的鼠标灵敏度一样。在onTouchEvent则根据手指滑动的距离设置俯仰角pitch和偏移脚yaw,调用skyBoxRender进行相机的旋转。另外如果你看github可能发现我注释掉了很多代码,那是用传感器旋转的尝试,但是觉得麻烦,也没继续做,有兴趣的读者可以自己搞一下。
第二步
SkyboxRender的主要工作就是加载贴在正方体表面的6个图片纹理,从文件读取着色器语言,而真正创建opengles program和绘制是用C++代码来写的,所以主要看一下这里。
#include
#include
#include
#include
#include
#include
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 vbo
unsigned 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
{
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的单位向量的方向来做到的。
源码下载
最后附上
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
android命令行 gles,Android利用OpenGLES绘制天空盒实例教程相关推荐
- 【Android 命令行工具】Android 命令行工具简介 ( 官方文档 | SDK 命令行工具 | SDK 构建工具 | SDK 平台工具 | 模拟器工具 | Jetifier 工具 )
文章目录 一.官方文档 二.Android 命令行工具简介 1.SDK 命令行工具 2.SDK 构建工具 3.SDK 平台工具 4.模拟器工具 5.Jetifier 工具 一.官方文档 Android ...
- 【错误记录】记录 Android 命令行执行 Java 程序中出现的错误 ( dx 打包 PC 可执行文件报错 | dalvik 命令执行 kotlin 编译的 dex 文件报错 )
文章目录 前言 一.Android 命令行与 PC 可执行 JAR 文件不兼容 二.Android 命令行使用 dalvik 命令不能直接执行 Kotlin 编译的 dex 文件 前言 尝试在 And ...
- 【Android 逆向】修改运行中的 Android 进程的内存数据 ( Android 命令行中获取要调试的应用进程的 PID | 进程注入调试进程内存的 so 库 )
文章目录 一.Android 命令行中获取要调试的应用进程的 PID 二.进程注入调试进程内存的 so 库 一.Android 命令行中获取要调试的应用进程的 PID 前置博客 [Android 逆向 ...
- androidsdktools安装_如何命令行安装Android SDK Build Tools(构建工具)?
Android构建工具安装的问题 我想从命令行建立Android开发环境,遇到了如下问题: wget http://dl.google.com/android/android-sdk_r22.0.5- ...
- 使用命令行对Android应用签名
基于命令行的方式对APK文件进行签名. 第一步:生成RSA密钥对 keytool -genkeypair -alias magick.keystore -keyalg RSA -validity ...
- android的命令行使用,Android命令行启动程序正确使用技巧解析
Android程序启动的方式除了使用界面方式进行启动之外,还能通过命令行启动.那么就让我们大家一起来看看Android命令行启动程序的具体操作方法. Android应用程序的启动方法有许多种,大家可以 ...
- android命令行打包、签名+自动打包器
本文主要讲解使用命令行打包android工程成apk文件,我的android工程结构如图 1.创建key: 使用keytool.exe(位于%JAVA_HOME%\bin\keytool.exe)创建 ...
- Android命令行启动应用方法
Android命令行启动程序正确使用技巧解析 Android程序启动的方式除了使用界面方式进行启动之外,还能通过命令行启动.那么就让我们大家一起来看看Android命令行启动程序的具体操作方法. An ...
- android id变化,命令行修改Android id
标签: 命令行修改Android id 1.确认已安装ADB 2配置ADB环境 2.1 打开环境变量 2.2配置path 将你的adb解压路径添加到path中 2.3 确认adb配置成功 在cmd 中 ...
最新文章
- 十三、面向对象程序设计
- build的时候出错,fatal error LNK1103
- java中nio怎么实现聊天,JAVA-NIO实现聊天室详细代码说明
- C++运算符重载函数作为类成员函数和友元函数
- 让微信扫描直接下载你的APK
- 千万级测试String、StringBuffer和StringBuilder的速度
- SVN汉化包安装后,没有出现对应的语言选项问题解决(附SVN1.12.1汉化包下载地址)
- word查重_医学论文查重参考文献算不算?
- java导出excel设置单元格样式_java poi批量导出excel 设置单元格样式
- 网站一键分享到新浪微博QQ空间腾讯微博
- 2019年图灵奖Edwin E. Catmull和Patrick M. Hanrahan简介
- Kanzi 记录:界面整体介绍(一),自己理解,绝非生搬硬套。
- 关于sqlserver身份登录失败的解决方法
- linux卸载kodi,在Ubuntu 18.04上,如何安装Kodi
- [nginx代理配置][nginx proxy_pass][nginx从一台服务器代理到另外一台服务器,浏览器地址不改变]
- 全球及中国吊臂汽车起重机行业研究及十四五规划分析报告
- 店铺创业选址的黄金法则
- ESB产品调用场景分析
- Win8上Service程序及外部App调用此Service
- APP软件的开发成本
热门文章
- 蚂蚁集团,打响2022反内卷第一枪?
- python3实战练手项目_Python0基础练手项目有哪些值得推荐?附实战项目+学习图谱...
- 为什么使用3msip2协议_知识卡片 | 链路状态路由协议OSPF凭什么会取代RIP?
- high definition audio控制器感叹号_三门峡回收科霸控制器
- 线性回归—梯度下降python实现
- 女生学的计算机专业有前途吗,计算机专业好不好 女生学计算机有前途吗
- android:id = @+id 用法,@+id/android:list和@android:id/list的写法
- python没有return语句的函数将返回_为什么Python没有return返回值
- java switch中标签重复_java程序 怎样把id相同的记录挑出来,分别存到不同的文件中,除了switch case,数据量很大,id种类很多。...
- Javascript 时间操作汇总