Udostępnij przez


Omówienie warstw

W tym omówieniu opisano podstawy korzystania z warstw Direct2D. Zawiera on następujące sekcje.

Co to są warstwy?

Layers, represented by ID2D1Layer objects, enable an application to manipulate a group of drawing operations. Stosujesz warstwę, "wypychając" ją na obiekt docelowy renderowania. Kolejne operacje rysowania wykonywane przez docelowy obiekt renderujący są przesyłane do warstwy. After you're finished with the layer, you "pop" the layer from the render target, which composites the layer's content back to the render target.

Podobnie jak pędzle, warstwy są zasobami zależnymi od urządzenia utworzonymi przez obiekty docelowe renderowania. Layers can be used on any render target in the same resource domain that contains the render target that created it. Jednak zasób warstwy może być używany tylko przez jeden element docelowy renderowania jednocześnie. Aby uzyskać więcej informacji na temat zasobów, zobacz Resources Overview.

Mimo że warstwy oferują zaawansowaną technikę renderowania na potrzeby tworzenia interesujących efektów, nadmierna liczba warstw w aplikacji może niekorzystnie wpłynąć na jej wydajność ze względu na różne koszty związane z zarządzaniem warstwami i zasobami warstw. Na przykład koszt wypełnienia lub wyczyszczenia warstwy, a następnie ponownego połączenia jej, szczególnie w przypadku wysokiej klasy sprzętu. Następnie jest koszt zarządzania zasobami warstwy. If you reallocate these frequently, the resulting stalls against the GPU will be the most significant problem. Podczas projektowania aplikacji spróbuj zmaksymalizować ponowne wykorzystanie zasobów warstwy.

Warstwy w systemie Windows 8 lub nowszym

System Windows 8 wprowadził nowe interfejsy API powiązane z warstwami, które upraszczają, zwiększają wydajność i dodają funkcje do warstw.

ID2D1DeviceContext and PushLayer

Interfejs ID2D1DeviceContext pochodzi z interfejsu ID2D1RenderTarget i jest kluczowy dla wyświetlania zawartości Direct2D w systemie Windows 8. Aby uzyskać więcej informacji na temat tego interfejsu, zobacz Urządzenia i konteksty urządzeń. Za pomocą interfejsu kontekstu urządzenia można pominąć wywoływanie metody CreateLayer, a następnie przekazać wartość NULL do metody ID2D1DeviceContext::PushLayer. Direct2D automatically manages the layer resource and can share resources between layers and effect graphs.

D2D1_LAYER_PARAMETERS1 and D2D1_LAYER_OPTIONS1

The D2D1_LAYER_PARAMETERS1 structure is the same as D2D1_LAYER_PARAMETERS, except the final member of the structure is now a D2D1_LAYER_OPTIONS1 enumeration.

D2D1_LAYER_OPTIONS1 nie ma opcji ClearType i ma dwie różne opcje, których można użyć do poprawy wydajności:

Tryby mieszania

Starting in Windows 8, the device context has a primitive blend mode that determines how each primitive is blended with the target surface. Ten tryb dotyczy również warstw podczas wywoływania metody PushLayer.

For example, if you are using a layer to clip primitives with transparency set the D2D1_PRIMITIVE_BLEND_COPY mode on the device context for proper results. The copy mode makes the device context linear interpolate all 4 color channels, including the alpha channel, of each pixel with the contents of the target surface according to the geometric mask of the layer.

Współdziałanie

Starting in Windows 8, Direct2D supports interoperation with Direct3D and GDI while a layer or clip is pushed. You call ID2D1GdiInteropRenderTarget::GetDC while a layer is pushed to interoperate with GDI. You call ID2D1DeviceContext::Flush and then render to the underlying surface to interoperate with Direct3D. Użytkownik ponosi odpowiedzialność za renderowanie wewnątrz warstwy lub klipu za pomocą funkcji Direct3D lub GDI. If you try to render outside the layer or clip the results are undefined.

Tworzenie warstw

