OpenGL 九

一、OpenGL ES 初识

1、OpenGL ES 简介

OpenGL ES (OpenGL for Embedded Systems) 是以手持和嵌⼊式为⽬标的⾼级3D图形应用程序编程接⼝口(API)。OpenGL ES 是⽬前智能⼿机中占据统治地位的图形API。⽀持的平台:iOS、Andriod、 BlackBerry、bada、Linux、Windows。

OpenGL ES 允许应⽤程序利用底层图形处理器的强⼤功能。iOS 设备上的 GPU 可以执⾏复杂的2D和3D绘图,以及最终图像中每个像素的复杂着⾊计算。

苹果官方文档  OpenGL ES Design Guidelines 中 OpenGL ES 的构建流程有详细介绍。

2、主要流程点介绍

2.1)顶点着色器:

  1、着⾊器程序:描述顶点上执行操作的顶点着⾊器程序源代码/可执⾏⽂件
  2、顶点着⾊器输⼊(属性): ⽤顶点数组提供每个顶点的数据
  3、统⼀变量(uniform):顶点/⽚元着⾊器使⽤的不变数据
  4、采样器:代表顶点着⾊器使⽤纹理的特殊统一变量类型

gl_Position:内建变量 --> 顶点数据(每一个),经过处理后得到的值

顶点着⾊器业务:
  1、矩阵变换位置
  2、计算光照公式⽣成逐顶点颜色
  3、⽣成/变换纹理坐标
总结:它可以⽤于执⾏⾃定义计算、实施新的变换、照明或者传统的固定功能所不允许的基于顶点操作的效果。

2.2)图元装配

顶点着⾊器之后的下一个阶段是  图元装配。
图元(Primitive):点、线、三⻆形等。
图元装配:将顶点数据计算成⼀个个图元。在这个阶段会执⾏裁剪、透视分割和 Viewport 变换操作。
图元类型和顶点索 确定将被渲染的单独图元。对于每个单独图元及其对应的顶点,图元装配阶段执⾏的操作包括:将顶点着⾊器的输出值执⾏裁剪、透视分割、视⼝变换 后进⼊光栅化阶段。

2.3)光栅化

在这个阶段,绘制对应的图元(点/线/三⻆角形)。
光栅化就是将图元转化成⼀组⼆维⽚段 的过程。而这些转化的⽚段将由⽚元着⾊器处理。这些⼆维⽚段就是屏幕上可绘制的像素。

--> 二维:屏幕2维嘛 像素点 --> 每个像素 100个像素点 片元着色器要处理100次 --> 性能?并不会导致性能问题,因为片元着色器是在GPU处理中其实是可以真正的实现高并发,并不会出现 CPU 上出现的性能问题。

 

2.4)片元着色器(片段着⾊器)

  1、着⾊器程序:描述⽚段上执⾏操作的⽚元着⾊器程序源代码/可执⾏⽂件
  2、输⼊变量:光栅化单元⽤插值为每个⽚段⽣成的顶点着色器输出
  3、统⼀变量(uniform):顶点/⽚元着⾊器使用的不变数据
  4、采样器:代表⽚元着⾊器使⽤纹理的特殊统一变量类型

gl_FragColor:内建变量 --> 每一个像素点,经过片元着色器处理后得到的值

⽚元着⾊器业务:
  1、计算颜色
  2、获取纹理值
  3、往像素点中填充颜⾊值(纹理值/颜色值)
总结:它可以⽤于图⽚/视频/图形中每个像素的颜色填充

⽐如给视频添加滤镜,实际上就是将视频中 每一帧的 每个图⽚的像素点颜色填充进⾏修改 --> 每一帧图片 --> 每一个像素点处理 --> 新值 --> 帧缓冲区 --> 显示

2.5)逐片段操作

 

像素归属测试:确定帧缓存区中位置(Xw,Yw)的像素⽬前是不是归属于OpenGL ES所 有。例如,一个显示OpenGL ES 帧缓存区 View 被另外一个View 所遮蔽,则窗⼝系统可以确定被遮蔽的像素不属于OpenGL ES上下文,从而不全显示这些像素。⽽像素归属测试是 OpenGL ES 的一部分,它不由开发者开⼈为控制,⽽是由 OpenGL ES 内部进行。
裁剪测试:裁剪测试确定(Xw,Yw)是否 位于 作为 OpenGL ES 状态的一部分裁剪矩形范围内。如果该⽚段位于裁剪区域之外,则被抛弃。
深度测试:输⼊⽚段的深度值进行比较,确定⽚段是否拒绝测试。
混合:将新生成的⽚段颜色与保存在帧缓存的位置的颜色值组合起来。
抖动:可⽤于 最小化 因为使用有限精度在帧缓存区中保存颜色值⽽产生的 伪像。

