国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android利用OpenGLES繪制天空盒實例教程

2019-10-21 21:43:01
字體:
來源:轉載
供稿:網友

前言

天空盒這個效果最早是在騰訊的實景地圖里看到的,當時覺得很牛逼,但是沒有想過自己去實現以下。最近這段時間對opengl很有興趣,順便就搞了這個天空盒,話不多說,先上效果。

Android,OpenGLES,天空盒

天空盒的原理就是在三維空間中放置一個正方體,然后將我們的相機放置在正方體內,當我們的視點轉動,相機跟著轉動。我們就可以看到相應的景色的變換了,天空盒本質上是一個立方體。

OpenGL

關于什么是OpenGL,什么是OpenGLES就不細說了,不了解的就自行百度吧,我們主要是關注代碼。整個項目采用了Kotlin + Ndk的形式進行的開發?,F在NDK的環境搭建比以前容易了,而且現在是使用CMakeList來構建C++代碼的,不熟悉的可以去查看一下。整個項目就兩個關鍵類,SkyBoxView和SkyBoxRender。下面分別來看一下。

第一步

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.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 <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 JNICALLJava_com_skateboard_skybox_SkyBoxRender_genProgram(JNIEnv *env, jobject thiz, jstring vertexPath,      jstring fragmentPath) {//load programconst char *cVertexPath = env->GetStringUTFChars(vertexPath, nullptr);const char *cFragmentPath = env->GetStringUTFChars(fragmentPath, nullptr);int program = glutils::loadProgram(cVertexPath, cFragmentPath);return program;}JNIEXPORT jint JNICALLJava_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 JNICALLJava_com_skateboard_skybox_SkyBoxRender_prepareTexture(JNIEnv *env, jobject thiz) {//gen textureunsigned 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 JNICALLJava_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 JNICALLJava_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的單位向量的方向來做到的。

源碼下載

最后附上

github

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 中方县| 锡林浩特市| 沙田区| 阿拉善右旗| 滦平县| 鱼台县| 万全县| 鄂伦春自治旗| 祁门县| 明水县| 忻州市| 金华市| 体育| 平乡县| 汽车| 皋兰县| 广平县| 灌云县| 偏关县| 万州区| 铜山县| 合山市| 璧山县| 祁连县| 忻城县| 紫金县| 鄯善县| 浦东新区| 仪征市| 师宗县| 南陵县| 额敏县| 资源县| 金华市| 阆中市| 陵水| 稷山县| 二连浩特市| 绵竹市| 刚察县| 垫江县|