一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

iOS圖形繪制框架 ——UIBezierPath 、Core Graphics 和OpenGL

 xiaotianyueye 2018-06-15

引子


PD:我們需要的界面大概是這樣子的,可以實(shí)現(xiàn)嗎?



技術(shù):ok,這個(gè)界面很簡單,我們用基本的view就可以實(shí)現(xiàn)。

數(shù)日后

UED:我們的設(shè)計(jì)是這樣子的



技術(shù):呃,晴天霹靂啊,為什么搞的這么復(fù)雜,又要弧度,又要曲線?為什么不能用標(biāo)準(zhǔn)的框架來


UED:這就是藝術(shù),激烈而又平滑的過渡才能彰顯她旺盛的生命力,而明暗錯(cuò)落的顏色賦予了她燃燒不盡的激情,仿佛一個(gè)少女,身材高挑、烈焰紅唇......


技術(shù):就不能少搞些奇技淫巧嗎,我已經(jīng)連吐槽的力氣都沒有了...


相信每個(gè)前端開發(fā)都有過這樣的經(jīng)歷,我們認(rèn)為可以用通用視圖解決的需求,視覺非要加上點(diǎn)特殊的元素,不規(guī)則圖形、不均勻顏色。做為一個(gè)有追求的Coder雖然嘴上說著不要,但身體卻很誠實(shí)的去查資料。google一下iOS 繪圖,各種繪圖的技術(shù)簡介和demo就搜出來了,隨之而來的是各種意思好像都差不多,好像不是一回事的名詞:UIBezierPath 、Quartz、Quartz 2D 、QuartzCore、Core Graphic、OpenGL 、OpenGL ES......


此時(shí)的我是這樣子的



完全搞不懂到底在哪種場景下應(yīng)該使用哪種技術(shù),有木有。本文的目的就是梳理在iOS平臺(tái)中供開發(fā)人員使用的繪圖框架以及他們之間的恩怨糾葛,以便選擇最合適的技術(shù)框架完成需求。


iOS、MacOS系統(tǒng)圖形架構(gòu)



由此圖可見:


  • iOS提供了兩套繪圖框架,分別是UIBezierPath和Core Graphics。UIBezierPath屬于UIKit。UIBezierPath是對Core Graphics框架的進(jìn)一步封裝。

  • OpenGL和Core Graphics都是繪圖專用的API類族,調(diào)用圖形處理器(GPU)進(jìn)行圖形的繪制和渲染。在架構(gòu)上是平級(jí)的,相比UIkit更接近底層。


UIBezierPath


用于創(chuàng)建基于矢量的路徑,如圓形、橢圓形和矩形,或者由多個(gè)直線和曲線組成的形狀。繪圖步驟也非常的簡單:


  1. 重寫drawRect方法

  2. 創(chuàng)建UIBezierPath對象

  3. 設(shè)置繪圖屬性,lineWidth

  4. 渲染


UIBezierPath繪制圖形代碼

//繪制圓形

- (void)drawRect:(CGRect)rect{
   UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];
   
   //設(shè)置繪圖屬性
   path.lineWidth = 1;
   UIColor *color = [UIColor readColor];
   [color set];
 
   //按照路徑繪制圖形
   [path stroke];
}


Quartz


在介紹 Core Graphics 之前,我們先把 Quartz 的概念理順清楚。嫌啰嗦可以直接拉到下面看結(jié)論


簡單來說:

  1. Quartz由Quartz Compositor和Quartz 2D兩部分組成

  2. Core Graphics是基于Quartz框架的2D繪圖引擎。所以很多資料將Core Graphics稱為Quartz是不準(zhǔn)確的。

  3. Core Graphics同Quartz 2D是等價(jià)的。


那么Quartz同OpenGL是什么關(guān)系呢?他的底層是否通過OpenGL調(diào)用GPU?


結(jié)論


  1. CoreGraphics是基于Quartz框架的繪圖引擎,同Quartz 2D是等價(jià)的。

  2. Quartz Extreme是針對Quartz底層的GPU加速。

  3. Quartz僅使用OpenGL的命令集,直接連接AGP(圖形加速接口)

  4. Quartz在CPU上執(zhí)行繪圖命令,在GPU上最終合成成圖形

  5. QuartzGL是Quartz 2D API的GPU加速。啟用QuartzGL后,所有Quartz繪圖命令都將轉(zhuǎn)換為OpenGL命令并在GPU上執(zhí)行。這個(gè)模式默認(rèn)是關(guān)閉的

  6. Quartz在進(jìn)行3D圖形渲染時(shí)是基于OpenGL的,通過OpenGL連接AGP


