Direct2D教程(十二)圖層


什么是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 layer
hr = 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 bitmap
g_pRenderTarget->DrawBitmap(
    g_pBitmap,
    D2D1::RectF(
    upperLeftCorner.x,
    upperLeftCorner.y,
    upperLeftCorner.x + size.width,
    upperLeftCorner.y + size.height)
) ;

// Pop layer before EndDraw
g_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 bitmap
g_pRenderTarget->DrawBitmap(
    g_pBitmap,
    D2D1::RectF(
    upperLeftCorner.x,
    upperLeftCorner.y,
    upperLeftCorner.x + size.width,
    upperLeftCorner.y + size.height)
) ;

// Opacity mask 1
g_pRenderTarget->FillRectangle(D2D1::RectF(100, 100, 200, 200), g_pBlackBrush) ;

// Opacity mask 2
g_pRenderTarget->FillRectangle(D2D1::RectF(200, 200, 300, 300), g_pBlackBrush) ;

// Opacity mask 3
g_pRenderTarget->FillRectangle(D2D1::RectF(300, 300, 400, 400), g_pBlackBrush) ;

// Pop layer before EndDraw
g_pRenderTarget->PopLayer() ;

g_pRenderTarget->EndDraw() ;

效果圖

圓形漸變畫刷

先創建一個圓形的漸變色畫刷,調用PushLayer的時候將這個畫刷作為參數傳遞給PushLayer的第一個參數。接下來繪制一個位圖,當調用PopLayer的時候兩次繪制的內容將被混合到一起,最后形成一個夜視鏡的效果。

代碼

g_pRenderTarget->BeginDraw() ;

// Clear background color to white
g_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 bitmap
g_pRenderTarget->DrawBitmap(
    g_pBitmap,
    D2D1::RectF(
    upperLeftCorner.x,
    upperLeftCorner.y,
    upperLeftCorner.x + size.width,
    upperLeftCorner.y + size.height)
) ;

// Pop layer before EndDraw
g_pRenderTarget->PopLayer() ;

g_pRenderTarget->EndDraw() ;

效果圖

最后一個例子代碼下載

== Happy Coding ==


免責聲明!

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



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