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

Direct2D 教程 第 3 部分:仿射变换

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (7投票s)

2020年8月20日

CPOL

4分钟阅读

viewsIcon

11742

downloadIcon

316

关于在绘图上应用仿射变换的 Direct2D 教程

目录

示例代码托管在 Github 上。

引言

在本文中,我们将了解如何在 Direct2D 中使用矩阵进行仿射变换。 变换必须在任何要转换的绘图之前设置。 本文的先决条件是具备设置 RenderTarget 的知识。 如果您不知道 RenderTarget 是什么,请先阅读 RenderTarget 文章,然后再回来阅读本文。

文本格式

要在 Direct2D 中显示文本,必须首先创建 IDWriteTextFormatIDWriteTextFormat 是一种设备无关的资源,在 CreateDeviceIndependentResources() 中创建,而 CreateDeviceIndependentResources() 又由 OnInitDialog() 或您可能拥有的任何初始化函数调用一次。 当 Direct2D 目标丢失时,无需重新创建设备无关的资源。 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()));
}

转换

Translated Text

在本节中,文本沿 y 轴向下平移(或移动)50 像素。 在使用我们的平移矩阵设置 SetTransform() 之前,必须使用 IdentityMatrix() 调用它,以重置在此阶段之前设置的任何矩阵。 平移矩阵由 Matrix3x2F::Translation() 创建。 Matrix3x2F::Translation() 的 2 个参数是要从当前点“移动”的 X 和 Y 坐标量。 然后,m_FillBrush 设置为 Direct2D 预定义的黑色。 您可以选择其他预定义或自定义颜色。 要定义要在 SetColor() 中使用的自定义颜色,请按 RGBA 顺序给出 ColorF() 4 个浮点数。 然后,要绘制文本,在 m_Target 上调用 DrawTextW

CRect rectClient;
GetClientRect(&rectClient);

auto rect = RectF(0.0f, 0.0f, rectClient.Width(), rectClient.Height());

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);

m_Target->SetTransform(trans);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), 
          m_TextFormat.Get(), &rect, m_FillBrush.Get());

倾斜

Skewed Text

接下来,我们将看到如何进行倾斜以使文本看起来像斜体,然后进行相同的平移。 前一节中的 GetClientRect() 代码未显示,因为它们没有改变。 变换通过矩阵乘法链接在一起。 您会看到矩阵乘法的顺序在这里非常重要。 矩阵乘法的顺序必须与所需变换的顺序相反。 例如,我们希望倾斜是第一个变换,然后在矩阵乘法中,则倾斜矩阵必须是最后一个操作数。 平移矩阵反之亦然。 见倾斜矩阵由 Matrix3x2F::Skew() 创建。 Matrix3x2F::Skew() 的前 2 个参数是沿 x 轴和 y 轴倾斜的角度(度),最后一个参数是倾斜的中心点。
注意:上面讨论了平移矩阵的创建。

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew
      (-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));

m_Target->SetTransform(trans * skew);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), 
          m_TextFormat.Get(), &rect, m_FillBrush.Get());

旋转

Rotated Text

在本节中,文本向上旋转 -10 度。 倾斜和旋转必须在平移之前执行,因此矩阵乘法是 trans * rotate * skew。 旋转矩阵由 Matrix3x2F::Rotation() 创建,该矩阵以角度作为其第一个参数。 可选的中心点参数默认为 0,0,如果省略。

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F rotate = D2D1::Matrix3x2F::Rotation(-10.0f);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew
(-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));

m_Target->SetTransform(trans * rotate * skew);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), 
                     m_TextFormat.Get(), &rect, m_FillBrush.Get());

Scale

Skewed Text

缩放通常用于在计算机绘图中实现放大和缩小。 在这最后一节中,我们将缩小文本绘图(使其更小)。 缩放必须在所有其他变换之前执行,因此它是矩阵乘法中的最后一个操作数。 见缩放矩阵由 Matrix3x2F::Scale() 创建,它有 2 个参数来指定 x 轴和 y 轴的缩放比例。

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F rotate = D2D1::Matrix3x2F::Rotation(-10.0f);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew
      (-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));
D2D1::Matrix3x2F scale = D2D1::Matrix3x2F::Scale(0.6f, 0.6f);

m_Target->SetTransform(trans * rotate * skew * scale);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), 
                     m_TextFormat.Get(), &rect, m_FillBrush.Get());

矩阵乘法的顺序

倾斜部分提到矩阵乘法的顺序必须与所需变换的顺序相反。 应该有一个更完整的解释的部分。 看一下由两个矩阵 TS 表示的两个变换,其中 T 变换首先应用于 V,然后是 S 变换。 V 是一个向量,由要变换的 xy 的笛卡尔坐标组成。

S(T(V))

注意:矩阵乘法是非交换的,因此必须尊重乘法的顺序。 虽然 T 首先应用,但 S 首先出现在等式中。

ST != TS

历史

  • 2021 年 1 月 28 日:添加了矩阵乘法的顺序以进行完整的解释。
  • 2020 年 8 月 20 日:初始版本

系列文章

© . All rights reserved.