OpenGL ES 2.0 Making the Hardware Work for You


显示控制

iOS 系统会通过一个称之为 Core Animation Compositor (核心动画合成器[系统组件])去控制最终在屏幕显示的图像。

--> 核心动画层可以同时拥有多个图层;

--> 图层保存了所有的绘制结果;

--> Core Animation Compositor 是由 OpenGL ES 来控制图形处理、图层的合成、帧缓存数据的快速交换;


Frame Buffers 和 Layers 的关系

--> pixel color render buffer,是 Frame Buffers 与 Layers 交换数据的地方(共享);

--> other render buffers,是可选的,但一个 OpenGL ES 程序至少包含一个;


例子:三角形

--?-> 如果用 UIKit 直接做会怎样?

----> Try It ...
ViewController.view + UIImageView
前者,设置背景色为黑色;
后者,添加进前者中成为子控件;
1)后者直接设置 .image 为 一张白色的图片(自己要制作一张图片);
2)后者不设置图片,设置颜色为白色,再 .layer 设置贝赛尔曲线进行剪切(要自己计算坐标,并进行绘制);

---->

--?-> 使用 OpenGL ES 直接进行绘制?

首先,分析图像的组成:

  • 背景色是纯黑色的;
  • 图中有一个白色的直角三角形;
    • 因为 OpenGL ES 实际绘制的图形是根据坐标点来进行填充的,而且三角形是由三个顶点连线组成的,所以 OpenGL ES 绘制的时候需要 三个坐标点;
      ----> Just Do It ...

类的绑定:


Controller --> OpenGLES_Ch2_1ViewController

view --> GLKView

核心代码:


OpenGLES_Ch2_1ViewController.h

完整代码:

//
//  OpenGLES_Ch2_1ViewController.m
//  OpenGLES_Ch2_1
//

#import "OpenGLES_Ch2_1ViewController.h"

@implementation OpenGLES_Ch2_1ViewController

@synthesize baseEffect;

/////////////////////////////////////////////////////////////////
// This data type is used to store information for each vertex
typedef struct {
   GLKVector3  positionCoords;
}
SceneVertex;

/////////////////////////////////////////////////////////////////
// Define vertex data for a triangle to use in example
static const SceneVertex vertices[] = 
{
   {{-0.5f, -0.5f, 0.0}}, // lower left corner
   {{ 0.5f, -0.5f, 0.0}}, // lower right corner
   {{-0.5f,  0.5f, 0.0}}, // upper left corner
};


/////////////////////////////////////////////////////////////////
// Called when the view controller's view is loaded
// Perform initialization before the view is asked to draw
- (void)viewDidLoad
{
   [super viewDidLoad];
   
   // Verify the type of view created automatically by the
   // Interface Builder storyboard
   GLKView *view = (GLKView *)self.view;
   NSAssert([view isKindOfClass:[GLKView class]],
      @"View controller's view is not a GLKView");
   
   // Create an OpenGL ES 2.0 context and provide it to the
   // view
   view.context = [[EAGLContext alloc] 
      initWithAPI:kEAGLRenderingAPIOpenGLES2];
   
   // Make the new context current
   [EAGLContext setCurrentContext:view.context];
   
   // Create a base effect that provides standard OpenGL ES 2.0
   // Shading Language programs and set constants to be used for 
   // all subsequent rendering
   self.baseEffect = [[GLKBaseEffect alloc] init];
   self.baseEffect.useConstantColor = GL_TRUE;
   self.baseEffect.constantColor = GLKVector4Make(
      1.0f, // Red
      1.0f, // Green
      1.0f, // Blue
      1.0f);// Alpha
   
   // Set the background color stored in the current context 
   glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // background color
   
   // Generate, bind, and initialize contents of a buffer to be 
   // stored in GPU memory
   glGenBuffers(1,                // STEP 1
      &vertexBufferID);
   glBindBuffer(GL_ARRAY_BUFFER,  // STEP 2
      vertexBufferID); 
   glBufferData(                  // STEP 3
      GL_ARRAY_BUFFER,  // Initialize buffer contents
      sizeof(vertices), // Number of bytes to copy
      vertices,         // Address of bytes to copy
      GL_STATIC_DRAW);  // Hint: cache in GPU memory
}


