《OpenGL從入門到放棄06》紋理圖片顯示

之前的文章:
《OpenGL從入門到放棄01 》一些基本概念
《OpenGL從入門到放棄02 》GLSurfaceView和Renderer
《OpenGL從入門到放棄03 》相機(jī)和視圖
《OpenGL從入門到放棄04 》畫一個(gè)長方形
《OpenGL從入門到放棄05》著色器語言

這一節(jié)我們來學(xué)習(xí)一下如何用OpenGL顯示一張圖片柑肴,先上圖


在OpenGL中顯示一張圖片蛔添,需要使用到紋理采樣函數(shù) texture2D,整個(gè)步驟大概如下

我們?cè)?a href="http://www.reibang.com/p/e75e03ab135b" target="_blank">《OpenGL從入門到放棄04 》畫一個(gè)長方形的基礎(chǔ)上修改

1角雷、修改著色器

    // 頂點(diǎn)著色器的腳本
    String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +         //接收傳入的轉(zhuǎn)換矩陣
            "attribute vec4 vPosition;" +      //接收傳入的頂點(diǎn)
            "attribute vec2 aTexCoord;" +       //接收傳入的頂點(diǎn)紋理位置
            "varying vec2 vTextureCoord;" +     //增加用于傳遞給片元著色器的紋理位置變量
            "void main() {" +
                    "gl_Position = uMVPMatrix * vPosition;" +  //矩陣變換計(jì)算之后的位置
                    "vTextureCoord = aTexCoord;" +
            " }";

    // 片元著色器的腳本
    String fragmentShaderCode =
            " precision mediump float;" +  // 聲明float類型的精度為中等(精度越高越耗資源)
              "varying vec2 vTextureCoord;" +  //紋理坐標(biāo)
              "uniform sampler2D sTexture;" + //紋理采樣器,代表一副紋理
              " void main() {" +
                     "gl_FragColor = texture2D(sTexture,vTextureCoord);" +//進(jìn)行紋理采樣
               " }";

片元的顏色不再是簡單的單色咆课,而是通過texture2D進(jìn)行紋理采樣燃领,得到的顏色。

紋理采樣器 sampler2D sTexture某饰,變量名sTexture是我們自己取的,我們不用為sTexture賦值,著色器會(huì)自動(dòng)處理sTexture黔漂,指向我們待會(huì)兒要傳過去的紋理圖片诫尽,紋理坐標(biāo)由頂點(diǎn)著色器傳過來。

2炬守、準(zhǔn)備紋理坐標(biāo)數(shù)據(jù)

先說一下紋理坐標(biāo)系

紋理貼圖:把一個(gè)紋理(對(duì)于2D貼圖牧嫉,可以簡單的理解為圖片),按照所期望的方式顯示在圖形的表面减途。

如果想把一幅紋理映射到相應(yīng)的幾何圖元酣藻,就必須告訴GPU如何進(jìn)行紋理映射,也就是為圖元的頂點(diǎn)指定恰當(dāng)?shù)募y理坐標(biāo)鳍置。紋理坐標(biāo)用浮點(diǎn)數(shù)來表示臊恋,范圍一般從0.0到1.0,左上角坐標(biāo)為(0.0墓捻,0.0)抖仅,右上角坐標(biāo)為(1.0,0.0)砖第,左下角坐標(biāo)為(0.0撤卢,1.0),右下角坐標(biāo)為(1.0梧兼,1.0)

紋理坐標(biāo)

頂點(diǎn)坐標(biāo)

看上面兩張圖就明白了放吩,假如長方形的頂點(diǎn)順序是V1、v2羽杰、v4渡紫、v3,那么紋理坐標(biāo)對(duì)應(yīng)V1考赛、v2惕澎、v4、v3颜骤,才能正常顯示

了解了紋理坐標(biāo)之后唧喉,開始寫代碼了~

根據(jù)長方形的頂點(diǎn)坐標(biāo),定義對(duì)應(yīng)的紋理坐標(biāo)

