OpenGL著色器程序的編譯鏈接和綁定

  • 讀取頂點著色器和片元著色器
  NSString *vertFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
  NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];

  • 編譯著色器程序
-(GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag {
    //定義2個零時著色器對象
    GLuint verShader, fragShader;
    //創(chuàng)建program
    GLint program = glCreateProgram();
    
    //編譯頂點著色程序哮缺、片元著色器程序
    //參數(shù)1:編譯完存儲的底層地址
    //參數(shù)2:編譯的類型,GL_VERTEX_SHADER(頂點)、GL_FRAGMENT_SHADER(片元)
    //參數(shù)3:文件路徑
    [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
    
    //創(chuàng)建最終的程序
    glAttachShader(program, verShader);
    glAttachShader(program, fragShader);
    
    //釋放不需要的shader
    glDeleteShader(verShader);
    glDeleteShader(fragShader);
    
    return program;
}

//編譯shader
- (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{
    
    //讀取文件路徑字符串
    NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar* source = (GLchar *)[content UTF8String];
    
    //創(chuàng)建一個shader(根據(jù)type類型)
    *shader = glCreateShader(type);
    
    //將頂點著色器源碼附加到著色器對象上。
    //參數(shù)1:shader,要編譯的著色器對象 *shader
    //參數(shù)2:numOfStrings,傳遞的源碼字符串?dāng)?shù)量 1個
    //參數(shù)3:strings,著色器程序的源碼(真正的著色器程序源碼)
    //參數(shù)4:lenOfStrings,長度军浆,具有每個字符串長度的數(shù)組坯门,或NULL微饥,這意味著字符串是NULL終止的
    glShaderSource(*shader, 1, &source,NULL);
    
    //把著色器源代碼編譯成目標(biāo)代碼
    glCompileShader(*shader); 
}
  • 鏈接
  // 加載shader
    self.myPrograme = [self loadShaders:vertFile Withfrag:fragFile];
  // 4.鏈接
    glLinkProgram(self.myPrograme);
  // 獲取鏈接狀態(tài)
    GLint linkStatus;
    glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
  // 鏈接失敗,則提示并退出
    if (linkStatus == GL_FALSE) {
        GLchar message[512];
        glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"Program Link Error:%@",messageString);
        return;
    }
 // 鏈接成功 
    NSLog(@"Program Link Success!");

  • 綁定參數(shù)
   // 5.使用program
    glUseProgram(self.myPrograme);
    
    // 6.設(shè)置頂點古戴、紋理坐標(biāo)
    // 前3個是頂點坐標(biāo)欠橘,后2個是紋理坐標(biāo)
    GLfloat attrArr[] =  {
        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
        -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,
        0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
    };

 //-----處理頂點數(shù)據(jù)--------
    // 頂點緩存區(qū)
    GLuint attrBuffer;
    // 申請一個緩存區(qū)標(biāo)識符
    glGenBuffers(1, &attrBuffer);
    // 將attrBuffer綁定到GL_ARRAY_BUFFER標(biāo)識符上
    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
    // 把頂點數(shù)據(jù)從CPU內(nèi)存復(fù)制到GPU上
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

    // 將頂點數(shù)據(jù)通過myPrograme中的傳遞到頂點著色程序的position
    // 1.glGetAttribLocation,用來獲取vertex attribute的入口的.
    // 2.告訴OpenGL ES,通過glEnableVertexAttribArray,
    // 3.最后數(shù)據(jù)是通過glVertexAttribPointer傳遞過去的现恼。
    // 注意:第二參數(shù)字符串必須和shaderv.vsh中的輸入變量:position保持一致
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
    
    // 2.設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(position);
    
    // 3.設(shè)置讀取方式
    // 參數(shù)1:index,頂點數(shù)據(jù)的索引
    // 參數(shù)2:size,每個頂點屬性的組件數(shù)量肃续,1,2叉袍,3始锚,或者4.默認(rèn)初始值是4.
    // 參數(shù)3:type,數(shù)據(jù)中的每個組件的類型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT喳逛。默認(rèn)初始值為GL_FLOAT
    //參數(shù)4:normalized,固定點數(shù)據(jù)值是否應(yīng)該歸一化瞧捌,或者直接轉(zhuǎn)換為固定值。(GL_FALSE)
    //參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量润文,默認(rèn)為0姐呐;
    //參數(shù)6:指定一個指針,指向數(shù)組中的第一個頂點屬性的第一個組件典蝌。默認(rèn)為0
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);
    
    
    //----處理紋理數(shù)據(jù)-------
    //1. glGetAttribLocation,用來獲取vertex attribute的入口的.
    // 注意:第二參數(shù)字符串必須和shaderv.vsh中的輸入變量:textCoordinate保持一致
    GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
    
    // 2.設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(textCoor);
    
    // 3.設(shè)置讀取方式
    // 參數(shù)1:index,頂點數(shù)據(jù)的索引
    // 參數(shù)2:size,每個頂點屬性的組件數(shù)量曙砂,1,2赠法,3,或者4.默認(rèn)初始值是4.
    // 參數(shù)3:type,數(shù)據(jù)中的每個組件的類型乔夯,常用的有GL_FLOAT,GL_BYTE,GL_SHORT砖织。默認(rèn)初始值為GL_FLOAT
    // 參數(shù)4:normalized,固定點數(shù)據(jù)值是否應(yīng)該歸一化,或者直接轉(zhuǎn)換為固定值末荐。(GL_FALSE)
    // 參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量侧纯,默認(rèn)為0;
    // 參數(shù)6:指定一個指針甲脏,指向數(shù)組中的第一個頂點屬性的第一個組件眶熬。默認(rèn)為0
    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3); 
    //加載紋理
    [self setupTexture:@"timg-3"];
    
    //注意,想要獲取shader里面的變量块请,這里記得要在glLinkProgram后面娜氏,后面,后面墩新!
    /*
     一個一致變量在一個圖元的繪制過程中是不會改變的贸弥,所以其值不能在glBegin/glEnd中設(shè)置。一致變量適合描述在一個圖元中海渊、一幀中甚至一個場景中都不變的值绵疲。一致變量在頂點shader和片斷shader中都是只讀的哲鸳。首先你需要獲得變量在內(nèi)存中的位置,這個信息只有在連接程序之后才可獲得
     */
    //rotate等于shaderv.vsh中的uniform屬性盔憨,rotateMatrix
    GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
    
    //獲取渲染的弧度
    float radians = 10 * 3.14159f / 180.0f;
    //求得弧度對于的sin\cos值
    float s = sin(radians);
    float c = cos(radians);
    
    // z軸旋轉(zhuǎn)矩陣 參考3D數(shù)學(xué)第二節(jié)課的圍繞z軸渲染矩陣公式
    // 為什么和公式不一樣徙菠?因為在3D課程中用的是橫向量,在OpenGL ES用的是列向量
    GLfloat zRotation[16] = {
        c, -s, 0, 0,
        s, c, 0, 0,
        0, 0, 1.0, 0,
        0.0, 0, 0, 1.0
    };
    
    //設(shè)置旋轉(zhuǎn)矩陣
    glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);
    
    glDrawArrays(GL_TRIANGLES, 0, 6);
    
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];

