OpenGL 11

一、索引绘图

若要绘制下图目标图形,按普通处理方式则需要一个个进行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
原文地址:https://www.cnblogs.com/zhangzhang-y/p/13428033.html