OpenGL 三 - 001、iOS 離屏渲染 切圓角一定會觸發離屏渲染嗎?


正式開始前,我們可以先看一下下面幾段代碼:

 1 //1.按鈕存在背景圖片 ==========》 觸發了離屏渲染
 2     UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
 3     btn1.frame = CGRectMake(100, 30, 100, 100);
 4     btn1.layer.cornerRadius = 50;
 5     [self.view addSubview:btn1];
 6     
 7     [btn1 setImage:[UIImage imageNamed:@"btn.png"] forState:UIControlStateNormal];
 8     btn1.clipsToBounds = YES;
 9     
10     //2.按鈕不存在背景圖片
11     UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
12     btn2.frame = CGRectMake(100, 180, 100, 100);
13     btn2.layer.cornerRadius = 50;
14     btn2.backgroundColor = [UIColor blueColor];
15     [self.view addSubview:btn2];
16     btn2.clipsToBounds = YES;
17     
18     //3.UIImageView 設置了圖片+背景色; ==========》 觸發了離屏渲染
19     UIImageView *img1 = [[UIImageView alloc]init];
20     img1.frame = CGRectMake(100, 320, 100, 100);
21     img1.backgroundColor = [UIColor blueColor];
22     [self.view addSubview:img1];
23     img1.layer.cornerRadius = 50;
24     img1.layer.masksToBounds = YES;
25     img1.image = [UIImage imageNamed:@"btn.png"];
26     
27     //4.UIImageView 只設置了圖片,無背景色;
28     UIImageView *img2 = [[UIImageView alloc]init];
29     img2.frame = CGRectMake(100, 480, 100, 100);
30     [self.view addSubview:img2];
31     img2.layer.cornerRadius = 50;
32     img2.layer.masksToBounds = YES;
33     img2.image = [UIImage imageNamed:@"btn.png"];

     //5.UIView 多個貼在 self.view 上

       UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 100, 100)];

       view1.backgroundColor = [UIColor blackColor];

       view1.layer.cornerRadius = 50;

       view1.clipsToBounds = YES;

       [self.view addSubview:view1];

       UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 60, 60)];

       view2.backgroundColor = [UIColor whiteColor];

       view2.layer.cornerRadius = 30;

       view2.clipsToBounds = YES;

       [self.view addSubview:view2];

運行,開啟模擬器的查看離屏渲染觸發功能:可看到 1 和 3 兩段代碼觸發了離屏渲染()。他們都開了圓角,卻並沒有都觸發離屏渲染,這是為什么呢?

 

   

 一、渲染簡圖 - 普通 & 離屏

普通渲染:普通情況下,我們的APP的渲染流程是,CPU/GPU 合作,不斷的將需要渲染的內容數據存到幀緩存區(Frame Buffer),顯示則是不斷地從幀緩存區取出數據進行顯示。多個view  每個都獨立 一層一層貼 在主view上。

 離屏渲染:觸發離屏渲染時,數據不會直接存到幀緩存區,而是先放在 另外開辟了一塊緩存區空間 --> 離屏緩存區(offscreen Buffer),在不斷地將數據存到離屏緩存區,之后將幾個圖層進行合並疊加,然后通過幀緩存區,再進行顯示。一個view上多個圖層。

二、離屏渲染 

1)為什么離屏渲染呢?例子:我們要顯示一個 button --> 背景粉色、有顆球的背景圖、圓角4 -->  這些圖層是不能一個個單獨的顯示在屏幕,需要三個疊加,那么疊加處理前 就要有個地方先存放它們 --> offscreen Buffer --> 三個都處理好了,然后一起疊加、處理 --> 到幀緩存區 --> 顯示。 (這里的圖層疊加並非是一層層獨立 view 的疊加,而是它們三個在同一層layer上)

張圖:

“不能單獨的顯示在屏幕”是設么意思呢?在腦海里想象一下,你想要做幅畫,它要長成下面描述的樣子,首先一層綠色的樹背景、背景上有棵大樹干、樹根旁有只貓,最后要把這個圖裁成圓形的。我們是不是要至少畫三個元素(綠色、樹、貓)合在一起才能呈現出這幅畫,然后一剪刀將其裁成的圓。畫紙便是我們的一層 view。“一張畫紙上畫多種元素” 區別於 “每張畫紙畫一種元素多張畫紙疊加”。

你可能要說那他為什么非要觸發離屏渲染呢?離屏渲染又要消耗我們的性能,我不可以直接一層一層的 view 擺放在屏幕上嗎?當然可以,但這個的前提是你要向 UI 要張圓形的圖片嘛,我們暫不考慮這個,沒有現成的圖的情況下我們是需要自己裁的。

2)離屏渲染為什么會引起性能問題呢?

  1、要額外存儲空間,大量的離屏渲染會使內存壓力會比較大

  2、offscreen Buffer --> frame Buffer 這個過程是需要一定時間的

  3、離屏緩存區的空間是有他的大小限制的:屏幕的2.5倍(像素點)

3)離屏渲染的大量使用,會造成性能問題,可能會引起掉幀卡頓現象,那么為什么要用離屏渲染呢?

  1、不得不使用:我們所需要的的一些特殊效果特效,並不能一次性一個圖層就得到想要的結果的,必須要多個圖層一起實現,不得不。

  2、效率:特殊效果的復用。多次出現的一個動畫特效,渲染結果保存在離屏緩存區里面,用的時候直接取。

到這里,我們再考慮下為什么切圓角沒有都觸發離屏渲染呢

  圖層只有一層時(一個顏色or一張背景圖...),我們對其渲染切圓角后直接就可以將其顯示在屏幕中了,不需要有另外的圖片或者其他什么和他混在一起的效果圖,那么何必將其放在離屏緩存區消耗空間呢。

三、觸發離屏渲染的常見場景

1)系統自動觸發:

  1、裁剪layer:例:切圓角 -- view.layer.masksToBounds = YES;(等同於 view.clipsToBounds = YES; )// 觸發離屏渲染原因

  圓角效果的幾點實現:

  a、按上面代碼直接切

  b、貝塞爾曲線畫圓角

  c、找UI要切好的圖

  

  2、陰影

  3、高斯模糊

  4、帶透明度的圖層的重合: 重合部分的顏色是必須要混合計算的

蘋果毛玻璃效果(高斯模糊)的渲染流程圖:

例子:對一張圖片進行模糊處理:

  渲染內容-Render Content(存offscreen Buffer) --> 抓取捕獲圖片內容-capture content(存) --> 垂直模糊-vertical blur(存) --> 水平模糊-horizonal blur(存) --> 合成compositiong Pass(四合一) --> 顯示 

2)主動觸發:我們在復用時

  光柵化:shouldRasterize --> When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content

  當設為YES時會開啟離屏渲染。

shouldRasterize 光柵化使用建議:

  1、如果layer不能被復用,不要開啟

  2、layer不是靜態的,要時時變化頻繁修改,開啟離屏渲染反而影響效率

  3、離屏渲染緩存內容是有時間限制的,當存的內容在100ms內沒有被復用,便會被清理掉,無法復用

  4、離屏渲染空間限制,2.5倍的屏幕,超過屏幕像素大小的2.5倍后,也不能繼續復用了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM