筆刷概觀
本概觀描述如何建立和使用 ID2D1SolidColorBrush、 ID2D1LinearGradientBrush、 ID2D1RadialGradientBrush和 ID2D1BitmapBrush 物件,以純色、漸層和點陣圖繪製區域。 包含以下幾節。
必要條件
此概觀假設您已熟悉基本 Direct2D 應用程式的結構,如 建立簡單的 Direct2D 應用程式中所述。
筆刷類型
筆刷會「繪製」具有其輸出的區域。 不同的筆刷有不同類型的輸出。 Direct2D 提供四種筆刷類型: ID2D1SolidColorBrush 以純色繪製區域、 ID2D1LinearGradientBrush 與線性漸層、 ID2D1RadialGradientBrush 搭配星形漸層,以及具有點陣圖的 ID2D1BitmapBrush 。
注意
從 Windows 8 開始,您也可以使用ID2D1ImageBrush,這類似于點陣圖筆刷,但您也可以使用基本類型。
所有筆刷都繼承自 ID2D1Brush ,並共用一組通用功能 (設定和取得不透明度,以及轉換筆刷) ;它們是由 ID2D1RenderTarget 所建立,而且是裝置相依的資源:您的應用程式應該在初始化筆刷之後建立筆刷,並在轉譯目標需要重新建立時重新建立筆刷。 (如需資源的詳細資訊,請參閱 資源概觀.)
下圖顯示每個不同筆刷類型的範例。
色彩基本概念
使用 ID2D1SolidColorBrush 或漸層筆刷繪製之前,您需要選擇色彩。 在 Direct2D 中,色彩會以 D2D1_COLOR_F 結構表示 (,這實際上只是 Direct3D、 D3DCOLORVALUE) 所使用之結構的新名稱。
在Windows 8之前,D2D1_COLOR_F會使用 sRGB 編碼。 sRGB 編碼會將色彩分成四個元件:紅色、綠色、藍色和 Alpha。 每個元件都是以一般範圍為 0.0 到 1.0 的浮點值代表。 值為 0.0 時,表示完全沒有該色彩,而值為 1.0 時,則表示全部為該色彩。 就 Alpha 元件而言,0.0 代表完全透明的色彩,1.0 則代表完全不透明的色彩。
從 Windows 8 開始,D2D1_COLOR_F也接受 scRGB 編碼。 scRGB 是 的超集合,允許色彩值高於 1.0 和低於 0.0。
若要定義色彩,您可以使用 D2D1_COLOR_F結構並 自行初始化其欄位,也可以使用 D2D1::ColorF 類別來協助您建立色彩。 ColorF類別提供數個建構函式來定義色彩。 如果未在建構函式中指定 Alpha 值,則預設為 1.0。
使用 ColorF (Enum、FLOAT) 建構函式來指定預先定義的色彩和 Alpha 色板值。 Alpha 色板值的範圍從 0.0 到 1.0,其中 0.0 代表完全透明色彩,1.0 代表完全不透明色彩。 下圖顯示數個預先定義的色彩及其十六進位對等專案。 如需預先定義色彩的完整清單,請參閱 ColorF 類別的 Color 常數一節。
下列範例會建立預先定義的色彩,並使用它來指定 ID2D1SolidColorBrush的色彩。
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
&m_pBlackBrush
);
使用 ColorF (FLOAT、FLOAT、FLOAT、FLOAT) 建構函式來指定紅色、綠色、藍色和 Alpha 序列中的色彩,其中每個元素的值介於 0.0 和 1.0 之間。
下列範例會指定色彩的紅色、綠色、藍色和 Alpha 值。
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
- 使用 ColorF (UINT32、FLOAT) 建構函式來指定色彩和 Alpha 值的十六進位值,如下列範例所示。
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),
&m_pYellowGreenBrush
);
Alpha 模式
不論您使用筆刷之轉譯目標的 Alpha 模式為何, D2D1_COLOR_F 值一律會解譯為直接 Alpha。
使用純色筆刷
若要建立純色筆刷,請呼叫 ID2D1RenderTarget::CreateSolidColorBrush 方法,此方法會傳回 HRESULT 和 ID2D1SolidColorBrush 物件。 下圖顯示使用黑色筆刷繪製的方形,並使用純色筆刷繪製,其色彩值為 0x9ACD32。
下列程式碼示範如何建立和使用黑色色彩筆刷,以及色彩值為 0x9ACD32 的筆刷,以填滿並繪製此方形。
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);
不同于其他筆刷,建立 ID2D1SolidColorBrush 是相對便宜的作業。 每次轉譯時,您可能會建立 ID2D1SolidColorBrush 物件,而不會影響效能。 不建議針對漸層或點陣圖筆刷使用此方法。
使用線性漸層筆刷
ID2D1LinearGradientBrush會繪製沿著線條、漸層軸定義線性漸層的區域。 您可以使用 ID2D1GradientStop 物件,在漸層軸上指定漸層色彩及其位置。 您也可以修改漸層軸,這可讓您建立水準和垂直漸層,以及反轉漸層方向。 若要建立線性漸層筆刷,請呼叫 ID2D1RenderTarget::CreateLinearGradientBrush 方法。
下圖顯示以 ID2D1LinearGradientBrush 繪製的方形,其具有兩個預先定義的色彩「Yellow」 和 「ForestGreen」。
若要建立上圖所示的漸層,請完成下列步驟:
宣告兩 個D2D1_GRADIENT_STOP 物件。 每個漸層停駐點都會指定色彩和位置。 0.0 的位置表示漸層的開頭,而 1.0 的位置則表示漸層的結尾。
下列程式碼會建立兩個 D2D1_GRADIENT_STOP 物件的陣列。 第一個停駐點指定位置 0 的色彩 「Yellow」,而第二個停駐點指定位置 1 的色彩 「ForestGreen」。
// 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;
- 建立 ID2D1GradientStopCollection。 下列範例會呼叫 CreateGradientStopCollection、傳入 D2D1_GRADIENT_STOP 物件的陣列、 (2) 的漸層停駐點數目、 插入D2D1_GAMMA_2_2 ,以及擴充模式 的D2D1_EXTEND_MODE_CLAMP 。
// 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
);
- 建立 ID2D1LinearGradientBrush。 下一個範例會呼叫 CreateLinearGradientBrush 方法,並傳遞線性漸層筆刷屬性,其中包含 (0、0) 的起點,以及 (150、150) ,以及上一個步驟中建立的漸層停駐點。
// 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
);
}
- 使用 ID2D1LinearGradientBrush。 下一個程式碼範例會使用筆刷填滿矩形。
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);
深入瞭解漸層停駐點
D2D1_GRADIENT_STOP是漸層筆刷的基本建置組塊。 漸層停駐點會指定漸層軸的色彩和位置。 漸層位置範圍介於 0.0 和 1.0 之間的值。 越接近 0.0,色彩越接近漸層的開頭;越接近 1.0,色彩越接近漸層的結尾。
下圖醒目提示漸層停駐點。 圓形會標示漸層停駐點的位置,而虛線會顯示漸層軸。
第一個漸層停駐點指定位於 0.0 位置的黃色。 第二個漸層停駐點指定位於 0.25 位置的紅色。 從左至右沿著漸層軸,這兩個停駐點之間的色彩會逐漸從黃色變更為紅色。 第三個漸層停駐點指定位於 0.75 位置的藍色。 第二個和第三個漸層停駐點之間的色彩會逐漸從紅色變更為藍色。 第四個漸層停駐點會在 1.0 的位置指定綠色綠色。 第三層和第四個漸層停駐點之間的色彩會逐漸從藍色變更為綠色。
漸層軸
如先前所述,線性漸層筆刷的漸層停駐點會沿著線條排列,也就是漸層軸。 您可以在建立線性漸層筆刷時,使用D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES結構的startPoint和endPoint欄位來指定線條的方向和大小。 建立筆刷之後,您可以呼叫筆刷的 SetStartPoint 和 SetEndPoint 方法來調整漸層軸。 藉由操作筆刷的起點和終點,您可以建立水準和垂直漸層、反轉漸層方向等等。
例如,在下圖中,起點會設定為 (0,0) ,並將端點設定為 (150,50) ;這會建立從左上角開始的對角漸層,並延伸至所繪製區域的右下角。 當您將起點設定為 (0、25) ,並將端點設定為 (150、25) 時,會建立水準漸層。 同樣地,將起點設定為 (75、0) ,並將端點設定為 (75、50) 會建立垂直漸層。 將起點設定為 (0、50) ,並將端點設定為 (150,0) 會建立從左下角開始的對角漸層,並延伸至繪製區域的右上角。
使用星形漸層筆刷
不同于在漸層軸上混合兩個或多個色彩 的 ID2D1LinearGradientBrush, ID2D1RadialGradientBrush 會使用星形漸層繪製一個區域,在橢圓形之間混合兩個或多個色彩。 雖然 ID2D1LinearGradientBrush 使用起點和終點定義其漸層軸,但 ID2D1RadialGradientBrush 藉由指定中心、水準和垂直弧度和漸層原點位移來定義其漸層橢圓形。
如同 ID2D1LinearGradientBrush, ID2D1RadialGradientBrush 會使用 ID2D1GradientStopCollection 來指定漸層中的色彩和位置。
下圖顯示以 ID2D1RadialGradientBrush繪製的圓形。 圓形有兩個漸層停駐點:第一個在 0.0 的位置指定預先定義的色彩 「Yellow」,而第二個指定 1.0 位置的預先定義色彩 「ForestGreen」。 漸層的中心 (75、75) 、 (0、0) 的漸層原點位移,以及 x 和 y 半徑為 75。
下列程式碼範例示範如何使用 ID2D1RadialGradientBrush 繪製此圓形,其色彩停駐點為 0.0,而 「ForestGreen」 位於 1.0 的位置。 與建立 ID2D1LinearGradientBrush類似,此範例會呼叫 CreateGradientStopCollection ,從漸層停駐點陣列建立 ID2D1GradientStopCollection 。
// 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
);
若要建立 ID2D1RadialGradientBrush,請使用 ID2D1RenderTarget::CreateRadialGradientBrush 方法。 CreateRadialGradientBrush會採用三個參數。 第一個參數, D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES 指定中心、漸層原點位移,以及漸層的水準和垂直弧度。 第二個參數是 ID2D1GradientStopCollection ,描述色彩及其在漸層中的位置,而第三個參數則是接收新 ID2D1RadialGradientBrush 參考的指標位址。 有些多載會採用額外的參數, D2D1_BRUSH_PROPERTIES 結構,指定要套用至新筆刷的不透明度值和轉換。
下一個範例會呼叫 CreateRadialGradientBrush、傳入漸層停駐點陣列,以及 將中心 值設定為 (75、75) 的星形漸層筆刷屬性、 將 gradientOriginOffset 設定為 (0、0) ,以及 radiusX 和 radiusY 都設定為 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
);
}
最後一個範例會使用筆刷來填滿橢圓形。
m_pRenderTarget->FillEllipse(ellipse, m_pRadialGradientBrush);
m_pRenderTarget->DrawEllipse(ellipse, m_pBlackBrush, 1, NULL);
設定星形漸層
中心、gradientOriginOffset、radiusX和/或radiusY的不同值會產生不同的漸層。 下圖顯示數個具有不同漸層原點位移的星形漸層,建立從不同角度照亮圓形的光線外觀。
使用點陣圖筆刷
ID2D1BitmapBrush會繪製以ID2D1Bitmap物件表示之點陣圖 (的區域) 。
下圖顯示以植物點陣圖繪製的方形。
下列範例示範如何使用 ID2D1BitmapBrush繪製此方形。
第一個範例會初始化 ID2D1Bitmap 以搭配筆刷使用。 ID2D1Bitmap是由範例中其他地方定義的 Helper 方法 LoadResourceBitmap 所提供。
// 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
);
}
若要建立點陣圖筆刷,請呼叫 ID2D1RenderTarget::CreateBitmapBrush 方法,並指定要繪製的 ID2D1Bitmap 。 方法會傳回 HRESULT 和 ID2D1BitmapBrush 物件。 某些 CreateBitmapBrush 多載可讓您藉由接受 D2D1_BRUSH_PROPERTIES 和 D2D1_BITMAP_BRUSH_PROPERTIES 結構來指定其他選項。
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateBitmapBrush(
m_pBitmap,
&m_pBitmapBrush
);
}
下一個範例會使用筆刷來填滿矩形。
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);
設定擴充模式
有時候,漸層筆刷或點陣圖筆刷的漸層不會完全填滿所繪製的區域。
當 ID2D1BitmapBrush發生此情況時,Direct2D 會使用筆刷的水準 (SetExtendModeX) 和垂直 (SetExtendModeY) 擴充模式設定,以決定如何填滿其餘區域。
當漸層筆刷發生這種情況時,Direct2D 會決定如何使用呼叫CreateGradientStopCollection時所指定的D2D1_EXTEND_MODE參數值來填滿其餘區域,以建立漸層筆刷的ID2D1GradientStopCollection。
下圖顯示 ID2D1BitmapBrush的每個可能擴充模式組合的結果: D2D1_EXTEND_MODE_CLAMP (CLAMP) 、 D2D1_EXTEND_MODE_WRAP (WRAP) ,以及 D2D1_EXTEND_MIRROR (MIRROR) 。
下列範例示範如何將點陣圖筆刷的 x 和 y 擴充模式設定為 D2D1_EXTEND_MIRROR。 然後,它會使用 ID2D1BitmapBrush繪製矩形。
m_pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_MIRROR);
m_pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_MIRROR);
m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);
它會產生輸出,如下圖所示。
轉換筆刷
當您使用筆刷繪製時,它會在轉譯目標的座標空間中繪製。 筆刷不會自動定位自己,使其與所繪製的物件對齊;根據預設,它們會開始在轉譯目標的原點 (0、0) 繪製。
您可以藉由設定其起點和終點,將 ID2D1LinearGradientBrush 定義的漸層「移動」至目的地區域。 同樣地,您可以藉由變更其中心與弧度來移動 ID2D1RadialGradientBrush 所定義的漸層。
若要將 ID2D1BitmapBrush 的內容對齊所繪製的區域,您可以使用 SetTransform 方法將點陣圖轉譯為所需的位置。 此轉換只會影響筆刷;它不會影響轉譯目標所繪製的任何其他內容。
下圖顯示使用 ID2D1BitmapBrush 填滿位於 (100, 100) 的矩形的效果。 左圖上的圖例顯示填滿矩形的結果,而不轉換筆刷:點陣圖是在轉譯目標的原點繪製。 因此,只有一部分的點陣圖會出現在矩形中。 右邊的圖例顯示轉換 ID2D1BitmapBrush 的結果,使其內容向右移位 50 圖元,並向下移 50 圖元。 點陣圖現在會填滿矩形。
下列程式碼示範如何完成此作業。 首先,將轉譯套用至 ID2D1BitmapBrush,將筆刷向右移動 50 圖元,沿著 X 軸往下移動 50 個圖元。 然後使用 ID2D1BitmapBrush 填滿左上角 (100、100) 和右下角的矩形, (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);