Přehled vrstev
Tento přehled popisuje základy používání vrstev Direct2D. Obsahuje následující části.
- co jsou vrstvy?
- Vrstvy ve Windows 8 a novějších
- vytváření vrstev
- Hranice obsahu
- Geometrické Masky
- masky neprůhlednosti
- Alternativy vrstev
- oříznutí libovolného obrazce
- související témata
Co jsou vrstvy?
Vrstvy reprezentované ID2D1Layer objekty umožňují aplikaci manipulovat se skupinou operací kreslení. Vrstvu použijete tak, že ji "přidáte" do cíle vykreslení. Následné operace kreslení podle cíle vykreslení jsou směrovány do vrstvy. Po dokončení vrstvy "vyskakujete" vrstvu z cíle vykreslení, což složí obsah vrstvy zpět do cíle vykreslení.
Podobně jako štětce jsou vrstvy zdroje závislé na zařízení, které jsou vytvářeny vykreslovacími cíli. Vrstvy je možné použít pro jakýkoli cíl vykreslení ve stejné doméně prostředků, která obsahuje cíl vykreslení, který ho vytvořil. Prostředek vrstvy může ale současně používat jenom jeden cíl vykreslení. Další informace o prostředcích naleznete v Přehled zdrojů.
I když vrstvy nabízejí výkonnou techniku vykreslování pro vytváření zajímavých efektů, nadměrný počet vrstev v aplikaci může nepříznivě ovlivnit jeho výkon, protože různé náklady spojené se správou vrstev a prostředků vrstev. Existují například náklady na vyplnění nebo vymazání vrstvy a následné prolnutí zpět, zejména na hardwaru vyššího typu. Dále, existují náklady na správu prostředků vrstvy. Pokud tyto často přesouváte, zpoždění ve výkonu oproti GPU budou nejvýznamnějším problémem. Při návrhu aplikace se pokuste maximalizovat znovupoužití vrstových prostředků.
Vrstvy ve Windows 8 a novějších verzích
Windows 8 zavedla nová rozhraní API související s vrstvami, která zjednodušují, zlepšují výkon a přidávají funkce do vrstev.
ID2D1DeviceContext a PushLayer
Rozhraní ID2D1DeviceContext je odvozeno z rozhraní ID2D1RenderTarget a je klíčem k zobrazení obsahu Direct2D v systému Windows 8, další informace o tomto rozhraní naleznete v tématu Zařízení a kontexty zařízení. S kontextovým rozhraním zařízení můžete přeskočit volání metody CreateLayer a pak předat hodnotu NULL metodě ID2D1DeviceContext::P ushLayer. Direct2D automaticky spravuje zdroj vrstvy a dokáže sdílet zdroje mezi vrstvami a grafy efektů.
D2D1_LAYER_PARAMETERS1 a D2D1_LAYER_OPTIONS1
Struktura D2D1_LAYER_PARAMETERS1 je stejná jako D2D1_LAYER_PARAMETERS, až na to, že poslední prvek struktury je nyní výčtového typu D2D1_LAYER_OPTIONS1.
D2D1_LAYER_OPTIONS1 nemá možnost ClearType a má dvě různé možnosti, které můžete použít ke zlepšení výkonu:
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND: Direct2D vykresluje prvky na vrstvu, aniž by ji vymazal průhlednou černou. Toto není výchozí hodnota, ale ve většině případů vede k lepšímu výkonu.
D2D1_LAYER_OPTIONS1_IGNORE_ALPHA: Pokud je podkladová plocha nastavená na D2D1_ALPHA_MODE_IGNORE, umožňuje Direct2D vyhnout se úpravám alfa kanálu vrstvy. Nepoužívejte to v jiných případech.
Režimy blendu
Počínaje Windows 8 má kontext zařízení primitivní režim prolínání, který určuje, jak se jednotlivé primitivy prolínají s cílovým povrchem. Tento režim platí také pro vrstvy při volání metody PushLayer.
Pokud například používáte vrstvu k oříznutí primitiv s průhledností, v kontextu zařízení nastavte režim D2D1_PRIMITIVE_BLEND_COPY pro správné výsledky. Režim kopírování umožňuje kontextu zařízení provádět lineární interpolaci všech čtyř barevných kanálů, včetně alfa kanálu, interpolaci každého pixelu s obsahem cílové plochy na základě geometrické masky vrstvy.
Spolupráce
Počínaje Windows 8 Direct2D podporuje spolupráci s Direct3D a GDI, když je vrstva nebo klip aktivní. Zavoláte ID2D1GdiInteropRenderTarget::GetDC, když je vrstva zakomponována pro spolupráci s GDI. Zavoláte ID2D1DeviceContext::Flush a pak vykreslíte na podkladovou plochu pro spolupráci s Direct3D. Je na vás vykreslit uvnitř vrstvy nebo klipu pomocí Direct3D nebo GDI. Pokud se pokusíte vykreslit mimo vrstvu nebo vystřihnete výsledky, nebudou definovány.
Vytváření vrstev
Práce s vrstvami vyžaduje znalost metody CreateLayer, PushLayera metody PopLayer a strukturu D2D1_LAYER_PARAMETERS, která obsahuje sadu parametrických dat definující způsob použití vrstvy. Následující seznam popisuje metody a strukturu.
Voláním metody CreateLayer vytvořte prostředek vrstvy.
Poznámka
Počínaje Windows 8 můžete přeskočit volání metody CreateLayer a pak předat hodnotu NULL metodě PushLayer v rámci rozhraní ID2D1DeviceContext. To je jednodušší a umožňuje Direct2D automatické spravování prostředků vrstev a sdílení prostředků mezi vrstvami a grafy efektů.
Po zahájení vykreslování cíle (po metodě jeho BeginDraw), můžete použít metodu PushLayer. Metoda PushLayer přidá zadanou vrstvu do cíle vykreslení, aby cíl přijímal všechny následné operace kreslení, dokud není zavolána metoda PopLayer. Tato metoda přebírá objekt ID2D1Layer vrácený voláním CreateLayer a layerParameters ve struktuře D2D1_LAYER_PARAMETERS. Následující tabulka popisuje pole struktury.
Pole Popis contentBounds Hranice obsahu vrstvy. Obsah se nevykreslí mimo tyto hranice. Tento parametr má výchozí hodnotu InfiniteRect. Když se použije výchozí hodnota, hranice obsahu se efektivně použijí jako hranice cíle vykreslení. geometrická maska (Volitelné) Oblast definovaná ID2D1Geometry, na kterou má být vrstva oříznuta. Pokud nemá být vrstva oříznuta podle geometrie, nastavte NULL. maskAntialiasMode Hodnota, která specifikuje režim antialiasingu pro geometrickou masku specifikovanou polem geometrické masky. maskTransform Hodnota, která určuje transformaci použitou na geometrické masky při vytváření vrstvy. To je relativní k světové transformaci. neprůhlednost Hodnota neprůhlednosti vrstvy. Neprůhlednost každého prvku ve vrstvě se při složení do cílového obrazu vynásobí touto hodnotou. krycíŠtětec (Volitelné) Štětec, který se používá k úpravě neprůhlednosti vrstvy. Štětec je namapován na vrstvu a alfa kanál každého mapovaného pixelu štětce je vynásoben odpovídajícím pixelu vrstvy. Pokud by vrstva neměla mít masku neprůhlednosti, nastavte na null. možnosti vrstvy Hodnota, která určuje, zda vrstva hodlá vykreslit text s clearType antialiasing. Tento parametr je ve výchozím nastavení vypnutý. Zapnutím povolíte, aby funkce ClearType fungovala správně, ale výsledkem je mírně pomalejší rychlost vykreslování. Poznámka
Počínaje systémem Windows 8 není možné vykreslit ClearType ve vrstvě, takže parametr layerOptions by měl být vždy nastaven na D2D1_LAYER_OPTIONS_NONE
Pro větší pohodlí poskytuje Direct2D metodu D2D1::LayerParameters, která vám pomůže vytvářet struktury D2D1_LAYER_PARAMETERS.
Pro složení obsahu vrstvy do cílového vykreslení zavolejte metodu PopLayer. Před voláním metody EndDraw je nutné volat metodu PopLayer.
Následující příklad ukazuje, jak používat CreateLayer, PushLayera PopLayer. Všechna pole ve struktuře D2D1_LAYER_PARAMETERS jsou nastavena na výchozí hodnoty s výjimkou neprůhlednostiBrush, která je nastavena na ID2D1RadialGradientBrush.
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(
D2D1::InfiniteRect(),
NULL,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0,
m_pRadialGradientBrush,
D2D1_LAYER_OPTIONS_NONE),
pLayer
);
pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));
pRT->FillRectangle(
D2D1::RectF(25.f, 25.f, 50.f, 50.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
V tomto příkladu byl vynechán kód.
Všimněte si, že při volání PushLayer a PopLayer, zajistěte, aby každé PushLayer mělo odpovídající volání PopLayer. Pokud existuje více volání PopLayer než volání PushLayer, dojde k chybovému stavu cíle vykreslení. Pokud se Flush volá před odstraněním všech nevyřízených vrstev, umístí se cíl vykreslení do chybového stavu a vrátí chybu. Chcete-li vymazat stav chyby, použijte EndDraw.
Hranice obsahu
contentBounds nastaví limit toho, co se má nakreslit do vrstvy. Pouze ty prvky v mezích obsahu se skládají zpět do cílové plochy vykreslování.
Následující příklad ukazuje, jak určit contentBounds tak, aby byl původní obrázek oříznut podle hranic obsahu s levým horním rohem na souřadnicích (10, 108) a pravým dolním rohem na souřadnicích (121, 177). Následující obrázek znázorňuje původní obrázek a výsledek oříznutí obrázku na hranice obsahu.
HRESULT DemoApp::RenderWithLayerWithContentBounds(ID2D1RenderTarget *pRT)
{
HRESULT hr = S_OK;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 0));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(D2D1::RectF(10, 108, 121, 177)),
pLayer
);
pRT->DrawBitmap(m_pWaterBitmap, D2D1::RectF(0, 0, 128, 192));
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
V tomto příkladu byl vynechán kód.
Poznámka
Výsledný oříznutý obrázek je dále ovlivněn, pokud zadáte geometrickou masku. Další informace najdete v části Geometrické masky.
Geometrické masky
Geometrická maska je klip nebo výřez definovaný objektem ID2D1Geometry, který maskuje vrstvu při vykreslení renderovacím cílem. Pomocí pole geometrická maska struktury D2D1_LAYER_PARAMETERS můžete výsledky maskovat do geometrie. Pokud například chcete zobrazit obrázek maskovaný blokovým písmenem "A", můžete nejprve vytvořit geometrii představující blokové písmeno "A" a tuto geometrii použít jako geometrické masky pro vrstvu. Po přidání vrstvy pak můžete obrázek nakreslit. Předělením vrstvy je obrázek oříznut na tvar písmena 'A'.
Následující příklad ukazuje, jak vytvořit ID2D1PathGeometry obsahující tvar hory a pak předat geometrii cesty do PushLayer. Potom nakreslí rastrový obrázek a čtverce. Pokud je ve vrstvě k vykreslení pouze rastrový obrázek, použijte FillGeometry s rastrovým štětcem s upevněním pro efektivitu. Následující obrázek znázorňuje výstup z příkladu.
První příklad definuje geometrii, která se má použít jako maska.
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
if(SUCCEEDED(hr))
{
ID2D1GeometrySink *pSink = NULL;
// Write to the path geometry using the geometry sink.
hr = m_pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
pSink->BeginFigure(
D2D1::Point2F(0, 90),
D2D1_FIGURE_BEGIN_FILLED
);
D2D1_POINT_2F points[7] = {
D2D1::Point2F(35, 30),
D2D1::Point2F(50, 50),
D2D1::Point2F(70, 45),
D2D1::Point2F(105, 90),
D2D1::Point2F(130, 90),
D2D1::Point2F(150, 60),
D2D1::Point2F(170, 90)
};
pSink->AddLines(points, 7);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
}
Další příklad používá geometrii jako masku pro vrstvu.
HRESULT DemoApp::RenderWithLayerWithGeometricMask(ID2D1RenderTarget *pRT)
{
HRESULT hr;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 450));
pRT->PushLayer(
D2D1::LayerParameters(D2D1::InfiniteRect(), m_pPathGeometry),
pLayer
);
pRT->DrawBitmap(m_pLeafBitmap, D2D1::RectF(0, 0, 198, 132));
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
V tomto příkladu byl vynechán kód.
Poznámka
Obecně platí, že pokud zadáte geometrickou masku, můžete použít výchozí hodnotu InfiniteRectpro contentBounds.
Pokud contentBounds má hodnotu NULL a geometrická maska není NULL, pak hranice obsahu jsou v podstatě hranice geometrické masky po použití transformace masky.
Pokud contentBounds není NULL a geometrická maska není NULL, transformovaná geometrická maska je efektivně oříznuta podle hranic obsahu a hranice obsahu jsou považovány za nekonečné.
Neprůhledné masky
Maska neprůhlednosti je maska popsaná štětcem nebo rastrovým obrázkem, která se použije u jiného objektu, aby byl objekt částečně nebo zcela průhledný. Umožňuje použití alfa kanálu štětce jako masky obsahu. Můžete například definovat radiální přechod, který přechází z neprůhledné na průhlednou, aby se vytvořil vinětový efekt.
Následující příklad používá ID2D1RadialGradientBrush (m_pRadialGradientBrush) jako neprůhlednou masku. Potom nakreslí rastrový obrázek a čtverce. Pokud je ve vrstvě pouze rastrový obrázek k vykreslení, použijte FillGeometry s rastrovým štětcem s omezeným rozsahem pro vyšší efektivitu. Následující obrázek znázorňuje výstup z tohoto příkladu.
HRESULT DemoApp::RenderWithLayerWithOpacityMask(ID2D1RenderTarget *pRT)
{
HRESULT hr = S_OK;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(
D2D1::InfiniteRect(),
NULL,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0,
m_pRadialGradientBrush,
D2D1_LAYER_OPTIONS_NONE),
pLayer
);
pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));
pRT->FillRectangle(
D2D1::RectF(25.f, 25.f, 50.f, 50.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
V tomto příkladu byl vynechán kód.
Poznámka
Tento příklad používá vrstvu k použití masky neprůhlednosti u jednoho objektu, aby byl příklad co nejjednodušší. Při použití masky neprůhlednosti u jednoho objektu je efektivnější použít FillOpacityMask nebo FillGeometry metody, nikoli vrstvy.
Pokyny k použití masky neprůhlednosti bez použití vrstvy najdete v přehledu masky neprůhlednosti.
Alternativy k vrstvě
Jak už bylo zmíněno dříve, nadměrný počet vrstev může nepříznivě ovlivnit výkon vaší aplikace. Chcete-li zvýšit výkon, vyhněte se používání vrstev, kdykoli je to možné; místo toho použijte jejich alternativy. Následující příklad kódu ukazuje, jak použít PushAxisAlignedClip a PopAxisAlignedClip k oříznutí oblasti, jako alternativu k použití vrstvy s hranicemi obsahu.
pRT->PushAxisAlignedClip(
D2D1::RectF(20, 20, 100, 100),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
pRT->FillRectangle(D2D1::RectF(0, 0, 200, 133), m_pOriginalBitmapBrush);
pRT->PopAxisAlignedClip();
Podobně použijte FillGeometry s přichyceným rastrovým štětcem jako alternativu k použití vrstvy s maskou průhlednosti, pokud je ve vrstvě k vykreslení pouze jeden obsah, jak je znázorněno v následujícím příkladu.
m_pRenderTarget->FillGeometry(
m_pRectGeo,
m_pLinearFadeFlowersBitmapBrush,
m_pLinearGradientBrush
);
Jako alternativu k použití vrstvy s geometrickým maskou zvažte použití rastrové masky k oříznutí oblasti, jak je znázorněno v následujícím příkladu.
// D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask
// to function properly.
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
m_pRenderTarget->FillOpacityMask(
m_pBitmapMask,
m_pOriginalBitmapBrush,
D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
&rcBrushRect,
NULL
);
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
A konečně, pokud chcete použít neprůhlednost na jeden prvek, měli byste vynásobit neprůhlednost s barvou štětce a poté vykreslit prvek. Nepotřebujete rastrovou mapu masky neprůhlednosti ani vrstvu.
float opacity = 0.9f;
ID2D1SolidColorBrush *pBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f * opacity)),
&pBrush
);
m_pRenderTarget->FillRectangle(
D2D1::RectF(50.0f, 50.0f, 75.0f, 75.0f),
pBrush
);
Oříznutí libovolného obrazce
Obrázek zde ukazuje výsledek použití klipu na obrázek.
Tento výsledek můžete získat pomocí vrstev s maskou geometrie nebo metodou FillGeometry s štětcem s průhledností.
Tady je příklad, který používá vrstvu:
// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
D2D1::LayerParameters(
boundsRect,
geometricMask));
Tady je příklad, který používá metodu FillGeometry:
// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
D2D1::BitmapProperties(
D2D1_BITMAP_OPTIONS_TARGET,
D2D1::PixelFormat(
DXGI_FORMAT_A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX, dpiY),
&opacityBitmap);
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();
// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
D2D1::BitmapBrushProperties(),
D2D1::BrushProperties(),
&bitmapBrush);
// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry(
clipGeometry.Get(),
brush.Get(),
opacityBrush.Get());
Při volání metody PushLayer v tomto příkladu kódu nepředáváte vrstvu vytvořenou aplikací. Direct2D vytvoří vrstvu za vás. Direct2D dokáže spravovat přidělení a zničení tohoto prostředku bez jakéhokoli zásahu z aplikace. Díky tomu může Direct2D interně používat vrstvy a používat optimalizace správy prostředků.
Poznámka
Ve Windows 8 jsme provedli řadu optimalizací použití vrstev a doporučujeme místo FillGeometry kdykoli je to možné, vyzkoušet rozhraní API vrstev.
Klipy zarovnané podle osy
Pokud je oblast, která se má oříznout, zarovnaná s osou plochy výkresu, a ne libovolně. Tento případ je vhodný pro použití obdélníku klipartu místo vrstvy. Zvýšení výkonu je větší pro aliasovanou geometrii než pro geometrii bez aliasingu. Další informace o klipech zarovnaných s osou najdete v tématu PushAxisAlignedClip.
Související témata