Core Graphics


Core Graphics是基于Quartz框架的高保真輸出2D圖形的渲染引擎??商幚砘诼窂降睦L圖、抗鋸齒渲染、漸變、圖像、顏色管理、PDF文檔等。 Core Graphics提供了一套2D繪圖功能的C語言API,使用C結(jié)構(gòu)體和C的函數(shù)模擬了一套面向?qū)ο蟮木幊虣C(jī)制。Core Graphics中沒有OC的對象和方法。


無論圖片、PDF還是視圖的圖層,都是由CoreGraphics框架完成繪制的。UIImage、UIBezierPath和NSString都提供了至少一種用于在drawRect:中繪圖的方法,實(shí)現(xiàn)原理是將Core Graphics代碼封裝在其中,降低繪圖難度。


Context


CoreGraphics中最重要的對象是graphics context,既圖形上下文。context是CGContextRef的對象,負(fù)責(zé)存儲(chǔ)繪畫狀態(tài)和繪制內(nèi)存所處的內(nèi)存空間。


我以前一直無法很好的理解Context,后來接觸Android繪圖的時(shí)候發(fā)現(xiàn)Android沒有這個(gè)東西。Android的2D圖形繪制通過Canvas和Paint實(shí)現(xiàn)的。Android的繪圖框架理解起來就非常的容易,你想畫圖首先你要有畫的地方Canvas,其次你要有筆Paint。而在iOS中Context就是要畫圖的畫板和畫筆。


Core Graphics繪制圖形代碼

//繪制圓形
- (void)drawInContext:(CGContextRef)ctx
{
   //保存當(dāng)前的繪圖Context
   CGContextSaveGState(ctx);
   CGRect rectAngle = CGRectMake(0, 0, 100, 100);
   //添加一個(gè)橢圓路徑
   CGContextAddEllipseInRect(ctx, rectAngle);
   //設(shè)置邊框?qū)挾?/span>
   CGContextSetLineWidth(ctx, self.ellipseBorderWidth);
   //設(shè)置邊框顏色
   CGContextSetStrokeColorWithColor(ctx, self.ellipseBorderColor.CGColor);
   CGContextStrokePath(ctx);
   //設(shè)置填充色
   CGContextSetFillColorWithColor(ctx, self.ellipseFillColor.CGColor);
   CGContextFillEllipseInRect(ctx, rectAngle);
   
   CGContextRestoreGState(ctx);
}


Core Graphics的Ref后綴類型


帶有Ref后綴的類型是CoreGraphics中用來模擬面向?qū)ο髾C(jī)制的C結(jié)構(gòu)。CoreGraphics對象是在上分配內(nèi)存,因此創(chuàng)建CoreGraphics對象時(shí),會(huì)返回一個(gè)指向?qū)ο髢?nèi)存地址的指針。


使用這種分配方式的C結(jié)構(gòu)都有一個(gè)用來表示結(jié)構(gòu)指針的類型定義(type definition)。例如,CGColor結(jié)構(gòu),不會(huì)被直接使用的類型,有一個(gè)表示Color * 的類型定義—CGColorRef,用來被使用的類型。使用這種類型定義是為了區(qū)分指針變量,方便開發(fā)者判斷指針變量是指向C結(jié)構(gòu)還是可以接收消息的Objective-C對象。


CGRect和CGPoint這種比較簡單直接在棧上分配的結(jié)構(gòu)體,不需要使用結(jié)構(gòu)指針,因此類型名稱后不帶Ref后綴。


帶有Ref后綴的類型的對象可能是強(qiáng)引用指針,成為指向?qū)ο蟮膿碛姓摺RC是無法識(shí)別Core對象的所有權(quán),必須在使用后手動(dòng)釋放。規(guī)則是,如果使用名稱中帶有create或者copy的函數(shù)創(chuàng)建了一個(gè)CoreGraphics對象,就必須調(diào)用Release函數(shù)并傳入該對象的指針。


Core Graphics 能完成的工作


  • 繪制圖形 : 線條、三角形、矩形、圓、圓弧弧等

  • 繪制文字

  • 繪制生成圖片(圖像)

  • 讀取生成PDF

  • 繪制漸變


Core Graphics相比UIBezierPath在使用上更復(fù)雜一些,但是支持的效果也更多,程序運(yùn)行效率更高。所以現(xiàn)在iOS系統(tǒng)上繪圖需求基本上都使用Core Graphis來完成。


