OPengL ES _ 著色器_實戰(zhàn)1

OpenGL ES _ 入門_01
OpenGL ES _ 入門_02
OpenGL ES _ 入門_03
OpenGL ES _ 入門_04
OpenGL ES _ 入門_05
OpenGL ES _ 入門練習(xí)_01
OpenGL ES _ 入門練習(xí)_02
OpenGL ES _ 入門練習(xí)_03
OpenGL ES _ 入門練習(xí)_04
OpenGL ES _ 入門練習(xí)_05
OpenGL ES _ 入門練習(xí)_06
OpenGL ES _ 著色器 _ 介紹
OpenGL ES _ 著色器 _ 程序
OpenGL ES _ 著色器 _ 語法
OpenGL ES_著色器_紋理圖像
OpenGL ES_著色器_預(yù)處理
OpenGL ES_著色器_頂點著色器詳解
OpenGL ES_著色器_片斷著色器詳解
OpenGL ES_著色器_實戰(zhàn)01
OpenGL ES_著色器_實戰(zhàn)02
OpenGL ES_著色器_實戰(zhàn)03

學(xué)習(xí)是一件開心的額事情

學(xué)習(xí)目標

使用著色器渲染一張圖片


核心步驟

  1. 創(chuàng)建著色器程序
  2. 加載頂點坐標
  3. 加載紋理坐標
  4. 加載紋理
  5. 繪制

代碼講解

1.由于著色器編譯 鏈接過程較為繁瑣庐橙,我封裝了一下,文件名為"OSShaderManager.h" 和"OSShaderManager.m"
如果你對著色器程序加載過程不熟悉請參考OpenGL ES _ 著色器 _ 程序
代碼:

 // 第一步.創(chuàng)建我們的對象
  self.shaderManager = [[OSShaderManager alloc]init];
// 第二步.編譯連個shader 文件
GLuint vertexShader,fragmentShader;
NSURL *vertexShaderPath = [[NSBundle mainBundle]URLForResource:@"Shader" withExtension:@"vsh"];
NSURL *fragmentShaderPath = [[NSBundle mainBundle]URLForResource:@"Shader" withExtension:@"fsh"];
if (![self.shaderManager compileShader:&vertexShader type:GL_VERTEX_SHADER URL:vertexShaderPath]||![self.shaderManager compileShader:&fragmentShader type:GL_FRAGMENT_SHADER URL:fragmentShaderPath]){
    return ;
}
//第三步. 注意獲取綁定屬性要在連接程序之前
[self.shaderManager bindAttribLocation:GLKVertexAttribPosition andAttribName:"position"];
[self.shaderManager bindAttribLocation:GLKVertexAttribTexCoord0 andAttribName:"texCoord0"];


//第四步 將編譯好的兩個對象和著色器程序進行連接
if(![self.shaderManager linkProgram]){
    [self.shaderManager deleteShader:&vertexShader];
    [self.shaderManager deleteShader:&fragmentShader];
}
// 第五步.獲取著色器全局屬性的索引
_textureBufferR = [self.shaderManager getUniformLocation:"sam2DR"];

// 第六步.程序編譯成功后瓷胧,刪除著色器對象
[self.shaderManager detachAndDeleteShader:&vertexShader];
[self.shaderManager detachAndDeleteShader:&fragmentShader];

2.加載頂點坐標
如果你對頂點坐標的概念不清楚請查看OpenGL ES _ 入門_02
先看一下我們的頂點坐標長什么樣子

static GLfloat vertex[8] = {
  1,1, //1
-1,1,//0
-1,-1, //2
1,-1, //3
};
02CA342E-8E04-4B5E-B8C5-1011A6C184D5.png

我們選擇的繪制模式為:GL_TRIANGLE_FAN
繪制方法:以V1為起始點桩引,逆時針以此繪制三角形,我們的排列順序為(V1,V0,V2,V3),那么我們繪制第一個三角形為 V1,V0,V2 繪制第二個三角形為 V1,V2,V3