Praca z warstwami wymaga znajomości metod CreateLayer, PushLayeri metod PopLayer oraz struktury D2D1_LAYER_PARAMETERS, która zawiera zestaw danych parametrycznych definiujących sposób użycia warstwy. Poniższa lista zawiera opis metod i struktury.

  • Wywołaj metodę CreateLayer, aby utworzyć zasób warstwy.

    Notatka

    Począwszy od systemu Windows 8, można pominąć wywoływanie metody CreateLayer, a następnie przekazać wartość NULL do metody PushLayer w interfejsie ID2D1DeviceContext. Jest to prostsze i umożliwia usłudze Direct2D automatyczne zarządzanie zasobem warstwy i udostępnianie zasobów między warstwami i grafami efektów.

     

  • After render target has begun drawing (after its BeginDraw method has been called), you can use the PushLayer method. The PushLayer method adds the specified layer to the render target, so that the target receives all subsequent drawing operations until PopLayer is called. This method takes an ID2D1Layer object returned by calling CreateLayer and an layerParameters in the D2D1_LAYER_PARAMETERS structure. W poniższej tabeli opisano pola struktury.

    Field Opis
    contentBounds Granice zawartości warstwy. Zawartość nie będzie renderowana poza tymi granicami. Ten parametr jest domyślnie InfiniteRect. Gdy jest używana wartość domyślna, granice zawartości są skutecznie podejmowane jako granice obiektu docelowego renderowania.
    geometryczna_maska (Optional) The area, defined by an ID2D1Geometry, to which the layer should be clipped. Set to NULL if the layer shouldn't be clipped to a geometry.
    maskAntialiasMode Wartość określająca tryb antyaliasingu dla maski geometrycznej określonej przez pole maski geometrycznej.
    maskTransform Wartość określająca przekształcenie stosowane do maski geometrycznej podczas komponowania warstwy. This is relative to the world transform.
    opacity Wartość nieprzezroczystości warstwy. The opacity of each resource in the layer is multiplied with this value when compositing to the target.
    opacityBrush (Opcjonalnie) Szczotka używana do modyfikowania nieprzezroczystości warstwy. The brush is mapped to the layer, and the alpha channel of each mapped brush pixel is multiplied against the corresponding layer pixel. Ustaw wartość na null, jeśli warstwa nie powinna mieć maski nieprzezroczystości.
    layerOptions Wartość określająca, czy warstwa zamierza renderować tekst z antyaliasingiem ClearType. Ten parametr jest domyślnie wyłączony. Włączenie go umożliwia poprawne działanie funkcji ClearType, ale powoduje nieco wolniejsze renderowanie.

     

    Notatka

    Począwszy od systemu Windows 8, nie można renderować funkcji ClearType w warstwie, więc parametr layerOptions powinien być zawsze ustawiony na D2D1_LAYER_OPTIONS_NONE

     

    Dla wygody funkcja Direct2D udostępnia metodę D2D1::LayerParameters ułatwiając tworzenie struktur D2D1_LAYER_PARAMETERS.

  • Aby połączyć zawartość warstwy z obiektem docelowym renderowania, wywołaj metodę PopLayer. Przed wywołaniem metody EndDraw należy wywołać metodę PopLayer.

W poniższym przykładzie pokazano, jak używać CreateLayer, PushLayeri PopLayer. Wszystkie pola w strukturze D2D1_LAYER_PARAMETERS są ustawione na wartości domyślne, z wyjątkiem OpacityBrush, który jest ustawiony 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);

Kod został pominięty w tym przykładzie.

Note that when you call PushLayer and PopLayer, ensure that each PushLayer has a matching PopLayer call. Jeśli jest więcej wywołań PopLayer niż wywołań PushLayer, docelowy obiekt renderowania jest umieszczany w stanie błędu. If Flush is called before all outstanding layers are popped, the render target is placed into an error state and returns an error. Aby wyczyścić stan błędu, użyj EndDraw.

Granice zawartości

The contentBounds sets the limit of what is to be drawn to the layer. Only those things within the content bounds are composited back to the render target.

The example that follows shows how to specify contentBounds so that the original image is clipped to the content bounds with the upper-left corner at (10, 108) and the lower-right corner at (121, 177). The following illustration shows the original image and the result of clipping the image to the content bounds.

illustration of content bounds on an original picture and the resulting clipped picture

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

Kod został pominięty w tym przykładzie.

Notatka

The resulting clipped image is further affected if you specify a geometricMask. See the Geometric Masks section for more information.

 

Maski geometryczne

A geometric mask is a clip or a cutout, defined by an ID2D1Geometry object, that masks a layer when it is drawn by a render target. You can use the geometricMask field of the D2D1_LAYER_PARAMETERS structure to mask the results to a geometry. Jeśli na przykład chcesz wyświetlić obraz zamaskowany literą blokową "A", możesz najpierw utworzyć geometrię reprezentującą literę blokową "A" i użyć tej geometrii jako maski geometrycznej dla warstwy. Następnie po wypchnięciu warstwy można narysować obraz. Popping the layer results in the image being clipped to the block letter "A" shape.

W poniższym przykładzie pokazano, jak utworzyć ID2D1PathGeometry zawierający kształt góry, a następnie przekazać geometrię ścieżki do PushLayer. Następnie rysuje mapę bitową i kwadraty. Jeśli w warstwie ma być renderowana tylko mapa bitowa, użyj FillGeometry z zaciśniętym pędzlem mapy bitowej w celu zwiększenia wydajności. Poniższa ilustracja przedstawia dane wyjściowe z przykładu.