OpenGL && OpenGL ES


OpenGL ES 是OpenGL 三維圖形API的子集,針對嵌入式操作系統(tǒng)設(shè)計(jì)。iOS和Android都在系統(tǒng)內(nèi)集成了OpenGL ES。所以針對OpenGL ES 的代碼可以實(shí)現(xiàn)跨平臺(tái),大多數(shù)游戲框架都基于OpenGL。


OpenGL編程流程


1、編寫shader腳本

  • 編寫vertex shader

  • 編寫fragment shader


2、創(chuàng)建shader實(shí)例

  • 創(chuàng)建 shader

  • 裝載 shader

  • 編譯 shader


3、創(chuàng)建program實(shí)例

  • 創(chuàng)建program

  • 裝配shader

  • 鏈接program

  • 使用program


裝載OpenGL shader 、創(chuàng)建OpenGL program示例代碼

- (void)setupProgram
{
   NSString *vertexShaderPath  = [[NSBundle mainBundle] pathForResource:@'VertexShader' ofType:@'glsl'];
   NSString *fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@'FragmentShader' ofType:@'glsl'];
   
   GLuint vertexShader = [GLESUtils loadShader:GL_VERTEX_SHADER withFilepath:vertexShaderPath];
   GLuint fragmentShader = [GLESUtils loadShader:GL_FRAGMENT_SHADER withFilepath:fragmentShaderPath];
   
   //Create program,attach shaders
   _programHandle = glCreateProgram();
   
   if (!_programHandle)
   {
       NSLog(@'Failed to create program');
       return;
   }
   
   glAttachShader(_programHandle, vertexShader);
   glAttachShader(_programHandle, fragmentShader);
   
   glLinkProgram(_programHandle);
   
   GLint linked;
   glGetProgramiv(_programHandle, GL_LINK_STATUS, &linked);
   
   if (!linked)
   {
       GLint infoLen = 0;
       glGetProgramiv(_programHandle, GL_INFO_LOG_LENGTH, &infoLen);
       
       if (infoLen > 1)
       {
           char *infoLog = malloc(sizeof(char) *infoLen);
           glGetProgramInfoLog(_programHandle, infoLen, NULL, infoLog);
           free(infoLog);
       }
       
       glDeleteProgram(_programHandle);
       _programHandle = 0;
       return;
   }
  
   glUseProgram(_programHandle);
   _positionSlot = glGetAttribLocation(_programHandle, 'vPosition');
   
}


iOS系統(tǒng)使用OpenGL編程流程


1、設(shè)置CAEAGLLayer

CAEAGLLayer是iOS中用于呈現(xiàn)OpenGL ES的渲染內(nèi)容的


2、設(shè)置EAGLContext

OpenGL ES 渲染上下文。這個(gè)context管理所有使用OpenGL ES 進(jìn)行描繪的狀態(tài),命令以及資源信息。


3、創(chuàng)建Renderbuffer

緩沖區(qū)用于存儲(chǔ)繪圖數(shù)據(jù),Render Buffer有三種類型,分別是color、depth、stencil buffer


4、創(chuàng)建Framebuffer object

Framebuffer object是buffer的管理者,color、depth、stencil可以添加到一個(gè)Framebuffer object上


5、銷毀Renderbuffer和Framebuffer

當(dāng)UIView變化后,layer的寬高也隨之變化,導(dǎo)致原來的renderbuffer 不再相符,需要銷毀既有 renderbuffer 和 framebuffer


iOS系統(tǒng)調(diào)用OpenGL示例代碼

//在iOS設(shè)備中通過CAEAGLLayer使用OpenGL接口渲染內(nèi)容
+ (Class)layerClass
{
   return [CAEAGLLayer class];
}

//設(shè)置呈現(xiàn)圖層
- (void)setupLayer
{
   _eaglLayer = (CAEAGLLayer *)self.layer;
   _eaglLayer.opaque = YES;
   _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
                                    kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat ,nil];
}

//設(shè)置圖形上下文
- (void)setupContext
{
   EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
   _context = [[EAGLContext alloc] initWithAPI:api];
   
   if (!_context)
   {
       NSLog(@'Failed to initialize');
       exit(1);
   }
 
   if (![EAGLContext setCurrentContext:_context])
   {
       exit(1);
   }
}

