iOS 系統(tǒng)會(huì)通過一個(gè)稱之為 Core Animation Compositor (核心動(dòng)畫合成器[系統(tǒng)組件])去控制最終在屏幕顯示的圖像递递。
--> 核心動(dòng)畫層可以同時(shí)擁有多個(gè)圖層迁匠;
--> 圖層保存了所有的繪制結(jié)果年扩;
--> Core Animation Compositor 是由 OpenGL ES 來(lái)控制圖形處理、圖層的合成魂爪、幀緩存數(shù)據(jù)的快速交換擅耽;
--> pixel color render buffer司恳,是 Frame Buffers 與 Layers 交換數(shù)據(jù)的地方(共享);
--> other render buffers俩功,是可選的幻枉,但一個(gè) OpenGL ES 程序至少包含一個(gè);
--诡蜓?-> 如果用 UIKit 直接做會(huì)怎樣熬甫?
----> 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)來(lái)進(jìn)行填充的正歼,而且三角形是由三個(gè)頂點(diǎn)連線組成的,所以 OpenGL ES 繪制的時(shí)候需要 三個(gè)坐標(biāo)點(diǎn)拷橘;
----> Just Do It ...
- 因?yàn)?OpenGL ES 實(shí)際繪制的圖形是根據(jù)坐標(biāo)點(diǎn)來(lái)進(jìn)行填充的正歼,而且三角形是由三個(gè)頂點(diǎn)連線組成的,所以 OpenGL ES 繪制的時(shí)候需要 三個(gè)坐標(biāo)點(diǎn)拷橘;
類的綁定:
核心代碼:
完整代碼:
//
// 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 ,基本的效果類
OpenGLES_Ch2_1ViewController.m 文件:
分析(viewDidload):
【步驟:判定當(dāng)前 View 是否是 GLKView --> 設(shè)置上下文環(huán)境(Context) --> 設(shè)置基本渲染效果(baseEffect) --> 準(zhǔn)備繪制的數(shù)據(jù)(標(biāo)記 Buffers --> 綁定 Buffers --> 初始化 Buffers ) 】
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è)置是否成功四敞;
- 1泛源、BaseEffect 的屬性
- 2、`constantColor` 填充色(設(shè)置填充色的前提是`self.baseEffect.useConstantColor = GL_TRUE;`忿危,開啟填充色)达箍,如果把 Green 置零
- 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)):
其中`GLKVector3` 定義 :
(Union,共用體)
--> 因?yàn)?OpenGL ES 的坐標(biāo)范圍為:【-1,1】,三角形在坐標(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í)候都會(huì)調(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ù),兩者要一一對(duì)應(yīng)起來(lái)寒随; 最后糠悯,把 vertexBufferID
置零,表明沒有使用這個(gè)標(biāo)記妻往;
- 停用 context
設(shè)置當(dāng)前繪制的 context 為 nil 互艾,表明不再進(jìn)行繪制;