Condividi tramite


Panoramica dei pennelli

Questa panoramica descrive come creare e usare oggetti ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrush e ID2D1BitmapBrush per disegnare aree con colori a tinta unita, sfumature e bitmap. Include le sezioni seguenti:

Prerequisiti

Questa panoramica presuppone che si abbia familiarità con la struttura di un'applicazione Direct2D di base, come descritto in Creare una semplice applicazione Direct2D.

Tipi di pennello

Un pennello "disegna" un'area con il relativo output. Pennelli diversi hanno diversi tipi di output. Direct2D fornisce quattro tipi di pennello: ID2D1SolidColorBrush disegna un'area con un colore a tinta unita, ID2D1LinearGradientBrush con una sfumatura lineare, ID2D1RadialGradientBrush con sfumatura radiale e ID2D1BitmapBrush con una bitmap.

Nota

A partire da Windows 8, è anche possibile usare ID2D1ImageBrush, che è simile a un pennello bitmap, ma è anche possibile usare primitive.

Tutti i pennelli ereditano da ID2D1Brush e condividono un set di funzionalità comuni (impostazione e recupero dell'opacità e trasformazione dei pennelli); vengono creati da ID2D1RenderTarget e sono risorse dipendenti dal dispositivo: l'applicazione deve creare pennelli dopo aver inizializzato la destinazione di rendering con cui verranno usati i pennelli e ricreare i pennelli ogni volta che la destinazione di rendering deve essere ricreata. Per altre informazioni sulle risorse, vedere Panoramica delle risorse.

La figura seguente mostra esempi di ognuno dei diversi tipi di pennello.

illustrazione degli effetti visivi da pennelli a tinta unita, pennelli sfumature lineari, pennelli sfumature radiali e pennelli bitmap

Nozioni di base sul colore

Prima di disegnare con un pennello con ID2D1SolidColorBrush o sfumatura, è necessario scegliere i colori. In Direct2D i colori sono rappresentati dalla struttura D2D1_COLOR_F (che in realtà è solo un nuovo nome per la struttura usata da Direct3D, D3DCOLORVALUE).

Prima di Windows 8, D2D1_COLOR_F usa la codifica sRGB. La codifica sRGB divide i colori in quattro componenti: rosso, verde, blu e alfa. Ogni componente è rappresentato da un valore a virgola mobile con un intervallo normale compreso tra 0,0 e 1,0. Il valore 0,0 indica l'assenza completa del colore specifico, mentre il valore 1,0 indica che il colore è completamente presente. Per il componente alfa, 0,0 rappresenta un colore completamente trasparente e 1,0 rappresenta un colore completamente opaco.

A partire da Windows 8, D2D1_COLOR_F accetta anche la codifica scRGB. scRGB è un superset di che consente valori di colore superiori a 1,0 e inferiori a 0,0.

Per definire un colore, è possibile usare la struttura D2D1_COLOR_F e inizializzare manualmente i relativi campi oppure usare la classe D2D1::ColorF per creare il colore. La classe ColorF fornisce diversi costruttori per la definizione dei colori. Se il valore alfa non viene specificato nei costruttori, per impostazione predefinita è 1.0.

  • Utilizzare il costruttore ColorF(Enum, FLOAT) per specificare un colore predefinito e un valore del canale alfa. Un valore del canale alfa è compreso tra 0,0 e 1,0, dove 0,0 rappresenta un colore completamente trasparente e 1,0 rappresenta un colore completamente opaco. La figura seguente mostra diversi colori predefiniti e i relativi equivalenti esadecimali. Per un elenco completo dei colori predefiniti, vedere la sezione Costanti Color della classe ColorF .

    illustrazione dei colori predefiniti

    L'esempio seguente crea un colore predefinito e lo usa per specificare il colore di un OGGETTO ID2D1SolidColorBrush.

hr = m_pRenderTarget->CreateSolidColorBrush(
    D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
    &m_pBlackBrush
    );
  • Utilizzare il costruttore ColorF(FLOAT, FLOAT, FLOAT, FLOAT) per specificare un colore nella sequenza di un rosso, verde, blu e alfa, in cui ogni elemento ha un valore compreso tra 0,0 e 1,0.

    Nell'esempio seguente vengono specificati i valori rosso, verde, blu e alfa per un colore.

    ID2D1SolidColorBrush *pGridBrush = NULL;
    hr = pCompatibleRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
        &pGridBrush
        );
  • Usare il costruttore ColorF(UINT32, FLOAT) per specificare il valore esadecimale di un colore e un valore alfa, come illustrato nell'esempio seguente.
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),  
        &m_pYellowGreenBrush
        );