private void initVertext() {
        float vertices[] = new float[]{
                -1, 1, 0,
                -1, -1, 0,
                1, 1, 0,
                1, -1, 0,
        };//頂點(diǎn)位置

        float[] colors = new float[]{
                0, 0,
                0, 1,
                1, 0,
                1, 1,
        };//紋理頂點(diǎn)數(shù)組
        //轉(zhuǎn)換成 FloatBuffer
        mVertexBuffer = GLUtil.floatArray2FloatBuffer(vertices);
        mTexCoordBuffer = GLUtil.floatArray2FloatBuffer(colors);
    }

這一步非常簡單了忍抽,頂點(diǎn)坐標(biāo)跟紋理坐標(biāo)一一對(duì)應(yīng)八孝,比如頂點(diǎn)在左上角[-1,1],紋理坐標(biāo)對(duì)應(yīng)[0,0]鸠项,此處忽略z軸干跛。不明白再看看上面兩張圖

3、獲取紋理坐標(biāo)句柄

頂點(diǎn)著色器中增加了紋理坐標(biāo)變量 vTextureCoord祟绊,
需要給他賦值楼入,所以先獲取句柄哥捕,然后在draw方法進(jìn)行設(shè)置數(shù)據(jù)

        //紋理位置句柄
        maTexCoordHandle = GLES20.glGetAttribLocation(mProgram,"aTexCoord");

光有紋理坐標(biāo),沒有紋理數(shù)據(jù)也不行浅辙,所以下一步是設(shè)置紋理數(shù)據(jù)

4扭弧、設(shè)置紋理數(shù)據(jù)

先上代碼

    private void initTexture(){
        int textures[] = new int[1]; //生成紋理id

        GLES20.glGenTextures(  //創(chuàng)建紋理對(duì)象
                1, //產(chǎn)生紋理id的數(shù)量
                textures, //紋理id的數(shù)組
                0  //偏移量
        );
        mTextureId = textures[0];

        //綁定紋理id阎姥,將對(duì)象綁定到環(huán)境的紋理單元
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);//設(shè)置MIN 采樣方式
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);//設(shè)置MAG采樣方式
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置S軸拉伸方式
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置T軸拉伸方式

        if (mBitmap == null){
            Log.e("lxb", "initTexture: mBitmap == null");
            return;
        }
        //加載圖片
        GLUtils.texImage2D( //實(shí)際加載紋理進(jìn)顯存
                GLES20.GL_TEXTURE_2D, //紋理類型
                0, //紋理的層次记舆,0表示基本圖像層,可以理解為直接貼圖
                mBitmap, //紋理圖像
                0 //紋理邊框尺寸
        );
    }

設(shè)置紋理數(shù)據(jù)有幾個(gè)步驟

  1. 創(chuàng)建紋理對(duì)象 GLES20.glGenTextures呼巴,可以拿到紋理id
  2. 綁定紋理id GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
  3. 設(shè)置采樣方法 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
    GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST)
  4. 實(shí)際加載紋理進(jìn)顯存 GLUtils.texImage2D泽腮,需要先準(zhǔn)備Bitmap

4、紋理坐標(biāo)賦值再繪制

紋理數(shù)據(jù)設(shè)置好了衣赶,紋理句柄有了诊赊,只差最后一步,把紋理坐標(biāo)傳給著色器

        //把紋理坐標(biāo)傳給著色器
        GLES20.glEnableVertexAttribArray(maTexCoordHandle);
        GLES20.glVertexAttribPointer(maTexCoordHandle, 2,
                GLES20.GL_FLOAT, false,
                2*4, mTexCoordBuffer);

主要修改以上幾點(diǎn)府瞄,其它的保存不變碧磅,整理后的代碼如下

/**
 *
 * 增加紋理
 */
public class Square02 {