下一個問題茉唉,我們?nèi)绾螌㈨旤c數(shù)據(jù)導(dǎo)入我們的GPU中去?

// 第一步.在GPU 中先申請一個內(nèi)存標識
glGenBuffers(1, &_vertexBuffer);
// 第二步.讓這個標識去綁定一個內(nèi)存區(qū)域,但是此時,這個內(nèi)存沒有大小.
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
// 第三步.根據(jù)頂點數(shù)組的大小海蔽,開辟內(nèi)存空間钥组,并將數(shù)據(jù)加載到內(nèi)存中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), &vertex, GL_STATIC_DRAW);
// 第四步 .啟用這塊內(nèi)存输硝,標記為位置
glEnableVertexAttribArray(GLKVertexAttribPosition);
// 第五步.告訴GPU 頂點數(shù)據(jù)在內(nèi)存中的格式是怎么樣的,應(yīng)該如何去使用
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 8, NULL);

3.加載紋理坐標系
同樣先看我們的紋理坐標長什么樣子

static GLfloat textureCoords[8] = {
1,1,// 對應(yīng)V1
0,1,// 對應(yīng)V0
0,0,// 對應(yīng)V2
1,0 // 對應(yīng)V3
};
紋理坐標系

紋理坐標系S 軸和 T 軸的取值范圍都為[0,1] 程梦,這張圖應(yīng)該能夠明白大體怎么使用吧!

問題:如何加載紋理坐標數(shù)據(jù)?(過程和加載頂點數(shù)據(jù)過程一樣)

// 第一步.在GPU 中先申請一個內(nèi)存標識
glGenBuffers(1, &_textureCoordBuffer);
// 第二步.讓這個標識去綁定一個內(nèi)存區(qū)域点把,但是此時橘荠,這個內(nèi)存沒有大小.
glBindBuffer(GL_ARRAY_BUFFER, _textureCoordBuffer);
// 第三步.根據(jù)頂點數(shù)組的大小,開辟內(nèi)存空間,并將數(shù)據(jù)加載到內(nèi)存中
glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW);
// 第四步 .啟用這塊內(nèi)存咧七,標記為位置
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
// 第五步.告訴GPU 頂點數(shù)據(jù)在內(nèi)存中的格式是怎么樣的速缨,應(yīng)該如何去使用
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 8, NULL);

4.加載紋理圖片像素數(shù)據(jù)
我們先用下面下面這段代碼獲取圖片的像素數(shù)據(jù)

