(准备篇提供Direct2D的基本操作,但是可能不会更新)
Direct2D 是一款笔者非常喜欢的图像API。在这里就写出D2D 1.1版本的笔记,方便大家也是方便自己。
网上有不少1.0版本的教程,但是几乎没有1.1版本的,很是可惜。希望本系列文章能帮助有需要的童鞋。
先说一下定位: Direct2D 1.1版本非常适合游戏开发,只有一个RenderTarget(以下简称RT)的继承实现,是D2D1DeviceContext,
而1.0版本自带了几个,其中HWNDRenderTarget(利用ID2D1Factory::CreateHwndRenderTarget)非常适合开发普通
Windows桌面程序,利用DxgiSurface创建的RT则也是适合游戏开发(使用ID2D1Factory::CreateDxgiSurfaceRenderTarget)。
再说一下系统要求,1.1版本系统要求是进行功能更新的Win7及其以上。看看吧,有一群人死守着XP,看你是否
为这些人单独设计还是使用其他接口。
1.0版本的D2D初始化非常简单,初始化COM就不多说了。
创建 ---> D2D工厂 --- 创建---> D2D RT
利用RT就可以渲染图形图像了。
在1.1版本就复杂了不少,先给张图吧:(这张图是面向Win8 应用商店程序的,不过也差不多)
本人的建议是: 大致看看这个流程,再看看在本文后面提供的模板即可。
以后开发应用直接利用这个模板即可,因为非常的定式化。
1. 创建D3D11 设备,也可以创建D3D10,不过D3D11更好。
D3D11CreateDevice
可以查看详细参数说明,唯一需要说明的是
创建flag 一定要有 D3D11_CREATE_DEVICE_BGRA_SUPPORT
比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37<span style="font-size:14px;">UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #ifdef _DEBUG // Debug状态 有D3D DebugLayer就可以取消注释 //creationFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; // 创建设备 hr = D3D11CreateDevice( // 设为空指针选择默认设备 pDxgiAdapter, // 强行指定硬件渲染 D3D_DRIVER_TYPE_HARDWARE, // 没有软件接口 nullptr, // 创建flag creationFlags, // 欲使用的特性等级列表 featureLevels, // 特性等级列表长度 lengthof(featureLevels), // SDK 版本 D3D11_SDK_VERSION, // 返回的D3D11设备指针 &pD3DDevice, // 返回的特性等级 &m_featureLevel, // 返回的D3D11设备上下文指针 &pD3DDeviceContext );</span>
2. 获取 IDXGIDevice
1<span style="font-size:14px;">hr = pD3DDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&pDxgiDevice);</span>
1
2
3
4
5<span style="font-size:14px;">hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), reinterpret_cast<void**>(&m_pD2DFactory) );</span>
4. 创建D2D设备
1<span style="font-size:14px;">hr = m_pD2DFactory->CreateDevice(pDxgiDevice, &m_pD2DDevice);</span>
1
2
3
4<span style="font-size:14px;">hr = m_pD2DDevice->CreateDeviceContext( D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &m_pD2DDeviceContext );</span>
理论上就初始化完毕了,但是这个D2D 设备上下文并没有渲染目标,
我们需要ID2D1DeviceContext::SetTarget设置一个渲染目标,这是一个什么目标呢。
可以是一个D2D位图(比如ID2D1Bitmap1),但是这样仅仅是在计算机里面做做运算,什么也不会显示。
我们可以创建一个窗口交换链,让这个窗口交换链承载渲染目标,这样我们就可以在窗口上面显示我们的图像了。
6. 获取Dxgi适配器 还可以可以获取该适配器信息,比如显卡型号
1<span style="font-size:14px;">hr = pDxgiDevice->GetAdapter(&pDxgiAdapter);</span>
7. 利用适配器获取父对象: Dxgi工厂
1<span style="font-size:14px;">hr = pDxgiAdapter->GetParent(IID_PPV_ARGS(&pDxgiFactory));</span>
8. 利用Dxgi工厂创建窗口交换链
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45<span style="font-size:14px;"> // 设置全屏参数(可以不要) DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreenDesc; // 设置刷新率60FPS fullscreenDesc.RefreshRate.Numerator = 60; fullscreenDesc.RefreshRate.Denominator = 1; // 扫描方案 fullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; // 缩放方案 fullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // 全屏显示 fullscreenDesc.Windowed = FALSE; // 获取窗口大小 RECT rect; ::GetClientRect(m_hwnd, &rect); rect.right -= rect.left; rect.bottom -= rect.top; // 交换链信息 DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; swapChainDesc.Width = rect.right; swapChainDesc.Height = rect.bottom; swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 2; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; // 应用商店程序 //swapChainDesc.Scaling = DXGI_SCALING_NONE; //swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // 桌面应用程序 swapChainDesc.Scaling = DXGI_SCALING_STRETCH; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = 0; // 利用窗口句柄创建交换链 hr = pDxgiFactory->CreateSwapChainForHwnd( pD3DDevice, m_hwnd, &swapChainDesc, false ? &fullscreenDesc : nullptr, nullptr, &m_pSwapChain );</span>
请注意有行写的是:
false ? &fullscreenDesc : nullptr
也就是可要可不要的,看需求吧。反正调试起来,窗口模式更方便,而且2D游戏也适合窗口模式,
让玩家可以干干其他的事情。
8.5 确保安全, 保证DXGI队列里边不会超过一帧:
1<span style="font-size:14px;">hr = pDxgiDevice->SetMaximumFrameLatency(1);</span>
9. 利用交换链获取其首个Dxgi表面:
1<span style="font-size:14px;"> hr = m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pDxgiBackBuffer));</span>
10. 利用Dxgi表面创建位图:
1
2
3
4
5
6
7
8
9
10
11<span style="font-size:14px;"> D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), FIXED_DPI, FIXED_DPI ); hr = m_pD2DDeviceContext->CreateBitmapFromDxgiSurface( pDxgiBackBuffer, &bitmapProperties, &m_pD2DTargetBimtap );</span>
这个位图就是需要的呈现目标
11 设置目标 :
1<span style="font-size:14px;">m_pD2DDeviceContext->SetTarget(m_pD2DTargetBimtap);</span>
11.5 (建议) 使用像素作为单位:
1<span style="font-size:14px;">m_pD2DDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);</span>
请注意,ID2D1DeviceContext::SetTarget这个接口。这个接口提供了方便的渲染方法:
在位图上渲染图像,
我们仅需GetTarget获取当前接口,再设置一个位图,渲染图像,再设置回来。
就能获取一张渲染好的位图。
比如在游戏中提供一个设置提高亮度的选项。如果不使用这个方法,我们必须将每个渲染方法均需要修改亮度,
这很麻烦。
使用这个方法,我们先对换渲染对象,先使用一张位图承载渲染目标。渲染完毕后,
再换回来,背景清空,单独渲染刚刚的位图,不透明度就是(1-提高亮度),越透明就越量。
提交给交换链,简直方便。
还有就是根据自己的情况创建WIC工厂、DWrite工厂等等。
好了,现在送上模板(图片来源于网络,采用CC0授权):
下载地址
最后
以上就是奋斗大象最近收集整理的关于Direct2D 1.1 开发笔记 准备篇(一) 初始化的全部内容,更多相关Direct2D内容请搜索靠谱客的其他文章。
发表评论 取消回复