2.6)EGL (Embedded Graphics Library )

OpenGL ES 命令需要渲染上下⽂和绘制表面才能完成图形、图像的绘制。
渲染上下文:存储相关OpenGL ES 状态。
绘制表⾯:⽤于绘制图元的表面,它指定渲染所需要的缓存区类型,例如颜⾊缓存区,深度缓冲区和模板缓存区。
OpenGL ES API 并没有提供如何创建渲染上下文或者上下⽂如何连接到原生窗⼝系统。EGL 是 Khronos 渲染API(如OpenGL ES) 和原⽣窗口系统之间的接口。唯⼀⽀持 OpenGL ES 却不⽀持 EGL 的平台是 iOS。Apple 提供了⾃己的 EGL API 用来 iOS 实现,称为 EAGL
因每个窗口系统都有不同的定义,所以 EGL 提供基本的不透明类型 --> EGLDisplay,这个类型封装了所有系统相关性⽤于和原生窗⼝系统接口。

由于 OpenGL ES 是基于 C 的 API,因此它⾮常便携且受到⼴泛⽀持。作为 C API,它与 Objective-C Cocoa Touch 应⽤程序⽆缝集成。OpenGL ES 规范没有定义窗⼝层,相 反,托管操作系统必须提供函数来创建一个接受命令的 OpenGL ES 渲染上下⽂和一个帧 缓冲区,其中写⼊任何绘图命令的结果。在iOS上使⽤ OpenGL ES 需要使⽤ iOS 类来设置 和呈现绘图表面,并使用平台中⽴的 API 来呈现其内容。

2.7)计算机对于动画的实现 

应用程序使用 OpenGL ES 执行动画显示的流程:

二、GLKit 框架 

GLKit 框架的设计⽬标是为了简化基于 OpenGL / OpenGL ES 的应⽤开发。它的出现加快了 OpenGL ES 或OpenGL 应⽤程序开发。使⽤数学库、背景纹理理加载、预先创建的着色器效果、以及标准视图GLKView和视图控制器GLKViewController来实现渲染循环。 GLKit 框架提供了功能和类,可以减少创建新的基于着⾊器的应⽤程序所需的⼯作量,或者⽀持依赖早期版本的 OpenGL ES 或 OpenGL 提供的固定函数顶点或⽚段处理的现有应⽤程序。

官方文档

 

GLKView:提供绘制场所 --> View
GLKViewController:扩展于标准的 UIKit 设计模式。⽤于绘制视图内容的管理与呈。

1、GLKit 

1)加载纹理

2)提供高性能的数学运算

3)提供常见的着色器

4)提供视图和视图控制器

GLKit 代码:

// 官方文档中代码
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Create an OpenGL ES context and assign it to the view loaded from storyboard
    GLKView *view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
 
    // Configure renderbuffers created by the view
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
 
    // Enable multisampling
    view.drawableMultisample = GLKViewDrawableMultisample4X;
}

// 必须实现的
- (void)drawRect:(CGRect)rect
{
    // Clear the framebuffer
    glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // Draw using previously configured texture, shader, uniforms, and vertex array
    glBindTexture(GL_TEXTURE_2D, _planetTexture);
    glUseProgram(_diffuseShading);
    glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
    glBindVertexArrayOES(_planetMesh);
    glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT);
}

2、案例

案例一效果(背景色+纹理):

 

案例二效果:

1)案例一 .m 代码

  1 //
  2 //  ViewController.m
  3 //  GLKit_Demo001
  4 //
  5 //  Created by Domy on 2020/7/26.
  6 //  Copyright © 2020 Domy. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 
 11 // 导入 OpenGL ES
 12 #import <OpenGLES/ES3/gl.h>
 13 #import <OpenGLES/ES3/glext.h>
 14 
 15 @interface ViewController () {
 16     // 创建上下文
 17     EAGLContext *context;
 18     // 着色器
 19     GLKBaseEffect *myEffect;
 20 }
 21 
 22 @end
 23 
 24 @implementation ViewController
 25 
 26 - (void)viewDidLoad {
 27     [super viewDidLoad];
 28     // Do any additional setup after loading the view.
 29     
 30     // 初始化
 31     [self setUpConfig];
 32     
 33     // 设置 顶点/纹理 坐标数据
 34     [self configVertex];
 35     
 36     // 设置纹理
 37     [self configTexture];
 38 }
 39 
 40 - (void)configTexture {
 41     
 42     // 1. 图片路径
 43     NSString *filePath = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"];
 44 
 45     // 2. 设置纹理参数
 46     // 纹理坐标原点是左下角,图片显示原点应该是左上角
 47     NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];// @(1):true
 48     // 纹理数据
 49     GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
 50 
 51     // 3. 使用 苹果封好的 着色器  GLKBaseEffect 包含了 顶点和片元着色器
 52     myEffect = [[GLKBaseEffect alloc] init];
 53     myEffect.texture2d0.enabled = GL_TRUE;
 54     myEffect.texture2d0.name = textureInfo.name;
 55     
 56 }
 57 
 58 - (void)configVertex {
 59     
 60     // 1. 顶点数组 数据
 61     // 顶点坐标 前3(x,yxz)    纹理坐标 后2(s,t)
 62     GLfloat vertexDataArr[] = {
 63         1.0, -0.5, 0.0f,    1.0f, 0.0f, //右下
 64         1.0, 0.5,  0.0f,    1.0f, 1.0f, //右上
 65         -1.0, 0.5, 0.0f,    0.0f, 1.0f, //左上
 66 
 67         1.0, -0.5, 0.0f,    1.0f, 0.0f, //右下
 68         -1.0, 0.5, 0.0f,    0.0f, 1.0f, //左上
 69         -1.0, -0.5, 0.0f,   0.0f, 0.0f, //左下
 70     };// --> 在内存中
 71 
 72 
 73     /*
 74     顶点数组: 开发者可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组
 75 
 76     顶点缓存区: 性能更高的做法是,提前分配一块显存,将顶点数据预先传入到显存当中。这部分的显存,就被称为顶点缓冲区
 77     */
 78     
 79     
 80     // 2. 顶点数据copy到顶点缓冲区
 81     //      2.1 创建顶点缓冲区
 82     GLuint bufferID;
 83     glGenBuffers(1, &bufferID);// 1个缓冲区  &bufferID:ID --> 顶点缓冲区存在GPU中
 84     //      2.2 绑定顶点缓冲区
 85     //      类型 GL_ARRAY_BUFFER: 存数组所以 array_buffer
 86     glBindBuffer(GL_ARRAY_BUFFER, bufferID);
 87     //      2.3 顶点数据copy到顶点缓冲区
 88     glBufferData(GL_ARRAY_BUFFER, sizeof(vertexDataArr), vertexDataArr, GL_STATIC_DRAW);
 89 
 90 
 91     // 3. 开启读取通道 -- 不开启即使数据copy到了缓冲区也不能用
 92     /*
 93       (1)在iOS中, 默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的.
 94       意味着,顶点数据在着色器端(服务端)是不可用的. 即使你已经使用glBufferData方法,将顶点数据从内存拷贝到顶点缓存区中(GPU显存中).
 95       所以, 必须由glEnableVertexAttribArray 方法打开通道.指定访问属性.才能让顶点着色器能够访问到从CPU复制到GPU的数据.
 96       注意: 数据在GPU端是否可见,即,着色器能否读取到数据,由是否启用了对应的属性决定,这就是glEnableVertexAttribArray的功能,允许顶点着色器读取GPU(服务器端)数据。
 97 
 98      (2)方法简介
 99      /// 功能: 上传顶点数据到显存的方法(设置合适的方式从buffer里面读取数据)
100      // 参数列表:
101          index, 指定要修改的顶点属性的索引值,例如: GLKVertexAttribPosition 、 GLKVertexAttribTexCoord0
102          size, 每次读取数量。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a),纹理则是2个.)
103          type, 指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
104          normalized, 指定当被访问时,固定点 数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)
105          stride, 指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0
106          ptr指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0
107      glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
108 
109     */
110     // vertexDataArr 数组中存了 顶点坐标和纹理坐标,要分别开启顶点和纹理通道
111     //      3.1 顶点数据
112     glEnableVertexAttribArray(GLKVertexAttribPosition);
113     // 从数组中读取数据:数据传给谁?顶点 GLKVertexAttribPosition -> 每次读取 3 个元素 -> 元素类型是 float,不归一化处理 -> 读取下一个数据的间隔 5  -> 从第 0 位开始读
114     glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
115     //      3.2 纹理数据
116     // GLKVertexAttribTexCoord0 GLKVertexAttribTexCoord1 GLKit只支持2个纹理
117     glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
118     // 从数组中读取数据:数据传给谁?纹理 GLKVertexAttribTexCoord0 -> 每次读取 2 个元素 -> 元素类型是 float,不归一化处理 -> 读取下一个数据的间隔 5  -> 从第 3 位开始读
119     glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
120 
121 }
122 
123 - (void)setUpConfig {
124     // 1.初始化上下文
125     context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
126     if (!context) {
127         NSLog(@"create content failed");
128     }
129     
130     // 2. 设置当前上下文
131     [EAGLContext setCurrentContext:context];
132     
133     // 3. 创建 GLKView
134     GLKView *view = (GLKView *)self.view;
135     view.context = context;
136     
137     // 颜色缓冲区 深度缓冲区
138     view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
139     view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
140     
141     // 4. 设置背景色
142     glClearColor(0, 0, 1, 1);
143 }
144 
145 // 5. 调用 drawInRect 方法
146 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
147     
148     glClear(GL_COLOR_BUFFER_BIT);// 清空背景颜色
149     
150     // 准备绘制
151     [myEffect prepareToDraw];
152     // 开始绘制
153     // mode:GL_TRIANGLES -- 图元链接方式
154     // 0: 从第 0 个顶点开始
155     // 6: 共6个顶点
156     glDrawArrays(GL_TRIANGLES, 0, 6);
157 }
158 
159 
160 @end