Modalità alfa

Indipendentemente dalla modalità alfa della destinazione di rendering con cui si usa un pennello, i valori D2D1_COLOR_F vengono sempre interpretati come alfa retta.

Uso dei pennelli a tinta unita

Per creare un pennello a tinta unita, chiamare il metodo ID2D1RenderTarget::CreateSolidColorBrush , che restituisce un valore HRESULT e un oggetto ID2D1SolidColorBrush . La figura seguente mostra un quadrato tracciato con un pennello di colore nero e disegnato con un pennello a tinta unita con il valore di colore 0x9ACD32.

illustrazione di un quadrato dipinto con un pennello a tinta unita

Il codice seguente illustra come creare e usare un pennello colore nero e un pennello con un valore di colore di 0x9ACD32 per riempire e disegnare questo quadrato.

    ID2D1SolidColorBrush *m_pBlackBrush;
    ID2D1SolidColorBrush *m_pYellowGreenBrush;
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
        &m_pBlackBrush
        );
}

// Create a solid color brush with its rgb value 0x9ACD32.
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),  
        &m_pYellowGreenBrush
        );
}
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pYellowGreenBrush);
m_pRenderTarget->DrawRectangle(&rcBrushRect, m_pBlackBrush, 1, NULL);

A differenza di altri pennelli, la creazione di un OGGETTO ID2D1SolidColorBrush è un'operazione relativamente poco costosa. È possibile creare oggetti ID2D1SolidColorBrush ogni volta che si esegue il rendering senza alcun impatto sulle prestazioni. Questo approccio non è consigliato per i pennelli sfumatura o bitmap.

Uso di pennelli sfumato lineare

Un oggetto ID2D1LinearGradientBrush disegna un'area con una sfumatura lineare definita lungo una linea, l'asse delle sfumature. Specificare i colori della sfumatura e la relativa posizione lungo l'asse delle sfumature usando oggetti ID2D1GradientStop . È anche possibile modificare l'asse delle sfumature, che consente di creare sfumature orizzontali e verticali e di invertire la direzione della sfumatura. Per creare un pennello sfumatura lineare, chiamare il metodo ID2D1RenderTarget::CreateLinearGradientBrush .

La figura seguente mostra un quadrato disegnato con un oggetto ID2D1LinearGradientBrush con due colori predefiniti, "Giallo" e "ForestGreen".

illustrazione di un quadrato dipinto con un pennello sfumato lineare di verde giallo e foresta

Per creare la sfumatura illustrata nella figura precedente, completare questi passaggi:

  1. Dichiarare due oggetti D2D1_GRADIENT_STOP . Ogni interruzione sfumatura specifica un colore e una posizione. Una posizione pari a 0,0 indica l'inizio della sfumatura, mentre una posizione pari a 1,0 indica la fine della sfumatura.

    Il codice seguente crea una matrice di due oggetti D2D1_GRADIENT_STOP . Il primo punto specifica il colore "Giallo" in una posizione 0 e il secondo punto specifica il colore "ForestGreen" nella posizione 1.

    // Create an array of gradient stops to put in the gradient stop
    // collection that will be used in the gradient brush.
    ID2D1GradientStopCollection *pGradientStops = NULL;

    D2D1_GRADIENT_STOP gradientStops[2];
    gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
    gradientStops[0].position = 0.0f;
    gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
    gradientStops[1].position = 1.0f;
  1. Creare un oggetto ID2D1GradientStopCollection. Nell'esempio seguente viene chiamato CreateGradientStopCollection, passando la matrice di oggetti D2D1_GRADIENT_STOP , il numero di interruzioni sfumature (2), D2D1_GAMMA_2_2 per l'interpolazione e D2D1_EXTEND_MODE_CLAMP per la modalità di estensione.
    // Create the ID2D1GradientStopCollection from a previously
    // declared array of D2D1_GRADIENT_STOP structs.
    hr = m_pRenderTarget->CreateGradientStopCollection(
        gradientStops,
        2,
        D2D1_GAMMA_2_2,
        D2D1_EXTEND_MODE_CLAMP,
        &pGradientStops
        );
  1. Creare id2D1LinearGradientBrush. L'esempio seguente chiama il metodo CreateLinearGradientBrush e lo passa alle proprietà del pennello sfumatura lineare che contengono il punto iniziale in corrispondenza di (0, 0) e il punto finale in corrispondenza (150, 150) e l'interruzione della sfumatura creata nel passaggio precedente.
    // The line that determines the direction of the gradient starts at
    // the upper-left corner of the square and ends at the lower-right corner.

    if (SUCCEEDED(hr))
    {
        hr = m_pRenderTarget->CreateLinearGradientBrush(
            D2D1::LinearGradientBrushProperties(
                D2D1::Point2F(0, 0),
                D2D1::Point2F(150, 150)),
            pGradientStops,
            &m_pLinearGradientBrush
            );
    }
  1. Usare ID2D1LinearGradientBrush. Nell'esempio di codice seguente viene usato il pennello per riempire un rettangolo.
    m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);

