什麼是Layers?
Layer,中文譯成圖層,在Direct2D中可以用來完成一些特殊效果,使用Layer的時候,先將Layer Push到render target,然後進行繪製,此時是直接繪製在Layer上的,繪製完畢後,將Layer Pop出來,剛剛繪製在Layer上的內容就會組合到render target上。在Direct2D中,Layer使用介面ID2D1Layer來表示。
和畫刷一樣,Layer由render target建立,屬於裝置相關的資源,Layer可以用於任何render target上,只要二者在相同的資源範圍內,在同一時間內,Layer只能用於一個render target。
儘管Layer為建立特效提供了強大的支援人員,但是過度使用Layer將導致D2D程式效能下降,因為操作Layer是比較耗時的,比如清除Layer上的內容,將Layer上繪製的內容混合到render target上都需要時間。
使用Layer的步驟
在Direct2D中,使用Layer的步驟非常簡單,首先建立一個Layer,在建立的時候,會指定一系列Layer的屬性,在繪製之前,先將Layer Push到當前的render target上,然後進行繪製操作,繪製完畢後將Layer Pop出來即可。
建立Layer
建立Layer使用CreateLayer函數,該函數定義如下:
virtual HRESULT CreateLayer( [in, optional] D2D1_SIZE_F *size, [out] ID2D1Layer **layer) = 0;
參數說明:
size,這是一個矩形地區,定義了建立的Layer的大小(像素尺寸),通常這個值設定為NULL,當調用PushLayer函數時,會自動為Layer分配最小的所需尺寸(通常是render target的尺寸)。
layer,這是一個ID2D1Layer**類型的變數,用來接收建立好的Layer。
建立Layer代碼如下。
ID2D1Layer* g_pLayer = NULL ;// Create layerhr = g_pRenderTarget->CreateLayer(NULL, &g_pLayer) ;if (FAILED(hr)){ MessageBox(hWnd, "Create layer failed!", "Error", 0) ; return ;}Push Layer
在BeginDraw函數調用完之後,並且在具體繪製開始之前,將Layer Push到render target。
PushLayer函數定義如下:
void PushLayer( const D2D1_LAYER_PARAMETERS &layerParameters, [in] ID2D1Layer *layer);
參數說明:
layerParameters,這是一個D2D1_LAYER_PARAMETERS類型的變數,它可以指定一系列Layer屬性,D2D1_LAYER_PARAMETERS結構體定義如下:
struct D2D1_LAYER_PARAMETERS { D2D1_RECT_F contentBounds; ID2D1Geometry *geometricMask; D2D1_ANTIALIAS_MODE maskAntialiasMode; D2D1_MATRIX_3X2_F maskTransform; FLOAT opacity; ID2D1Brush *opacityBrush; D2D1_LAYER_OPTIONS layerOptions;};
參數說明
- contentBounds,這是一個矩形地區,指定了Layer的繪製範圍,也就是說在該範圍之外的內容都不會被繪製。
- geometricMask,這是一個幾何圖形,它指定了Layer的哪一部分被顯示,比如你可以設定一Path Geometry,然後繪製一個位元影像,這樣,只有PathGeometry內部的位元影像會顯示,相當於給幾何圖形加上了位元影像紋理。
- maskAntialiasMode,這個暫時用不到,不理它。
- maskTransform,這是一個變換矩陣,指定了施加在第二個參數上的幾何變換。
- opacity,這是一個透明值,指定了Layer與render target混合時使用的透明值。
- opacityBrush,這是一個畫刷,用來改變Layer的透明值。
- layerOptions,一個D2D1_LAYER_OPTIONS變數,基本用不到,從windows 8開始,使用D2D1_LAYER_OPTIONS1來代替。
Direct2D提供了一個函數LayerParameters來初始化上面這些參數,這個函數為上面每個參數都提供了一個預設值,如下:
D2D1_LAYER_PARAMETERS LayerParameters( _In_ const D2D1_RECT_F &contentBounds = D2D1::InfiniteRect(), _In_opt_ ID2D1Geometry *geometricMask = NULL, D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1_MATRIX_3X2_F maskTransform = D2D1::IdentityMatrix(), FLOAT opacity = 1.0, ID2D1Brush *opacityBrush = NULL, D2D1_LAYER_OPTIONS layerOptions = D2D1_LAYER_OPTIONS_NONE);
在這裡,我們使用這個函數建立一個Layer,在隨後的介紹中,會指定某些特定的參數來達到特殊的效果。
g_pRenderTarget->PushLayer( D2D1::LayerParameters(), g_pLayer) ;
繪製
這裡可以繪製任意內容,幾何圖形,文本,圖片等,為了示範Layer的特殊效果,這裡通常繪製位元影像。
Pop Layer
繪製完畢後,將Layer Pop出來,這樣已經在Layer上繪製的內容就會與render target上的內容混合。
Demo
下面幾個Demo都是通過位元影像來示範的,原始的位元影像如下,三個可愛的企鵝。
限定位元影像繪製地區
在PushLayer的時候指定一個矩形地區,在這個地區內的圖形將被顯示,而這個地區外的圖形都將被屏蔽掉,為了方便查看結果,這裡繪製一個位元影像,可以清楚的看到位元影像的那一部分被繪製了。
代碼
g_pRenderTarget->BeginDraw() ;g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));g_pRenderTarget->PushLayer( D2D1::LayerParameters(D2D1::RectF(100, 100, 400, 400)), g_pLayer) ;D2D1_SIZE_F size = g_pBitmap->GetSize() ;D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;// Draw bitmapg_pRenderTarget->DrawBitmap( g_pBitmap, D2D1::RectF( upperLeftCorner.x, upperLeftCorner.y, upperLeftCorner.x + size.width, upperLeftCorner.y + size.height)) ;// Pop layer before EndDrawg_pRenderTarget->PopLayer() ;g_pRenderTarget->EndDraw() ;
透明效果
在PushLayer調用完之後,先繪製一個位元影像,然後再繪製三個矩形,這三個矩形使用綠顏色的畫刷來繪製,所以最終的結果就是位元影像和矩形混合後的結果,可以看到矩形呈透明狀,建立綠色畫刷的代碼省略。
代碼
g_pRenderTarget->BeginDraw() ;g_pRenderTarget->PushLayer(D2D1::LayerParameters(), g_pLayer) ;g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));D2D1_SIZE_F size = g_pBitmap->GetSize() ;D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;// Draw bitmapg_pRenderTarget->DrawBitmap( g_pBitmap, D2D1::RectF( upperLeftCorner.x, upperLeftCorner.y, upperLeftCorner.x + size.width, upperLeftCorner.y + size.height)) ;// Opacity mask 1g_pRenderTarget->FillRectangle(D2D1::RectF(100, 100, 200, 200), g_pBlackBrush) ;// Opacity mask 2g_pRenderTarget->FillRectangle(D2D1::RectF(200, 200, 300, 300), g_pBlackBrush) ;// Opacity mask 3g_pRenderTarget->FillRectangle(D2D1::RectF(300, 300, 400, 400), g_pBlackBrush) ;// Pop layer before EndDrawg_pRenderTarget->PopLayer() ;g_pRenderTarget->EndDraw() ;
圓形漸層畫刷
先建立一個圓形的漸層色畫刷,調用PushLayer的時候將這個畫刷作為參數傳遞給PushLayer的第一個參數。接下來繪製一個位元影像,當調用PopLayer的時候兩次繪製的內容將被混合到一起,最後形成一個夜視鏡的效果。
代碼
g_pRenderTarget->BeginDraw() ;// Clear background color to whiteg_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));g_pRenderTarget->PushLayer( D2D1::LayerParameters( D2D1::InfiniteRect(), NULL, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::IdentityMatrix(), 1.0f, g_pRadialGradientBrush, D2D1_LAYER_OPTIONS_NONE), g_pLayer);D2D1_SIZE_F size = g_pBitmap->GetSize() ;D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;// Draw bitmapg_pRenderTarget->DrawBitmap( g_pBitmap, D2D1::RectF( upperLeftCorner.x, upperLeftCorner.y, upperLeftCorner.x + size.width, upperLeftCorner.y + size.height)) ;// Pop layer before EndDrawg_pRenderTarget->PopLayer() ;g_pRenderTarget->EndDraw() ;
== Happy Coding ==