• Directx11学习笔记【三】 第一个D3D11程序


    在先前的解决方案中新建一个新的Win32项目FirstD3D11Demo。在写代码之前,我们必须先添加dx11所需要的库。为了链接dx库,右键项目选择属性->vc++目录,在包含目录中添加你所安装的SDK根目录Include,在库目录中添加 根目录libx86(或x64),在链接器->输入的附加依赖项中添加d3d11.lib、d3dx11.lib、dxerr.lib。

    第一次使用d3d,首先应该从初始化开始。

    初始化d3d11的步骤主要有以下几个:

    1、定义我们要检查的设备类型和特征级别

    2、创建d3d设备,渲染环境和交换链

    3、创建渲染对象

    4、设置视口观察区(ViewPort)

    下面将对一些概念和用到的d3d对象和函数作具体说明。

    数据格式

    D3D应用程序中,无论是纹理图片,还是创建的缓冲区,都有着特定的数据格式。D3D11支持有限的数据格式,以枚举变量形式存在,如下几种:

    DXGI_FORMAT_R32G32B32_FLOAT: 3个32位单精度符点数组成,比如用于代表三维空间坐标,以及24位颜色;

    DXGI_FORMAT_R16G16B16A16_UNORM: 4个16位数组成,每个成员位于[0,1.0f]之间,UNORM意指:unsigned normalized,即无符号,且归一化的;

    DXGI_FORMAT_R32G32_UINT:2个32位数组成,每个成员为无符号整型(unsigned int);

    DXGI_FORMAT_R8G8B8A8_UNORM:4个8位数组成,每个成员为[0,1.f]之间;

    DXGI_FORMAT_R8G8B8A8_SNORM:4个8位数组成,每个成员为[-1.0f, 1.0f]之间,SNORM意指:signed normalized;

    DXGI_FORMAT_R8G8B8A8_SINT:4个8位数组成,每个成员为有符号整型;

    特征级别(Feature Level)

    特征级别定义了一系列支持不同d3d功能的相应等级,如果一个用户的硬件不支持某一特征等级,程序可以选择较低的等级来运行。

    下面是d3d定义的几个不同级别代表不同的d3d版本

    typedef enum D3D_FEATURE_LEVEL { 
      D3D_FEATURE_LEVEL_9_1   = 0x9100,
      D3D_FEATURE_LEVEL_9_2   = 0x9200,
      D3D_FEATURE_LEVEL_9_3   = 0x9300,
      D3D_FEATURE_LEVEL_10_0  = 0xa000,
      D3D_FEATURE_LEVEL_10_1  = 0xa100,
      D3D_FEATURE_LEVEL_11_0  = 0xb000,
      D3D_FEATURE_LEVEL_11_1  = 0xb100,
      D3D_FEATURE_LEVEL_12_0  = 0xc000,
      D3D_FEATURE_LEVEL_12_1  = 0xc100
    } D3D_FEATURE_LEVEL;

    在初始化过程中,我们可以提供一组不同的特征等级,程序会从第一个开始逐个检测,碰到第一个合适的来创建设备。因此我们在数组中从高到低放置特征等级提供给初始化程序。

    交换链(SwapChain)

    为了实现平滑的动画,至少需要两个缓冲区,一个前缓冲区用于显示,一个后缓冲区用于下一帧的绘制,每次绘制完一帧后通过交换前、后缓冲区对应的指针来显示新一帧,并在之前的前缓冲区(当前的后缓冲区)上开始继续绘制下一帧。交换链可以有3个或者更多缓冲区,但一般情况下两个够用了。通常在游戏中,我们有两种颜色缓存,一个主缓存,一个辅助缓存,这就是所谓的前向和后向缓存。主缓存是显示在屏幕上的,辅助缓存则是用于下一帧的绘制。在d3d11中交换链对应的接口为IDXGISwapChain。

    深度/模板缓冲区:Depth/Stencil Buffer

    深度缓冲区是与交换链缓冲区大小完全一样的一块显存区域,即每个像素在深度缓冲区中对应相应的位置。在渲染管线的最终的混合阶段(Output Merger Stage),每个片(Fragment)都有一个深度值z,与深度缓冲区对应位置上的深度相比较,如果该片段z更小,则绘制该片段,并覆盖当前的尝试值,否则抛弃该片段。该缓冲区主要用于实现投影在屏幕上同一位置、远近不同的物体之间相同的遮挡效果。此外,灵活配置尝试缓冲区,可以实现很多种高级特效。

     多重采样抗锯齿:Multisampling Atialiasing

           针对光栅化显示器抗锯齿的方法有多种,在d3d中采用的多重采样方法。即在每个像素点内部,设置多个采样点,绘制多边形边缘时,针对每个采样点判断是否被多边形覆盖,最终的颜色值从采样点中取均值,以对多边形的边缘进行“模糊化",从而减轻锯齿效果。如下图所示,这是一个4重采样的例子,该像素最终的颜色值是多边形本身颜色值的3/4:

    支持d3d11的硬件全部支持4重采样,因此我们在后面的程序中将普遍使用4个采样点。在d3d11中通过结构DXGI_SAMPLE_DESC来设置多重采样,其定义如下:

    typedef struct DXGI_SAMPLE_DESC {
      UINT Count;
      UINT Quality;
    } DXGI_SAMPLE_DESC;

    D3D11_CREATE_DEVICE_FLAG 枚举类型

    typedef enum D3D11_CREATE_DEVICE_FLAG { 
      D3D11_CREATE_DEVICE_SINGLETHREADED                                 = 0x1,
      D3D11_CREATE_DEVICE_DEBUG                                          = 0x2,
      D3D11_CREATE_DEVICE_SWITCH_TO_REF                                  = 0x4,
      D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS       = 0x8,
      D3D11_CREATE_DEVICE_BGRA_SUPPORT                                   = 0x20,
      D3D11_CREATE_DEVICE_DEBUGGABLE                                     = 0x40,
      D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY  = 0x80,
      D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT                            = 0x100,
      D3D11_CREATE_DEVICE_VIDEO_SUPPORT                                  = 0x800
    } D3D11_CREATE_DEVICE_FLAG;

    D3D11_CREATE_DEVICE_SINGLETHREADED
    如果使用该常量,你的应用程序将只可以在一个线程中的调用 Dierct3D 11接口。在默认情况下ID3D11Device
    对象是一个安全线程。使用这个标志,你可以增强性能。然而,如果你使用这个标志并且你的应用程序使用
    多线程调用Dierct3D 11接口,可能导致不可预期的结果。

    D3D11_CREATE_DEVICE_DEBUG
    创建一个设备支持调用层。

    D3D11_CREATE_DEVICE_SWITCH_TO_REF
    注意 这个标志不支持Direct3D 11.

    D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
    阻止被多线程创建。当使用WARP标志时,WARP和所有光栅不能够被线程调用。这个标志不建议使用。

    D3D11_CREATE_DEVICE_BGRA_SUPPORT
    Dierct2D需要和Direct3D资源交互。

    下面是每个步骤对应的代码:

    一、指明驱动设备等级和特征等级

     1 HRESULT hResult = S_OK;//返回结果
     2 
     3     RECT rc;
     4     GetClientRect(g_hWnd, &rc);//获取窗口客户区大小
     5     UINT width = rc.right - rc.left;
     6     UINT height = rc.bottom - rc.top;
     7 
     8     UINT createDeviceFlags = 0;
     9 #ifdef _DEBUG
    10     createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
    11 #endif
    12 
    13     //驱动类型数组
    14     D3D_DRIVER_TYPE driverTypes[] = 
    15     {
    16         D3D_DRIVER_TYPE_HARDWARE,
    17         D3D_DRIVER_TYPE_WARP,
    18         D3D_DRIVER_TYPE_REFERENCE
    19     };
    20     UINT numDriverTypes = ARRAYSIZE(driverTypes);
    21 
    22     //特征级别数组
    23     D3D_FEATURE_LEVEL featureLevels[] =
    24     {
    25         D3D_FEATURE_LEVEL_11_0,
    26         D3D_FEATURE_LEVEL_10_1,
    27         D3D_FEATURE_LEVEL_10_0
    28     };
    29     UINT numFeatureLevels = ARRAYSIZE(featureLevels);

    二、创建设备和交换链

    交换链具体定义

    typedef struct DXGI_SWAP_CHAIN_DESC {
      DXGI_MODE_DESC   BufferDesc;
      DXGI_SAMPLE_DESC SampleDesc;
      DXGI_USAGE       BufferUsage;
      UINT             BufferCount;
      HWND             OutputWindow;
      BOOL             Windowed;
      DXGI_SWAP_EFFECT SwapEffect;
      UINT             Flags;
    } DXGI_SWAP_CHAIN_DESC;

       BufferDesc指定后缓冲区有关特性;

           SampleDesc指定多重采样,前面说过;

           BufferUsage,对于交换链,为DXGI_USAGE_RENDER_TARGET_OUTPUT;

           BufferCount:我们只创建一个后缓冲区(双缓冲),因此为1;

           OutputWindow:指定窗口句柄,Win32程序初始化完创建的主窗口;

           Windowed:是否全屏;

           DXGI_SWAP_EFFECT:通常为DXGI_SWAP_EFFECT_DISCARD;

           Flags:可选

    其中DXGI_MODE_DESC定义如下
    typedef struct DXGI_MODE_DESC {
      UINT                     Width;
      UINT                     Height;
      DXGI_RATIONAL            RefreshRate;
      DXGI_FORMAT              Format;
      DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
      DXGI_MODE_SCALING        Scaling;
    } DXGI_MODE_DESC, *LPDXGI_MODE_DESC;

    Width、Height为缓冲区大小,一般设为主窗口大小;

    Format为缓冲区类型,一般作为渲染对象缓冲区类型为DXGI_FORMAT_R8G8B8A8_UNORM;

    其他参数一般为固定的。

    交换链的设置

     1 //交换链
     2     DXGI_SWAP_CHAIN_DESC sd;
     3     ZeroMemory(&sd, sizeof(DXGI_SWAP_CHAIN_DESC));//填充
     4     sd.BufferCount = 1;                              //我们只创建一个后缓冲(双缓冲)因此为1
     5     sd.BufferDesc.Width = width;
     6     sd.BufferDesc.Height = height;
     7     sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
     8     sd.BufferDesc.RefreshRate.Numerator = 60;
     9     sd.BufferDesc.RefreshRate.Denominator = 1;
    10     sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    11     sd.OutputWindow = g_hWnd;
    12     sd.SampleDesc.Count = 1;                      //1重采样
    13     sd.SampleDesc.Quality = 0;                      //采样等级
    14     sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;      //常用参数
    15     sd.Windowed = TRUE;                              //是否全屏

    创建设备及交换链,d3d设备一般都是设备本身和硬件之间的通信,而d3d上下文是一种描述设备如何绘制的渲染设备上下文,这也包含了渲染状态和其他的绘图信息。

    而交换链是设备和上下文将要绘制的渲染目标。

    D3D11CreateDeviceAndSwapChain函数原型:

    HRESULT D3D11CreateDeviceAndSwapChain(
      _In_opt_        IDXGIAdapter         *pAdapter,
                      D3D_DRIVER_TYPE      DriverType,
                      HMODULE              Software,
                      UINT                 Flags,
      _In_opt_  const D3D_FEATURE_LEVEL    *pFeatureLevels,
                      UINT                 FeatureLevels,
                      UINT                 SDKVersion,
      _In_opt_  const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
      _Out_opt_       IDXGISwapChain       **ppSwapChain,
      _Out_opt_       ID3D11Device         **ppDevice,
      _Out_opt_       D3D_FEATURE_LEVEL    *pFeatureLevel,
      _Out_opt_       ID3D11DeviceContext  **ppImmediateContext
    );

    pAdapter来选择相应的图形适配器,设为NULL以选择默认的适配器;

    DriverType设置驱动类型,一般毫无疑问选择硬件加速,即D3D_DRIVER_TYPE_HARDWARE,此时下一个参数就是NULL;

    Flags为可选参数,一般为NULL,可以设为D3D11_CREATE_DEVICE_DEBUG、D3D11_CREATE_DEVICE_SINGLETHREADED,或两者一起,前者让要用于调试时收集信息,后者在确定程序只在单线程下运行时设置为它,可以提高性能;

    pFeatureLevels为我们提供给程序的特征等级的一个数组,下一个参数为数组中元素个数;

    SDKVersion恒定为D3D11_SDK_VERSION;

    ppDevice为设备指针的地址,注意设备是指针类型,这里传递的是指针的地址(二维指针,d3d程序中所有的接口都声明为指针类型!);

    pFeatureLevel为最后程序选中的特征等级,我们定义相应的变量,传递它的地址进来;

    ppImmediateContext为设备上下文指针的地址,要求同设备指针。

    创建设备和交换链的相关代码

     1 for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; ++driverTypeIndex)
     2     {
     3         g_driverType = driverTypes[driverTypeIndex];
     4         hResult = D3D11CreateDeviceAndSwapChain(
     5             NULL,                                //默认图形适配器
     6             g_driverType,                        //驱动类型
     7             NULL,                                //实现软件渲染设备的动态库句柄,如果使用的驱动设备类型是软件设备则不能为NULL
     8             createDeviceFlags,                    //创建标志,0用于游戏发布,一般D3D11_CREATE_DEVICE_DEBUG允许我们创建可供调试的设备,在开发中比较有用
     9             featureLevels,                        //特征等级
    10             numFeatureLevels,                    //特征等级数量
    11             D3D11_SDK_VERSION,                    //sdk版本号
    12             &sd,
    13             &g_pSwapChain,
    14             &g_pd3dDevice,
    15             &g_featureLevel,
    16             &g_pImmediateContext
    17             );
    18         if (SUCCEEDED(hResult))
    19             break;
    20     }
    21     if (FAILED(hResult))
    22         return hResult;

    三、创建和绑定渲染目标视图

    一个渲染目标视图是一个由Output MergerStage读取的D3D资源。交换链的主缓存和辅助缓存为彩色的图像,通过调用交换链中的函数GetBuffer来得到它的指针。得到指针后,然后再通过CreateRenderTargetView函数来创建一个渲染目标视图。创建完渲染目标后,就可以调用Release()释放指针到交换链的后台缓存了。当想渲染一个特定的渲染目标的时,要在绘制函数调用前对它进行设置,这个工作是由OMSetRenderTarget函数完成的。

    CreateRenderTargetView函数原型

    HRESULT CreateRenderTargetView(
      [in]                  ID3D11Resource                *pResource,
      [in, optional]  const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,
      [out, optional]       ID3D11RenderTargetView        **ppRTView
    );

    pResource为视图对应资源

    pDesc为视图描述 

    ppRTView要创建的视图,是一个指针的地址

    这一部分的代码

     1 //创建渲染目标视图
     2     ID3D11Texture2D *pBackBuffer = NULL;
     3     //获取后缓冲区地址
     4     hResult = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
     5     if (FAILED(hResult))
     6         return hResult;
     7 
     8     //创建目标视图
     9     hResult = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
    10     //释放后缓冲
    11     pBackBuffer->Release();
    12     if (FAILED(hResult))
    13         return hResult;
    14 
    15     //绑定到渲染管线
    16     g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);

    四、创建视口

    视口定义了渲染到屏幕上的面积,对于单屏游戏来说一般为全屏的,这样我们设置视口的width和height为交换链对应的width、height就好了;对于分屏游戏,可以创建两个视口

    放在屏幕不同位置,以不同玩家的角度来渲染。

    D3D11_VIEWPORT定义

    typedef struct D3D11_VIEWPORT {
      FLOAT TopLeftX;        //视口左上角x坐标,一般视口占满屏幕的,所以为0
      FLOAT TopLeftY;        //y坐标
      FLOAT Width;            //视口宽度,一般与后缓冲区一致,以保持图像不变形
      FLOAT Height;            //高度,同上
      FLOAT MinDepth;        //最小深度值:0.0f
      FLOAT MaxDepth;        //最大深度值:1.0f
    } D3D11_VIEWPORT;

    具体代码

    1 //设置viewport
    2     D3D11_VIEWPORT vp;
    3     vp.Height = (FLOAT)height;
    4     vp.Width = (FLOAT)width;
    5     vp.MinDepth = 0.0f;
    6     vp.MaxDepth = 1.0f;
    7     vp.TopLeftX = 0;
    8     vp.TopLeftY = 0;
    9     g_pImmediateContext->RSSetViewports(1, &vp);

     接下来的Render函数中实现了清除显示屏幕的功能

    float ClearColor[4] = { 0.5f, 0.1f, 0.2f, 1.0f }; //red,green,blue,alpha
        g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);
        g_pSwapChain->Present(0, 0);

      

    下面给出整个工程的代码:

    #include <windows.h>
    #include <d3d11.h>
    #include <DxErr.h>
    #include <D3DX11.h>
    
    HINSTANCE g_hInstance = NULL;
    HWND g_hWnd = NULL;
    LPCWSTR g_name = L"FirstD3D11Demo";
    D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;                //驱动类型
    D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;            //特征等级    
    ID3D11Device *g_pd3dDevice = NULL;                                    //设备
    ID3D11DeviceContext *g_pImmediateContext = NULL;                    //设备上下文
    IDXGISwapChain *g_pSwapChain = NULL;                                //交换链
    ID3D11RenderTargetView *g_pRenderTargetView = NULL;                    //要创建的视图
    
    
    HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
    HRESULT InitDevice();
    void CleanupDevice();
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    void Render();
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
    {
        if (FAILED(InitWindow(hInstance, nShowCmd)))
            return 0;
        if (FAILED(InitDevice()))
        {
            CleanupDevice();
            return 0;
        }
        MSG msg;
        ZeroMemory(&msg, sizeof(MSG));
        while (msg.message != WM_QUIT)
        {
            if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else//渲染
            {
                Render();
            }
        }
        CleanupDevice();
        return static_cast<int>(msg.wParam);
    }
    
    HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
    {
        WNDCLASSEX wcex;
        wcex.cbClsExtra = 0;
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.cbWndExtra = 0;
        wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
        wcex.hIcon = LoadIcon(NULL, IDI_WINLOGO);
        wcex.hIconSm = wcex.hIcon;
        wcex.hInstance = hInstance;
        wcex.lpfnWndProc = WndProc;
        wcex.lpszClassName = g_name;
        wcex.lpszMenuName = NULL;
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        if (!RegisterClassEx(&wcex))
            return E_FAIL;
    
        g_hInstance = hInstance;
        RECT rc{0,0,640,480};
        AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
        g_hWnd = CreateWindowEx(WS_EX_APPWINDOW, g_name, g_name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
            rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, g_hInstance, NULL);
        if (!g_hWnd)
            return E_FAIL;
    
        ShowWindow(g_hWnd, nCmdShow);
    
        return S_OK;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wPararm, LPARAM lParam)
    {
        switch (message)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wPararm, lParam);
        }
        return 0;
    }
    
    //创建设备及交换链
    HRESULT InitDevice()
    {
        HRESULT hResult = S_OK;//返回结果
    
        RECT rc;
        GetClientRect(g_hWnd, &rc);//获取窗口客户区大小
        UINT width = rc.right - rc.left;
        UINT height = rc.bottom - rc.top;
    
        UINT createDeviceFlags = 0;
    #ifdef _DEBUG
        createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif
    
        //驱动类型数组
        D3D_DRIVER_TYPE driverTypes[] = 
        {
            D3D_DRIVER_TYPE_HARDWARE,
            D3D_DRIVER_TYPE_WARP,
            D3D_DRIVER_TYPE_REFERENCE
        };
        UINT numDriverTypes = ARRAYSIZE(driverTypes);
    
        //特征级别数组
        D3D_FEATURE_LEVEL featureLevels[] =
        {
            D3D_FEATURE_LEVEL_11_0,
            D3D_FEATURE_LEVEL_10_1,
            D3D_FEATURE_LEVEL_10_0
        };
        UINT numFeatureLevels = ARRAYSIZE(featureLevels);
    
        //交换链
        DXGI_SWAP_CHAIN_DESC sd;
        ZeroMemory(&sd, sizeof(DXGI_SWAP_CHAIN_DESC));//填充
        sd.BufferCount = 1;                              //我们只创建一个后缓冲(双缓冲)因此为1
        sd.BufferDesc.Width = width;
        sd.BufferDesc.Height = height;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.BufferDesc.RefreshRate.Numerator = 60;
        sd.BufferDesc.RefreshRate.Denominator = 1;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.OutputWindow = g_hWnd;
        sd.SampleDesc.Count = 1;                      //1重采样
        sd.SampleDesc.Quality = 0;                      //采样等级
        sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;      //常用参数
        sd.Windowed = TRUE;                              //是否全屏
    
        for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; ++driverTypeIndex)
        {
            g_driverType = driverTypes[driverTypeIndex];
            hResult = D3D11CreateDeviceAndSwapChain(
                NULL,                                //默认图形适配器
                g_driverType,                        //驱动类型
                NULL,                                //实现软件渲染设备的动态库句柄,如果使用的驱动设备类型是软件设备则不能为NULL
                createDeviceFlags,                    //创建标志,0用于游戏发布,一般D3D11_CREATE_DEVICE_DEBUG允许我们创建可供调试的设备,在开发中比较有用
                featureLevels,                        //特征等级
                numFeatureLevels,                    //特征等级数量
                D3D11_SDK_VERSION,                    //sdk版本号
                &sd,
                &g_pSwapChain,
                &g_pd3dDevice,
                &g_featureLevel,
                &g_pImmediateContext
                );
            if (SUCCEEDED(hResult))
                break;
        }
        if (FAILED(hResult))
            return hResult;
    
        //创建渲染目标视图
        ID3D11Texture2D *pBackBuffer = NULL;
        //获取后缓冲区地址
        hResult = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
        if (FAILED(hResult))
            return hResult;
    
        //创建目标视图
        hResult = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
        //释放后缓冲
        pBackBuffer->Release();
        if (FAILED(hResult))
            return hResult;
    
        //绑定到渲染管线
        g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
    
        //设置viewport
        D3D11_VIEWPORT vp;
        vp.Height = (FLOAT)height;
        vp.Width = (FLOAT)width;
        vp.MinDepth = 0.0f;
        vp.MaxDepth = 1.0f;
        vp.TopLeftX = 0;
        vp.TopLeftY = 0;
        g_pImmediateContext->RSSetViewports(1, &vp);
    
        return S_OK;
    }
    
    void Render()
    {
        float ClearColor[4] = { 0.5f, 0.1f, 0.2f, 1.0f }; //red,green,blue,alpha
        g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);
        g_pSwapChain->Present(0, 0);
    }
    
    void CleanupDevice()
    {
        if (g_pImmediateContext)
            g_pImmediateContext->ClearState();
        if (g_pSwapChain)
            g_pSwapChain->Release();
        if (g_pRenderTargetView)
            g_pRenderTargetView->Release();
        if (g_pImmediateContext)
            g_pImmediateContext->Release();
        if (g_pd3dDevice)
            g_pd3dDevice->Release();
    }
     
     

     
  • 相关阅读:
    MySQL
    MySQL
    MySQL
    javaScript之深度理解原型链
    javaScript之this的五种情况
    ES6之箭头函数中的this
    javaScript之跨浏览器的事件对象
    javaScript之事件处理程序
    javaScript之promise
    VUE之使用百度地图API
  • 原文地址:https://www.cnblogs.com/zhangbaochong/p/5174059.html
Copyright © 2020-2023  润新知