我是靠谱客的博主 奋斗大象,最近开发中收集的这篇文章主要介绍Direct2D 1.1 开发笔记 准备篇(一) 初始化,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

(准备篇提供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

比如:

<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

<span style="font-size:14px;">hr = pD3DDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&pDxgiDevice);</span>
3. 创建 D2D 工厂

<span style="font-size:14px;">hr = D2D1CreateFactory(
            D2D1_FACTORY_TYPE_SINGLE_THREADED,
            __uuidof(ID2D1Factory1),
            reinterpret_cast<void**>(&m_pD2DFactory)
            );</span>

4.  创建D2D设备

<span style="font-size:14px;">hr = m_pD2DFactory->CreateDevice(pDxgiDevice, &m_pD2DDevice);</span>
5. 创建D2D设备上下文

<span style="font-size:14px;">hr = m_pD2DDevice->CreateDeviceContext(
            D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
            &m_pD2DDeviceContext
            );</span>


理论上就初始化完毕了,但是这个D2D 设备上下文并没有渲染目标,

我们需要ID2D1DeviceContext::SetTarget设置一个渲染目标,这是一个什么目标呢。

可以是一个D2D位图(比如ID2D1Bitmap1),但是这样仅仅是在计算机里面做做运算,什么也不会显示。


我们可以创建一个窗口交换链,让这个窗口交换链承载渲染目标,这样我们就可以在窗口上面显示我们的图像了。


6. 获取Dxgi适配器 还可以可以获取该适配器信息,比如显卡型号

<span style="font-size:14px;">hr = pDxgiDevice->GetAdapter(&pDxgiAdapter);</span>

7. 利用适配器获取父对象: Dxgi工厂

<span style="font-size:14px;">hr = pDxgiAdapter->GetParent(IID_PPV_ARGS(&pDxgiFactory));</span>


8. 利用Dxgi工厂创建窗口交换链

<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队列里边不会超过一帧:

<span style="font-size:14px;">hr = pDxgiDevice->SetMaximumFrameLatency(1);</span>

9. 利用交换链获取其首个Dxgi表面:

<span style="font-size:14px;">    hr = m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pDxgiBackBuffer));</span>

10.  利用Dxgi表面创建位图:

<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 设置目标 :

        

<span style="font-size:14px;">m_pD2DDeviceContext->SetTarget(m_pD2DTargetBimtap);</span>

11.5 (建议) 使用像素作为单位:
        

<span style="font-size:14px;">m_pD2DDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);</span>


请注意,ID2D1DeviceContext::SetTarget这个接口。这个接口提供了方便的渲染方法:

在位图上渲染图像,

我们仅需GetTarget获取当前接口,再设置一个位图,渲染图像,再设置回来。

就能获取一张渲染好的位图。


比如在游戏中提供一个设置提高亮度的选项。如果不使用这个方法,我们必须将每个渲染方法均需要修改亮度,

这很麻烦。


使用这个方法,我们先对换渲染对象,先使用一张位图承载渲染目标。渲染完毕后,

再换回来,背景清空,单独渲染刚刚的位图,不透明度就是(1-提高亮度),越透明就越量。

提交给交换链,简直方便。



还有就是根据自己的情况创建WIC工厂、DWrite工厂等等。


好了,现在送上模板(图片来源于网络,采用CC0授权):





下载地址

最后

以上就是奋斗大象为你收集整理的Direct2D 1.1 开发笔记 准备篇(一) 初始化的全部内容,希望文章能够帮你解决Direct2D 1.1 开发笔记 准备篇(一) 初始化所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部