Android平臺openGL ES實現(xiàn)全景圖片

全景又被稱為3D實景案狠,是一種新興的富媒體技術(shù),其與視頻卷雕,聲音节猿,圖片等傳統(tǒng)的流媒體最大的區(qū)別是“可操作,可交互”爽蝴。 全景分為虛擬現(xiàn)實和3D實景兩種沐批。虛擬現(xiàn)實是利用maya等軟件,制作出來的模擬現(xiàn)實的場景蝎亚,代表有虛擬紫禁城等;3D實景是利用單反相機或街景車拍攝實景照片先馆,經(jīng)過特殊的拼合发框,處理,讓作者立于畫境中煤墙,讓最美的一面展現(xiàn)出來梅惯。

全景顧名思義就是給人以三維立體感覺的實景360度全方位圖像~
此圖像最大的三個特點是:
1、全:全方位仿野,全面的展示了360度球型范圍內(nèi)的所有景致铣减;可在例子中用鼠標(biāo)左鍵按住拖動,觀看場景的各個方向脚作;  
2葫哗、景:實景,真實的場景球涛,三維實景大多是在照片基礎(chǔ)之上拼合得到的圖像劣针,最大限度的保留了場景的真實性;  
3亿扁、360:360度環(huán)視的效果捺典,雖然照片都是平面的,但是通過軟件處理之后得到的360度實景从祝,卻能給人以三維立體的空間感覺襟己,使觀者猶如身在其中引谜。全景由于它給人們帶來全新的真實現(xiàn)場感和交互式的感受。它可廣泛應(yīng)用于三維電子商務(wù)擎浴,如在線的房地產(chǎn)樓盤展示煌张、虛擬旅游、虛擬教育等領(lǐng)域退客。

本篇我們基于上一篇粒子光束 的基礎(chǔ)上實現(xiàn)全景背景圖

看效果圖:

GIF_.gif

我們用連續(xù)的6張?zhí)炜請D片骏融,拼接成了一個無縫的立方體。想想一下我們站在這個立方體的中心萌狂,這個時候我們的前后左右上下都充滿了天空的圖片档玻,不管你的頭轉(zhuǎn)向哪邊,都能夠看見天空茫藏。
理論上我們把眼睛旋轉(zhuǎn)360度觀察误趴,圖上的三個光束會先消失在出現(xiàn),這就像是我們把立方體旋轉(zhuǎn)了360度又回到了原位置一樣务傲。就像下圖:

GIF5_.gif

之所以能實現(xiàn)360度旋轉(zhuǎn)凉当,是因為我們用了6張圖片并把他們加載成一個立方體。

我們先創(chuàng)建一個模型對象類售葡,即立方體模型看杭。

public class Skybox {
    private static final int POSITION_COMPONENT_COUNT = 3;
    private final VertexArray vertexArray;
    private final ByteBuffer indexArray;

    public Skybox() {        
        // Create a unit cube.
        vertexArray = new VertexArray(new float[] {
            -1,  1,  1,     // (0) Top-left near
             1,  1,  1,     // (1) Top-right near
            -1, -1,  1,     // (2) Bottom-left near
             1, -1,  1,     // (3) Bottom-right near
            -1,  1, -1,     // (4) Top-left far
             1,  1, -1,     // (5) Top-right far
            -1, -1, -1,     // (6) Bottom-left far
             1, -1, -1      // (7) Bottom-right far                        
        });

        // 6 indices per cube side
        indexArray =  ByteBuffer.allocateDirect(6 * 6)
            .put(new byte[] {
                // Front
                1, 3, 0,
                0, 3, 2,

                // Back
                4, 6, 5,
                5, 6, 7,

                // Left
                0, 2, 4,
                4, 2, 6,

                // Right
                5, 7, 1,
                1, 7, 3,

                // Top
                5, 1, 4,
                4, 1, 0,

                // Bottom
                6, 2, 7,
                7, 2, 3
            });
        indexArray.position(0);        
    }
    public void bindData(SkyboxShaderProgram skyboxProgram) {
        vertexArray.setVertexAttribPointer(0,
            skyboxProgram.getPositionAttributeLocation(),
            POSITION_COMPONENT_COUNT, 0);               
    }

    public void draw() {
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indexArray);
    }
}

我們用VertexArray儲存立方體的8個頂點。用indexArray 這個索引數(shù)組的索引指向每個頂點挟伙,把所有頂點分別綁定成三角形組楼雹,每個組有立方體上每個面的2個三角形。

bindData方法從內(nèi)存中加載數(shù)據(jù)綁定尖阔,然后通過 glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indexArray);繪制立方體贮缅。

下面我們添加著色器

頂點著色器

uniform mat4 u_Matrix;
attribute vec3 a_Position;  
varying vec3 v_Position;

void main()                    
{                                                 
    v_Position = a_Position;    //把頂點位置傳給片段著色器

    v_Position.z = -v_Position.z; //反轉(zhuǎn)Z分量。把右手坐標(biāo)系轉(zhuǎn)化為左手坐標(biāo)系

    gl_Position = u_Matrix * vec4(a_Position, 1.0);//成u_Matrix即用投影~
    gl_Position = gl_Position.xyww;//把Z值變成W介却,這樣透視除法之后為1谴供,即Z始終在1的遠平面上。Z=1最遠齿坷,即在別的物體的后面桂肌,就像是背景。
}    

片段著色器:

precision mediump float; 

