Direct2D教程.docx
- 文档编号:12314652
- 上传时间:2023-06-05
- 格式:DOCX
- 页数:92
- 大小:1.25MB
Direct2D教程.docx
《Direct2D教程.docx》由会员分享,可在线阅读,更多相关《Direct2D教程.docx(92页珍藏版)》请在冰点文库上搜索。
Direct2D教程
Direct2D教程
(一)Direct2D已经来了,谁是GDI的终结者?
什么是Direct2D
一言以蔽之,就是Windows7平台上的一个2D图形API,可以提供高性能,高质量的2D渲染。
大多数人对Direct2D可能都比较陌生,以至于我之前在论坛上提到这个词的时候,有人竟然说你是不是写错了?
可能大家比较熟悉的是Direct3D,因为D3D已经是当前游戏界的主流应用。
在过去,3D世界是OpenGL与DirectX二分天下,但是由于OpenGL发展十分滞后,而且没有一个像微软这样强大的后台支柱,所以逐渐被DirectX所超越。
回过头来说2D,过去Windows上的2D程序还主要基于GDI和GDI+,遗憾的是这两者都是软件实现,而Direct2D则不同,它基于Direct3D,所以能够使用硬件加速功能,能更大程度的发挥硬件特性,创建高性能,高质量的2D图形,这些图形包括几何图形,如矩形,椭圆等。
还有位图,文本。
而且更方便的是,Direct2D与GDI,GDI+和D3D都是可以交互的。
运行需求
要开发和使用Direct2D程序,系统必须是Windows7,WindowsVistaSP2,WindowsServer2008R2或者WindowsServer2008SP2,这样的系统需求无疑会稍稍阻碍Direct2D前进的步伐,虽然Vista和Windows7已经推出有一段时间了,但是不可否认的是,仍然有很多人在使用XP系统。
甚至是Win2K。
但是新技术的普及是不可阻碍的,相信不久的将来,Direct2D将会成为2D图形世界的主流。
D2D的架构
Direct2D是基于Direct3D10.1API构建的,这意味着Direct2D可以使用硬件加速,下图是Direct2D与Direct3D的一个关系图
由上图可以看出,Direct2D还自带了一个软件实现(Softwarerasterizer),这是因为如果显卡不支持硬件加速,那么Direct2D可以使用软件方式渲染,即使这样,效果还是要优于GDI的。
上图中在Direct3D下面还有一个层叫DXGI,其全称是:
DirectXGraphicsInfrastructure,DXGI从Direct3D10中才开始存在,主要是为了将一些与3D图形无关的工作从原本的runtime中分离处理,这些工作多是一些底层的操作,比如枚举设备,显示帧缓冲,gamma控制,管理全屏等,在Direct3D10以前的版本中,这些操作全部集成到了Direct3D的API中,现在分离处理单独成为一个component,就是DXGI。
可视效果
使用Direct2D可以获得比GDI更加优秀的可视效果,Direct2D支持基于图元的抗锯齿效果,而且完全支持透明和Alpha混合。
下图是GDI和Direct2D的一个比较,大家可以看一下,Direct2D的细腻程度可见一斑。
可交互性
Direct2D与Direct3D,GDI,GDI+都有着良好的交互性,因为他们都支持表面级别的操作,这里的表面在Direct3D中就是surface,而在GDI中则相当于DC(DeviceContext)。
此外Direct2D还能很好的支持DirectWrite,DirectWrite也是DirectX中一个新的Feature,主要用来做文本的绘制。
下图是这几者指间的关系
期待
虽然Direct2D有着明显的优势,但是想取代GDI仍然非短时间可以达到,为了保持向后兼容,微软在短时间绝不会放弃GDI。
如今Direct2D出世已经有一段时间了,GDI还有多少时间?
对于Windows平台上的图形世界,DirectX一统江湖的日子还有多远?
我们拭目以待!
Direct2D教程
(二)来看D2D世界中的Hello,World
引子
任何一门语言的第一个教程几乎都是Hello,world。
我们也不例外,但是这里不是教大家打印Hello,world,而是编写一个简单的D2D绘制程序,让大家对Direct2D的程序结构及编程方法有一个基本的认识。
下面我们来看如何一步一步绘制一个矩形。
基本概念
在开始之前,还是先介绍一些基本的概念,有助于大家理解程序,这些概念包括,Brush(画刷),Rendertarget(渲染目标),Geometry(几何图形),它们会贯穿整个教程,所以越早介绍越好,对于有WindowsGDI基础的人来说,理解这些概念很容易。
没有基础的也没关系,我们可以先了解一下,随着学习的深入,会有更加深刻的认识。
Brush
Brush-画刷,画刷是绘图的工具,它管理图形的颜色,虚实,画刷可以绘制几何图形,也可以绘制位图。
Rendertarget
Rendertarget-渲染目标(姑且这么翻译吧)是绘制的场所,其实这就是一个surface,一个表面,再具体点就是一块存,可以是显存,也可能是系统存。
所有的绘图操作都在这里完成。
Geometry,Bitmap,Text
Geometry-几何图形,Bitmap-位图,Text-文本。
这三者是要绘制的容,几何图形包括矩形,圆角矩形,椭圆等,当然Direct2D除了可以绘制几何图形之外,还可绘制位图和文本,D2D没有提供加载位图的接口,所以对位图的加载都是使用WIC来实现的。
而对文本的绘制则是通过DirectWrite来实现的,DirectWrite在分类上属于D2D,但是目前已经独立成一个组件了。
为了便于理解以上三者之间的关系,大家可以想象一个画家,他在作画的时候,都需要那些东西呢?
第一,他需要一支画笔用来绘制,这相当于上面的画刷,第二,他需要一纸或者一画布用来承载绘制的东西,这就是上面的Rendertarget,最后,他想画什么呢?
山水?
花鸟?
亦或是人物?
这就是绘制的容,相当于上面的几何图形,位图或者文本。
Resource
在Direct2D中主要有两种资源,一是设备无关的资源,另一个是设备相关的资源。
所谓设备无关,是指该资源不与特定的硬件渲染设备相关联,所以设备无关的资源都分配在CPU中,而设备相关是指该资源与特定的渲染硬件相关联,比如当硬件加速可用时,使用GPU渲染,否则使用CPU渲染。
设备无关的资源
∙ID2D1DrawingStateBlock
∙ID2D1Factory
∙ID2D1Geometry及继承自它的接口
∙ID2D1GeometrySink和ID2D1SimplifiedGeometrySink
∙ID2D1StrokeStyle
除了ID2D1RenderTarget之外,所有使用ID2D1Factory创建的资源都是设备无关的。
设备相关的资源
∙ID2D1Brush及继承自它的接口
∙ID2D1Layer
∙ID2D1RenderTarget及继承自它的接口
一般来说,使用ID2D1RenderTarget创建的资源都是设备相关的。
程序框架
一个简单的D2D程序大致包含下面三个核心函数。
1创建资源(CreateResources)-设备无关的资源可以一次性创建,永久使用,而设备相关的资源则需要随着设备改变而相应的改变。
2渲染(Render)-响应WM_PAINT消息进行绘制。
3清理资源(Cleanup)-DX是基于COM的,所有COM对象在使用完毕时,都要释放。
为了便于大家理解,我画了一图,这个图简单描述了D2D程序的基本渲染流程。
需要说明的是,Direct2D的渲染时机与D3D有些不同,D3D是在没有消息处理时进行渲染,而D2D则是响应WM_PAINT消息进行渲染。
下面的代码中会有详细的解释。
代码
添加头文件
除了Win32编程需要的头文件(比如Windows.h)之外,任何D2D程序都需要头文件d2d1.h。
#include
#include
声明全局变量
首先我们需要一个ID2D1Factory*类型的对象,也就是D2D工厂接口,这个接口是所有D2D程序的起始点,几乎所有的D2D资源都是由这个接口创建的,其次我们需要一个渲染的场所,也就是RenderTarget,在D2D中有多种类型的RenderTarget,这里我们选择ID2D1HwndRenderTarget类型,用来在窗口中进行渲染。
最后我们定义一个画刷,用来绘制图形,这里选择固定颜色的画刷,即ID2D1SolidColorBrush。
ID2D1Factory*pD2DFactory=NULL;//Direct2Dfactory
ID2D1HwndRenderTarget*pRenderTarget=NULL; //Rendertarget
ID2D1SolidColorBrush*pBlackBrush=NULL;//Ablackbrush,reflectthelinecolor
RECTrc;//Renderarea
HWNDg_Hwnd;//Windowhandle
创建D2D工厂
接下来创建D2D工厂对象,有了这个对象才能创建后续的资源,这个函数有两个参数,第一个参数是工厂的类型,这里只有单线程和多线程两类,如果是单线程的话,意味着D2D不会为所创建的工厂的对象以及由这个对象创建的子对象提供同步机制,也就是说,如果有多个线程访问了这个资源,那么需要自己提供同步机制。
如果是多线程类型,那么D2D会为你提供同步机制。
第二个参数用来接收创建的工厂。
HRESULThr;
hr=D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&pD2DFactory);
if(FAILED(hr))
{
MessageBox(hWnd,"CreateD2Dfactoryfailed!
","Error",0);
return;
}
创建Rendertarget
有了工厂对象以后,开始创建RenderTarget,CreateHwndRenderTarget函数有三个参数,第一个参数是Rendertarget属性,包括渲染模式,象素格式,DPI等,D2D提供了一个函数D2D1:
:
RenderTargetProperties(),可以用来生成默认的属性,我们这里直接使用这个函数。
第二个参数是Hwnd类型的Rendertarget属性,它包含三个参数,第一个是窗口句柄,第二个是Rendertarget的大小,第三个参数是Present选项,这个参数有个默认值,这里我们使用它的默认值。
CreateHwndRenderTarget函数的最后一个参数用来接收创建的Rendertarget。
//CreateaDirect2Drendertarget
hr=pD2DFactory->CreateHwndRenderTarget(
D2D1:
:
RenderTargetProperties(),
D2D1:
:
HwndRenderTargetProperties(
hWnd,
D2D1:
:
SizeU(rc.right-rc.left,rc.bottom-rc.top)
),
&pRenderTarget
);
if(FAILED(hr))
{
MessageBox(hWnd,"Createrendertargetfailed!
","Error",0);
return;
}
创建画刷
有了Rendertarget,再使用函数CreateSolidColorBrush创建画刷,这里创建一个固定颜色的画刷,第一个参数是画刷的颜色,第二个参数接收创建的画刷,画刷的颜色就是绘制线条所用的颜色,比如这里创建一个红色的画刷,那么后面绘制的矩形就是红色的。
//Createabrush
hr=pRenderTarget->CreateSolidColorBrush(
D2D1:
:
ColorF(D2D1:
:
ColorF:
:
Red),
&pBlackBrush
);
if(FAILED(hr))
{
MessageBox(hWnd,"Createbrushfailed!
","Error",0);
return;
}
绘制矩形
万事俱备,只欠渲染!
渲染的代码很简单,首先调用CreateD2DResource函数来创建资源,这是个自定义函数,用来创建资源,比如Rendertarget,画刷之类的,该函数包含了上面提到的代码。
绘制的代码要放在BeginDraw和EndDraw函数之间,调用Clear函数可以将Rendertarget清除为指定的背景色。
DrawRectangle函数用来绘制矩形,它有两个参数,第一个是被绘制的矩形,第二个是绘制所用的画刷。
函数EndDraw的返回值标识了渲染是否成功。
VOIDDrawRectangle()
{
CreateD2DResource(g_Hwnd);
pRenderTarget->BeginDraw();
//Clearbackgroundcolorwhite
pRenderTarget->Clear(D2D1:
:
ColorF(D2D1:
:
ColorF:
:
White));
//DrawRectangle
pRenderTarget->DrawRectangle(
D2D1:
:
RectF(100.f,100.f,500.f,500.f),
pBlackBrush
);
HRESULThr=pRenderTarget->EndDraw();
if(FAILED(hr))
{
MessageBox(NULL,"Drawfailed!
","Error",0);
return;
}
清理资源
最后,在程序退出时,清理程序资源,每个COM对象都有一个Release方法,用来释放自己,这里我们定义一个宏来释放COM对象。
VOIDCleanup()
{
SAFE_RELEASE(pRenderTarget);
SAFE_RELEASE(pBlackBrush);
SAFE_RELEASE(pD2DFactory);
}
释放COM对象的宏。
#defineSAFE_RELEASE(P)if(P){P->Release();P=NULL;}
效果图如下
HappyCoding
==THEEND==
Direct2D教程(三)简单几何图形
从本章开始,我们介绍D2D几何图形。
D2D图形分类
Direct2D支持多种类型的几何图形,包括
SimpleGeometry(简单几何图形)
∙矩形
∙圆角矩形
∙椭圆
PathGeometry(路径图形)
CompositeGeometry(复合图形)
∙GeometryGroup(图形组)
∙TransformedGeometry(变换的图形)
各种图形对应的D2D接口如下,所有接口都继承自ID2D1Geometry。
∙矩形-ID2D1RectangleGeometry
∙圆角矩形-ID2D1RoundedRectangleGeometry
∙椭圆-ID2D1EllipseGeometry
∙路径图形-ID2D1PathGeometry
∙图形组-ID2D1GeometryGroup
∙经过变换的图形-ID2D1TransformedGeometry
今天我们先来看一下简单几何图形,其他类型的图形将在后续章节中介绍,上面的简单图形有三种,其实还有一种,就是直线,所以D2D目前支持的简单图形有如下四种。
∙Line-直线
∙Rectangle-矩形
∙RoundedRectangle-圆角矩形
∙Ellipse-椭圆
下面逐个介绍每种图形的绘制方法,绘制某种图形是通过Rendertarget对象调用相应的绘图函数来完成的,所以下面的代码都假定Rendertarget对象已经创建好了。
直线
绘制直线使用函数DrawLine,先看一下函数定义,前两个参数分别是直线的起点和终点,第三个参数是画刷。
第四个参数是线的宽度,最后一个参数是线的样式,比如实线,虚线或是其他风格的线,你可以使用D2D提供的样式,也可以自己定义样式。
由于最后两个参数有默认值,所以我们通常只提供前三个参数即可。
最后两个参数在下面的绘图函数中都有出现。
virtualvoidDrawLine(
D2D1_POINT_2Fpoint0,
D2D1_POINT_2Fpoint1,
[in]ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
[in,optional]ID2D1StrokeStyle*strokeStyle=NULL
)=0;
下面的代码绘制一条黑色直线,起点是(100,100),终点是(500,500)。
pRenderTarget->DrawLine(
D2D1:
:
Point2F(100.f,100.f),
D2D1:
:
Point2F(500.f,500.f),
pBlackBrush);
矩形
矩形使用如下的结构体表示。
structD2D_RECT_F{
FLOATleft;
FLOATtop;
FLOATright;
FLOATbottom;
};
绘制矩形使用函数DrawRectangle,定义如下。
第一个参数是D2D1_RECT_F结构,表示待绘制的矩形,它其他参数前面已经提到过,不再赘述。
voidDrawRectangle(
[ref]constD2D1_RECT_F&rect,
[in]ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
[in,optional]ID2D1StrokeStyle*strokeStyle=NULL
);
下面的代码绘制一个矩形,该矩形的左上角坐标是(100,100),右下角坐标是(500,500)。
pRenderTarget->DrawRectangle(
D2D1:
:
RectF(100.f,100.f,500.f,500.f),
pBlackBrush
);
圆角矩形
D2D支持圆角矩形,先看看什么是圆角矩形。
可见圆角矩形就是常规矩形的改版,将尖角用圆弧代替即可。
所以一个圆角矩形可以由一个普通矩形加上两个半径构造而成,这两个半径分别表示椭圆的X轴和Y轴,而这个椭圆则用来取代矩形的尖角。
圆角矩形的定义如下:
第一个参数是一个常规矩形,上面已经介绍过,后两个参数分别是椭圆的X轴半径和Y轴半径。
D2D1_ROUNDED_RECTRoundedRect(
__inconstD2D1_RECT_F&rect,
FLOATradiusX,
FLOATradiusY
);
绘制圆角矩形的函数定义如下,第一个参数是一个圆角矩形,后面的参数不再赘述。
voidDrawRoundedRectangle(
[ref]constD2D1_ROUNDED_RECT&roundedRect,
[in]ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
[in,optional]ID2D1StrokeStyle*strokeStyle=NULL
);
下面的代码绘制一个圆角矩形,其左上角坐标是(100,100),右下角坐标是(500,500)。
圆角的X轴半径是30,Y轴半径是50。
D2D1_ROUNDED_RECTroundedRect=D2D1:
:
RoundedRect(
D2D1:
:
RectF(100.f,100.f,500.f,500.f),
30.0f,
50.0f
);
pRenderTarget->DrawRoundedRectangle(roundedRect,pBlackBrush,1.0f);
椭圆
椭圆由如下所示的结构体定义,第一个参数是椭圆的中心,后两个参数分别是X轴半径和Y轴半径。
structD2D1_ELLIPSE{
D2D1_POINT_2Fpoint;
FLOATradiusX;
FLOATradiusY;
};
绘制椭圆的函数定义如下
voidDrawEllipse(
[ref]constD2D1_ELLIPSE&ellipse,
[in]ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
[in,optional]ID2D1StrokeStyle*strokeStyle=NULL
);
下面的代码绘制一个椭圆,中心在(100,100),长轴半径100,短轴半径50。
D2D1_ELLIPSEellipse=D2D1:
:
Ellipse(D2D1:
:
Point2F(100.0f,100.0f),100.0f,50.0f);
pRenderTarget->DrawEllipse(ellipse,pBlackBrush);
三角形
D2D没有提供绘制三角形的函数,不过我们可以使用DrawLine函数自己实现一个,代码很简单,对于给定的三个顶点,在每两个顶点之间调用上面的DrawLine函数即可。
voidDrawTriangle(D2D1_POINT_2Fp0,D2D1_POINT_2Fp1,D2D1_POINT_2Fp2,
ID2D1HwndRenderTarget*pRenderTarget,
ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
ID2D1StrokeStyle*strokeStyle=NULL)
{
pRenderTarget->DrawLine(p0,p1,brush);
pRenderTarget->DrawLine(p1,p2,brush);
pRenderTarget->DrawLine(p2,p0,brush);
}
圆
D2D同样没有提供绘制圆的函数,因为圆是特殊的椭圆,可以通过绘制椭圆的函数来实现,只要使X轴半径和Y轴半径相等即可。
voidDrawCircle(D2D1_POINT_2Fcenter,FLOATradius,
ID2D1HwndRenderTarget*pRenderTarget,
ID2D1Brush*brush,
FLOATstrokeWidth=1.0f,
ID2D1StrokeStyle*strokeStyle=NULL
)
{
D2D1_E
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Direct2D 教程