Megosztás a következőn keresztül:


Rétegek áttekintése

Ez az áttekintés a Direct2D-rétegek használatának alapjait ismerteti. A következő szakaszokat tartalmazza.

Mik azok a rétegek?

Az ID2D1Layer objektumok által képviselt rétegek lehetővé teszik, hogy az alkalmazások manipulálják a rajzműveletek egy csoportját. Egy réteget úgy használhat, hogy "leküldi" egy renderelési célra. A renderelési cél későbbi rajzműveletei a rétegre lesznek irányítva. Miután végzett a réteggel, a réteget a renderelési célból "felugratja", amely a réteg tartalmát visszaépíti a renderelési célhoz.

Az ecsetekhez hasonlóan a rétegek is eszközfüggő erőforrások, amelyeket renderelési célok hoztak létre. A rétegek bármely renderelési célon használhatók ugyanabban az erőforrástartományban, amely a létrehozott renderelési célt tartalmazza. A rétegerőforrásokat azonban egyszerre csak egy renderelési cél használhatja. További információ az erőforrásokról: Erőforrások áttekintése.

Bár a rétegek hatékony renderelési technikát kínálnak érdekes hatások előállításához, az alkalmazásokban lévő rétegek túlzott száma hátrányosan befolyásolhatja a teljesítményét a rétegek és rétegerőforrások kezelésével kapcsolatos különböző költségek miatt. Például, a réteg kitöltése vagy törlése, majd visszakeverése költséggel jár, különösen a csúcskategóriás hardverek esetében. Ezután a rétegerőforrások kezelésének költsége is megvan. Ha ezeket gyakran átcsoportosítja, az eredményül kapott GPU-val kapcsolatos leállások jelentik majd a legnagyobb problémát. Az alkalmazás tervezésekor próbálja maximalizálni a rétegerőforrások újrafelhasználását.

Rétegek a Windows 8-ban és újabb verziókban

A Windows 8 új réteghez kapcsolódó API-kat vezetett be, amelyek leegyszerűsítik, javítják a teljesítményének, és funkciókkal bővítik a rétegeket.

ID2D1DeviceContext és PushLayer

Az ID2D1DeviceContext felület az ID2D1RenderTarget felületből származik, és kulcsfontosságú a Direct2D-tartalmak Windows 8 rendszerben való megjelenítéséhez. Erről a felületről további információt az Eszközök és eszközkörnyezetekcímű témakörben talál. Az eszköz környezeti felületével kihagyhatja a CreateLayer metódus meghívását, majd null értéket adhat a ID2D1DeviceContext::P ushLayer metódusnak. A Direct2D automatikusan kezeli a rétegerőforrást, és megoszthatja az erőforrásokat a rétegek és az effektusdiagramok között.

D2D1_LAYER_PARAMETERS1 és D2D1_LAYER_OPTIONS1

A D2D1_LAYER_PARAMETERS1 struktúra megegyezik a D2D1_LAYER_PARAMETERSstruktúrával, kivéve hogy a struktúra utolsó tagja most egy D2D1_LAYER_OPTIONS1 enumeráció.

D2D1_LAYER_OPTIONS1 nem rendelkezik ClearType beállítással, és két különböző beállítással rendelkezik, amelyekkel javíthatja a teljesítményt:

Keverési módok

A Windows 8-tól kezdve az eszközkörnyezet egy primitív keverési módot, amely meghatározza, hogy az egyes primitívek hogyan keverednek a célfelülettel. Ez a mód a PushLayer metódus meghívásakor is vonatkozik a rétegekre.

Ha például egy réteget használ a primitívek átlátszóságú kivágásához, állítsa be a D2D1_PRIMITIVE_BLEND_COPY módot az eszközkörnyezetben a megfelelő eredmények érdekében. A másolási mód lineárisan interpolálja az eszközkörnyezetet az egyes képpontok mind a 4 színcsatornáját, beleértve az alfa csatornát is, a réteg geometriai maszkjának megfelelően a célfelület tartalmával.

Együttműködés

