OpenGLES開發(fā)基礎(chǔ)(二彩届、創(chuàng)建和使用著色器)

在上一節(jié)的文章中遵倦,我們對著色器的基礎(chǔ)有一些基礎(chǔ)的認(rèn)識。學(xué)習(xí)到這里,下面我們挽起褲管就是干雁佳,看看著色器在開發(fā)中的應(yīng)用

有不對的地方希望大佬拍板 ヽ(′з`)?

創(chuàng)建著色器(shader)

這里先貼上安卓代碼,然后在做進(jìn)一步的講解(筆者一直在使用這個(gè)怜跑,感覺非常的好用)

 public int loadshader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            //加載shader的源代碼
            GLES20.glShaderSource(shader, source);
            //編譯shader
            GLES20.glCompileShader(shader);
            //聲明一個(gè)數(shù)組存放著色器
            int[] shaderNum = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, shaderNum, 0);
            if (shaderNum[0] != 0) {
                Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");
                Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }
    public int CreateProgram(String vertexSource, String fragmentSource) {
        //加載頂點(diǎn)著色器
        int vertexProgram = loadshader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexProgram == 0) {
            return 0;
        }
        //加載片元著色器
        int fragmentProgram = loadshader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (fragmentProgram == 0) {
            return 0;
        }
        //創(chuàng)建程序
        int program = GLES20.glCreateProgram();
        //若程序創(chuàng)建成功則向程序中加入頂點(diǎn)著色器與片元著色器
        if (program != 0) {
            //綁定頂點(diǎn)著色器
            GLES20.glAttachShader(program, vertexProgram);
            checkGlError("glAttachShader");//檢測錯誤
            //綁定片元著色器
            GLES20.glAttachShader(program, fragmentProgram);
            checkGlError("fragmentProgram");//檢測錯誤
            GLES20.glLinkProgram(program);//鏈接程序
            //---------實(shí)際這一步都已經(jīng)成功了色瘩,只是要檢測錯誤的著色器
            //存放連接錯誤的數(shù)據(jù)
            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 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);
        }
    }

好了,這就是全部的生成頂點(diǎn)著色器和片元著色器的全部代碼了碍拆,是不是很簡單若治。哈哈......學(xué)到這里,筆者來給大家講解一些方法在著色器中的作用感混,方面大家理解端幼,記憶

glCreateProgram

函數(shù)原型:int glCreateProgram ()
在連接著色器之前,應(yīng)該先創(chuàng)建著色器接收程序的容器弧满,該方法相當(dāng)于就是創(chuàng)建一個(gè)容器婆跑。
如果創(chuàng)建成功,返回一個(gè)正整數(shù)作為該著色器程序的id庭呜。

glAttachShader

函數(shù)原型:void glAttachShader (int program, int shader)
綁定頂點(diǎn)著色器著色器和片元著色器滑进,綁定到容器中。它們都是同一個(gè)方法募谎。

glLinkProgram

函數(shù)原型:void glLinkProgram (int program)
鏈接程序

glGetProgramiv

函數(shù)原型:void glGetProgramiv(int var0, int var1, int[] var2, int var3)
獲取program的連接情況

在這里創(chuàng)建著色器程序的代碼基本介紹完畢了扶关,在CreateProgram方法中,返回一個(gè)int類型的變量数冬,我暫時(shí)把這個(gè)int類型的變量叫做變量A节槐,在使用時(shí),還會用到glUseProgram吉执。

glUseProgram

函數(shù)原型:void glUseProgram(int var0);
它的作用就是使用某套share程序


使用著色器(shader)

同樣疯淫,我們先上代碼,從代碼中講解

    //初始化著色器
    public void initShader(FGLView view) {
        //加載頂點(diǎn)著色器的腳本內(nèi)容
        String mVertexShader = loadFromAssetsFile("vertex.glsl", view.getResources());
        //加載片元著色器的腳本內(nèi)容
        String mFragmentShader = loadFromAssetsFile("frag.glsl", view.getResources());
        //基于頂點(diǎn)著色器與片元著色器創(chuàng)建程序
        mProgram = CreateProgram(mVertexShader, mFragmentShader);
        //獲取程序中頂點(diǎn)位置屬性引用id
        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        //獲取程序中頂點(diǎn)紋理坐標(biāo)屬性引用id
        maTexCoorHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoor");
        //獲取程序中總變換矩陣引用id
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    }
    //流文件讀取assets下面的著色器文件
    public String loadFromAssetsFile(String frame, Resources r) {
        String result = null;
        try {
            InputStream is = r.getAssets().open(frame);
            int ch = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = is.read()) != -1) {
                baos.write(ch);
            }
            byte[] buff = baos.toByteArray();
            baos.close();
            is.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

在這個(gè)代碼中戳玫,loadFromAssetsFile方法我們不用多說熙掺,就是在代碼中通過流的形式,加載著色器文件

下面為大家講解用到的方法

glGetAttribLocation

函數(shù)原型:int glGetAttribLocation(int var0, String var1)
這個(gè)方法主要是用來綁定屬性的id咕宿,這里的id是頂點(diǎn)著色器中的id(位置币绩,紋理,變換矩陣名稱)府阀,如果有讀者不明白頂點(diǎn)著色器缆镣,請參考第一章(http://www.reibang.com/p/ca4c54b2b3db

 public void drawSelf(int texId) {
        //制定使用某套share程序
        GLES20.glUseProgram(mProgram);
        MatrixState.setInitStack();
        //位移操作
        MatrixState.transtate(0, 0, 1);
        MatrixState.rotate(xAngle, 1, 0, 0);
        MatrixState.rotate(yAngle, 0, 1, 0);
        MatrixState.rotate(zAngle, 0, 0, 1);
        //給著色器賦值
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1,
                false, MatrixState.getFinalMatrix(), 0);
        //畫筆設(shè)置頂點(diǎn)數(shù)據(jù)
        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
                false, 0, mVertexBuffer);
        //畫筆給紋理設(shè)置數(shù)據(jù)
        GLES20.glVertexAttribPointer(maTexCoorHandle, 2, GLES20.GL_FLOAT,
                false, 0, mTexCoorBuffer);
        //開啟頂點(diǎn)和紋理繪制
        GLES20.glEnableVertexAttribArray(maPositionHandle);
        GLES20.glEnableVertexAttribArray(maTexCoorHandle);
        //綁定紋理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
        //繪制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
glVertexAttribPointer

畫筆設(shè)置頂點(diǎn)、顏色试浙、紋理數(shù)據(jù)
函數(shù)原型:void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, Buffer ptr)
indx:指定要修改的頂點(diǎn)屬性的索引值
size:指定每個(gè)頂點(diǎn)屬性的組件數(shù)量董瞻。必須為1、2、3或者4钠糊。初始值為4挟秤。(如position是由3個(gè)(x,y,z)組成,而顏色是4個(gè)(r,g,b,a))
type:指定數(shù)組中每個(gè)組件的數(shù)據(jù)類型抄伍∷腋眨可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值為GL_FLOAT截珍。
normalized:指定當(dāng)被訪問時(shí)攀甚,固定點(diǎn)數(shù)據(jù)值是否應(yīng)該被歸一化(GL_TRUE)或者直接轉(zhuǎn)換為固定點(diǎn)值(GL_FALSE)。
stride:指定連續(xù)頂點(diǎn)屬性之間的偏移量岗喉。如果為0秋度,那么頂點(diǎn)屬性會被理解為:它們是緊密排列在一起的。初始值為0沈堡。
ptr:指定一個(gè)指針静陈,指向數(shù)組中第一個(gè)頂點(diǎn)屬性的第一個(gè)組件燕雁。初始值為0诞丽。

glEnableVertexAttribArray

開啟頂點(diǎn)和紋理繪制(允許頂點(diǎn)著色器讀取GPU(服務(wù)器端)數(shù)據(jù)。)
函數(shù)原型:void glEnableVertexAttribArray(int var0)
var0:著色器頂點(diǎn)數(shù)據(jù)

glActiveTexture

該函數(shù)選擇一個(gè)紋理單元拐格,線面的紋理函數(shù)將作用于該紋理單元上僧免,參數(shù)為符號常量GL_TEXTUREi ,i的取值范圍為0~K-1捏浊,K是OpenGL實(shí)現(xiàn)支持的最大紋理單元數(shù)懂衩,可以使用GL_MAX_TEXTURE_UNITS來調(diào)用函數(shù)glGetIntegerv()獲取該值。

glBindTexture

綁定紋理數(shù)據(jù)
函數(shù)原型:glBindTexture(int var0, int var1);
var0:紋理類型
var1:紋理數(shù)據(jù)

glDrawArrays和glDrawElements

glDrawArrays

函數(shù)原型:GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
mode:繪制方式金踪,OpenGL2.0以后提供以下參數(shù):GL_POINTS浊洞、GL_LINES、GL_LINE_LOOP胡岔、GL_LINE_STRIP法希、GL_TRIANGLES、GL_TRIANGLE_STRIP靶瘸、GL_TRIANGLE_FAN苫亦。
first:從數(shù)組緩存中的哪一位開始繪制,一般為0怨咪。
count:數(shù)組中頂點(diǎn)的數(shù)量屋剑。

glDrawElements

函數(shù)原型:void glDrawElements( GLenum mode, GLsizei count,
GLenum type, const GLvoid *indices);
mode指定繪制圖元的類型诗眨,它應(yīng)該是下列值之一唉匾,GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, and GL_POLYGON.
count為繪制圖元的數(shù)量乘上一個(gè)圖元的頂點(diǎn)數(shù)。
type為索引值的類型匠楚,只能是下列值之一:GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT巍膘。
indices:指向索引存貯位置的指針卫病。

在這里著重講解一下這幾個(gè)方法:
GL_LINES_STRIP(條帶線):按照頂點(diǎn)順序連接頂點(diǎn)
GL_TRIANGLES(循環(huán)線):按照頂點(diǎn)順序連接頂點(diǎn),最后一個(gè)點(diǎn)連接第一點(diǎn)
GL_TRIANGLES(三角形):三個(gè)點(diǎn)一組典徘,如果不夠三個(gè)點(diǎn)就會舍棄 多余的點(diǎn)
GL_TRIANGLE_STRIP(三角形帶):頂點(diǎn)按照順序依次 組成三角形繪制蟀苛,最后實(shí)際形成的是一個(gè)三角型帶
GL_TRIANGLE_FAN(三角形扇面):將第一個(gè)點(diǎn)作為中心點(diǎn),其他點(diǎn)作為邊緣點(diǎn)逮诲,繪制一系列的組成扇形的三角形

相同點(diǎn):它們的作用都是矩陣數(shù)據(jù)渲染圖元帜平、進(jìn)行繪制
異同:(這是筆者自己的理解,文采有限...哈哈哈)在移動平臺中梅鹦,glDrawArrays繪制通過每三個(gè)點(diǎn)繪制一個(gè)三角形裆甩,在面點(diǎn)數(shù)據(jù)中,不會重用頂點(diǎn)數(shù)據(jù)齐唆。glDrawElements繪制也是通過每三個(gè)點(diǎn)繪制一個(gè)三角形嗤栓,但是會重用頂點(diǎn)數(shù)據(jù),也就是繪制相同的結(jié)果箍邮。glDrawElements需要的頂點(diǎn)數(shù)據(jù)會更少茉帅,看下面圖更容易理解:
glDrawArray和glDrawElements.png

在MatrixState方法中,封裝了對變換矩陣的常用方法(這套結(jié)構(gòu)讀者可以自己封裝锭弊,方法名也可以自行命名)堪澎。在代碼中解釋也很清楚。請讀者自己查看理解

public class MatrixState {
    private static float[] mProjMatrix = new float[16];//4x4矩陣 投影用
    private static float[] mVMatrix = new float[16];//攝像機(jī)位置朝向9參數(shù)矩陣
    private static float[] mMVPMatrix;//最后起作用的總變換矩陣
    static float[] mMMatrix = new float[16];//具體物體的移動旋轉(zhuǎn)矩陣

    //獲取不變換初始矩陣
    public static void setInitStack() {
        Matrix.setRotateM(mMMatrix, 0, 0, 1, 0, 0);
    }

    //設(shè)置沿xyz軸移動
    public static void transtate(float x, float y, float z) {
        Matrix.translateM(mMMatrix, 0, x, y, z);
    }

    //設(shè)置繞xyz軸轉(zhuǎn)動
    public static void rotate(float angle, float x, float y, float z) {
        Matrix.rotateM(mMMatrix, 0, angle, x, y, z);
    }

    /**
     * 作用:設(shè)置攝像機(jī)
     * 前三個(gè):攝像機(jī)位置x y z
     * 中間三個(gè):攝像機(jī)目標(biāo)點(diǎn)x y z
     * 后三個(gè):攝像機(jī)UP向量X分量味滞,攝像機(jī)UP向量Y分量樱蛤,攝像機(jī)UP向量Z分量
     */
    public static void setCamera(float cx, float cy, float cz, float tx, float ty, float tz, float upx, float upy, float upz) {
        Matrix.setLookAtM(mVMatrix, 0,
                cx, cy, cz,
                tx, ty, tz,
                upx, upy, upz);
    }
    /**
     * 作用:設(shè)置透視投影參數(shù)
     * 前四個(gè):near面的left,right剑鞍,bottom昨凡,top
     * 后兩個(gè):near面距離,far面距離
     */
    public static void setProject(float left, float right, float bottom, float top, float near, float far) {
        Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    //獲取具體物體的總變換矩陣( // 合并投影和視口矩陣 )
    public static float[] getFinalMatrix() {
        mMVPMatrix = new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        return mMVPMatrix;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚁署,一起剝皮案震驚了整個(gè)濱河市便脊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌形用,老刑警劉巖就轧,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異田度,居然都是意外死亡妒御,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門镇饺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乎莉,“玉大人,你說我怎么就攤上這事⊥锟校” “怎么了哼鬓?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長边灭。 經(jīng)常有香客問我异希,道長,這世上最難降的妖魔是什么绒瘦? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任称簿,我火速辦了婚禮,結(jié)果婚禮上惰帽,老公的妹妹穿的比我還像新娘憨降。我一直安慰自己,他們只是感情好该酗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布授药。 她就那樣靜靜地躺著,像睡著了一般呜魄。 火紅的嫁衣襯著肌膚如雪悔叽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天耕赘,我揣著相機(jī)與錄音骄蝇,去河邊找鬼。 笑死操骡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赚窃。 我是一名探鬼主播册招,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勒极!你這毒婦竟也來了是掰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤辱匿,失蹤者是張志新(化名)和其女友劉穎键痛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匾七,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡絮短,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昨忆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丁频。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出席里,到底是詐尸還是另有隱情叔磷,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布奖磁,位于F島的核電站改基,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咖为。R本人自食惡果不足惜寥裂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望案疲。 院中可真熱鬧封恰,春花似錦、人聲如沸褐啡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽备畦。三九已至低飒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懂盐,已是汗流浹背褥赊。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莉恼,地道東北人拌喉。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像俐银,于是被迫代替她去往敵國和親尿背。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349