Altre informazioni sulle interruzioni sfumature

Il D2D1_GRADIENT_STOP è il blocco predefinito di base di un pennello sfumato. Un punto di interruzione sfumatura specifica il colore e la posizione lungo l'asse delle sfumature. Valore della posizione del gradiente compreso tra 0,0 e 1,0. Più vicino è a 0,0, più vicino il colore è all'inizio della sfumatura; più vicino è a 1,0, più vicino il colore è alla fine della sfumatura.

Nella figura seguente vengono evidenziate le interruzioni sfumature. Il cerchio contrassegna la posizione delle interruzioni sfumature e una linea tratteggiata mostra l'asse delle sfumature.

illustrazione di un pennello sfumato lineare con quattro stop lungo l'asse

La prima interruzione sfumatura specifica il colore giallo in una posizione di 0,0. La seconda interruzione sfumatura specifica il colore rosso in una posizione di 0,25. Da sinistra a destra lungo l'asse delle sfumature, i colori tra questi due si arresta gradualmente da giallo a rosso. La terza interruzione sfumatura specifica il colore blu in una posizione di 0,75. I colori tra il secondo e il terzo gradiente cambiano gradualmente da rosso a blu. La quarta interruzione sfumatura specifica il verde lime in una posizione di 1,0. I colori tra il terzo e il quarto gradiente cambiano gradualmente da blu a verde lime.

Asse delle sfumature

Come accennato in precedenza, le interruzioni sfumature di un pennello sfumato lineare vengono posizionate lungo una linea, l'asse delle sfumature. È possibile specificare l'orientamento e le dimensioni della riga utilizzando i campi startPoint e endPoint della struttura D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES quando si crea un pennello sfumato lineare. Dopo aver creato un pennello, è possibile regolare l'asse delle sfumature chiamando i metodi SetStartPoint e SetEndPoint del pennello. Modificando il punto iniziale e il punto finale del pennello, è possibile creare sfumature orizzontali e verticali, invertire la direzione della sfumatura e altro ancora.

Nella figura seguente, ad esempio, il punto iniziale è impostato su (0,0) e il punto finale su (150, 50); in questo modo viene creata una sfumatura diagonale che inizia nell'angolo superiore sinistro e si estende all'angolo inferiore destro dell'area da disegnare. Quando si imposta il punto iniziale su (0, 25) e il punto finale su (150, 25), viene creata una sfumatura orizzontale. Analogamente, l'impostazione del punto iniziale su (75, 0) e il punto finale su (75, 50) crea una sfumatura verticale. L'impostazione del punto iniziale su (0, 50) e il punto finale su (150, 0) crea una sfumatura diagonale che inizia nell'angolo inferiore sinistro e si estende all'angolo superiore destro dell'area da disegnare.

illustrazione di quattro diversi assi sfumato sullo stesso rettangolo

Uso di pennelli sfumato radiali

A differenza di un OGGETTO ID2D1LinearGradientBrush, che fonde due o più colori lungo un asse delle sfumature, un oggetto ID2D1RadialGradientBrush disegna un'area con una sfumatura radiale che fonde due o più colori su un'ellisse. Mentre id2D1LinearGradientBrush definisce l'asse delle sfumature con un punto iniziale e un punto finale, un OGGETTO ID2D1RadialGradientBrush ne definisce l'ellisse sfumatura specificando un'ellisse centrale, orizzontale e verticale e un offset di origine sfumatura.

Analogamente a un ID2D1LinearGradientBrush, un OGGETTO ID2D1RadialGradientBrush usa un oggetto ID2D1GradientStopCollection per specificare i colori e le posizioni nella sfumatura.

La figura seguente mostra un cerchio disegnato con id2D1RadialGradientBrush. Il cerchio ha due punti di sfumatura: il primo specifica un colore predefinito "Giallo" in una posizione di 0,0 e il secondo specifica un colore predefinito "ForestGreen" in una posizione di 1,0. La sfumatura ha un centro di (75, 75), una differenza di origine sfumatura di (0, 0) e un raggio x e y di 75.

illustrazione di un cerchio dipinto con un pennello sfumato radiale

