GLSL代碼
頂點著色器代碼
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main()
{
varyTextCoord = textCoordinate;
gl_Position = position;
}
片元著色器代碼
獲取紋理對應(yīng)像素點的顏色值
-
TexCoord
紋理坐標,通過頂點著色器傳遞 -
colorMap
,紋理采樣器
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
//lowp vec4 temp = texture2D(colorMap, varyTextCoord);
//gl_FragColor = temp;
gl_FragColor = texture2D(colorMap, varyTextCoord);
}
代碼實現(xiàn)
整體實現(xiàn)流程圖
繪制前的準備
-
設(shè)置圖層
初始化
CAEAGLLayer
self.myEagLayer = (CAEAGLLayer *)self.layer;
設(shè)置屏幕比例
[self setContentScaleFactor:[[UIScreen mainScreen]scale]];
設(shè)置描述屬性
kEAGLDrawablePropertyRetainedBacking
表示繪圖表面顯示后淋淀,是否保留其內(nèi)容凑队。-
kEAGLDrawablePropertyColorFormat
可繪制表面的內(nèi)部顏色緩存區(qū)格式袁辈,這個key對應(yīng)的值是一個NSString指定特定顏色緩存區(qū)對象涮较。kEAGLDrawablePropertyColorFormat枚舉值 描述 kEAGLColorFormatRGBA8 32位的RGBA顏色值(每個表示8位,所以4*8=32位) kEAGLColorFormatRGB565 16位的RGB顏色值 kEAGLColorFormatSRGBA8 表示標準的紅、綠方灾、藍滤祖,sRGB的色彩空間基于獨立的色彩坐標。
self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,nil];
-
創(chuàng)建EAGL上下文
-(void)setupContext { //1.指定OpenGL ES 渲染API版本棍潘,我們使用2.0 EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2; //2.創(chuàng)建圖形上下文 EAGLContext *context = [[EAGLContext alloc]initWithAPI:api]; //3.判斷是否創(chuàng)建成功 if (!context) { NSLog(@"Create context failed!"); return; } //4.設(shè)置圖形上下文 if (![EAGLContext setCurrentContext:context]) { NSLog(@"setCurrentContext failed!"); return; } //5.將局部context恃鞋,變成全局的 self.myContext = context; }
-
清空緩沖區(qū)
-(void)deleteRenderAndFrameBuffer { /* buffer分為frame buffer 和 render buffer2個大類。 其中frame buffer 相當于render buffer的管理者亦歉。 frame buffer object即稱FBO恤浪。 render buffer則又可分為3類。colorBuffer肴楷、depthBuffer水由、stencilBuffer。 */ glDeleteBuffers(1, &_myColorRenderBuffer); self.myColorRenderBuffer = 0; glDeleteBuffers(1, &_myColorFrameBuffer); self.myColorFrameBuffer = 0; }
-
設(shè)置
RenderBuffer
//1.定義一個緩存區(qū)ID GLuint buffer; //2.申請一個緩存區(qū)標志 glGenRenderbuffers(1, &buffer); //3. self.myColorRenderBuffer = buffer; //4.將標識符綁定到GL_RENDERBUFFER glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer); //5.將可繪制對象drawable object's CAEAGLLayer的存儲綁定到OpenGL ES renderBuffer對象 [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
-
設(shè)置
FrameBuffer
生成幀緩存區(qū)之后赛蔫,則需要將
renderbuffer
跟framebuffer
進行綁定砂客,調(diào)用glFramebufferRenderbuffer
函數(shù)進行綁定到對應(yīng)的附著點上,后面的繪制才能起作用呵恢,因此需要先綁定RenderBuffer
鞠值,在綁定FrameBuffer
。//5.設(shè)置FrameBuffer -(void)setupFrameBuffer { //1.定義一個緩存區(qū)ID GLuint buffer; //2.申請一個緩存區(qū)標志 glGenRenderbuffers(1, &buffer); //3. self.myColorFrameBuffer = buffer; //4.綁定 glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer); //5.將渲染緩存區(qū)myColorRenderBuffer 通過glFramebufferRenderbuffer函數(shù)綁定到 GL_COLOR_ATTACHMENT0上渗钉。 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer); }
繪制
繪制流程圖
-
初始化視口
//設(shè)置清屏顏色 glClearColor(0.3f, 0.45f, 0.5f, 1.0f); //清除屏幕 glClear(GL_COLOR_BUFFER_BIT); //1.設(shè)置視口大小 CGFloat scale = [[UIScreen mainScreen]scale]; glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);
-
編譯著色器
-
讀取著色器代碼彤恶,編譯著色器
//編譯shader - (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{ //1.讀取文件路徑字符串 NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; const GLchar* source = (GLchar *)[content UTF8String]; //2.創(chuàng)建一個shader(根據(jù)type類型) *shader = glCreateShader(type); //3.將著色器源碼附加到著色器對象上。 //參數(shù)1:shader,要編譯的著色器對象 *shader //參數(shù)2:numOfStrings,傳遞的源碼字符串數(shù)量 1個 //參數(shù)3:strings,著色器程序的源碼(真正的著色器程序源碼) //參數(shù)4:lenOfStrings,長度晌姚,具有每個字符串長度的數(shù)組粤剧,或NULL,這意味著字符串是NULL終止的 glShaderSource(*shader, 1, &source,NULL); //4.把著色器源代碼編譯成目標代碼 glCompileShader(*shader); }
-
-
鏈接程序
-
將著色器附著到程序上
//加載shader -(GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag { //1.定義2個零時著色器對象 GLuint verShader, fragShader; //創(chuàng)建program GLint program = glCreateProgram(); //2.編譯頂點著色程序挥唠、片元著色器程序 //參數(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]; //3.創(chuàng)建最終的程序 glAttachShader(program, verShader); glAttachShader(program, fragShader); //4.釋放不需要的shader glDeleteShader(verShader); glDeleteShader(fragShader); return program; }
-
鏈接程序宝磨,獲得鏈接狀態(tài)
//3.加載shader self.myPrograme = [self loadShaders:vertFile Withfrag:fragFile]; //4.鏈接 glLinkProgram(self.myPrograme); GLint linkStatus; //獲取鏈接狀態(tài) 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; }
-
使用程序
//5.使用program glUseProgram(self.myPrograme);
-
-
著色器讀取頂點數(shù)據(jù)
-
處理紋理數(shù)據(jù)
GLfloat attrArr[] = { 0.5f, -0.5f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -1.0f, 0.0f, 1.0f, 0.5f, 0.5f, -1.0f, 1.0f, 0.0f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -1.0f, 1.0f, 1.0f, }; //7.-----處理頂點數(shù)據(jù)-------- //(1)頂點緩存區(qū) GLuint attrBuffer; //(2)申請一個緩存區(qū)標識符 glGenBuffers(1, &attrBuffer); //(3)將attrBuffer綁定到GL_ARRAY_BUFFER標識符上 glBindBuffer(GL_ARRAY_BUFFER, attrBuffer); //(4)把頂點數(shù)據(jù)從CPU內(nèi)存復(fù)制到GPU上 glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
-
將頂點數(shù)據(jù)傳遞到頂點著色程序的
position
-
glGetAttribLocation
,用來獲取vertex attribute
的入口的. - 告訴OpenGL ES,通過
glEnableVertexAttribArray
弧关, - 最后數(shù)據(jù)是通過
glVertexAttribPointer
傳遞過去的。
//(1)注意:第二參數(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.默認初始值是4. //參數(shù)3:type,數(shù)據(jù)中的每個組件的類型株憾,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默認初始值為GL_FLOAT //參數(shù)4:normalized,固定點數(shù)據(jù)值是否應(yīng)該歸一化,或者直接轉(zhuǎn)換為固定值嗤瞎。(GL_FALSE) //參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量墙歪,默認為0; //參數(shù)6:指定一個指針贝奇,指向數(shù)組中的第一個頂點屬性的第一個組件虹菲。默認為0 glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);
-
-
處理紋理數(shù)據(jù)
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.默認初始值是4. //參數(shù)3:type,數(shù)據(jù)中的每個組件的類型陕习,常用的有GL_FLOAT,GL_BYTE,GL_SHORT霎褐。默認初始值為GL_FLOAT //參數(shù)4:normalized,固定點數(shù)據(jù)值是否應(yīng)該歸一化,或者直接轉(zhuǎn)換為固定值衡查。(GL_FALSE) //參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量瘩欺,默認為0; //參數(shù)6:指定一個指針拌牲,指向數(shù)組中的第一個頂點屬性的第一個組件俱饿。默認為0 glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3);
-
-
加載紋理
-
加載紋理
/10.加載紋理 [self setupTexture:@"kunkun"];
-
圖片解壓
//1、將 UIImage 轉(zhuǎn)換為 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框架棉圈,坐標系與UIKit 不一樣。UIKit框架的原點在屏幕的左上角眷蜓,Core Graphics框架的原點在屏幕的左下角分瘾。 CGContextDrawImage 參數(shù)1:繪圖上下文 參數(shù)2:rect坐標 參數(shù)3:繪制的圖片 */ CGRect rect = CGRectMake(0, 0, width, height); //6.使用默認方式繪制 CGContextDrawImage(spriteContext, rect, spriteImage); //7、畫圖完畢就釋放上下文 CGContextRelease(spriteContext);
-
設(shè)置紋理參數(shù)
//8吁系、綁定紋理到默認的紋理ID( glBindTexture(GL_TEXTURE_2D, 0); //9.設(shè)置紋理屬性 /* 參數(shù)1:紋理維度 參數(shù)2:線性過濾德召、為s,t坐標設(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; //10.載入紋理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); //11.釋放spriteData free(spriteData);
-
-
-
設(shè)置紋理采樣器
//11. 設(shè)置紋理采樣器 sampler2D glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
- 繪制并渲染
//12.繪圖 glDrawArrays(GL_TRIANGLES, 0, 6); //13.從渲染緩存區(qū)顯示到屏幕上 [self.myContext presentRenderbuffer:GL_RENDERBUFFER];