/////////////////////////////////////////////////////////////////
// GLKView delegate method: Called by the view controller's view
// whenever Cocoa Touch asks the view controller's view to
// draw itself. (In this case, render into a frame buffer that
// shares memory with a Core Animation Layer)
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
   [self.baseEffect prepareToDraw];
   
   // Clear Frame Buffer (erase previous drawing)
   glClear(GL_COLOR_BUFFER_BIT);
   
   // Enable use of positions from bound vertex buffer
   glEnableVertexAttribArray(      // STEP 4
      GLKVertexAttribPosition);
      
   glVertexAttribPointer(          // STEP 5
      GLKVertexAttribPosition, 
      3,                   // three components per vertex
      GL_FLOAT,            // data is floating point
      GL_FALSE,            // no fixed point scaling
      sizeof(SceneVertex), // no gaps in data
      NULL);               // NULL tells GPU to start at 
                           // beginning of bound buffer
                                   
   // Draw triangles using the first three vertices in the 
   // currently bound vertex buffer
   glDrawArrays(GL_TRIANGLES,      // STEP 6
      0,  // Start with first vertex in currently bound buffer
      3); // Use three vertices from currently bound buffer
}


/////////////////////////////////////////////////////////////////
// Called when the view controller's view has been unloaded
// Perform clean-up that is possible when you know the view 
// controller's view won't be asked to draw again soon.
- (void)viewDidUnload
{
   [super viewDidUnload];
   
   // Make the view's context current
   GLKView *view = (GLKView *)self.view;
   [EAGLContext setCurrentContext:view.context];
    
   // Delete buffers that aren't needed when view is unloaded
   if (0 != vertexBufferID)
   {
      glDeleteBuffers (1,          // STEP 7 
                       &vertexBufferID);  
      vertexBufferID = 0;
   }
   
   // Stop using the context created in -viewDidLoad
   ((GLKView *)self.view).context = nil;
   [EAGLContext setCurrentContext:nil];
}

@end

---->完整分析

绘制的整体过程:
【标记 Buffers --> 绑定 Buffers --> 初始化 Buffers --> 使能 Buffers --> 计算所有点的偏移量 --> 绘制 Buffers --> 删除 Buffers 】

OpenGLES_Ch2_1ViewController.h 文件


分析:

  • 因为OpenGL ES 2.0 绘制的第一步需要一个标记,所以需要定义一个 GLuint 变量作为标记

GLuint 的定义:typedef uint32_t GLuint; (位于 OpenGLES/gltypes.h)

  • GLKBaseEffect ,基本的效果类
GLKit

OpenGLES_Ch2_1ViewController.m 文件:


分析(viewDidload):


viewDidload

【步骤:判定当前 View 是否是 GLKView --> 设置上下文环境(Context) --> 设置基本渲染效果(baseEffect) --> 准备绘制的数据(标记 Buffers --> 绑定 Buffers --> 初始化 Buffers ) 】

判定 View
Context
  • 1、view.context 的定义: GLKit/GLKView.h -->@property (nonatomic, retain) EAGLContext *context;

  • 2、initWithAPI:定义:OpenGLES/EAGL.h --> - (instancetype) initWithAPI:(EAGLRenderingAPI) api;

  • 3、EAGLRenderingAPI的定义:

typedef NS_ENUM(NSUInteger, EAGLRenderingAPI)
{
    kEAGLRenderingAPIOpenGLES1 = 1,
    kEAGLRenderingAPIOpenGLES2 = 2,
    kEAGLRenderingAPIOpenGLES3 = 3,
};

因为现在 OpenGL ES 已经更新到 3.0了所以有三个选项,因为本文的例子是 基于OpenGL ES 2.0 所以要选择 kEAGLRenderingAPIOpenGLES2 (注意这个不能选错);

  • 4、setCurrentContext 的定义: + (BOOL) setCurrentContext:(EAGLContext*) context;,可以监听返回值,设置是否成功;
