一、索引繪圖
若要繪制下圖目標圖形,按普通處理方式則需要一個個進行N多個三角形的頂點處理。圖中所用到頂點重復性很高,其實只有7個不同的頂點 --> 索引繪圖 --> 將頂點按索引信息進行面的繪制 --> 索引數組:{1,2,3}{3,2,4}{4,2,7}{7,2,5} {4,7,2}{2,7,6}
索引繪圖與圖元裝配中的三角形連接方式結合繪制所需圖形。
二、案例繪制一個三角錐金字塔 - GLSL
1、效果:
2、頂點數據:
上圖,三角錐金字塔所需頂點數據 和 索引信息
3、主要代碼
view 代碼:
1 // 2 // MyGLSLView.m 3 // GL_Demo_GLSL 4 // 5 // Created by Domy on 2020/7/31. 6 // Copyright © 2020 Domy. All rights reserved. 7 // 8 9 10 /* 11 不采用 GLKBaseEffect,使用編譯鏈接自定義的着色器(shader)。用簡單的 glsl 語言來實現頂點、片元着色器,並圖形進行簡單的變換。 12 思路: 13 1.創建圖層 14 2.創建上下文 15 3.清空緩存區 16 4.設置RenderBuffer 17 5.設置FrameBuffer 18 6.開始繪制 19 */ 20 21 #import "MyGLSLView.h" 22 23 #import <OpenGLES/ES2/gl.h> 24 25 #import "GLESMath.h" 26 27 28 @interface MyGLSLView () { 29 30 float xDegree; 31 float yDegree; 32 float zDegree; 33 BOOL bX; 34 BOOL bY; 35 BOOL bZ; 36 NSTimer *myTimer; 37 } 38 39 @property (nonatomic, strong) CAEAGLLayer *myEGLLayer;// 圖層 40 @property (nonatomic, strong) EAGLContext *myContext;// 上下文 41 42 @property (nonatomic, assign) GLuint myColorFrameBuffer;// 43 @property (nonatomic, assign) GLuint myColorRenderBuffer;// 渲染緩沖區 44 45 @property (nonatomic, assign) GLuint myProgram; 46 47 @end 48 49 50 @implementation MyGLSLView 51 52 // 重寫系統 layer 方法 53 +(Class)layerClass { 54 return [CAEAGLLayer class]; 55 } 56 57 - (void)layoutSubviews { 58 59 // 1. 創建設置圖層 60 // 設置 layer 61 self.myEGLLayer = (CAEAGLLayer *)self.layer; 62 63 // 設置 scale 64 [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; 65 66 // 設置屬性 67 /* 68 kEAGLDrawablePropertyRetainedBacking:繪圖表面顯示后,是否保留其內容。 69 kEAGLDrawablePropertyColorFormat:可繪制表面的內部顏色緩存區格式,這個key對應的值是一個NSString指定特定顏色緩存區對象。默認是kEAGLColorFormatRGBA8; 70 71 kEAGLColorFormatRGBA8:32位RGBA的顏色,4*8=32位 72 kEAGLColorFormatRGB565:16位RGB的顏色, 73 kEAGLColorFormatSRGBA8:sRGB代表了標准的紅、綠、藍,即CRT顯示器、LCD顯示器、投影機、打印機以及其他設備中色彩再現所使用的三個基本色素,sRGB的色彩空間基於獨立的色彩坐標,可以使色彩在不同的設備使用傳輸中對應於同一個色彩坐標體系,而不受這些設備各自具有的不同色彩坐標的影響。 74 */ 75 // self.myEGLLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking:@(NO),kEAGLDrawablePropertyColorFormat:kEAGLColorFormatRGBA8}; 76 self.myEGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,nil]; 77 78 79 // 2. 設置上下文 80 self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 81 if (!self.myContext) { 82 NSLog(@"create context failed!"); 83 return; 84 } 85 BOOL isSetSuccess = [EAGLContext setCurrentContext:self.myContext]; 86 if (!isSetSuccess) { 87 return; 88 } 89 90 91 // 3. 清空緩沖區 92 glDeleteBuffers(1, &_myColorRenderBuffer); 93 self.myColorRenderBuffer = 0; 94 glDeleteBuffers(1, &_myColorFrameBuffer); 95 self.myColorFrameBuffer = 0; 96 97 98 // 4. 設置渲染緩沖區 renderBuffer 99 // 生成緩沖區 ID 100 GLuint rb; 101 glGenRenderbuffers(1, &rb); 102 self.myColorRenderBuffer = rb; 103 // 綁定緩沖區 104 glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer); 105 106 // 綁到 context: contect 與 eagllayer綁定在一起 107 [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEGLLayer]; 108 109 110 // 5. 設置幀緩沖區 FrameBuffer 111 glGenBuffers(1, &_myColorFrameBuffer); 112 glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer); 113 114 // 渲染緩沖區 與 幀緩沖區綁在一起 115 /* 116 target: 117 attachment:將 renderBuffer 附着到frameBuffer的哪個附着點上 118 renderbuffertarget 119 renderbuffer 120 */ 121 // glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) 122 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer); 123 124 125 // 開始繪制 126 [self renderLayer]; 127 128 } 129 130 - (void)renderLayer { 131 132 glClearColor(0.7, 0.7, 0.7, 1); 133 glClear(GL_COLOR_BUFFER_BIT); 134 135 /// 1. 設置視口 136 CGFloat mainScale = [UIScreen mainScreen].scale; 137 glViewport(self.frame.origin.x * mainScale, self.frame.origin.y * mainScale, self.frame.size.width * mainScale, self.frame.size.height * mainScale); 138 139 /// 2. 讀取着色器代碼 140 // 定義路徑 141 NSString *verPath = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"vsh"]; 142 NSString *fragPath = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"fsh"]; 143 144 /// 3. 加載着色器 145 if (self.myProgram) { 146 // delete 147 glDeleteProgram(self.myProgram); 148 self.myProgram = 0; 149 } 150 self.myProgram = [self loadShadersWithVertex:verPath Withfrag:fragPath]; 151 152 /// 4. 鏈接 program 153 glLinkProgram(self.myProgram); 154 // 獲取連接狀態 155 GLint linkStatus; 156 glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkStatus); 157 if (linkStatus == GL_FALSE) {// 鏈接出錯 158 // 獲取錯誤信息 log 159 GLchar message[512]; 160 glGetProgramInfoLog(self.myProgram, sizeof(message), 0, &message[0]); 161 NSString *messageString = [NSString stringWithUTF8String:message]; 162 NSLog(@"Program Link Error:%@",messageString); 163 return; 164 } 165 166 /// 5. 使用 program 167 glUseProgram(self.myProgram); 168 169 170 171 /// 6. 設置頂點、顏色RGB 172 GLfloat attrArr[] = { 173 174 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0 175 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上1 176 -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下2 177 178 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下3 179 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //頂點4 180 }; 181 // 索引數組 182 GLuint indices[] = { 183 0, 3, 2, 184 0, 1, 3, 185 0, 2, 4, 186 0, 4, 1, 187 2, 3, 4, 188 1, 4, 3, 189 }; 190 191 /// 7. copy 到頂點緩沖區 192 GLuint buffer; 193 glGenBuffers(1, &buffer); 194 glBindBuffer(GL_ARRAY_BUFFER, buffer); 195 // 頂點數據 copy 到緩沖區 196 glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW); 197 198 /// 8. 打開通道 199 // 8.1 頂點 200 // 獲取通道 ID 201 /* 202 glGetAttribLocation(GLuint program, const GLchar *name) 203 program: 204 name: 給誰傳 --> .vsh 的 position 205 */ 206 GLuint position = glGetAttribLocation(self.myProgram, "position"); 207 // 打開通道 208 glEnableVertexAttribArray(position); 209 // 讀數據 210 glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, NULL); 211 212 // 頂點顏色 213 GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor"); 214 // 設置合適的方式從 buffer 里面讀取數據 215 glEnableVertexAttribArray(positionColor); 216 glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)NULL + 3); 217 218 // 矩陣變換 219 [self configMartix]; 220 221 222 /// 11. 繪制 223 // glDrawArrays(GL_TRIANGLES, 0, 6); 224 225 glEnable(GL_CULL_FACE); 226 glEnable(GL_DEPTH_TEST); 227 228 229 // 使用索引繪圖 230 /* 231 void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices); 232 參數列表: 233 mode:要呈現的畫圖的模型 234 GL_POINTS 235 GL_LINES 236 GL_LINE_LOOP 237 GL_LINE_STRIP 238 GL_TRIANGLES 239 GL_TRIANGLE_STRIP 240 GL_TRIANGLE_FAN 241 count:繪圖個數 242 type:類型 243 GL_BYTE 244 GL_UNSIGNED_BYTE 245 GL_SHORT 246 GL_UNSIGNED_SHORT 247 GL_INT 248 GL_UNSIGNED_INT 249 indices:繪制索引數組 250 251 */ 252 glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices); 253 254 255 256 // 12. 從渲染緩沖區顯示到屏幕 257 [self.myContext presentRenderbuffer:GL_RENDERBUFFER]; 258 } 259 260 // 旋轉 - 矩陣變換 261 - (void)configMartix { 262 263 // 1.找到myProgram中的projectionMatrix、modelViewMatrix 2個矩陣的地址。如果找到則返回地址,否則返回-1,表示沒有找到2個對象。 264 GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix"); 265 GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix"); 266 267 float width = self.frame.size.width; 268 float height = self.frame.size.height; 269 270 // 2.創建4 * 4投影矩陣 271 KSMatrix4 _projectionMatrix; 272 //(1)獲取單元矩陣 273 ksMatrixLoadIdentity(&_projectionMatrix); 274 //(2)計算縱橫比例 = 長/寬 275 float aspect = width / height; //長寬比 276 //(3)獲取透視矩陣 277 /* 278 參數1:矩陣 279 參數2:視角,度數為單位 280 參數3:縱橫比 281 參數4:近平面距離 282 參數5:遠平面距離 283 284 */ 285 ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f); //透視變換,視角30° 286 //(4)將投影矩陣傳遞到頂點着色器 287 /* 288 void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); 289 參數列表: 290 location:指要更改的uniform變量的位置 291 count:更改矩陣的個數 292 transpose:是否要轉置矩陣,並將它作為uniform變量的值。必須為GL_FALSE 293 value:執行count個元素的指針,用來更新指定uniform變量 294 */ 295 glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]); 296 297 298 // 3.創建一個4 * 4 矩陣,模型視圖矩陣 299 KSMatrix4 _modelViewMatrix; 300 //(1)獲取單元矩陣 301 ksMatrixLoadIdentity(&_modelViewMatrix); 302 //(2)平移,z軸平移-10 303 ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0); 304 //(3)創建一個4 * 4 矩陣,旋轉矩陣 305 KSMatrix4 _rotationMatrix; 306 //(4)初始化為單元矩陣 307 ksMatrixLoadIdentity(&_rotationMatrix); 308 //(5)旋轉 309 ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0); //繞X軸 310 ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0); //繞Y軸 311 ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0); //繞Z軸 312 //(6)把變換矩陣相乘.將_modelViewMatrix矩陣與_rotationMatrix矩陣相乘,結合到模型視圖 313 ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix); 314 //(7)將模型視圖矩陣傳遞到頂點着色器 315 /* 316 void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); 317 參數列表: 318 location:指要更改的uniform變量的位置 319 count:更改矩陣的個數 320 transpose:是否要轉置矩陣,並將它作為uniform變量的值。必須為GL_FALSE 321 value:執行count個元素的指針,用來更新指定uniform變量 322 */ 323 glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]); 324 } 325 326 // 加載紋理 327 - (void)loadTexture { 328 329 // 9.0 image 轉為 CGImageRef 330 CGImageRef spriteImage = [UIImage imageNamed:@"0001"].CGImage; 331 // 圖片是否獲取成功 332 if (!spriteImage) { 333 NSLog(@"Failed to load image "); 334 return; 335 } 336 // 獲取圖片寬高 337 size_t width = CGImageGetWidth(spriteImage); 338 size_t height = CGImageGetHeight(spriteImage); 339 // 獲取圖片字節數 寬*高*4(RGBA) 340 GLubyte *spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); 341 342 // 創建上下文 343 /* 344 data:指向要渲染的繪制圖像的內存地址 345 width:bitmap 的寬度,單位為像素 346 height:bitmap 的高度,單位為像素 347 bitPerComponent:內存中像素的每個組件的位數,比如 32 位 RGBA,就設置為 8 348 bytesPerRow:bitmap 的沒一行的內存所占的比特數 349 colorSpace:bitmap 上使用的顏色空間 kCGImageAlphaPremultipliedLast:RGBA 350 */ 351 CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); 352 353 // 在 CGContextRef 上 --> 將圖片繪制出來 354 /* 355 CGContextDrawImage 使用的 Core Graphics 框架,坐標系與 UIKit 不一樣。UIKit 框架的原點在屏幕的左上角,Core Graphics 框架的原點在屏幕的左下角。 356 CGContextDrawImage(CGContextRef _Nullable c, CGRect rect, CGImageRef _Nullable image) 357 c:繪圖上下文 358 rect:rect坐標 359 image:繪制的圖片 360 */ 361 CGRect rect = CGRectMake(0, 0, width, height); 362 CGContextDrawImage(spriteContext, rect, spriteImage); 363 364 365 // 翻轉圖片 方案一 366 // x、y 軸平移 367 CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y); 368 // y 平移 369 CGContextTranslateCTM(spriteContext, 0, rect.size.height); 370 // Y 軸方向 Scale -1 翻轉 371 CGContextScaleCTM(spriteContext, 1.0, -1.0); 372 // 平移回原點位置處 373 CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y); 374 // 重繪 375 CGContextDrawImage(spriteContext, rect, spriteImage); 376 377 378 // 繪完 釋放上下文 379 CGContextRelease(spriteContext); 380 381 // 9.1. 綁定紋理到默認的紋理ID 382 glBindTexture(GL_TEXTURE_2D, 0); 383 384 // 9.2. 設置紋理屬性 385 /* 386 glTexParameteri(GLenum target, GLenum pname, GLint param) 387 target:紋理維度 388 pname:線性過濾; 為s,t坐標設置模式 389 param:wrapMode; 環繞模式 390 */ 391 // 過濾方式 392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 394 // 環繞方式 395 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 396 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 397 398 // 9.3 載入紋理 399 /* 載入紋理 glTexImage2D 400 參數1:紋理維度,GL_TEXTURE_2D 401 參數2:mip貼圖層次 402 參數3:紋理單元存儲的顏色成分(從讀取像素圖中獲得) 403 參數4:加載紋理寬度 404 參數5:加載紋理的高度 405 參數6:為紋理貼圖指定一個邊界寬度 0 406 參數7、8:像素數據的數據類型, GL_UNSIGNED_BYTE無符號整型 407 參數9:指向紋理圖像數據的指針 408 */ 409 float fw = width, fh = height; 410 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); 411 412 // 9.4 釋放 sprite 413 free(spriteData); 414 } 415 416 417 418 419 // 加載着色器 420 // 頂點着色器 和 片元着色器 的代碼傳進來(.vsh .fsh) 421 -(GLuint)loadShadersWithVertex:(NSString *)vert Withfrag:(NSString *)frag { 422 423 // 1.定義 着色器 424 GLuint verShader, fragShader; 425 426 // 2.創建程序 program 427 GLint program = glCreateProgram();// 創建一個空的程序對象 428 429 // 3.編譯着色器 --> 封裝一個方法 compileShaderWithShader: 430 [self compileShaderWithShader:&verShader shaderType:GL_VERTEX_SHADER filePath:vert]; 431 [self compileShaderWithShader:&fragShader shaderType:GL_FRAGMENT_SHADER filePath:frag]; 432 433 // 4.attach shader, 將shader附着到 程序 434 glAttachShader(program, verShader); 435 glAttachShader(program, fragShader); 436 437 //5.已附着好的 shader 刪掉,避免不必要的內存占用 438 glDeleteShader(verShader); 439 glDeleteShader(fragShader); 440 441 return program;// 返回編譯好的程序 442 } 443 // 編譯着色器 444 /* 445 shader: 着色器 ID 446 type: 着色器類型 447 path: 着色器代碼文件路徑 448 */ 449 - (void)compileShaderWithShader:(GLuint *)shader shaderType:(GLenum)type filePath:(NSString *)path { 450 451 // 1.讀取文件路徑 452 NSString *file = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; 453 // NSString 轉 C 的 char 454 const GLchar *source = (GLchar *)[file UTF8String]; 455 456 // 2.創建對應類型的shader 457 *shader = glCreateShader(type); 458 459 // 3.讀取着色器源碼 將其附着到着色器對象上面 460 /* params: 461 shader: 要編譯的着色器對象 *shader 462 numOfStrings: 傳遞的源碼字符串數量 1個 463 參數3:strings: 着色器程序的源碼(真正的着色器程序源碼) 464 參數4:lenOfStrings: 長度,具有每個字符串長度的數組,或NULL,這意味着字符串是NULL終止的 465 */ 466 // glShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length) 467 glShaderSource(*shader, 1, &source,NULL); 468 469 // 4. 編譯 470 glCompileShader(*shader); 471 } 472 473 - (IBAction)rotClick:(UIButton *)sender { 474 475 bX = bY = bZ = YES; 476 477 myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(reDegree) userInfo:nil repeats:YES]; 478 } 479 480 481 // 旋轉 482 -(void)reDegree { 483 484 //如果停止X軸旋轉,X = 0則度數就停留在暫停前的度數. 485 //更新度數 486 xDegree += bX * 5; 487 yDegree += bY * 7; 488 zDegree += bZ * 9; 489 //重新渲染 490 [self renderLayer]; 491 492 } 493 494 @end
着色器代碼:
1 // 頂點着色器 2 3 attribute vec4 position; 4 attribute vec4 positionColor; 5 6 uniform mat4 projectionMatrix; 7 uniform mat4 modelViewMatrix; 8 9 varying lowp vec4 varyColor; 10 11 void main() { 12 13 varyColor = positionColor; 14 15 vec4 vPos; 16 17 //4*4 * 4*4 * 4*1 18 vPos = projectionMatrix * modelViewMatrix * position; 19 20 //ERROR 21 //vPos = position * modelViewMatrix * projectionMatrix ; 22 gl_Position = vPos; 23 }
1 // 紋理着色器 2 varying lowp vec4 varyColor; 3 void main() { 4 5 gl_FragColor = varyColor; 6 }
3.1、混合紋理
紋理加載代碼和之前Demo相同,不再贅述。
着色器代碼所需修改:
效果見下面效果動圖
三、GLKit 索引繪圖繪制旋轉三角錐 - 顏色紋理混合
效果:
代碼:
1 #import "ViewController.h" 2 3 @interface ViewController () { 4 5 dispatch_source_t timer; 6 } 7 8 @property (nonatomic, strong) EAGLContext *myContext; 9 @property (nonatomic, strong) GLKBaseEffect *myEffect; 10 11 // 旋轉的度數 12 @property(nonatomic, assign) float XDegree; 13 @property(nonatomic, assign) float YDegree; 14 @property(nonatomic, assign) float ZDegree; 15 16 @property(nonatomic, assign) int count;// 頂點個數 17 18 @end 19 20 @implementation ViewController 21 22 - (void)viewDidLoad { 23 [super viewDidLoad]; 24 // Do any additional setup after loading the view. 25 26 // 新建圖層 27 [self creatContext]; 28 29 // 渲染圖層 30 [self render]; 31 } 32 33 - (void)render { 34 35 // 頂點數據 36 // // 3頂點 3顏色 37 // GLfloat attrArr[] = { 38 // -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上 39 // 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上 40 // -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下 41 // 42 // 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下 43 // 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //頂點 44 // }; 45 46 // 3頂點 3顏色 2紋理 47 GLfloat attrArr[] = { 48 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,//左上 49 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,//右上 50 -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,//左下 51 52 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,//右下 53 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f,//頂點 54 }; 55 56 // 繪圖索引數組 57 GLuint indexes[] = { 58 0, 3, 2, 59 0, 1, 3, 60 0, 2, 4, 61 0, 4, 1, 62 2, 3, 4, 63 1, 4, 3, 64 }; 65 self.count = sizeof(indexes) / sizeof(GLuint);//sizeof(indexes[0]); 66 67 // 頂點數據copy到緩沖區 68 GLuint attBuffer; 69 glGenBuffers(1, &attBuffer); 70 glBindBuffer(GL_ARRAY_BUFFER, attBuffer); 71 glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW); 72 73 // 索引數據copy到緩沖區 74 GLuint indexesBuffer; 75 glGenBuffers(1, &indexesBuffer); 76 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexesBuffer); 77 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW); 78 79 // 傳遞使用頂點數據 80 glEnableVertexAttribArray(GLKVertexAttribPosition); 81 glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*8, NULL); 82 83 // 使用傳遞y顏色數據 84 glEnableVertexAttribArray(GLKVertexAttribColor); 85 glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*8, (GLfloat *)NULL + 3); 86 87 // 紋理 88 glEnableVertexAttribArray(GLKVertexAttribTexCoord0); 89 glVertexAttribPointer(GLKVertexAttribTexCoord0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6); 90 91 // 紋理圖片的讀取 92 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"]; 93 NSDictionary *option = @{GLKTextureLoaderOriginBottomLeft:@(YES)}; 94 GLKTextureInfo *info = [GLKTextureLoader textureWithContentsOfFile:filePath options:option error:nil]; 95 96 // 繪制 97 self.myEffect = [[GLKBaseEffect alloc] init]; 98 // 紋理 99 self.myEffect.texture2d0.enabled = YES; 100 self.myEffect.texture2d0.name = info.name; 101 102 // 投影矩陣 103 float aspect = fabs(self.view.frame.size.width/self.view.frame.size.height); 104 GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 100.f); 105 // 投影矩陣 scale 106 projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0, 1.0, 1.0); 107 self.myEffect.transform.projectionMatrix = projectionMatrix; 108 109 // 模型視圖矩陣 110 GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f); 111 self.myEffect.transform.modelviewMatrix = modelViewMatrix; 112 113 114 // GCD 定時器 - 旋轉 115 double seconds = 0.1; 116 timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); 117 dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0); 118 dispatch_source_set_event_handler(timer, ^{ 119 120 self.XDegree += 0.1f; 121 self.YDegree += 0.1f; 122 self.ZDegree += 0.1f; 123 124 }); 125 dispatch_resume(timer); 126 } 127 128 - (void)creatContext { 129 130 self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 131 132 // view 133 GLKView *kitView = (GLKView *)self.view; 134 kitView.context = self.myContext; 135 kitView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; 136 kitView.drawableDepthFormat = GLKViewDrawableDepthFormat24; 137 138 // 設置當前上下文 139 [EAGLContext setCurrentContext:self.myContext]; 140 141 // 開啟深度測試 142 glEnable(GL_DEPTH_TEST); 143 } 144 145 #pragma mark - GLKView delegate - 繪制 - 146 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { 147 148 glClearColor(0.0, 0.3, 0.3, 1); 149 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 150 151 [self.myEffect prepareToDraw]; 152 glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0); 153 154 } 155 // update - 旋轉 156 - (void)update { 157 158 GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0); 159 modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.XDegree); 160 modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.YDegree); 161 modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.ZDegree); 162 163 self.myEffect.transform.modelviewMatrix = modelViewMatrix; 164 165 } 166 167 - (IBAction)rotClick:(UIButton *)sender { 168 169 } 170 171 172 @end