//設(shè)置紋理
- (GLuint)setupTexture:(NSString *)fileName {
    //1郁岩、獲取圖片的CGImageRef
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
    
    //判斷圖片是否獲取成功
    if (!spriteImage) {
        NSLog(@"Failed to load image %@", fileName);
        exit(1);
    }
    
    //2婿奔、讀取圖片的大小,寬和高
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    
    //3.獲取圖片字節(jié)數(shù) 寬*高*4(RGBA)
    GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
    
    //4.創(chuàng)建上下文
    /*
     參數(shù)1:data,指向要渲染的繪制圖像的內(nèi)存地址
     參數(shù)2:width,bitmap的寬度驯用,單位為像素
     參數(shù)3:height,bitmap的高度脸秽,單位為像素
     參數(shù)4:bitPerComponent,內(nèi)存中像素的每個組件的位數(shù),比如32位RGBA蝴乔,就設(shè)置為8
     參數(shù)5:bytesPerRow,bitmap的沒一行的內(nèi)存所占的比特數(shù)
     參數(shù)6:colorSpace,bitmap上使用的顏色空間  kCGImageAlphaPremultipliedLast:RGBA
     */
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    
    
    
    //5记餐、在CGContextRef上繪圖
    /*
     CGContextDrawImage 使用的是Core Graphics框架,坐標(biāo)系與UIKit 不一樣薇正。UIKit框架的原點在屏幕的左上角片酝,Core Graphics框架的原點在屏幕的左下角。
     CGContextDrawImage 
     參數(shù)1:繪圖上下文
     參數(shù)2:rect坐標(biāo)
     參數(shù)3:繪制的圖片
     */
    CGRect rect = CGRectMake(0, 0, width, height);
    //使用默認(rèn)方式繪制挖腰,發(fā)現(xiàn)圖片是倒的雕沿。
    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
    /*
     解決圖片倒置的方法(2):
     CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
     CGContextTranslateCTM(spriteContext, 0, rect.size.height);
     CGContextScaleCTM(spriteContext, 1.0, -1.0);
     CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
     CGContextDrawImage(spriteContext, rect, spriteImage);
     */
   
    //6、畫圖完畢就釋放上下文
    CGContextRelease(spriteContext);
    
    //5猴仑、綁定紋理到默認(rèn)的紋理ID(這里只有一張圖片审轮,故而相當(dāng)于默認(rèn)于片元著色器里面的colorMap,如果有多張圖不可以這么做)
    glBindTexture(GL_TEXTURE_2D, 0);
    
    //設(shè)置紋理屬性
    /*
     參數(shù)1:紋理維度
     參數(shù)2:線性過濾辽俗、為s,t坐標(biāo)設(shè)置模式
     參數(shù)3:wrapMode,環(huán)繞模式
     */
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    float fw = width, fh = height;
    //載入紋理2D數(shù)據(jù)
    /*
     參數(shù)1:紋理模式疾渣,GL_TEXTURE_1D、GL_TEXTURE_2D崖飘、GL_TEXTURE_3D
     參數(shù)2:加載的層次榴捡,一般設(shè)置為0
     參數(shù)3:紋理的顏色值GL_RGBA
     參數(shù)4:寬
     參數(shù)5:高
     參數(shù)6:border,邊界寬度
     參數(shù)7:format
     參數(shù)8:type
     參數(shù)9:紋理數(shù)據(jù)
     */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    
    //綁定紋理
    /*
     參數(shù)1:紋理維度
     參數(shù)2:紋理ID,因為只有一個紋理朱浴,給0就可以了吊圾。
     */
    glBindTexture(GL_TEXTURE_2D, 0);
    
    //釋放spriteData
    free(spriteData);
    
    return 0;
}

