Direct2D学习教程(一)(原)
㈠ 关于Direct2D
Direct2D是一个硬件加速的,提供立即模式的二维图形API。它提供了二维的几何体,位图,文本的高性能,高质量的渲染。十分方便的是,Direct2D与GDI,GDI+和D3D都是可以交互的。一项技术总是有其受众面,看看微软本身怎么说的:
- 大型企业级本机应用程序开发人员。
- 创建供下游开发人员使用的控件工具包和库的开发人员。
- 需要对二维图形进行服务器端呈现的开发人员。
- 使用 Direct3D 图形,并且需要在菜单、用户界面 (UI) 元素和抬头显示器 (HUD) 中使用高性能的简单二维和文本呈现的开发人员。
㈡ Direct2D的架构
Direct2D是基于使用Direct3D 10.1的API,所以Direct2D的应用可以再渲染的时候受益于显卡的硬件加速。以下是其架构图,来源于Direct2D的document:
在Direct2D的右下方,有一个软件光栅化(software rasterizer),假如显卡不支持硬件加速,那么Direct2D可以使用软件方式渲染,即便是这样,其效果还是要优于GDI的。在Direct 3D下面还有一层叫DXGI(DirectX Graphics Infrastructure (DXGI) ),对于DXGI,现在我还不是很了解,这里就不敢乱说了。抱歉抱歉。。
㈢ 视觉效果
使用Direct2D渲染出来的效果要比GDI要好的多。因为Direct2D使用基于图元的反锯齿效果(这样会使线条更加的平滑),而且在渲染二维图元的时候,完全支持透明和alpha混合。以下是对比的照片:
两者的对比很明显吧!显然,右边的Direct2D的线条效果要好于左边的GDI。
㈢ 交互性
介绍交互性,先看看下面这张图:
此张图介绍了Direct2D与Direct3D,GDI+,GDI,DirectWrite,Windows Imaging Component (WIC)的交互性。在这张图中列出了与各个不同的平台交互的函数。虽然对其中的某些平台不了解,但看起来好像很厉害的样子。
㈣ Direct2D的Hello World
⑴ Direct2D的头文件
Direct2D API定义于以下头文件中:
头文件 | 描述 |
d2d1.h | 定义了主要的Direct2D API |
d2d1helper.h | 定义了C++帮助函数,类和结构 |
d2dbasetypes.h | 定义了Direct2D的主要绘图,例如:点,矩形等。其头文件也包含在d2d1.h之中。 |
d2derr.h | 定义了异常代码在Direct2D中。其头文件也包含在d2d1.h之中。 |
除了包含这些头文件,还有包含d2d1.lib这个库。你可以在Windows Software Development Kit (SDK) for Windows 7中可以找到以上这些东西。
⑵ 基本术语解释
① Direct2D Resources(资源)
所谓的资源,指的是视频内存或系统内存的某种分配。举例来说,位图和画笔就是资源。Direct2D提供了更直接的映射来充分利用 GPU。它提供了两类资源:与设备无关的资源和与设备有关的资源。(以下两部分内容来自msdn上的解释)
ⅰ 与设备无关的资源(如 ID2D1Geometry)保留在 CPU 上。
- ID2D1DrawingStateBlock
- ID2D1Factory
- ID2D1Geometry 以及从其继承的接口。
- ID2D1GeometrySink 和 ID2D1SimplifiedGeometrySink
- ID2D1StrokeStyle
ⅱ 与设备有关的资源(如 ID2D1RenderTarget 和 ID2D1LinearGradientBrush)直接映射到 GPU 上的资源(如果硬件加速可用)。通过将来自几何对象的顶点和覆盖信息与由与设备有关的资源生成的纹理信息进行组合,来执行呈现调用。
- ID2D1Brush 以及从其继承的接口。使用呈现器目标可创建画笔。
- ID2D1Layer 使用呈现器目标可创建层。
- ID2D1RenderTarget 以及从其继承的接口。若要创建呈现器目标,请使用工厂或其他呈现器目标。
② RenderTarget(渲染目标)
渲染目标是从ID2D1RenderTarget 接口继承的资源。其用于创建绘制的资源,并执行实际的绘制操作。你可以通过以下方式使用多种类型的渲染目标来呈现图形:。(以下部分内容来自msdn上的解释)
- ID2D1HwndRenderTarget 对象将内容呈现到窗口。
- ID2D1DCRenderTarget 对象呈现到 GDI 设备上下文。
- 位图呈现器目标对象将内容呈现到屏幕外位图。
- DXGI 呈现器目标对象呈现到用于 Direct3D 的 DXGI 图面。
③ Brush(画笔)
画笔用其输出来“绘制”区域,不同的画笔具有不同的输出类型。Direct2D 提供了四种画笔:。(以下部分内容来自msdn上的解释)
- ID2D1SolidColorBrush 用纯色绘制区域
- ID2D1LinearGradientBrush 用线性渐变绘制区域
- ID2D1RadialGradientBrush 用径向渐变绘制区域
- ID2D1BitmapBrush 用位图绘制区域
④ ID2D1Geometry(几何对象)
Direct2D 几何对象是由 ID2D1Factory 创建的与设备无关的不可变资源。其对象可以是简单几何对象(ID2D1RectangleGeometry、ID2D1RoundedRectangleGeometry 或 ID2D1EllipseGeometry)、路径几何对象 (ID2D1PathGeometry) 或复合几何对象(ID2D1GeometryGroup 和ID2D1TransformedGeometry)。
⑤ Bitmap(位图)
Direct2D 不提供用于加载或存储位图的方法;而是使您可以使用 Windows 图像处理组件 (WIC) 创建位图。位图资源可以使用 WIC 进行加载,然后通过 ID2D1RenderTarget::CreateBitmapFromWicBitmap 方法用于创建 ID2D1Bitmap。
⑶ Hello World来了,创建一个矩形!
① 包含 Direct2D 头文件
// windows的头文件
#include <windows.h>
// Direct2D的头文件
#include <d2d1.h>
② 创建一个ID2D1Factory
ID2D1Factory是使用 Direct2D 的起点,使用 ID2D1Factory 可创建 Direct2D 资源。
ID2D1Factory* pd2dfactory = null;
HRESULT hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&pd2dfactory
);
③ 创建 ID2D1HwndRenderTarget
创建工厂之后,我们要创建渲染目标。具体见下面的代码:
HRESULT hr = S_OK;
if (!m_pRenderTarget)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// 创建一个Direct2D渲染目标,m_pRenderTarget这是我们要创建的。
hr = m_pDirect2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
// 创建一个灰色的画笔,调用的是CreateSolidColorBrush函数,LightSlateGray这是笔的颜色
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::LightSlateGray),
&m_pLightSlateGrayBrush
);
}
if (SUCCEEDED(hr))
{
// 创建一个蓝色的画笔
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::CornflowerBlue),
&m_pCornflowerBlueBrush
);
}
}
④ 绘制矩形
HRESULT hr = S_OK;
hr = CreateDeviceResources(); // 创建好了m_pRenderTarget
if (SUCCEEDED(hr))
{
m_pRenderTarget->BeginDraw(); // 绘制就在BeginDraw()和EndDraw()之间
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue)); // 背景颜色
D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
// 绘制一个网格背景
int width = static_cast<int>(rtSize.width);
int height = static_cast<int>(rtSize.height);
for (int x = 0; x < width; x += 10)
{
m_pRenderTarget->DrawLine(
D2D1::Point2F(static_cast<FLOAT>(x), 0.0f),
D2D1::Point2F(static_cast<FLOAT>(x), rtSize.height),
m_pLightSlateGrayBrush,
0.5f
);
}
for (int y = 0; y < height; y += 10)
{
m_pRenderTarget->DrawLine(
D2D1::Point2F(0.0f, static_cast<FLOAT>(y)),
D2D1::Point2F(rtSize.width, static_cast<FLOAT>(y)),
m_pLightSlateGrayBrush,
0.5f
);
}
//绘制两个矩形
D2D1_RECT_F rectangle1 = D2D1::RectF(
rtSize.width/2 - 50.0f,
rtSize.height/2 - 50.0f,
rtSize.width/2 + 50.0f,
rtSize.height/2 + 50.0f
);
D2D1_RECT_F rectangle2 = D2D1::RectF(
rtSize.width/2 - 100.0f,
rtSize.height/2 - 100.0f,
rtSize.width/2 + 100.0f,
rtSize.height/2 + 100.0f
);
// 绘制一个实心的矩形
m_pRenderTarget->FillRectangle(&rectangle1, m_pLightSlateGrayBrush);
// 绘制一个空心的矩形
m_pRenderTarget->DrawRectangle(&rectangle2, m_pCornflowerBlueBrush);
// 结束绘制
hr = m_pRenderTarget->EndDraw();
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources(); // 释放资源
}
⑤ 释放资源
template<class Interface>
inline void SafeRelease(
Interface **ppInterfaceToRelease
)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
// 上面是释放函数,下面是释放的对象!
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pLightSlateGrayBrush);
SafeRelease(&m_pCornflowerBlueBrush);
这是执行的结果:
弄了两天才写好,上面的有些东西也不是特别了解,请见谅!但是应该会随着时间的推移,了解更深的。如果大牛们看到其中的不足,请大牛们指正,本人不甚感激!
参考文献
1. msdn文档:http://msdn.microsoft.com/zh-cn/library/dd370990(v=vs.85).aspx
2.还是msdn文档。。。。因为本文是基于文档写成的。