- (void*)getImageData:(UIImage*)image{
CGImageRef imageRef = [image CGImage];
size_t imageWidth = CGImageGetWidth(imageRef);
size_t imageHeight = CGImageGetHeight(imageRef);
GLubyte *imageData = (GLubyte *)malloc(imageWidth*imageHeight*4);
memset(imageData, 0,imageWidth *imageHeight*4);
CGContextRef imageContextRef = CGBitmapContextCreate(imageData, imageWidth, imageHeight, 8, imageWidth*4, CGImageGetColorSpace(imageRef), kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(imageContextRef, 0, imageHeight);
CGContextScaleCTM(imageContextRef, 1.0, -1.0);
CGContextDrawImage(imageContextRef, CGRectMake(0.0, 0.0, (CGFloat)imageWidth, (CGFloat)imageHeight), imageRef);
CGContextRelease(imageContextRef);
return  imageData;
}

然后開始加載我們的圖片像素數(shù)據(jù):

-(void)loadTexture{
//第一步.將我們著色器中的紋理采樣器和紋理區(qū)域0進行關(guān)聯(lián).
glUniform1i(_textureBufferR, 0); // 0 代表GL_TEXTURE0
GLuint tex1;
//第二步.激活紋理區(qū)域0
glActiveTexture(GL_TEXTURE0);
//第三步. 申請內(nèi)存標識
glGenTextures(1, &tex1);
//第四步. 將內(nèi)存和激活的紋理區(qū)域綁定
glBindTexture(GL_TEXTURE_2D,  tex1);
UIImage *image = [UIImage imageNamed:@"2.png"];
GLubyte *imageData = [self getImageData:image];
//第五步.將圖片像素數(shù)據(jù),加載到紋理區(qū)域0 中去
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA , image.size.width, image.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
//第六步.設(shè)置圖片在渲染時的一些配置
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

5.最后一步繪制

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
  // 設(shè)置清除顏色
 glClearColor(1, 1, 1, 1); 
 // 清除顏色緩沖區(qū)
 glClear(GL_COLOR_BUFFER_BIT);
 // 使用著色器程序
 [self.shaderManager useProgram];
  // 繪制 GL_TRIANGLE_FAN 這個是繪制方式贮懈,我們上面講過了.
 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

著色器程序源碼講解

Shader.vsh 頂點著色器,后綴隨便起的(vertex Shader)你也可以這是text沒有關(guān)系,不糾結(jié)哈,我們看代碼:

attribute vec4 position; //  頂點位置
attribute vec2 texCoord0;// 紋理坐標
varying  vec2 texCoordVarying;//片段著色器的輸入變量
void main (){
gl_Position = position;
texCoordVarying = texCoord0;
}

attribute 代表變量是頂點著色器的輸入變量
vec4 4維向量
varying 代表這個變量是片段著色器的輸入變量

我們看看片段著色器的代碼(Shader.fsh)

precision mediump float;//mediump
varying  vec2 texCoordVarying;
uniform sampler2D sam2DR;
void main(){
lowp vec4 rgba = vec4(0,0,0,1);
rgba = texture2D(sam2DR,texCoordVarying);
gl_FragColor = rgba;
}

precision 設(shè)置float精度影暴,mediump 表示中等還有l(wèi)owp 和highp 可選
uniform 代表這個變量是需要從程序外部错邦,即應(yīng)用程序中輸入的,uniform 只能輸入全局變量,切記.

總結(jié)

講解了如何使用著色器加載一樣圖片型宙,把代碼放在這里了,希望你能下載下來看看撬呢。提供一個群號(578734141)給需要幫助的小伙伴!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市妆兑,隨后出現(xiàn)的幾起案子魂拦,更是在濱河造成了極大的恐慌,老刑警劉巖搁嗓,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芯勘,死亡現(xiàn)場離奇詭異,居然都是意外死亡腺逛,警方通過查閱死者的電腦和手機荷愕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棍矛,“玉大人安疗,你說我怎么就攤上這事」晃” “怎么了荐类?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茁帽。 經(jīng)常有香客問我玉罐,道長,這世上最難降的妖魔是什么潘拨? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任吊输,我火速辦了婚禮,結(jié)果婚禮上战秋,老公的妹妹穿的比我還像新娘璧亚。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布癣蟋。 她就那樣靜靜地躺著透硝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疯搅。 梳的紋絲不亂的頭發(fā)上濒生,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音幔欧,去河邊找鬼罪治。 笑死,一個胖子當著我的面吹牛礁蔗,可吹牛的內(nèi)容都是我干的觉义。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼浴井,長吁一口氣:“原來是場噩夢啊……” “哼晒骇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起磺浙,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤洪囤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后撕氧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘤缩,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年伦泥,在試婚紗的時候發(fā)現(xiàn)自己被綠了剥啤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡不脯,死狀恐怖铐殃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跨新,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布坏逢,位于F島的核電站域帐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏是整。R本人自食惡果不足惜肖揣,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浮入。 院中可真熱鬧龙优,春花似錦、人聲如沸事秀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宰衙,卻和暖如春平道,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背供炼。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工一屋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人袋哼。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓冀墨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涛贯。 傳聞我的和親對象是個殘疾皇子诽嘉,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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