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 11 Stenciling / StencilDemo / StencilApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  46.4 KB  |  1,261 lines

  1. //***************************************************************************************
  2. // StencilApp.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. enum class RenderLayer : int
  55. {
  56.     Opaque = 0,
  57.     Mirrors ,
  58.     Reflected,
  59.     Transparent,
  60.     Shadow,
  61.     Count
  62. };
  63.  
  64. class StencilApp : public D3DApp
  65. {
  66. public:
  67.     StencilApp(HINSTANCE hInstance);
  68.     StencilApp(const StencilApp& rhs) = delete;
  69.     StencilApp& operator=(const StencilApp& rhs) = delete;
  70.     ~StencilApp();
  71.  
  72.     virtual bool Initialize()override;
  73.  
  74. private:
  75.     virtual void OnResize()override;
  76.     virtual void Update(const GameTimer& gt)override;
  77.     virtual void Draw(const GameTimer& gt)override;
  78.  
  79.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  80.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  81.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  82.  
  83.     void OnKeyboardInput(const GameTimer& gt);
  84.     void UpdateCamera(const GameTimer& gt);
  85.     void AnimateMaterials(const GameTimer& gt);
  86.     void UpdateObjectCBs(const GameTimer& gt);
  87.     void UpdateMaterialCBs(const GameTimer& gt);
  88.     void UpdateMainPassCB(const GameTimer& gt);
  89.     void UpdateReflectedPassCB(const GameTimer& gt);
  90.  
  91.     void LoadTextures();
  92.     void BuildRootSignature();
  93.     void BuildDescriptorHeaps();
  94.     void BuildShadersAndInputLayout();
  95.     void BuildRoomGeometry();
  96.     void BuildSkullGeometry();
  97.     void BuildPSOs();
  98.     void BuildFrameResources();
  99.     void BuildMaterials();
  100.     void BuildRenderItems();
  101.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  102.  
  103.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  104.  
  105. private:
  106.  
  107.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  108.     FrameResource* mCurrFrameResource = nullptr;
  109.     int mCurrFrameResourceIndex = 0;
  110.  
  111.     UINT mCbvSrvDescriptorSize = 0;
  112.  
  113.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  114.  
  115.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  116.  
  117.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  118.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  119.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  120.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  121.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  122.  
  123.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  124.  
  125.     // Cache render items of interest.
  126.     RenderItem* mSkullRitem = nullptr;
  127.     RenderItem* mReflectedSkullRitem = nullptr;
  128.     RenderItem* mShadowedSkullRitem = nullptr;
  129.  
  130.     // List of all the render items.
  131.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  132.  
  133.     // Render items divided by PSO.
  134.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  135.  
  136.     PassConstants mMainPassCB;
  137.     PassConstants mReflectedPassCB;
  138.  
  139.     XMFLOAT3 mSkullTranslation = { 0.0f, 1.0f, -5.0f };
  140.  
  141.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  142.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  143.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  144.  
  145.     float mTheta = 1.24f*XM_PI;
  146.     float mPhi = 0.42f*XM_PI;
  147.     float mRadius = 12.0f;
  148.  
  149.     POINT mLastMousePos;
  150. };
  151.  
  152. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  153.     PSTR cmdLine, int showCmd)
  154. {
  155.     // Enable run-time memory check for debug builds.
  156. #if defined(DEBUG) | defined(_DEBUG)
  157.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  158. #endif
  159.  
  160.     try
  161.     {
  162.         StencilApp theApp(hInstance);
  163.         if(!theApp.Initialize())
  164.             return 0;
  165.  
  166.         return theApp.Run();
  167.     }
  168.     catch(DxException& e)
  169.     {
  170.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  171.         return 0;
  172.     }
  173. }
  174.  
  175. StencilApp::StencilApp(HINSTANCE hInstance)
  176.     : D3DApp(hInstance)
  177. {
  178. }
  179.  
  180. StencilApp::~StencilApp()
  181. {
  182.     if(md3dDevice != nullptr)
  183.         FlushCommandQueue();
  184. }
  185.  
  186. bool StencilApp::Initialize()
  187. {
  188.     if(!D3DApp::Initialize())
  189.         return false;
  190.  
  191.     // Reset the command list to prep for initialization commands.
  192.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  193.  
  194.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  195.     // so we have to query this information.
  196.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  197.  
  198.     LoadTextures();
  199.     BuildRootSignature();
  200.     BuildDescriptorHeaps();
  201.     BuildShadersAndInputLayout();
  202.     BuildRoomGeometry();
  203.     BuildSkullGeometry();
  204.     BuildMaterials();
  205.     BuildRenderItems();
  206.     BuildFrameResources();
  207.     BuildPSOs();
  208.  
  209.     // Execute the initialization commands.
  210.     ThrowIfFailed(mCommandList->Close());
  211.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  212.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  213.  
  214.     // Wait until initialization is complete.
  215.     FlushCommandQueue();
  216.  
  217.     return true;
  218. }
  219.  
  220. void StencilApp::OnResize()
  221. {
  222.     D3DApp::OnResize();
  223.  
  224.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  225.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  226.     XMStoreFloat4x4(&mProj, P);
  227. }
  228.  
  229. void StencilApp::Update(const GameTimer& gt)
  230. {
  231.     OnKeyboardInput(gt);
  232.     UpdateCamera(gt);
  233.  
  234.     // Cycle through the circular frame resource array.
  235.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  236.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  237.  
  238.     // Has the GPU finished processing the commands of the current frame resource?
  239.     // If not, wait until the GPU has completed commands up to this fence point.
  240.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  241.     {
  242.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  243.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  244.         WaitForSingleObject(eventHandle, INFINITE);
  245.         CloseHandle(eventHandle);
  246.     }
  247.  
  248.     AnimateMaterials(gt);
  249.     UpdateObjectCBs(gt);
  250.     UpdateMaterialCBs(gt);
  251.     UpdateMainPassCB(gt);
  252.     UpdateReflectedPassCB(gt);
  253. }
  254.  
  255. void StencilApp::Draw(const GameTimer& gt)
  256. {
  257.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  258.  
  259.     // Reuse the memory associated with command recording.
  260.     // We can only reset when the associated command lists have finished execution on the GPU.
  261.     ThrowIfFailed(cmdListAlloc->Reset());
  262.  
  263.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  264.     // Reusing the command list reuses memory.
  265.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  266.  
  267.     mCommandList->RSSetViewports(1, &mScreenViewport);
  268.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  269.  
  270.     // Indicate a state transition on the resource usage.
  271.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  272.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  273.  
  274.     // Clear the back buffer and depth buffer.
  275.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), (float*)&mMainPassCB.FogColor, 0, nullptr);
  276.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  277.  
  278.     // Specify the buffers we are going to render to.
  279.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  280.  
  281.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  282.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  283.  
  284.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  285.  
  286.     UINT passCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(PassConstants));
  287.  
  288.     // Draw opaque items--floors, walls, skull.
  289.     auto passCB = mCurrFrameResource->PassCB->Resource();
  290.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  291.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  292.     
  293.     // Mark the visible mirror pixels in the stencil buffer with the value 1
  294.     mCommandList->OMSetStencilRef(1);
  295.     mCommandList->SetPipelineState(mPSOs["markStencilMirrors"].Get());
  296.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Mirrors]);
  297.  
  298.     // Draw the reflection into the mirror only (only for pixels where the stencil buffer is 1).
  299.     // Note that we must supply a different per-pass constant buffer--one with the lights reflected.
  300.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress() + 1 * passCBByteSize);
  301.     mCommandList->SetPipelineState(mPSOs["drawStencilReflections"].Get());
  302.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Reflected]);
  303.  
  304.     // Restore main pass constants and stencil ref.
  305.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  306.     mCommandList->OMSetStencilRef(0);
  307.  
  308.     // Draw mirror with transparency so reflection blends through.
  309.     mCommandList->SetPipelineState(mPSOs["transparent"].Get());
  310.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);
  311.  
  312.     // Draw shadows
  313.     mCommandList->SetPipelineState(mPSOs["shadow"].Get());
  314.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Shadow]);
  315.     
  316.     // Indicate a state transition on the resource usage.
  317.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  318.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  319.  
  320.     // Done recording commands.
  321.     ThrowIfFailed(mCommandList->Close());
  322.  
  323.     // Add the command list to the queue for execution.
  324.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  325.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  326.  
  327.     // Swap the back and front buffers
  328.     ThrowIfFailed(mSwapChain->Present(0, 0));
  329.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  330.  
  331.     // Advance the fence value to mark commands up to this fence point.
  332.     mCurrFrameResource->Fence = ++mCurrentFence;
  333.  
  334.     // Notify the fence when the GPU completes commands up to this fence point.
  335.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  336. }
  337.  
  338. void StencilApp::OnMouseDown(WPARAM btnState, int x, int y)
  339. {
  340.     mLastMousePos.x = x;
  341.     mLastMousePos.y = y;
  342.  
  343.     SetCapture(mhMainWnd);
  344. }
  345.  
  346. void StencilApp::OnMouseUp(WPARAM btnState, int x, int y)
  347. {
  348.     ReleaseCapture();
  349. }
  350.  
  351. void StencilApp::OnMouseMove(WPARAM btnState, int x, int y)
  352. {
  353.     if((btnState & MK_LBUTTON) != 0)
  354.     {
  355.         // Make each pixel correspond to a quarter of a degree.
  356.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  357.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  358.  
  359.         // Update angles based on input to orbit camera around box.
  360.         mTheta += dx;
  361.         mPhi += dy;
  362.  
  363.         // Restrict the angle mPhi.
  364.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  365.     }
  366.     else if((btnState & MK_RBUTTON) != 0)
  367.     {
  368.         // Make each pixel correspond to 0.2 unit in the scene.
  369.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  370.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  371.  
  372.         // Update the camera radius based on input.
  373.         mRadius += dx - dy;
  374.  
  375.         // Restrict the radius.
  376.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  377.     }
  378.  
  379.     mLastMousePos.x = x;
  380.     mLastMousePos.y = y;
  381. }
  382.  
  383. void StencilApp::OnKeyboardInput(const GameTimer& gt)
  384. {
  385.     //
  386.     // Allow user to move skull.
  387.     //
  388.  
  389.     const float dt = gt.DeltaTime();
  390.  
  391.     if(GetAsyncKeyState('A') & 0x8000)
  392.         mSkullTranslation.x -= 1.0f*dt;
  393.  
  394.     if(GetAsyncKeyState('D') & 0x8000)
  395.         mSkullTranslation.x += 1.0f*dt;
  396.  
  397.     if(GetAsyncKeyState('W') & 0x8000)
  398.         mSkullTranslation.y += 1.0f*dt;
  399.  
  400.     if(GetAsyncKeyState('S') & 0x8000)
  401.         mSkullTranslation.y -= 1.0f*dt;
  402.  
  403.     // Don't let user move below ground plane.
  404.     mSkullTranslation.y = MathHelper::Max(mSkullTranslation.y, 0.0f);
  405.  
  406.     // Update the new world matrix.
  407.     XMMATRIX skullRotate = XMMatrixRotationY(0.5f*MathHelper::Pi);
  408.     XMMATRIX skullScale = XMMatrixScaling(0.45f, 0.45f, 0.45f);
  409.     XMMATRIX skullOffset = XMMatrixTranslation(mSkullTranslation.x, mSkullTranslation.y, mSkullTranslation.z);
  410.     XMMATRIX skullWorld = skullRotate*skullScale*skullOffset;
  411.     XMStoreFloat4x4(&mSkullRitem->World, skullWorld);
  412.  
  413.     // Update reflection world matrix.
  414.     XMVECTOR mirrorPlane = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
  415.     XMMATRIX R = XMMatrixReflect(mirrorPlane);
  416.     XMStoreFloat4x4(&mReflectedSkullRitem->World, skullWorld * R);
  417.  
  418.     // Update shadow world matrix.
  419.     XMVECTOR shadowPlane = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); // xz plane
  420.     XMVECTOR toMainLight = -XMLoadFloat3(&mMainPassCB.Lights[0].Direction);
  421.     XMMATRIX S = XMMatrixShadow(shadowPlane, toMainLight);
  422.     XMMATRIX shadowOffsetY = XMMatrixTranslation(0.0f, 0.001f, 0.0f);
  423.     XMStoreFloat4x4(&mShadowedSkullRitem->World, skullWorld * S * shadowOffsetY);
  424.  
  425.     mSkullRitem->NumFramesDirty = gNumFrameResources;
  426.     mReflectedSkullRitem->NumFramesDirty = gNumFrameResources;
  427.     mShadowedSkullRitem->NumFramesDirty = gNumFrameResources;
  428. }
  429.  
  430. void StencilApp::UpdateCamera(const GameTimer& gt)
  431. {
  432.     // Convert Spherical to Cartesian coordinates.
  433.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  434.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  435.     mEyePos.y = mRadius*cosf(mPhi);
  436.  
  437.     // Build the view matrix.
  438.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  439.     XMVECTOR target = XMVectorZero();
  440.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  441.  
  442.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  443.     XMStoreFloat4x4(&mView, view);
  444. }
  445.  
  446. void StencilApp::AnimateMaterials(const GameTimer& gt)
  447. {
  448.  
  449. }
  450.  
  451. void StencilApp::UpdateObjectCBs(const GameTimer& gt)
  452. {
  453.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  454.     for(auto& e : mAllRitems)
  455.     {
  456.         // Only update the cbuffer data if the constants have changed.  
  457.         // This needs to be tracked per frame resource.
  458.         if(e->NumFramesDirty > 0)
  459.         {
  460.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  461.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  462.  
  463.             ObjectConstants objConstants;
  464.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  465.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  466.  
  467.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  468.  
  469.             // Next FrameResource need to be updated too.
  470.             e->NumFramesDirty--;
  471.         }
  472.     }
  473. }
  474.  
  475. void StencilApp::UpdateMaterialCBs(const GameTimer& gt)
  476. {
  477.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  478.     for(auto& e : mMaterials)
  479.     {
  480.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  481.         // data changes, it needs to be updated for each FrameResource.
  482.         Material* mat = e.second.get();
  483.         if(mat->NumFramesDirty > 0)
  484.         {
  485.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  486.  
  487.             MaterialConstants matConstants;
  488.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  489.             matConstants.FresnelR0 = mat->FresnelR0;
  490.             matConstants.Roughness = mat->Roughness;
  491.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  492.  
  493.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  494.  
  495.             // Next FrameResource need to be updated too.
  496.             mat->NumFramesDirty--;
  497.         }
  498.     }
  499. }
  500.  
  501. void StencilApp::UpdateMainPassCB(const GameTimer& gt)
  502. {
  503.     XMMATRIX view = XMLoadFloat4x4(&mView);
  504.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  505.  
  506.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  507.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  508.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  509.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  510.  
  511.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  512.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  513.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  514.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  515.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  516.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  517.     mMainPassCB.EyePosW = mEyePos;
  518.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  519.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  520.     mMainPassCB.NearZ = 1.0f;
  521.     mMainPassCB.FarZ = 1000.0f;
  522.     mMainPassCB.TotalTime = gt.TotalTime();
  523.     mMainPassCB.DeltaTime = gt.DeltaTime();
  524.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  525.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  526.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  527.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  528.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  529.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  530.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  531.  
  532.     // Main pass stored in index 2
  533.     auto currPassCB = mCurrFrameResource->PassCB.get();
  534.     currPassCB->CopyData(0, mMainPassCB);
  535. }
  536.  
  537. void StencilApp::UpdateReflectedPassCB(const GameTimer& gt)
  538. {
  539.     mReflectedPassCB = mMainPassCB;
  540.  
  541.     XMVECTOR mirrorPlane = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
  542.     XMMATRIX R = XMMatrixReflect(mirrorPlane);
  543.  
  544.     // Reflect the lighting.
  545.     for(int i = 0; i < 3; ++i)
  546.     {
  547.         XMVECTOR lightDir = XMLoadFloat3(&mMainPassCB.Lights[i].Direction);
  548.         XMVECTOR reflectedLightDir = XMVector3TransformNormal(lightDir, R);
  549.         XMStoreFloat3(&mReflectedPassCB.Lights[i].Direction, reflectedLightDir);
  550.     }
  551.  
  552.     // Reflected pass stored in index 1
  553.     auto currPassCB = mCurrFrameResource->PassCB.get();
  554.     currPassCB->CopyData(1, mReflectedPassCB);
  555. }
  556.  
  557. void StencilApp::LoadTextures()
  558. {
  559.     auto bricksTex = std::make_unique<Texture>();
  560.     bricksTex->Name = "bricksTex";
  561.     bricksTex->Filename = L"../../Textures/bricks3.dds";
  562.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  563.         mCommandList.Get(), bricksTex->Filename.c_str(),
  564.         bricksTex->Resource, bricksTex->UploadHeap));
  565.  
  566.     auto checkboardTex = std::make_unique<Texture>();
  567.     checkboardTex->Name = "checkboardTex";
  568.     checkboardTex->Filename = L"../../Textures/checkboard.dds";
  569.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  570.         mCommandList.Get(), checkboardTex->Filename.c_str(),
  571.         checkboardTex->Resource, checkboardTex->UploadHeap));
  572.  
  573.     auto iceTex = std::make_unique<Texture>();
  574.     iceTex->Name = "iceTex";
  575.     iceTex->Filename = L"../../Textures/ice.dds";
  576.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  577.         mCommandList.Get(), iceTex->Filename.c_str(),
  578.         iceTex->Resource, iceTex->UploadHeap));
  579.  
  580.     auto white1x1Tex = std::make_unique<Texture>();
  581.     white1x1Tex->Name = "white1x1Tex";
  582.     white1x1Tex->Filename = L"../../Textures/white1x1.dds";
  583.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  584.         mCommandList.Get(), white1x1Tex->Filename.c_str(),
  585.         white1x1Tex->Resource, white1x1Tex->UploadHeap));
  586.  
  587.     mTextures[bricksTex->Name] = std::move(bricksTex);
  588.     mTextures[checkboardTex->Name] = std::move(checkboardTex);
  589.     mTextures[iceTex->Name] = std::move(iceTex);
  590.     mTextures[white1x1Tex->Name] = std::move(white1x1Tex);
  591. }
  592.  
  593. void StencilApp::BuildRootSignature()
  594. {
  595.     CD3DX12_DESCRIPTOR_RANGE texTable;
  596.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  597.  
  598.     // Root parameter can be a table, root descriptor or root constants.
  599.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  600.  
  601.     // Perfomance TIP: Order from most frequent to least frequent.
  602.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  603.     slotRootParameter[1].InitAsConstantBufferView(0);
  604.     slotRootParameter[2].InitAsConstantBufferView(1);
  605.     slotRootParameter[3].InitAsConstantBufferView(2);
  606.  
  607.     auto staticSamplers = GetStaticSamplers();
  608.  
  609.     // A root signature is an array of root parameters.
  610.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  611.         (UINT)staticSamplers.size(), staticSamplers.data(),
  612.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  613.  
  614.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  615.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  616.     ComPtr<ID3DBlob> errorBlob = nullptr;
  617.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  618.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  619.  
  620.     if(errorBlob != nullptr)
  621.     {
  622.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  623.     }
  624.     ThrowIfFailed(hr);
  625.  
  626.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  627.         0,
  628.         serializedRootSig->GetBufferPointer(),
  629.         serializedRootSig->GetBufferSize(),
  630.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  631. }
  632.  
  633. void StencilApp::BuildDescriptorHeaps()
  634. {
  635.     //
  636.     // Create the SRV heap.
  637.     //
  638.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  639.     srvHeapDesc.NumDescriptors = 4;
  640.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  641.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  642.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  643.  
  644.     //
  645.     // Fill out the heap with actual descriptors.
  646.     //
  647.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  648.  
  649.     auto bricksTex = mTextures["bricksTex"]->Resource;
  650.     auto checkboardTex = mTextures["checkboardTex"]->Resource;
  651.     auto iceTex = mTextures["iceTex"]->Resource;
  652.     auto white1x1Tex = mTextures["white1x1Tex"]->Resource;
  653.  
  654.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  655.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  656.     srvDesc.Format = bricksTex->GetDesc().Format;
  657.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  658.     srvDesc.Texture2D.MostDetailedMip = 0;
  659.     srvDesc.Texture2D.MipLevels = -1;
  660.     md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);
  661.  
  662.     // next descriptor
  663.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  664.  
  665.     srvDesc.Format = checkboardTex->GetDesc().Format;
  666.     md3dDevice->CreateShaderResourceView(checkboardTex.Get(), &srvDesc, hDescriptor);
  667.  
  668.     // next descriptor
  669.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  670.  
  671.     srvDesc.Format = iceTex->GetDesc().Format;
  672.     md3dDevice->CreateShaderResourceView(iceTex.Get(), &srvDesc, hDescriptor);
  673.  
  674.     // next descriptor
  675.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  676.  
  677.     srvDesc.Format = white1x1Tex->GetDesc().Format;
  678.     md3dDevice->CreateShaderResourceView(white1x1Tex.Get(), &srvDesc, hDescriptor);
  679. }
  680.  
  681. void StencilApp::BuildShadersAndInputLayout()
  682. {
  683.     const D3D_SHADER_MACRO defines[] =
  684.     {
  685.         "FOG", "1",
  686.         NULL, NULL
  687.     };
  688.  
  689.     const D3D_SHADER_MACRO alphaTestDefines[] =
  690.     {
  691.         "FOG", "1",
  692.         "ALPHA_TEST", "1",
  693.         NULL, NULL
  694.     };
  695.  
  696.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  697.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", defines, "PS", "ps_5_0");
  698.     mShaders["alphaTestedPS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", alphaTestDefines, "PS", "ps_5_0");
  699.     
  700.     mInputLayout =
  701.     {
  702.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  703.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  704.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  705.     };
  706. }
  707.  
  708. void StencilApp::BuildRoomGeometry()
  709. {
  710.         // Create and specify geometry.  For this sample we draw a floor
  711.     // and a wall with a mirror on it.  We put the floor, wall, and
  712.     // mirror geometry in one vertex buffer.
  713.     //
  714.     //   |--------------|
  715.     //   |              |
  716.     //   |----|----|----|
  717.     //   |Wall|Mirr|Wall|
  718.     //   |    | or |    |
  719.     //   /--------------/
  720.     //  /   Floor      /
  721.     // /--------------/
  722.  
  723.     std::array<Vertex, 20> vertices = 
  724.     {
  725.         // Floor: Observe we tile texture coordinates.
  726.         Vertex(-3.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 4.0f), // 0 
  727.         Vertex(-3.5f, 0.0f,   0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f),
  728.         Vertex(7.5f, 0.0f,   0.0f, 0.0f, 1.0f, 0.0f, 4.0f, 0.0f),
  729.         Vertex(7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 4.0f, 4.0f),
  730.  
  731.         // Wall: Observe we tile texture coordinates, and that we
  732.         // leave a gap in the middle for the mirror.
  733.         Vertex(-3.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 2.0f), // 4
  734.         Vertex(-3.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
  735.         Vertex(-2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.0f),
  736.         Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, 2.0f),
  737.  
  738.         Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 2.0f), // 8 
  739.         Vertex(2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
  740.         Vertex(7.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f),
  741.         Vertex(7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f),
  742.  
  743.         Vertex(-3.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f), // 12
  744.         Vertex(-3.5f, 6.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
  745.         Vertex(7.5f, 6.0f, 0.0f, 0.0f, 0.0f, -1.0f, 6.0f, 0.0f),
  746.         Vertex(7.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 6.0f, 1.0f),
  747.  
  748.         // Mirror
  749.         Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f), // 16
  750.         Vertex(-2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
  751.         Vertex(2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f),
  752.         Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f)
  753.     };
  754.  
  755.     std::array<std::int16_t, 30> indices = 
  756.     {
  757.         // Floor
  758.         0, 1, 2,    
  759.         0, 2, 3,
  760.  
  761.         // Walls
  762.         4, 5, 6,
  763.         4, 6, 7,
  764.  
  765.         8, 9, 10,
  766.         8, 10, 11,
  767.  
  768.         12, 13, 14,
  769.         12, 14, 15,
  770.  
  771.         // Mirror
  772.         16, 17, 18,
  773.         16, 18, 19
  774.     };
  775.  
  776.     SubmeshGeometry floorSubmesh;
  777.     floorSubmesh.IndexCount = 6;
  778.     floorSubmesh.StartIndexLocation = 0;
  779.     floorSubmesh.BaseVertexLocation = 0;
  780.  
  781.     SubmeshGeometry wallSubmesh;
  782.     wallSubmesh.IndexCount = 18;
  783.     wallSubmesh.StartIndexLocation = 6;
  784.     wallSubmesh.BaseVertexLocation = 0;
  785.  
  786.     SubmeshGeometry mirrorSubmesh;
  787.     mirrorSubmesh.IndexCount = 6;
  788.     mirrorSubmesh.StartIndexLocation = 24;
  789.     mirrorSubmesh.BaseVertexLocation = 0;
  790.  
  791.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  792.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  793.  
  794.     auto geo = std::make_unique<MeshGeometry>();
  795.     geo->Name = "roomGeo";
  796.  
  797.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  798.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  799.  
  800.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  801.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  802.  
  803.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  804.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  805.  
  806.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  807.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  808.  
  809.     geo->VertexByteStride = sizeof(Vertex);
  810.     geo->VertexBufferByteSize = vbByteSize;
  811.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  812.     geo->IndexBufferByteSize = ibByteSize;
  813.  
  814.     geo->DrawArgs["floor"] = floorSubmesh;
  815.     geo->DrawArgs["wall"] = wallSubmesh;
  816.     geo->DrawArgs["mirror"] = mirrorSubmesh;
  817.  
  818.     mGeometries[geo->Name] = std::move(geo);
  819. }
  820.  
  821. void StencilApp::BuildSkullGeometry()
  822. {
  823.     std::ifstream fin("Models/skull.txt");
  824.     
  825.     if(!fin)
  826.     {
  827.         MessageBox(0, L"Models/skull.txt not found.", 0, 0);
  828.         return;
  829.     }
  830.  
  831.     UINT vcount = 0;
  832.     UINT tcount = 0;
  833.     std::string ignore;
  834.  
  835.     fin >> ignore >> vcount;
  836.     fin >> ignore >> tcount;
  837.     fin >> ignore >> ignore >> ignore >> ignore;
  838.     
  839.     std::vector<Vertex> vertices(vcount);
  840.     for(UINT i = 0; i < vcount; ++i)
  841.     {
  842.         fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
  843.         fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
  844.  
  845.         // Model does not have texture coordinates, so just zero them out.
  846.         vertices[i].TexC = { 0.0f, 0.0f };
  847.     }
  848.  
  849.     fin >> ignore;
  850.     fin >> ignore;
  851.     fin >> ignore;
  852.  
  853.     std::vector<std::int32_t> indices(3 * tcount);
  854.     for(UINT i = 0; i < tcount; ++i)
  855.     {
  856.         fin >> indices[i*3+0] >> indices[i*3+1] >> indices[i*3+2];
  857.     }
  858.  
  859.     fin.close();
  860.  
  861.     //
  862.     // Pack the indices of all the meshes into one index buffer.
  863.     //
  864.  
  865.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  866.  
  867.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
  868.  
  869.     auto geo = std::make_unique<MeshGeometry>();
  870.     geo->Name = "skullGeo";
  871.  
  872.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  873.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  874.  
  875.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  876.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  877.  
  878.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  879.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  880.  
  881.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  882.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  883.  
  884.     geo->VertexByteStride = sizeof(Vertex);
  885.     geo->VertexBufferByteSize = vbByteSize;
  886.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  887.     geo->IndexBufferByteSize = ibByteSize;
  888.  
  889.     SubmeshGeometry submesh;
  890.     submesh.IndexCount = (UINT)indices.size();
  891.     submesh.StartIndexLocation = 0;
  892.     submesh.BaseVertexLocation = 0;
  893.  
  894.     geo->DrawArgs["skull"] = submesh;
  895.  
  896.     mGeometries[geo->Name] = std::move(geo);
  897. }
  898.  
  899. void StencilApp::BuildPSOs()
  900. {
  901.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  902.  
  903.     //
  904.     // PSO for opaque objects.
  905.     //
  906.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  907.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  908.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  909.     opaquePsoDesc.VS = 
  910.     { 
  911.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  912.         mShaders["standardVS"]->GetBufferSize()
  913.     };
  914.     opaquePsoDesc.PS = 
  915.     { 
  916.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  917.         mShaders["opaquePS"]->GetBufferSize()
  918.     };
  919.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  920.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  921.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  922.     opaquePsoDesc.SampleMask = UINT_MAX;
  923.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  924.     opaquePsoDesc.NumRenderTargets = 1;
  925.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  926.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  927.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  928.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  929.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  930.  
  931.     //
  932.     // PSO for transparent objects
  933.     //
  934.  
  935.     D3D12_GRAPHICS_PIPELINE_STATE_DESC transparentPsoDesc = opaquePsoDesc;
  936.  
  937.     D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
  938.     transparencyBlendDesc.BlendEnable = true;
  939.     transparencyBlendDesc.LogicOpEnable = false;
  940.     transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  941.     transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  942.     transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
  943.     transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
  944.     transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
  945.     transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  946.     transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
  947.     transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  948.  
  949.     transparentPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
  950.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&transparentPsoDesc, IID_PPV_ARGS(&mPSOs["transparent"])));
  951.  
  952.     //
  953.     // PSO for marking stencil mirrors.
  954.     //
  955.  
  956.     CD3DX12_BLEND_DESC mirrorBlendState(D3D12_DEFAULT);
  957.     mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0;
  958.  
  959.     D3D12_DEPTH_STENCIL_DESC mirrorDSS;
  960.     mirrorDSS.DepthEnable = true;
  961.     mirrorDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
  962.     mirrorDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
  963.     mirrorDSS.StencilEnable = true;
  964.     mirrorDSS.StencilReadMask = 0xff;
  965.     mirrorDSS.StencilWriteMask = 0xff;
  966.     
  967.     mirrorDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  968.     mirrorDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  969.     mirrorDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
  970.     mirrorDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
  971.  
  972.     // We are not rendering backfacing polygons, so these settings do not matter.
  973.     mirrorDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  974.     mirrorDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  975.     mirrorDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
  976.     mirrorDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
  977.  
  978.     D3D12_GRAPHICS_PIPELINE_STATE_DESC markMirrorsPsoDesc = opaquePsoDesc;
  979.     markMirrorsPsoDesc.BlendState = mirrorBlendState;
  980.     markMirrorsPsoDesc.DepthStencilState = mirrorDSS;
  981.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&markMirrorsPsoDesc, IID_PPV_ARGS(&mPSOs["markStencilMirrors"])));
  982.  
  983.     //
  984.     // PSO for stencil reflections.
  985.     //
  986.  
  987.     D3D12_DEPTH_STENCIL_DESC reflectionsDSS;
  988.     reflectionsDSS.DepthEnable = true;
  989.     reflectionsDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
  990.     reflectionsDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
  991.     reflectionsDSS.StencilEnable = true;
  992.     reflectionsDSS.StencilReadMask = 0xff;
  993.     reflectionsDSS.StencilWriteMask = 0xff;
  994.  
  995.     reflectionsDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  996.     reflectionsDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  997.     reflectionsDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
  998.     reflectionsDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
  999.  
  1000.     // We are not rendering backfacing polygons, so these settings do not matter.
  1001.     reflectionsDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  1002.     reflectionsDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  1003.     reflectionsDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
  1004.     reflectionsDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
  1005.  
  1006.     D3D12_GRAPHICS_PIPELINE_STATE_DESC drawReflectionsPsoDesc = opaquePsoDesc;
  1007.     drawReflectionsPsoDesc.DepthStencilState = reflectionsDSS;
  1008.     drawReflectionsPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
  1009.     drawReflectionsPsoDesc.RasterizerState.FrontCounterClockwise = true;
  1010.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&drawReflectionsPsoDesc, IID_PPV_ARGS(&mPSOs["drawStencilReflections"])));
  1011.  
  1012.     //
  1013.     // PSO for shadow objects
  1014.     //
  1015.  
  1016.     // We are going to draw shadows with transparency, so base it off the transparency description.
  1017.     D3D12_DEPTH_STENCIL_DESC shadowDSS;
  1018.     shadowDSS.DepthEnable = true;
  1019.     shadowDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
  1020.     shadowDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
  1021.     shadowDSS.StencilEnable = true;
  1022.     shadowDSS.StencilReadMask = 0xff;
  1023.     shadowDSS.StencilWriteMask = 0xff;
  1024.  
  1025.     shadowDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  1026.     shadowDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  1027.     shadowDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
  1028.     shadowDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
  1029.  
  1030.     // We are not rendering backfacing polygons, so these settings do not matter.
  1031.     shadowDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
  1032.     shadowDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
  1033.     shadowDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
  1034.     shadowDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
  1035.  
  1036.     D3D12_GRAPHICS_PIPELINE_STATE_DESC shadowPsoDesc = transparentPsoDesc;
  1037.     shadowPsoDesc.DepthStencilState = shadowDSS;
  1038.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&shadowPsoDesc, IID_PPV_ARGS(&mPSOs["shadow"])));
  1039. }
  1040.  
  1041. void StencilApp::BuildFrameResources()
  1042. {
  1043.     for(int i = 0; i < gNumFrameResources; ++i)
  1044.     {
  1045.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  1046.             2, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  1047.     }
  1048. }
  1049.  
  1050. void StencilApp::BuildMaterials()
  1051. {
  1052.     auto bricks = std::make_unique<Material>();
  1053.     bricks->Name = "bricks";
  1054.     bricks->MatCBIndex = 0;
  1055.     bricks->DiffuseSrvHeapIndex = 0;
  1056.     bricks->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1057.     bricks->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  1058.     bricks->Roughness = 0.25f;
  1059.  
  1060.     auto checkertile = std::make_unique<Material>();
  1061.     checkertile->Name = "checkertile";
  1062.     checkertile->MatCBIndex = 1;
  1063.     checkertile->DiffuseSrvHeapIndex = 1;
  1064.     checkertile->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1065.     checkertile->FresnelR0 = XMFLOAT3(0.07f, 0.07f, 0.07f);
  1066.     checkertile->Roughness = 0.3f;
  1067.  
  1068.     auto icemirror = std::make_unique<Material>();
  1069.     icemirror->Name = "icemirror";
  1070.     icemirror->MatCBIndex = 2;
  1071.     icemirror->DiffuseSrvHeapIndex = 2;
  1072.     icemirror->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.3f);
  1073.     icemirror->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  1074.     icemirror->Roughness = 0.5f;
  1075.  
  1076.     auto skullMat = std::make_unique<Material>();
  1077.     skullMat->Name = "skullMat";
  1078.     skullMat->MatCBIndex = 3;
  1079.     skullMat->DiffuseSrvHeapIndex = 3;
  1080.     skullMat->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1081.     skullMat->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  1082.     skullMat->Roughness = 0.3f;
  1083.  
  1084.     auto shadowMat = std::make_unique<Material>();
  1085.     shadowMat->Name = "shadowMat";
  1086.     shadowMat->MatCBIndex = 4;
  1087.     shadowMat->DiffuseSrvHeapIndex = 3;
  1088.     shadowMat->DiffuseAlbedo = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.5f);
  1089.     shadowMat->FresnelR0 = XMFLOAT3(0.001f, 0.001f, 0.001f);
  1090.     shadowMat->Roughness = 0.0f;
  1091.  
  1092.     mMaterials["bricks"] = std::move(bricks);
  1093.     mMaterials["checkertile"] = std::move(checkertile);
  1094.     mMaterials["icemirror"] = std::move(icemirror);
  1095.     mMaterials["skullMat"] = std::move(skullMat);
  1096.     mMaterials["shadowMat"] = std::move(shadowMat);
  1097. }
  1098.  
  1099. void StencilApp::BuildRenderItems()
  1100. {
  1101.     auto floorRitem = std::make_unique<RenderItem>();
  1102.     floorRitem->World = MathHelper::Identity4x4();
  1103.     floorRitem->TexTransform = MathHelper::Identity4x4();
  1104.     floorRitem->ObjCBIndex = 0;
  1105.     floorRitem->Mat = mMaterials["checkertile"].get();
  1106.     floorRitem->Geo = mGeometries["roomGeo"].get();
  1107.     floorRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1108.     floorRitem->IndexCount = floorRitem->Geo->DrawArgs["floor"].IndexCount;
  1109.     floorRitem->StartIndexLocation = floorRitem->Geo->DrawArgs["floor"].StartIndexLocation;
  1110.     floorRitem->BaseVertexLocation = floorRitem->Geo->DrawArgs["floor"].BaseVertexLocation;
  1111.     mRitemLayer[(int)RenderLayer::Opaque].push_back(floorRitem.get());
  1112.  
  1113.     auto wallsRitem = std::make_unique<RenderItem>();
  1114.     wallsRitem->World = MathHelper::Identity4x4();
  1115.     wallsRitem->TexTransform = MathHelper::Identity4x4();
  1116.     wallsRitem->ObjCBIndex = 1;
  1117.     wallsRitem->Mat = mMaterials["bricks"].get();
  1118.     wallsRitem->Geo = mGeometries["roomGeo"].get();
  1119.     wallsRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1120.     wallsRitem->IndexCount = wallsRitem->Geo->DrawArgs["wall"].IndexCount;
  1121.     wallsRitem->StartIndexLocation = wallsRitem->Geo->DrawArgs["wall"].StartIndexLocation;
  1122.     wallsRitem->BaseVertexLocation = wallsRitem->Geo->DrawArgs["wall"].BaseVertexLocation;
  1123.     mRitemLayer[(int)RenderLayer::Opaque].push_back(wallsRitem.get());
  1124.  
  1125.     auto skullRitem = std::make_unique<RenderItem>();
  1126.     skullRitem->World = MathHelper::Identity4x4();
  1127.     skullRitem->TexTransform = MathHelper::Identity4x4();
  1128.     skullRitem->ObjCBIndex = 2;
  1129.     skullRitem->Mat = mMaterials["skullMat"].get();
  1130.     skullRitem->Geo = mGeometries["skullGeo"].get();
  1131.     skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1132.     skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
  1133.     skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
  1134.     skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;
  1135.     mSkullRitem = skullRitem.get();
  1136.     mRitemLayer[(int)RenderLayer::Opaque].push_back(skullRitem.get());
  1137.  
  1138.     // Reflected skull will have different world matrix, so it needs to be its own render item.
  1139.     auto reflectedSkullRitem = std::make_unique<RenderItem>();
  1140.     *reflectedSkullRitem = *skullRitem;
  1141.     reflectedSkullRitem->ObjCBIndex = 3;
  1142.     mReflectedSkullRitem = reflectedSkullRitem.get();
  1143.     mRitemLayer[(int)RenderLayer::Reflected].push_back(reflectedSkullRitem.get());
  1144.  
  1145.     // Shadowed skull will have different world matrix, so it needs to be its own render item.
  1146.     auto shadowedSkullRitem = std::make_unique<RenderItem>();
  1147.     *shadowedSkullRitem = *skullRitem;
  1148.     shadowedSkullRitem->ObjCBIndex = 4;
  1149.     shadowedSkullRitem->Mat = mMaterials["shadowMat"].get();
  1150.     mShadowedSkullRitem = shadowedSkullRitem.get();
  1151.     mRitemLayer[(int)RenderLayer::Shadow].push_back(shadowedSkullRitem.get());
  1152.  
  1153.     auto mirrorRitem = std::make_unique<RenderItem>();
  1154.     mirrorRitem->World = MathHelper::Identity4x4();
  1155.     mirrorRitem->TexTransform = MathHelper::Identity4x4();
  1156.     mirrorRitem->ObjCBIndex = 5;
  1157.     mirrorRitem->Mat = mMaterials["icemirror"].get();
  1158.     mirrorRitem->Geo = mGeometries["roomGeo"].get();
  1159.     mirrorRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1160.     mirrorRitem->IndexCount = mirrorRitem->Geo->DrawArgs["mirror"].IndexCount;
  1161.     mirrorRitem->StartIndexLocation = mirrorRitem->Geo->DrawArgs["mirror"].StartIndexLocation;
  1162.     mirrorRitem->BaseVertexLocation = mirrorRitem->Geo->DrawArgs["mirror"].BaseVertexLocation;
  1163.     mRitemLayer[(int)RenderLayer::Mirrors].push_back(mirrorRitem.get());
  1164.     mRitemLayer[(int)RenderLayer::Transparent].push_back(mirrorRitem.get());
  1165.  
  1166.     mAllRitems.push_back(std::move(floorRitem));
  1167.     mAllRitems.push_back(std::move(wallsRitem));
  1168.     mAllRitems.push_back(std::move(skullRitem));
  1169.     mAllRitems.push_back(std::move(reflectedSkullRitem));
  1170.     mAllRitems.push_back(std::move(shadowedSkullRitem));
  1171.     mAllRitems.push_back(std::move(mirrorRitem));
  1172. }
  1173.  
  1174. void StencilApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  1175. {
  1176.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  1177.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  1178.  
  1179.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  1180.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  1181.  
  1182.     // For each render item...
  1183.     for(size_t i = 0; i < ritems.size(); ++i)
  1184.     {
  1185.         auto ri = ritems[i];
  1186.  
  1187.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  1188.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  1189.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  1190.  
  1191.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  1192.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  1193.  
  1194.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  1195.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  1196.  
  1197.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  1198.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  1199.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  1200.  
  1201.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  1202.     }
  1203. }
  1204.  
  1205. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> StencilApp::GetStaticSamplers()
  1206. {
  1207.     // Applications usually only need a handful of samplers.  So just define them all up front
  1208.     // and keep them available as part of the root signature.  
  1209.  
  1210.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  1211.         0, // shaderRegister
  1212.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1213.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1214.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1215.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1216.  
  1217.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  1218.         1, // shaderRegister
  1219.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1220.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1221.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1222.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1223.  
  1224.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  1225.         2, // shaderRegister
  1226.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1227.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1228.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1229.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1230.  
  1231.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  1232.         3, // shaderRegister
  1233.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1234.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1235.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1236.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1237.  
  1238.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  1239.         4, // shaderRegister
  1240.         D3D12_FILTER_ANISOTROPIC, // filter
  1241.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1242.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1243.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1244.         0.0f,                             // mipLODBias
  1245.         8);                               // maxAnisotropy
  1246.  
  1247.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1248.         5, // shaderRegister
  1249.         D3D12_FILTER_ANISOTROPIC, // filter
  1250.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1251.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1252.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1253.         0.0f,                              // mipLODBias
  1254.         8);                                // maxAnisotropy
  1255.  
  1256.     return { 
  1257.         pointWrap, pointClamp,
  1258.         linearWrap, linearClamp, 
  1259.         anisotropicWrap, anisotropicClamp };
  1260. }
  1261.