Gli esempi di codice seguenti illustrano come disegnare questo cerchio con un oggetto ID2D1RadialGradientBrush con due punti di interruzione di colore: "Giallo" in una posizione di 0,0 e "ForestGreen" in una posizione di 1,0. Analogamente alla creazione di un oggetto ID2D1LinearGradientBrush, l'esempio chiama CreateGradientStopCollection per creare un oggetto ID2D1GradientStopCollection da una matrice di interruzioni sfumature.

// Create an array of gradient stops to put in the gradient stop
// collection that will be used in the gradient brush.
ID2D1GradientStopCollection *pGradientStops = NULL;

D2D1_GRADIENT_STOP gradientStops[2];
gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
gradientStops[0].position = 0.0f;
gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
gradientStops[1].position = 1.0f;
// Create the ID2D1GradientStopCollection from a previously
// declared array of D2D1_GRADIENT_STOP structs.
hr = m_pRenderTarget->CreateGradientStopCollection(
    gradientStops,
    2,
    D2D1_GAMMA_2_2,
    D2D1_EXTEND_MODE_CLAMP,
    &pGradientStops
    );

Per creare un oggetto ID2D1RadialGradientBrush, utilizzare il metodo ID2D1RenderTarget::CreateRadialGradientBrush . CreateRadialGradientBrush accetta tre parametri. Il primo parametro, un D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES specifica il centro, l'offset dell'origine sfumatura e il raggio orizzontale e verticale della sfumatura. Il secondo parametro è un oggetto ID2D1GradientStopCollection che descrive i colori e le relative posizioni nella sfumatura e il terzo parametro è l'indirizzo del puntatore che riceve il nuovo riferimento ID2D1RadialGradientBrush . Alcuni overload accettano un parametro aggiuntivo, una struttura D2D1_BRUSH_PROPERTIES che specifica un valore di opacità e una trasformazione da applicare al nuovo pennello.

L'esempio seguente chiama CreateRadialGradientBrush, passando la matrice di interruzioni sfumature e le proprietà del pennello sfumato radiale con il valore centrale impostato su (75, 75), il gradientOriginOffset impostato su (0, 0) e radiusX e radiusY entrambi impostati su 75.

// The center of the gradient is in the center of the box.
// The gradient origin offset was set to zero(0, 0) or center in this case.
if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateRadialGradientBrush(
        D2D1::RadialGradientBrushProperties(
            D2D1::Point2F(75, 75),
            D2D1::Point2F(0, 0),
            75,
            75),
        pGradientStops,
        &m_pRadialGradientBrush
        );
}

Nell'esempio finale viene utilizzato il pennello per riempire un'ellisse.

m_pRenderTarget->FillEllipse(ellipse, m_pRadialGradientBrush);
m_pRenderTarget->DrawEllipse(ellipse, m_pBlackBrush, 1, NULL);

Configurazione di una sfumatura radiale

Valori diversi per center, gradientOriginOffset, radiusX e/o radiusY producono sfumature diverse. La figura seguente mostra diverse sfumature radiali con offset di origine sfumatura diversi, creando l'aspetto della luce illuminando i cerchi da diverse angolazioni.

illustrazione dello stesso cerchio disegnato con pennelli sfumato radiali con offset di origine diversi

Uso dei pennelli bitmap

Id2D1BitmapBrush disegna un'area con una bitmap (rappresentata da un oggetto ID2D1Bitmap).

La figura seguente mostra un quadrato dipinto con una bitmap di una pianta.

illustrazione di un quadrato dipinto con bitmap pianta

Gli esempi seguenti illustrano come disegnare questo quadrato con id2D1BitmapBrush.

Il primo esempio inizializza un OGGETTO ID2D1Bitmap da usare con il pennello. ID2D1Bitmap viene fornito da un metodo helper, LoadResourceBitmap, definito altrove nell'esempio.

// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
    hr = LoadResourceBitmap(
        m_pRenderTarget,
        m_pWICFactory,
        L"FERN",
        L"Image",
        &m_pBitmap
        );
}

Per creare il pennello bitmap, chiamare il metodo ID2D1RenderTarget::CreateBitmapBrush e specificare id2D1Bitmap con cui disegnare. Il metodo restituisce un valore HRESULT e un oggetto ID2D1BitmapBrush . Alcuni overload CreateBitmapBrush consentono di specificare opzioni aggiuntive accettando un D2D1_BRUSH_PROPERTIES e una struttura D2D1_BITMAP_BRUSH_PROPERTIES .

if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateBitmapBrush(
        m_pBitmap,
        &m_pBitmapBrush
        );
}

Nell'esempio seguente viene usato il pennello per riempire un rettangolo.

m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);

