aliang study opengles之opengles開篇

Android Opengles開篇

前言:opengles感覺算是一個很"古老"的技術(shù)了酱固,從1.0-2.0-3.0經(jīng)歷 了三個版本了
本篇及以后講述的都是建立在opengles2.0基礎(chǔ)上進行demo演示的。可能有些人
對opengl比較陌生府怯,但在Android手機當(dāng)中和圖像相關(guān)的東西,都會涉及到Opengl矗烛。

一.什么是Opengles玫镐?

Opengl這東西是有的倒戏,為什么要在后面加上一個ES呢?它主要是針對于嵌入式設(shè)備恐似,對原本Opengl
進行了裁剪的縮減庫.Opengles的功能比Opengl要少一些杜跷。說白了就是Opengles中你要寫的代碼就更多了,
因為在Opengl中有的一些基本圖形被縮減到只有點矫夷,線葛闷,三角形了。


二.廢話就不. 多說了双藕,開篇就用opengles畫個三角形淑趾,對其中的基本概念進行敘述。

開發(fā)工具就用是Android studio2.1
在AndroidStudio中有個GLSL的插件忧陪,可以識別著色器語言的.
GLSL是opengles中一個關(guān)鍵的文件扣泊,它主要是分為Vertex(頂點)Shader的glsl以及Fragment(片段)Shader的glsl.對它們的編寫就決定最終物體相關(guān)屬性是怎么設(shè)置的了。
對于GLES的說明會放到后面進行嘶摊。這里畫三角形延蟹,對GLSL編寫也是很簡單的,就直接在代碼里加注釋說明更卒。


以建造房子為例子來闡述一個三角形的繪制

三.首先是GLES的簡單編寫

1.畫筆準(zhǔn)備:

Vertex和Frament在opengles中是以字符串的形式被載入等孵,所以在assets里面創(chuàng)建兩個資源文件
vertex.glsl和frag.glsl

vertex.glsl

uniform mat4 uMVPMatrix;  //頂點最終變換矩陣
attribute vec3 aPostion;  //頂點坐標(biāo)值(x,y,z)
attribute vec4 aColor;  //頂點的顏色(R,G,B,A)
varying vec4 vColor;   //傳遞給片段著色器的顏色值,varying聲明的變量都是要傳遞給fragment的

void main(){
    //gl_Position是glsl的內(nèi)置變量稚照,記錄頂點最終的位置 蹂空。
    //vec4(aPostion,1)為是矩陣想成匹配
    gl_Position = uMVPMatrix * vec4(aPostion,1);
    vColor = aColor;//將頂點顏色值傳遞給fragment
}

frag.glsl

precision mediump float;  //聲明float的精度俯萌,一般情況下都是用mediump的
varying vec4 vColor; //接收從頂點glsl傳過來的顏色參數(shù)
//對片段顏色的具體處理
void main(){
    //直接將頂點傳過來的顏色參數(shù)賦值給了內(nèi)置變量gl_fragColor,也就給fragment上色了
    gl_FragColor = vColor;
}

2.將shader(glsl)載入到系統(tǒng)中做畫畫準(zhǔn)備:

幫助類的編寫,這個是固定的模板上枕,以后都可以直接進行復(fù)用的.
這個幫主類的簡單流程如下:

  1. 將asset中的vertext.glsl和frag.glsl
    1. 方法名為:public static String loadFromAssetsFile(String fname, Resources r);
  2. 獲取vertex的ID和fragment的ID
    1. 方法名為:public static int loadShader(int shaderType, String source )
  3. 通過上面獲得的ID,將vertext和fragment組合成programe
    1. public static int createProgram(String vertexSource, String fragmentSource)
幫助類ShaderUtil的具體代碼
package com.bn.Sample3_1;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import android.content.res.Resources;
import android.opengl.GLES20;
import android.util.Log;

