65.9K
CodeProject 正在变化。 阅读更多。
Home

Direct2D 教程 第 4 部分:渐变画笔

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2020年9月17日

CPOL

3分钟阅读

viewsIcon

10341

downloadIcon

313

Direct2D 教程:线性与径向渐变画笔

目录

示例代码托管在 Github 上。

引言

在本文中,我们将学习如何在 Direct2D 中使用线性与径向渐变颜色进行绘制。阅读本文的前提是您需要了解如何设置 RenderTarget。如果您还不清楚 RenderTarget 是什么,请先阅读 RenderTarget 文章,然后再回来阅读本文。

线性渐变

Linear Gradient Image

要创建线性渐变画笔,必须定义一个渐变停止数组。一个渐变停止由其位置和颜色组成。第一个渐变停止位置应为 0,最后一个为 1。然后调用 CreateGradientStopCollection()stops[] 创建 ID2D1GradientStopCollection,然后调用 CreateLinearGradientBrush() 创建 ID2D1LinearGradientBrush

ComPtr<ID2D1LinearGradientBrush> m_LinearBrush;

void CD2DGradientDlg::CreateLinearGradientBrush()
{
    D2D1_GRADIENT_STOP stops[] =
    {
        { 0.0f, ColorF(ColorF::Cyan) },
        { 1.0f, ColorF(ColorF::DarkBlue) }
    };

    ComPtr<ID2D1GradientStopCollection> collection;

    HR(m_Target->CreateGradientStopCollection(stops, _countof(stops),
        collection.GetAddressOf()));

    D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};

    HR(m_Target->CreateLinearGradientBrush(props, collection.Get(),
        m_LinearBrush.ReleaseAndGetAddressOf()));
}

在创建渐变画笔后,我们可以使用它进行绘制。首先,使用 SetStartPoint()SetEndPoint() 设置起始点和结束点。或者,起始点和结束点可以在上面的画笔创建代码中的 D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES 结构中指定。我们的渐变从位置 (0,0) 开始,到对话框的宽度和高度的位置结束,这意味着渐变是对角线。

void CD2DGradientDlg::DrawLinearGradientRect()
{
    auto size = m_Target->GetSize();

	m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));

    m_LinearBrush->SetEndPoint(Point2F(size.width, size.height));

    auto r = RectF(0.0f, 0.0f, size.width, size.height);

    m_Target->FillRectangle(r, m_LinearBrush.Get());
}

彩虹线性渐变

接下来,我们将创建一个水平线性渐变,使用彩虹颜色(意味着超过 2 种颜色)。之前的渐变停止被注释掉,并指定了包含 4 种颜色的新的停止。第 2 个和第 3 个停止分别位于 0.330.66。这些停止之间的任何颜色都将进行线性插值。

ComPtr<ID2D1LinearGradientBrush> m_LinearBrush;

void CD2DGradientDlg::CreateLinearGradientBrush()
{
    /*
    D2D1_GRADIENT_STOP stops[] =
    {
        { 0.0f, ColorF(ColorF::Cyan) },
        { 1.0f, ColorF(ColorF::DarkBlue) }
    };
    */
    D2D1_GRADIENT_STOP stops[] =
    {
        { 0.0f, ColorF(227.0f / 255.0f, 9.0f / 255.0f, 64.0f / 255.0f, 1.0f) },
        { 0.33f, ColorF(231.0f / 255.0f, 215.0f / 255.0f, 2.0f / 255.0f, 1.0f) },
        { 0.66f, ColorF(15.0f / 255.0f, 168.0f / 255.0f, 149.0f / 255.0f, 1.0f) },
        { 1.0f, ColorF(19.0f / 255.0f, 115.0f / 255.0f, 232.0f / 255.0f, 1.0f) }
    };
    ComPtr<ID2D1GradientStopCollection> collection;

    HR(m_Target->CreateGradientStopCollection(stops, _countof(stops),
        collection.GetAddressOf()));

    D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};

    HR(m_Target->CreateLinearGradientBrush(props, collection.Get(),
        m_LinearBrush.ReleaseAndGetAddressOf()));
}

在绘制中,代码保持不变,除了将结束点的 y 坐标更改为 0 以创建水平渐变。

