作业
课程设计
#include "../../Common/d3dApp.h" // 基本d3d结构
#include "../../Common/MathHelper.h" // 基本数学包装
#include "../../Common/UploadBuffer.h" // 上传缓冲区包装
#include "../../Common/GeometryGenerator.h" // 生成模型包装
#include "FrameResource.h" // 帧资源包装
#include "Waves.h" // 生成波纹
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "D3D12.lib")
//帧资源数
const int NumFrameResources = 3;
//渲染项
struct RenderItem
{
RenderItem() = default;
// 世界坐标
DirectX::XMFLOAT4X4 World = MathHelper::Identity4x4();
// 指示对象数据已更改
int NumFramesDirty = NumFrameResources;
// 常量缓冲区索引
UINT ObjCBIndex = -1;
// 材质
Material* Mat = nullptr;
// 模型
MeshGeometry* Geo = nullptr;
// 拓扑结构
D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
// 绘制索引总数
UINT IndexCount = 0;
// 绘制索引开始
UINT StartIndexLocation = 0;
// 绘制索引偏移
int BaseVertexLocation = 0;
};
//渲染层
enum class RenderLayer : int
{
Opaque = 0,
Count
};
//主类
class LitWavesApp final : public D3DApp
{
public:
LitWavesApp() = delete;
explicit LitWavesApp(HINSTANCE hInstance);
LitWavesApp(const LitWavesApp& rhs) = delete;
LitWavesApp(LitWavesApp&& rhs) = delete;
LitWavesApp& operator=(const LitWavesApp& rhs) = delete;
LitWavesApp& operator=(LitWavesApp&& rhs) = delete;
~LitWavesApp();
// 初始化
bool Initialize() override;
private:
// 窗口缩放
void OnResize() override;
// 更新
void Update(const GameTimer& gt) override;
// 绘制
void Draw(const GameTimer& gt) override;
// 处理鼠标按下
void OnMouseDown(WPARAM btnState, int x, int y) override;
// 处理鼠标抬起
void OnMouseUp(WPARAM btnState, int x, int y) override;
// 处理鼠标移动
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 UpdateMaterialCBs(const GameTimer& gt);
// 更新Pass常量缓冲区
void UpdateMainPassCB(const GameTimer& gt);
// 更新波浪
void UpdateWaves(const GameTimer& gt) const;
// 创建根签名
void BuildRootSignature();
// 创建着色器和输入层
void BuildShadersAndInputLayout();
// 创建陆地模型
void BuildLandGeometry();
// 创建波浪模型缓冲区
void BuildWavesGeometryBuffers();
// 创建流水线状态对象
void BuildPSOs();
// 创建帧资源
void BuildFrameResources();
// 创建材质
void BuildMaterials();
// 创建渲染项
void BuildRenderItems();
// 绘制所有渲染项
void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems) const;
// 获取地形高度
static float GetHillsHeight(float x, float z);
// 获取地形法线
DirectX::XMFLOAT3 GetHillsNormal(float x, float z) const;
// 帧资源
std::vector<std::unique_ptr<FrameResource>> mFrameResources;
// 当前帧资源
FrameResource* mCurrFrameResource = nullptr;
// 当前帧资源索引
int mCurrFrameResourceIndex = 0;
// 描述符的大小
UINT mCbvSrvDescriptorSize = 0;
// 根签名
Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
// 模型
std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
// 材质
std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
// 着色器
std::unordered_map<std::string, Microsoft::WRL::ComPtr<ID3DBlob>> mShaders;
// 流水线状态对象
std::unordered_map<std::string, Microsoft::WRL::ComPtr<ID3D12PipelineState>> mPSOs;
// 输入布局
std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
// 水的渲染项
RenderItem* mWavesRitem = nullptr;
// 所有的渲染项
std::vector<std::unique_ptr<RenderItem>> mAllRitems;
// 渲染层
std::vector<RenderItem*> mRitemLayer[static_cast<int>(RenderLayer::Count)];
// 波纹
std::unique_ptr<Waves> mWaves;
// main pass
PassConstants mMainPassCB;
// 观察矩阵
DirectX::XMFLOAT3 mEyePos = {0.0f, 0.0f, 0.0f};
DirectX::XMFLOAT4X4 mView = MathHelper::Identity4x4();
DirectX::XMFLOAT4X4 mProj = MathHelper::Identity4x4();
float mTheta = 1.5f * DirectX::XM_PI;
float mPhi = DirectX::XM_PIDIV2 - 0.1f;
float mRadius = 50.0f;
// 光源
float mSunTheta = 1.25f * DirectX::XM_PI;
float mSunPhi = DirectX::XM_PIDIV4;
// 鼠标位置
POINT mLastMousePos{};
};
LitWavesApp::LitWavesApp(const HINSTANCE hInstance) : D3DApp(hInstance)
{
}
LitWavesApp::~LitWavesApp()
{
if (md3dDevice != nullptr)
FlushCommandQueue();
}
bool LitWavesApp::Initialize()
{
// 初始化Windows窗口 和 Direct3D 12
if (!D3DApp::Initialize()) return false;
// 重置命令队列
ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
// 获取描述符的大小
mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
// 产生波浪模拟
mWaves = std::make_unique<Waves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);
// 创建根签名
BuildRootSignature();
// 创建着色器和输入层
BuildShadersAndInputLayout();
// 创建陆地模型
BuildLandGeometry();
// 创建波浪模型缓冲区
BuildWavesGeometryBuffers();
// 创建材质
BuildMaterials();
// 创建渲染项
BuildRenderItems();
// 创建帧资源
BuildFrameResources();
// 创建流水线状态对象
BuildPSOs();
// 初始化命令队列
ThrowIfFailed(mCommandList->Close());
ID3D12CommandList* cmdsLists[] = {mCommandList.Get()};
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
// 等待命令队列初始化完成
FlushCommandQueue();
return true;
}
void LitWavesApp::OnResize()
{
D3DApp::OnResize();
// 更改投影矩阵
const auto p = DirectX::XMMatrixPerspectiveFovLH(0.25f * MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
XMStoreFloat4x4(&mProj, p);
}
void LitWavesApp::Update(const GameTimer& gt)
{
OnKeyboardInput(gt);
UpdateCamera(gt);
// 循环遍历循环帧资源数组
mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % NumFrameResources;
mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
// 等待GPU处理
if (mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
{
const auto eventHandle = CreateEventEx(nullptr, nullptr, false, EVENT_ALL_ACCESS);
ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
WaitForSingleObject(eventHandle, INFINITE);
CloseHandle(eventHandle);
}
// 更新常量缓冲区
UpdateObjectCBs(gt);
UpdateMaterialCBs(gt);
UpdateMainPassCB(gt);
UpdateWaves(gt);
}
void LitWavesApp::Draw(const GameTimer& gt)
{
auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
// 重置命令队列
ThrowIfFailed(cmdListAlloc->Reset());
ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
// 更新投影矩阵
mCommandList->RSSetViewports(1, &mScreenViewport);
// 更新裁剪矩阵
mCommandList->RSSetScissorRects(1, &mScissorRect);
// 设置资源状态
mCommandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET));
// 清空背景缓冲区
mCommandList->ClearRenderTargetView(
CurrentBackBufferView(),
DirectX::Colors::LightSteelBlue,
0,
nullptr);
// 清空模板
mCommandList->ClearDepthStencilView(
DepthStencilView(),
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL,
1.0f,
0,
0,
nullptr);
// 指定渲染缓冲区
mCommandList->OMSetRenderTargets(
1,
&CurrentBackBufferView(),
true,
&DepthStencilView());
// 设置根签名
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
// 指定pass
auto passCB = mCurrFrameResource->PassCB->Resource();
mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
// 绘制所有渲染项
DrawRenderItems(mCommandList.Get(), mRitemLayer[static_cast<int>(RenderLayer::Opaque)]);
// 设置资源状态
mCommandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(
CurrentBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT));
// 结束命令提交
ThrowIfFailed(mCommandList->Close());
// 将命令添加到队列
ID3D12CommandList* cmdsLists[] = {mCommandList.Get()};
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
// 交换前后缓冲区
ThrowIfFailed(mSwapChain->Present(0, 0));
mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
// 设置围栏
mCurrFrameResource->Fence = ++mCurrentFence;
mCommandQueue->Signal(mFence.Get(), mCurrentFence);
}
void LitWavesApp::OnMouseDown(WPARAM btnState, const int x, const int y)
{
mLastMousePos.x = x;
mLastMousePos.y = y;
SetCapture(mhMainWnd);
}
void LitWavesApp::OnMouseUp(WPARAM btnState, int x, int y)
{
ReleaseCapture();
}
void LitWavesApp::OnMouseMove(const WPARAM btnState, const int x, const int y)
{
// 左键
if ((btnState & MK_LBUTTON) != 0)
{
const auto dx = DirectX::XMConvertToRadians(0.25f * static_cast<float>(x - mLastMousePos.x));
const auto dy = DirectX::XMConvertToRadians(0.25f * static_cast<float>(y - mLastMousePos.y));
mTheta += dx;
mPhi += dy;
mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
}
else if ((btnState & MK_RBUTTON) != 0) // 右键
{
float dx = 0.2f * static_cast<float>(x - mLastMousePos.x);
float dy = 0.2f * static_cast<float>(y - mLastMousePos.y);
mRadius += dx - dy;
mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
}
mLastMousePos.x = x;
mLastMousePos.y = y;
}
void LitWavesApp::OnKeyboardInput(const GameTimer& gt)
{
const auto dt = gt.DeltaTime();
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
mSunTheta -= 1.0f * dt;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
mSunTheta += 1.0f * dt;
if (GetAsyncKeyState(VK_UP) & 0x8000)
mSunPhi -= 1.0f * dt;
if (GetAsyncKeyState(VK_DOWN) & 0x8000)
mSunPhi += 1.0f * dt;
mSunPhi = MathHelper::Clamp(mSunPhi, 0.1f, DirectX::XM_PIDIV2);
}
void LitWavesApp::UpdateCamera(const GameTimer& gt)
{
// 将球面坐标转换为笛卡尔坐标
mEyePos.x = mRadius * sinf(mPhi) * cosf(mTheta);
mEyePos.z = mRadius * sinf(mPhi) * sinf(mTheta);
mEyePos.y = mRadius * cosf(mPhi);
// 构建视图矩阵
const auto pos = DirectX::XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
const auto target = DirectX::XMVectorZero();
const auto up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
const auto view = DirectX::XMMatrixLookAtLH(pos, target, up);
XMStoreFloat4x4(&mView, view);
}
void LitWavesApp::UpdateObjectCBs(const GameTimer& gt)
{
auto currObjectCB = mCurrFrameResource->ObjectCB.get();
for (auto& e : mAllRitems)
{
if (e->NumFramesDirty > 0)
{
const auto world = XMLoadFloat4x4(&e->World);
ObjectConstants objConstants;
XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
currObjectCB->CopyData(e->ObjCBIndex, objConstants);
e->NumFramesDirty--;
}
}
}
void LitWavesApp::UpdateMaterialCBs(const GameTimer& gt)
{
auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
for (auto& e : mMaterials)
{
const auto mat = e.second.get();
if (mat->NumFramesDirty > 0)
{
MaterialConstants matConstants;
matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
matConstants.FresnelR0 = mat->FresnelR0;
matConstants.Roughness = mat->Roughness;
currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
mat->NumFramesDirty--;
}
}
}
void LitWavesApp::UpdateMainPassCB(const GameTimer& gt)
{
// 更新投影矩阵
using DirectX::operator-;
const auto view = XMLoadFloat4x4(&mView);
const auto proj = XMLoadFloat4x4(&mProj);
const auto viewProj = XMMatrixMultiply(view, proj);
const auto invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
const auto invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
const auto 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 = DirectX::XMFLOAT2(static_cast<float>(mClientWidth), static_cast<float>(mClientHeight));
mMainPassCB.InvRenderTargetSize = DirectX::XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
mMainPassCB.NearZ = 1.0f;
mMainPassCB.FarZ = 1000.0f;
mMainPassCB.TotalTime = gt.TotalTime();
mMainPassCB.DeltaTime = gt.DeltaTime();
mMainPassCB.AmbientLight = {0.25f, 0.25f, 0.35f, 1.0f};
// 更新光源位置
const auto lightDir = -MathHelper::SphericalToCartesian(1.0f, mSunTheta, mSunPhi);
XMStoreFloat3(&mMainPassCB.Lights[0].Direction, lightDir);
mMainPassCB.Lights[0].Strength = {1.0f, 1.0f, 0.9f};
auto currPassCB = mCurrFrameResource->PassCB.get();
currPassCB->CopyData(0, mMainPassCB);
}
void LitWavesApp::UpdateWaves(const GameTimer& gt) const
{
// 随机生成波浪
static auto tBase = 0.0f;
if (mTimer.TotalTime() - tBase >= 0.25f)
{
tBase += 0.25f;
const auto i = MathHelper::Rand(4, mWaves->RowCount() - 5);
const auto j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
const float r = MathHelper::RandF(0.2f, 0.5f);
mWaves->Disturb(i, j, r);
}
mWaves->Update(gt.DeltaTime());
// 更新波浪的顶点缓冲区
auto currWavesVB = mCurrFrameResource->WavesVB.get();
for (int i = 0; i < mWaves->VertexCount(); ++i)
{
Vertex v{};
v.Pos = mWaves->Position(i);
v.Normal = mWaves->Normal(i);
currWavesVB->CopyData(i, v);
}
mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
}
void LitWavesApp::BuildRootSignature()
{
// 根参数
CD3DX12_ROOT_PARAMETER slotRootParameter[3];
// 创建常量缓冲区视图
for (auto i = 0; i < 3; ++i) slotRootParameter[i].InitAsConstantBufferView(i);
// 创建根签名描述
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(
3,
slotRootParameter,
0,
nullptr,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
// 创建根签名指针
Microsoft::WRL::ComPtr<ID3DBlob> serializedRootSig = nullptr;
// 错误指针
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob = nullptr;
// 序列化根签名
const auto hr = D3D12SerializeRootSignature(
&rootSigDesc,
D3D_ROOT_SIGNATURE_VERSION_1,
serializedRootSig.GetAddressOf(),
errorBlob.GetAddressOf());
// 输出错误
if (errorBlob != nullptr)
{
OutputDebugStringA(static_cast<char*>(errorBlob->GetBufferPointer()));
}
ThrowIfFailed(hr);
//创建根签名
ThrowIfFailed(md3dDevice->CreateRootSignature(
0,
serializedRootSig->GetBufferPointer(),
serializedRootSig->GetBufferSize(),
IID_PPV_ARGS(mRootSignature.GetAddressOf())));
}
void LitWavesApp::BuildShadersAndInputLayout()
{
// 编译顶点着色器和片元着色器
mShaders["standardVS"] = d3dUtil::CompileShader(
L"D:\\Default.hlsl",
nullptr,
"VS",
"vs_5_0");
mShaders["opaquePS"] = d3dUtil::CompileShader(
L"D:\\Default.hlsl",
nullptr,
"PS",
"ps_5_0");
// 定于着色器输入布局
mInputLayout =
{
{
"POSITION",
0,
DXGI_FORMAT_R32G32B32_FLOAT,
0,
0,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0
},
{
"NORMAL",
0,
DXGI_FORMAT_R32G32B32_FLOAT,
0,
12,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0
}
};
}
void LitWavesApp::BuildLandGeometry()
{
// 创建网格
GeometryGenerator geoGen;
auto grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
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);
vertices[i].Normal = GetHillsNormal(p.x, p.z);
}
// 顶点缓冲大小
const UINT vbByteSize = static_cast<UINT>(vertices.size()) * sizeof(Vertex);
// 索引缓冲大小
auto indices = grid.GetIndices16();
const UINT ibByteSize = static_cast<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 = static_cast<UINT>(indices.size());
submesh.StartIndexLocation = 0;
submesh.BaseVertexLocation = 0;
geo->DrawArgs["grid"] = submesh;
mGeometries["landGeo"] = std::move(geo);
}
void LitWavesApp::BuildWavesGeometryBuffers()
{
// 为每个面创建3个索引
std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount());
assert(mWaves->VertexCount() < 0x0000ffff);
// 创建面
const auto m = mWaves->RowCount();
const auto n = mWaves->ColumnCount();
auto k = 0;
for (auto i = 0; i < m - 1; ++i)
{
for (auto 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;
}
}
// 构建动态模型
const UINT vbByteSize = mWaves->VertexCount() * sizeof(Vertex);
const UINT ibByteSize = static_cast<UINT>(indices.size()) * sizeof(std::uint16_t);
auto geo = std::make_unique<MeshGeometry>();
geo->Name = "waterGeo";
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 = static_cast<UINT>(indices.size());
submesh.StartIndexLocation = 0;
submesh.BaseVertexLocation = 0;
geo->DrawArgs["grid"] = submesh;
mGeometries["waterGeo"] = std::move(geo);
}
void LitWavesApp::BuildPSOs()
{
// 创建流水线状态对象描述符
D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
// 输入布局描述
opaquePsoDesc.InputLayout = {mInputLayout.data(), static_cast<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"])));
}
void LitWavesApp::BuildFrameResources()
{
for (auto i = 0; i < NumFrameResources; ++i)
{
mFrameResources.push_back(std::make_unique<FrameResource>(
md3dDevice.Get(),
1,
static_cast<UINT>(mAllRitems.size()),
static_cast<UINT>(mMaterials.size()),
mWaves->VertexCount()));
}
}
void LitWavesApp::BuildMaterials()
{
// 创建草
auto grass = std::make_unique<Material>();
grass->Name = "grass";
grass->MatCBIndex = 0;
grass->DiffuseAlbedo = DirectX::XMFLOAT4(0.2f, 0.6f, 0.2f, 1.0f);
grass->FresnelR0 = DirectX::XMFLOAT3(0.01f, 0.01f, 0.01f);
grass->Roughness = 0.125f;
// 创建简单水
auto water = std::make_unique<Material>();
water->Name = "water";
water->MatCBIndex = 1;
water->DiffuseAlbedo = DirectX::XMFLOAT4(0.0f, 0.2f, 0.6f, 1.0f);
water->FresnelR0 = DirectX::XMFLOAT3(0.1f, 0.1f, 0.1f);
water->Roughness = 0.0f;
mMaterials["grass"] = std::move(grass);
mMaterials["water"] = std::move(water);
}
void LitWavesApp::BuildRenderItems()
{
// 创建水
auto wavesRitem = std::make_unique<RenderItem>();
wavesRitem->World = MathHelper::Identity4x4();
wavesRitem->ObjCBIndex = 0;
wavesRitem->Mat = mMaterials["water"].get();
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[static_cast<int>(RenderLayer::Opaque)].push_back(wavesRitem.get());
// 创建陆地
auto gridRitem = std::make_unique<RenderItem>();
gridRitem->World = MathHelper::Identity4x4();
gridRitem->ObjCBIndex = 1;
gridRitem->Mat = mMaterials["grass"].get();
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[static_cast<int>(RenderLayer::Opaque)].push_back(gridRitem.get());
mAllRitems.push_back(std::move(wavesRitem));
mAllRitems.push_back(std::move(gridRitem));
}
void LitWavesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems) const
{
const auto objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
const auto matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
auto objectCB = mCurrFrameResource->ObjectCB->Resource();
auto matCB = mCurrFrameResource->MaterialCB->Resource();
for (auto ri : ritems)
{
cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
const auto objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex * objCBByteSize;
const auto matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex * matCBByteSize;
cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);
cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
}
}
float LitWavesApp::GetHillsHeight(const float x, const float z)
{
return 0.3f * (z * sinf(0.1f * x) + x * cosf(0.1f * z));
}
DirectX::XMFLOAT3 LitWavesApp::GetHillsNormal(const float x, const float z) const
{
// n = (-df/dx, 1, -df/dz)
DirectX::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));
const auto unitNormal = DirectX::XMVector3Normalize(XMLoadFloat3(&n));
XMStoreFloat3(&n, unitNormal);
return n;
}
//主程序
int WINAPI WinMain(const HINSTANCE hInstance, HINSTANCE, PSTR, int)
{
// 检测内存泄露
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
try
{
LitWavesApp 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;
}
}