//加載頂點Shader與片元Shader的工具類
public class ShaderUtil {
    // 加載制定shader的方法
    public static int loadShader(int shaderType, // shader的類型
                                                    // GLES20.GL_VERTEX_SHADER(頂點)
                                                    // GLES20.GL_FRAGMENT_SHADER(片元)
            String source // shader的腳本字符串
    ) {
        // 創(chuàng)建一個新shader
        int shader = GLES20.glCreateShader(shaderType);
        // 若創(chuàng)建成功則加載shader
        if (shader != 0) {
            // 加載shader的源代碼
            GLES20.glShaderSource(shader, source);
            // 編譯shader
            GLES20.glCompileShader(shader);
            // 存放編譯成功shader數(shù)量的數(shù)組
            int[] compiled = new int[1];
            // 獲取Shader的編譯情況
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {// 若編譯失敗則顯示錯誤日志并刪除此shader
                Log.e("ES20_ERROR", "Could not compile shader " + shaderType
                        + ":");
                Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    // 創(chuàng)建shader程序的方法
    public static int createProgram(String vertexSource, String fragmentSource) {
        // 加載頂點著色器
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }

        // 加載片元著色器
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        // 創(chuàng)建程序
        int program = GLES20.glCreateProgram();
        // 若程序創(chuàng)建成功則向程序中加入頂點著色器與片元著色器
        if (program != 0) {
            // 向程序中加入頂點著色器
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            // 向程序中加入片元著色器
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            // 鏈接程序
            GLES20.glLinkProgram(program);
            // 存放鏈接成功program數(shù)量的數(shù)組
            int[] linkStatus = new int[1];
            // 獲取program的鏈接情況
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            // 若鏈接失敗則報錯并刪除程序
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e("ES20_ERROR", "Could not link program: ");
                Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    // 檢查每一步操作是否有錯誤的方法
    public static void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e("ES20_ERROR", op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    // 從sh腳本中加載shader內(nèi)容的方法
    public static String loadFromAssetsFile(String fname, Resources r) {
        String result = null;
        try {
            InputStream in = r.getAssets().open(fname);
            int ch = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = in.read()) != -1) {
                baos.write(ch);
            }
            byte[] buff = baos.toByteArray();
            baos.close();
            in.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

準(zhǔn)備工作做完咐熙,就需要開始繪制三角形了。

3.Trangle 三角形類編寫

注意事項:1.opengles采用的是左手坐標(biāo)系x->大拇指辨萍,y->中指棋恼,z->食指
2.其中涉及到的一些矩陣,后續(xù)會講到锈玉。

//三角形
public class Triangle
{
    public static float[] mProjMatrix = new float[16];//4x4矩陣 投影用
    public static float[] mVMatrix = new float[16];//攝像機位置朝向9參數(shù)矩陣
    public static float[] mMVPMatrix;//最后起作用的總變換矩陣
    
    int mProgram;//自定義渲染管線程序id
    int muMVPMatrixHandle;//總變換矩陣引用id
    int maPositionHandle; //頂點位置屬性引用id  
    int maColorHandle; //頂點顏色屬性引用id  
    String mVertexShader;//頂點著色器         
    String mFragmentShader;//片元著色器
    static float[] mMMatrix = new float[16];//具體物體的移動旋轉(zhuǎn)矩陣爪飘,旋轉(zhuǎn)、平移
    
    FloatBuffer   mVertexBuffer;//頂點坐標(biāo)數(shù)據(jù)緩沖
    FloatBuffer   mColorBuffer;//頂點著色數(shù)據(jù)緩沖
    int vCount=0;   
    float xAngle=0;//繞x軸旋轉(zhuǎn)的角度
    public Triangle(MyTDView mv)
    {       
        //初始化頂點坐標(biāo)與著色數(shù)據(jù)
        initVertexData();
        //初始化shader
        initShader(mv);
    }
   
    public void initVertexData()
    {
        //頂點坐標(biāo)數(shù)據(jù)的初始化
        vCount=3;  
        final float UNIT_SIZE=0.2f;
        float vertices[]=new float[]
        {
            -4*UNIT_SIZE,0,
            0,0,-4*UNIT_SIZE,
            0,4*UNIT_SIZE,0,0,
            -4*UNIT_SIZE,0,0
        };
        
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
        vbb.order(ByteOrder.nativeOrder());
        mVertexBuffer = vbb.asFloatBuffer();
        mVertexBuffer.put(vertices);
        mVertexBuffer.position(0);
        
        float colors[]=new float[]
        {
                1,0,0,1,
                0,0,1,0,
                0,1,0,0
        };
        
        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
        cbb.order(ByteOrder.nativeOrder());
        mColorBuffer = cbb.asFloatBuffer();
        mColorBuffer.put(colors);
        mColorBuffer.position(0);
    }

    //初始化shader
    public void initShader(MyTDView mv)
    {
        //加載頂點著色器的腳本內(nèi)容
        mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
        //加載片元著色器的腳本內(nèi)容
        mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());  
        //基于頂點著色器與片元著色器創(chuàng)建程序
        mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
        //獲取程序中頂點位置屬性引用id  
        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        //獲取程序中頂點顏色屬性引用id  
        maColorHandle= GLES20.glGetAttribLocation(mProgram, "aColor");
        //獲取程序中總變換矩陣引用id
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");  
    }
    
    int i=0;
    public void drawSelf()
    {        
         //制定使用某套shader程序
         GLES20.glUseProgram(mProgram);        
         //初始化變換矩陣
         Matrix.setRotateM(mMMatrix,0,0,0,1,0);
         i=1;
         if(i == 1){
             for(int j=0;j<mMMatrix.length;j++){
                 Log.i("liang.chen","item"+j+" is:"+mMMatrix[j]);
             }
             
         }
         i++;
         
         //設(shè)置沿Z軸正向位移1
         Matrix.translateM(mMMatrix,0,0,0,-1);
         //設(shè)置繞x軸旋轉(zhuǎn)
         Matrix.rotateM(mMMatrix,0,xAngle,0,0,1);
         //
         GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFianlMatrix(mMMatrix), 0); 
         //為畫筆指定頂點位置數(shù)據(jù)
         GLES20.glVertexAttribPointer(
                maPositionHandle,   
                3, 
                GLES20.GL_FLOAT, 
                false,
                3*4,   
                mVertexBuffer
         );
         GLES20.glVertexAttribPointer  
         (
                maColorHandle,
                4,
                GLES20.GL_FLOAT,
                false,
                4*4,
                mColorBuffer
         );
         //允許頂點位置數(shù)據(jù)數(shù)組
         GLES20.glEnableVertexAttribArray(maPositionHandle);  
         GLES20.glEnableVertexAttribArray(maColorHandle);  
         //繪制三角形
         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount); 
    }
    public static float[] getFianlMatrix(float[] spec)
    {
        mMVPMatrix=new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, spec, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);        
        return mMVPMatrix;
    }
}

現(xiàn)在對代碼的==關(guān)鍵點==進行說明:

  • 四個重要的矩陣mMMatrix拉背,mVMatrix师崎,mProjMatrix,mMVPMatrix

    1. mMMatrix指的是物體本身位置椅棺,角度的狀態(tài)矩陣
    2. mVMatrix指的是人眼看物體時候的位置犁罩,角度的狀態(tài)矩陣
    3. mProjMatrix指的是物體成像所處的透視環(huán)境狀態(tài)
    4. mMVPMatrix指的是mMMatrix,mVMatrix,mProjMatrix三者結(jié)合的矩陣
  • 其它參數(shù)說明:

    1. mVertexBuffer指的是vertex buffer ,將頂點數(shù)據(jù)燦在vertex buffer里面后后續(xù)的管線操作就可以直接從buffer取的數(shù)據(jù),這樣加快了數(shù)據(jù)的讀取
    2. mColorBuffer 類似
  • 局部代碼說明:

    float vertices[]=new float[]
      {
          -4*UNIT_SIZE,0,
          0,0,-4*UNIT_SIZE,
          0,4*UNIT_SIZE,0,0,
      };
    

    頂點的坐標(biāo)的两疚,前面說過了opengl采用的是左手坐標(biāo)系

       float colors[]=new float[]
        {
                1,0,0,1,
                0,0,1,0,
                0,1,0,0
        };
    

    三個頂點的顏色值采用的是RGBA

    1. Matrix.setRotateM(mMMatrix,0,0,1,0,0)床估,是將mMMatrix初始化為單位矩陣

     GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFianlMatrix(mMMatrix), 0); 
         //為畫筆指定頂點位置數(shù)據(jù)
         GLES20.glVertexAttribPointer(
                maPositionHandle,   
                3, 
                GLES20.GL_FLOAT, 
                false,
                3*4,   
                mVertexBuffer
         );
         GLES20.glVertexAttribPointer  
         (
                maColorHandle,
                4,
                GLES20.GL_FLOAT,
                false,
                4*4,
                mColorBuffer
         );
    