uniform samplerCube u_TextureUnit;//立方體紋理
varying vec3 v_Position;

void main()                         
{
    gl_FragColor = textureCube(u_TextureUnit, v_Position);    
}

然后用Java代碼封裝著色器程序
這里用java代碼映射到著色器上

  uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
    uTextureUnitLocation = glGetUniformLocation(program, U_TEXTURE_UNIT);
    aPositionLocation = glGetAttribLocation(program, A_POSITION);
  }


  public void setUniforms(float[] matrix, int textureId) {
    glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
    glUniform1i(uTextureUnitLocation, 0);
  }

有了關(guān)系映射胃夏,就可以綁定數(shù)據(jù)進行繪制了
@onDrawFrame(GL10 gl10)中

skyboxProgram.useProgram();
    skyboxProgram.setUniforms(viewProjectionMatrix, skyboxTexture);//映射
    skybox.bindData(skyboxProgram);//綁定數(shù)據(jù)
    skybox.draw();//繪制

下面看手勢操作代碼
在Activity中監(jiān)聽glSurfaceView

glSurfaceView.setOnTouchListener(new View.OnTouchListener() {
      float previousX, previousY;

      @Override public boolean onTouch(View v, MotionEvent event) {
        if (event != null) {
          if (event.getAction() == MotionEvent.ACTION_DOWN) {
            previousX = event.getX();
            previousY = event.getY();
          } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            final float deltaX = event.getX() - previousX;
            final float deltaY = event.getY() - previousY;

            previousX = event.getX();
            previousY = event.getY();

            glSurfaceView.queueEvent(new Runnable() {
              @Override public void run() {
                particlesRenderer.handleTouchDrag(deltaX, deltaY);
              }
            });
          }

          return true;
        } else {
          return false;
        }
      }
    });

因為openGL是在一個單獨的線程中的轴或,所以需要 glSurfaceView.queueEvent發(fā)送事件

把deltaX, deltaY傳遞到了Renderer類中

public void handleTouchDrag(float deltaX, float deltaY) {
    xRotation += deltaX / 16f; //除以16是縮減拖動效果的
    yRotation += deltaY / 16f;

然后我們根據(jù)這個滑動值,用矩陣去操作立方體變化仰禀。
@onDrawFrame

//以 0 0 0為中心繪制照雁,我們站在中心觀察
  private void drawSkybox() {
    setIdentityM(viewMatrix, 0);
    rotateM(viewMatrix, 0, -yRotation, 1f, 0f, 0f);//沿著Y軸旋轉(zhuǎn)
    rotateM(viewMatrix, 0, -xRotation, 0f, 1f, 0f);//沿著x軸旋轉(zhuǎn)  FPS模型
    multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
    skyboxProgram.useProgram();
    skyboxProgram.setUniforms(viewProjectionMatrix, skyboxTexture);
    skybox.bindData(skyboxProgram);
    skybox.draw();
  }

在這之前我們要在onSurfaceCreated里面初始化立方體

skyboxProgram = new SkyboxShaderProgram(context);
    skybox = new Skybox();

@Override public void onSurfaceChanged(GL10 gl10, int width, int height) {
    GLES20.glViewport(0, 0, width, height);
    MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width / (float) height, 1f, 10f);
  }

ps:

Kotlin可以編譯成Java字節(jié)碼,也可以編譯成JavaScript,方便在沒有JVM的設(shè)備上運行饺蚊,最近發(fā)布了Kotlin/Native能把Kotlin編譯成機器碼萍诱,也就是C/C++一樣的能力。本專題專注Kotlin污呼,Kotlin/Native裕坊,KotlinJS與Kotlin_Android的那些事,讓我們共同學(xué)習(xí)Kotlin壯大Kotlin~
加入專題吧

Kotlin-Android-KotlinJS-Kotlin/Native:http://www.reibang.com/c/e88f0f9356a8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燕酷,一起剝皮案震驚了整個濱河市籍凝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苗缩,老刑警劉巖饵蒂,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異酱讶,居然都是意外死亡退盯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門泻肯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渊迁,“玉大人,你說我怎么就攤上這事灶挟×鹦啵” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵膏萧,是天一觀的道長漓骚。 經(jīng)常有香客問我,道長榛泛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任噩斟,我火速辦了婚禮曹锨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剃允。我一直安慰自己沛简,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布斥废。 她就那樣靜靜地躺著椒楣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牡肉。 梳的紋絲不亂的頭發(fā)上捧灰,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音统锤,去河邊找鬼毛俏。 笑死炭庙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的煌寇。 我是一名探鬼主播焕蹄,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阀溶!你這毒婦竟也來了腻脏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤银锻,失蹤者是張志新(化名)和其女友劉穎永品,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徒仓,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡腐碱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掉弛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片症见。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖殃饿,靈堂內(nèi)的尸體忽然破棺而出谋作,到底是詐尸還是另有隱情,我是刑警寧澤乎芳,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布遵蚜,位于F島的核電站,受9級特大地震影響奈惑,放射性物質(zhì)發(fā)生泄漏吭净。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一肴甸、第九天 我趴在偏房一處隱蔽的房頂上張望寂殉。 院中可真熱鬧,春花似錦原在、人聲如沸友扰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽村怪。三九已至,卻和暖如春浮庐,著一層夾襖步出監(jiān)牢的瞬間甚负,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腊敲,地道東北人击喂。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像碰辅,于是被迫代替她去往敵國和親懂昂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容