home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 8 Lighting / LitColumns / LitColumnsApp.cpp < prev   
Encoding:
C/C++ Source or Header  |  2016-03-02  |  33.2 KB  |  900 lines

  1. //***************************************************************************************
  2. // LitColumnsApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10.  
  11. using Microsoft::WRL::ComPtr;
  12. using namespace DirectX;
  13. using namespace DirectX::PackedVector;
  14.  
  15. #pragma comment(lib, "d3dcompiler.lib")
  16. #pragma comment(lib, "D3D12.lib")
  17.  
  18. const int gNumFrameResources = 3;
  19.  
  20. // Lightweight structure stores parameters to draw a shape.  This will
  21. // vary from app-to-app.
  22. struct RenderItem
  23. {
  24.     RenderItem() = default;
  25.  
  26.     // World matrix of the shape that describes the object's local space
  27.     // relative to the world space, which defines the position, orientation,
  28.     // and scale of the object in the world.
  29.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  30.  
  31.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  32.  
  33.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  34.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  35.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  36.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  37.     int NumFramesDirty = gNumFrameResources;
  38.  
  39.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  40.     UINT ObjCBIndex = -1;
  41.  
  42.     Material* Mat = nullptr;
  43.     MeshGeometry* Geo = nullptr;
  44.  
  45.     // Primitive topology.
  46.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  47.  
  48.     // DrawIndexedInstanced parameters.
  49.     UINT IndexCount = 0;
  50.     UINT StartIndexLocation = 0;
  51.     int BaseVertexLocation = 0;
  52. };
  53.  
  54. class LitColumnsApp : public D3DApp
  55. {
  56. public:
  57.     LitColumnsApp(HINSTANCE hInstance);
  58.     LitColumnsApp(const LitColumnsApp& rhs) = delete;
  59.     LitColumnsApp& operator=(const LitColumnsApp& rhs) = delete;
  60.     ~LitColumnsApp();
  61.  
  62.     virtual bool Initialize()override;
  63.  
  64. private:
  65.     virtual void OnResize()override;
  66.     virtual void Update(const GameTimer& gt)override;
  67.     virtual void Draw(const GameTimer& gt)override;
  68.  
  69.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  70.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  71.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  72.  
  73.     void OnKeyboardInput(const GameTimer& gt);
  74.     void UpdateCamera(const GameTimer& gt);
  75.     void AnimateMaterials(const GameTimer& gt);
  76.     void UpdateObjectCBs(const GameTimer& gt);
  77.     void UpdateMaterialCBs(const GameTimer& gt);
  78.     void UpdateMainPassCB(const GameTimer& gt);
  79.  
  80.     void BuildRootSignature();
  81.     void BuildShadersAndInputLayout();
  82.     void BuildShapeGeometry();
  83.     void BuildSkullGeometry();
  84.     void BuildPSOs();
  85.     void BuildFrameResources();
  86.     void BuildMaterials();
  87.     void BuildRenderItems();
  88.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  89.  
  90. private:
  91.  
  92.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  93.     FrameResource* mCurrFrameResource = nullptr;
  94.     int mCurrFrameResourceIndex = 0;
  95.  
  96.     UINT mCbvSrvDescriptorSize = 0;
  97.  
  98.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  99.  
  100.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  101.  
  102.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  103.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  104.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  105.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  106.  
  107.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  108.  
  109.     ComPtr<ID3D12PipelineState> mOpaquePSO = nullptr;
  110.  
  111.     // List of all the render items.
  112.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  113.  
  114.     // Render items divided by PSO.
  115.     std::vector<RenderItem*> mOpaqueRitems;
  116.  
  117.     PassConstants mMainPassCB;
  118.  
  119.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  120.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  121.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  122.  
  123.     float mTheta = 1.5f*XM_PI;
  124.     float mPhi = 0.2f*XM_PI;
  125.     float mRadius = 15.0f;
  126.  
  127.     POINT mLastMousePos;
  128. };
  129.  
  130. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  131.     PSTR cmdLine, int showCmd)
  132. {
  133.     // Enable run-time memory check for debug builds.
  134. #if defined(DEBUG) | defined(_DEBUG)
  135.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  136. #endif
  137.  
  138.     try
  139.     {
  140.         LitColumnsApp theApp(hInstance);
  141.         if(!theApp.Initialize())
  142.             return 0;
  143.  
  144.         return theApp.Run();
  145.     }
  146.     catch(DxException& e)
  147.     {
  148.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  149.         return 0;
  150.     }
  151. }
  152.  
  153. LitColumnsApp::LitColumnsApp(HINSTANCE hInstance)
  154.     : D3DApp(hInstance)
  155. {
  156. }
  157.  
  158. LitColumnsApp::~LitColumnsApp()
  159. {
  160.     if(md3dDevice != nullptr)
  161.         FlushCommandQueue();
  162. }
  163.  
  164. bool LitColumnsApp::Initialize()
  165. {
  166.     if(!D3DApp::Initialize())
  167.         return false;
  168.  
  169.     // Reset the command list to prep for initialization commands.
  170.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  171.  
  172.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  173.     // so we have to query this information.
  174.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  175.  
  176.     BuildRootSignature();
  177.     BuildShadersAndInputLayout();
  178.     BuildShapeGeometry();
  179.     BuildSkullGeometry();
  180.     BuildMaterials();
  181.     BuildRenderItems();
  182.     BuildFrameResources();
  183.     BuildPSOs();
  184.  
  185.     // Execute the initialization commands.
  186.     ThrowIfFailed(mCommandList->Close());
  187.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  188.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  189.  
  190.     // Wait until initialization is complete.
  191.     FlushCommandQueue();
  192.  
  193.     return true;
  194. }
  195.  
  196. void LitColumnsApp::OnResize()
  197. {
  198.     D3DApp::OnResize();
  199.  
  200.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  201.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  202.     XMStoreFloat4x4(&mProj, P);
  203. }
  204.  
  205. void LitColumnsApp::Update(const GameTimer& gt)
  206. {
  207.     OnKeyboardInput(gt);
  208.     UpdateCamera(gt);
  209.  
  210.     // Cycle through the circular frame resource array.
  211.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  212.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  213.  
  214.     // Has the GPU finished processing the commands of the current frame resource?
  215.     // If not, wait until the GPU has completed commands up to this fence point.
  216.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  217.     {
  218.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  219.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  220.         WaitForSingleObject(eventHandle, INFINITE);
  221.         CloseHandle(eventHandle);
  222.     }
  223.  
  224.     AnimateMaterials(gt);
  225.     UpdateObjectCBs(gt);
  226.     UpdateMaterialCBs(gt);
  227.     UpdateMainPassCB(gt);
  228. }
  229.  
  230. void LitColumnsApp::Draw(const GameTimer& gt)
  231. {
  232.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  233.  
  234.     // Reuse the memory associated with command recording.
  235.     // We can only reset when the associated command lists have finished execution on the GPU.
  236.     ThrowIfFailed(cmdListAlloc->Reset());
  237.  
  238.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  239.     // Reusing the command list reuses memory.
  240.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mOpaquePSO.Get()));
  241.  
  242.     mCommandList->RSSetViewports(1, &mScreenViewport);
  243.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  244.  
  245.     // Indicate a state transition on the resource usage.
  246.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  247.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  248.  
  249.     // Clear the back buffer and depth buffer.
  250.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  251.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  252.  
  253.     // Specify the buffers we are going to render to.
  254.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  255.  
  256.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  257.  
  258.     auto passCB = mCurrFrameResource->PassCB->Resource();
  259.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  260.  
  261.     DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
  262.  
  263.     // Indicate a state transition on the resource usage.
  264.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  265.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  266.  
  267.     // Done recording commands.
  268.     ThrowIfFailed(mCommandList->Close());
  269.  
  270.     // Add the command list to the queue for execution.
  271.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  272.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  273.  
  274.     // Swap the back and front buffers
  275.     ThrowIfFailed(mSwapChain->Present(0, 0));
  276.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  277.  
  278.     // Advance the fence value to mark commands up to this fence point.
  279.     mCurrFrameResource->Fence = ++mCurrentFence;
  280.  
  281.     // Add an instruction to the command queue to set a new fence point. 
  282.     // Because we are on the GPU timeline, the new fence point won't be 
  283.     // set until the GPU finishes processing all the commands prior to this Signal().
  284.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  285. }
  286.  
  287. void LitColumnsApp::OnMouseDown(WPARAM btnState, int x, int y)
  288. {
  289.     mLastMousePos.x = x;
  290.     mLastMousePos.y = y;
  291.  
  292.     SetCapture(mhMainWnd);
  293. }
  294.  
  295. void LitColumnsApp::OnMouseUp(WPARAM btnState, int x, int y)
  296. {
  297.     ReleaseCapture();
  298. }
  299.  
  300. void LitColumnsApp::OnMouseMove(WPARAM btnState, int x, int y)
  301. {
  302.     if((btnState & MK_LBUTTON) != 0)
  303.     {
  304.         // Make each pixel correspond to a quarter of a degree.
  305.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  306.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  307.  
  308.         // Update angles based on input to orbit camera around box.
  309.         mTheta += dx;
  310.         mPhi += dy;
  311.  
  312.         // Restrict the angle mPhi.
  313.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  314.     }
  315.     else if((btnState & MK_RBUTTON) != 0)
  316.     {
  317.         // Make each pixel correspond to 0.2 unit in the scene.
  318.         float dx = 0.05f*static_cast<float>(x - mLastMousePos.x);
  319.         float dy = 0.05f*static_cast<float>(y - mLastMousePos.y);
  320.  
  321.         // Update the camera radius based on input.
  322.         mRadius += dx - dy;
  323.  
  324.         // Restrict the radius.
  325.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  326.     }
  327.  
  328.     mLastMousePos.x = x;
  329.     mLastMousePos.y = y;
  330. }
  331.  
  332. void LitColumnsApp::OnKeyboardInput(const GameTimer& gt)
  333. {
  334. }
  335.  
  336. void LitColumnsApp::UpdateCamera(const GameTimer& gt)
  337. {
  338.     // Convert Spherical to Cartesian coordinates.
  339.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  340.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  341.     mEyePos.y = mRadius*cosf(mPhi);
  342.  
  343.     // Build the view matrix.
  344.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  345.     XMVECTOR target = XMVectorZero();
  346.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  347.  
  348.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  349.     XMStoreFloat4x4(&mView, view);
  350. }
  351.  
  352. void LitColumnsApp::AnimateMaterials(const GameTimer& gt)
  353. {
  354.     
  355. }
  356.  
  357. void LitColumnsApp::UpdateObjectCBs(const GameTimer& gt)
  358. {
  359.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  360.     for(auto& e : mAllRitems)
  361.     {
  362.         // Only update the cbuffer data if the constants have changed.  
  363.         // This needs to be tracked per frame resource.
  364.         if(e->NumFramesDirty > 0)
  365.         {
  366.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  367.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  368.  
  369.             ObjectConstants objConstants;
  370.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  371.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  372.  
  373.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  374.  
  375.             // Next FrameResource need to be updated too.
  376.             e->NumFramesDirty--;
  377.         }
  378.     }
  379. }
  380.  
  381. void LitColumnsApp::UpdateMaterialCBs(const GameTimer& gt)
  382. {
  383.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  384.     for(auto& e : mMaterials)
  385.     {
  386.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  387.         // data changes, it needs to be updated for each FrameResource.
  388.         Material* mat = e.second.get();
  389.         if(mat->NumFramesDirty > 0)
  390.         {
  391.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  392.  
  393.             MaterialConstants matConstants;
  394.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  395.             matConstants.FresnelR0 = mat->FresnelR0;
  396.             matConstants.Roughness = mat->Roughness;
  397.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  398.  
  399.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  400.  
  401.             // Next FrameResource need to be updated too.
  402.             mat->NumFramesDirty--;
  403.         }
  404.     }
  405. }
  406.  
  407. void LitColumnsApp::UpdateMainPassCB(const GameTimer& gt)
  408. {
  409.     XMMATRIX view = XMLoadFloat4x4(&mView);
  410.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  411.  
  412.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  413.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  414.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  415.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  416.  
  417.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  418.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  419.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  420.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  421.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  422.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  423.     mMainPassCB.EyePosW = mEyePos;
  424.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  425.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  426.     mMainPassCB.NearZ = 1.0f;
  427.     mMainPassCB.FarZ = 1000.0f;
  428.     mMainPassCB.TotalTime = gt.TotalTime();
  429.     mMainPassCB.DeltaTime = gt.DeltaTime();
  430.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  431.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  432.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  433.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  434.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  435.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  436.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  437.  
  438.     auto currPassCB = mCurrFrameResource->PassCB.get();
  439.     currPassCB->CopyData(0, mMainPassCB);
  440. }
  441.  
  442. void LitColumnsApp::BuildRootSignature()
  443. {
  444.     // Root parameter can be a table, root descriptor or root constants.
  445.     CD3DX12_ROOT_PARAMETER slotRootParameter[3];
  446.  
  447.     // Create root CBV.
  448.     slotRootParameter[0].InitAsConstantBufferView(0);
  449.     slotRootParameter[1].InitAsConstantBufferView(1);
  450.     slotRootParameter[2].InitAsConstantBufferView(2);
  451.  
  452.     // A root signature is an array of root parameters.
  453.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  454.  
  455.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  456.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  457.     ComPtr<ID3DBlob> errorBlob = nullptr;
  458.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  459.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  460.  
  461.     if(errorBlob != nullptr)
  462.     {
  463.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  464.     }
  465.     ThrowIfFailed(hr);
  466.  
  467.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  468.         0,
  469.         serializedRootSig->GetBufferPointer(),
  470.         serializedRootSig->GetBufferSize(),
  471.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  472. }
  473.  
  474. void LitColumnsApp::BuildShadersAndInputLayout()
  475. {
  476.     const D3D_SHADER_MACRO alphaTestDefines[] =
  477.     {
  478.         "ALPHA_TEST", "1",
  479.         NULL, NULL
  480.     };
  481.  
  482.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_1");
  483.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_1");
  484.     
  485.     mInputLayout =
  486.     {
  487.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  488.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  489.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  490.     };
  491. }
  492.  
  493. void LitColumnsApp::BuildShapeGeometry()
  494. {
  495.     GeometryGenerator geoGen;
  496.     GeometryGenerator::MeshData box = geoGen.CreateBox(1.5f, 0.5f, 1.5f, 3);
  497.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(20.0f, 30.0f, 60, 40);
  498.     GeometryGenerator::MeshData sphere = geoGen.CreateSphere(0.5f, 20, 20);
  499.     GeometryGenerator::MeshData cylinder = geoGen.CreateCylinder(0.5f, 0.3f, 3.0f, 20, 20);
  500.  
  501.     //
  502.     // We are concatenating all the geometry into one big vertex/index buffer.  So
  503.     // define the regions in the buffer each submesh covers.
  504.     //
  505.  
  506.     // Cache the vertex offsets to each object in the concatenated vertex buffer.
  507.     UINT boxVertexOffset = 0;
  508.     UINT gridVertexOffset = (UINT)box.Vertices.size();
  509.     UINT sphereVertexOffset = gridVertexOffset + (UINT)grid.Vertices.size();
  510.     UINT cylinderVertexOffset = sphereVertexOffset + (UINT)sphere.Vertices.size();
  511.  
  512.     // Cache the starting index for each object in the concatenated index buffer.
  513.     UINT boxIndexOffset = 0;
  514.     UINT gridIndexOffset = (UINT)box.Indices32.size();
  515.     UINT sphereIndexOffset = gridIndexOffset + (UINT)grid.Indices32.size();
  516.     UINT cylinderIndexOffset = sphereIndexOffset + (UINT)sphere.Indices32.size();
  517.  
  518.     SubmeshGeometry boxSubmesh;
  519.     boxSubmesh.IndexCount = (UINT)box.Indices32.size();
  520.     boxSubmesh.StartIndexLocation = boxIndexOffset;
  521.     boxSubmesh.BaseVertexLocation = boxVertexOffset;
  522.  
  523.     SubmeshGeometry gridSubmesh;
  524.     gridSubmesh.IndexCount = (UINT)grid.Indices32.size();
  525.     gridSubmesh.StartIndexLocation = gridIndexOffset;
  526.     gridSubmesh.BaseVertexLocation = gridVertexOffset;
  527.  
  528.     SubmeshGeometry sphereSubmesh;
  529.     sphereSubmesh.IndexCount = (UINT)sphere.Indices32.size();
  530.     sphereSubmesh.StartIndexLocation = sphereIndexOffset;
  531.     sphereSubmesh.BaseVertexLocation = sphereVertexOffset;
  532.  
  533.     SubmeshGeometry cylinderSubmesh;
  534.     cylinderSubmesh.IndexCount = (UINT)cylinder.Indices32.size();
  535.     cylinderSubmesh.StartIndexLocation = cylinderIndexOffset;
  536.     cylinderSubmesh.BaseVertexLocation = cylinderVertexOffset;
  537.  
  538.     //
  539.     // Extract the vertex elements we are interested in and pack the
  540.     // vertices of all the meshes into one vertex buffer.
  541.     //
  542.  
  543.     auto totalVertexCount =
  544.         box.Vertices.size() +
  545.         grid.Vertices.size() +
  546.         sphere.Vertices.size() +
  547.         cylinder.Vertices.size();
  548.  
  549.     std::vector<Vertex> vertices(totalVertexCount);
  550.  
  551.     UINT k = 0;
  552.     for(size_t i = 0; i < box.Vertices.size(); ++i, ++k)
  553.     {
  554.         vertices[k].Pos = box.Vertices[i].Position;
  555.         vertices[k].Normal = box.Vertices[i].Normal;
  556.     }
  557.  
  558.     for(size_t i = 0; i < grid.Vertices.size(); ++i, ++k)
  559.     {
  560.         vertices[k].Pos = grid.Vertices[i].Position;
  561.         vertices[k].Normal = grid.Vertices[i].Normal;
  562.     }
  563.  
  564.     for(size_t i = 0; i < sphere.Vertices.size(); ++i, ++k)
  565.     {
  566.         vertices[k].Pos = sphere.Vertices[i].Position;
  567.         vertices[k].Normal = sphere.Vertices[i].Normal;
  568.     }
  569.  
  570.     for(size_t i = 0; i < cylinder.Vertices.size(); ++i, ++k)
  571.     {
  572.         vertices[k].Pos = cylinder.Vertices[i].Position;
  573.         vertices[k].Normal = cylinder.Vertices[i].Normal;
  574.     }
  575.  
  576.     std::vector<std::uint16_t> indices;
  577.     indices.insert(indices.end(), std::begin(box.GetIndices16()), std::end(box.GetIndices16()));
  578.     indices.insert(indices.end(), std::begin(grid.GetIndices16()), std::end(grid.GetIndices16()));
  579.     indices.insert(indices.end(), std::begin(sphere.GetIndices16()), std::end(sphere.GetIndices16()));
  580.     indices.insert(indices.end(), std::begin(cylinder.GetIndices16()), std::end(cylinder.GetIndices16()));
  581.  
  582.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  583.     const UINT ibByteSize = (UINT)indices.size()  * sizeof(std::uint16_t);
  584.  
  585.     auto geo = std::make_unique<MeshGeometry>();
  586.     geo->Name = "shapeGeo";
  587.  
  588.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  589.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  590.  
  591.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  592.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  593.  
  594.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  595.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  596.  
  597.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  598.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  599.  
  600.     geo->VertexByteStride = sizeof(Vertex);
  601.     geo->VertexBufferByteSize = vbByteSize;
  602.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  603.     geo->IndexBufferByteSize = ibByteSize;
  604.  
  605.     geo->DrawArgs["box"] = boxSubmesh;
  606.     geo->DrawArgs["grid"] = gridSubmesh;
  607.     geo->DrawArgs["sphere"] = sphereSubmesh;
  608.     geo->DrawArgs["cylinder"] = cylinderSubmesh;
  609.  
  610.     mGeometries[geo->Name] = std::move(geo);
  611. }
  612.  
  613. void LitColumnsApp::BuildSkullGeometry()
  614. {
  615.     std::ifstream fin("Models/skull.txt");
  616.  
  617.     if(!fin)
  618.     {
  619.         MessageBox(0, L"Models/skull.txt not found.", 0, 0);
  620.         return;
  621.     }
  622.  
  623.     UINT vcount = 0;
  624.     UINT tcount = 0;
  625.     std::string ignore;
  626.  
  627.     fin >> ignore >> vcount;
  628.     fin >> ignore >> tcount;
  629.     fin >> ignore >> ignore >> ignore >> ignore;
  630.  
  631.     std::vector<Vertex> vertices(vcount);
  632.     for(UINT i = 0; i < vcount; ++i)
  633.     {
  634.         fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
  635.         fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
  636.     }
  637.  
  638.     fin >> ignore;
  639.     fin >> ignore;
  640.     fin >> ignore;
  641.  
  642.     std::vector<std::int32_t> indices(3 * tcount);
  643.     for(UINT i = 0; i < tcount; ++i)
  644.     {
  645.         fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
  646.     }
  647.  
  648.     fin.close();
  649.  
  650.     //
  651.     // Pack the indices of all the meshes into one index buffer.
  652.     //
  653.  
  654.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  655.  
  656.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
  657.  
  658.     auto geo = std::make_unique<MeshGeometry>();
  659.     geo->Name = "skullGeo";
  660.  
  661.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  662.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  663.  
  664.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  665.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  666.  
  667.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  668.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  669.  
  670.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  671.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  672.  
  673.     geo->VertexByteStride = sizeof(Vertex);
  674.     geo->VertexBufferByteSize = vbByteSize;
  675.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  676.     geo->IndexBufferByteSize = ibByteSize;
  677.  
  678.     SubmeshGeometry submesh;
  679.     submesh.IndexCount = (UINT)indices.size();
  680.     submesh.StartIndexLocation = 0;
  681.     submesh.BaseVertexLocation = 0;
  682.  
  683.     geo->DrawArgs["skull"] = submesh;
  684.  
  685.     mGeometries[geo->Name] = std::move(geo);
  686. }
  687.  
  688. void LitColumnsApp::BuildPSOs()
  689. {
  690.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  691.  
  692.     //
  693.     // PSO for opaque objects.
  694.     //
  695.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  696.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  697.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  698.     opaquePsoDesc.VS = 
  699.     { 
  700.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  701.         mShaders["standardVS"]->GetBufferSize()
  702.     };
  703.     opaquePsoDesc.PS = 
  704.     { 
  705.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  706.         mShaders["opaquePS"]->GetBufferSize()
  707.     };
  708.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  709.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  710.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  711.     opaquePsoDesc.SampleMask = UINT_MAX;
  712.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  713.     opaquePsoDesc.NumRenderTargets = 1;
  714.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  715.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  716.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  717.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  718.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mOpaquePSO)));
  719. }
  720.  
  721. void LitColumnsApp::BuildFrameResources()
  722. {
  723.     for(int i = 0; i < gNumFrameResources; ++i)
  724.     {
  725.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  726.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  727.     }
  728. }
  729.  
  730. void LitColumnsApp::BuildMaterials()
  731. {
  732.     auto bricks0 = std::make_unique<Material>();
  733.     bricks0->Name = "bricks0";
  734.     bricks0->MatCBIndex = 0;
  735.     bricks0->DiffuseSrvHeapIndex = 0;
  736.     bricks0->DiffuseAlbedo = XMFLOAT4(Colors::ForestGreen);
  737.     bricks0->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  738.     bricks0->Roughness = 0.1f;
  739.  
  740.     auto stone0 = std::make_unique<Material>();
  741.     stone0->Name = "stone0";
  742.     stone0->MatCBIndex = 1;
  743.     stone0->DiffuseSrvHeapIndex = 1;
  744.     stone0->DiffuseAlbedo = XMFLOAT4(Colors::LightSteelBlue);
  745.     stone0->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  746.     stone0->Roughness = 0.3f;
  747.  
  748.     auto tile0 = std::make_unique<Material>();
  749.     tile0->Name = "tile0";
  750.     tile0->MatCBIndex = 2;
  751.     tile0->DiffuseSrvHeapIndex = 2;
  752.     tile0->DiffuseAlbedo = XMFLOAT4(Colors::LightGray);
  753.     tile0->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  754.     tile0->Roughness = 0.2f;
  755.  
  756.     auto skullMat = std::make_unique<Material>();
  757.     skullMat->Name = "skullMat";
  758.     skullMat->MatCBIndex = 3;
  759.     skullMat->DiffuseSrvHeapIndex = 3;
  760.     skullMat->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  761.     skullMat->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05);
  762.     skullMat->Roughness = 0.3f;
  763.     
  764.     mMaterials["bricks0"] = std::move(bricks0);
  765.     mMaterials["stone0"] = std::move(stone0);
  766.     mMaterials["tile0"] = std::move(tile0);
  767.     mMaterials["skullMat"] = std::move(skullMat);
  768. }
  769.  
  770. void LitColumnsApp::BuildRenderItems()
  771. {
  772.     auto boxRitem = std::make_unique<RenderItem>();
  773.     XMStoreFloat4x4(&boxRitem->World, XMMatrixScaling(2.0f, 2.0f, 2.0f)*XMMatrixTranslation(0.0f, 0.5f, 0.0f));
  774.     XMStoreFloat4x4(&boxRitem->TexTransform, XMMatrixScaling(1.0f, 1.0f, 1.0f));
  775.     boxRitem->ObjCBIndex = 0;
  776.     boxRitem->Mat = mMaterials["stone0"].get();
  777.     boxRitem->Geo = mGeometries["shapeGeo"].get();
  778.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  779.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  780.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  781.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  782.     mAllRitems.push_back(std::move(boxRitem));
  783.  
  784.     auto gridRitem = std::make_unique<RenderItem>();
  785.     gridRitem->World = MathHelper::Identity4x4();
  786.     XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(8.0f, 8.0f, 1.0f));
  787.     gridRitem->ObjCBIndex = 1;
  788.     gridRitem->Mat = mMaterials["tile0"].get();
  789.     gridRitem->Geo = mGeometries["shapeGeo"].get();
  790.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  791.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  792.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  793.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  794.     mAllRitems.push_back(std::move(gridRitem));
  795.  
  796.     auto skullRitem = std::make_unique<RenderItem>();
  797.     XMStoreFloat4x4(&skullRitem->World, XMMatrixScaling(0.5f, 0.5f, 0.5f)*XMMatrixTranslation(0.0f, 1.0f, 0.0f));
  798.     skullRitem->TexTransform = MathHelper::Identity4x4();
  799.     skullRitem->ObjCBIndex = 2;
  800.     skullRitem->Mat = mMaterials["skullMat"].get();
  801.     skullRitem->Geo = mGeometries["skullGeo"].get();
  802.     skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  803.     skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
  804.     skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
  805.     skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;
  806.     mAllRitems.push_back(std::move(skullRitem));
  807.  
  808.     XMMATRIX brickTexTransform = XMMatrixScaling(1.0f, 1.0f, 1.0f);
  809.     UINT objCBIndex = 3;
  810.     for(int i = 0; i < 5; ++i)
  811.     {
  812.         auto leftCylRitem = std::make_unique<RenderItem>();
  813.         auto rightCylRitem = std::make_unique<RenderItem>();
  814.         auto leftSphereRitem = std::make_unique<RenderItem>();
  815.         auto rightSphereRitem = std::make_unique<RenderItem>();
  816.  
  817.         XMMATRIX leftCylWorld = XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f);
  818.         XMMATRIX rightCylWorld = XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f);
  819.  
  820.         XMMATRIX leftSphereWorld = XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f);
  821.         XMMATRIX rightSphereWorld = XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f);
  822.  
  823.         XMStoreFloat4x4(&leftCylRitem->World, rightCylWorld);
  824.         XMStoreFloat4x4(&leftCylRitem->TexTransform, brickTexTransform);
  825.         leftCylRitem->ObjCBIndex = objCBIndex++;
  826.         leftCylRitem->Mat = mMaterials["bricks0"].get();
  827.         leftCylRitem->Geo = mGeometries["shapeGeo"].get();
  828.         leftCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  829.         leftCylRitem->IndexCount = leftCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  830.         leftCylRitem->StartIndexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  831.         leftCylRitem->BaseVertexLocation = leftCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  832.  
  833.         XMStoreFloat4x4(&rightCylRitem->World, leftCylWorld);
  834.         XMStoreFloat4x4(&rightCylRitem->TexTransform, brickTexTransform);
  835.         rightCylRitem->ObjCBIndex = objCBIndex++;
  836.         rightCylRitem->Mat = mMaterials["bricks0"].get();
  837.         rightCylRitem->Geo = mGeometries["shapeGeo"].get();
  838.         rightCylRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  839.         rightCylRitem->IndexCount = rightCylRitem->Geo->DrawArgs["cylinder"].IndexCount;
  840.         rightCylRitem->StartIndexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].StartIndexLocation;
  841.         rightCylRitem->BaseVertexLocation = rightCylRitem->Geo->DrawArgs["cylinder"].BaseVertexLocation;
  842.  
  843.         XMStoreFloat4x4(&leftSphereRitem->World, leftSphereWorld);
  844.         leftSphereRitem->TexTransform = MathHelper::Identity4x4();
  845.         leftSphereRitem->ObjCBIndex = objCBIndex++;
  846.         leftSphereRitem->Mat = mMaterials["stone0"].get();
  847.         leftSphereRitem->Geo = mGeometries["shapeGeo"].get();
  848.         leftSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  849.         leftSphereRitem->IndexCount = leftSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  850.         leftSphereRitem->StartIndexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  851.         leftSphereRitem->BaseVertexLocation = leftSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  852.  
  853.         XMStoreFloat4x4(&rightSphereRitem->World, rightSphereWorld);
  854.         rightSphereRitem->TexTransform = MathHelper::Identity4x4();
  855.         rightSphereRitem->ObjCBIndex = objCBIndex++;
  856.         rightSphereRitem->Mat = mMaterials["stone0"].get();
  857.         rightSphereRitem->Geo = mGeometries["shapeGeo"].get();
  858.         rightSphereRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  859.         rightSphereRitem->IndexCount = rightSphereRitem->Geo->DrawArgs["sphere"].IndexCount;
  860.         rightSphereRitem->StartIndexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].StartIndexLocation;
  861.         rightSphereRitem->BaseVertexLocation = rightSphereRitem->Geo->DrawArgs["sphere"].BaseVertexLocation;
  862.  
  863.         mAllRitems.push_back(std::move(leftCylRitem));
  864.         mAllRitems.push_back(std::move(rightCylRitem));
  865.         mAllRitems.push_back(std::move(leftSphereRitem));
  866.         mAllRitems.push_back(std::move(rightSphereRitem));
  867.     }
  868.  
  869.     // All the render items are opaque.
  870.     for(auto& e : mAllRitems)
  871.         mOpaqueRitems.push_back(e.get());
  872. }
  873.  
  874. void LitColumnsApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  875. {
  876.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  877.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  878.  
  879.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  880.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  881.  
  882.     // For each render item...
  883.     for(size_t i = 0; i < ritems.size(); ++i)
  884.     {
  885.         auto ri = ritems[i];
  886.  
  887.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  888.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  889.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  890.  
  891.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  892.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  893.  
  894.         cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
  895.         cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);
  896.  
  897.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  898.     }
  899. }
  900.