    這兩個的作用是對頂點屬性值進行賦值的,以第一個glVertexAttribPointer為例
    ==maPositionHandle ==是vertex shader中對應(yīng)的位置屬性值诱渤,==3==指的是坐標(biāo)點是以頂點數(shù)組中三個值為一個頂點丐巫,==GLES20.GL_FLOAT==是頂點數(shù)組中數(shù)據(jù)類型,==34==值的是Buffer中一個頂點的大小因為三個float組成一個頂點所以是34,mVertexBuffer就是頂點坐標(biāo)數(shù)組轉(zhuǎn)成的buffer了

    5.GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    Android的openlgles的圖元有點勺美,線鞋吉,三角形,所有的圖形就靠它們來組成励烦,因為這里
    是直接畫三角形谓着,所以就用GLES20.GL_TRAINGLES

    這篇就直觀上講解了opengles繪制一個簡單圖形是怎么繪制的。下篇開始講知識點坛掠。
    代碼地址:http://pan.baidu.com/s/1dFcjdZj

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赊锚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子屉栓,更是在濱河造成了極大的恐慌舷蒲,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件友多,死亡現(xiàn)場離奇詭異牲平,居然都是意外死亡,警方通過查閱死者的電腦和手機域滥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門纵柿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜈抓,“玉大人,你說我怎么就攤上這事昂儒」凳梗” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵渊跋,是天一觀的道長腊嗡。 經(jīng)常有香客問我,道長拾酝,這世上最難降的妖魔是什么燕少? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蒿囤,結(jié)果婚禮上棺亭,老公的妹妹穿的比我還像新娘。我一直安慰自己蟋软,他們只是感情好镶摘,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岳守,像睡著了一般凄敢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上湿痢,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天涝缝,我揣著相機與錄音,去河邊找鬼譬重。 笑死拒逮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的臀规。 我是一名探鬼主播滩援,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼塔嬉!你這毒婦竟也來了玩徊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤谨究,失蹤者是張志新(化名)和其女友劉穎恩袱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胶哲,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡畔塔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澈吨。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡把敢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棚辽,到底是詐尸還是另有隱情,我是刑警寧澤冰肴,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布屈藐,位于F島的核電站,受9級特大地震影響熙尉,放射性物質(zhì)發(fā)生泄漏联逻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一检痰、第九天 我趴在偏房一處隱蔽的房頂上張望包归。 院中可真熱鬧,春花似錦铅歼、人聲如沸公壤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厦幅。三九已至,卻和暖如春慨飘,著一層夾襖步出監(jiān)牢的瞬間确憨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工瓤的, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留休弃,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓圈膏,卻偏偏與公主長得像塔猾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子稽坤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

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