A Windows 8-tól kezdve a Direct2D támogatja a Direct3D és a GDI együttműködését, miközben egy réteg vagy klip leküldése történik. Meghívja ID2D1GdiInteropRenderTarget::GetDC, miközben egy réteg van beállítva, ami a GDI-vel együttműködik. Meghívja a ID2D1DeviceContext::Flush-t, majd a mögöttes felületre renderel, hogy együttműködjön a Direct3D-vel. Az Ön felelőssége, hogy a rétegen vagy a klipen belül rendereljen Direct3D-vel vagy GDI-vel. Ha a rétegen kívül próbál renderelni vagy kivágni, az eredmények nem lesznek definiáltak.

Rétegek létrehozása

A rétegek használatához ismerni kell a CreateLayer, PushLayerés PopLayer metódusokat, valamint a D2D1_LAYER_PARAMETERS struktúrát, amely a réteg használatának módját meghatározó parametrikus adatokat tartalmaz. Az alábbi lista a metódusokat és a szerkezetet ismerteti.

  • Rétegerőforrás létrehozásához hívja meg a CreateLayer metódust.

    Jegyzet

    A Windows 8-tól kezdve kihagyhatja a CreateLayer metódus meghívását, majd null értéket adhat át a PushLayer metódusnak az ID2D1DeviceContext felületen. Ez egyszerűbb, és lehetővé teszi, hogy a Direct2D automatikusan kezelje a rétegerőforrást, és erőforrásokat osztjon meg rétegek és effektusdiagramok között.

     

  • Miután a renderelési cél elkezdődött a rajzolás (miután a BeginDraw metódus meghívása megtörtént), használhatja a PushLayer metódust. A PushLayer metódus hozzáadja a megadott réteget a renderelési célhoz, így a cél az összes további rajzműveletet megkapja, amíg PopLayer nem lesz meghívva. Ez a metódus egy ID2D1Layer objektumot használ, amelyet CreateLayer meghívásával, valamint egy rétegparaméterek a D2D1_LAYER_PARAMETERS struktúrában. Az alábbi táblázat a struktúra mezőit ismerteti.

    Mező Leírás
    tartalomHatárok A réteg tartalomkorlátjai. A tartalom nem jelenik meg ezeken a korlátokon kívül. Ez a paraméter alapértelmezés szerint InfiniteRect. Az alapértelmezett érték használata esetén a tartalomkorlátok ténylegesen a renderelési cél határértékei lesznek.
    GeometricMask (Nem kötelező) Az a terület, amelyet az ID2D1Geometry határoz meg, amelyhez a réteget kapcsolni kell. Állítsa értékre NULL, ha a réteget nem kell geometriához igazítani.
    maskAntialiasMode A geometricMask mező által megadott geometriai maszk élsimítási módját meghatározó érték.
    maskTransform Egy érték, amely megadja a geometriai maszkra alkalmazott átalakítást a réteg írásakor. Ez a világ átalakulásához képest van.
    átlátszóság A réteg átlátszatlansági értéke. A rétegben lévő egyes erőforrások átlátszatlansága megszorozódik ezzel az értékkel a célhoz való összeállításkor.
    opacityBrush (Nem kötelező) A réteg átlátszatlanságát módosító ecset. Az ecset a rétegre van leképezve, és az egyes leképezett ecset képpontok alfa csatornája megszorzódik a megfelelő réteg képpontjával. Állítsa be NULL értékre, ha a rétegnek nem kell átlátszatlansági maszkot használnia.
    réteg beállítások Egy érték, amely meghatározza, hogy a réteg a ClearType antialiasing használatával kívánja-e megjeleníteni a szöveget. Ez a paraméter alapértelmezés szerint ki van kapcsolva. Bekapcsolásával a ClearType megfelelően működik, de valamivel lassabb renderelési sebességet eredményez.

     

    Jegyzet

    A Windows 8-tól kezdve a ClearType nem jeleníthető meg egy rétegben, ezért a layerOptions paramétert mindig D2D1_LAYER_OPTIONS_NONE kell beállítani.

     

    A Direct2D rendelkezésre bocsátja a D2D1::LayerParameters metódust, hogy segítsen létrehozni D2D1_LAYER_PARAMETERS struktúrákat.

  • Ha a réteg tartalmát a renderelési célba szeretné illeszteni, hívja meg a PopLayer metódust. A EndDraw metódus meghívása előtt meg kell hívnia a PopLayer metódust.

