Direct2D教程(八)梯度色畫刷


概述

單色畫刷產生的顏色是單一的,比如一個紅色畫刷只能輸出紅色,而漸變畫刷則不同,它可以輸出多種顏色,這些顏色通常是連續的,從一個顏色平滑過渡到另一個顏色,看起來有漸變的效果。漸變畫刷又分為兩種,一種是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 ==


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM