• win32


    我们可以使用D3D为游戏,科学和桌面应用程序创建3-D图形。

    当然,我们第一步要开始认识里面的基本api。

    #include <d3d11.h>  
    #include <chrono>
    
    using namespace std::chrono;
    
    #pragma comment(lib,"D3D11.lib")
    //-----------------------------------------------------------------------------  
    // 全局变量  
    //-----------------------------------------------------------------------------  
    HRESULT hr;
    ID3D11Device* g_pd3dDevice = nullptr;
    IDXGISwapChain* g_pSwapChain = nullptr;
    ID3D11DeviceContext* g_pImmediateContext = nullptr;
    ID3D11RenderTargetView* pTarget = nullptr;
    std::chrono::steady_clock::time_point last;
    
    //-----------------------------------------------------------------------------  
    // Desc: 初始化Direct3D  
    //-----------------------------------------------------------------------------  
    HRESULT InitD3D(HWND hWnd)
    {
        DXGI_SWAP_CHAIN_DESC sd;
        ZeroMemory(&sd, sizeof(sd));
        sd.BufferCount = 1;  // BufferCount: number of buffers  1: 设置一个后缓存,再加上一个自动设置的前缓存,就是双缓存
        sd.BufferDesc.Width = 0; //系统自动设置合适的值
        sd.BufferDesc.Height = 0;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.BufferDesc.RefreshRate.Numerator = 0;  //不处于全屏模式,所以不用管刷新率
        sd.BufferDesc.RefreshRate.Denominator = 0;
        sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;  //程序自己决定缩放比率
        sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; //对于大多数显示器,不用设置扫描线顺序
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;  // Use the surface or resource as an output render target.
        sd.OutputWindow = hWnd;
        sd.SampleDesc.Count = 1;   //不需要抗锯齿,一般默认该值
        sd.SampleDesc.Quality = 0;
        sd.Windowed = TRUE; //窗口化
    
        if (FAILED(hr = D3D11CreateDeviceAndSwapChain(
            NULL,
            D3D_DRIVER_TYPE_HARDWARE,
            NULL,
            0,
            NULL,
            0,
            D3D11_SDK_VERSION,
            &sd,
            &g_pSwapChain,
            &g_pd3dDevice,
            NULL,
            &g_pImmediateContext)))
        {
            return hr;
        }
        //gain access to texture subresource in swap chain (back buffer)
        ID3D11Resource* pBackBuffer = nullptr;
        g_pSwapChain->GetBuffer(0, _uuidof(ID3D11Resource), reinterpret_cast<void**>(&pBackBuffer)); // Get the back buffer  0: 后缓存的索引
        g_pd3dDevice->CreateRenderTargetView(
            pBackBuffer,
            nullptr,
            &pTarget  // pTarget is used to save RenderTarget view
        );
        pBackBuffer->Release(); 
       
    }
    
    
    //-----------------------------------------------------------------------------  
    // Desc: 释放创建对象  
    //-----------------------------------------------------------------------------  
    VOID Cleanup()
    {
        //释放Direct3D设备对象  
        if (g_pd3dDevice != NULL)
            g_pd3dDevice->Release();
        //释放Direct3D对象  
        if (g_pSwapChain != NULL)
            g_pSwapChain->Release();
        if (g_pImmediateContext != NULL)
            g_pImmediateContext->Release();
        if (pTarget != NULL)
            pTarget->Release();
    }
    
    //定时器
    float Peek()
    {
        return duration<float>(steady_clock::now() - last).count();
    }
    
    //-----------------------------------------------------------------------------  
    // Desc: 渲染图形  
    //-----------------------------------------------------------------------------  
    void Render()
    {
        // Just clear the backbuffer
        float r = sin(Peek()) / 2.0f + 0.5f;
        float ClearColor[4] = { r, r, 1.0f, 1.0f }; //red,green,blue,alpha
        g_pImmediateContext->ClearRenderTargetView(pTarget, ClearColor); // undertake all the drawing work
        g_pSwapChain->Present(0u, 0u);    //Presents a rendered image to the user.
    }
    
    
    //-----------------------------------------------------------------------------  
    // Desc: 消息处理  
    //-----------------------------------------------------------------------------  
    LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_DESTROY:
            Cleanup();
            PostQuitMessage(0);
            return 0;
    
        case WM_PAINT:
            Render();
            ValidateRect(hWnd, NULL);
            return 0;
        }
    
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    
    //-----------------------------------------------------------------------------  
    // Desc: 程序入口  
    //-----------------------------------------------------------------------------  
    INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
    {
        //注册窗口类  
        WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                          GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                          L"ClassName", NULL };
        RegisterClassEx(&wc);
    
        //创建窗口  
        HWND hWnd = CreateWindow(L"ClassName", L"A Direct3D appp",
            WS_OVERLAPPEDWINDOW, 200, 100, 600, 500,
            NULL, NULL, wc.hInstance, NULL);
        last = steady_clock::now(); //running timer
        //初始化Direct3D  
        if (SUCCEEDED(InitD3D(hWnd)))
        {
            //显示主窗口  
            ShowWindow(hWnd, SW_SHOWDEFAULT);
            UpdateWindow(hWnd);
    
            //进入消息循环  
            MSG msg;
            ZeroMemory(&msg, sizeof(msg));
            while (msg.message != WM_QUIT)
            {
                if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else
                {
                    Render();  //渲染图形  
                }
            }
        }
    
        UnregisterClass(L"ClassName", wc.hInstance);
        return 0;
    }

    先上一个简单的demo供参考,里面有很多的参数介绍。

    大概流程:

    创建一个交换链(D3D11CreateDeviceAndSwapChain),然后创建一个后缓存(GetBuffer),再创建一个RenderTarget作为后台缓冲区的渲染目标(ID3D11RenderTargetView* pTarget = nullptr)。 使用CreateRenderTargetView创建用于访问资源数据的渲染目标视图,它承担所有绘图工作。

    ClearRenderTargetView将渲染目标中的所有元素设置为一个值。

    上面都是对象的创建, 我们还需要context,即上下文,用于发送渲染命令并配置渲染管道。D3D11CreateDeviceAndSwapChain已经帮我们创建好了

    等这些都创建完毕,则可以调用g_pSwapChain->Present(0u, 0u); 来将渲染的图片发给user --------------------Present命令相当于bitblt,用于将后缓存的视图快速复制给前缓存

    另附一张图:

     简单说来就是,传统情况下,显示器从单个缓冲区扫描像素的时候,它遵循自左上角到右下角的点扫描,就是一个像素一个像素的扫描,那么如果我们在单个缓冲区里绘制东西的时候,还没绘制好就被显示器扫描走了,那就会显示不完整的图形。

     所以D3D需要后缓存来避免这样的问题。当后缓存的东西绘制完毕,使用present或者filp来将后缓存快速复制给前缓存,那么显示器在扫描的时候,每次扫描完前缓存的东西时(扫描也需要时间的),后缓存已经准备好了。

    言归正传,在代码中我们有了后缓存pBackBuffer,但是我们得需要一个渲染视图在后缓存中绘制我们需要的东西,那么我们就需要创建一个渲染对象pTarget,然后使用CreateRenderTargetView来使pTarget保存渲染的视图(渲染视图相当于后缓冲区)。 好了,有了渲染视图,就可以使用ClearRenderTargetView将RGBA的数值渲染到视图中,这样我们就可以使用Present来显示图像了。

    为什么需要渲染呢?

    从逻辑上将, 我们会说:“后缓存...!" 并完成。 但是,Direct3D在这一点上并不知道。 

    在Direct3D中渲染时,必须建立渲染目标。 这是一个简单的com对象,它在视频内存中维护一个位置,供我们渲染。 在大多数情况下, 这是后台缓冲区。

    拓展:

    纹理资源是旨在存储纹理像素的数据的结构化集合。纹素表示管道可以读取或写入的纹理的最小单位。与缓冲区不同,纹理可以被着色器单元读取,从而可以通过纹理采样器进行过滤。

    渲染管线是指:在给定一个3D场景的几何描述及一架已确定位置和方向的虚拟摄像机(virtual camera)时,根据虚拟摄像机的视角生成2D图像的一系列步骤。

  • 相关阅读:
    Hive 导入、导出数据
    mysql 命令行参数说明
    mysql 查看表信息
    python之冒泡排序
    python之选择排序
    python之快速排序
    光荣之路测试开发面试linux考题之四:性能命令
    测试开发linux面试之三:后台进程之操作
    测试开发面试的Linux面试题总结之二:常用命令
    测试开发面试的Linux面试题总结之一:vim使用方法
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14216932.html
Copyright © 2020-2023  润新知