(本文為學(xué)習(xí)筆記,資料來自CC老師)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翰蠢,一起剝皮案震驚了整個濱河市项乒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梁沧,老刑警劉巖板丽,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡埃碱,警方通過查閱死者的電腦和手機猖辫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砚殿,“玉大人啃憎,你說我怎么就攤上這事∷蒲祝” “怎么了辛萍?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長羡藐。 經(jīng)常有香客問我贩毕,道長,這世上最難降的妖魔是什么仆嗦? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任辉阶,我火速辦了婚禮,結(jié)果婚禮上瘩扼,老公的妹妹穿的比我還像新娘谆甜。我一直安慰自己,他們只是感情好集绰,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布规辱。 她就那樣靜靜地躺著,像睡著了一般栽燕。 火紅的嫁衣襯著肌膚如雪罕袋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天碍岔,我揣著相機與錄音浴讯,去河邊找鬼。 笑死付秕,一個胖子當(dāng)著我的面吹牛兰珍,可吹牛的內(nèi)容都是我干的侍郭。 我是一名探鬼主播询吴,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亮元!你這毒婦竟也來了猛计?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤爆捞,失蹤者是張志新(化名)和其女友劉穎奉瘤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡盗温,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年藕赞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卖局。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡斧蜕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砚偶,到底是詐尸還是另有隱情批销,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布染坯,位于F島的核電站均芽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏单鹿。R本人自食惡果不足惜掀宋,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羞反。 院中可真熱鬧布朦,春花似錦、人聲如沸昼窗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澄惊。三九已至唆途,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掸驱,已是汗流浹背肛搬。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毕贼,地道東北人温赔。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像鬼癣,于是被迫代替她去往敵國和親陶贼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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