OpenGL ES 2.0 Making the Hardware Work for You


顯示控制

iOS 系統(tǒng)會通過一個(gè)稱之為 Core Animation Compositor (核心動畫合成器[系統(tǒng)組件])去控制最終在屏幕顯示的圖像。

--> 核心動畫層可以同時(shí)擁有多個(gè)圖層;

--> 圖層保存了所有的繪制結(jié)果;

--> Core Animation Compositor 是由 OpenGL ES 來控制圖形處理、圖層的合成、幀緩存數(shù)據(jù)的快速交換;


Frame Buffers 和 Layers 的關(guān)系

--> pixel color render buffer,是 Frame Buffers 與 Layers 交換數(shù)據(jù)的地方(共享);

--> other render buffers,是可選的,但一個(gè) OpenGL ES 程序至少包含一個(gè);


例子:三角形

--?-> 如果用 UIKit 直接做會怎樣?

----> Try It ...
ViewController.view + UIImageView
前者,設(shè)置背景色為黑色;
后者,添加進(jìn)前者中成為子控件;
1)后者直接設(shè)置 .image 為 一張白色的圖片(自己要制作一張圖片);
2)后者不設(shè)置圖片,設(shè)置顏色為白色,再 .layer 設(shè)置貝賽爾曲線進(jìn)行剪切(要自己計(jì)算坐標(biāo),并進(jìn)行繪制);

---->

--?-> 使用 OpenGL ES 直接進(jìn)行繪制?

首先,分析圖像的組成:

  • 背景色是純黑色的;
  • 圖中有一個(gè)白色的直角三角形;
    • 因?yàn)?OpenGL ES 實(shí)際繪制的圖形是根據(jù)坐標(biāo)點(diǎn)來進(jìn)行填充的,而且三角形是由三個(gè)頂點(diǎn)連線組成的,所以 OpenGL ES 繪制的時(shí)候需要 三個(gè)坐標(biāo)點(diǎn);
      ----> 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

---->完整分析

繪制的整體過程:
【標(biāo)記 Buffers --> 綁定 Buffers --> 初始化 Buffers --> 使能 Buffers --> 計(jì)算所有點(diǎn)的偏移量 --> 繪制 Buffers --> 刪除 Buffers 】

OpenGLES_Ch2_1ViewController.h 文件


分析:

  • 因?yàn)镺penGL ES 2.0 繪制的第一步需要一個(gè)標(biāo)記,所以需要定義一個(gè) GLuint 變量作為標(biāo)記

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

  • GLKBaseEffect ,基本的效果類
GLKit

OpenGLES_Ch2_1ViewController.m 文件:


分析(viewDidload):


viewDidload

【步驟:判定當(dāng)前 View 是否是 GLKView --> 設(shè)置上下文環(huán)境(Context) --> 設(shè)置基本渲染效果(baseEffect) --> 準(zhǔn)備繪制的數(shù)據(jù)(標(biāo)記 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,
};

因?yàn)楝F(xiàn)在 OpenGL ES 已經(jīng)更新到 3.0了所以有三個(gè)選項(xiàng),因?yàn)楸疚牡睦邮?基于OpenGL ES 2.0 所以要選擇 kEAGLRenderingAPIOpenGLES2 (注意這個(gè)不能選錯(cuò));

  • 4、setCurrentContext 的定義: + (BOOL) setCurrentContext:(EAGLContext*) context;,可以監(jiān)聽返回值,設(shè)置是否成功;
設(shè)置 BaseEffect
- 1、BaseEffect  的屬性
- 2、`constantColor` 填充色(設(shè)置填充色的前提是`self.baseEffect.useConstantColor = GL_TRUE;`,開啟填充色),如果把 Green 置零
準(zhǔn)備繪制的數(shù)據(jù)
- 1、`glClearColor`,設(shè)置(view)背景色,定義 -->  `GL_API void           GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);`修改顏色值觀察變化 
填充色
背景色
- 2、`glGenBuffers`,添加標(biāo)記,定義`GL_API void  GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);`, GLsizei  `typedef int32_t  GLsizei;`

第一個(gè)參數(shù)是表明,有多少個(gè)標(biāo)記;

第二個(gè)參數(shù)是表明,標(biāo)記數(shù)是多少;

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