设置 BaseEffect
- 1、BaseEffect  的属性
- 2、`constantColor` 填充色(设置填充色的前提是`self.baseEffect.useConstantColor = GL_TRUE;`,开启填充色),如果把 Green 置零
准备绘制的数据
- 1、`glClearColor`,设置(view)背景色,定义 -->  `GL_API void           GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);`修改颜色值观察变化 
填充色
背景色
- 2、`glGenBuffers`,添加标记,定义`GL_API void  GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);`, GLsizei  `typedef int32_t  GLsizei;`

第一个参数是表明,有多少个标记;

第二个参数是表明,标记数是多少;

- 3、`glBindBuffer`,添加绑定,定义`GL_API void  GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);` GLenum `typedef uint32_t GLenum;`

第一个参数是表明,要绑定的 Buffers 类型(有两个值:GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER

- 4、`glBufferData`,`定义:GL_API void   GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);`

第一个参数,何种类型的 Buffers ;

第二个参数,GLsizeiptr typedef intptr_t GLsizeiptr; (就是 long), 拷贝多少字节的数据;

第三个参数, 数据的指针;

第四个参数,绘制的类型(STATIC 是表明 Buffers 的内容是静态的,不再改变;DYNAMIC 表明 Buffers 的内容是频繁更新的);

- 5、`vertices`,因为我们是要绘制 三角形,所以有三个坐标点(顶点):

坐标值
其中`GLKVector3` 定义 :

(Union,共用体)

--> 因为 OpenGL ES 的坐标范围为:【-1,1】,三角形在坐标系下的展示为:
坐标系的展示

数据的准备已经做完,那么现在就可以进行图形绘制了。

绘制的方法是,- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect 这个方法是 GLKView 的代理方法;

Dash 中查看代理方法:


只有一个代理方法,在 Controller 需要重新绘制 View 的时候都会调用这个代理方法,进行绘制。

【绘制步骤:绘制前准备 --> 擦除之前的绘制 --> 绘制最新的】

  • 绘制前准备,[self.baseEffect prepareToDraw];

查看 prepareToDraw 方法:


同步绘制前所有的更改,保证现在要绘制的图形就是最新的修改;

  • 擦除之前的绘制

// Clear Frame Buffer (erase previous drawing) glClear(GL_COLOR_BUFFER_BIT);

glClear 的定义是:GL_API void GL_APIENTRY glClear (GLbitfield mask);

GLbitfield,定义 :typedef uint32_t GLbitfield;有以下三个值选择:

因为现在我们绘制的图形是 2D 的而且只填充了颜色参数,所以直接选择 GL_COLOR_BUFFER_BIT 选项即可;

  • 绘制最新的


【使能 Buffers --> 计算所有点的偏移量 --> 绘制 Buffers 】

- 使能 Buffers `glEnableVertexAttribArray`,函数的定义是:

GL_API void GL_APIENTRY glEnableVertexAttribArray (GLuint index) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);

绘制的选项


因为我们是以坐标点进行绘制的,所以选择 GLKVertexAttribPosition

- 计算所有点的偏移量 `glVertexAttribPointer` , 函数定义为 `GL_API void           GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);`

其中,GLint typedef int32_t GLint; ; GLboolean typedef uint8_t GLboolean; ; GLvoid typedef void GLvoid;

参数分析:

第一个参数,表明资源数据的类型;

第二个参数,表明一个坐标点中有多少个元素;

第三个参数,表明元素的类型是什么;

第四个参数,表明有没有使用缩放;

第五个参数,表明坐标点有多少个字节;

第六个参数,表明从坐标数据缓冲区的起始位开始;

  • 绘制三角形


    glDrawArrays 定义:GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);第一个参数,表明要求 GPU 绘制一个三角形;第二个参数,表明起始坐标下标;第三个参数,表明有多少个坐标要绘制;

  • 删除 Buffers

【步骤:保证当前 View.context 是正在使用的 context --> 删除 Buffers --> 停用 Context】

  • 保证 context
  • 删除 Buffers


glDeleteBuffers 定义: GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers); 与 标记的函数是一样参数,两者要一一对应起来; 最后,把 vertexBufferID 置零,表明没有使用这个标记;

  • 停用 context

设置当前绘制的 context 为 nil ,表明不再进行绘制;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容