m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));

m_LinearBrush->SetEndPoint(Point2F(size.width, 0.0f));

这是我们创建的彩虹渐变。

Rainbow Linear Gradient Image

彩虹线性渐变文本

在本节中,我们将学习如何将渐变画笔应用于文本。在 Direct2D 中,画笔可以应用于接受画笔参数的任何绘图函数。要使用 DrawText 显示文本,必须从 DirectWrite 工厂创建设备无关资源 IDWriteTextFormat,并使用 CreateTextFormat()

ComPtr<IDWriteTextFormat> m_TextFormat;

void CD2DAffineTransformDlg::CreateDeviceIndependentResources()
{
    HR(FactorySingleton::GetDWriteFactory()->CreateTextFormat(L"Arial Black",
        nullptr, DWRITE_FONT_WEIGHT_ULTRA_BOLD, DWRITE_FONT_STYLE_NORMAL,
        DWRITE_FONT_STRETCH_NORMAL, 40, L"",
        m_TextFormat.ReleaseAndGetAddressOf()));
}

要绘制文本,将上述绘图代码中的 FillRectangle() 替换为 DrawText()

void CD2DGradientDlg::DrawLinearGradientText()
{
    auto size = m_Target->GetSize();

    m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));

    m_LinearBrush->SetEndPoint(Point2F(size.width, 0.0f));

    auto r = RectF(0.0f, 0.0f, size.width, size.height);

    m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), 
        &r, m_LinearBrush.Get());
}

这是渐变文本输出。

Rainbow Linear Gradient Text Image

径向渐变

Radial Gradient Image

在本节中,我们将展示如何创建和使用径向渐变画笔。其创建函数几乎与线性渐变画笔相同,只是函数与径向渐变画笔相关。请注意,在 D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES 中,设置了其中心点。

ComPtr<ID2D1RadialGradientBrush> m_RadialBrush;

void CD2DGradientDlg::CreateRadialGradientBrush()
{
    D2D1_GRADIENT_STOP stops[] =
    {
        { 0.0f, ColorF(ColorF::Cyan) },
        { 1.0f, ColorF(ColorF::DarkBlue) }
    };

    ComPtr<ID2D1GradientStopCollection> collection;
    HR(m_Target->CreateGradientStopCollection(stops, _countof(stops), 
        collection.GetAddressOf()));

    D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = {};
    props.center = Point2F(50.0f, 50.0f);
    HR(m_Target->CreateRadialGradientBrush(props, collection.Get(), 
        m_RadialBrush.ReleaseAndGetAddressOf()));
}

然后使用径向渐变画笔调用 FillRectangle()

void CD2DGradientDlg::DrawRadialGradientRect()
{
    auto size = m_Target->GetSize();
    auto radius = min(size.width, size.height);

    m_RadialBrush->SetRadiusX(radius);
    m_RadialBrush->SetRadiusY(radius);

    m_Target->FillRectangle(RectF(0.0f, 0.0f, size.width, size.height), 
        m_RadialBrush.Get());
}

径向渐变文本

Radial Gradient Text Image

要使用径向渐变画笔绘制文本,代码与线性渐变文本相同,只是将径向渐变画笔传递给 DrawText()

void CD2DGradientDlg::DrawRadialGradientText()
{
    auto size = m_Target->GetSize();
    auto radius = min(size.width, size.height);

    m_RadialBrush->SetRadiusX(radius);
    m_RadialBrush->SetRadiusY(radius);

    auto r = RectF(0.0f, 0.0f, size.width, size.height);

    m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), 
        &r, m_RadialBrush.Get());
}

演示代码

文章中显示的所有代码都放在一个单独的演示程序中。要查看特定的渐变演示,只需在 Draw() 中注释和取消注释您想要查看的函数即可。

void CD2DGradientDlg::Draw()
{
    m_Target->Clear(ColorF(ColorF::White));

    //DrawLinearGradientRect();
    //DrawLinearGradientText();
    //DrawRadialGradientRect();
    DrawRadialGradientText();
}

历史

  • 2020 年 9 月 18 日:首次发布

系列文章

© . All rights reserved.