Configurazione delle modalità di estensione

In alcuni casi, la sfumatura di un pennello sfumato o la bitmap per un pennello bitmap non riempie completamente l'area da disegnare.

  • Quando ciò si verifica per un oggetto ID2D1BitmapBrush, Direct2D usa le impostazioni della modalità di estensione orizzontale del pennello (SetExtendModeX) e verticale (SetExtendModeY) per determinare come riempire l'area rimanente.

  • Quando ciò si verifica per un pennello sfumato, Direct2D determina come riempire l'area rimanente usando il valore del parametro D2D1_EXTEND_MODE specificato quando è stato chiamato CreateGradientStopCollection per creare l'ID2D1GradientStopCollection del pennello sfumato.

La figura seguente mostra i risultati di ogni possibile combinazione delle modalità di estensione per un oggetto ID2D1BitmapBrush: D2D1_EXTEND_MODE_CLAMP (CLAMP), D2D1_EXTEND_MODE_WRAP (WRAP) e D2D1_EXTEND_MIRROR (MIRROR).

illustrazione di un'immagine originale e delle immagini risultanti da varie modalità di estensione

Nell'esempio seguente viene illustrato come impostare le modalità x-and-extend del pennello bitmap su D2D1_EXTEND_MIRROR. Disegna quindi il rettangolo con ID2D1BitmapBrush.

m_pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_MIRROR);
m_pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_MIRROR);

m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);

Produce output come illustrato nella figura seguente.

illustrazione di un'immagine originale e dell'immagine risultante dopo il mirroring della direzione x e della direzione y

Trasformazione dei pennelli

Quando si disegna con un pennello, disegna nello spazio delle coordinate della destinazione di rendering. I pennelli non si posizionano automaticamente per allinearsi con l'oggetto disegnato; per impostazione predefinita, iniziano a disegnare all'origine (0, 0) della destinazione di rendering.

È possibile "spostare" la sfumatura definita da un oggetto ID2D1LinearGradientBrush in un'area di destinazione impostando il punto iniziale e il punto finale. Analogamente, è possibile spostare la sfumatura definita da un OGGETTO ID2D1RadialGradientBrush modificandone il centro e il raggio.

Per allineare il contenuto di un oggetto ID2D1BitmapBrush all'area da disegnare, è possibile utilizzare il metodo SetTransform per convertire la bitmap nella posizione desiderata. Questa trasformazione influisce solo sul pennello; non influisce su altri contenuti disegnati dalla destinazione di rendering.

Le illustrazioni seguenti illustrano l'effetto dell'uso di un oggetto ID2D1BitmapBrush per riempire un rettangolo situato in (100, 100). La figura a sinistra mostra il risultato del riempimento del rettangolo senza trasformare il pennello: la bitmap viene disegnata all'origine della destinazione di rendering. Di conseguenza, solo una parte della bitmap viene visualizzata nel rettangolo. La figura a destra mostra il risultato della trasformazione di ID2D1BitmapBrush in modo che il relativo contenuto venga spostato a destra e 50 pixel verso il basso. La bitmap ora riempie il rettangolo.

illustrazione di un quadrato dipinto con un pennello bitmap senza trasformare il pennello e trasformando il pennello

Il codice seguente illustra come eseguire questa operazione. Applicare prima una conversione all'oggetto ID2D1BitmapBrush, spostando il pennello di 50 pixel lungo l'asse x e 50 pixel verso il basso lungo l'asse y. Usare quindi ID2D1BitmapBrush per riempire il rettangolo con l'angolo superiore sinistro in corrispondenza (100, 100) e l'angolo inferiore destro in corrispondenza di (200, 200).

// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
    hr = LoadResourceBitmap(
        m_pRenderTarget,
        m_pWICFactory,
        L"FERN",
        L"Image",
        &m_pBitmap
        );
   
}

if (SUCCEEDED(hr))
{
    hr = m_pRenderTarget->CreateBitmapBrush(
        m_pBitmap,
        &m_pBitmapBrush
        );
}

D2D1_RECT_F rcTransformedBrushRect = D2D1::RectF(100, 100, 200, 200);

// Demonstrate the effect of transforming a bitmap brush.
m_pBitmapBrush->SetTransform(
     D2D1::Matrix3x2F::Translation(D2D1::SizeF(50,50))
     );

// To see the content of the rcTransformedBrushRect, comment
// out this statement.
m_pRenderTarget->FillRectangle(
     &rcTransformedBrushRect, 
     m_pBitmapBrush
     );

m_pRenderTarget->DrawRectangle(rcTransformedBrushRect, m_pBlackBrush, 1, NULL);