书法字典:https://www.shufadict.com

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 ==

posted on 2012-11-22 08:41  翰墨小生  阅读(8483)  评论(2编辑  收藏  举报

导航

书法字典:https://www.shufadict.com