日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

音视频开发之旅(41)-天空盒

發布時間:2023/12/31 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 音视频开发之旅(41)-天空盒 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 天空盒的實現原理
  • 具體代碼實現
  • 資料
  • 收獲
  • 效果如下

    ?

    今天我們學習實踐天空盒,天空盒的技術本身比較簡單,但是卻可以做出來很多比較天空、大山、大海、以及VR看房等效果??梢宰鳛楸尘皠討B移動,也可以跟隨手勢或者傳感器等進行移動變換。

    一、立方體貼圖和天空盒

    所謂的天空盒其實就是將一個立方體展開,然后在六個面上貼上相應的貼圖

    天空盒的效果正如開篇動畫中展示的效果一樣,從一個視點,旋轉視角看天空,呈現出來不同畫面。我們可以想象成我們自己就位于一個三維空間的內部中心點,四周是一個大的立方體,包含上下、左右、前后 六個平面,我們旋轉我們的視角就會看到不同的畫面。

    因此我們可以采用上面的原理,在一個立方體進行立方體貼圖

    在實際的渲染中,將這個立方體始終罩在攝像機的周圍,讓攝像機始終處于這個立方體的中心位置,然后根據視線與立方體的交點的坐標,來確定究竟要在哪一個面上進行紋理采樣。具體的映射方法為:設視線與立方體的交點為(x,y,z)(x,y,z),在x、y、zx、y、z中取絕對值最大的那個分量,根據它的符號來判定在哪個面上采樣。

    然后讓其他兩個分量都除以最大分量的絕對值,這樣就讓另外兩個分量都映射到了[0,1]內,然后就可以直接在對應的紋理上做紋理映射就行了,這個方法就是所謂的Cube Map,是天空盒方法的核心

    立方體貼圖是和2D紋理創建流程一樣

    ?

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0)GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, skyBoxTexture)GLES20.glUniform1i(uTextureLoc, 0)

    立方體紋理貼圖的加載如下

    ?

    /*** 加載立方體紋理貼圖* @param context* @param cubeResources* @return*/public static int loadCubeMap(Context context, int[] cubeResources) {final int[] textureObjectIds = new int[1];glGenTextures(1, textureObjectIds, 0);if (textureObjectIds[0] == 0) {Log.w(TAG, "Could not generate a new OpenGL texture object.");return 0;}final BitmapFactory.Options options = new BitmapFactory.Options();options.inScaled = false;final Bitmap[] cubeBitmaps = new Bitmap[6];for (int i = 0; i < 6; i++) {cubeBitmaps[i] =BitmapFactory.decodeResource(context.getResources(),cubeResources[i], options);if (cubeBitmaps[i] == null) {Log.w(TAG, "Resource ID " + cubeResources[i]+ " could not be decoded.");glDeleteTextures(1, textureObjectIds, 0);return 0;}}// Linear filtering for minification and magnification//注意這里不是GL_TEXTURE_2D,而是GL_TEXTURE_CUBE_MAP,使用六張紋理組合成一個立方體紋理glBindTexture(GL_TEXTURE_CUBE_MAP, textureObjectIds[0]);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//左右、下上、前后---》注意 使用的是左手坐標系texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, cubeBitmaps[0], 0);texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, cubeBitmaps[1], 0);texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, cubeBitmaps[2], 0);texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, cubeBitmaps[3], 0);texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, cubeBitmaps[4], 0);texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, cubeBitmaps[5], 0);glBindTexture(GL_TEXTURE_CUBE_MAP, 0);//把紋理復制到GPU后就可以回收原理的bitmap了for (Bitmap bitmap : cubeBitmaps) {bitmap.recycle();}return textureObjectIds[0];}

    OpenGL給我們提供了6個特殊的紋理目標,專門對應立方體貼圖的一個面。

    GL_TEXTURE_CUBE_MAP_POSITIVE_X 右
    GL_TEXTURE_CUBE_MAP_NEGATIVE_X 左
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y 上
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 下
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z 后
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 前

    另外在著色器上使用立方體紋理

    ?

    //使用立方體紋理 uniform samplerCube uTexture; varying vec3 vPosition;void main() {gl_FragColor = textureCube(uTexture,vPosition); }

    二、具體代碼實現

    通過上面小節,我們了解到天空盒的實現原理比較簡單,下面我們開始具體的代碼實現。

    首先,寫著色器代碼

    ?

    uniform mat4 uMatrix; attribute vec3 aPosition; varying vec3 vPosition;void main() {vPosition = aPosition;gl_Position = uMatrix*vec4(aPosition, 1.0);//注意這里gl_Position = gl_Position.xyww; }

    z = w
    在投影變換之后,會做一步透視除法,即讓四元向量的所有分量都除以它的W分量,從而使視錐體內的區域的x、y映射到[?1,1][?1,1],z映射到[0,1][0,1],從而根據透視除法之后的x、y、zx、y、z的范圍直接剔除掉那些不可見的頂點,如果令z=wz=w,就表示透視除法后的z=1z=1,也就是讓天空盒始終處于遠平面的位置

    ?

    //使用立方體紋理 uniform samplerCube uTexture; varying vec3 vPosition;void main() {gl_FragColor = textureCube(uTexture,vPosition); }

    接著我們重點來看下Render的實現

    ?

    package com.av.mediajourney.skyboximport android.content.Context import android.opengl.GLES20 import android.opengl.GLSurfaceView import android.opengl.Matrix import com.av.mediajourney.R import com.av.mediajourney.opengl.ShaderHelper import com.av.mediajourney.particles.android.util.TextureHelper import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.opengles.GL10class SkyBoxRender(var context: Context) : GLSurfaceView.Renderer {lateinit var skyBox: SkyBox;var mProgram = -1private val projectionMatrix = FloatArray(16)private val viewMatrix = FloatArray(16)private val viewProjectionMatrix = FloatArray(16)private var aPositionLoc = -1;private var uMatrixLoc = -1;private var uTextureLoc = -1;private var skyBoxTexture = -1;override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES20.glClearColor(0f, 0f, 0f, 1f)skyBox = SkyBox()val vertexStr = ShaderHelper.loadAsset(context.resources, "sky_box_vertex.glsl")val fragStr = ShaderHelper.loadAsset(context.resources, "sky_box_fragment.glsl")mProgram = ShaderHelper.loadProgram(vertexStr, fragStr)aPositionLoc = GLES20.glGetAttribLocation(mProgram, "aPosition")uMatrixLoc = GLES20.glGetUniformLocation(mProgram, "uMatrix")uTextureLoc = GLES20.glGetUniformLocation(mProgram, "uTexture")skyBoxTexture = TextureHelper.loadCubeMap(context, intArrayOf(R.drawable.left2, R.drawable.right2,R.drawable.bottom2, R.drawable.top2,R.drawable.front2, R.drawable.back2))}override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {GLES20.glViewport(0, 0, width, height)val whRadio = width / (height * 1.0f)Matrix.setIdentityM(projectionMatrix, 0)Matrix.perspectiveM(projectionMatrix, 0, 105f, whRadio, 1f, 10f)}var frameIndex: Int = 0override fun onDrawFrame(gl: GL10?) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)GLES20.glClearColor(0f, 0f, 0f, 1f)//自動旋轉的val xRotationAuto = frameIndex / 8f//整體旋轉的值 = 自旋轉+滑動觸摸觸發的旋轉值val xRotationT = xRotationAuto +xRotationframeIndex++Matrix.setIdentityM(viewMatrix, 0)//采用移動的方式,可以看到立方體的6個面上的紋理圖片 // Matrix.translateM(viewMatrix,0, xRotation,0f,0f)//采用旋轉的方式,只能采用旋轉的方式,進行實現視角變換,達到移動的效果Matrix.rotateM(viewMatrix, 0, xRotationT, 0f, 1f, 0f) // Matrix.rotateM(viewMatrix, 0, yRotation, 1f, 0f, 0f)Matrix.multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0)GLES20.glUseProgram(mProgram)//傳mvp矩陣數據GLES20.glUniformMatrix4fv(uMatrixLoc, 1, false, viewProjectionMatrix, 0)//傳紋理數據GLES20.glActiveTexture(GLES20.GL_TEXTURE0)GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, skyBoxTexture)GLES20.glUniform1i(uTextureLoc, 0)GLES20.glEnableVertexAttribArray(aPositionLoc)skyBox.vertexArrayBuffer.position(0);GLES20.glVertexAttribPointer(aPositionLoc, SkyBox.POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, 0, skyBox.vertexArrayBuffer)GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_BYTE, skyBox.indexArrayBuffer)}private var xRotation = 0fprivate var yRotation = 0ffun handleTouchMove(deltaX: Float, deltaY: Float) {xRotation += deltaX / 16fyRotation += deltaY / 16fif (yRotation < -90f) {yRotation = -90f} else if (yRotation > 90) {yRotation = 90f}}}

    具體的流程和邏輯詳見代碼注釋。
    這里說明下為什么采用旋轉的方式,而不是位移的方式進行視角的切換,因為我們不是在一個平面中,而是位于一個立方體的中央,沿著某個方向(比如Y軸)進行選擇,即可實現天空移動的效果,如果采用位移的方式看到的是立方體的移動。
    對比效果如下:

    ?

    另外關于移動,可以自動旋轉,也可以加入觸碰旋轉的實現,通過glSurfaceView.queueEvent給render刷新旋轉的大小,即可相應跟隨手勢旋轉的效果

    ?

    glSurfaceView.setOnTouchListener(object : OnTouchListener {var lastX = 0f;var lastY = 0f;override fun onTouch(v: View?, event: MotionEvent?): Boolean {if (event == null) {return false}if (MotionEvent.ACTION_DOWN == event.action) {lastX = event.x;lastY = event.y;} else if (MotionEvent.ACTION_MOVE == event.action) {val deltaX = event.x - lastXval deltaY = event.y - lastYlastX = event.xlastY = event.yglSurfaceView.queueEvent {skyBoxRender.handleTouchMove(deltaX, deltaY)}}return true}})

    詳細代碼請查看?github?https://github.com/ayyb1988/mediajourney

    三、資料

  • 天空盒(SkyBox)的實現原理與細節
  • NDK OpenGL ES 3.0 開發(十五):立方體貼圖(天空盒)
  • 立方體貼圖
  • OpenGL 圖形庫的使用(二十六)—— 高級OpenGL之立方體貼圖Cubemaps
  • opengl渲染管線 不能再詳細了
  • 四、收獲

  • 了解天空盒的原理
  • 立方體貼圖的實現
  • 具體代碼實現
  • 感謝你的閱讀
    要讓渲染的內容更加逼真,反射、折射等的應用必不可少
    下一篇我們進入光照部分的學習實踐,歡迎關注公眾號“音視頻開發之旅”,一起學習成長。
    歡迎交流

    總結

    以上是生活随笔為你收集整理的音视频开发之旅(41)-天空盒的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 免费成人在线视频观看 | 国产色婷婷一区二区 | 97久久国产亚洲精品超碰热 | 你懂的91| 伊人久久精品一区二区三区 | 成人在线观看免费高清 | 免费黄网在线看 | 日韩美在线 | 先锋av资源在线 | 一区二区三区视频免费 | 色婷婷综合久久久久中文字幕 | 97自拍视频在线 | 日本人妻不卡一区二区三区中文字幕 | 日本一区二区不卡在线观看 | www.国产区 | 黑人操亚洲人 | 99re这里只有精品首页 | 免费在线观看a级片 | 一区二区三区国产精品 | 美女脱裤子让男人捅 | 撕开少妇裙子猛然进入 | 九色视频偷拍少妇的秘密 | 中文字幕在线观看视频一区 | 暗呦丨小u女国产精品 | 国产精品一线二线 | 在线免费观看一区 | 久久免费高清视频 | 日本伦理片在线播放 | 女人喂男人奶水做爰视频 | 美女靠逼视频网站 | 人妻互换一区二区三区四区五区 | 国产精品毛片一区二区在线看舒淇 | 青青草草| 91网站免费在线观看 | 国产精品久久久午夜夜伦鲁鲁 | 精品久久久久久久免费人妻 | 日韩精品在线免费 | 日韩三级视频 | 亚洲综合在线一区 | 潘金莲黄色一级片 | 亚洲AV无码成人精品区在线观 | 国产精品国产三级国产专播精品人 | 哪里可以看毛片 | 香蕉在线网站 | 免费av的网站 | 精品人伦一区二区三区蜜桃免费 | 国产成人午夜精品 | 午夜黄色在线 | 成人欧美一区二区 | 粉嫩一区二区三区 | 淫视频网站 | 久热精品在线观看 | www.中文字幕在线观看 | 国产又黄又粗又猛又爽视频 | 亚洲av少妇一区二区在线观看 | 在线观看 中文字幕 | 成人香蕉网 | 男女做爰真人视频直播 | 久久都是精品 | 97人妻精品一区二区 | 91sao| 青苹果av | 麻豆网址 | 中文字幕一区二区三区精华液 | 国产v亚洲v天堂无码 | 国产香蕉视频在线观看 | 热久久最新 | 日本免费专区 | 国模小丫大尺度啪啪人体 | 国产亚洲天堂 | 亚洲丝袜一区 | 欧美一区二区三区久久妖精 | 都市豪门艳霸淫美妇 | 性高潮久久久久 | 久久久精品视频免费 | 色婷婷综合在线 | 亚洲精品a | 成人综合婷婷国产精品久久 | 日本三级视频在线播放 | 黄页网站免费观看 | 日韩影院在线 | 毛片91| 一区二区三区av | 国产日韩欧美综合 | 五月婷网站 | 小色哥网站 | 精品黑人一区二区三区国语馆 | 国产黄频 | 成人免费观看视频网站 | 88xx成人永久免费观看 | 中文字幕 欧美激情 | 每日av在线 | av优选在线观看 | 国产美女菊爆在线播放APP | 国产51视频 | 无码精品在线观看 | 亚洲成人播放器 | 中文字幕在线视频免费 | 成人勉费视频 |