- 讀取頂點著色器和片元著色器
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老師)