    // 頂點(diǎn)著色器的腳本
    String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +         //接收傳入的轉(zhuǎn)換矩陣
            "attribute vec4 vPosition;" +      //接收傳入的頂點(diǎn)
            "attribute vec2 aTexCoord;" +       //接收傳入的頂點(diǎn)紋理位置
            "varying vec2 vTextureCoord;" +     //增加用于傳遞給片元著色器的紋理位置變量
            "void main() {" +
                    "gl_Position = uMVPMatrix * vPosition;" +  //矩陣變換計(jì)算之后的位置
                    "vTextureCoord = aTexCoord;" +
            " }";


    // 片元著色器的腳本
    String fragmentShaderCode =
            " precision mediump float;" +  // 聲明float類型的精度為中等(精度越高越耗資源)
              "varying vec2 vTextureCoord;" +
              "uniform sampler2D sTexture;" + //紋理采樣器,代表一副紋理
              " void main() {" +
                     "gl_FragColor = texture2D(sTexture,vTextureCoord);" +//進(jìn)行紋理采樣
               " }";

    private FloatBuffer mVertexBuffer;  //頂點(diǎn)坐標(biāo)數(shù)據(jù)要轉(zhuǎn)化成FloatBuffer格式
    private FloatBuffer mTexCoordBuffer;//頂點(diǎn)紋理坐標(biāo)緩存


    // 數(shù)組中每3個(gè)值作為一個(gè)坐標(biāo)點(diǎn)
    static final int COORDS_PER_VERTEX = 3;

    //一個(gè)頂點(diǎn)有3個(gè)float遵馆,一個(gè)float是4個(gè)字節(jié)鲸郊,所以一個(gè)頂點(diǎn)要12字節(jié)
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per mVertex

    //當(dāng)前繪制的頂點(diǎn)位置句柄
    private int vPositionHandle;
    //變換矩陣句柄
    private int mMVPMatrixHandle;
    //這個(gè)可以理解為一個(gè)OpenGL程序句柄
    private  int mProgram;
    //紋理坐標(biāo)句柄
    private int maTexCoordHandle;

    //變換矩陣,提供set方法
    private float[] mvpMatrix = new float[16];
    private int mTextureId;

    public void setMvpMatrix(float[] mvpMatrix) {
        this.mvpMatrix = mvpMatrix;
    }
    private Bitmap mBitmap;

    public Square02(Bitmap bitmap) {
        this.mBitmap = bitmap;
        initVertext();
        initShder();
        initTexture();
    }

    private void initVertext() {
        float vertices[] = new float[]{
                -1, 1, 0,
                -1, -1, 0,
                1, 1, 0,
                1, -1, 0,
        };//頂點(diǎn)位置

        float[] colors = new float[]{
                0, 0,
                0, 1,
                1, 0,
                1, 1,
        };//紋理頂點(diǎn)數(shù)組
        mVertexBuffer = GLUtil.floatArray2FloatBuffer(vertices);
        mTexCoordBuffer = GLUtil.floatArray2FloatBuffer(colors);
    }

    private void initShder() {
        //獲取程序货邓,封裝了加載秆撮、鏈接等操作
        mProgram = GLUtil.createProgram(vertexShaderCode,fragmentShaderCode);
        /***1.獲取句柄*/
        // 獲取頂點(diǎn)著色器的位置的句柄(這里可以理解為當(dāng)前繪制的頂點(diǎn)位置)
        vPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        // 獲取變換矩陣的句柄
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        //紋理位置句柄
        maTexCoordHandle = GLES20.glGetAttribLocation(mProgram,"aTexCoord");
    }

    private void initTexture(){
        int textures[] = new int[1]; //生成紋理id

        GLES20.glGenTextures(  //創(chuàng)建紋理對(duì)象
                1, //產(chǎn)生紋理id的數(shù)量
                textures, //紋理id的數(shù)組
                0  //偏移量
        );
        mTextureId = textures[0];

        //綁定紋理id,將對(duì)象綁定到環(huán)境的紋理單元
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);//設(shè)置MIN 采樣方式
//        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
//                GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);//設(shè)置MAG采樣方式
//        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
//                GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置S軸拉伸方式
//        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
//                GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置T軸拉伸方式

