• 基于 DirectX11 的 MMDViewer 03-渲染管线


      准备工作:  


       开始搭建框架之前,你需要确保已经进行了 D3D 开发环境的搭建,相关教程可以阅读这篇文章。不了解 DirectX11 的人,这个作者有关 DirectX11 的教程最好阅读一下,虽然文章不多,但都很详细,有了基础以后在进行深一步的扩展。

      和 OpenGL 一样,在渲染出图形之前,都需要经过很多步骤(窗口配置、图形上下文的创建、顶点数据配置、着色器的配置、变换矩阵配置等等),不是一两行代码就可以了。而 DirectX11 则更为复杂,其中如果发生一点错误,将导致图形渲染失败,但你难以检测发生的错误。对于初学者,在你辛辛苦苦编写完渲染代码后,却出现显示不出图形但又不知道哪里出错的情况,那你又能怎么办呢?

      下面给出一个基本的渲染框架(能够渲染出一个旋转正方体),通过在这个框架上进行扩展,开发 MMDViewer 项目。而不是自己编写一个可能有错误的框架,这样会浪费大量时间。

    这个框架并不是最简单的框架,但它包括了渲染管线的大部分内容:着色器设置、MVP 变换矩阵设置、裁剪矩形区域(在 GUI 项目常用)、光栅化状态设置、模板测试、深度测试、颜色混合(支持 alpha 通道)。

    #include <windows.h>
    #include <string>
    
    /* 引入 D3D 头文件 */
    #include <D3D11.h>
    #include <D3DX11.h>
    #include <D3Dcompiler.h>
    #include <xnamath.h>
    
    #pragma comment(lib, "d3d11.lib")
    #pragma comment(lib, "d3dx10.lib")
    #pragma comment(lib, "d3dx11.lib")
    #pragma comment(lib, "dxguid.lib")
    #pragma comment(lib, "d3dcompiler.lib")
    
    //--------------------------------------------------------------------------------------
    // Structures
    //--------------------------------------------------------------------------------------
    struct SimpleVertex
    {
        XMFLOAT3 Pos;
        XMFLOAT4 Color;
    };
    
    struct ConstantBuffer
    {
        XMMATRIX mWorld;
        XMMATRIX mView;
        XMMATRIX mProjection;
    };
    
    
    //--------------------------------------------------------------------------------------
    // Global Variables
    //--------------------------------------------------------------------------------------
    HINSTANCE               g_hInst = NULL;
    HWND                    g_hWnd = NULL;
    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;
    ID3D11DepthStencilView* g_pDepthStencilView = NULL;
    ID3D11VertexShader*     g_pVertexShader = NULL;
    ID3D11PixelShader*      g_pPixelShader = NULL;
    ID3D11InputLayout*      g_pVertexLayout = NULL;
    ID3D11Buffer*           g_pVertexBuffer = NULL;
    ID3D11Buffer*           g_pIndexBuffer = NULL;
    ID3D11Buffer*           g_pConstantBuffer = NULL;
    XMMATRIX                g_World;
    XMMATRIX                g_View;
    XMMATRIX                g_Projection;
    
    //--------------------------------------------------------------------------------------
    // Helper for compiling shaders with D3DX11
    //--------------------------------------------------------------------------------------
    HRESULT CompileShaderFromFile(char* fiel_name, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
    {
        HRESULT hr = S_OK;
    
        DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
    #if defined( DEBUG ) || defined( _DEBUG )
        // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
        // Setting this flag improves the shader debugging experience, but still allows 
        // the shaders to be optimized and to run exactly the way they will run in 
        // the release configuration of this program.
        dwShaderFlags |= D3DCOMPILE_DEBUG;
    #endif
    
        ID3DBlob* pErrorBlob;
        hr = D3DX11CompileFromFileA(fiel_name, NULL, NULL, szEntryPoint, szShaderModel, dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL);
        if ( FAILED(hr) )
        {
            if ( pErrorBlob != NULL )
            {
                OutputDebugStringA(( char* ) pErrorBlob->GetBufferPointer());
            }
            if ( pErrorBlob ) pErrorBlob->Release();
            return hr;
        }
        if ( pErrorBlob ) pErrorBlob->Release();
    
        return S_OK;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Forward declarations
    //--------------------------------------------------------------------------------------
    HRESULT InitDevice()
    {
        HRESULT hr = S_OK;
    
        RECT rc;
        GetClientRect(g_hWnd, &rc);
        UINT width = rc.right - rc.left;
        UINT height = rc.bottom - rc.top;
    
        //----------------------------------------------------------------------------
        // 渲染管线设置,创建设备、设备上下文和交换链
        //----------------------------------------------------------------------------
        /* 设置调试标记,程序退出时也可以显示所有对象的引用数量,可以用于内存泄露检测 */
        UINT create_device_flags = 0;
    #ifdef _DEBUG
        create_device_flags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif
    
        D3D_DRIVER_TYPE driver_types[] =
        {
            D3D_DRIVER_TYPE_HARDWARE,
            D3D_DRIVER_TYPE_WARP,
            D3D_DRIVER_TYPE_REFERENCE,
        };
        UINT num_driver_types = ARRAYSIZE(driver_types);
    
        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 swap_desc;
        ZeroMemory(&swap_desc, sizeof(swap_desc));
        swap_desc.BufferCount = 1;
        swap_desc.BufferDesc.Width = width;
        swap_desc.BufferDesc.Height = height;
        swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        swap_desc.BufferDesc.RefreshRate.Numerator = 60;
        swap_desc.BufferDesc.RefreshRate.Denominator = 1;
        swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swap_desc.OutputWindow = g_hWnd;
        swap_desc.SampleDesc.Count = 1;
        swap_desc.SampleDesc.Quality = 0;
        swap_desc.Windowed = TRUE;
    
        for ( UINT driver_type_index = 0; driver_type_index < num_driver_types; driver_type_index++ )
        {
            g_driverType = driver_types[driver_type_index];
            hr = D3D11CreateDeviceAndSwapChain(NULL, g_driverType, NULL, create_device_flags, featureLevels, numFeatureLevels,
                D3D11_SDK_VERSION, &swap_desc, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
            if ( SUCCEEDED(hr) ) break;
        }
        if ( FAILED(hr) ) return hr;
    
        //----------------------------------------------------------------------------
        // 渲染管线输出设置
        //----------------------------------------------------------------------------
        /* 获取交换链的后缓冲 */
        ID3D11Texture2D* pBackBuffer = NULL;
        hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), ( LPVOID* ) &pBackBuffer);
        if ( FAILED(hr) ) return hr;
    
        /* 创建渲染目标视图 */
        hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
        pBackBuffer->Release();
        if ( FAILED(hr) ) return hr;
    
        /* 设置视口 */
        D3D11_VIEWPORT view_port;
        view_port.Width = ( FLOAT ) width;
        view_port.Height = ( FLOAT ) height;
        view_port.MinDepth = 0.0f;
        view_port.MaxDepth = 1.0f;
        view_port.TopLeftX = 0;
        view_port.TopLeftY = 0;
        g_pImmediateContext->RSSetViewports(1, &view_port);
    
        //----------------------------------------------------------------------------
        // 渲染管线输入数据
        //----------------------------------------------------------------------------
        /* 顶点缓冲区 */
        SimpleVertex vertices[] =
        {
            { XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
            { XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
            { XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
            { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) }
        };
        D3D11_BUFFER_DESC vertex_desc;
        vertex_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        vertex_desc.ByteWidth = sizeof( SimpleVertex ) * 8;
        vertex_desc.CPUAccessFlags = 0;
        vertex_desc.MiscFlags = 0;
        vertex_desc.StructureByteStride = 0;
        vertex_desc.Usage = D3D11_USAGE_DEFAULT;
    
        D3D11_SUBRESOURCE_DATA vertex_data;
        vertex_data.pSysMem = vertices;
        vertex_data.SysMemPitch = 0;
        vertex_data.SysMemSlicePitch = 0;
        hr = g_pd3dDevice->CreateBuffer(&vertex_desc, &vertex_data, &g_pVertexBuffer);
        if ( FAILED(hr) ) return hr;
    
        /* 索引缓冲区 */
        UINT indices[] = {
            7, 4, 5, 7, 5, 6,    // 前面
            4, 0, 1, 4, 1, 5,    // 上面
            3, 7, 6, 3, 6, 2,    // 下面
            2, 1, 0, 2, 0, 3,    // 后面
            6, 5, 1, 6, 1, 2,    // 右面
            3, 0, 4, 3, 4, 7     // 左面
        };
        D3D11_BUFFER_DESC index_desc;
        index_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
        index_desc.ByteWidth = sizeof( UINT ) * 36;
        index_desc.MiscFlags = 0;
        index_desc.CPUAccessFlags = 0;
        index_desc.StructureByteStride = 0;
        index_desc.Usage = D3D11_USAGE_DEFAULT;
    
        D3D11_SUBRESOURCE_DATA index_data;
        index_data.pSysMem = indices;
        index_data.SysMemPitch = 0;
        index_data.SysMemSlicePitch = 0;
        hr = g_pd3dDevice->CreateBuffer(&index_desc, &index_data, &g_pIndexBuffer);
        if ( FAILED(hr) ) return hr;
    
        /* 设置顶点缓冲区 */
        UINT stride = sizeof(SimpleVertex);
        UINT offset = 0;
        g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
        g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
    
        /* 设置图元 */
        g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    
        //----------------------------------------------------------------------------
        // 着色器设置
        //----------------------------------------------------------------------------
        /* 编译顶点着色器 */
        ID3DBlob* pVSBlob = NULL;
        hr = CompileShaderFromFile("shader.hlsl", "VS", "vs_5_0", &pVSBlob);
        if ( FAILED(hr) )
        {
            MessageBox(NULL, L"不能编译着色程序", L"Error", MB_OK); return hr;
        }
    
        /* 创建顶点着色器 */
        hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
        if ( FAILED(hr) )
        {
            pVSBlob->Release(); return hr;
        }
    
        D3D11_INPUT_ELEMENT_DESC layout[] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        };
        UINT numElements = ARRAYSIZE(layout);
    
        /* 创建输入布局  */
        hr = g_pd3dDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout);
        pVSBlob->Release();
        if ( FAILED(hr) ) return hr;
    
        /* 设置输入布局  */
        g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
    
        /* 编译像素着色器 */
        ID3DBlob* pPSBlob = NULL;
        hr = CompileShaderFromFile("shader.hlsl", "PS", "ps_5_0", &pPSBlob);
        if ( FAILED(hr) )
        {
            MessageBox(NULL, L"不能编译着色程序", L"Error", MB_OK); return hr;
        }
    
        /* 创建像素着色器 */
        hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
        pPSBlob->Release();
        if ( FAILED(hr) ) return hr;
    
        //----------------------------------------------------------------------------
        // 光栅化状态
        //----------------------------------------------------------------------------
        ID3D11RasterizerState* rasterater_state = nullptr;
        D3D11_RASTERIZER_DESC rasterizer_desc;
        ZeroMemory(&rasterizer_desc, sizeof(rasterizer_desc));
    
        rasterizer_desc.CullMode = D3D11_CULL_BACK;           // 背面剔除    
        rasterizer_desc.FillMode = D3D11_FILL_SOLID;          // 填充由顶点形成的三角形
        rasterizer_desc.ScissorEnable = true;                 // 开启裁剪
        rasterizer_desc.FrontCounterClockwise = false;        // 顺时针为正方向
        hr = g_pd3dDevice->CreateRasterizerState(&rasterizer_desc, &rasterater_state);
        if ( FAILED(hr) ) return hr;
    
        g_pImmediateContext->RSSetState(rasterater_state);
        rasterater_state->Release();
    
        /* 设置裁剪矩形,这里仅设置和窗口大小一样,所以没有效果 */
        D3D11_RECT scissor = { 0 /* left */, 0 /* top */, 800 /* right */, 600 /* bottom */ };
        g_pImmediateContext->RSSetScissorRects(1, &scissor);
    
        //----------------------------------------------------------------------------
        // 模板测试和深度测试
        //----------------------------------------------------------------------------
        ID3D11Texture2D* depth_stencil_tex = nullptr;
        D3D11_TEXTURE2D_DESC depth_stencil_tex_desc;
        ZeroMemory(&depth_stencil_tex_desc, sizeof(depth_stencil_tex_desc));
    
        depth_stencil_tex_desc.Width = width;
        depth_stencil_tex_desc.Height = height;
        depth_stencil_tex_desc.MipLevels = 1;
        depth_stencil_tex_desc.ArraySize = 1;
        depth_stencil_tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
        depth_stencil_tex_desc.SampleDesc.Count = 1;
        depth_stencil_tex_desc.SampleDesc.Quality = 0;
        depth_stencil_tex_desc.Usage = D3D11_USAGE_DEFAULT;
        depth_stencil_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
        depth_stencil_tex_desc.MiscFlags = 0;
        depth_stencil_tex_desc.CPUAccessFlags = 0;
        hr = g_pd3dDevice->CreateTexture2D(&depth_stencil_tex_desc, 0, &depth_stencil_tex);
        if ( FAILED(hr) ) return hr;
    
        hr = g_pd3dDevice->CreateDepthStencilView(depth_stencil_tex, 0, &g_pDepthStencilView);
        if ( FAILED(hr) ) return hr;
    
        /* 设置深度、模板视图到渲染管线 */
        g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
        depth_stencil_tex->Release();
    
        /* 设置深度、模板状态到渲染管线 */
        ID3D11DepthStencilState* depth_stencil_state = nullptr;
        D3D11_DEPTH_STENCIL_DESC depth_stencil_desc;
        ZeroMemory(&depth_stencil_desc, sizeof(depth_stencil_desc));
    
        depth_stencil_desc.DepthEnable = TRUE;
        depth_stencil_desc.DepthFunc = D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS;
        depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL;
        depth_stencil_desc.StencilEnable = FALSE;
        depth_stencil_desc.FrontFace.StencilFunc = D3D11_COMPARISON_FUNC::D3D11_COMPARISON_ALWAYS;
        depth_stencil_desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
        depth_stencil_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
        depth_stencil_desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
        depth_stencil_desc.BackFace = depth_stencil_desc.FrontFace;
        depth_stencil_desc.StencilReadMask = 0xFF;
        depth_stencil_desc.StencilWriteMask = 0xFF;
        hr = g_pd3dDevice->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state);
        if ( FAILED(hr) ) return hr;
    
        g_pImmediateContext->OMSetDepthStencilState(depth_stencil_state, 1);
        depth_stencil_state->Release();
    
        //----------------------------------------------------------------------------
        // 颜色混合
        //----------------------------------------------------------------------------
        D3D11_BLEND_DESC blend_desc;
        ZeroMemory(&blend_desc, sizeof(blend_desc));
    
        blend_desc.AlphaToCoverageEnable = false;
        blend_desc.IndependentBlendEnable = false;            // 是否使用多个目标渲染视图
        blend_desc.RenderTarget[0].BlendEnable = true;
        blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
        blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
        blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
        blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
        blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
        blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
        blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    
        ID3D11BlendState* blend_state = nullptr;
        hr = g_pd3dDevice->CreateBlendState(&blend_desc, &blend_state);
        if ( FAILED(hr) ) return hr;
    
        const float blend_factor[4] = { 1, 1, 1, 1 };
        g_pImmediateContext->OMSetBlendState(blend_state, blend_factor, 0xFFFFFFFF);
        blend_state->Release();
    
        //----------------------------------------------------------------------------
        // 视图矩阵和投影矩阵
        //----------------------------------------------------------------------------
        D3D11_BUFFER_DESC constant_desc;
        constant_desc.Usage = D3D11_USAGE_DEFAULT;
        constant_desc.ByteWidth = sizeof(ConstantBuffer);
        constant_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        constant_desc.CPUAccessFlags = 0;
        constant_desc.MiscFlags = 0;
        constant_desc.StructureByteStride = 0;
        hr = g_pd3dDevice->CreateBuffer(&constant_desc, NULL, &g_pConstantBuffer);
        if ( FAILED(hr) ) return hr;
    
        /* 初始化世界矩阵 */
        g_World = XMMatrixIdentity();
    
        /* 初始化视图矩阵 */
        XMVECTOR eye = XMVectorSet(1.0f, 1.0f, -1.5f, 0.0f);
        XMVECTOR at  = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
        XMVECTOR up  = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
        g_View = XMMatrixLookAtLH(eye, at, up);
    
        /* 初始化投影矩阵 */
        g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, width / ( FLOAT ) height, 0.01f, 100.0f);
    
        return S_OK;
    }
    
    void CleanupDevice()
    {
        if ( g_pImmediateContext ) g_pImmediateContext->ClearState();
    
        if ( g_pVertexBuffer ) g_pVertexBuffer->Release();
        if ( g_pIndexBuffer ) g_pIndexBuffer->Release();
        if ( g_pVertexLayout ) g_pVertexLayout->Release();
        if ( g_pVertexShader ) g_pVertexShader->Release();
        if ( g_pPixelShader ) g_pPixelShader->Release();
        if ( g_pConstantBuffer ) g_pConstantBuffer->Release();
        if ( g_pRenderTargetView ) g_pRenderTargetView->Release();
        if ( g_pDepthStencilView ) g_pDepthStencilView->Release();
        if ( g_pSwapChain ) g_pSwapChain->Release();
        if ( g_pImmediateContext ) g_pImmediateContext->Release();
        if ( g_pd3dDevice ) g_pd3dDevice->Release();
    }
    
    void Render()
    {
        //----------------------------------------------------------------------------
        // 旋转正方体
        //----------------------------------------------------------------------------
        /* 更新时间 */
        static float t = 0.0f;
        if ( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
        {
            t += ( float ) XM_PI * 0.0125f;
        }
        else
        {
            static DWORD dwTimeStart = 0;
            DWORD dwTimeCur = GetTickCount();
            if ( dwTimeStart == 0 )
            {
                dwTimeStart = dwTimeCur;
            }
            t = (dwTimeCur - dwTimeStart) / 1000.0f;
        }
        /* 更新世界矩阵,使正方体旋转 */
        g_World = XMMatrixRotationY(t);
    
        //----------------------------------------------------------------------------
        // 渲染
        //----------------------------------------------------------------------------
        /* 清空后缓冲 */
        float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f };
        g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);
        g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
    
        /* 更新常量缓冲区数据 */
        ConstantBuffer cb;
        cb.mView = XMMatrixTranspose(g_View);
        cb.mWorld = XMMatrixTranspose(g_World);
        cb.mProjection = XMMatrixTranspose(g_Projection);
        g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, NULL, &cb, 0, 0);
    
        /* 渲染三角形 */
        g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
        g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
        g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
        g_pImmediateContext->DrawIndexed(36, 0, 0);
    
        g_pSwapChain->Present(1, 0);
    }
    
    /* 窗口事件处理回调函数 */
    LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch ( msg )
        {
        case WM_CLOSE:
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case WM_PAINT:
            RECT rect;
            if ( GetUpdateRect(wnd, &rect, FALSE) )
            {
                ValidateRect(wnd, &rect);
            }
            break;
        }
        return DefWindowProc(wnd, msg, wParam, lParam);
    }
    
    /* 创建窗口并返回句柄 */
    HWND Create()
    {
        /* 设计窗口类 */
        WNDCLASS wndclass;
        memset(&wndclass, 0, sizeof(WNDCLASSA));
    
        wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        wndclass.lpfnWndProc = ( WNDPROC ) WindowProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = ( HINSTANCE ) GetModuleHandle(0);
        wndclass.hIcon = 0;
        wndclass.hCursor = 0;
        wndclass.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
        wndclass.lpszMenuName = 0;
        wndclass.lpszClassName = L"MMDViewer";
    
        /* 注册窗口类 */
        RegisterClass(&wndclass);
    
        /* 不能改变窗口大小 */
        int style = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
    
        /* 根据客户区大小计算窗口大小 */
        RECT rect = { 0, 0, 800, 600 };
        AdjustWindowRect(&rect, style, 0);
    
        /* 居中显示计算窗口位置和大小 */
        int w = rect.right - rect.left;
        int h = rect.bottom - rect.top;
        int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
        int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
    
        /* 创建窗口 */
        HWND hwnd = CreateWindow(L"MMDViewer", L"MMDViewer", style, x, y, w, h, NULL, 0, ( HINSTANCE ) GetModuleHandle(0), 0);
    
        /* 显示窗口 */
        ShowWindow(hwnd, SW_SHOWNORMAL);
        UpdateWindow(hwnd);
    
        return hwnd;
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
        g_hWnd = Create();
    
        if ( FAILED(InitDevice()) )
        {
            CleanupDevice();
            return 0;
        }
    
        /* 主事件循环 */
        MSG msg = { 0 };
        while ( WM_QUIT != msg.message )
        {
            if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            Render();
        }
    
        CleanupDevice();
        return 0;
    }

      Shader 代码:

    //--------------------------------------------------------------------------------------
    // Constant Buffer Variables
    //--------------------------------------------------------------------------------------
    cbuffer ConstantBuffer : register( b0 )
    {
        matrix World;
        matrix View;
        matrix Projection;
    }
    
    //--------------------------------------------------------------------------------------
    struct VS_OUTPUT
    {
        float4 Pos : SV_POSITION;
        float4 Color : COLOR0;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex Shader
    //--------------------------------------------------------------------------------------
    VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
    {
        VS_OUTPUT output = (VS_OUTPUT)0;
        output.Pos = mul( Pos, World );
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Color = Color;
        return output;
    }
    
    //--------------------------------------------------------------------------------------
    // Pixel Shader
    //--------------------------------------------------------------------------------------
    float4 PS( VS_OUTPUT input ) : SV_Target
    {
        return input.Color;
    }

      配置好相关的库后,运行程序,你会看到一个旋转的三角形:

      渲染管线:


      渲染管线就是将 3D 图像转换成 2D 图像输出到屏幕的过程,所以你要进行渲染操作就要使用渲染管线。那么渲染管线在哪呢?有如何创建渲染管线呢?渲染管线的渲染结果如何输出到你创建的窗口呢?

      为此需要关注三个对象:设备(ID3D11Device)、设备上下文(ID3D11DeviceContext)和交换链(IDXGISwapChain),这三者和渲染管线有以下关系:

      1、设备(ID3D11Device):用于分配GPU资源,如缓冲,纹理,着色器和状态对象(仅举几例),从框架代码中可以看出,基本上都是 CreateXX() 函数。

      2、设备上下文(ID3D11DeviceContext):你可以将它理解成渲染管线,用于设置管线状态、将资源绑定到渲染管线和生成渲染命令。

      3、交换链(IDXGISwapChain):渲染管线和你创建的窗口间的桥梁,将窗口句柄和交换链绑定,渲染管线输出到交换链的后缓冲,最后呈现到窗口上。

      通过调用函数 D3D11CreateDeviceAndSwapChain() 就可以一次性创建这三个对象。下图为渲染管线过程:

       结语:

      这篇文章简要说明一下渲染管线,接下来将介绍框架源码中的内容。

      源码下载:MMDViewer 03.zip

  • 相关阅读:
    Double 四舍五入保留小数
    QQ在线人数统计图数据解析
    Errors running builder 'Android Resource Manager' on project 'DeskClock'.
    批处理脚本学习笔记——程序猿版
    BZOJ 1002: [FJOI2007]轮状病毒
    《逆袭大学——传给IT学子的正能量》文件夹
    webservice 开发规范
    webservice面试题
    jdbc连接oracle数据库问题
    jdbc连接 orale 和 mysql 所需要的jar包
  • 原文地址:https://www.cnblogs.com/ForEmail5/p/8150425.html
Copyright © 2020-2023  润新知