illustration of a picture of a leaf and the resulting picture after a geometric mask of a mountain is applied

W pierwszym przykładzie zdefiniowano geometrię, która ma być używana 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);
       }

W następnym przykładzie użyto geometrii jako maski dla warstwy.

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

Kod został pominięty w tym przykładzie.

Notatka

In general, if you specify a geometricMask, you can use the default value, InfiniteRect, for the contentBounds.

If contentBounds is NULL, and geometricMask is non-NULL, then the content bounds are effectively the bounds of the geometric mask after the mask transform is applied.

If contentBounds is non-NULL, and geometricMask is non-NULL, then the transformed geometric mask is effectively clipped against content bounds and the content bounds are assumed to be infinite.

 

Maski nieprzezroczystości

Maska nieprzezroczystości to maska opisana za pomocą pędzla lub mapy bitowej, która jest stosowana do innego obiektu, aby uczynić ten obiekt częściowo lub całkowicie przezroczystym. Umożliwia użycie kanału alfa pędzla jako maski zawartości. For example, you can define a radial gradient brush that varies from opaque to transparent to create a vignette effect.

W poniższym przykładzie użyto ID2D1RadialGradientBrush (m_pRadialGradientBrush) jako maski nieprzezroczystości. Następnie rysuje mapę bitową i kwadraty. Jeśli w warstwie ma być renderowana tylko mapa bitowa, użyj FillGeometry z zaciśniętym pędzlem mapy bitowej w celu zwiększenia wydajności. Poniższa ilustracja przedstawia dane wyjściowe z tego przykładu.

illustration of a picture of trees and the resulting picture after an opacity mask is applied

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

Kod został pominięty w tym przykładzie.

Notatka

W tym przykładzie użyto warstwy, aby zastosować maskę nieprzezroczystości do pojedynczego obiektu, aby zachować jak najprostszy przykład. W przypadku stosowania maski nieprzezroczystości do pojedynczego obiektu bardziej wydajne jest użycie metody FillOpacityMask lub FillGeometry, a nie warstwy.

 

For instructions on how to apply an opacity mask without using a layer, see the Opacity Masks Overview.

Alternatywy dla warstw

Jak wspomniano wcześniej, nadmierna liczba warstw może niekorzystnie wpłynąć na wydajność aplikacji. Aby zwiększyć wydajność, należy unikać używania warstw, gdy jest to możliwe; zamiast tego należy użyć ich alternatyw. W poniższym przykładzie kodu pokazano, jak używać PushAxisAlignedClip i PopAxisAlignedClip w celu wyciąć region, jako alternatywę dla używania warstwy z granicami zawartości.

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

Similarly, use FillGeometry with a clamped bitmap brush as an alternative to using a layer with an opacity mask when there is only one content in the layer to render, as shown in the following example.

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

Alternatywą dla używania warstwy z maską geometryczną jest użycie maski mapy bitowej do przycinania regionu, jak pokazano w poniższym przykładzie.

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

Lastly, if you want to apply opacity to a single primitive, you should multiply the opacity into the into the brush color and then render the primitive. You do not need a layer or an opacity mask bitmap.

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

Przycinanie dowolnego kształtu

Na rysunku przedstawiono wynik zastosowania klipu do obrazu.

obraz przedstawiający przykład obrazu przed klipem i po nim.

You can get this result by using layers with a geometry mask or the FillGeometry method with an opacity brush.

Oto przykład, który używa warstwy:

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

Oto przykład, który używa metody 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()); 

W tym przykładzie kodu podczas wywoływania metody PushLayer nie przekazujesz warstwy utworzonej przez aplikację. Direct2D tworzy warstwę dla Ciebie. Funkcja Direct2D umożliwia zarządzanie alokacją i zniszczeniem tego zasobu bez udziału aplikacji. To umożliwia Direct2D wewnętrzne ponowne użycie warstw oraz stosowanie optymalizacji zarządzania zasobami.

Notatka

W systemie Windows 8 wprowadzono wiele optymalizacji w zakresie użycia warstw i zalecamy wypróbowanie korzystania z API warstw zamiast FillGeometry, gdy tylko to możliwe.

 

Axis aligned clips

If the region to be clipped is aligned to the axis of the drawing surface, instead of arbitrary. This case is suited for using a clip rectangle instead of a layer. The performance gain is more for aliased geometry than antialiased geometry. For more info on axis aligned clips, see the PushAxisAlignedClip topic.

Direct2D Reference