//設(shè)置渲染緩沖區(qū)
- (void)setupRenderBuffer
{
   glGenRenderbuffers(1, &_colorRenderBuffer);
   glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
   [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

//設(shè)置FrameBuffer
- (void)setupFrameBuffer
{
   glGenFramebuffers(1, &_frameBuffer);
   glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
   glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
}

- (void)destoryRenderAndFrameBuffer
{
   glDeleteFramebuffers(1 , &_frameBuffer);
   _frameBuffer = 0;
   glDeleteRenderbuffers(1, &_colorRenderBuffer);
   _colorRenderBuffer = 0;
}


示例代碼地址:

http://gitlab./xunfeng.zy/opengl/blob/master/OpenGLDemo/


結(jié)論


UIBezierPath的優(yōu)勢是方便,能用最少的代碼得要想要的圖形,并且不需要管理圖形上下文、緩沖區(qū)等容易出問題的地方,只需要關(guān)注圖形本身就行了。最主要的缺點(diǎn)是支持的效果有限,當(dāng)需要實(shí)現(xiàn)一些復(fù)雜圖形、復(fù)雜漸變效果的時(shí)候就無能為力了。所以如果只是一個(gè)簡單的圖形沒有特別的要求,可以用UIBezierPath實(shí)現(xiàn)。


Core Graphics的功能就比UIBezierPath強(qiáng)大很多,使用起來也更復(fù)雜,而且需要自己管理圖形上下文,需要投入更多的開發(fā)工作量。在效率和可做更多工作這兩個(gè)方面上Core Graphics全面壓制UIBezierPath,所以如果是復(fù)雜的圖形、多個(gè)圖形疊加、多種顏色漸變等需求可以使用Core Graphics實(shí)現(xiàn)。


OpenGL ES是直接操作GPU繪圖,而Core Graphics框架是先把命令輸入到CPU再調(diào)用GPU繪圖。很明顯OpenGL ES繪圖的效率更高,使用OpenGL ES繪圖也可以實(shí)現(xiàn)跨平臺(tái),而Core Graphics只能在iOS系統(tǒng)中使用。相比Core Graphics只支持2D繪圖,OpenGL ES對2D\3D都有很好的支持。


可見OpenGL ES是全方面的碾壓Core Graphics,但是除了特別大的圖片運(yùn)算需求外,我們很少使用OpenGL ES。其實(shí)上面的示例代碼已經(jīng)很好的說明了,繪制同一個(gè)圖形UIBezierPath需要5行代碼,Core Graphics需要10行代碼,雖然Core Graphics明顯比UIBezierPath工作量大,但還是同一個(gè)數(shù)量級(jí)的。


而使用OpenGL ES繪制,算上Vertex Shader和Fragment Shader繪制一個(gè)圖形要300~400行代碼。整整增加了兩個(gè)數(shù)量級(jí)。再加上調(diào)試、debug的工作量,就算有跨平臺(tái)的加成也無法抵消增加的時(shí)間成本。想使用OpenGL進(jìn)行繪圖,基本上都需要二次封裝,這也是為什么我們在繪圖的時(shí)候一般首選Core Graphics。


作者:darcy87

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多

    欧美成人一区二区三区在线| 好吊色欧美一区二区三区顽频| 久久天堂夜夜一本婷婷| 日本91在线观看视频| 国产免费黄片一区二区| 日本精品中文字幕人妻| 欧美日韩国内一区二区| 91在线播放在线播放观看| 欧美午夜色视频国产精品| 国产又色又粗又黄又爽| 日本三区不卡高清更新二区| 国产在线一区二区免费| 国产激情国产精品久久源| 久久人妻人人澡人人妻| 午夜福利92在线观看| 亚洲一区二区久久观看| 亚洲精品国产主播一区| 亚洲欧洲在线一区二区三区| 人妻少妇系列中文字幕| 亚洲国产香蕉视频在线观看| 亚洲最大福利在线观看| 色偷偷偷拍视频在线观看| 欧美精品久久男人的天堂| 久久综合日韩精品免费观看| 少妇淫真视频一区二区| 午夜免费精品视频在线看| 亚洲精品中文字幕无限乱码| 欧美一区二区三区五月婷婷| 好吊日成人免费视频公开| 九九九热视频最新在线| 亚洲黑人精品一区二区欧美| 久久精品少妇内射毛片| 欧美大胆美女a级视频| 亚洲欧美精品伊人久久| 91麻豆精品欧美视频| 国产农村妇女成人精品| 中文文精品字幕一区二区| 国产亚洲成av人在线观看| 国产精品久久女同磨豆腐| 精品精品国产欧美在线| 日韩欧美黄色一级视频|