home *** CD-ROM | disk | FTP | other *** search
- //***************************************************************************************
- // LandAndWavesApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
- //
- // Hold down '1' key to view scene in wireframe mode.
- //***************************************************************************************
-
- #include "../../Common/d3dApp.h"
- #include "../../Common/MathHelper.h"
- #include "../../Common/UploadBuffer.h"
- #include "../../Common/GeometryGenerator.h"
- #include "FrameResource.h"
- #include "Waves.h"
-
- using Microsoft::WRL::ComPtr;
- using namespace DirectX;
- using namespace DirectX::PackedVector;
-
- const int gNumFrameResources = 3;
-
- // Lightweight structure stores parameters to draw a shape. This will
- // vary from app-to-app.
- struct RenderItem
- {
- RenderItem() = default;
-
- // World matrix of the shape that describes the object's local space
- // relative to the world space, which defines the position, orientation,
- // and scale of the object in the world.
- XMFLOAT4X4 World = MathHelper::Identity4x4();
-
- // Dirty flag indicating the object data has changed and we need to update the constant buffer.
- // Because we have an object cbuffer for each FrameResource, we have to apply the
- // update to each FrameResource. Thus, when we modify obect data we should set
- // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
- int NumFramesDirty = gNumFrameResources;
-
- // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
- UINT ObjCBIndex = -1;
-
- MeshGeometry* Geo = nullptr;
-
- // Primitive topology.
- D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
-
- // DrawIndexedInstanced parameters.
- UINT IndexCount = 0;
- UINT StartIndexLocation = 0;
- int BaseVertexLocation = 0;
- };
-
- enum class RenderLayer : int
- {
- Opaque = 0,
- Count
- };
-
- class LandAndWavesApp : public D3DApp
- {
- public:
- LandAndWavesApp(HINSTANCE hInstance);
- LandAndWavesApp(const LandAndWavesApp& rhs) = delete;
- LandAndWavesApp& operator=(const LandAndWavesApp& rhs) = delete;
- ~LandAndWavesApp();
-
- virtual bool Initialize()override;
-
- private:
- virtual void OnResize()override;
- virtual void Update(const GameTimer& gt)override;
- virtual void Draw(const GameTimer& gt)override;
-
- virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
- virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
- virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
-
- void OnKeyboardInput(const GameTimer& gt);
- void UpdateCamera(const GameTimer& gt);
- void UpdateObjectCBs(const GameTimer& gt);
- void UpdateMainPassCB(const GameTimer& gt);
- void UpdateWaves(const GameTimer& gt);
-
- void BuildRootSignature();
- void BuildShadersAndInputLayout();
- void BuildLandGeometry();
- void BuildWavesGeometryBuffers();
- void BuildPSOs();
- void BuildFrameResources();
- void BuildRenderItems();
- void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
-
- float GetHillsHeight(float x, float z)const;
- XMFLOAT3 GetHillsNormal(float x, float z)const;
-
- private:
-
- std::vector<std::unique_ptr<FrameResource>> mFrameResources;
- FrameResource* mCurrFrameResource = nullptr;
- int mCurrFrameResourceIndex = 0;
-
- UINT mCbvSrvDescriptorSize = 0;
-
- ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
-
- std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
- std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
- std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
-
- std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
-
- RenderItem* mWavesRitem = nullptr;
-
- // List of all the render items.
- std::vector<std::unique_ptr<RenderItem>> mAllRitems;
-
- // Render items divided by PSO.
- std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
-
- std::unique_ptr<Waves> mWaves;
-
- PassConstants mMainPassCB;
-
- bool mIsWireframe = false;
-
- XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
- XMFLOAT4X4 mView = MathHelper::Identity4x4();
- XMFLOAT4X4 mProj = MathHelper::Identity4x4();
-
- float mTheta = 1.5f*XM_PI;
- float mPhi = XM_PIDIV2 - 0.1f;
- float mRadius = 50.0f;
-
- float mSunTheta = 1.25f*XM_PI;
- float mSunPhi = XM_PIDIV4;
-
- POINT mLastMousePos;
- };
-
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
- PSTR cmdLine, int showCmd)
- {
- // Enable run-time memory check for debug builds.
- #if defined(DEBUG) | defined(_DEBUG)
- _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- #endif
-
- try
- {
- LandAndWavesApp theApp(hInstance);
- if(!theApp.Initialize())
- return 0;
-
- return theApp.Run();
- }
- catch(DxException& e)
- {
- MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
- return 0;
- }
- }
-
- LandAndWavesApp::LandAndWavesApp(HINSTANCE hInstance)
- : D3DApp(hInstance)
- {
- }
-
- LandAndWavesApp::~LandAndWavesApp()
- {
- if(md3dDevice != nullptr)
- FlushCommandQueue();
- }
-
- bool LandAndWavesApp::Initialize()
- {
- if(!D3DApp::Initialize())
- return false;
-
- // Reset the command list to prep for initialization commands.
- ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
-
- mWaves = std::make_unique<Waves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);
-
- BuildRootSignature();
- BuildShadersAndInputLayout();
- BuildLandGeometry();
- BuildWavesGeometryBuffers();
- BuildRenderItems();
- BuildRenderItems();
- BuildFrameResources();
- BuildPSOs();
-
- // Execute the initialization commands.
- ThrowIfFailed(mCommandList->Close());
- ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
- mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
-
- // Wait until initialization is complete.
- FlushCommandQueue();
-
- return true;
- }
-
- void LandAndWavesApp::OnResize()
- {
- D3DApp::OnResize();
-
- // The window resized, so update the aspect ratio and recompute the projection matrix.
- XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
- XMStoreFloat4x4(&mProj, P);
- }
-
- void LandAndWavesApp::Update(const GameTimer& gt)
- {
- OnKeyboardInput(gt);
- UpdateCamera(gt);
-
- // Cycle through the circular frame resource array.
- mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
- mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
-
- // Has the GPU finished processing the commands of the current frame resource?
- // If not, wait until the GPU has completed commands up to this fence point.
- if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
- {
- HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
- ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
- WaitForSingleObject(eventHandle, INFINITE);
- CloseHandle(eventHandle);
- }
-
- UpdateObjectCBs(gt);
- UpdateMainPassCB(gt);
- UpdateWaves(gt);
- }
-
- void LandAndWavesApp::Draw(const GameTimer& gt)
- {
- auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
-
- // Reuse the memory associated with command recording.
- // We can only reset when the associated command lists have finished execution on the GPU.
- ThrowIfFailed(cmdListAlloc->Reset());
-
- // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
- // Reusing the command list reuses memory.
- if(mIsWireframe)
- {
- ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque_wireframe"].Get()));
- }
- else
- {
- ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
- }
-
- mCommandList->RSSetViewports(1, &mScreenViewport);
- mCommandList->RSSetScissorRects(1, &mScissorRect);
-
- // Indicate a state transition on the resource usage.
- mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
- D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
-
- // Clear the back buffer and depth buffer.
- mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
- mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
-
- // Specify the buffers we are going to render to.
- mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
-
- mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
-
- // Bind per-pass constant buffer. We only need to do this once per-pass.
- auto passCB = mCurrFrameResource->PassCB->Resource();
- mCommandList->SetGraphicsRootConstantBufferView(1, passCB->GetGPUVirtualAddress());
-
- DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
-
- // Indicate a state transition on the resource usage.
- mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
- D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
-
- // Done recording commands.
- ThrowIfFailed(mCommandList->Close());
-
- // Add the command list to the queue for execution.
- ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
- mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
-
- // Swap the back and front buffers
- ThrowIfFailed(mSwapChain->Present(0, 0));
- mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
-
- // Advance the fence value to mark commands up to this fence point.
- mCurrFrameResource->Fence = ++mCurrentFence;
-
- // Add an instruction to the command queue to set a new fence point.
- // Because we are on the GPU timeline, the new fence point won't be
- // set until the GPU finishes processing all the commands prior to this Signal().
- mCommandQueue->Signal(mFence.Get(), mCurrentFence);
- }
-
- void LandAndWavesApp::OnMouseDown(WPARAM btnState, int x, int y)
- {
- mLastMousePos.x = x;
- mLastMousePos.y = y;
-
- SetCapture(mhMainWnd);
- }
-
- void LandAndWavesApp::OnMouseUp(WPARAM btnState, int x, int y)
- {
- ReleaseCapture();
- }
-
- void LandAndWavesApp::OnMouseMove(WPARAM btnState, int x, int y)
- {
- if((btnState & MK_LBUTTON) != 0)
- {
- // Make each pixel correspond to a quarter of a degree.
- float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
- float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
-
- // Update angles based on input to orbit camera around box.
- mTheta += dx;
- mPhi += dy;
-
- // Restrict the angle mPhi.
- mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
- }
- else if((btnState & MK_RBUTTON) != 0)
- {
- // Make each pixel correspond to 0.2 unit in the scene.
- float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
- float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
-
- // Update the camera radius based on input.
- mRadius += dx - dy;
-
- // Restrict the radius.
- mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
- }
-
- mLastMousePos.x = x;
- mLastMousePos.y = y;
- }
-
- void LandAndWavesApp::OnKeyboardInput(const GameTimer& gt)
- {
- if(GetAsyncKeyState('1') & 0x8000)
- mIsWireframe = true;
- else
- mIsWireframe = false;
- }
-
- void LandAndWavesApp::UpdateCamera(const GameTimer& gt)
- {
- // Convert Spherical to Cartesian coordinates.
- mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
- mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
- mEyePos.y = mRadius*cosf(mPhi);
-
- // Build the view matrix.
- XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
- XMVECTOR target = XMVectorZero();
- XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
-
- XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
- XMStoreFloat4x4(&mView, view);
- }
-
- void LandAndWavesApp::UpdateObjectCBs(const GameTimer& gt)
- {
- auto currObjectCB = mCurrFrameResource->ObjectCB.get();
- for(auto& e : mAllRitems)
- {
- // Only update the cbuffer data if the constants have changed.
- // This needs to be tracked per frame resource.
- if(e->NumFramesDirty > 0)
- {
- XMMATRIX world = XMLoadFloat4x4(&e->World);
-
- ObjectConstants objConstants;
- XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
-
- currObjectCB->CopyData(e->ObjCBIndex, objConstants);
-
- // Next FrameResource need to be updated too.
- e->NumFramesDirty--;
- }
- }
- }
-
- void LandAndWavesApp::UpdateMainPassCB(const GameTimer& gt)
- {
- XMMATRIX view = XMLoadFloat4x4(&mView);
- XMMATRIX proj = XMLoadFloat4x4(&mProj);
-
- XMMATRIX viewProj = XMMatrixMultiply(view, proj);
- XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
- XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
- XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
-
- XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
- XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
- XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
- XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
- XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
- XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
- mMainPassCB.EyePosW = mEyePos;
- mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
- mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
- mMainPassCB.NearZ = 1.0f;
- mMainPassCB.FarZ = 1000.0f;
- mMainPassCB.TotalTime = gt.TotalTime();
- mMainPassCB.DeltaTime = gt.DeltaTime();
-
- auto currPassCB = mCurrFrameResource->PassCB.get();
- currPassCB->CopyData(0, mMainPassCB);
- }
-
- void LandAndWavesApp::UpdateWaves(const GameTimer& gt)
- {
- // Every quarter second, generate a random wave.
- static float t_base = 0.0f;
- if((mTimer.TotalTime() - t_base) >= 0.25f)
- {
- t_base += 0.25f;
-
- int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
- int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
-
- float r = MathHelper::RandF(0.2f, 0.5f);
-
- mWaves->Disturb(i, j, r);
- }
-
- // Update the wave simulation.
- mWaves->Update(gt.DeltaTime());
-
- // Update the wave vertex buffer with the new solution.
- auto currWavesVB = mCurrFrameResource->WavesVB.get();
- for(int i = 0; i < mWaves->VertexCount(); ++i)
- {
- Vertex v;
-
- v.Pos = mWaves->Position(i);
- v.Color = XMFLOAT4(DirectX::Colors::Blue);
-
- currWavesVB->CopyData(i, v);
- }
-
- // Set the dynamic VB of the wave renderitem to the current frame VB.
- mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
- }
-
- void LandAndWavesApp::BuildRootSignature()
- {
- // Root parameter can be a table, root descriptor or root constants.
- CD3DX12_ROOT_PARAMETER slotRootParameter[2];
-
- // Create root CBV.
- slotRootParameter[0].InitAsConstantBufferView(0);
- slotRootParameter[1].InitAsConstantBufferView(1);
-
- // A root signature is an array of root parameters.
- CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(2, slotRootParameter, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
-
- // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
- ComPtr<ID3DBlob> serializedRootSig = nullptr;
- ComPtr<ID3DBlob> errorBlob = nullptr;
- HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
- serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
-
- if(errorBlob != nullptr)
- {
- ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
- }
- ThrowIfFailed(hr);
-
- ThrowIfFailed(md3dDevice->CreateRootSignature(
- 0,
- serializedRootSig->GetBufferPointer(),
- serializedRootSig->GetBufferSize(),
- IID_PPV_ARGS(mRootSignature.GetAddressOf())));
- }
-
- void LandAndWavesApp::BuildShadersAndInputLayout()
- {
- mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "VS", "vs_5_0");
- mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\color.hlsl", nullptr, "PS", "ps_5_0");
-
- mInputLayout =
- {
- { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
- { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
- };
- }
-
- void LandAndWavesApp::BuildLandGeometry()
- {
- GeometryGenerator geoGen;
- GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
-
- //
- // Extract the vertex elements we are interested and apply the height function to
- // each vertex. In addition, color the vertices based on their height so we have
- // sandy looking beaches, grassy low hills, and snow mountain peaks.
- //
-
- std::vector<Vertex> vertices(grid.Vertices.size());
- for(size_t i = 0; i < grid.Vertices.size(); ++i)
- {
- auto& p = grid.Vertices[i].Position;
- vertices[i].Pos = p;
- vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
-
- // Color the vertex based on its height.
- if(vertices[i].Pos.y < -10.0f)
- {
- // Sandy beach color.
- vertices[i].Color = XMFLOAT4(1.0f, 0.96f, 0.62f, 1.0f);
- }
- else if(vertices[i].Pos.y < 5.0f)
- {
- // Light yellow-green.
- vertices[i].Color = XMFLOAT4(0.48f, 0.77f, 0.46f, 1.0f);
- }
- else if(vertices[i].Pos.y < 12.0f)
- {
- // Dark yellow-green.
- vertices[i].Color = XMFLOAT4(0.1f, 0.48f, 0.19f, 1.0f);
- }
- else if(vertices[i].Pos.y < 20.0f)
- {
- // Dark brown.
- vertices[i].Color = XMFLOAT4(0.45f, 0.39f, 0.34f, 1.0f);
- }
- else
- {
- // White snow.
- vertices[i].Color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
- }
- }
-
- const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
-
- std::vector<std::uint16_t> indices = grid.GetIndices16();
- const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
-
- auto geo = std::make_unique<MeshGeometry>();
- geo->Name = "landGeo";
-
- ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
- CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
-
- ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
- CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
-
- geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
- mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
-
- geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
- mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
-
- geo->VertexByteStride = sizeof(Vertex);
- geo->VertexBufferByteSize = vbByteSize;
- geo->IndexFormat = DXGI_FORMAT_R16_UINT;
- geo->IndexBufferByteSize = ibByteSize;
-
- SubmeshGeometry submesh;
- submesh.IndexCount = (UINT)indices.size();
- submesh.StartIndexLocation = 0;
- submesh.BaseVertexLocation = 0;
-
- geo->DrawArgs["grid"] = submesh;
-
- mGeometries["landGeo"] = std::move(geo);
- }
-
- void LandAndWavesApp::BuildWavesGeometryBuffers()
- {
- std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount()); // 3 indices per face
- assert(mWaves->VertexCount() < 0x0000ffff);
-
- // Iterate over each quad.
- int m = mWaves->RowCount();
- int n = mWaves->ColumnCount();
- int k = 0;
- for(int i = 0; i < m - 1; ++i)
- {
- for(int j = 0; j < n - 1; ++j)
- {
- indices[k] = i*n + j;
- indices[k + 1] = i*n + j + 1;
- indices[k + 2] = (i + 1)*n + j;
-
- indices[k + 3] = (i + 1)*n + j;
- indices[k + 4] = i*n + j + 1;
- indices[k + 5] = (i + 1)*n + j + 1;
-
- k += 6; // next quad
- }
- }
-
- UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
- UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint16_t);
-
- auto geo = std::make_unique<MeshGeometry>();
- geo->Name = "waterGeo";
-
- // Set dynamically.
- geo->VertexBufferCPU = nullptr;
- geo->VertexBufferGPU = nullptr;
-
- ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
- CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
-
- geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
- mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
-
- geo->VertexByteStride = sizeof(Vertex);
- geo->VertexBufferByteSize = vbByteSize;
- geo->IndexFormat = DXGI_FORMAT_R16_UINT;
- geo->IndexBufferByteSize = ibByteSize;
-
- SubmeshGeometry submesh;
- submesh.IndexCount = (UINT)indices.size();
- submesh.StartIndexLocation = 0;
- submesh.BaseVertexLocation = 0;
-
- geo->DrawArgs["grid"] = submesh;
-
- mGeometries["waterGeo"] = std::move(geo);
- }
-
- void LandAndWavesApp::BuildPSOs()
- {
- D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
-
- //
- // PSO for opaque objects.
- //
- ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
- opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
- opaquePsoDesc.pRootSignature = mRootSignature.Get();
- opaquePsoDesc.VS =
- {
- reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()),
- mShaders["standardVS"]->GetBufferSize()
- };
- opaquePsoDesc.PS =
- {
- reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
- mShaders["opaquePS"]->GetBufferSize()
- };
- opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
- opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
- opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
- opaquePsoDesc.SampleMask = UINT_MAX;
- opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
- opaquePsoDesc.NumRenderTargets = 1;
- opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
- opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
- opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
- opaquePsoDesc.DSVFormat = mDepthStencilFormat;
- ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
-
- //
- // PSO for opaque wireframe objects.
- //
-
- D3D12_GRAPHICS_PIPELINE_STATE_DESC opaqueWireframePsoDesc = opaquePsoDesc;
- opaqueWireframePsoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
- ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaqueWireframePsoDesc, IID_PPV_ARGS(&mPSOs["opaque_wireframe"])));
- }
-
- void LandAndWavesApp::BuildFrameResources()
- {
- for(int i = 0; i < gNumFrameResources; ++i)
- {
- mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
- 1, (UINT)mAllRitems.size(), mWaves->VertexCount()));
- }
- }
-
- void LandAndWavesApp::BuildRenderItems()
- {
- auto wavesRitem = std::make_unique<RenderItem>();
- wavesRitem->World = MathHelper::Identity4x4();
- wavesRitem->ObjCBIndex = 0;
- wavesRitem->Geo = mGeometries["waterGeo"].get();
- wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
- wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
- wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
-
- mWavesRitem = wavesRitem.get();
-
- mRitemLayer[(int)RenderLayer::Opaque].push_back(wavesRitem.get());
-
- auto gridRitem = std::make_unique<RenderItem>();
- gridRitem->World = MathHelper::Identity4x4();
- gridRitem->ObjCBIndex = 1;
- gridRitem->Geo = mGeometries["landGeo"].get();
- gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
- gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
- gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
-
- mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
-
- mAllRitems.push_back(std::move(wavesRitem));
- mAllRitems.push_back(std::move(gridRitem));
- }
-
- void LandAndWavesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
- {
- UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
-
- auto objectCB = mCurrFrameResource->ObjectCB->Resource();
-
- // For each render item...
- for(size_t i = 0; i < ritems.size(); ++i)
- {
- auto ri = ritems[i];
-
- cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
- cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
- cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
-
- D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress();
- objCBAddress += ri->ObjCBIndex*objCBByteSize;
-
- cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
-
- cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
- }
- }
-
- float LandAndWavesApp::GetHillsHeight(float x, float z)const
- {
- return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
- }
-
- XMFLOAT3 LandAndWavesApp::GetHillsNormal(float x, float z)const
- {
- // n = (-df/dx, 1, -df/dz)
- XMFLOAT3 n(
- -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
- 1.0f,
- -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
-
- XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
- XMStoreFloat3(&n, unitNormal);
-
- return n;
- }
-