概述
單色畫刷產生的顏色是單一的,比如一個紅色畫刷只能輸出紅色,而漸變畫刷則不同,它可以輸出多種顏色,這些顏色通常是連續的,從一個顏色平滑過渡到另一個顏色,看起來有漸變的效果。漸變畫刷又分為兩種,一種是ID2D1LinearGradientBrush(線性漸變畫刷),另一種是ID2D1RadialGradientBrush(放射漸變畫刷),下圖顯示了這兩種畫刷的效果。
線性漸變畫刷
這種畫刷的顏色從一個位置線性漸變到另外一個位置,所以在創建這種畫刷之前需要確定以下兩個屬性
- 起始位置及顏色
- 終止位置及顏色
在Direct2D中,結構體D2D1_GRADIENT_STOP用來表示一個位置及其顏色,其定義如下:
struct D2D1_GRADIENT_STOP { FLOAT position; D2D1_COLOR_F color; };
其中第一個成員position表示位置,這個值得范圍必須是[0.0, 1.0]。第二個成員color表示顏色。我們用兩個這樣的結構體變量就可以表示起始/終止位置及顏色了。
在創建畫刷時,需要指定畫刷的會制范圍,如果待填充圖形的范圍大於畫刷的會制范圍,我們需要告訴D2D如何處填充超出范圍的部分。這需要通過顏色的擴展方式來指定,顏色擴展的方式用D2D1_EXTEND_MODE這個枚舉類型來表示,它的定義如下:
typedef enum { D2D1_EXTEND_MODE_CLAMP = 0, D2D1_EXTEND_MODE_WRAP = 1, D2D1_EXTEND_MODE_MIRROR = 2 } D2D1_EXTEND_MODE;
如果大家了解紋理的話,對這幾種方式一定不陌生,他們的含義如下:
- D2D1_EXTEND_MODE_CLAMP,表示按照邊緣的顏色進行擴展
- D2D1_EXTEND_MODE_WRAP,表示重復畫刷的顏色
- D2D1_EXTEND_MODE_MIRROR,也是重復畫刷的顏色,不過是以相反的方向進行,所以像鏡面效果一樣
這三種擴展方式的效果圖如下,這里,矩形的寬度是畫刷繪制范圍的2倍,也就是說,顏色的擴展是從矩形的中間開始的。
D2D1_EXTEND_MODE_CLAMP
D2D1_EXTEND_MODE_WRAP
D2D1_EXTEND_MODE_MIRROR
下面開始具體的創建步驟,首先定義兩個梯度點並指定其位置及顏色,這里第一個點位置是0,顏色是黃色,第二個點位置是1,顏色是紅色。
D2D1_GRADIENT_STOP gradientStops[2] ; gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow) ; gradientStops[0].position = 0.f ; gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::Red) ; gradientStops[1].position = 1.f ;
其次,創建梯度點集合,這個集合將作為參數用來創建梯度色畫刷,我們使用函數CreateGradientStopCollection來完成這個任務,它的定義如下:
virtual HRESULT CreateGradientStopCollection( [in] const D2D1_GRADIENT_STOP *gradientStops, UINT gradientStopsCount, D2D1_GAMMA colorInterpolationGamma, D2D1_EXTEND_MODE extendMode, [out] ID2D1GradientStopCollection **gradientStopCollection ) = 0;
參數說明:
- gradientStops,梯度點數組,也就是上面剛剛創建的。
- gradientStopsCount,梯度點個數,這里是兩個。
- colorInterpolationGamma,這個參數用來控制顏色插值的方式,有如下兩種:
typedef enum { D2D1_GAMMA_2_2 = 0, D2D1_GAMMA_1_0 = 1 } D2D1_GAMMA;
這兩種方式的效果圖如下,這里我們使用D2D1_GAMMA_2_2。
extendMode,指定顏色超出繪制范圍時如何擴展。這里我們使用D2D1_EXTEND_MODE_CLAMP,也就是按照邊緣色擴展。
gradientStopCollection,這個參數用來接收創建后的梯度點集合。
創建梯度點集合的代碼如下,所有參數前面均已說明。
// Create gradient stops collection ID2D1GradientStopCollection* pGradientStops = NULL ; hr = pRenderTarget->CreateGradientStopCollection( gradientStops, 2, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &pGradientStops ) ; if (FAILED(hr)) { MessageBox(NULL, "Create gradient stops collection failed!", "Error", 0); }
最后,創建線性梯度色畫刷。我們使用函數CreateLinearGradientBrush,看看它的定義:
virtual HRESULT CreateLinearGradientBrush( [in] const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties, [in, optional] const D2D1_BRUSH_PROPERTIES *brushProperties, [in] ID2D1GradientStopCollection *gradientStopCollection, [out] ID2D1LinearGradientBrush **linearGradientBrush ) = 0;
參數說明:
- linearGradientBrushProperties,用來指定畫刷的起始位置和終止位置。
- brushProperties,這是個可選參數,用來指定畫刷的透明度及變換矩陣,這里我們指定其為NULL。
- gradientStopCollection,梯度點集合,一般我們指定兩個即可,分別是起始位置和終止位置。
- linearGradientBrush,用來接收創建好的畫刷。
具體代碼如下,畫刷的起始和結束位置分別對應矩形的左上角點和右下角點。
// Create a linear gradient brush to fill in the rectangle hr = pRenderTarget->CreateLinearGradientBrush( D2D1::LinearGradientBrushProperties( D2D1::Point2F(roundRect.rect.left, roundRect.rect.top), D2D1::Point2F(roundRect.rect.right, roundRect.rect.bottom)), pGradientStops, &pLinearGradientBrush ) ; if (FAILED(hr)) { MessageBox(hWnd, "Create linear gradient brush failed!", "Error", 0) ; return ; }
效果圖
放射漸變畫刷
這種畫刷的顏色從一個中心點向周圍擴散,呈放射狀,這可能也是其名字的由來吧。創建這種畫刷的步驟和上面一樣,先創建梯度點及其集合,然后使用函數CreateRadialGradientBrush創建畫刷,關於如何創建梯度點及其集合,前面已經說了,所以這里只看創建畫刷的步驟。函數CreateRadialGradientBrush的定義如下:
HRESULT CreateRadialGradientBrush( const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES &radialGradientBrushProperties, [in] ID2D1GradientStopCollection *gradientStopCollection, [out] ID2D1RadialGradientBrush **radialGradientBrush );
參數說明:
- radialGradientBrushProperties,畫刷屬性,用以下結構體來表示:
struct D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES { D2D1_POINT_2F center; D2D1_POINT_2F gradientOriginOffset; FLOAT radiusX; FLOAT radiusY; };
-
- center, 梯度中心點,從此點開始向外圍放射
- gradientOriginOffset,起始點偏移,一般設置為(0,0)
- radiusX,橢圓x軸長度
- radiusY,橢圓y軸長度
- gradientStopCollection,梯度點集合
- radialGradientBrush,用來接收創建后的畫刷
代碼如下:
創建橢圓
D2D1_ELLIPSE g_Ellipse = D2D1::Ellipse(D2D1::Point2F(300, 300), 200, 150);
創建畫刷,這里我們指定起始顏色為黃色,終止顏色為藍色,填充圖形為橢圓,顏色從橢圓的中心向周圍發散。
// Create a linear gradient brush to fill in the rectangle hr = pRenderTarget->CreateRadialGradientBrush( D2D1::RadialGradientBrushProperties( g_Ellipse.point, D2D1::Point2F(0, 0), g_Ellipse.radiusX, g_Ellipse.radiusY), pGradientStops, &pRadialGradientBrush ) ; if (FAILED(hr)) { MessageBox(hWnd, "Create linear gradient brush failed!", "Error", 0) ; return ; }
效果圖
使用漸變畫刷配合橢圓及圓角矩形可以創建出非常漂亮的Button控件,如果你喜歡自定義控件,不妨試一試。
== Happy Coding ==