Az alábbi példa bemutatja, hogyan használható CreateLayer, PushLayerés PopLayer. A D2D1_LAYER_PARAMETERS struktúra minden mezője alapértelmezett értékre van állítva, kivéve a opacityBrush, amely egy ID2D1RadialGradientBrush-re van beállítva.

// 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);

Ebből a példából kihagyta a kódot.

Vegye figyelembe, hogy PushLayer és PopLayerhívásakor győződjön meg arról, hogy minden PushLayer rendelkezik egyező PopLayer hívással. Ha több PopLayer- hívás van, mint PushLayer hívások, a renderelési cél hibaállapotba kerül. Ha a Flush hívása megtörténik, mielőtt az összes függőben lévő réteg eltávolításra kerül, a renderelési cél hibaállapotba kerül és hibát ad vissza. A hibaállapot törléséhez használja EndDraw.

Tartalomkorlátok

A contentBounds beállítja a rétegre rajzolandó határokat. Csak a tartalomkorlátokon belüli dolgok lesznek visszakonfigurálva a renderelési célhoz.

Az alábbi példa bemutatja, hogyan adhatók meg a contentBounds úgy, hogy az eredeti kép a tartalomhatárokhoz legyen igazítva, a bal felső sarok a (10, 108) és a jobb alsó sarok a (121, 177) pozícióban legyen kivágva. Az alábbi ábrán az eredeti kép és a kép tartalomkorlátokra való kivágásának eredménye látható.

eredeti kép tartalomkorlátjainak illusztrációja és az eredményként kapott levágott kép

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;
    
}

Ebből a példából kihagyta a kódot.

Jegyzet

Az eredményül kapott levágott képre további hatás van, ha megad egy geometriai maszkot. További információt a geometriai maszkok szakaszban talál.

 

Geometriai maszkok

A geometriai maszk egy, ID2D1Geometry objektum által meghatározott klip vagy kivágás, amely maszkolja a réteget a renderelési cél rajzolásakor. A D2D1_LAYER_PARAMETERS struktúra geometriai maszk mezőjével az eredményeket egy geometria alapján elfedheti. Ha például egy "A" blokkbetűvel maszkolt képet szeretne megjeleníteni, először létrehozhat egy geometriát az "A" blokkbetűvel, és ezt a geometriát használhatja geometriai maszkként egy réteghez. Ezután, miután a réteget hozzáadta, megrajzolhatja a képet. A réteg felugratásával a kép az "A" blokkbetűs alakzatra lesz vágva.

Az alábbi példa bemutatja, hogyan hozhat létre egy ID2D1PathGeometry, amely egy hegy alakzatát tartalmazza, majd adja át az elérési út geometriáját a PushLayer. Ezután rajzol egy bitképet és négyzeteket. Ha a rétegben csak egy bitképet szeretne renderelni, használja a FillGeometry egy rögzített bitképkefével a hatékonyság érdekében. Az alábbi ábrán a példa kimenete látható.

egy levél képének és az eredményként kapott képnek a hegy geometriai maszkjának alkalmazása utáni ábrája

Az első példa a maszkként használandó geometriát határozza meg.

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);
       }

A következő példa a geometriát használja maszkként a réteghez.

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;
    
}

Ebből a példából kihagyta a kódot.

Jegyzet

Ha megadja a GeometricMask-t, akkor a InfiniteRectalapértelmezett értékét használhatja a contentBoundsesetében.

Ha a contentBounds null értékű, és a geometriai maszk nem NULL, akkor a tartalmi határok hatékonyan a geometriai maszk határai lesznek a maszkátalakítás alkalmazása után.

Ha contentBounds értéke nem NULL, és geometriai maszk nem NULL, akkor az átalakított geometriai maszk gyakorlatilag a tartalomkorlátokhoz lesz vágva, és a tartalomkorlátok végtelennek számítanak.

 

Átlátszatlansági maszkok

Az átlátszatlansági maszk egy ecsettel vagy bitképtel leírt maszk, amelyet egy másik objektumra alkalmazva részlegesen vagy teljesen áttetszővé teszi az objektumot. Lehetővé teszi az ecset alfa csatornájának használatát tartalommaszkként. Definiálhat például egy sugárirányú színátmenet ecsetet, amely átlátszatlantól átlátszóig változik, így vignetta effektust hozhat létre.