        if (mBitmap == null){
            Log.e("lxb", "initTexture: mBitmap == null");
            return;
        }
        //加載圖片
        GLUtils.texImage2D( //實(shí)際加載紋理進(jìn)顯存
                GLES20.GL_TEXTURE_2D, //紋理類型
                0, //紋理的層次换况,0表示基本圖像層职辨,可以理解為直接貼圖
                mBitmap, //紋理圖像
                0 //紋理邊框尺寸
        );
    }

    public void draw() {
        // 將程序添加到OpenGL ES環(huán)境
        GLES20.glUseProgram(mProgram);

        /**設(shè)置數(shù)據(jù)*/
        // 啟用頂點(diǎn)屬性,最后對(duì)應(yīng)禁用
        GLES20.glEnableVertexAttribArray(vPositionHandle);
        GLES20.glEnableVertexAttribArray(maTexCoordHandle);

        //設(shè)置三角形坐標(biāo)數(shù)據(jù)(一個(gè)頂點(diǎn)三個(gè)坐標(biāo))
        GLES20.glVertexAttribPointer(vPositionHandle, 3,
                GLES20.GL_FLOAT, false,
                3 * 4, mVertexBuffer);
        //設(shè)置紋理坐標(biāo)數(shù)據(jù)
        GLES20.glVertexAttribPointer(maTexCoordHandle, 2,
                GLES20.GL_FLOAT, false,
                2*4, mTexCoordBuffer);

        // 將投影和視圖轉(zhuǎn)換傳遞給著色器戈二,可以理解為給uMVPMatrix這個(gè)變量賦值為mvpMatrix
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

//        //設(shè)置使用的紋理編號(hào)
//        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

        /** 繪制三角形舒裤,三個(gè)頂點(diǎn)*/
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        // 禁用頂點(diǎn)數(shù)組(好像不禁用也沒啥問題)
        GLES20.glDisableVertexAttribArray(vPositionHandle);
        GLES20.glDisableVertexAttribArray(maTexCoordHandle);
    }
}

源碼已經(jīng)給出,大家可以先動(dòng)手試試觉吭,有問題歡迎留言惭每。

下一篇文章比較有意思了,關(guān)于濾鏡的亏栈,實(shí)現(xiàn)黑白圖片台腥、冷暖色調(diào)、四分鏡等等绒北,敬請(qǐng)期待黎侈。

四分鏡
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市闷游,隨后出現(xiàn)的幾起案子峻汉,更是在濱河造成了極大的恐慌贴汪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件休吠,死亡現(xiàn)場離奇詭異扳埂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瘤礁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門阳懂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柜思,你說我怎么就攤上這事岩调。” “怎么了赡盘?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵号枕,是天一觀的道長。 經(jīng)常有香客問我陨享,道長葱淳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任抛姑,我火速辦了婚禮赞厕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘途戒。我一直安慰自己坑傅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布喷斋。 她就那樣靜靜地躺著唁毒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪星爪。 梳的紋絲不亂的頭發(fā)上浆西,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音顽腾,去河邊找鬼近零。 笑死,一個(gè)胖子當(dāng)著我的面吹牛抄肖,可吹牛的內(nèi)容都是我干的久信。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼漓摩,長吁一口氣:“原來是場噩夢啊……” “哼裙士!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起管毙,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤腿椎,失蹤者是張志新(化名)和其女友劉穎桌硫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啃炸,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铆隘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了南用。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膀钠。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖训枢,靈堂內(nèi)的尸體忽然破棺而出托修,到底是詐尸還是另有隱情忘巧,我是刑警寧澤恒界,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站砚嘴,受9級(jí)特大地震影響十酣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜际长,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一耸采、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧工育,春花似錦虾宇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怔接,卻和暖如春搪泳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扼脐。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工岸军, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓦侮。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓艰赞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肚吏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子方妖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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