Direct2D 教程 第 2 部分:基本形状





5.00/5 (7投票s)
关于绘制基本形状的 Direct2D 教程
目录
示例代码托管在 Github 上。
引言
在本文中,我们将探讨如何在 Direct2D 中绘制线条和基本形状。 本文的前提是设置 RenderTarget
的知识。 如果您不了解 RenderTarget
是什么,请先阅读 RenderTarget 文章,然后再回来阅读本文。
笔触样式
为了绘制形状,需要一个辅助函数 CreateStrokeStyle()
来创建 ID2D1StrokeStyle
以定义端点和连接样式。 ID2D1StrokeStyle
是一个与设备无关的资源。 在 StrokeStyleProperties
构造函数中,起始端点、结束端点和虚线端点的样式均为圆形,如 3 个 D2D1_CAP_STYLE_ROUND
参数所示。 指定的虚线端点样式未被使用,因为笔触样式没有任何虚线,由 D2D1_DASH_STYLE_SOLID
指定,并且线条连接样式为圆形,由 D2D1_LINE_JOIN_ROUND
指示。 读者可以通过修改 CreateStrokeStyle()
来尝试其他端点和连接样式。
ComPtr<ID2D1StrokeStyle> CD2DShapesDlg::CreateStrokeStyle()
{
ComPtr<ID2D1StrokeStyle> strokeStyle;
HR(FactorySingleton::GetGraphicsFactory()->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_ROUND,
D2D1_CAP_STYLE_ROUND,
D2D1_CAP_STYLE_ROUND,
D2D1_LINE_JOIN_ROUND,
0.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
strokeStyle.GetAddressOf()
));
return strokeStyle;
}
纯色画刷
使用 CreateSolidColorBrush()
创建用于笔触和填充的两个纯色画刷。 由于画刷是与设备相关的资源,因此应在 CreateDeviceResources()
内部创建它们。 它的颜色可以使用 SetColor()
成员函数动态更改,您稍后会看到。
void CD2DShapesDlg::CreateDeviceResources()
{
HR(m_Target->CreateSolidColorBrush(ColorF(ColorF::Crimson),
m_StrokeBrush.ReleaseAndGetAddressOf()));
HR(m_Target->CreateSolidColorBrush(ColorF(ColorF::Yellow),
m_FillBrush.ReleaseAndGetAddressOf()));
}
Line
使用 DrawLine()
从一个起点和一个终点绘制一条线。 线条粗细指定为 8
像素。
m_StrokeBrush->SetColor(ColorF(ColorF::Black));
ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
m_Target->DrawLine(
Point2F(10.0f, 40.0f),
Point2F(110.0f, 40.0f),
m_StrokeBrush.Get(),
8.0f,
stroke.Get());
矩形
笔触画刷和填充画刷分别设置为红色和黄色。 使用一个 rect
变量来指定矩形边界。 矩形的轮廓使用 DrawRectangle()
绘制,并使用 FillRectangle()
填充黄色。 DrawRectangle()
的第三个参数是线条粗细,为 10
像素。
ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_RECT_F rect = RectF(10, 10, 210, 160);
m_Target->DrawRectangle(
rect,
m_StrokeBrush.Get(),
16.0f,
stroke.Get());
m_Target->FillRectangle(
rect,
m_FillBrush.Get());
圆角矩形
我经常使用圆角矩形来绘制文章中使用的框图,因为矩形看起来更美观。 Direct2D 的创建者也知道圆角矩形是一种常见的绘图原语,并决定为其用户提供这种便利。 使用一个 roundedRect
变量来指定矩形边界(来自 rect
变量),以及圆角的 x 和 y 半径。 轮廓和填充分别使用 DrawRoundedRectangle()
和 FillRoundedRectangle()
完成。 DrawRoundedRectangle()
的第三个参数是线条粗细,为 10
像素。
ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_RECT_F rect = RectF(10, 10, 210, 160);
const D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect(
rect,
10.f,
10.f
);
m_Target->DrawRoundedRectangle(
roundedRect,
m_StrokeBrush.Get(),
16.0f,
stroke.Get());
m_Target->FillRoundedRectangle(
roundedRect,
m_FillBrush.Get());
三角形
不幸的是,Direct2D 中没有绘制三角形的函数。 我们可以随时使用 ID2D1PathGeometry
来创建我们想要的任何形状。 GenTriangleGeometry()
是一个辅助函数,用于创建然后绘制的三角形几何图形。 ID2D1PathGeometry
变量使用 CreatePathGeometry()
创建。 然后,该 ID2D1PathGeometry
变量 m_pPathGeometry
用于打开 ID2D1GeometrySink
变量 pSink
。 在 pSink
上调用 BeginFigure()
以指定第一个点和要填充的绘图。 使用来自 2 个点的 AddLine
添加 2 个线段图元。 D2D1_FIGURE_END_CLOSED
告诉 EndFigure()
用一条线闭合第一个点和最后一个点。 如果您已经通过指定最后一个点与第一个点相同来自己闭合了第一个点和最后一个点,并且您可能不希望 EndFigure()
在它们之间绘制一条线,则应指定 D2D1_FIGURE_END_OPEN
。
ComPtr<ID2D1PathGeometry> CD2DShapesDlg::GenTriangleGeometry
(D2D1_POINT_2F pt1, D2D1_POINT_2F pt2, D2D1_POINT_2F pt3)
{
ID2D1GeometrySink* pSink = NULL;
HRESULT hr = S_OK;
ComPtr<ID2D1PathGeometry> m_pPathGeometry;
// Create a path geometry.
if (SUCCEEDED(hr))
{
hr = FactorySingleton::GetGraphicsFactory()->CreatePathGeometry
(m_pPathGeometry.ReleaseAndGetAddressOf());
if (SUCCEEDED(hr))
{
// Write to the path geometry using the geometry sink.
hr = m_pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
pSink->BeginFigure(
pt1,
D2D1_FIGURE_BEGIN_FILLED
);
pSink->AddLine(pt2);
pSink->AddLine(pt3);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
}
}
return m_pPathGeometry;
}
三角形的轮廓和填充分别使用 DrawGeometry()
和 FillGeometry()
绘制。
ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
ComPtr<ID2D1PathGeometry> geometry = GenTriangleGeometry(
Point2F(110, 10), Point2F(210, 140), Point2F(10, 140));
m_Target->DrawGeometry(
geometry.Get(),
m_StrokeBrush.Get(),
16.0f,
stroke.Get());
m_Target->FillGeometry(
geometry.Get(),
m_FillBrush.Get());
圆
可以使用椭圆绘制函数绘制一个圆。 在下面的代码中,使用一个中心点和 x 和 y 半径创建一个椭圆变量 ell
。 圆的轮廓和填充分别使用 DrawEllipse()
和 FillEllipse()
绘制。
ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_ELLIPSE ell = Ellipse(Point2F(100.0f, 100.0f), 90, 90);
m_Target->DrawEllipse(
ell,
m_StrokeBrush.Get(),
16.0f,
stroke.Get());
m_Target->FillEllipse(
ell,
m_FillBrush.Get());
历史
- 2021 年 1 月 5 日:将所有颜色更新为深红色和黄色,以及更大的形状。
- 2020 年 8 月 22 日:为了最佳实践,将画刷创建放入
CreateDeviceResource()
中 - 2020 年 8 月 20 日:首次发布