2)案例二 .m 代码

  1 //
  2 //  ViewController.m
  3 //  GLKit_Demo001
  4 //
  5 //  Created by Domy on 2020/7/26.
  6 //  Copyright © 2020 Domy. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 
 11 // 导入 OpenGL ES
 12 #import <OpenGLES/ES3/gl.h>
 13 #import <OpenGLES/ES3/glext.h>
 14 
 15 @interface ViewController () {
 16     // 创建上下文
 17     EAGLContext *context;
 18     // 着色器
 19     GLKBaseEffect *myEffect;
 20     
 21     // 立方体旋转
 22     int rotation;
 23     GLvoid *vertexData;
 24 }
 25 
 26 @end
 27 
 28 @implementation ViewController
 29 
 30 - (void)viewDidLoad {
 31     [super viewDidLoad];
 32     // Do any additional setup after loading the view.
 33     
 34     // 初始化
 35     [self setUpConfig];
 36     // 顶点/纹理 坐标
 37     [self configVertex];
 38     // 设置纹理
 39     [self configTexture];
 40 }
 41 
 42 // 纹理
 43 - (void)configTexture {
 44     
 45     // 1. 图片路径
 46     NSString *filePath = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"];
 47 
 48     // 2. 设置纹理参数
 49     NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(YES),GLKTextureLoaderOriginBottomLeft, nil];
 50     // 纹理数据
 51     GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
 52 
 53     // 3. 着色器  GLKBaseEffect 包含了 顶点和片元着色器
 54     myEffect = [[GLKBaseEffect alloc] init];
 55     myEffect.texture2d0.enabled = GL_TRUE;
 56     myEffect.texture2d0.name = textureInfo.name;
 57     
 58     
 59     // 4. 投影矩阵
 60     CGFloat aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
 61     GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.01, 100.0);
 62     myEffect.transform.projectionMatrix = projectionMatrix;// 设置投影矩阵
 63 }
 64 
 65 // xy 平面上的2个面
 66 - (void)configVertex {
 67     
 68     // 1.
 69     GLfloat vertexDataArr[] = {
 70         //
 71         0.25, -0.25, 0.0f,    1.0f, 0.0f, //右下
 72         0.25, 0.25,  0.0f,    1.0f, 1.0f, //右上
 73         -0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
 74 
 75         0.25, -0.25, 0.0f,    1.0f, 0.0f, //右下
 76         -0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
 77         -0.25, -0.25, 0.0f,   0.0f, 0.0f, //左下
 78 
 79         //
 80         0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
 81         0.25, 0.25,  0.5f,    1.0f, 1.0f, //右上
 82         -0.25, 0.25, 0.5f,    0.0f, 1.0f, //左上
 83 
 84         0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
 85         -0.25, 0.25, 0.5f,    0.0f, 1.0f, //左上
 86         -0.25, -0.25, 0.5f,   0.0f, 0.0f, //左下
 87 
 88         //
 89         0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
 90         0.25, 0.25, 0.5f,    1.0f, 1.0f, //右上
 91         0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
 92 
 93         0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
 94         0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
 95         0.25, -0.25, 0.0f,   0.0f, 0.0f, //左下
 96 
 97         //
 98         -0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
 99         -0.25, 0.25, 0.5f,    1.0f, 1.0f, //右上
100         -0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
101 
102         -0.25, -0.25, 0.5f,    1.0f, 0.0f, //右下
103         -0.25, 0.25, 0.0f,    0.0f, 1.0f, //左上
104         -0.25, -0.25, 0.0f,   0.0f, 0.0f, //左下
105 
106         //
107         0.25, 0.25, 0.0f,    1.0f, 0.0f, //右下
108         0.25, 0.25, 0.5f,    1.0f, 1.0f, //右上
109         -0.25, 0.25, 0.5f,    0.0f, 1.0f, //左上
110 
111         0.25, 0.25, 0.0f,    1.0f, 0.0f, //右下
112         -0.25, 0.25, 0.5f,    0.0f, 1.0f, //左上
113         -0.25, 0.25, 0.0f,   0.0f, 0.0f, //左下
114 
115         //
116         0.25, -0.25, 0.0f,    1.0f, 0.0f, //右下
117         0.25, -0.25, 0.5f,    1.0f, 1.0f, //右上
118         -0.25, -0.25, 0.5f,    0.0f, 1.0f, //左上
119 
120         0.25, -0.25, 0.0f,    1.0f, 0.0f, //右下
121         -0.25, -0.25, 0.5f,    0.0f, 1.0f, //左上
122         -0.25, -0.25, 0.0f,   0.0f, 0.0f, //左下
123         
124     };
125 
126     // 2. 顶点数据copy到顶点缓冲区
127     //      2.1 创建顶点缓冲区
128     GLuint bufferID;
129     glGenBuffers(1, &bufferID);// 1个缓冲区  &bufferID:ID --> 顶点缓冲区存在GPU中
130     //      2.2 绑定顶点缓冲区
131     glBindBuffer(GL_ARRAY_BUFFER, bufferID);
132     //      2.3 顶点数据copy到顶点缓冲区
133     glBufferData(GL_ARRAY_BUFFER, sizeof(vertexDataArr), vertexDataArr, GL_STATIC_DRAW);
134     //      3.1 顶点数据
135     glEnableVertexAttribArray(GLKVertexAttribPosition);
136     // 从数组中读取数据:数据传给谁?顶点 GLKVertexAttribPosition -> 每次读取 3 个元素 -> 元素类型是 float,不归一化处理 -> 读取下一个数据的间隔 5  -> 从第 0 位开始读
137     glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
138     //      3.2 纹理数据
139     glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
140     glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
141 
142 }
143 
144 - (void)setUpConfig {
145     
146 //    147 //
148     ///
149     
150     // 1.初始化上下文
151     context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
152     if (!context) {
153         NSLog(@"create context failed");
154     }
155     
156     // 2. 设置当前上下文
157     [EAGLContext setCurrentContext:context];
158     
159     // 3. 创建 GLKView
160     GLKView *view = (GLKView *)self.view;
161     view.context = context;
162     
163     // 颜色缓冲区 深度缓冲区
164     view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
165     view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
166     
167     // 4. 设置背景色
168     glClearColor(0.7, 0.7, 0.7, 1);
169 }
170 
171 // 旋转
172 - (void)update {
173     // Set up transform matrices for the rotating planet
174    
175     // Z轴上向里移动 3
176     GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -3.0);
177     
178     // 旋转度数
179     rotation = (rotation + 2) % 360;
180     // 参数: 矩阵  弧度  x  y  z
181     modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, GLKMathDegreesToRadians(rotation), 0.5, 0.5, 0.5);
182     
183     // set 模型视图矩阵
184     myEffect.transform.modelviewMatrix = modelviewMatrix;
185 }
186 
187 - (void)drawCovers {
188     
189     [self update];
190     // 准备绘制
191     [myEffect prepareToDraw];
192     // 开始绘制
193     glDrawArrays(GL_TRIANGLES, 0, 36);
194 }
195 
196 // 5. 调用 drawInRect 方法
197 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
198     
199     // 开启深度测试
200     glEnable(GL_DEPTH_TEST);
201     
202     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清空 颜色 深度缓冲
203 
204     [self drawCovers];// 绘制面
205 }
206 
207 
208 @end
原文地址:https://www.cnblogs.com/zhangzhang-y/p/13379587.html