Az alábbi példa egy ID2D1RadialGradientBrush (m_pRadialGradientBrush) használja átlátszatlansági maszkként. Ezután rajzol egy bitképet és négyzeteket. Ha a rétegben csak egy bitképet szeretne renderelni, használja a FillGeometry egy rögzített bitképkefével a hatékonyság érdekében. Az alábbi ábrán a példa kimenete látható.

fa képének és az eredményként kapott képnek az átlátszatlansági maszk alkalmazása utáni ábrája

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;
    
}

Ebből a példából kihagyta a kódot.

Jegyzet

Ez a példa egy réteggel alkalmaz átlátszatlansági maszkot egyetlen objektumra, hogy a példa a lehető legegyszerűbb legyen. Ha átlátszatlansági maszkot alkalmaz egyetlen objektumra, hatékonyabb a FillOpacityMask vagy FillGeometry metódusok használata réteg helyett.

 

Az átlátszatlansági maszk réteg használata nélküli alkalmazásával kapcsolatos útmutatásért tekintse meg az Opacitásmaszkok áttekintésecímű témakört.

A rétegek alternatívái

Ahogy korábban említettük, a rétegek túlzott száma hátrányosan befolyásolhatja az alkalmazás teljesítményét. A teljesítmény javítása érdekében lehetőleg kerülje a rétegek használatát; helyett használja az alternatívákat. Az alábbi példakód bemutatja, hogyan használható PushAxisAlignedClip és PopAxisAlignedClip egy régió kivágására, a tartalomkorlátokkal rendelkező réteg használata helyett.

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();

Hasonlóképpen használja a FillGeometry funkciót egy leszorított bitképkefével, alternatívaként átlátszatlansági maszkkal rendelkező réteg helyett, ha a rétegben csak egy tartalom van megjelenítve, ahogyan az alábbi példában is látható.

        m_pRenderTarget->FillGeometry(
            m_pRectGeo, 
            m_pLinearFadeFlowersBitmapBrush, 
            m_pLinearGradientBrush
            );

A geometriai maszkot tartalmazó réteg használata helyett érdemes lehet bitképmaszkot használni egy régió kivágásához, ahogyan az az alábbi példában is látható.

// 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);

Végül, ha átlátszatlanságot szeretne alkalmazni egyetlen primitívre, akkor meg kell szoroznia az átlátszatlanságot az ecset színével, majd meg kell jelenítenie a primitívet. Nincs szükség rétegre vagy átlátszatlansági maszk bitképre.

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
    ); 

Tetszőleges alakzat kivágása

Az alábbi ábrán egy klip képre való alkalmazásának eredménye látható.

egy kép, amely bemutat egy példát arról, hogy néz ki egy kép a klip előtt és után.

Ezt az eredményt geometriai maszkkal ellátott rétegekkel vagy a FillGeometry módszerrel, átlátszatlansági ecsettel érheti el.

Íme egy példa, amely egy réteget használ:

// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
    D2D1::LayerParameters(
        boundsRect,
        geometricMask));

Íme egy példa, amely a FillGeometry metódust használja:

// 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()); 

Ebben a kód példában, amikor meghívja a PushLayer metódust, nem adja át az alkalmazás által létrehozott réteget. A Direct2D létrehoz egy réteget. A Direct2D az alkalmazás közreműködése nélkül képes kezelni az erőforrás lefoglalását és megsemmisítését. Ez lehetővé teszi, hogy a Direct2D belsőleg újra felhasználja a rétegeket, és erőforrás-kezelési optimalizálásokat alkalmazzon.

Jegyzet

A Windows 8-ban számos optimalizálást hajtottak végre a rétegek használatára, és azt javasoljuk, hogy a FillGeometry helyett használjon réteg API-kat, amikor csak lehetséges.

 

Tengelyhez igazított klipek

Ha a kivágandó régió tetszőleges helyett a rajzfelület tengelyéhez van igazítva. Ez az eset alkalmas arra, hogy réteg helyett kivágási téglalapot használjon. Az aliasolt geometria esetében a teljesítménynövekedés nagyobb, mint az antialiasolt geometria esetében. A tengelyhez igazított klipekkel kapcsolatos további információkért lásd a PushAxisAlignedClip témakört.

Direct2D-referencia