第一個(gè)參數(shù)是表明,要綁定的 Buffers 類型(有兩個(gè)值:GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER

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

第一個(gè)參數(shù),何種類型的 Buffers ;

第二個(gè)參數(shù),GLsizeiptr typedef intptr_t GLsizeiptr; (就是 long), 拷貝多少字節(jié)的數(shù)據(jù);

第三個(gè)參數(shù), 數(shù)據(jù)的指針;

第四個(gè)參數(shù),繪制的類型(STATIC 是表明 Buffers 的內(nèi)容是靜態(tài)的,不再改變;DYNAMIC 表明 Buffers 的內(nèi)容是頻繁更新的);

- 5、`vertices`,因?yàn)槲覀兪且L制 三角形,所以有三個(gè)坐標(biāo)點(diǎn)(頂點(diǎn)):

坐標(biāo)值
其中`GLKVector3` 定義 :

(Union,共用體)

--> 因?yàn)?OpenGL ES 的坐標(biāo)范圍為:【-1,1】,三角形在坐標(biāo)系下的展示為:
坐標(biāo)系的展示

數(shù)據(jù)的準(zhǔn)備已經(jīng)做完,那么現(xiàn)在就可以進(jìn)行圖形繪制了。

繪制的方法是,- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect 這個(gè)方法是 GLKView 的代理方法;

Dash 中查看代理方法:


只有一個(gè)代理方法,在 Controller 需要重新繪制 View 的時(shí)候都會調(diào)用這個(gè)代理方法,進(jìn)行繪制。

【繪制步驟:繪制前準(zhǔn)備 --> 擦除之前的繪制 --> 繪制最新的】

  • 繪制前準(zhǔn)備,[self.baseEffect prepareToDraw];

查看 prepareToDraw 方法:


同步繪制前所有的更改,保證現(xiàn)在要繪制的圖形就是最新的修改;

  • 擦除之前的繪制

// 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;有以下三個(gè)值選擇:

因?yàn)楝F(xiàn)在我們繪制的圖形是 2D 的而且只填充了顏色參數(shù),所以直接選擇 GL_COLOR_BUFFER_BIT 選項(xiàng)即可;

  • 繪制最新的


【使能 Buffers --> 計(jì)算所有點(diǎn)的偏移量 --> 繪制 Buffers 】

- 使能 Buffers `glEnableVertexAttribArray`,函數(shù)的定義是:

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

繪制的選項(xiàng)


因?yàn)槲覀兪且宰鴺?biāo)點(diǎn)進(jìn)行繪制的,所以選擇 GLKVertexAttribPosition

- 計(jì)算所有點(diǎn)的偏移量 `glVertexAttribPointer` , 函數(shù)定義為 `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;

參數(shù)分析:

第一個(gè)參數(shù),表明資源數(shù)據(jù)的類型;

第二個(gè)參數(shù),表明一個(gè)坐標(biāo)點(diǎn)中有多少個(gè)元素;

第三個(gè)參數(shù),表明元素的類型是什么;

第四個(gè)參數(shù),表明有沒有使用縮放;

第五個(gè)參數(shù),表明坐標(biāo)點(diǎn)有多少個(gè)字節(jié);

第六個(gè)參數(shù),表明從坐標(biāo)數(shù)據(jù)緩沖區(qū)的起始位開始;

  • 繪制三角形


    glDrawArrays 定義:GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);第一個(gè)參數(shù),表明要求 GPU 繪制一個(gè)三角形;第二個(gè)參數(shù),表明起始坐標(biāo)下標(biāo);第三個(gè)參數(shù),表明有多少個(gè)坐標(biāo)要繪制;

  • 刪除 Buffers

【步驟:保證當(dāng)前 View.context 是正在使用的 context --> 刪除 Buffers --> 停用 Context】

  • 保證 context
  • 刪除 Buffers


glDeleteBuffers 定義: GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers); 與 標(biāo)記的函數(shù)是一樣參數(shù),兩者要一一對應(yīng)起來; 最后,把 vertexBufferID 置零,表明沒有使用這個(gè)標(biāo)記;

  • 停用 context

設(shè)置當(dāng)前繪制的 context 為 nil ,表明不再進(jìn)行繪制;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容