This commit is contained in:
Dmitry 2020-05-01 21:50:55 +03:00
parent ca36fcc02e
commit ee5afaab96
112 changed files with 5752 additions and 1241 deletions

BIN
Bin/PAKBuilder.exe Normal file

Binary file not shown.

BIN
Bin/TextureTool.exe Normal file

Binary file not shown.

View file

@ -39,10 +39,8 @@ std::queue<FileEntry> g_fileEntries;
void TraverseDirectory(CWSZ parentDir, CWSZ foundDir, IO::RFile pakFile);
int main(VERUS_MAIN_DEFAULT_ARGS)
void Run()
{
try
{
std::wcout << _T("PACK Builder 1.2.1") << std::endl;
std::wcout << _T("Copyright (c) 2006-2020 Dmitry Maluev") << std::endl;
std::wcout << _T("Arguments: [PAK/folder name] [input directory] [PAK output directory]") << std::endl;
@ -126,13 +124,6 @@ int main(VERUS_MAIN_DEFAULT_ARGS)
pakFile.Close();
if (argCount < 2)
system("pause");
}
catch (const std::exception&)
{
system("pause");
return -1;
}
return 0;
}
INT64 WriteData(CWSZ name, RcString password, IO::RFile pakFile, const BYTE* p, INT64 size)
@ -332,3 +323,17 @@ void TraverseDirectory(CWSZ parentDir, CWSZ foundDir, IO::RFile pakFile)
}
g_depth--;
}
int main(VERUS_MAIN_DEFAULT_ARGS)
{
try
{
Run();
}
catch (const std::exception& e)
{
std::wcerr << _T("EXCEPTION: ") << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View file

@ -1,2 +1,8 @@
# verus
Game Engine
# Release
undef VERUS_RELEASE_DEBUG
UseFullPaths=false
DebugInformationFormat=None
GenerateDebugInformation=false (Link)

View file

@ -48,7 +48,7 @@ void CommandBufferD3D12::End()
throw VERUS_RUNTIME_ERROR << "Close(), hr=" << VERUS_HR(hr);
}
void CommandBufferD3D12::BeginRenderPass(int renderPassHandle, int framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
void CommandBufferD3D12::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
{
VERUS_QREF_RENDERER_D3D12;
@ -99,7 +99,7 @@ void CommandBufferD3D12::EndRenderPass()
if (_vAttachmentStates[index] != attachment._finalState)
{
const auto& resources = _pFramebuffer->_vResources[index];
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState, 0);
}
index++;
if (VERUS_MAX_RT == barrierCount)
@ -157,6 +157,13 @@ void CommandBufferD3D12::BindPipeline(PipelinePtr pipe)
void CommandBufferD3D12::SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth)
{
if (il.size() > 0)
{
const float w = il.begin()->Width();
const float h = il.begin()->Height();
_viewportSize = Vector4(w, h, 1 / w, 1 / h);
}
CD3DX12_VIEWPORT vpD3D12[VERUS_MAX_RT];
int count = 0;
for (const auto& rc : il)
@ -182,7 +189,7 @@ void CommandBufferD3D12::SetBlendConstants(const float* p)
GetD3DGraphicsCommandList()->OMSetBlendFactor(p);
}
bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, int complexSetHandle)
bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
bool copyDescOnly = false;
if (setNumber < 0)
@ -197,7 +204,7 @@ bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, int co
if (shaderD3D12.TryRootConstants(setNumber, *this))
return true;
const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateUniformBuffer(setNumber, complexSetHandle, copyDescOnly);
const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateUniformBuffer(setNumber, complexSetHandle.Get(), copyDescOnly);
if (!hGPU.ptr)
return false;
@ -208,9 +215,9 @@ bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, int co
else
pCmdList->SetGraphicsRootDescriptorTable(rootParameterIndex, hGPU);
if (complexSetHandle >= 0 && !shaderD3D12.IsCompute())
if (complexSetHandle.IsSet() && !shaderD3D12.IsCompute())
{
const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateSamplers(setNumber, complexSetHandle);
const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateSamplers(setNumber, complexSetHandle.Get());
if (hGPU.ptr)
{
const UINT rootParameterIndex = shaderD3D12.GetDescriptorSetCount();
@ -283,7 +290,7 @@ void CommandBufferD3D12::PrepareSubpass()
if (_vAttachmentStates[ref._index] != ref._state)
{
const auto& resources = fs._vResources[resIndex];
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, 0);
_vAttachmentStates[ref._index] = ref._state;
}
resIndex++;
@ -294,7 +301,7 @@ void CommandBufferD3D12::PrepareSubpass()
if (_vAttachmentStates[ref._index] != ref._state)
{
const auto& resources = fs._vResources[resIndex];
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, 0);
_vAttachmentStates[ref._index] = ref._state;
}
resIndex++;
@ -304,7 +311,7 @@ void CommandBufferD3D12::PrepareSubpass()
const auto& ref = subpass._depthStencil;
if (_vAttachmentStates[ref._index] != ref._state)
{
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, 0);
_vAttachmentStates[ref._index] = ref._state;
}
}

View file

@ -23,7 +23,7 @@ namespace verus
virtual void Begin() override;
virtual void End() override;
virtual void BeginRenderPass(int renderPassHandle, int framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void NextSubpass() override;
virtual void EndRenderPass() override;
@ -35,7 +35,7 @@ namespace verus
virtual void SetScissor(std::initializer_list<Vector4> il) override;
virtual void SetBlendConstants(const float* p) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, int complexSetHandle) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range<int> mipLevels, int arrayLayer) override;

View file

@ -20,11 +20,11 @@ void GeometryD3D12::Init(RcGeometryDesc desc)
_dynBindingsMask = desc._dynBindingsMask;
_32BitIndices = desc._32BitIndices;
_vInputElementDesc.reserve(GetInputElementDescCount(desc._pInputElementDesc));
_vInputElementDesc.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
int i = 0;
while (desc._pInputElementDesc[i]._offset >= 0)
while (desc._pVertexInputAttrDesc[i]._offset >= 0)
{
int binding = desc._pInputElementDesc[i]._binding;
int binding = desc._pVertexInputAttrDesc[i]._binding;
D3D12_INPUT_CLASSIFICATION inputClassification = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
UINT instanceDataStepRate = 0;
if (binding < 0)
@ -36,11 +36,11 @@ void GeometryD3D12::Init(RcGeometryDesc desc)
}
D3D12_INPUT_ELEMENT_DESC ieDesc =
{
ToNativeSemanticName(desc._pInputElementDesc[i]._usage),
static_cast<UINT>(desc._pInputElementDesc[i]._usageIndex),
ToNativeFormat(desc._pInputElementDesc[i]._usage, desc._pInputElementDesc[i]._type, desc._pInputElementDesc[i]._components),
ToNativeSemanticName(desc._pVertexInputAttrDesc[i]._usage),
static_cast<UINT>(desc._pVertexInputAttrDesc[i]._usageIndex),
ToNativeFormat(desc._pVertexInputAttrDesc[i]._usage, desc._pVertexInputAttrDesc[i]._type, desc._pVertexInputAttrDesc[i]._components),
static_cast<UINT>(binding),
static_cast<UINT>(desc._pInputElementDesc[i]._offset),
static_cast<UINT>(desc._pVertexInputAttrDesc[i]._offset),
inputClassification,
instanceDataStepRate
};
@ -48,7 +48,7 @@ void GeometryD3D12::Init(RcGeometryDesc desc)
i++;
}
_vStrides.reserve(GetBindingCount(desc._pInputElementDesc));
_vStrides.reserve(GetBindingCount(desc._pVertexInputAttrDesc));
i = 0;
while (desc._pStrides[i] > 0)
{

View file

@ -103,6 +103,8 @@ D3D_PRIMITIVE_TOPOLOGY CGI::ToNativePrimitiveTopology(PrimitiveTopology primitiv
case PrimitiveTopology::lineStrip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
case PrimitiveTopology::triangleList: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
case PrimitiveTopology::triangleStrip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
case PrimitiveTopology::patchList3: return D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST;
case PrimitiveTopology::patchList4: return D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
default: throw VERUS_RECOVERABLE << "ToNativePrimitiveTopology()";
}
}
@ -116,6 +118,8 @@ D3D12_PRIMITIVE_TOPOLOGY_TYPE CGI::ToNativePrimitiveTopologyType(PrimitiveTopolo
case PrimitiveTopology::lineStrip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
case PrimitiveTopology::triangleList: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
case PrimitiveTopology::triangleStrip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
case PrimitiveTopology::patchList3: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
case PrimitiveTopology::patchList4: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
default: throw VERUS_RECOVERABLE << "ToNativePrimitiveTopologyType()";
}
}
@ -141,14 +145,16 @@ CSZ CGI::ToNativeSemanticName(IeUsage usage)
static const CSZ names[] =
{
"POSITION", // IeUsage::position
"BLENDWEIGHT", // IeUsage::blendWeight
"BLENDWEIGHTS", // IeUsage::blendWeights
"BLENDINDICES", // IeUsage::blendIndices
"NORMAL", // IeUsage::normal
"TANGENT", // IeUsage::tangent
"BINORMAL", // IeUsage::binormal
"COLOR", // IeUsage::color
"PSIZE", // IeUsage::psize
"TEXCOORD", // IeUsage::texCoord
"TEXCOORD", // IeUsage::tangent
"TEXCOORD", // IeUsage::binormal
"COLOR" // IeUsage::color
"INSTDATA", // IeUsage::instData
"ATTR" // IeUsage::attr
};
return names[+usage];
}

View file

@ -51,11 +51,12 @@ void PipelineD3D12::Init(RcPipelineDesc desc)
D3D12_GRAPHICS_PIPELINE_STATE_DESC gpsDesc = {};
gpsDesc.pRootSignature = _pRootSignature;
gpsDesc.VS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::vs));
gpsDesc.PS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::fs));
gpsDesc.DS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::ds));
gpsDesc.HS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::hs));
gpsDesc.GS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::gs));
ShaderD3D12::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
gpsDesc.VS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::vs].Get());
gpsDesc.PS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::fs].Get());
gpsDesc.DS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::ds].Get());
gpsDesc.HS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::hs].Get());
gpsDesc.GS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::gs].Get());
gpsDesc.StreamOutput = {};
gpsDesc.BlendState = {};
@ -141,7 +142,7 @@ void PipelineD3D12::Init(RcPipelineDesc desc)
gpsDesc.RasterizerState.SlopeScaledDepthBias = desc._rasterizationState._depthBiasSlopeFactor;
gpsDesc.RasterizerState.DepthClipEnable = desc._rasterizationState._depthClampEnable;
gpsDesc.RasterizerState.MultisampleEnable = FALSE;
gpsDesc.RasterizerState.AntialiasedLineEnable = TRUE;
gpsDesc.RasterizerState.AntialiasedLineEnable = (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA) ? TRUE : FALSE;
gpsDesc.RasterizerState.ForcedSampleCount = 0;
gpsDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
@ -200,7 +201,8 @@ void PipelineD3D12::InitCompute(RcPipelineDesc desc)
D3D12_COMPUTE_PIPELINE_STATE_DESC cpsDesc = {};
cpsDesc.pRootSignature = _pRootSignature;
cpsDesc.CS = ToBytecode(shader.GetD3DBlob(desc._shaderBranch, BaseShader::Stage::cs));
ShaderD3D12::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
cpsDesc.CS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::cs].Get());
cpsDesc.NodeMask = 0;
cpsDesc.CachedPSO = { nullptr, 0 };
cpsDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;

View file

@ -40,13 +40,13 @@ void RendererD3D12::Done()
Renderer::I().ImGuiSetCurrentContext(nullptr);
}
DeleteFramebuffer(-1);
DeleteRenderPass(-1);
DeleteFramebuffer(FBHandle::Make(-2));
DeleteRenderPass(RPHandle::Make(-2));
_vSamplers.clear();
_dhSamplers.Reset();
_dhCbvSrvUav.Reset();
_dhViews.Reset();
if (_hFence != INVALID_HANDLE_VALUE)
{
@ -210,7 +210,7 @@ void RendererD3D12::InitD3D()
_pFence = CreateFence();
_hFence = CreateEvent(nullptr, FALSE, FALSE, nullptr);
_dhCbvSrvUav.Create(_pDevice.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, settings.GetLimits()._d3d12_dhCbvSrvUavCapacity, 16, true);
_dhViews.Create(_pDevice.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, settings.GetLimits()._d3d12_dhViewsCapacity, 16, true);
_dhSamplers.Create(_pDevice.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, settings.GetLimits()._d3d12_dhSamplersCapacity, 0, true);
CreateSamplers();
@ -326,40 +326,40 @@ void RendererD3D12::CreateSamplers()
// <Wrap>
desc = init;
_vSamplers[+Sampler::linear3D] = desc;
_vSamplers[+Sampler::linearMipL] = desc;
desc = init;
desc.Filter = ApplyTrilinearFilter(D3D12_FILTER_MIN_MAG_MIP_POINT);
_vSamplers[+Sampler::nearest3D] = desc;
_vSamplers[+Sampler::nearestMipL] = desc;
desc = init;
desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
_vSamplers[+Sampler::linear2D] = desc;
_vSamplers[+Sampler::linearMipN] = desc;
desc = init;
desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
_vSamplers[+Sampler::nearest2D] = desc;
_vSamplers[+Sampler::nearestMipN] = desc;
// </Wrap>
// <Clamp>
desc = init;
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
_vSamplers[+Sampler::linearClamp3D] = desc;
_vSamplers[+Sampler::linearClampMipL] = desc;
desc = init;
desc.Filter = ApplyTrilinearFilter(D3D12_FILTER_MIN_MAG_MIP_POINT);
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
_vSamplers[+Sampler::nearestClamp3D] = desc;
_vSamplers[+Sampler::nearestClampMipL] = desc;
desc = init;
desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
_vSamplers[+Sampler::linearClamp2D] = desc;
_vSamplers[+Sampler::linearClampMipN] = desc;
desc = init;
desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
_vSamplers[+Sampler::nearestClamp2D] = desc;
_vSamplers[+Sampler::nearestClampMipN] = desc;
// </Clamp>
}
@ -368,7 +368,7 @@ D3D12_STATIC_SAMPLER_DESC RendererD3D12::GetStaticSamplerDesc(Sampler s) const
return _vSamplers[+s];
}
void RendererD3D12::ImGuiInit(int renderPassHandle)
void RendererD3D12::ImGuiInit(RPHandle renderPassHandle)
{
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
@ -392,12 +392,12 @@ void RendererD3D12::ImGuiInit(int renderPassHandle)
ImGui::StyleColorsDark();
ImGui_ImplSDL2_InitForD3D(renderer.GetMainWindow()->GetSDL());
auto hp = _dhCbvSrvUav.GetStaticHandlePair(0);
auto hp = _dhViews.GetStaticHandlePair(0);
ImGui_ImplDX12_Init(
_pDevice.Get(),
s_ringBufferSize,
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
_dhCbvSrvUav.GetD3DDescriptorHeap(),
_dhViews.GetD3DDescriptorHeap(),
hp._hCPU,
hp._hGPU);
}
@ -450,7 +450,7 @@ void RendererD3D12::BeginFrame(bool present)
renderer.GetCommandBuffer()->Begin();
ID3D12DescriptorHeap* ppHeaps[] = { _dhCbvSrvUav.GetD3DDescriptorHeap(), _dhSamplers.GetD3DDescriptorHeap() };
ID3D12DescriptorHeap* ppHeaps[] = { _dhViews.GetD3DDescriptorHeap(), _dhSamplers.GetD3DDescriptorHeap() };
static_cast<CommandBufferD3D12*>(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList()->SetDescriptorHeaps(2, ppHeaps);
}
@ -552,7 +552,7 @@ void RendererD3D12::DeleteTexture(PBaseTexture p)
TStoreTextures::Delete(static_cast<PTextureD3D12>(p));
}
int RendererD3D12::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD)
RPHandle RendererD3D12::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD)
{
RP::D3DRenderPass renderPass;
@ -627,16 +627,16 @@ int RendererD3D12::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, s
renderPass._vSubpasses.push_back(std::move(d3dSubpass));
}
const int handle = GetNextRenderPassHandle();
if (handle >= _vRenderPasses.size())
const int nextIndex = GetNextRenderPassIndex();
if (nextIndex >= _vRenderPasses.size())
_vRenderPasses.push_back(std::move(renderPass));
else
_vRenderPasses[handle] = renderPass;
_vRenderPasses[nextIndex] = renderPass;
return handle;
return RPHandle::Make(nextIndex);
}
int RendererD3D12::CreateFramebuffer(int renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
{
RP::RcD3DRenderPass renderPass = GetRenderPass(renderPassHandle);
RP::D3DFramebuffer framebuffer;
@ -746,32 +746,32 @@ int RendererD3D12::CreateFramebuffer(int renderPassHandle, std::initializer_list
framebuffer._vSubpasses.push_back(std::move(fs));
}
const int handle = GetNextFramebufferHandle();
if (handle >= _vFramebuffers.size())
const int nextIndex = GetNextFramebufferIndex();
if (nextIndex >= _vFramebuffers.size())
_vFramebuffers.push_back(std::move(framebuffer));
else
_vFramebuffers[handle] = framebuffer;
_vFramebuffers[nextIndex] = framebuffer;
return handle;
return FBHandle::Make(nextIndex);
}
void RendererD3D12::DeleteRenderPass(int handle)
void RendererD3D12::DeleteRenderPass(RPHandle handle)
{
if (handle >= 0)
_vRenderPasses[handle] = RP::D3DRenderPass();
else
if (handle.IsSet())
_vRenderPasses[handle.Get()] = RP::D3DRenderPass();
else if (-2 == handle.Get())
_vRenderPasses.clear();
}
void RendererD3D12::DeleteFramebuffer(int handle)
void RendererD3D12::DeleteFramebuffer(FBHandle handle)
{
if (handle >= 0)
_vFramebuffers[handle] = RP::D3DFramebuffer();
else
if (handle.IsSet())
_vFramebuffers[handle.Get()] = RP::D3DFramebuffer();
else if (-2 == handle.Get())
_vFramebuffers.clear();
}
int RendererD3D12::GetNextRenderPassHandle() const
int RendererD3D12::GetNextRenderPassIndex() const
{
const int count = Utils::Cast32(_vRenderPasses.size());
VERUS_FOR(i, count)
@ -782,7 +782,7 @@ int RendererD3D12::GetNextRenderPassHandle() const
return count;
}
int RendererD3D12::GetNextFramebufferHandle() const
int RendererD3D12::GetNextFramebufferIndex() const
{
const int count = Utils::Cast32(_vFramebuffers.size());
VERUS_FOR(i, count)
@ -793,12 +793,12 @@ int RendererD3D12::GetNextFramebufferHandle() const
return count;
}
RP::RcD3DRenderPass RendererD3D12::GetRenderPass(int handle) const
RP::RcD3DRenderPass RendererD3D12::GetRenderPass(RPHandle handle) const
{
return _vRenderPasses[handle];
return _vRenderPasses[handle.Get()];
}
RP::RcD3DFramebuffer RendererD3D12::GetFramebuffer(int handle) const
RP::RcD3DFramebuffer RendererD3D12::GetFramebuffer(FBHandle handle) const
{
return _vFramebuffers[handle];
return _vFramebuffers[handle.Get()];
}

View file

@ -20,7 +20,7 @@ namespace verus
ComPtr<IDXGISwapChain4> _pSwapChain;
Vector<ComPtr<ID3D12Resource>> _vSwapChainBuffers;
DescriptorHeap _dhSwapChainBuffersRTVs;
DynamicDescriptorHeap _dhCbvSrvUav;
DynamicDescriptorHeap _dhViews;
DynamicDescriptorHeap _dhSamplers;
TMapCommandAllocators _mapCommandAllocators[s_ringBufferSize];
ComPtr<ID3D12Fence> _pFence;
@ -64,7 +64,7 @@ namespace verus
ID3D12CommandAllocator* GetD3DCommandAllocator(int ringBufferIndex) const { return _mapCommandAllocators[ringBufferIndex].at(std::this_thread::get_id()).Get(); }
D3D12_STATIC_SAMPLER_DESC GetStaticSamplerDesc(Sampler s) const;
virtual void ImGuiInit(int renderPassHandle) override;
virtual void ImGuiInit(RPHandle renderPassHandle) override;
virtual void ImGuiRenderDrawData() override;
virtual void ResizeSwapChain() override;
@ -91,17 +91,17 @@ namespace verus
virtual void DeleteShader(PBaseShader p) override;
virtual void DeleteTexture(PBaseTexture p) override;
virtual int CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
virtual int CreateFramebuffer(int renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) override;
virtual void DeleteRenderPass(int handle) override;
virtual void DeleteFramebuffer(int handle) override;
int GetNextRenderPassHandle() const;
int GetNextFramebufferHandle() const;
RP::RcD3DRenderPass GetRenderPass(int handle) const;
RP::RcD3DFramebuffer GetFramebuffer(int handle) const;
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) override;
virtual void DeleteRenderPass(RPHandle handle) override;
virtual void DeleteFramebuffer(FBHandle handle) override;
int GetNextRenderPassIndex() const;
int GetNextFramebufferIndex() const;
RP::RcD3DRenderPass GetRenderPass(RPHandle handle) const;
RP::RcD3DFramebuffer GetFramebuffer(FBHandle handle) const;
RDynamicDescriptorHeap GetHeapCbvSrvUav() { return _dhCbvSrvUav; }
RDynamicDescriptorHeap GetHeapSampler() { return _dhSamplers; }
RDynamicDescriptorHeap GetViewHeap() { return _dhViews; }
RDynamicDescriptorHeap GetSamplerHeap() { return _dhSamplers; }
};
VERUS_TYPEDEFS(RendererD3D12);
}

View file

@ -66,12 +66,12 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
while (*branches)
{
String entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages;
String entry, stageEntries[+Stage::count], stages;
Vector<String> vMacroName;
Vector<String> vMacroValue;
const String entry = Parse(*branches, entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
const String branch = Parse(*branches, entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
if (IsInIgnoreList(_C(entry)))
if (IsInIgnoreList(_C(branch)))
{
branches++;
continue;
@ -118,12 +118,13 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
// </System defines>
Compiled compiled;
compiled._entry = entry;
if (strchr(_C(stages), 'V'))
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_VS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryVS), _C("vs_" + version), flags, 0, &compiled._pBlobs[+Stage::vs], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::vs]), _C("vs_" + version), flags, 0, &compiled._pBlobs[+Stage::vs], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
}
@ -131,7 +132,7 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_HS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryHS), _C("hs_" + version), flags, 0, &compiled._pBlobs[+Stage::hs], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::hs]), _C("hs_" + version), flags, 0, &compiled._pBlobs[+Stage::hs], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
}
@ -139,7 +140,7 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_DS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryDS), _C("ds_" + version), flags, 0, &compiled._pBlobs[+Stage::ds], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::ds]), _C("ds_" + version), flags, 0, &compiled._pBlobs[+Stage::ds], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
}
@ -147,7 +148,7 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_GS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryGS), _C("gs_" + version), flags, 0, &compiled._pBlobs[+Stage::gs], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::gs]), _C("gs_" + version), flags, 0, &compiled._pBlobs[+Stage::gs], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
}
@ -155,7 +156,7 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_FS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryFS), _C("ps_" + version), flags, 0, &compiled._pBlobs[+Stage::fs], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::fs]), _C("ps_" + version), flags, 0, &compiled._pBlobs[+Stage::fs], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
}
@ -163,12 +164,12 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex].Name = "_CS";
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(entryCS), _C("cs_" + version), flags, 0, &compiled._pBlobs[+Stage::cs], &pErrorMsgs);
hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::cs]), _C("cs_" + version), flags, 0, &compiled._pBlobs[+Stage::cs], &pErrorMsgs);
CheckErrorMsgs(pErrorMsgs);
_compute = true;
}
_mapCompiled[entry] = compiled;
_mapCompiled[branch] = compiled;
branches++;
}
@ -284,6 +285,16 @@ void ShaderD3D12::CreatePipelineLayout()
stageFlags |= dsd._stageFlags;
if (dsd._capacity > 0)
{
D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL;
switch (dsd._stageFlags)
{
case ShaderStageFlags::vs: visibility = D3D12_SHADER_VISIBILITY_VERTEX; break;
case ShaderStageFlags::hs: visibility = D3D12_SHADER_VISIBILITY_HULL; break;
case ShaderStageFlags::ds: visibility = D3D12_SHADER_VISIBILITY_DOMAIN; break;
case ShaderStageFlags::gs: visibility = D3D12_SHADER_VISIBILITY_GEOMETRY; break;
case ShaderStageFlags::fs: visibility = D3D12_SHADER_VISIBILITY_PIXEL; break;
}
CD3DX12_DESCRIPTOR_RANGE1 descRange;
descRange.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, space);
vDescRanges.push_back(descRange);
@ -313,18 +324,15 @@ void ShaderD3D12::CreatePipelineLayout()
{
Sampler s = dsd._vSamplers[i];
if (Sampler::input == s)
s = Sampler::nearest2D;
s = Sampler::nearestMipN;
D3D12_STATIC_SAMPLER_DESC samplerDesc = pRendererD3D12->GetStaticSamplerDesc(s);
samplerDesc.ShaderRegister = i + 1;
samplerDesc.RegisterSpace = space;
samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
samplerDesc.ShaderVisibility = visibility;
vStaticSamplers.push_back(samplerDesc);
}
}
}
D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL;
if (ShaderStageFlags::fs == dsd._stageFlags)
visibility = D3D12_SHADER_VISIBILITY_PIXEL;
CD3DX12_ROOT_PARAMETER1 rootParam;
rootParam.InitAsDescriptorTable(1 + textureCount, pDescriptorRanges, visibility);
vRootParams.push_back(rootParam);
@ -359,6 +367,8 @@ void ShaderD3D12::CreatePipelineLayout()
rootSignatureFlags |= D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
}
UpdateDebugInfo(vRootParams, vStaticSamplers, rootSignatureFlags);
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init_1_1(
Utils::Cast32(vRootParams.size()), vRootParams.data(),
@ -376,7 +386,7 @@ void ShaderD3D12::CreatePipelineLayout()
throw VERUS_RUNTIME_ERROR << "CreateRootSignature(), hr=" << VERUS_HR(hr);
}
int ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
{
VERUS_QREF_RENDERER_D3D12;
@ -400,7 +410,7 @@ int ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<
RComplexSet complexSet = _vComplexSets[complexSetHandle];
complexSet._vTextures.reserve(il.size());
complexSet._dhSrvUav.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Utils::Cast32(il.size()));
complexSet._dhViews.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Utils::Cast32(il.size()));
if (!dsd._staticSamplersOnly)
complexSet._dhSamplers.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, Utils::Cast32(il.size()));
int index = 0;
@ -412,14 +422,14 @@ int ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<
if (Sampler::storage == dsd._vSamplers[index])
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
complexSet._dhSrvUav.AtCPU(index),
complexSet._dhViews.AtCPU(index),
texD3D12.GetDescriptorHeapUAV().AtCPU(mip),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
complexSet._dhSrvUav.AtCPU(index),
complexSet._dhViews.AtCPU(index),
texD3D12.GetDescriptorHeapSRV().AtCPU(mip),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
if (Sampler::custom == dsd._vSamplers[index])
@ -433,18 +443,18 @@ int ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<
index++;
}
return complexSetHandle;
return CSHandle::Make(complexSetHandle);
}
void ShaderD3D12::FreeDescriptorSet(int& complexSetHandle)
void ShaderD3D12::FreeDescriptorSet(CSHandle& complexSetHandle)
{
if (complexSetHandle >= 0 && complexSetHandle < _vComplexSets.size())
if (complexSetHandle.IsSet() && complexSetHandle.Get() < _vComplexSets.size())
{
_vComplexSets[complexSetHandle]._vTextures.clear();
_vComplexSets[complexSetHandle]._dhSrvUav.Reset();
_vComplexSets[complexSetHandle]._dhSamplers.Reset();
_vComplexSets[complexSetHandle.Get()]._vTextures.clear();
_vComplexSets[complexSetHandle.Get()]._dhViews.Reset();
_vComplexSets[complexSetHandle.Get()]._dhSamplers.Reset();
}
complexSetHandle = -1;
complexSetHandle = CSHandle();
}
void ShaderD3D12::BeginBindDescriptors()
@ -532,7 +542,7 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, in
dsd._index++;
}
auto hpBase = pRendererD3D12->GetHeapCbvSrvUav().GetNextHandlePair();
auto hpBase = pRendererD3D12->GetViewHeap().GetNextHandlePair();
// Copy CBV:
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
@ -545,8 +555,8 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, in
const auto& complexSet = _vComplexSets[complexSetHandle];
const int count = Utils::Cast32(complexSet._vTextures.size());
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(count,
pRendererD3D12->GetHeapCbvSrvUav().GetNextHandlePair(count)._hCPU,
complexSet._dhSrvUav.AtCPU(0),
pRendererD3D12->GetViewHeap().GetNextHandlePair(count)._hCPU,
complexSet._dhViews.AtCPU(0),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
@ -562,15 +572,24 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateSamplers(int setNumber, int com
if (dsd._staticSamplersOnly)
return CD3DX12_GPU_DESCRIPTOR_HANDLE();
CD3DX12_GPU_DESCRIPTOR_HANDLE hOffset = CD3DX12_GPU_DESCRIPTOR_HANDLE();
const auto& complexSet = _vComplexSets[complexSetHandle];
const int count = Utils::Cast32(complexSet._vTextures.size());
auto hpSampler = pRendererD3D12->GetHeapSampler().GetNextHandlePair(count);
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(count,
const int maxCount = Utils::Cast32(complexSet._vTextures.size());
VERUS_FOR(i, maxCount)
{
if (Sampler::custom == dsd._vSamplers[i])
{
auto hpSampler = pRendererD3D12->GetSamplerHeap().GetNextHandlePair(1);
if (!hOffset.ptr)
hOffset = hpSampler._hGPU;
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
hpSampler._hCPU,
complexSet._dhSamplers.AtCPU(0),
complexSet._dhSamplers.AtCPU(i),
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
}
}
return hpSampler._hGPU;
return hOffset;
}
void ShaderD3D12::OnError(CSZ s)
@ -587,3 +606,112 @@ void ShaderD3D12::OnError(CSZ s)
else
renderer.OnShaderWarning(s);
}
void ShaderD3D12::UpdateDebugInfo(
const Vector<CD3DX12_ROOT_PARAMETER1>& vRootParams,
const Vector<D3D12_STATIC_SAMPLER_DESC>& vStaticSamplers,
D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags)
{
StringStream ss;
auto PrintShaderVisibility = [&ss](D3D12_SHADER_VISIBILITY shaderVisibility)
{
switch (shaderVisibility)
{
case D3D12_SHADER_VISIBILITY_ALL: ss << "All"; break;
case D3D12_SHADER_VISIBILITY_VERTEX: ss << "V"; break;
case D3D12_SHADER_VISIBILITY_HULL: ss << "H"; break;
case D3D12_SHADER_VISIBILITY_DOMAIN: ss << "D"; break;
case D3D12_SHADER_VISIBILITY_GEOMETRY: ss << "G"; break;
case D3D12_SHADER_VISIBILITY_PIXEL: ss << "P"; break;
}
};
int totalSize = 0;
int index = 0;
for (const auto& rootParam : vRootParams)
{
ss << "Index=" << index;
ss << ", Type=";
switch (rootParam.ParameterType)
{
case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: ss << "Table"; totalSize += 4; break;
case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: ss << "Const"; totalSize += 4 * rootParam.Constants.Num32BitValues; break;
case D3D12_ROOT_PARAMETER_TYPE_CBV: ss << "CBV"; totalSize += 8; break;
case D3D12_ROOT_PARAMETER_TYPE_SRV: ss << "SRV"; totalSize += 8; break;
case D3D12_ROOT_PARAMETER_TYPE_UAV: ss << "UAV"; totalSize += 8; break;
}
ss << ", Visibility=";
PrintShaderVisibility(rootParam.ShaderVisibility);
if (totalSize > 64)
ss << " (spilled)";
ss << std::endl;
switch (rootParam.ParameterType)
{
case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
{
VERUS_FOR(i, rootParam.DescriptorTable.NumDescriptorRanges)
{
auto& descRange = rootParam.DescriptorTable.pDescriptorRanges[i];
ss << " Type=";
switch (descRange.RangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: ss << "SRV"; break;
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: ss << "UAV"; break;
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: ss << "CBV"; break;
case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: ss << "Sampler"; break;
}
ss << ", Count=" << descRange.NumDescriptors;
ss << ", Register=" << descRange.BaseShaderRegister;
ss << ", Space=" << descRange.RegisterSpace;
ss << ", Flags=" << descRange.Flags;
ss << ", Offset=" << static_cast<int>(descRange.OffsetInDescriptorsFromTableStart);
ss << std::endl;
}
}
break;
case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
{
ss << " ";
ss << "Register=" << rootParam.Constants.ShaderRegister;
ss << ", Space=" << rootParam.Constants.RegisterSpace;
ss << ", Count=" << rootParam.Constants.Num32BitValues << "x4 bytes";
ss << std::endl;
}
break;
default:
{
}
break;
}
index++;
}
for (const auto& sampler : vStaticSamplers)
{
ss << "StaticSampler Register=" << sampler.ShaderRegister;
ss << ", Space=" << sampler.RegisterSpace;
ss << ", Visibility=";
PrintShaderVisibility(sampler.ShaderVisibility);
ss << std::endl;
}
ss << "TotalSize=" << totalSize << " bytes (256 max)";
ss << ", Flags=";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)
ss << "[AIAIL]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS)
ss << "[DVSRA]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS)
ss << "[DHSRA]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS)
ss << "[DDSRA]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS)
ss << "[DGSRA]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS)
ss << "[DPSRA]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT)
ss << "[ASO]";
if (rootSignatureFlags & D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE)
ss << "[LRS]";
_debugInfo = ss.str();
}

View file

@ -19,11 +19,16 @@ namespace verus
class ShaderD3D12 : public BaseShader
{
public:
struct Compiled
{
ComPtr<ID3DBlob> _pBlobs[+Stage::count];
String _entry;
int _stageCount = 0;
};
VERUS_TYPEDEFS(Compiled);
private:
typedef Map<String, Compiled> TMapCompiled;
struct DescriptorSetDesc
@ -48,7 +53,7 @@ namespace verus
struct ComplexSet
{
Vector<TexturePtr> _vTextures;
DescriptorHeap _dhSrvUav;
DescriptorHeap _dhViews;
DescriptorHeap _dhSamplers;
};
VERUS_TYPEDEFS(ComplexSet);
@ -57,6 +62,7 @@ namespace verus
Vector<DescriptorSetDesc> _vDescriptorSetDesc;
Vector<ComplexSet> _vComplexSets;
ComPtr<ID3D12RootSignature> _pRootSignature;
String _debugInfo;
UINT64 _currentFrame = UINT64_MAX;
bool _compute = false;
@ -69,8 +75,8 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
virtual void CreatePipelineLayout() override;
virtual int BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual void FreeDescriptorSet(int& complexSetHandle) override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
virtual void BeginBindDescriptors() override;
virtual void EndBindDescriptors() override;
@ -79,8 +85,7 @@ namespace verus
// D3D12
//
ID3DBlob* GetD3DBlob(CSZ branch, Stage stage) const { return _mapCompiled.at(branch)._pBlobs[+stage].Get(); }
int GetStageCount(CSZ branch) const { return _mapCompiled.at(branch)._stageCount; }
RcCompiled GetCompiled(CSZ branch) const { return _mapCompiled.at(branch); }
ID3D12RootSignature* GetD3DRootSignature() const { return _pRootSignature.Get(); }
@ -92,6 +97,11 @@ namespace verus
bool IsCompute() const { return _compute; }
void OnError(CSZ s);
void UpdateDebugInfo(
const Vector<CD3DX12_ROOT_PARAMETER1>& vRootParams,
const Vector<D3D12_STATIC_SAMPLER_DESC>& vStaticSamplers,
D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags);
};
VERUS_TYPEDEFS(ShaderD3D12);
}

View file

@ -29,7 +29,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
const bool depthFormat = IsDepthFormat(desc._format);
const bool depthSampled = _desc._flags & TextureDesc::Flags::depthSampled;
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
@ -50,17 +50,13 @@ void TextureD3D12::Init(RcTextureDesc desc)
D3D12_RESOURCE_STATES initialResourceState = ToNativeImageLayout(_mainLayout);
D3D12_CLEAR_VALUE clearValue = {};
clearValue.Format = ToNativeFormat(_desc._format, false);
if (renderTarget)
{
initialResourceState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
memcpy(clearValue.Color, _desc._clearValue.ToPointer(), sizeof(clearValue.Color));
}
if (depthFormat)
{
initialResourceState = D3D12_RESOURCE_STATE_DEPTH_WRITE;
clearValue.DepthStencil.Depth = _desc._clearValue.getX();
clearValue.DepthStencil.Stencil = static_cast<UINT8>(_desc._clearValue.getY());
if (depthSampled)
if (_desc._flags & TextureDesc::Flags::depthSampledR)
initialResourceState = D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
}
D3D12MA::ALLOCATION_DESC allocDesc = {};
@ -83,6 +79,12 @@ void TextureD3D12::Init(RcTextureDesc desc)
resDescUAV.Height = Math::Max(1, _desc._height >> 1);
resDescUAV.MipLevels = uavMipLevels;
resDescUAV.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
// sRGB cannot be used with UAV:
switch (resDescUAV.Format)
{
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: resDescUAV.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: resDescUAV.Format = DXGI_FORMAT_B8G8R8A8_UNORM; break;
}
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
@ -91,18 +93,18 @@ void TextureD3D12::Init(RcTextureDesc desc)
&resDescUAV,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
nullptr,
&_uavResource._pMaAllocation,
IID_PPV_ARGS(&_uavResource._pResource))))
&_uaResource._pMaAllocation,
IID_PPV_ARGS(&_uaResource._pResource))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT), hr=" << VERUS_HR(hr);
_dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels);
VERUS_FOR(i, uavMipLevels)
{
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = resDesc.Format;
uavDesc.Format = resDescUAV.Format;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
uavDesc.Texture2D.MipSlice = i;
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uavResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(i));
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(i));
}
}
@ -152,9 +154,9 @@ void TextureD3D12::Done()
_dhDSV.Reset();
_dhRTV.Reset();
_dhSRV.Reset();
VERUS_SMART_RELEASE(_uavResource._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_uavResource._pResource.Get());
_uavResource._pResource.Reset();
VERUS_SMART_RELEASE(_uaResource._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_uaResource._pResource.Get());
_uaResource._pResource.Reset();
VERUS_SMART_RELEASE(_resource._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_resource._pResource.Get());
_resource._pResource.Reset();
@ -258,7 +260,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
ub._srcMipLevel = srcMip;
ub._mipLevelCount = dispatchMipCount;
ub._srcDimensionCase = (srcHeight & 1) << 1 | (srcWidth & 1);
ub._srgb = false;
ub._srgb = IsSRGBFormat(_desc._format);
ub._texelSize.x = 1.f / dstWidth;
ub._texelSize.y = 1.f / dstHeight;
@ -267,7 +269,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
int mips[5] = {}; // For input texture (always mip 0) and 4 UAV mips.
VERUS_FOR(mip, dispatchMipCount)
mips[mip + 1] = srcMip + mip;
const int complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
}
@ -278,7 +280,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
auto rb = CD3DX12_RESOURCE_BARRIER::UAV(_uavResource._pResource.Get());
auto rb = CD3DX12_RESOURCE_BARRIER::UAV(_uaResource._pResource.Get());
pCmdList->ResourceBarrier(1, &rb);
// Transition state for upcoming CopyTextureRegion():
@ -288,7 +290,8 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
VERUS_FOR(mip, dispatchMipCount)
{
const int subUAV = srcMip + mip;
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uavResource._pResource.Get(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
@ -301,7 +304,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
pCmdList->CopyTextureRegion(
&CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subSRV),
0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(_uavResource._pResource.Get(), subUAV),
&CD3DX12_TEXTURE_COPY_LOCATION(_uaResource._pResource.Get(), subUAV),
nullptr);
}
// Transition state for next Dispatch():
@ -311,7 +314,8 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
VERUS_FOR(mip, dispatchMipCount)
{
const int subUAV = srcMip + mip;
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uavResource._pResource.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, subUAV);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
@ -348,7 +352,7 @@ Continue TextureD3D12::Scheduled_Update()
{
VERUS_QREF_RENDERER;
auto shader = renderer.GetShaderGenerateMips();
for (int csh : _vCshGenerateMips)
for (auto& csh : _vCshGenerateMips)
shader->FreeDescriptorSet(csh);
_vCshGenerateMips.clear();
}

View file

@ -13,9 +13,9 @@ namespace verus
};
ResourceEx _resource;
ResourceEx _uavResource;
ResourceEx _uaResource;
Vector<ResourceEx> _vStagingBuffers;
Vector<int> _vCshGenerateMips;
Vector<CSHandle> _vCshGenerateMips;
DescriptorHeap _dhSRV;
DescriptorHeap _dhUAV;
DescriptorHeap _dhRTV;

View file

@ -44,7 +44,7 @@ void CommandBufferVulkan::End()
throw VERUS_RUNTIME_ERROR << "vkEndCommandBuffer(), res=" << res;
}
void CommandBufferVulkan::BeginRenderPass(int renderPassHandle, int framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
void CommandBufferVulkan::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
{
VERUS_QREF_RENDERER_VULKAN;
VERUS_QREF_CONST_SETTINGS;
@ -120,6 +120,13 @@ void CommandBufferVulkan::BindPipeline(PipelinePtr pipe)
void CommandBufferVulkan::SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth)
{
if (il.size() > 0)
{
const float w = il.begin()->Width();
const float h = il.begin()->Height();
_viewportSize = Vector4(w, h, 1 / w, 1 / h);
}
VkViewport vpVulkan[VERUS_MAX_RT];
int count = 0;
for (const auto& rc : il)
@ -155,7 +162,7 @@ void CommandBufferVulkan::SetBlendConstants(const float* p)
vkCmdSetBlendConstants(GetVkCommandBuffer(), p);
}
bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, int complexSetHandle)
bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
if (setNumber < 0)
return true;
@ -167,7 +174,7 @@ bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, int c
if (offset < 0)
return false;
const VkDescriptorSet descriptorSet = (complexSetHandle >= 0) ?
const VkDescriptorSet descriptorSet = complexSetHandle.IsSet() ?
shaderVulkan.GetComplexVkDescriptorSet(complexSetHandle) : shaderVulkan.GetVkDescriptorSet(setNumber);
const uint32_t dynamicOffset = offset;
const uint32_t dynamicOffsetCount = 1;

View file

@ -19,7 +19,7 @@ namespace verus
virtual void Begin() override;
virtual void End() override;
virtual void BeginRenderPass(int renderPassHandle, int framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void NextSubpass() override;
virtual void EndRenderPass() override;
@ -31,7 +31,7 @@ namespace verus
virtual void SetScissor(std::initializer_list<Vector4> il) override;
virtual void SetBlendConstants(const float* p) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, int complexSetHandle) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range<int> mipLevels, int arrayLayer) override;

View file

@ -19,13 +19,13 @@ void GeometryVulkan::Init(RcGeometryDesc desc)
_dynBindingsMask = desc._dynBindingsMask;
_32BitIndices = desc._32BitIndices;
const int bindingCount = GetBindingCount(desc._pInputElementDesc);
const int bindingCount = GetBindingCount(desc._pVertexInputAttrDesc);
_vVertexInputBindingDesc.reserve(bindingCount);
_vVertexInputAttributeDesc.reserve(GetInputElementDescCount(desc._pInputElementDesc));
_vVertexInputAttributeDesc.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
int i = 0;
while (desc._pInputElementDesc[i]._offset >= 0)
while (desc._pVertexInputAttrDesc[i]._offset >= 0)
{
int binding = desc._pInputElementDesc[i]._binding;
int binding = desc._pVertexInputAttrDesc[i]._binding;
VkVertexInputRate inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
if (binding < 0)
{
@ -53,10 +53,10 @@ void GeometryVulkan::Init(RcGeometryDesc desc)
}
VkVertexInputAttributeDescription vkviad = {};
vkviad.location = ToNativeLocation(desc._pInputElementDesc[i]._usage, desc._pInputElementDesc[i]._usageIndex);
vkviad.location = ToNativeLocation(desc._pVertexInputAttrDesc[i]._usage, desc._pVertexInputAttrDesc[i]._usageIndex);
vkviad.binding = binding;
vkviad.format = ToNativeFormat(desc._pInputElementDesc[i]._usage, desc._pInputElementDesc[i]._type, desc._pInputElementDesc[i]._components);
vkviad.offset = desc._pInputElementDesc[i]._offset;
vkviad.format = ToNativeFormat(desc._pVertexInputAttrDesc[i]._usage, desc._pVertexInputAttrDesc[i]._type, desc._pVertexInputAttrDesc[i]._components);
vkviad.offset = desc._pVertexInputAttrDesc[i]._offset;
_vVertexInputAttributeDesc.push_back(vkviad);
i++;
}

View file

@ -90,6 +90,8 @@ VkPrimitiveTopology CGI::ToNativePrimitiveTopology(PrimitiveTopology primitiveTo
case PrimitiveTopology::lineStrip: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
case PrimitiveTopology::triangleList: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case PrimitiveTopology::triangleStrip: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case PrimitiveTopology::patchList3: return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
case PrimitiveTopology::patchList4: return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
default: throw VERUS_RECOVERABLE << "ToNativePrimitiveTopology()";
}
}
@ -148,14 +150,16 @@ int CGI::ToNativeLocation(IeUsage usage, int usageIndex)
switch (usage)
{
case IeUsage::position: return 0;
case IeUsage::blendWeight: return 1;
case IeUsage::blendWeights: return 1;
case IeUsage::blendIndices: return 6;
case IeUsage::normal: return 2;
case IeUsage::psize: return 7;
case IeUsage::texCoord: return 8 + usageIndex;
case IeUsage::tangent: return 14;
case IeUsage::binormal: return 15;
case IeUsage::color: return 3 + usageIndex;
case IeUsage::psize: return 7;
case IeUsage::texCoord: return 8 + usageIndex;
case IeUsage::instData: return 16 + usageIndex;
case IeUsage::attr: return usageIndex;
default: throw VERUS_RECOVERABLE << "ToNativeLocation()";
}
}

View file

@ -38,27 +38,31 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
attachmentCount++;
}
const bool tess = desc._topology >= PrimitiveTopology::patchList3 && desc._topology <= PrimitiveTopology::patchList4;
ShaderVulkan::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
Vector<String> entryNames(+BaseShader::Stage::count);
Vector<VkPipelineShaderStageCreateInfo> vShaderStages;
vShaderStages.reserve(shader.GetStageCount(desc._shaderBranch));
auto PushShaderStage = [&vShaderStages, &shader, &desc](CSZ name, BaseShader::Stage stage, VkShaderStageFlagBits shaderStageFlagBits)
vShaderStages.reserve(compiled._stageCount);
auto PushShaderStage = [&vShaderStages, &compiled, &entryNames](CSZ suffix, BaseShader::Stage stage, VkShaderStageFlagBits shaderStageFlagBits)
{
const VkShaderModule shaderModule = shader.GetVkShaderModule(desc._shaderBranch, stage);
const VkShaderModule shaderModule = compiled._shaderModules[+stage];
entryNames[+stage] = compiled._entry + suffix;
if (shaderModule != VK_NULL_HANDLE)
{
VkPipelineShaderStageCreateInfo vkpssci = {};
vkpssci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vkpssci.stage = shaderStageFlagBits;
vkpssci.module = shaderModule;
vkpssci.pName = name;
vkpssci.pName = _C(entryNames[+stage]);
vShaderStages.push_back(vkpssci);
}
};
PushShaderStage("mainVS", BaseShader::Stage::vs, VK_SHADER_STAGE_VERTEX_BIT);
PushShaderStage("mainHS", BaseShader::Stage::hs, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
PushShaderStage("mainDS", BaseShader::Stage::ds, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
PushShaderStage("mainGS", BaseShader::Stage::gs, VK_SHADER_STAGE_GEOMETRY_BIT);
PushShaderStage("mainFS", BaseShader::Stage::fs, VK_SHADER_STAGE_FRAGMENT_BIT);
PushShaderStage("VS", BaseShader::Stage::vs, VK_SHADER_STAGE_VERTEX_BIT);
PushShaderStage("HS", BaseShader::Stage::hs, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
PushShaderStage("DS", BaseShader::Stage::ds, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
PushShaderStage("GS", BaseShader::Stage::gs, VK_SHADER_STAGE_GEOMETRY_BIT);
PushShaderStage("FS", BaseShader::Stage::fs, VK_SHADER_STAGE_FRAGMENT_BIT);
Vector<VkVertexInputBindingDescription> vVertexInputBindingDesc;
Vector<VkVertexInputAttributeDescription> vVertexInputAttributeDesc;
@ -70,6 +74,14 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
inputAssemblyState.topology = ToNativePrimitiveTopology(desc._topology);
inputAssemblyState.primitiveRestartEnable = desc._primitiveRestartEnable;
VkPipelineTessellationStateCreateInfo tessellationState = {};
tessellationState.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
tessellationState.patchControlPoints = 3;
switch (desc._topology)
{
case PrimitiveTopology::patchList4: tessellationState.patchControlPoints = 4; break;
}
VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = desc._multiViewport;
@ -77,6 +89,8 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = {};
rasterizationLineState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
if (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA)
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
VkPipelineRasterizationStateCreateInfo rasterizationState = {};
rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
@ -94,7 +108,6 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
VkPipelineMultisampleStateCreateInfo multisampleState = {};
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleState.sampleShadingEnable = VK_FALSE;
multisampleState.rasterizationSamples = ToNativeSampleCount(desc._sampleCount);
VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
@ -196,6 +209,7 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
vkgpci.pStages = vShaderStages.data();
vkgpci.pVertexInputState = &vertexInputState;
vkgpci.pInputAssemblyState = &inputAssemblyState;
vkgpci.pTessellationState = tess ? &tessellationState : nullptr;
vkgpci.pViewportState = &viewportState;
vkgpci.pRasterizationState = &rasterizationState;
vkgpci.pMultisampleState = &multisampleState;
@ -225,14 +239,17 @@ void PipelineVulkan::InitCompute(RcPipelineDesc desc)
VkResult res = VK_SUCCESS;
RcShaderVulkan shader = static_cast<RcShaderVulkan>(*desc._shader);
const VkShaderModule shaderModule = shader.GetVkShaderModule(desc._shaderBranch, BaseShader::Stage::cs);
ShaderVulkan::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
const VkShaderModule shaderModule = compiled._shaderModules[+BaseShader::Stage::cs];
String entryName = compiled._entry + "CS";
VkComputePipelineCreateInfo vkcpci = {};
vkcpci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
vkcpci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vkcpci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
vkcpci.stage.module = shaderModule;
vkcpci.stage.pName = "mainCS";
vkcpci.stage.pName = _C(entryName);
vkcpci.layout = shader.GetVkPipelineLayout();
if (VK_SUCCESS != (res = vkCreateComputePipelines(pRendererVulkan->GetVkDevice(), VK_NULL_HANDLE, 1, &vkcpci, pRendererVulkan->GetAllocator(), &_pipeline)))
throw VERUS_RUNTIME_ERROR << "vkCreateComputePipelines(), res=" << res;

View file

@ -100,8 +100,8 @@ void RendererVulkan::Done()
Renderer::I().ImGuiSetCurrentContext(nullptr);
}
DeleteFramebuffer(-1);
DeleteRenderPass(-1);
DeleteFramebuffer(FBHandle::Make(-2));
DeleteRenderPass(RPHandle::Make(-2));
for (auto sampler : _vSamplers)
VERUS_VULKAN_DESTROY(sampler, vkDestroySampler(_device, sampler, GetAllocator()));
@ -189,6 +189,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL RendererVulkan::DebugUtilsMessengerCallback(
severity = D::Log::Severity::warning;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
severity = D::Log::Severity::error;
if (!strstr(pCallbackData->pMessage, "ptr to input arr[1] of struct of"))
D::Log::I().Write(pCallbackData->pMessage, std::this_thread::get_id(), __FILE__, __LINE__, severity);
return VK_FALSE;
}
@ -394,10 +395,12 @@ void RendererVulkan::PickPhysicalDevice()
void RendererVulkan::CreateDevice()
{
VERUS_QREF_CONST_SETTINGS;
VkResult res = VK_SUCCESS;
VkPhysicalDeviceLineRasterizationFeaturesEXT lineRasterizationFeatures = {};
lineRasterizationFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
lineRasterizationFeatures.bresenhamLines = VK_TRUE;
lineRasterizationFeatures.smoothLines = VK_TRUE;
_queueFamilyIndices = FindQueueFamilyIndices(_physicalDevice);
@ -416,6 +419,8 @@ void RendererVulkan::CreateDevice()
vDeviceQueueCreateInfos.push_back(vkdqci);
}
VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
physicalDeviceFeatures.geometryShader = VK_TRUE;
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE;
physicalDeviceFeatures.fillModeNonSolid = VK_TRUE;
physicalDeviceFeatures.multiViewport = VK_TRUE;
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE;
@ -624,46 +629,46 @@ void RendererVulkan::CreateSamplers()
// <Repeat>
vksci = init;
_vSamplers[+Sampler::linear3D] = Create(vksci);
_vSamplers[+Sampler::linearMipL] = Create(vksci);
vksci = init;
vksci.magFilter = VK_FILTER_NEAREST;
vksci.minFilter = VK_FILTER_NEAREST;
_vSamplers[+Sampler::nearest3D] = Create(vksci);
_vSamplers[+Sampler::nearestMipL] = Create(vksci);
vksci = init;
vksci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
_vSamplers[+Sampler::linear2D] = Create(vksci);
_vSamplers[+Sampler::linearMipN] = Create(vksci);
vksci = init;
vksci.magFilter = VK_FILTER_NEAREST;
vksci.minFilter = VK_FILTER_NEAREST;
vksci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
_vSamplers[+Sampler::nearest2D] = Create(vksci);
_vSamplers[+Sampler::nearestMipN] = Create(vksci);
// </Repeat>
// <Clamp>
vksci = init;
vksci.addressModeU = vksci.addressModeV = vksci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
_vSamplers[+Sampler::linearClamp3D] = Create(vksci);
_vSamplers[+Sampler::linearClampMipL] = Create(vksci);
vksci = init;
vksci.magFilter = VK_FILTER_NEAREST;
vksci.minFilter = VK_FILTER_NEAREST;
vksci.addressModeU = vksci.addressModeV = vksci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
_vSamplers[+Sampler::nearestClamp3D] = Create(vksci);
_vSamplers[+Sampler::nearestClampMipL] = Create(vksci);
vksci = init;
vksci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
vksci.addressModeU = vksci.addressModeV = vksci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
_vSamplers[+Sampler::linearClamp2D] = Create(vksci);
_vSamplers[+Sampler::linearClampMipN] = Create(vksci);
vksci = init;
vksci.magFilter = VK_FILTER_NEAREST;
vksci.minFilter = VK_FILTER_NEAREST;
vksci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
vksci.addressModeU = vksci.addressModeV = vksci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
_vSamplers[+Sampler::nearestClamp2D] = Create(vksci);
_vSamplers[+Sampler::nearestClampMipN] = Create(vksci);
// </Clamp>
}
@ -692,7 +697,7 @@ void RendererVulkan::ImGuiCheckVkResultFn(VkResult res)
throw VERUS_RUNTIME_ERROR << "ImGuiCheckVkResultFn(), res=" << res;
}
void RendererVulkan::ImGuiInit(int renderPassHandle)
void RendererVulkan::ImGuiInit(RPHandle renderPassHandle)
{
VkResult res = VK_SUCCESS;
VkDescriptorPoolSize vkdps = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
@ -720,7 +725,7 @@ void RendererVulkan::ImGuiInit(int renderPassHandle)
IO::FileSystem::LoadResource(_C(settings._imguiFont), vData);
void* pFontData = IM_ALLOC(vData.size());
memcpy(pFontData, vData.data(), vData.size());
io.Fonts->AddFontFromMemoryTTF(pFontData, Utils::Cast32(vData.size()), settings.GetFontSize(), nullptr, io.Fonts->GetGlyphRangesCyrillic());
io.Fonts->AddFontFromMemoryTTF(pFontData, Utils::Cast32(vData.size()), static_cast<float>(settings.GetFontSize()), nullptr, io.Fonts->GetGlyphRangesCyrillic());
}
ImGui::StyleColorsDark();
@ -738,7 +743,7 @@ void RendererVulkan::ImGuiInit(int renderPassHandle)
info.MinImageCount = settings._screenVSync ? 3 : 2;;
info.ImageCount = s_ringBufferSize;
info.CheckVkResultFn = ImGuiCheckVkResultFn;
ImGui_ImplVulkan_Init(&info, _vRenderPasses[renderPassHandle]);
ImGui_ImplVulkan_Init(&info, _vRenderPasses[renderPassHandle.Get()]);
CommandBufferVulkan commandBuffer;
commandBuffer.InitOneTimeSubmit();
@ -912,7 +917,7 @@ void RendererVulkan::DeleteTexture(PBaseTexture p)
TStoreTextures::Delete(static_cast<PTextureVulkan>(p));
}
int RendererVulkan::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD)
RPHandle RendererVulkan::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD)
{
VkResult res = VK_SUCCESS;
@ -1111,16 +1116,16 @@ int RendererVulkan::CreateRenderPass(std::initializer_list<RP::Attachment> ilA,
if (VK_SUCCESS != (res = vkCreateRenderPass(_device, &vkrpci, GetAllocator(), &renderPass)))
throw VERUS_RUNTIME_ERROR << "vkCreateRenderPass(), res=" << res;
const int handle = GetNextRenderPassHandle();
if (handle >= _vRenderPasses.size())
const int nextIndex = GetNextRenderPassIndex();
if (nextIndex >= _vRenderPasses.size())
_vRenderPasses.push_back(renderPass);
else
_vRenderPasses[handle] = renderPass;
_vRenderPasses[nextIndex] = renderPass;
return handle;
return RPHandle::Make(nextIndex);
}
int RendererVulkan::CreateFramebuffer(int renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
FBHandle RendererVulkan::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
{
VkResult res = VK_SUCCESS;
@ -1138,7 +1143,7 @@ int RendererVulkan::CreateFramebuffer(int renderPassHandle, std::initializer_lis
for (const auto& x : il)
{
auto& texVulkan = static_cast<RTextureVulkan>(*x);
imageViews[count] = texVulkan.GetVkImageView();
imageViews[count] = texVulkan.GetVkImageViewForFramebuffer();
count++;
}
vkfci.attachmentCount = count;
@ -1149,27 +1154,27 @@ int RendererVulkan::CreateFramebuffer(int renderPassHandle, std::initializer_lis
if (VK_SUCCESS != (res = vkCreateFramebuffer(_device, &vkfci, GetAllocator(), &framebuffer)))
throw VERUS_RUNTIME_ERROR << "vkCreateFramebuffer(), res=" << res;
const int handle = GetNextFramebufferHandle();
const int nextIndex = GetNextFramebufferIndex();
Framebuffer fb;
fb._framebuffer = framebuffer;
fb._width = w;
fb._height = h;
if (handle >= _vFramebuffers.size())
if (nextIndex >= _vFramebuffers.size())
_vFramebuffers.push_back(fb);
else
_vFramebuffers[handle] = fb;
_vFramebuffers[nextIndex] = fb;
return handle;
return FBHandle::Make(nextIndex);
}
void RendererVulkan::DeleteRenderPass(int handle)
void RendererVulkan::DeleteRenderPass(RPHandle handle)
{
if (handle >= 0)
if (handle.IsSet())
{
vkDestroyRenderPass(_device, _vRenderPasses[handle], GetAllocator());
_vRenderPasses[handle] = VK_NULL_HANDLE;
vkDestroyRenderPass(_device, _vRenderPasses[handle.Get()], GetAllocator());
_vRenderPasses[handle.Get()] = VK_NULL_HANDLE;
}
else
else if (-2 == handle.Get())
{
for (auto renderPass : _vRenderPasses)
vkDestroyRenderPass(_device, renderPass, GetAllocator());
@ -1177,14 +1182,14 @@ void RendererVulkan::DeleteRenderPass(int handle)
}
}
void RendererVulkan::DeleteFramebuffer(int handle)
void RendererVulkan::DeleteFramebuffer(FBHandle handle)
{
if (handle >= 0)
if (handle.IsSet())
{
vkDestroyFramebuffer(_device, _vFramebuffers[handle]._framebuffer, GetAllocator());
_vFramebuffers[handle]._framebuffer = VK_NULL_HANDLE;
vkDestroyFramebuffer(_device, _vFramebuffers[handle.Get()]._framebuffer, GetAllocator());
_vFramebuffers[handle.Get()]._framebuffer = VK_NULL_HANDLE;
}
else
else if (-2 == handle.Get())
{
for (auto framebuffer : _vFramebuffers)
vkDestroyFramebuffer(_device, framebuffer._framebuffer, GetAllocator());
@ -1192,7 +1197,7 @@ void RendererVulkan::DeleteFramebuffer(int handle)
}
}
int RendererVulkan::GetNextRenderPassHandle() const
int RendererVulkan::GetNextRenderPassIndex() const
{
const int count = Utils::Cast32(_vRenderPasses.size());
VERUS_FOR(i, count)
@ -1203,7 +1208,7 @@ int RendererVulkan::GetNextRenderPassHandle() const
return count;
}
int RendererVulkan::GetNextFramebufferHandle() const
int RendererVulkan::GetNextFramebufferIndex() const
{
const int count = Utils::Cast32(_vFramebuffers.size());
VERUS_FOR(i, count)
@ -1214,14 +1219,14 @@ int RendererVulkan::GetNextFramebufferHandle() const
return count;
}
VkRenderPass RendererVulkan::GetRenderPass(int handle) const
VkRenderPass RendererVulkan::GetRenderPass(RPHandle handle) const
{
return _vRenderPasses[handle];
return _vRenderPasses[handle.Get()];
}
RendererVulkan::RcFramebuffer RendererVulkan::GetFramebuffer(int handle) const
RendererVulkan::RcFramebuffer RendererVulkan::GetFramebuffer(FBHandle handle) const
{
return _vFramebuffers[handle];
return _vFramebuffers[handle.Get()];
}
void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation)

View file

@ -127,7 +127,7 @@ namespace verus
const VkSampler* GetImmutableSampler(Sampler s) const;
static void ImGuiCheckVkResultFn(VkResult res);
virtual void ImGuiInit(int renderPassHandle) override;
virtual void ImGuiInit(RPHandle renderPassHandle) override;
virtual void ImGuiRenderDrawData() override;
virtual void ResizeSwapChain() override;
@ -154,14 +154,14 @@ namespace verus
virtual void DeleteShader(PBaseShader p) override;
virtual void DeleteTexture(PBaseTexture p) override;
virtual int CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
virtual int CreateFramebuffer(int renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex) override;
virtual void DeleteRenderPass(int handle) override;
virtual void DeleteFramebuffer(int handle) override;
int GetNextRenderPassHandle() const;
int GetNextFramebufferHandle() const;
VkRenderPass GetRenderPass(int handle) const;
RcFramebuffer GetFramebuffer(int handle) const;
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex) override;
virtual void DeleteRenderPass(RPHandle handle) override;
virtual void DeleteFramebuffer(FBHandle handle) override;
int GetNextRenderPassIndex() const;
int GetNextFramebufferIndex() const;
VkRenderPass GetRenderPass(RPHandle handle) const;
RcFramebuffer GetFramebuffer(FBHandle handle) const;
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation);
void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, PBaseCommandBuffer pCB = nullptr);

View file

@ -70,12 +70,12 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
while (*branches)
{
String entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages;
String entry, stageEntries[+Stage::count], stages;
Vector<String> vMacroName;
Vector<String> vMacroValue;
const String entry = Parse(*branches, entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
const String branch = Parse(*branches, entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
if (IsInIgnoreList(_C(entry)))
if (IsInIgnoreList(_C(branch)))
{
branches++;
continue;
@ -126,12 +126,13 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
// </System defines>
Compiled compiled;
compiled._entry = entry;
if (strchr(_C(stages), 'V'))
{
compiled._stageCount++;
vDefines[typeIndex] = "_VS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryVS), "vs", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::vs]), "vs", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::vs]);
}
@ -140,7 +141,7 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex] = "_HS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryHS), "hs", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::hs]), "hs", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::hs]);
}
@ -149,7 +150,7 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex] = "_DS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryDS), "ds", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::ds]), "ds", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::ds]);
}
@ -158,7 +159,7 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex] = "_GS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryGS), "gs", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::gs]), "gs", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::gs]);
}
@ -167,7 +168,7 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex] = "_FS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryFS), "fs", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::fs]), "fs", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::fs]);
}
@ -176,13 +177,13 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
{
compiled._stageCount++;
vDefines[typeIndex] = "_CS";
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(entryCS), "cs", flags, &pCode, &size, &pErrorMsgs))
if (!RendererVulkan::VulkanCompile(source, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::cs]), "cs", flags, &pCode, &size, &pErrorMsgs))
CheckErrorMsgs(pErrorMsgs);
CreateShaderModule(pCode, size, compiled._shaderModules[+Stage::cs]);
_compute = true;
}
_mapCompiled[entry] = compiled;
_mapCompiled[branch] = compiled;
branches++;
}
@ -248,6 +249,24 @@ void ShaderVulkan::CreatePipelineLayout()
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
StringStream ss;
auto PrintStageFlags = [&ss](VkShaderStageFlags stageFlags)
{
if (stageFlags & VK_SHADER_STAGE_VERTEX_BIT)
ss << "[V]";
if (stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
ss << "[TC]";
if (stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
ss << "[TE]";
if (stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
ss << "[G]";
if (stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT)
ss << "[F]";
if (stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
ss << "[C]";
};
VkPushConstantRange vkpcr = {};
VkPipelineLayoutCreateInfo vkplci = {};
vkplci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
@ -307,6 +326,34 @@ void ShaderVulkan::CreatePipelineLayout()
vkdslci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
vkdslci.bindingCount = Utils::Cast32(vBindings.size());
vkdslci.pBindings = vBindings.data();
ss << "Set=" << _vDescriptorSetLayouts.size();
ss << std::endl;
for (const auto& binding : vBindings)
{
ss << " binding=" << binding.binding;
ss << ", type=";
switch (binding.descriptorType)
{
case VK_DESCRIPTOR_TYPE_SAMPLER: ss << "SAMPLER"; break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: ss << "COMBINED_IMAGE_SAMPLER"; break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: ss << "SAMPLED_IMAGE"; break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: ss << "STORAGE_IMAGE"; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: ss << "UNIFORM_TEXEL_BUFFER"; break;
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: ss << "STORAGE_TEXEL_BUFFER"; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: ss << "UNIFORM_BUFFER"; break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: ss << "STORAGE_BUFFER"; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: ss << "UNIFORM_BUFFER_DYNAMIC"; break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ss << "STORAGE_BUFFER_DYNAMIC"; break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ss << "INPUT_ATTACHMENT"; break;
}
ss << ", count=" << binding.descriptorCount;
ss << ", flags=";
PrintStageFlags(binding.stageFlags);
ss << ", immutableSampler=" << binding.pImmutableSamplers;
ss << std::endl;
}
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
if (VK_SUCCESS != (res = vkCreateDescriptorSetLayout(pRendererVulkan->GetVkDevice(), &vkdslci, pRendererVulkan->GetAllocator(), &descriptorSetLayout)))
throw VERUS_RUNTIME_ERROR << "vkCreateDescriptorSetLayout(), res=" << res;
@ -321,6 +368,14 @@ void ShaderVulkan::CreatePipelineLayout()
vkpcr.size = dsd._size;
vkplci.pushConstantRangeCount = 1;
vkplci.pPushConstantRanges = &vkpcr;
ss << "Set=PushConst";
ss << std::endl;
ss << " flags=";
PrintStageFlags(vkpcr.stageFlags);
ss << ", offset=" << vkpcr.offset;
ss << ", size=" << vkpcr.size;
ss << std::endl;
}
}
@ -328,6 +383,8 @@ void ShaderVulkan::CreatePipelineLayout()
vkplci.pSetLayouts = _vDescriptorSetLayouts.data();
}
_debugInfo = ss.str();
if (VK_SUCCESS != (res = vkCreatePipelineLayout(pRendererVulkan->GetVkDevice(), &vkplci, pRendererVulkan->GetAllocator(), &_pipelineLayout)))
throw VERUS_RUNTIME_ERROR << "vkCreatePipelineLayout(), res=" << res;
@ -340,7 +397,7 @@ void ShaderVulkan::CreatePipelineLayout()
}
}
int ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
{
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
@ -448,21 +505,21 @@ int ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list
vkUpdateDescriptorSets(pRendererVulkan->GetVkDevice(), Utils::Cast32(vWriteDescriptorSet.size()), vWriteDescriptorSet.data(), 0, nullptr);
return complexSetHandle;
return CSHandle::Make(complexSetHandle);
}
void ShaderVulkan::FreeDescriptorSet(int& complexSetHandle)
void ShaderVulkan::FreeDescriptorSet(CSHandle& complexSetHandle)
{
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
if (complexSetHandle >= 0 && complexSetHandle < _vComplexDescriptorSets.size() && _vComplexDescriptorSets[complexSetHandle] != VK_NULL_HANDLE)
if (complexSetHandle.IsSet() && complexSetHandle.Get() < _vComplexDescriptorSets.size() && _vComplexDescriptorSets[complexSetHandle.Get()] != VK_NULL_HANDLE)
{
if (VK_SUCCESS != (res = vkFreeDescriptorSets(pRendererVulkan->GetVkDevice(), _descriptorPool, 1, &_vComplexDescriptorSets[complexSetHandle])))
if (VK_SUCCESS != (res = vkFreeDescriptorSets(pRendererVulkan->GetVkDevice(), _descriptorPool, 1, &_vComplexDescriptorSets[complexSetHandle.Get()])))
throw VERUS_RUNTIME_ERROR << "vkFreeDescriptorSets(), res=" << res;
_vComplexDescriptorSets[complexSetHandle] = VK_NULL_HANDLE;
_vComplexDescriptorSets[complexSetHandle.Get()] = VK_NULL_HANDLE;
}
complexSetHandle = -1;
complexSetHandle = CSHandle();
}
void ShaderVulkan::BeginBindDescriptors()
@ -582,9 +639,9 @@ VkDescriptorSet ShaderVulkan::GetVkDescriptorSet(int setNumber)
return _vDescriptorSetDesc[setNumber]._descriptorSet;
}
VkDescriptorSet ShaderVulkan::GetComplexVkDescriptorSet(int descSetID)
VkDescriptorSet ShaderVulkan::GetComplexVkDescriptorSet(CSHandle descSetID)
{
return _vComplexDescriptorSets[descSetID];
return _vComplexDescriptorSets[descSetID.Get()];
}
bool ShaderVulkan::TryPushConstants(int setNumber, RBaseCommandBuffer cb)
@ -621,7 +678,7 @@ int ShaderVulkan::UpdateUniformBuffer(int setNumber)
void ShaderVulkan::OnError(CSZ s)
{
VERUS_QREF_RENDERER;
if (strstr(s, ": error "))
if (strstr(s, " ERROR: "))
renderer.OnShaderError(s);
else
renderer.OnShaderWarning(s);

View file

@ -6,11 +6,16 @@ namespace verus
{
class ShaderVulkan : public BaseShader
{
public:
struct Compiled
{
VkShaderModule _shaderModules[+Stage::count] = {};
String _entry;
int _stageCount = 0;
};
VERUS_TYPEDEFS(Compiled);
private:
typedef Map<String, Compiled> TMapCompiled;
struct DescriptorSetDesc
@ -36,6 +41,7 @@ namespace verus
Vector<VkDescriptorSet> _vComplexDescriptorSets;
VkDescriptorPool _descriptorPool = VK_NULL_HANDLE;
VkPipelineLayout _pipelineLayout = VK_NULL_HANDLE;
String _debugInfo;
UINT64 _currentFrame = UINT64_MAX;
uint32_t _poolComplexUniformBuffers = 0;
uint32_t _poolComplexImageSamplers = 0;
@ -52,8 +58,8 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
virtual void CreatePipelineLayout() override;
virtual int BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual void FreeDescriptorSet(int& complexSetHandle) override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
virtual void BeginBindDescriptors() override;
virtual void EndBindDescriptors() override;
@ -65,10 +71,9 @@ namespace verus
void CreateDescriptorPool();
void CreateDescriptorSets();
VkDescriptorSet GetVkDescriptorSet(int setNumber);
VkDescriptorSet GetComplexVkDescriptorSet(int descSetID);
VkDescriptorSet GetComplexVkDescriptorSet(CSHandle descSetID);
VkShaderModule GetVkShaderModule(CSZ branch, Stage stage) const { return _mapCompiled.at(branch)._shaderModules[+stage]; }
int GetStageCount(CSZ branch) const { return _mapCompiled.at(branch)._stageCount; }
RcCompiled GetCompiled(CSZ branch) const { return _mapCompiled.at(branch); }
VkPipelineLayout GetVkPipelineLayout() const { return _pipelineLayout; }

View file

@ -28,9 +28,8 @@ void TextureVulkan::Init(RcTextureDesc desc)
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
const bool inputAttach = (_desc._flags & TextureDesc::Flags::inputAttachment);
const bool depthFormat = IsDepthFormat(desc._format);
const bool depthSampled = _desc._flags & TextureDesc::Flags::depthSampled;
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
@ -50,14 +49,16 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (renderTarget)
vkici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (inputAttach)
vkici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
if (_desc._flags & TextureDesc::Flags::generateMips)
vkici.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (depthFormat)
{
vkici.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (depthSampled)
vkici.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
}
if (_desc._flags & TextureDesc::Flags::inputAttachment)
vkici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
pRendererVulkan->CreateImage(&vkici, VMA_MEMORY_USAGE_GPU_ONLY, _image, _vmaAllocation);
if (_desc._flags & TextureDesc::Flags::generateMips)
@ -68,6 +69,12 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkiciStorage.extent.height = Math::Max(1, _desc._height >> 1);
vkiciStorage.mipLevels = Math::Max(1, _desc._mipLevels - 1);
vkiciStorage.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
// sRGB cannot be used with storage image:
switch (vkiciStorage.format)
{
case VK_FORMAT_R8G8B8A8_SRGB: vkiciStorage.format = VK_FORMAT_R8G8B8A8_UNORM; break;
case VK_FORMAT_B8G8R8A8_SRGB: vkiciStorage.format = VK_FORMAT_B8G8R8A8_UNORM; break;
}
pRendererVulkan->CreateImage(&vkiciStorage, VMA_MEMORY_USAGE_GPU_ONLY, _storageImage, _storageVmaAllocation);
_vCshGenerateMips.reserve((_desc._mipLevels + 3) / 4);
@ -78,7 +85,7 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _storageImage;
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
vkivci.format = vkici.format;
vkivci.format = vkiciStorage.format;
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkivci.subresourceRange.baseMipLevel = mip;
vkivci.subresourceRange.levelCount = 1;
@ -103,6 +110,12 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkivci.subresourceRange.layerCount = vkici.arrayLayers;
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_imageView)))
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(), res=" << res;
if (renderTarget)
{
vkivci.subresourceRange.levelCount = 1;
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_imageViewLevelZero)))
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(LevelZero), res=" << res;
}
if (_desc._pSamplerDesc)
CreateSampler();
@ -116,7 +129,7 @@ void TextureVulkan::Init(RcTextureDesc desc)
}
if (depthFormat)
{
const ImageLayout layout = depthSampled ? ImageLayout::depthStencilReadOnly : ImageLayout::depthStencilAttachment;
const ImageLayout layout = (_desc._flags & TextureDesc::Flags::depthSampledR) ? ImageLayout::depthStencilReadOnly : ImageLayout::depthStencilAttachment;
CommandBufferVulkan commandBuffer;
commandBuffer.InitOneTimeSubmit();
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, layout, 0, 0);
@ -134,6 +147,7 @@ void TextureVulkan::Done()
ForceScheduled();
VERUS_VULKAN_DESTROY(_sampler, vkDestroySampler(pRendererVulkan->GetVkDevice(), _sampler, pRendererVulkan->GetAllocator()));
VERUS_VULKAN_DESTROY(_imageViewLevelZero, vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageViewLevelZero, pRendererVulkan->GetAllocator()));
VERUS_VULKAN_DESTROY(_imageView, vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageView, pRendererVulkan->GetAllocator()));
for (auto view : _vStorageImageViews)
VERUS_VULKAN_DESTROY(view, vkDestroyImageView(pRendererVulkan->GetVkDevice(), view, pRendererVulkan->GetAllocator()));
@ -237,7 +251,7 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
ub._srcMipLevel = srcMip;
ub._mipLevelCount = dispatchMipCount;
ub._srcDimensionCase = (srcHeight & 1) << 1 | (srcWidth & 1);
ub._srgb = false;
ub._srgb = IsSRGBFormat(_desc._format);
ub._texelSize.x = 1.f / dstWidth;
ub._texelSize.y = 1.f / dstHeight;
@ -246,7 +260,7 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
int mips[5] = {}; // For input texture (always mip 0) and 4 storage mips.
VERUS_FOR(mip, dispatchMipCount)
mips[mip + 1] = srcMip + mip;
const int complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
}
@ -312,7 +326,7 @@ Continue TextureVulkan::Scheduled_Update()
{
VERUS_QREF_RENDERER;
auto shader = renderer.GetShaderGenerateMips();
for (int csh : _vCshGenerateMips)
for (auto& csh : _vCshGenerateMips)
shader->FreeDescriptorSet(csh);
_vCshGenerateMips.clear();
}

View file

@ -17,11 +17,12 @@ namespace verus
VkImage _storageImage = VK_NULL_HANDLE;
VmaAllocation _storageVmaAllocation = VK_NULL_HANDLE;
VkImageView _imageView = VK_NULL_HANDLE;
VkImageView _imageViewLevelZero = VK_NULL_HANDLE;
VkSampler _sampler = VK_NULL_HANDLE;
Vector<UINT32> _vDefinedSubresources;
Vector<VkImageView> _vStorageImageViews;
Vector<VkBufferEx> _vStagingBuffers;
Vector<int> _vCshGenerateMips;
Vector<CSHandle> _vCshGenerateMips;
bool _definedStorage = false;
public:
@ -45,6 +46,7 @@ namespace verus
VkImage GetVkImage() const { return _image; }
VkImageView GetVkImageView() const { return _imageView; }
VkImageView GetVkImageViewForFramebuffer() const { return _imageViewLevelZero ? _imageViewLevelZero : _imageView; }
VkImageView GetStorageVkImageView(int mip) const { return _vStorageImageViews[mip]; }
VkSampler GetVkSampler() const { return _sampler; }
ImageLayout GetSubresourceMainLayout(int mipLevel, int arrayLayer) const;

View file

@ -1 +0,0 @@
"C:\Home\nvidia-texture-tools-2.1.1-win64\bin64\nvcompress.exe" -bc1a %1

View file

@ -1 +0,0 @@
"C:\Home\nvidia-texture-tools-2.1.1-win64\bin64\nvcompress.exe" -bc3 %1

View file

@ -1 +0,0 @@
"C:\Home\nvidia-texture-tools-2.1.1-win64\bin64\nvcompress.exe" -bc7 %1

View file

@ -0,0 +1 @@
"C:\Home\Projects\Verus\verus\Bin\TextureTool.exe" %1

View file

@ -0,0 +1 @@
"C:\Home\Projects\Verus\verus\Bin\TextureTool.exe" --non-color-data %1

View file

@ -0,0 +1 @@
"C:\Home\Projects\Verus\verus\Bin\TextureTool.exe" --normal-map %1

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>TextureTool</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Verus\Verus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Verus\Verus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Verus\Verus.vcxproj">
<Project>{b154d670-e4b1-4d8a-885c-69546a5bd833}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

363
TextureTool/main.cpp Normal file
View file

@ -0,0 +1,363 @@
#define VERUS_INCLUDE_COMPRESSONATOR
#include <verus.h>
using namespace verus;
void DeleteMipmap(CWSZ pathname);
CMP_BOOL CompressionCallback(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2)
{
std::wcout << _T("ProcessTexture progress = ") << static_cast<int>(progress) << _T("%") << std::endl;
return false;
}
void Run()
{
int argCount = 0;
LPWSTR* argArray = CommandLineToArgvW(GetCommandLine(), &argCount);
WideString pathNameW;
std::wcout << _T("TextureTool") << std::endl;
std::wcout << _T("Copyright (c) 2016-2020 Dmitry Maluev") << std::endl;
if (argCount < 2)
{
std::wcout << _T("Enter file name: ");
std::wcin >> pathNameW;
}
else
pathNameW = argArray[argCount - 1];
String pathname = Str::WideToUtf8(pathNameW);
bool argDeleteMipmap = false;
bool argFade = false;
bool argNormalMap = false;
bool argColorData = true;
VERUS_FOR(i, argCount)
{
if (!_wcsicmp(argArray[i], L"--delete-mipmap"))
argDeleteMipmap = true;
if (!_wcsicmp(argArray[i], L"--fade"))
argFade = true;
if (!_wcsicmp(argArray[i], L"--normal-map"))
argNormalMap = true;
if (!_wcsicmp(argArray[i], L"--non-color-data"))
argColorData = false;
}
LocalFree(argArray);
if (argDeleteMipmap)
{
DeleteMipmap(_C(pathNameW));
return;
}
CMP_ERROR cmpError = CMP_OK;
CMP_MipSet srcMipSet = {};
cmpError = CMP_LoadTexture(_C(pathname), &srcMipSet);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_LoadTexture(), ") << cmpError << std::endl;
throw std::exception();
}
// FX image with extra info:
Vector<UINT32> vMipFX[2];
String pathnameFX(pathname);
Str::ReplaceExtension(pathnameFX, ".FX.png");
if (argNormalMap && IO::FileSystem::FileExist(_C(pathnameFX)))
{
std::wcout << _T("FX file: ") << Str::Utf8ToWide(pathnameFX) << std::endl;
IO::Image imageFX;
imageFX.Init(_C(pathnameFX));
if (imageFX._width == srcMipSet.m_nWidth && imageFX._height == srcMipSet.m_nHeight)
{
const int pixelCount = imageFX._width * imageFX._height;
vMipFX[0].resize(pixelCount);
vMipFX[1].resize(pixelCount);
VERUS_FOR(i, pixelCount)
memcpy(&vMipFX[0][i], imageFX._p + imageFX._bytesPerPixel * i, imageFX._bytesPerPixel);
}
else
{
std::wcerr << _T("ERROR: FX image has different dimensions: ") << imageFX._width << _T("x") << imageFX._height << std::endl;
throw std::exception();
}
}
if (srcMipSet.m_nMipLevels <= 1)
CMP_GenerateMIPLevels(&srcMipSet, 0);
CMP_MipLevel* pMipLevel = srcMipSet.m_pMipLevelTable[0];
const BYTE* pData = pMipLevel->m_pbData;
const int pixelCount = srcMipSet.m_nWidth * srcMipSet.m_nHeight;
Vector<UINT32> vMip[2];
vMip[0].resize(pixelCount);
vMip[1].resize(pixelCount);
const float fadePerMip = pow(0.02f, 1.f / srcMipSet.m_nMipLevels);
int mip = 0;
bool finish = false;
do
{
std::wcout << _T("Processing mipmap ") << mip << std::endl;
const int mipW = Math::Max(1, srcMipSet.m_nWidth >> mip);
const int mipH = Math::Max(1, srcMipSet.m_nHeight >> mip);
// Switch between in and out:
const int inIndex = (mip & 0x1);
const int outIndex = ((mip + 1) & 0x1);
VERUS_FOR(i, mipH)
{
VERUS_FOR(j, mipW)
{
int offset = 0;
UINT32 color = 0;
UINT32 colorFX = 0;
if (mip) // Generate mipmap level 1+:
{
offset = i * mipW + j;
const int aboveMipW = mipW << 1;
const int aboveMipH = mipH << 1;
const int aboveMipEdgeW = aboveMipW - 1;
const int aboveMipEdgeH = aboveMipH - 1;
const int sampleA[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
const int sampleB[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
const int sampleC[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
const int sampleD[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
const int offsetA = sampleA[1] * aboveMipW + sampleA[0];
const int offsetB = sampleB[1] * aboveMipW + sampleB[0];
const int offsetC = sampleC[1] * aboveMipW + sampleC[0];
const int offsetD = sampleD[1] * aboveMipW + sampleD[0];
if (argNormalMap)
{
Vector4 data[4];
float raw[4];
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, false); data[0] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, false); data[1] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, false); data[2] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, false); data[3] = Vector4::MakeFromPointer(raw);
// Generate FX mipmap:
if (!vMipFX[inIndex].empty())
{
const BYTE* rgbaA = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetA]);
const BYTE* rgbaB = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetB]);
const BYTE* rgbaC = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetC]);
const BYTE* rgbaD = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetD]);
BYTE rgbaOut[4] =
{
static_cast<BYTE>((rgbaA[0] + rgbaB[0] + rgbaC[0] + rgbaD[0]) >> 2),
static_cast<BYTE>((rgbaA[1] + rgbaB[1] + rgbaC[1] + rgbaD[1]) >> 2),
static_cast<BYTE>((rgbaA[2] + rgbaB[2] + rgbaC[2] + rgbaD[2]) >> 2),
static_cast<BYTE>((rgbaA[3] + rgbaB[3] + rgbaC[3] + rgbaD[3]) >> 2)
};
memcpy(&colorFX, rgbaOut, 4);
}
const float prevAvgLength[4] =
{
data[0].getW(),
data[1].getW(),
data[2].getW(),
data[3].getW()
};
data[0].setW(0);
data[1].setW(0);
data[2].setW(0);
data[3].setW(0);
float minAvgLength = 1;
VERUS_FOR(i, 4) // To [-1 to 1]:
{
data[i] = data[i] * 2.f - Vector4(1, 1, 1, 0);
minAvgLength = Math::Min(minAvgLength, prevAvgLength[i]);
}
Vector4 avg = (
data[0] * prevAvgLength[0] +
data[1] * prevAvgLength[1] +
data[2] * prevAvgLength[2] +
data[3] * prevAvgLength[3]) * 0.25f;
float len = VMath::length(avg);
if (len > minAvgLength) // Don't make it too smooth.
len = (len + minAvgLength) * 0.5f;
Vector4 dataOut = VMath::normalize(data[0] + data[1] + data[2] + data[3]);
if (argFade)
dataOut = VMath::normalize(VMath::lerp(fadePerMip, Vector4(0, 0, 1, 0), dataOut));
dataOut = dataOut * 0.5f + Vector4(0.5f, 0.5f, 0.5f, 0); // To [0 to 1]:
dataOut.setW(len);
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), false);
}
else
{
Vector4 data[4];
float raw[4];
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, argColorData); data[0] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, argColorData); data[1] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, argColorData); data[2] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, argColorData); data[3] = Vector4::MakeFromPointer(raw);
Vector4 dataOut = (data[0] + data[1] + data[2] + data[3]) * 0.25f;
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), argColorData);
}
}
else // Handle topmost mipmap level:
{
if (argNormalMap)
{
const bool upsideDownBGRA = false;
if (upsideDownBGRA)
{
// Input image is upside down BGRA (?):
offset = (mipH - i - 1) * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
reinterpret_cast<BYTE*>(&input)[3] >>= 2; // Divide alpha by 4.
color = VERUS_COLOR_TO_D3D(input);
offset = i * mipW + j;
}
else
{
offset = i * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
reinterpret_cast<BYTE*>(&input)[3] = 0xFF;
color = input;
if (!vMipFX[inIndex].empty())
{
colorFX = vMipFX[inIndex][offset];
BYTE* rgbaFX = reinterpret_cast<BYTE*>(&colorFX);
rgbaFX[0] /= 4;
rgbaFX[1] /= 4;
rgbaFX[2] /= 4;
rgbaFX[3] /= 4;
}
}
}
else // Simple copy for color:
{
offset = i * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
color = input;
}
}
vMip[outIndex][offset] = color;
if (!vMipFX[outIndex].empty())
vMipFX[outIndex][offset] = colorFX;
}
}
if (argNormalMap)
{
// Shuffle channels, read from outIndex, write to inIndex:
const int pixelCount = mipW * mipH;
VERUS_FOR(i, pixelCount)
{
BYTE* rgbaFX = vMipFX[outIndex].empty() ? nullptr : reinterpret_cast<BYTE*>(&vMipFX[outIndex][i]);
BYTE* rgba = reinterpret_cast<BYTE*>(&vMip[outIndex][i]);
const int len = Math::Clamp(rgba[3] - 128, 0, 0xFF);
vMip[inIndex][i] = VERUS_COLOR_RGBA(rgbaFX ? rgbaFX[0] : 0, rgba[1], len, rgba[0]);
}
// Save shuffled mip level, read from inIndex:
CMP_MipLevel* pDstMipLevel = srcMipSet.m_pMipLevelTable[mip];
memcpy(pDstMipLevel->m_pbData, vMip[inIndex].data(), mipW * mipH * sizeof(UINT32));
}
else
{
CMP_MipLevel* pDstMipLevel = srcMipSet.m_pMipLevelTable[mip];
memcpy(pDstMipLevel->m_pbData, vMip[outIndex].data(), mipW * mipH * sizeof(UINT32));
}
finish = (mipW == 1) && (mipH == 1);
mip++; // Next level, switch between in and out.
} while (!finish);
CMP_MipSet dstMipSet = {};
KernelOptions kernelOptions = {};
kernelOptions.format = CMP_FORMAT_BC7;
kernelOptions.fquality = 0.51f; // Tests show that 51% is production quality.
cmpError = CMP_ProcessTexture(&srcMipSet, &dstMipSet, kernelOptions, CompressionCallback);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_ProcessTexture(), ") << cmpError << std::endl;
throw std::exception();
}
Str::ReplaceExtension(pathname, ".dds");
cmpError = CMP_SaveTexture(_C(pathname), &dstMipSet);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_SaveTexture(), ") << cmpError << std::endl;
throw std::exception();
}
CMP_FreeMipSet(&srcMipSet);
CMP_FreeMipSet(&dstMipSet);
}
void DeleteMipmap(CWSZ pathname)
{
const String pathnameIn = Str::WideToUtf8(pathname);
const String pathnameOut = pathnameIn + "-del-mip.dds";
IO::File file, fileOut;
if (file.Open(_C(pathnameIn)) && file.GetSize() > sizeof(IO::DDSHeader) && fileOut.Open(_C(pathnameOut), "wb"))
{
IO::DDSHeader header;
file >> header;
if (!header.Validate())
{
std::wcerr << _T("ERROR: Invalid DDS header: ") << Str::Utf8ToWide(pathnameIn) << std::endl;
throw std::exception();
}
if (header.IsBC1() && header._mipMapCount > 1)
{
const int levelSize = IO::DDSHeader::ComputeBcLevelSize(header._width, header._height, true);
header._mipMapCount--;
header._width >>= 1;
header._height >>= 1;
header._pitchOrLinearSize = IO::DDSHeader::ComputeBcLevelSize(header._width, header._height, true);
fileOut << header;
file.Seek(sizeof(IO::DDSHeader) + levelSize, SEEK_SET);
Vector<BYTE> vData;
vData.resize(file.GetSize() - levelSize - sizeof(IO::DDSHeader));
file.Read(vData.data(), vData.size());
fileOut.Write(vData.data(), vData.size());
}
else
{
std::wcerr << _T("ERROR: Must be DXT1 with mipmaps") << std::endl;
throw std::exception();
}
}
}
int main(VERUS_MAIN_DEFAULT_ARGS)
{
try
{
Run();
}
catch (const std::exception& e)
{
std::wcerr << _T("EXCEPTION: ") << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View file

@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VulkanShaderCompiler", "Vul
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PAKBuilder", "PAKBuilder\PAKBuilder.vcxproj", "{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextureTool", "TextureTool\TextureTool.vcxproj", "{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -45,6 +47,10 @@ Global
{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}.Debug|x64.Build.0 = Debug|x64
{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}.Release|x64.ActiveCfg = Release|x64
{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}.Release|x64.Build.0 = Release|x64
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Debug|x64.ActiveCfg = Debug|x64
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Debug|x64.Build.0 = Debug|x64
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Release|x64.ActiveCfg = Release|x64
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.88\src;C:\Home\Middleware\bullet3-2.88\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\SDL2-2.0.10\include;C:\Program Files %28x86%29\OpenAL 1.1 SDK\include;C:\VulkanSDK\1.2.131.2\Include;C:\VulkanSDK\1.2.131.2\glslang;$(IncludePath)</IncludePath>
<LibraryPath>C:\Home\Middleware\bullet3-2.88\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\SDL2-2.0.10\lib\x64;C:\Program Files %28x86%29\OpenAL 1.1 SDK\libs\Win64;C:\VulkanSDK\1.2.131.2\Lib;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.88\src;C:\Home\Middleware\bullet3-2.88\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\SDL2-2.0.10\include;C:\Program Files %28x86%29\OpenAL 1.1 SDK\include;C:\VulkanSDK\1.2.131.2\Include;C:\VulkanSDK\1.2.131.2\glslang;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.88\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\SDL2-2.0.10\lib\x64;C:\Program Files %28x86%29\OpenAL 1.1 SDK\libs\Win64;C:\VulkanSDK\1.2.131.2\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View file

@ -117,6 +117,7 @@
<ClInclude Include="src\CGI\DeferredShading.h" />
<ClInclude Include="src\CGI\RendererParser.h" />
<ClInclude Include="src\CGI\Scheduled.h" />
<ClInclude Include="src\CGI\TextureRAM.h" />
<ClInclude Include="src\CGI\Types.h" />
<ClInclude Include="src\CGI\Formats.h" />
<ClInclude Include="src\CGI\Renderer.h" />
@ -202,6 +203,7 @@
<ClInclude Include="src\Scene\Camera.h" />
<ClInclude Include="src\Scene\CameraOrbit.h" />
<ClInclude Include="src\Scene\EditorTerrain.h" />
<ClInclude Include="src\Scene\Grass.h" />
<ClInclude Include="src\Scene\Helpers.h" />
<ClInclude Include="src\Scene\MaterialManager.h" />
<ClInclude Include="src\Scene\Mesh.h" />
@ -209,6 +211,7 @@
<ClInclude Include="src\Scene\SceneManager.h" />
<ClInclude Include="src\Scene\ShadowMap.h" />
<ClInclude Include="src\Scene\Terrain.h" />
<ClInclude Include="src\Scene\Water.h" />
<ClInclude Include="src\Security\CipherRC4.h" />
<ClInclude Include="src\Security\Security.h" />
<ClInclude Include="src\ThirdParty\imgui\imconfig.h" />
@ -274,6 +277,7 @@
<ClCompile Include="src\CGI\RendererParser.cpp" />
<ClCompile Include="src\CGI\RenderPass.cpp" />
<ClCompile Include="src\CGI\Scheduled.cpp" />
<ClCompile Include="src\CGI\TextureRAM.cpp" />
<ClCompile Include="src\D\D.cpp" />
<ClCompile Include="src\D\Log.cpp" />
<ClCompile Include="src\Extra\Extra.cpp" />
@ -333,6 +337,7 @@
<ClCompile Include="src\Scene\Camera.cpp" />
<ClCompile Include="src\Scene\CameraOrbit.cpp" />
<ClCompile Include="src\Scene\EditorTerrain.cpp" />
<ClCompile Include="src\Scene\Grass.cpp" />
<ClCompile Include="src\Scene\Helpers.cpp" />
<ClCompile Include="src\Scene\MaterialManager.cpp" />
<ClCompile Include="src\Scene\Mesh.cpp" />
@ -340,6 +345,7 @@
<ClCompile Include="src\Scene\SceneManager.cpp" />
<ClCompile Include="src\Scene\ShadowMap.cpp" />
<ClCompile Include="src\Scene\Terrain.cpp" />
<ClCompile Include="src\Scene\Water.cpp" />
<ClCompile Include="src\ThirdParty\fast_atof.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
@ -578,6 +584,56 @@
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\LibSurface.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\LibTessellation.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_Grass.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Grass.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Sky.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\Sky.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Water.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\Water.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\WaterGen.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\WaterGen.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\SimpleTerrain.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\SimpleTerrain.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View file

@ -552,6 +552,15 @@
<ClInclude Include="src\IO\Xxx.h">
<Filter>src\IO</Filter>
</ClInclude>
<ClInclude Include="src\Scene\Grass.h">
<Filter>src\Scene</Filter>
</ClInclude>
<ClInclude Include="src\CGI\TextureRAM.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\Scene\Water.h">
<Filter>src\Scene</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -917,6 +926,15 @@
<ClCompile Include="src\IO\Xxx.cpp">
<Filter>src\IO</Filter>
</ClCompile>
<ClCompile Include="src\Scene\Grass.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
<ClCompile Include="src\CGI\TextureRAM.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\Scene\Water.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Lib.hlsl">
@ -979,6 +997,42 @@
<None Include="src\Shaders\DebugDraw.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\LibSurface.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\LibTessellation.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\Sky.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\Sky.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Grass.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Grass.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\Water.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\Water.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\WaterGen.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\WaterGen.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\SimpleTerrain.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\SimpleTerrain.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml.natvis">

View file

@ -25,6 +25,7 @@ void Settings::Load()
_gapi = GetI("gapi", _gapi);
_gpuAnisotropyLevel = GetI("gpuAnisotropyLevel", _gpuAnisotropyLevel);
_gpuAntialiasingLevel = GetI("gpuAntialiasingLevel", _gpuAntialiasingLevel);
_gpuTessellation = GetB("gpuTessellation", _gpuTessellation);
_gpuTextureLodLevel = GetI("gpuTextureLodLevel", _gpuTextureLodLevel);
_gpuTrilinearFilter = GetB("gpuTrilinearFilter", _gpuTrilinearFilter);
_inputMouseSensitivity = GetF("inputMouseSensitivity", _inputMouseSensitivity);
@ -67,6 +68,7 @@ void Settings::Save()
Set("gapi", _gapi);
Set("gpuAnisotropyLevel", _gpuAnisotropyLevel);
Set("gpuAntialiasingLevel", _gpuAntialiasingLevel);
Set("gpuTessellation", _gpuTessellation);
Set("gpuTextureLodLevel", _gpuTextureLodLevel);
Set("gpuTrilinearFilter", _gpuTrilinearFilter);
Set("inputMouseSensitivity", _inputMouseSensitivity);

View file

@ -7,7 +7,7 @@ namespace verus
class Limits
{
public:
int _d3d12_dhCbvSrvUavCapacity = 10000;
int _d3d12_dhViewsCapacity = 10000;
int _d3d12_dhSamplersCapacity = 500;
int _mesh_ubPerFrameCapacity = 100;
int _mesh_ubPerMaterialFSCapacity = 1000;
@ -64,6 +64,7 @@ namespace verus
int _gapi = 0;
int _gpuAnisotropyLevel = 4;
int _gpuAntialiasingLevel = 0;
bool _gpuTessellation = true;
int _gpuTextureLodLevel = 0;
bool _gpuTrilinearFilter = false;
float _inputMouseSensitivity = 1;

View file

@ -7,6 +7,8 @@ namespace verus
class BaseCommandBuffer : public Object, public Scheduled
{
protected:
Vector4 _viewportSize = Vector4(0);
BaseCommandBuffer() = default;
virtual ~BaseCommandBuffer() = default;
@ -17,7 +19,7 @@ namespace verus
virtual void Begin() = 0;
virtual void End() = 0;
virtual void BeginRenderPass(int renderPassHandle, int framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
virtual void NextSubpass() = 0;
virtual void EndRenderPass() = 0;
@ -29,7 +31,7 @@ namespace verus
virtual void SetScissor(std::initializer_list<Vector4> il) = 0;
virtual void SetBlendConstants(const float* p) = 0;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, int complexSetHandle = -1) = 0;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle = CSHandle()) = 0;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout,
@ -39,6 +41,8 @@ namespace verus
virtual void DrawIndexed(int indexCount, int instanceCount = 1, int firstIndex = 0, int vertexOffset = 0, int firstInstance = 0) = 0;
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ = 1) = 0;
RcVector4 GetViewportSize() const { return _viewportSize; }
};
VERUS_TYPEDEFS(BaseCommandBuffer);

View file

@ -3,7 +3,7 @@
using namespace verus;
using namespace verus::CGI;
int BaseGeometry::GetInputElementDescCount(PcInputElementDesc p)
int BaseGeometry::GetVertexInputAttrDescCount(PcVertexInputAttrDesc p)
{
int i = 0;
while (p[i]._offset >= 0)
@ -11,7 +11,7 @@ int BaseGeometry::GetInputElementDescCount(PcInputElementDesc p)
return i;
}
int BaseGeometry::GetBindingCount(PcInputElementDesc p)
int BaseGeometry::GetBindingCount(PcVertexInputAttrDesc p)
{
int count = 0;
int i = 0;

View file

@ -8,7 +8,7 @@ namespace verus
struct GeometryDesc
{
PcInputElementDesc _pInputElementDesc;
PcVertexInputAttrDesc _pVertexInputAttrDesc;
const int* _pStrides = nullptr;
UINT32 _dynBindingsMask = 0;
bool _32BitIndices = false;
@ -35,8 +35,8 @@ namespace verus
virtual void CreateIndexBuffer(int count) = 0;
virtual void UpdateIndexBuffer(const void* p, BaseCommandBuffer* pCB = nullptr) = 0;
static int GetInputElementDescCount(PcInputElementDesc p);
static int GetBindingCount(PcInputElementDesc p);
static int GetVertexInputAttrDescCount(PcVertexInputAttrDesc p);
static int GetBindingCount(PcVertexInputAttrDesc p);
bool Has32BitIndices() const { return _32BitIndices; }
};

View file

@ -14,7 +14,7 @@ namespace verus
PipelineRasterizationState _rasterizationState;
PrimitiveTopology _topology = PrimitiveTopology::triangleList;
int _sampleCount = 1;
int _renderPassHandle = -1;
RPHandle _renderPassHandle;
int _subpass = 0;
int _multiViewport = 1; // See SV_ViewportArrayIndex semantic output by a geometry shader.
UINT32 _vertexInputBindingsFilter = UINT32_MAX;
@ -26,7 +26,7 @@ namespace verus
bool _compute = false; // Compute pipeline, use PipelineDesc(ShaderPtr, CSZ) to set this to true.
// What to draw (geo)? How to draw (shader)? Where to draw (render pass)?
PipelineDesc(GeometryPtr geo, ShaderPtr shader, CSZ branch, int renderPassHandle, int subpass = 0) :
PipelineDesc(GeometryPtr geo, ShaderPtr shader, CSZ branch, RPHandle renderPassHandle, int subpass = 0) :
_geometry(geo), _shader(shader), _shaderBranch(branch), _renderPassHandle(renderPassHandle), _subpass(subpass)
{
_colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;

View file

@ -45,6 +45,30 @@ void BaseRenderer::UpdateScheduled()
}), _vScheduled.end());
}
RPHandle BaseRenderer::CreateSimpleRenderPass(Format format, ImageLayout layout)
{
return CreateRenderPass(
{
RP::Attachment("Attach", format).LoadOpDontCare().Layout(layout),
},
{
RP::Subpass("Sp0").Color({RP::Ref("Attach", ImageLayout::colorAttachment)}),
},
{});
}
RPHandle BaseRenderer::CreateShadowRenderPass(Format format)
{
return CreateRenderPass(
{
RP::Attachment("Depth", format).LoadOpClear().Layout(ImageLayout::depthStencilReadOnly),
},
{
RP::Subpass("Sp0").Color({}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
},
{});
}
void BaseRenderer::SetAlphaBlendHelper(
CSZ sz,
int& colorBlendOp,

View file

@ -50,7 +50,7 @@ namespace verus
void Unschedule(PScheduled p);
void UpdateScheduled();
virtual void ImGuiInit(int renderPassHandle) = 0;
virtual void ImGuiInit(RPHandle renderPassHandle) = 0;
virtual void ImGuiRenderDrawData() = 0;
virtual void ResizeSwapChain() = 0;
@ -77,10 +77,12 @@ namespace verus
virtual void DeleteShader(PBaseShader p) = 0;
virtual void DeleteTexture(PBaseTexture p) = 0;
virtual int CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) = 0;
virtual int CreateFramebuffer(int renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) = 0;
virtual void DeleteRenderPass(int handle) = 0;
virtual void DeleteFramebuffer(int handle) = 0;
RPHandle CreateSimpleRenderPass(Format format, ImageLayout layout = ImageLayout::fsReadOnly);
RPHandle CreateShadowRenderPass(Format format);
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) = 0;
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) = 0;
virtual void DeleteRenderPass(RPHandle handle) = 0;
virtual void DeleteFramebuffer(FBHandle handle) = 0;
static void SetAlphaBlendHelper(
CSZ sz,

View file

@ -36,32 +36,24 @@ void BaseShader::Load(CSZ url)
String BaseShader::Parse(
CSZ branchDesc,
RString entryVS,
RString entryHS,
RString entryDS,
RString entryGS,
RString entryFS,
RString entryCS,
RString entry,
String stageEntries[],
RString stages,
Vector<String>& vMacroName,
Vector<String>& vMacroValue,
CSZ prefix)
{
VERUS_RT_ASSERT(branchDesc);
entryVS.clear();
entryHS.clear();
entryDS.clear();
entryGS.clear();
entryFS.clear();
entryCS.clear();
VERUS_FOR(i, +Stage::count)
stageEntries[i].clear();
stages = "(VF)";
vMacroName.clear();
vMacroValue.clear();
CSZ space = strchr(branchDesc, ' ');
String entry;
space ? entry.assign(branchDesc, space) : entry.assign(branchDesc);
String entryBranch;
space ? entryBranch.assign(branchDesc, space) : entryBranch.assign(branchDesc);
if (space)
{
@ -97,44 +89,46 @@ String BaseShader::Parse(
} while (branchDesc);
}
const size_t colon = entry.find(":");
const size_t colon = entryBranch.find(":");
if (String::npos == colon)
{
entryVS = entry + "VS";
entryHS = entry + "HS";
entryDS = entry + "DS";
entryGS = entry + "GS";
entryFS = entry + "FS";
entryCS = entry + "CS";
return entry;
entry = entryBranch;
stageEntries[+Stage::vs] = entryBranch + "VS";
stageEntries[+Stage::hs] = entryBranch + "HS";
stageEntries[+Stage::ds] = entryBranch + "DS";
stageEntries[+Stage::gs] = entryBranch + "GS";
stageEntries[+Stage::fs] = entryBranch + "FS";
stageEntries[+Stage::cs] = entryBranch + "CS";
return entryBranch;
}
else
{
const String func = entry.substr(0, colon);
entryVS = func + "VS";
entryHS = func + "HS";
entryDS = func + "DS";
entryGS = func + "GS";
entryFS = func + "FS";
entryCS = func + "CS";
return entry.substr(colon + 1);
const String func = entryBranch.substr(0, colon);
entry = func;
stageEntries[+Stage::vs] = func + "VS";
stageEntries[+Stage::hs] = func + "HS";
stageEntries[+Stage::ds] = func + "DS";
stageEntries[+Stage::gs] = func + "GS";
stageEntries[+Stage::fs] = func + "FS";
stageEntries[+Stage::cs] = func + "CS";
return entryBranch.substr(colon + 1);
}
}
void BaseShader::TestParse()
{
String entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages;
String entry, stageEntries[+Stage::count], stages;
Vector<String> vMacroName;
Vector<String> vMacroValue;
Parse("",
entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
Parse("Foo",
entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
Parse("Bar FOO BAR XYZ (VGF)",
entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
Parse("FooBar FOO=1 BAR=xyz XYZ= XYZ2=",
entryVS, entryHS, entryDS, entryGS, entryFS, entryCS, stages, vMacroName, vMacroValue, "DEF_");
entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
}
bool BaseShader::IsInIgnoreList(CSZ name) const

View file

@ -46,12 +46,8 @@ namespace verus
void Load(CSZ url);
static String Parse(
CSZ branchDesc,
RString entryVS,
RString entryHS,
RString entryDS,
RString entryGS,
RString entryFS,
RString entryCS,
RString entry,
String stageEntries[],
RString stages,
Vector<String>& vMacroName,
Vector<String>& vMacroValue,
@ -61,8 +57,8 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size,
int capacity = 1, std::initializer_list<Sampler> il = {}, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
virtual void CreatePipelineLayout() = 0;
virtual int BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips = nullptr) = 0;
virtual void FreeDescriptorSet(int& complexSetHandle) = 0;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips = nullptr) = 0;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) = 0;
virtual void BeginBindDescriptors() = 0;
virtual void EndBindDescriptors() = 0;

View file

@ -28,8 +28,10 @@ void BaseTexture::LoadDDS(CSZ url, int texturePart)
IO::Async::I().Load(url, this, IO::Async::TaskDesc(false, false, texturePart));
}
void BaseTexture::LoadDDS(RcBlob blob)
void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
{
_name = url;
int offset = sizeof(IO::DDSHeader);
IO::DDSHeader header;
memcpy(&header, blob._p, sizeof(header));
@ -70,6 +72,7 @@ void BaseTexture::LoadDDS(RcBlob blob)
desc._width = header._width >> lod;
desc._height = header._height >> lod;
desc._mipLevels = header._mipMapCount - lod;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -97,6 +100,7 @@ void BaseTexture::LoadDDS(RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -118,6 +122,7 @@ void BaseTexture::LoadDDS(RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -151,6 +156,7 @@ void BaseTexture::LoadDDS(RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -202,10 +208,17 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
const BYTE* pData = vData.data();
const size_t size = vData.size();
int offset = sizeof(IO::DDSHeader);
IO::DDSHeader header;
memcpy(&header, pData, sizeof(header));
if (!header.Validate())
throw VERUS_RUNTIME_ERROR << "Invalid DDS header: " << _name;
IO::DDSHeaderDXT10 header10;
if (header.IsDXT10())
{
memcpy(&header10, pData + offset, sizeof(header10));
offset += sizeof(IO::DDSHeaderDXT10);
}
VERUS_QREF_CONST_SETTINGS;
@ -240,9 +253,12 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
desc._format = SelectFormat(Format::unormBC2, Format::srgbBC2);
else if (header.IsBC3())
desc._format = SelectFormat(Format::unormBC3, Format::srgbBC3);
else if (header10.IsBC7())
desc._format = SelectFormat(Format::unormBC7, Format::srgbBC7);
desc._width = w;
desc._height = h;
desc._mipLevels = header._mipMapCount - lod;
desc._pSamplerDesc = _desc._pSamplerDesc;
if (init)
{
@ -250,7 +266,6 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
Init(desc);
}
int offset = sizeof(header);
VERUS_U_FOR(i, header._mipMapCount)
{
UINT32 w = header._width >> i;
@ -274,7 +289,7 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
void BaseTexture::Async_Run(CSZ url, RcBlob blob)
{
LoadDDS(blob);
LoadDDS(url, blob);
}
int BaseTexture::FormatToBytesPerPixel(Format format)
@ -307,6 +322,20 @@ int BaseTexture::FormatToBytesPerPixel(Format format)
return 0;
}
bool BaseTexture::IsSRGBFormat(Format format)
{
switch (format)
{
case Format::srgbR8G8B8A8: return true;
case Format::srgbB8G8R8A8: return true;
case Format::srgbBC1: return true;
case Format::srgbBC2: return true;
case Format::srgbBC3: return true;
case Format::srgbBC7: return true;
}
return false;
}
bool BaseTexture::IsBC(Format format)
{
return format >= Format::unormBC1 && format <= Format::srgbBC7;
@ -329,11 +358,12 @@ void TexturePtr::Init(RcTextureDesc desc)
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(!_p);
_p = renderer->InsertTexture();
_p->SetSamplerDesc(desc._pSamplerDesc);
if (desc._flags & TextureDesc::Flags::sync)
{
Vector<BYTE> v;
IO::FileSystem::LoadResource(desc._url, v);
_p->LoadDDS(Blob(v.data(), v.size()));
Vector<BYTE> vData;
IO::FileSystem::LoadResource(desc._url, vData);
_p->LoadDDS(desc._url, Blob(vData.data(), vData.size()));
}
else
{

View file

@ -32,11 +32,12 @@ namespace verus
none = 0,
colorAttachment = (1 << 0),
inputAttachment = (1 << 1),
depthSampled = (1 << 2),
anyShaderResource = (1 << 3), // Will use xsReadOnly as main layout.
generateMips = (1 << 4), // Allows GenerateMips calls.
forceArrayTexture = (1 << 5), // Create array texture even if arrayLayers=1.
sync = (1 << 6)
depthSampledR = (1 << 2),
depthSampledW = (1 << 3),
anyShaderResource = (1 << 4), // Will use xsReadOnly as main layout.
generateMips = (1 << 5), // Allows GenerateMips calls.
forceArrayTexture = (1 << 6), // Create array texture even if arrayLayers=1.
sync = (1 << 7)
};
Vector4 _clearValue = Vector4(0);
@ -98,8 +99,10 @@ namespace verus
RcVector4 GetSize() const { return _size; }
bool IsSRGB() const;
void SetSamplerDesc(PcSamplerDesc pSamplerDesc) { _desc._pSamplerDesc = pSamplerDesc; }
void LoadDDS(CSZ url, int texturePart = 0);
void LoadDDS(RcBlob blob);
void LoadDDS(CSZ url, RcBlob blob);
void LoadDDSArray(CSZ* urls);
virtual void Async_Run(CSZ url, RcBlob blob) override;
@ -109,6 +112,7 @@ namespace verus
virtual void GenerateMips(BaseCommandBuffer* pCB = nullptr) = 0;
static int FormatToBytesPerPixel(Format format);
static bool IsSRGBFormat(Format format);
static bool IsBC(Format format);
static bool Is4BitsBC(Format format);
static bool IsDepthFormat(Format format);

View file

@ -12,6 +12,7 @@
#include "BaseCommandBuffer.h"
#include "BaseRenderer.h"
#include "TextureRAM.h"
#include "DebugDraw.h"
#include "DeferredShading.h"
#include "Renderer.h"

View file

@ -25,13 +25,13 @@ void DebugDraw::Init()
_shader->CreatePipelineLayout();
GeometryDesc geoDesc;
const InputElementDesc ied[] =
const VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(Vertex, _pos), IeType::floats, 3, IeUsage::position, 0},
{0, offsetof(Vertex, _color), IeType::ubytes, 4, IeUsage::color, 0},
InputElementDesc::End()
VertexInputAttrDesc::End()
};
geoDesc._pInputElementDesc = ied;
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(Vertex), 0 };
geoDesc._pStrides = strides;
geoDesc._dynBindingsMask = 0x1;
@ -43,7 +43,7 @@ void DebugDraw::Init()
_offset = 0;
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPass_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._topology = PrimitiveTopology::pointList;
_pipe[PIPE_POINTS].Init(pipeDesc);
@ -51,7 +51,7 @@ void DebugDraw::Init()
_pipe[PIPE_POINTS_NO_Z].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPass_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._topology = PrimitiveTopology::lineList;
_pipe[PIPE_LINES].Init(pipeDesc);
@ -59,7 +59,7 @@ void DebugDraw::Init()
_pipe[PIPE_LINES_NO_Z].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPass_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._rasterizationState._polygonMode = PolygonMode::line;
pipeDesc._topology = PrimitiveTopology::triangleList;

View file

@ -16,7 +16,7 @@ namespace verus
PIPE_LINES_NO_Z,
PIPE_POLY,
PIPE_POLY_NO_Z,
PIPE_MAX
PIPE_COUNT
};
public:
@ -38,7 +38,7 @@ namespace verus
GeometryPwn _geo;
ShaderPwn _shader;
PipelinePwns<PIPE_MAX> _pipe;
PipelinePwns<PIPE_COUNT> _pipe;
Vector<Vertex> _vDynamicBuffer;
UINT64 _currentFrame = UINT64_MAX;
const int _maxVerts = 0x10000;

View file

@ -27,12 +27,11 @@ void DeferredShading::Init()
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
_rp = renderer->CreateRenderPass(
_rph = renderer->CreateRenderPass(
{
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::floatR32).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR10G10B10A2).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::unormR10G10B10A2).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccDiff", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccSpec", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).LoadOpClear().Layout(ImageLayout::depthStencilAttachment),
@ -42,62 +41,85 @@ void DeferredShading::Init()
{
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
RP::Ref("GBuffer2", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
RP::Subpass("Sp1").Input(
{
RP::Ref("GBuffer0", ImageLayout::fsReadOnly),
RP::Ref("GBuffer1", ImageLayout::fsReadOnly),
RP::Ref("GBuffer2", ImageLayout::fsReadOnly),
RP::Ref("GBuffer3", ImageLayout::fsReadOnly)
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
}).Color(
{
RP::Ref("LightAccDiff", ImageLayout::colorAttachment),
RP::Ref("LightAccSpec", ImageLayout::colorAttachment),
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment))
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
},
{
RP::Dependency("Sp0", "Sp1").Mode(1)
});
_rphCompose = renderer->CreateRenderPass(
{
RP::Attachment("Composed", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("Composed", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly)),
RP::Subpass("Sp1").Color(
{
RP::Ref("Composed", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
},
{
RP::Dependency("Sp0", "Sp1").Mode(1)
});
_shader[S_LIGHT].Init("[Shaders]:DS.hlsl");
_shader[S_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame));
_shader[S_LIGHT]->CreateDescriptorSet(1, &s_ubTexturesFS, sizeof(s_ubTexturesFS), 1,
_shader[SHADER_LIGHT].Init("[Shaders]:DS.hlsl");
_shader[SHADER_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame));
_shader[SHADER_LIGHT]->CreateDescriptorSet(1, &s_ubTexturesFS, sizeof(s_ubTexturesFS), 1,
{
Sampler::input,
Sampler::input,
Sampler::input,
Sampler::input,
Sampler::shadow,
Sampler::nearest2D
Sampler::nearestMipN
}, CGI::ShaderStageFlags::fs);
_shader[S_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), 1000, {}, CGI::ShaderStageFlags::vs);
_shader[S_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), 1000, {}, CGI::ShaderStageFlags::fs);
_shader[S_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0);
_shader[S_LIGHT]->CreatePipelineLayout();
_shader[SHADER_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), 1000, {}, CGI::ShaderStageFlags::vs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), 1000, {}, CGI::ShaderStageFlags::fs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0);
_shader[SHADER_LIGHT]->CreatePipelineLayout();
_shader[S_COMPOSE].Init("[Shaders]:DS_Compose.hlsl");
_shader[S_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 1, {}, CGI::ShaderStageFlags::vs);
_shader[S_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 1,
_shader[SHADER_COMPOSE].Init("[Shaders]:DS_Compose.hlsl");
_shader[SHADER_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 2, {}, CGI::ShaderStageFlags::vs);
_shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 2,
{
Sampler::nearest2D,
Sampler::nearest2D,
Sampler::nearest2D,
Sampler::nearest2D,
Sampler::nearest2D,
Sampler::nearest2D
Sampler::nearestMipN,
Sampler::nearestMipN,
Sampler::nearestMipN,
Sampler::nearestMipN,
Sampler::nearestMipN,
Sampler::nearestMipN
}, CGI::ShaderStageFlags::fs);
_shader[S_COMPOSE]->CreatePipelineLayout();
_shader[SHADER_COMPOSE]->CreatePipelineLayout();
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[S_COMPOSE], "#", renderer.GetRenderPass_SwapChainDepth());
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose);
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_COMPOSE].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), renderer.GetShaderQuad(), "#", renderer.GetRenderPass_SwapChainDepth());
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_SwapChainDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_TONE_MAPPING].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), renderer.GetShaderQuad(), "#", renderer.GetRenderPassHandle_SwapChainDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_QUAD].Init(pipeDesc);
@ -121,39 +143,33 @@ void DeferredShading::InitGBuffers(int w, int h)
_tex[TEX_GBUFFER_0].Init(texDesc);
// GB1:
texDesc._clearValue = Vector4(1);
texDesc._format = Format::floatR32;
texDesc._clearValue = Vector4(0.5f, 0.5f, 0.25f, 0.5f);
texDesc._format = Format::unormR10G10B10A2;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_1].Init(texDesc);
// GB2:
texDesc._clearValue = Vector4(0.5f, 0.5f, 0.25f, 0.5f);
texDesc._format = Format::unormR10G10B10A2;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_2].Init(texDesc);
// GB3:
texDesc._clearValue = Vector4(1, 1, 1, 1);
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_3].Init(texDesc);
_tex[TEX_GBUFFER_2].Init(texDesc);
}
void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
{
VERUS_QREF_RENDERER;
_texShadowAtmo = texShadow;
_cshLight = _shader[S_LIGHT]->BindDescriptorSetTextures(1,
_cshLight = _shader[SHADER_LIGHT]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
_texShadowAtmo,
_texShadowAtmo
});
@ -170,16 +186,18 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
if (done)
{
_shader[S_LIGHT]->FreeDescriptorSet(_cshLight);
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
renderer.GetShaderQuad()->FreeDescriptorSet(_cshQuad[i]);
_shader[S_COMPOSE]->FreeDescriptorSet(_cshCompose);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
renderer->DeleteFramebuffer(_fb);
renderer->DeleteFramebuffer(_fbhCompose);
renderer->DeleteFramebuffer(_fbh);
_tex[TEX_COMPOSED].Done();
_tex[TEX_LIGHT_ACC_SPEC].Done();
_tex[TEX_LIGHT_ACC_DIFF].Done();
_tex[TEX_GBUFFER_3].Done();
_tex[TEX_GBUFFER_2].Done();
_tex[TEX_GBUFFER_1].Done();
_tex[TEX_GBUFFER_0].Done();
@ -198,34 +216,47 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
texDesc._height = renderer.GetSwapChainHeight();
texDesc._flags = TextureDesc::Flags::colorAttachment;
_tex[TEX_LIGHT_ACC_DIFF].Init(texDesc);
texDesc._format = Format::floatR11G11B10;
texDesc._width = renderer.GetSwapChainWidth();
texDesc._height = renderer.GetSwapChainHeight();
texDesc._flags = TextureDesc::Flags::colorAttachment;
_tex[TEX_LIGHT_ACC_SPEC].Init(texDesc);
_tex[TEX_COMPOSED].Init(texDesc);
_fb = renderer->CreateFramebuffer(_rp,
_fbh = renderer->CreateFramebuffer(_rph,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC],
renderer.GetTexDepthStencil()
},
renderer.GetSwapChainWidth(),
renderer.GetSwapChainHeight());
_fbhCompose = renderer->CreateFramebuffer(_rphCompose,
{
_tex[TEX_COMPOSED],
renderer.GetTexDepthStencil()
},
renderer.GetSwapChainWidth(),
renderer.GetSwapChainHeight());
_cshCompose = _shader[S_COMPOSE]->BindDescriptorSetTextures(1,
_cshCompose = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
});
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_COMPOSED],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_0],
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
});
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
_cshQuad[i] = renderer.GetShaderQuad()->BindDescriptorSetTextures(1, { _tex[TEX_GBUFFER_0 + i] });
@ -313,12 +344,11 @@ void DeferredShading::BeginGeometryPass(bool onlySetRT, bool spriteBaking)
_activeGeometryPass = true;
_frame = renderer.GetFrameCount();
renderer.GetCommandBuffer()->BeginRenderPass(_rp, _fb,
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex[TEX_GBUFFER_0]->GetClearValue(),
_tex[TEX_GBUFFER_1]->GetClearValue(),
_tex[TEX_GBUFFER_2]->GetClearValue(),
_tex[TEX_GBUFFER_3]->GetClearValue(),
_tex[TEX_LIGHT_ACC_DIFF]->GetClearValue(),
_tex[TEX_LIGHT_ACC_SPEC]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
@ -342,7 +372,7 @@ bool DeferredShading::BeginLightingPass()
_activeLightingPass = true;
renderer.GetCommandBuffer()->NextSubpass();
_shader[S_LIGHT]->BeginBindDescriptors();
_shader[SHADER_LIGHT]->BeginBindDescriptors();
if (!IsLoaded())
return false;
@ -355,7 +385,7 @@ bool DeferredShading::BeginLightingPass()
Scene::RDeferredLights dl = helpers.GetDeferredLights();
{
PipelineDesc pipeDesc(dl.Get(CGI::LightType::dir).GetGeometry(), _shader[S_LIGHT], "#InstancedDir", _rp, 1);
PipelineDesc pipeDesc(dl.Get(CGI::LightType::dir).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedDir", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
@ -363,7 +393,7 @@ bool DeferredShading::BeginLightingPass()
_pipe[PIPE_INSTANCED_DIR].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(dl.Get(CGI::LightType::omni).GetGeometry(), _shader[S_LIGHT], "#InstancedOmni", _rp, 1);
PipelineDesc pipeDesc(dl.Get(CGI::LightType::omni).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedOmni", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._rasterizationState._cullMode = CullMode::front;
@ -373,7 +403,7 @@ bool DeferredShading::BeginLightingPass()
_pipe[PIPE_INSTANCED_OMNI].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(dl.Get(CGI::LightType::spot).GetGeometry(), _shader[S_LIGHT], "#InstancedSpot", _rp, 1);
PipelineDesc pipeDesc(dl.Get(CGI::LightType::spot).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedSpot", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._rasterizationState._cullMode = CullMode::front;
@ -394,28 +424,71 @@ void DeferredShading::EndLightingPass()
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass);
_activeLightingPass = false;
_shader[S_LIGHT]->EndBindDescriptors();
_shader[SHADER_LIGHT]->EndBindDescriptors();
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::Compose(RcVector4 bgColor)
void DeferredShading::BeginCompose(RcVector4 bgColor)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
renderer.GetCommandBuffer()->BeginRenderPass(_rphCompose, _fbhCompose,
{
_tex[TEX_COMPOSED]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_COMPOSE]);
_shader[S_COMPOSE]->BeginBindDescriptors();
const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP());
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat();
s_ubComposeFS._colorAmbient = Vector4(0.1f, 0.1f, 0.2f, 1).GLM();
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
s_ubComposeFS._colorAmbient = float4(atmo.GetAmbientColor().GLM(), 0);
s_ubComposeFS._colorBackground = bgColor.GLM();
s_ubComposeFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
memcpy(&s_ubComposeFS._toneMappingConfig.x, &_toneMappingConfig, sizeof(_toneMappingConfig));
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshCompose);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad();
renderer.GetCommandBuffer()->NextSubpass();
}
void DeferredShading::EndCompose()
{
VERUS_QREF_RENDERER;
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::ToneMapping()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat();
s_ubComposeFS._colorAmbient = float4(atmo.GetAmbientColor().GLM(), 0);
s_ubComposeFS._fogColor = Vector4(0.5f, 0.5f, 0.5f, 0.002f).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_COMPOSE], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_COMPOSE], 1, _cshCompose);
_shader[S_COMPOSE]->EndBindDescriptors();
memcpy(&s_ubComposeFS._toneMappingConfig.x, &_toneMappingConfig, sizeof(_toneMappingConfig));
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad();
}
@ -437,36 +510,38 @@ void DeferredShading::OnNewLightType(LightType type, bool wireframe)
VERUS_QREF_RENDERER;
VERUS_QREF_ATMO;
auto cb = renderer.GetCommandBuffer();
switch (type)
{
case CGI::LightType::dir:
{
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_INSTANCED_DIR]);
cb->BindPipeline(_pipe[PIPE_INSTANCED_DIR]);
}
break;
case CGI::LightType::omni:
{
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_INSTANCED_OMNI]);
cb->BindPipeline(_pipe[PIPE_INSTANCED_OMNI]);
}
break;
case CGI::LightType::spot:
{
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_INSTANCED_SPOT]);
cb->BindPipeline(_pipe[PIPE_INSTANCED_SPOT]);
}
break;
}
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_LIGHT], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_LIGHT], 1, _cshLight);
cb->BindDescriptors(_shader[SHADER_LIGHT], 0);
cb->BindDescriptors(_shader[SHADER_LIGHT], 1, _cshLight);
// Shadow:
s_ubShadowFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrixDS(0).UniformBufferFormat();
s_ubShadowFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrixDS(1).UniformBufferFormat();
s_ubShadowFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrixDS(2).UniformBufferFormat();
s_ubShadowFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrixDS(3).UniformBufferFormat();
s_ubShadowFS._shadowConfig = atmo.GetShadowMap().GetConfig().GLM();
memcpy(&s_ubShadowFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubShadowFS._shadowConfig));
s_ubShadowFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_LIGHT], 3);
cb->BindDescriptors(_shader[SHADER_LIGHT], 3);
}
void DeferredShading::UpdateUniformBufferPerFrame()
@ -486,7 +561,7 @@ void DeferredShading::UpdateUniformBufferPerFrame()
void DeferredShading::BindDescriptorsPerMeshVS()
{
VERUS_QREF_RENDERER;
renderer.GetCommandBuffer()->BindDescriptors(_shader[S_LIGHT], 2);
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_LIGHT], 2);
}
void DeferredShading::Load()

View file

@ -17,11 +17,11 @@ namespace verus
#include "../Shaders/DS.inc.hlsl"
#include "../Shaders/DS_Compose.inc.hlsl"
enum S
enum SHADER
{
S_LIGHT,
S_COMPOSE,
S_MAX
SHADER_LIGHT,
SHADER_COMPOSE,
SHADER_COUNT
};
enum PIPE
@ -30,19 +30,20 @@ namespace verus
PIPE_INSTANCED_OMNI,
PIPE_INSTANCED_SPOT,
PIPE_COMPOSE,
PIPE_TONE_MAPPING,
PIPE_QUAD,
PIPE_MAX
PIPE_COUNT
};
enum TEX
{
TEX_GBUFFER_0, // Albedo RGB, A = motion blur.
TEX_GBUFFER_1, // Depth.
TEX_GBUFFER_2, // RG - Normals in screen space, Emission, Metallicity.
TEX_GBUFFER_3, // LamScale, LamBias, Specular, Gloss.
TEX_GBUFFER_0, // Albedo, Spec.
TEX_GBUFFER_1, // RG - Normals, Emission, Motion.
TEX_GBUFFER_2, // LamScale, LamBias, Metallicity, Gloss.
TEX_LIGHT_ACC_DIFF,
TEX_LIGHT_ACC_SPEC,
TEX_MAX
TEX_COMPOSED,
TEX_COUNT
};
static UB_PerFrame s_ubPerFrame;
@ -53,21 +54,31 @@ namespace verus
static UB_ComposeVS s_ubComposeVS;
static UB_ComposeFS s_ubComposeFS;
ShaderPwns<S_MAX> _shader;
PipelinePwns<PIPE_MAX> _pipe;
TexturePwns<TEX_MAX> _tex;
ShaderPwns<SHADER_COUNT> _shader;
PipelinePwns<PIPE_COUNT> _pipe;
TexturePwns<TEX_COUNT> _tex;
TexturePtr _texShadowAtmo;
UINT64 _frame = 0;
int _rp = -1;
int _fb = -1;
int _cshLight = -1;
int _cshCompose = -1;
int _cshQuad[6];
RPHandle _rph;
RPHandle _rphCompose;
FBHandle _fbh;
FBHandle _fbhCompose;
CSHandle _cshLight;
CSHandle _cshCompose;
CSHandle _cshToneMapping;
CSHandle _cshQuad[6];
bool _activeGeometryPass = false;
bool _activeLightingPass = false;
bool _async_initPipe = false;
public:
struct ToneMappingConfig
{
float _exposure = 0.005f;
float _filmicLook = 0.5f;
float _albedoScale = 0.5f;
} _toneMappingConfig;
DeferredShading();
~DeferredShading();
@ -85,13 +96,17 @@ namespace verus
bool IsActiveGeometryPass() const { return _activeGeometryPass; }
bool IsActiveLightingPass() const { return _activeLightingPass; }
int GetRenderPassHandle() const { return _rp; }
RPHandle GetRenderPassHandle() const { return _rph; }
RPHandle GetRenderPassHandle_Compose() const { return _rphCompose; }
int GetSubpass_Compose() const { return 1; }
void BeginGeometryPass(bool onlySetRT = false, bool spriteBaking = false);
void EndGeometryPass(bool resetRT = false);
bool BeginLightingPass();
void EndLightingPass();
void Compose(RcVector4 bgColor = Vector4(0));
void BeginCompose(RcVector4 bgColor = Vector4(0));
void EndCompose();
void ToneMapping();
void AntiAliasing();
static bool IsLightUrl(CSZ url);

View file

@ -52,35 +52,15 @@ void Renderer::Init(PRendererDelegate pDelegate)
_commandBuffer.Init();
GeometryDesc geoDesc;
const InputElementDesc ied[] =
_rphSwapChain = _pBaseRenderer->CreateRenderPass(
{
{0, offsetof(Vertex, _pos), IeType::floats, 2, IeUsage::position, 0},
InputElementDesc::End()
};
geoDesc._pInputElementDesc = ied;
const int strides[] = { sizeof(Vertex), 0 };
geoDesc._pStrides = strides;
_geoQuad.Init(geoDesc);
_shader[S_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
_shader[S_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), 100,
{ Sampler::linearClamp2D, Sampler::storage, Sampler::storage, Sampler::storage, Sampler::storage }, ShaderStageFlags::cs);
_shader[S_GENERATE_MIPS]->CreatePipelineLayout();
_shader[S_QUAD].Init("[Shaders]:Quad.hlsl");
_shader[S_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), 100, {}, ShaderStageFlags::vs);
_shader[S_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), 100, { Sampler::linearClamp2D }, ShaderStageFlags::fs);
_shader[S_QUAD]->CreatePipelineLayout();
PipelineDesc pipeDesc(_shader[S_GENERATE_MIPS], "#");
_pipeGenerateMips.Init(pipeDesc);
_rpSwapChain = _pBaseRenderer->CreateRenderPass(
{ RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::undefined, ImageLayout::presentSrc) },
{ RP::Subpass("Sp0").Color({RP::Ref("Color", ImageLayout::colorAttachment)}) },
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::undefined, ImageLayout::presentSrc)
},
{
RP::Subpass("Sp0").Color({RP::Ref("Color", ImageLayout::colorAttachment)})
},
{});
_rpSwapChainDepth = _pBaseRenderer->CreateRenderPass(
_rphSwapChainDepth = _pBaseRenderer->CreateRenderPass(
{
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::undefined, ImageLayout::presentSrc),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
@ -93,9 +73,40 @@ void Renderer::Init(PRendererDelegate pDelegate)
},
{});
GeometryDesc geoDesc;
const VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(Vertex, _pos), IeType::floats, 2, IeUsage::position, 0},
VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(Vertex), 0 };
geoDesc._pStrides = strides;
_geoQuad.Init(geoDesc);
_shader[S_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
_shader[S_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), 100,
{
Sampler::linearClampMipN,
Sampler::storage,
Sampler::storage,
Sampler::storage,
Sampler::storage
},
ShaderStageFlags::cs);
_shader[S_GENERATE_MIPS]->CreatePipelineLayout();
_shader[S_QUAD].Init("[Shaders]:Quad.hlsl");
_shader[S_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), 100, {}, ShaderStageFlags::vs);
_shader[S_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), 100, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
_shader[S_QUAD]->CreatePipelineLayout();
PipelineDesc pipeDesc(_shader[S_GENERATE_MIPS], "#");
_pipeGenerateMips.Init(pipeDesc);
OnSwapChainResized(true, false);
_pBaseRenderer->ImGuiInit(_rpSwapChainDepth);
_pBaseRenderer->ImGuiInit(_rphSwapChainDepth);
ImGuiUpdateStyle();
_ds.Init();
@ -126,6 +137,7 @@ void Renderer::Done()
_geoQuad.Done();
_commandBuffer.Done();
Scene::Grass::DoneStatic();
Scene::Terrain::DoneStatic();
Scene::Mesh::DoneStatic();
@ -151,7 +163,7 @@ void Renderer::Present()
_frameCount++;
VERUS_QREF_TIMER;
_fps = _fps * 0.75f + timer.GetDeltaTimeInv() * 0.25f;
_fps = Math::Lerp(_fps, timer.GetDeltaTimeInv(), 0.25f);
}
void Renderer::OnWindowResized(int w, int h)
@ -170,10 +182,10 @@ void Renderer::OnSwapChainResized(bool init, bool done)
{
if (done)
{
VERUS_FOR(i, _fbSwapChainDepth.size())
_pBaseRenderer->DeleteFramebuffer(_fbSwapChainDepth[i]);
VERUS_FOR(i, _fbSwapChain.size())
_pBaseRenderer->DeleteFramebuffer(_fbSwapChain[i]);
VERUS_FOR(i, _fbhSwapChainDepth.size())
_pBaseRenderer->DeleteFramebuffer(_fbhSwapChainDepth[i]);
VERUS_FOR(i, _fbhSwapChain.size())
_pBaseRenderer->DeleteFramebuffer(_fbhSwapChain[i]);
_texDepthStencil.Done();
}
@ -185,14 +197,15 @@ void Renderer::OnSwapChainResized(bool init, bool done)
texDesc._format = Format::unormD24uintS8;
texDesc._width = _swapChainWidth;
texDesc._height = _swapChainHeight;
texDesc._flags = TextureDesc::Flags::inputAttachment | TextureDesc::Flags::depthSampledW;
_texDepthStencil.Init(texDesc);
_fbSwapChain.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbSwapChain.size())
_fbSwapChain[i] = _pBaseRenderer->CreateFramebuffer(_rpSwapChain, {}, _swapChainWidth, _swapChainHeight, i);
_fbSwapChainDepth.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbSwapChainDepth.size())
_fbSwapChainDepth[i] = _pBaseRenderer->CreateFramebuffer(_rpSwapChainDepth, { _texDepthStencil }, _swapChainWidth, _swapChainHeight, i);
_fbhSwapChain.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbhSwapChain.size())
_fbhSwapChain[i] = _pBaseRenderer->CreateFramebuffer(_rphSwapChain, {}, _swapChainWidth, _swapChainHeight, i);
_fbhSwapChainDepth.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbhSwapChainDepth.size())
_fbhSwapChainDepth[i] = _pBaseRenderer->CreateFramebuffer(_rphSwapChainDepth, { _texDepthStencil }, _swapChainWidth, _swapChainHeight, i);
}
}

View file

@ -44,10 +44,10 @@ namespace verus
int _swapChainWidth = 0;
int _swapChainHeight = 0;
float _fps = 30;
int _rpSwapChain = 0;
int _rpSwapChainDepth = 0;
Vector<int> _fbSwapChain;
Vector<int> _fbSwapChainDepth;
RPHandle _rphSwapChain;
RPHandle _rphSwapChainDepth;
Vector<FBHandle> _fbhSwapChain;
Vector<FBHandle> _fbhSwapChainDepth;
UB_GenerateMips _ubGenerateMips;
UB_QuadVS _ubQuadVS;
UB_QuadFS _ubQuadFS;
@ -78,16 +78,17 @@ namespace verus
RDeferredShading GetDS() { return _ds; }
CommandBufferPtr GetCommandBuffer() const { return _commandBuffer; }
GeometryPtr GetGeoQuad() const { return _geoQuad; }
TexturePtr GetTexDepthStencil() const { return _texDepthStencil; }
void OnShaderError(CSZ s);
void OnShaderWarning(CSZ s);
// Window:
App::PWindow GetMainWindow() const { return _pMainWindow; }
App::PWindow SetMainWindow(App::PWindow p) { return Utils::Swap(_pMainWindow, p); }
float GetSwapChainAspectRatio() const;
// ImGui:
virtual void ImGuiSetCurrentContext(ImGuiContext* pContext);
void ImGuiUpdateStyle();
@ -95,15 +96,19 @@ namespace verus
float GetFps() const { return _fps; }
UINT64 GetFrameCount() const { return _frameCount; }
int GetRenderPass_SwapChain() const { return _rpSwapChain; }
int GetRenderPass_SwapChainDepth() const { return _rpSwapChainDepth; }
int GetFramebuffer_SwapChain(int index) const { return _fbSwapChain[index]; }
int GetFramebuffer_SwapChainDepth(int index) const { return _fbSwapChainDepth[index]; }
// RenderPass & Framebuffer:
RPHandle GetRenderPassHandle_SwapChain() const { return _rphSwapChain; }
RPHandle GetRenderPassHandle_SwapChainDepth() const { return _rphSwapChainDepth; }
FBHandle GetFramebufferHandle_SwapChain(int index) const { return _fbhSwapChain[index]; }
FBHandle GetFramebufferHandle_SwapChainDepth(int index) const { return _fbhSwapChainDepth[index]; }
// Generate mips:
PipelinePtr GetPipelineGenerateMips() { return _pipeGenerateMips; }
ShaderPtr GetShaderGenerateMips() { return _shader[S_GENERATE_MIPS]; }
UB_GenerateMips& GetUbGenerateMips() { return _ubGenerateMips; }
// Quad:
GeometryPtr GetGeoQuad() const { return _geoQuad; }
ShaderPtr GetShaderQuad() { return _shader[S_QUAD]; }
UB_QuadVS& GetUbQuadVS() { return _ubQuadVS; }
UB_QuadFS& GetUbQuadFS() { return _ubQuadFS; }

View file

@ -0,0 +1,48 @@
#include "verus.h"
using namespace verus;
using namespace verus::CGI;
TextureRAM::TextureRAM()
{
}
TextureRAM::~TextureRAM()
{
Done();
}
void TextureRAM::Init(RcTextureDesc desc)
{
VERUS_INIT();
VERUS_RT_ASSERT(desc._width > 0 && desc._height > 0);
VERUS_QREF_RENDERER;
_size = Vector4(
float(desc._width),
float(desc._height),
1.f / desc._width,
1.f / desc._height);
_desc = desc;
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
_vBuffer.resize(_desc._width * _desc._height * _bytesPerPixel);
}
void TextureRAM::Done()
{
VERUS_DONE(TextureRAM);
}
void TextureRAM::UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB)
{
if (mipLevel || arrayLayer)
return;
memcpy(_vBuffer.data(), p, _vBuffer.size());
}
void TextureRAM::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(__FUNCTION__);
}

View file

@ -0,0 +1,26 @@
#pragma once
namespace verus
{
namespace CGI
{
class TextureRAM : public BaseTexture
{
Vector<BYTE> _vBuffer;
public:
TextureRAM();
virtual ~TextureRAM() override;
virtual void Init(RcTextureDesc desc) override;
virtual void Done() override;
virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;
const BYTE* GetData() const { VERUS_RT_ASSERT(IsLoaded()); return _vBuffer.data(); }
};
VERUS_TYPEDEFS(TextureRAM);
}
}

View file

@ -37,7 +37,9 @@ namespace verus
lineList,
lineStrip,
triangleList,
triangleStrip
triangleStrip,
patchList3,
patchList4
};
struct PipelineRasterizationState
@ -72,7 +74,9 @@ namespace verus
gs = (1 << 3),
fs = (1 << 4),
cs = (1 << 5),
vs_fs = vs | fs
vs_fs = vs | fs,
vs_hs_ds = vs | hs | ds,
vs_hs_ds_fs = vs | hs | ds | fs
};
enum class IeType : int
@ -82,22 +86,24 @@ namespace verus
shorts
};
// See: https://docs.microsoft.com/en-us/windows/desktop/direct3d9/d3ddeclusage
// See: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3ddeclusage
enum class IeUsage : int
{
position,
blendWeight,
blendWeights,
blendIndices,
normal,
psize,
texCoord,
tangent,
binormal,
color
color,
psize,
texCoord,
instData,
attr
};
// See: https://docs.microsoft.com/en-us/windows/desktop/direct3d9/d3dvertexelement9
struct InputElementDesc
// See: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dvertexelement9
struct VertexInputAttrDesc
{
int _binding;
int _offset;
@ -106,9 +112,9 @@ namespace verus
IeUsage _usage;
int _usageIndex;
static constexpr InputElementDesc End() { return { -1, -1, IeType::floats, 0, IeUsage::position, 0 }; }
static constexpr VertexInputAttrDesc End() { return { -1, -1, IeType::floats, 0, IeUsage::position, 0 }; }
};
VERUS_TYPEDEFS(InputElementDesc);
VERUS_TYPEDEFS(VertexInputAttrDesc);
enum class Sampler : int
{
@ -117,15 +123,51 @@ namespace verus
input,
shadow,
aniso, // Most common sampler for 3D.
linear3D,
nearest3D,
linear2D,
nearest2D,
linearClamp3D,
nearestClamp3D,
linearClamp2D,
nearestClamp2D,
linearMipL,
nearestMipL,
linearMipN,
nearestMipN,
linearClampMipL,
nearestClampMipL,
linearClampMipN,
nearestClampMipN,
count
};
template<typename T>
class BaseHandle
{
int _h = -1;
protected:
static T Make(int value)
{
T ret;
ret._h = value;
return ret;
}
public:
int Get() const { return _h; }
bool IsSet() const { return _h >= 0; }
};
class RPHandle : public BaseHandle<RPHandle>
{
public:
static RPHandle Make(int value) { return BaseHandle::Make(value); }
};
class FBHandle : public BaseHandle<FBHandle>
{
public:
static FBHandle Make(int value) { return BaseHandle::Make(value); }
};
class CSHandle : public BaseHandle<CSHandle>
{
public:
static CSHandle Make(int value) { return BaseHandle::Make(value); }
};
}
}

View file

@ -71,16 +71,31 @@ UINT16 Convert::Uint8x4ToUint4x4(UINT32 in)
return (x[0] << 12) | (x[1] << 8) | (x[2] << 4) | (x[3]);
}
UINT32 Convert::Uint4x4ToUint8x4(UINT16 in)
UINT32 Convert::Uint4x4ToUint8x4(UINT16 in, bool scaleTo255)
{
int x[4] =
{
(in >> 12) & 0xF,
(in >> 8) & 0xF,
(in >> 4) & 0xF,
(in >> 0) & 0xF
((in >> 12) & 0xF) << 4,
((in >> 8) & 0xF) << 4,
((in >> 4) & 0xF) << 4,
((in >> 0) & 0xF) << 4
};
return (x[0] << 28) | (x[1] << 20) | (x[2] << 12) | (x[3] << 4);
if (scaleTo255)
{
VERUS_FOR(i, 4)
x[i] = x[i] * 255 / 0xF0;
}
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3] << 0);
}
float Convert::SRGBToLinear(float color)
{
return color < 0.04045f ? color * (1 / 12.92f) : pow((color + 0.055f) * (1 / 1.055f), 2.4f);
}
float Convert::LinearToSRGB(float color)
{
return color < 0.0031308f ? 12.92f * color : 1.055f * pow(color, 1 / 2.4f) - 0.055f;
}
UINT32 Convert::Color16To32(UINT16 in)
@ -93,20 +108,35 @@ UINT32 Convert::Color16To32(UINT16 in)
void Convert::ColorInt32ToFloat(UINT32 in, float* out, bool sRGB)
{
const float gamma = sRGB ? 2.2f : 1.f;
out[0] = pow(float(int((in >> 0) & 0xFF))* (1 / 255.f), gamma);
out[1] = pow(float(int((in >> 8) & 0xFF))* (1 / 255.f), gamma);
out[2] = pow(float(int((in >> 16) & 0xFF))* (1 / 255.f), gamma);
out[3] = float(int((in >> 24) & 0xFF))* (1 / 255.f);
out[0] = ((in >> 0) & 0xFF) * (1 / 255.f);
out[1] = ((in >> 8) & 0xFF) * (1 / 255.f);
out[2] = ((in >> 16) & 0xFF) * (1 / 255.f);
out[3] = ((in >> 24) & 0xFF) * (1 / 255.f);
if (sRGB)
{
out[0] = SRGBToLinear(out[0]);
out[1] = SRGBToLinear(out[1]);
out[2] = SRGBToLinear(out[2]);
}
}
UINT32 Convert::ColorFloatToInt32(const float* in, bool sRGB)
{
const float gamma = sRGB ? 1 / 2.2f : 1.f;
const int r = Math::Clamp(int(pow(in[0], gamma) * 255.5f), 0, 255);
const int g = Math::Clamp(int(pow(in[1], gamma) * 255.5f), 0, 255);
const int b = Math::Clamp(int(pow(in[2], gamma) * 255.5f), 0, 255);
const int a = Math::Clamp(int(in[3] * 255.5f), 0, 255);
float out[4];
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
if (sRGB)
{
out[0] = LinearToSRGB(out[0]);
out[1] = LinearToSRGB(out[1]);
out[2] = LinearToSRGB(out[2]);
}
const int r = Math::Clamp(static_cast<int>(out[0] * 255 + 0.5f), 0, 255);
const int g = Math::Clamp(static_cast<int>(out[1] * 255 + 0.5f), 0, 255);
const int b = Math::Clamp(static_cast<int>(out[2] * 255 + 0.5f), 0, 255);
const int a = Math::Clamp(static_cast<int>(out[3] * 255 + 0.5f), 0, 255);
return VERUS_COLOR_RGBA(r, g, b, a);
}
@ -140,11 +170,16 @@ void Convert::ColorTextToFloat4(CSZ sz, float* out, bool sRGB)
if (3 == count)
color[3] = 255;
}
const float gamma = sRGB ? 2.2f : 1.f;
out[0] = pow(float(color[0]) * (1 / 255.f), gamma);
out[1] = pow(float(color[1]) * (1 / 255.f), gamma);
out[2] = pow(float(color[2]) * (1 / 255.f), gamma);
out[3] = float(color[3]) * (1 / 255.f);
out[0] = color[0] * (1 / 255.f);
out[1] = color[1] * (1 / 255.f);
out[2] = color[2] * (1 / 255.f);
out[3] = color[3] * (1 / 255.f);
if (sRGB)
{
out[0] = SRGBToLinear(out[0]);
out[1] = SRGBToLinear(out[1]);
out[2] = SRGBToLinear(out[2]);
}
}
UINT32 Convert::ColorTextToInt32(CSZ sz)
@ -321,6 +356,8 @@ String Convert::ToMd5String(const Vector<BYTE>& vBin)
void Convert::Test()
{
const float e = 1e-6f;
BYTE dataUint8[] = { 0, 127, 255 };
UINT16 dataUint16[] = { 0, 127, 65535, 65534 };
char dataSint8[] = { 64, -127, -128 };
@ -336,6 +373,32 @@ void Convert::Test()
Sint16ToSnorm(dataSint16, dataFloat, 4);
SnormToSint16(dataFloat, dataSint16, 4);
BYTE colorIn[20];
VERUS_FOR(i, 16)
colorIn[i] = i;
colorIn[16] = 64;
colorIn[17] = 128;
colorIn[18] = 192;
colorIn[19] = 255;
float colorOut[20];
VERUS_FOR(i, 20)
colorOut[i] = SRGBToLinear(colorIn[i] * (1 / 255.f));
BYTE colorTest[20];
VERUS_FOR(i, 20)
colorTest[i] = static_cast<BYTE>(LinearToSRGB(colorOut[i]) * 255 + 0.5f);
VERUS_FOR(i, 20)
{
if (i < 19)
{
const float d = colorOut[i + 1] - colorOut[i];
if (i < 10)
VERUS_RT_ASSERT(glm::epsilonEqual(d, colorOut[1], e));
else
VERUS_RT_ASSERT(glm::epsilonNotEqual(d, colorOut[1], e));
}
VERUS_RT_ASSERT(colorIn[i] == colorTest[i]);
}
Vector<BYTE> vBin;
vBin.resize(16);

View file

@ -43,9 +43,11 @@ namespace verus
// 4 bits per channel:
static UINT16 Uint8x4ToUint4x4(UINT32 in);
static UINT32 Uint4x4ToUint8x4(UINT16 in);
static UINT32 Uint4x4ToUint8x4(UINT16 in, bool scaleTo255 = false);
// Colors:
static float SRGBToLinear(float color);
static float LinearToSRGB(float color);
static UINT32 Color16To32(UINT16 in);
static void ColorInt32ToFloat(UINT32 in, float* out, bool sRGB = true);
static UINT32 ColorFloatToInt32(const float* in, bool sRGB = true);

View file

@ -86,6 +86,7 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere
{
Scene::Mesh::InitStatic();
Scene::Terrain::InitStatic();
Scene::Grass::InitStatic();
//Scene::CForest::InitStatic();
}

View file

@ -7,8 +7,8 @@
#define VERUS_QREF_BLUR Effects::RBlur blur = Effects::Blur::I()
#define VERUS_QREF_BULLET Physics::RBullet bullet = Physics::Bullet::I()
#define VERUS_QREF_CONST_SETTINGS App::RcSettings settings = App::Settings::IConst()
#define VERUS_QREF_DEPTH Effects::RDepth depth = Effects::Depth::I()
#define VERUS_QREF_DD CGI::RDebugDraw dd = CGI::DebugDraw::I()
#define VERUS_QREF_DEPTH Effects::RDepth depth = Effects::Depth::I()
#define VERUS_QREF_FSYS IO::RFileSystem fsys = IO::FileSystem::I()
#define VERUS_QREF_GAME Game::RGame game = Game::Game::I()
#define VERUS_QREF_GRASS Scene::RGrass grass = Scene::Grass::I()

View file

@ -9,6 +9,18 @@ bool Math::IsPowerOfTwo(int x)
return !(x & (x - 1));
}
UINT32 Math::NextPowerOfTwo(UINT32 x)
{
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return x;
}
int Math::HighestBit(int x)
{
int bit = -1;
@ -59,6 +71,11 @@ float Math::LinearToCos(float t)
return cos(t * VERUS_PI) * -0.5f + 0.5f; // [1 to -1] -> [0 to 1].
}
float Math::EaseInOutSine(float x)
{
return -(cos(VERUS_PI * x) - 1) * 0.5f;
}
Vector3 Math::TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c)
{
return VMath::normalize(VMath::cross(a - b, a - c));
@ -77,15 +94,15 @@ float Math::TriangleArea(
return sqrt(s * (s - a) * (s - b) * (s - c));
}
int Math::GetStripGridIndexCount(int polyCountWidth, int polyCountHeight)
int Math::StripGridIndexCount(int polyCountWidth, int polyCountHeight)
{
const int vertCountWidth = polyCountWidth + 1;
return (vertCountWidth * 2) * polyCountHeight + (polyCountHeight - 1) * 2; // Strip and primitive restart values.
}
void Math::BuildStripGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices)
void Math::CreateStripGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices)
{
vIndices.resize(GetStripGridIndexCount(polyCountWidth, polyCountHeight));
vIndices.resize(StripGridIndexCount(polyCountWidth, polyCountHeight));
int offset = 0;
const int vertCountWidth = polyCountWidth + 1;
VERUS_FOR(h, polyCountHeight)
@ -114,7 +131,7 @@ void Math::BuildStripGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16
}
}
void Math::BuildListGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices)
void Math::CreateListGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices)
{
vIndices.resize(polyCountWidth * polyCountHeight * 6);
int offset = 0;
@ -148,6 +165,23 @@ void Math::BuildListGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>
}
}
bool Math::CheckIndexBuffer(Vector<UINT16>& vIndices, int maxIndex)
{
Vector<UINT16> vTemp(vIndices.begin(), vIndices.end());
std::sort(vTemp.begin(), vTemp.end());
auto itRestart = std::find(vTemp.begin(), vTemp.end(), 0xFFFF);
if (itRestart != vTemp.end())
vTemp.erase(itRestart, vTemp.end());
if (vTemp.empty())
return false;
if (vTemp.front() != 0)
return false;
if (vTemp.back() != maxIndex)
return false;
auto it = std::adjacent_find(vTemp.begin(), vTemp.end(), [](UINT16 a, UINT16 b) {return (b - a) > 1; });
return vTemp.end() == it;
}
Transform3 Math::BoundsDrawMatrix(RcPoint3 mn, RcPoint3 mx)
{
const Vector3 d = mx - mn;
@ -161,6 +195,13 @@ float Math::ComputeOnePixelDistance(float size, float screenHeight, float fovY)
return viewSliceSize / (tan(fovY * 0.5f) * 2);
}
float Math::ComputeDistToMipScale(float texSize, float screenSize, float realSize, float fovY)
{
const float fillScreenScale = screenSize / texSize;
const float a = realSize * fillScreenScale * 0.5f;
return tan(fovY * 0.5f) / a;
}
void Math::Quadrant(const int** ppSrcMinMax, int** ppDestMinMax, int half, int id)
{
VERUS_RT_ASSERT(id >= 0 && id < 4);
@ -395,7 +436,7 @@ void Math::Test()
{
Vector<UINT16> v;
BuildStripGrid(2, 2, v);
CreateStripGrid(2, 2, v);
VERUS_RT_ASSERT(v.size() == 14);
VERUS_RT_ASSERT(0 == v[0] && 3 == v[1] && 1 == v[2]); // First triangle is CCW.
}

View file

@ -48,6 +48,7 @@ namespace verus
{
// Bits:
bool IsPowerOfTwo(int x);
UINT32 NextPowerOfTwo(UINT32 x);
int HighestBit(int x);
bool IsNaN(float x);
@ -61,19 +62,22 @@ namespace verus
float SmoothStep(float a, float b, float t);
float LinearToSin(float t);
float LinearToCos(float t);
float EaseInOutSine(float x);
// Shapes:
Vector3 TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c);
float TriangleArea(const glm::vec3& p0, const glm::vec3& p1, const glm::vec3& p2);
// Geometry:
int GetStripGridIndexCount(int polyCountWidth, int polyCountHeight);
void BuildStripGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices);
void BuildListGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices);
int StripGridIndexCount(int polyCountWidth, int polyCountHeight);
void CreateStripGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices);
void CreateListGrid(int polyCountWidth, int polyCountHeight, Vector<UINT16>& vIndices);
bool CheckIndexBuffer(Vector<UINT16>& vIndices, int maxIndex);
// Scene:
Transform3 BoundsDrawMatrix(RcPoint3 mn, RcPoint3 mx);
float ComputeOnePixelDistance(float size, float screenHeight = 120, float fovY = VERUS_PI / 4);
float ComputeDistToMipScale(float texSize, float screenSize, float realSize, float fovY);
void Quadrant(const int** ppSrcMinMax, int** ppDestMinMax, int half, int id);
int ComputeMipLevels(int w, int h, int d = 1);

View file

@ -3,6 +3,11 @@
using namespace verus;
using namespace verus::Scene;
Atmosphere::UB_PerFrame Atmosphere::s_ubPerFrame;
Atmosphere::UB_PerMaterialFS Atmosphere::s_ubPerMaterialFS;
Atmosphere::UB_PerMeshVS Atmosphere::s_ubPerMeshVS;
Atmosphere::UB_PerObject Atmosphere::s_ubPerObject;
Atmosphere::Atmosphere()
{
}
@ -17,20 +22,214 @@ void Atmosphere::Init()
VERUS_INIT();
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_UTILS;
_skyDome.Init("[Models]:SkyDome.x3d");
_shader.Init("[Shaders]:Sky.hlsl");
_shader->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), 100);
_shader->CreateDescriptorSet(1, &s_ubPerMaterialFS, sizeof(s_ubPerMaterialFS), 100,
{
CGI::Sampler::aniso,
CGI::Sampler::aniso,
CGI::Sampler::aniso,
CGI::Sampler::aniso
}, CGI::ShaderStageFlags::fs);
_shader->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), 100, {}, CGI::ShaderStageFlags::vs);
_shader->CreateDescriptorSet(3, &s_ubPerObject, sizeof(s_ubPerObject), 100);
_shader->CreatePipelineLayout();
if (settings._sceneShadowQuality > App::Settings::ShadowQuality::none)
_shadowMap.Init(4096);
renderer.GetDS().InitByAtmosphere(_shadowMap.GetTexture());
_sun._dirTo = VMath::normalize(Vector3(1.3f, 1, 1.3f));
_texSky.LoadDDS("[Textures]:Sky/Sky.dds");
_tex[TEX_SKY].Init("[Textures]:Sky/Sky.dds");
_tex[TEX_STARS].Init("[Textures]:Sky/Stars.dds");
_tex[TEX_SUN].Init("[Textures]:Sky/Sun.dds");
_tex[TEX_MOON].Init("[Textures]:Sky/Moon.dds");
_tex[TEX_CLOUDS].Init("[Textures]:Sky/Clouds.FX.dds");
_tex[TEX_CLOUDS_NM].Init("[Textures]:Sky/Clouds.NM.dds");
_clouds._phaseA.setX(utils.GetRandom().NextFloat());
_clouds._phaseA.setY(utils.GetRandom().NextFloat());
_clouds._phaseB.setX(utils.GetRandom().NextFloat());
_clouds._phaseB.setY(utils.GetRandom().NextFloat());
_sun._matTilt = Matrix3::rotationX(-VERUS_PI / 10);
_sun._dirToMidnight = _sun._matTilt * Vector3(0, -1, 0);
_sun._dirTo = VMath::mulPerElem(_sun._dirToMidnight, Vector3(1, -1, 1));
}
void Atmosphere::Done()
{
_shader->FreeDescriptorSet(_cshSkyFS);
VERUS_DONE(Atmosphere);
}
void Atmosphere::UpdateSun(float time)
{
// Update time and sun's color before calling this method.
_sun._dirTo = Matrix3::rotationZ(time * VERUS_2PI) * _sun._dirToMidnight;
_night = false;
if (_sun._dirTo.getY() < 0) // Moon light:
{
_night = true;
_sun._dirTo = Matrix3::rotationZ(time * VERUS_2PI + VERUS_PI) * _sun._dirToMidnight;
_sun._color = VMath::mulPerElem(_sun._color, Vector3(0.19f, 0.21f, 0.45f));
}
// Reduce light's intensity when near horizon:
const float intensity = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1);
_sun._color *= intensity;
}
void Atmosphere::Update()
{
VERUS_QREF_RENDERER;
VERUS_QREF_TIMER;
if (!_async_loaded)
{
bool allTexLoaded = true;
VERUS_FOR(i, TEX_COUNT)
{
if (!_tex[i]->IsLoaded())
allTexLoaded = false;
}
if (_skyDome.IsLoaded() && allTexLoaded)
{
_async_loaded = true;
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_SKY].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_CLOUDS].Init(pipeDesc);
}
_shader->FreeDescriptorSet(_cshSkyFS);
_cshSkyFS = _shader->BindDescriptorSetTextures(1, { _tex[TEX_SKY], _tex[TEX_STARS], _tex[TEX_CLOUDS], _tex[TEX_CLOUDS_NM] });
}
}
if (!_async_loaded)
return;
_time = glm::fract(_time + dt * _timeSpeed);
_clouds._cloudiness.Update();
float color[3];
GetColor(64, color, 1.5f); _fog._color = Vector3::MakeFromPointer(color) * _hdrScale;
GetColor(208, color, 0.3f); _ambientColor = Vector3::MakeFromPointer(color) * _hdrScale;
GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * _hdrScale;
glm::vec3 ambientColor = _ambientColor.GLM();
glm::vec3 fogColor = _fog._color.GLM();
_ambientColor = glm::saturation(0.75f, ambientColor);
const float clearSky = Math::Min(1.f, 1.5f - _clouds._cloudiness);
_fog._color = glm::saturation(clearSky * 0.75f, fogColor);
_fog._colorInit = _fog._color;
UpdateSun(_time);
}
void Atmosphere::DrawSky()
{
if (!_async_loaded)
return;
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
auto cb = renderer.GetCommandBuffer();
RcCamera cam = *sm.GetCamera();
Matrix3 matS = Matrix3::scale(Vector3(4, 1, 4)); // Stretch sky dome.
const Matrix4 matSkyDome = cam.GetMatrixVP() * Transform3(matS, Vector3(cam.GetEyePosition()));
s_ubPerFrame._time_cloudiness_expo.x = _time;
s_ubPerFrame._time_cloudiness_expo.y = _clouds._cloudiness;
s_ubPerFrame._time_cloudiness_expo.z = 0;
s_ubPerFrame._dirToSun = float4(_sun._dirTo.GLM(), 0);
s_ubPerFrame._phaseAB = float4(
_clouds._phaseA.getX(),
_clouds._phaseA.getY(),
_clouds._phaseB.getX(),
_clouds._phaseB.getY());
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), 0);
_skyDome.CopyPosDeqScale(&s_ubPerMeshVS._posDeqScale.x);
_skyDome.CopyPosDeqBias(&s_ubPerMeshVS._posDeqBias.x);
s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat();
_skyDome.BindGeo(cb);
// <Sky>
cb->BindPipeline(_pipe[PIPE_SKY]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _cshSkyFS);
cb->BindDescriptors(_shader, 2);
cb->BindDescriptors(_shader, 3);
_shader->EndBindDescriptors();
cb->DrawIndexed(_skyDome.GetIndexCount());
// </Sky>
// <Clouds>
cb->BindPipeline(_pipe[PIPE_CLOUDS]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _cshSkyFS);
cb->BindDescriptors(_shader, 2);
cb->BindDescriptors(_shader, 3);
_shader->EndBindDescriptors();
cb->DrawIndexed(_skyDome.GetIndexCount());
// </Clouds>
}
void Atmosphere::GetColor(int level, float* pOut, float scale)
{
if (!_texSky.IsLoaded())
return;
const float texCoord = _time * 256;
const int intPartA = static_cast<int>(texCoord) & 0xFF;
const int intPartB = (intPartA + 1) & 0xFF;
const float fractPart = texCoord - intPartA;
const int offsetA = (level << 10) + (intPartA << 2);
const int offsetB = (level << 10) + (intPartB << 2);
auto LoadFromSky = [this](float rgb[3], int offset)
{
rgb[0] = Convert::SRGBToLinear(Convert::Uint8ToUnorm(_texSky.GetData()[offset + 0]));
rgb[1] = Convert::SRGBToLinear(Convert::Uint8ToUnorm(_texSky.GetData()[offset + 1]));
rgb[2] = Convert::SRGBToLinear(Convert::Uint8ToUnorm(_texSky.GetData()[offset + 2]));
};
float rgbA[3];
float rgbB[3];
LoadFromSky(rgbA, offsetA);
LoadFromSky(rgbB, offsetB);
VERUS_FOR(i, 3)
pOut[i] = Math::Clamp<float>(Math::Lerp(rgbA[i], rgbB[i], fractPart) * 0.5f * scale, 0, 1);
}
RcVector3 Atmosphere::GetDirToSun() const
{
return _sun._dirTo;

View file

@ -6,6 +6,37 @@ namespace verus
{
class Atmosphere : public Singleton<Atmosphere>, public Object
{
public:
#include "../Shaders/Sky.inc.hlsl"
enum PIPE
{
PIPE_SKY,
PIPE_CLOUDS,
PIPE_COUNT
};
enum TEX
{
TEX_SKY,
TEX_STARS,
TEX_SUN,
TEX_MOON,
TEX_CLOUDS,
TEX_CLOUDS_NM,
TEX_COUNT
};
private:
struct Clouds
{
Vector4 _phaseA = Vector4(0);
Vector4 _phaseB = Vector4(0);
float _speedPhaseA = 0.017f;
float _speedPhaseB = 0.003f;
Anim::Damping<float> _cloudiness = 0.25f;
};
struct Fog
{
Vector3 _color = Vector3(0);
@ -14,7 +45,7 @@ namespace verus
float _end = 100000;
float _startEx = 0;
float _endEx = 0;
float _density = 1 / 1500.f;
float _density = 0.0002f;
};
struct Sun
@ -25,12 +56,27 @@ namespace verus
Vector3 _color = Vector3(0);
};
static UB_PerFrame s_ubPerFrame;
static UB_PerMaterialFS s_ubPerMaterialFS;
static UB_PerMeshVS s_ubPerMeshVS;
static UB_PerObject s_ubPerObject;
CGI::ShaderPwn _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
Clouds _clouds;
Fog _fog;
Sun _sun;
Vector3 _colorAmbient = Vector3(0);
Vector3 _ambientColor = Vector3(0);
CascadedShadowMap _shadowMap;
Mesh _skyDome;
CGI::TextureRAM _texSky;
float _time = 0.5f;
float _timeSpeed = 1 / 300.f;
float _hdrScale = 1000;
CGI::CSHandle _cshSkyFS;
bool _night = false;
bool _async_loaded = false;
public:
Atmosphere();
@ -39,13 +85,28 @@ namespace verus
void Init();
void Done();
void UpdateSun(float time);
void Update();
void DrawSky();
void GetColor(int level, float* pOut, float scale);
// Time:
float GetTime() const { return _time; }
void SetTime(float x) { _time = x; }
void SetTimeSpeed(float x) { _timeSpeed = x; }
RcVector3 GetAmbientColor() const { return _ambientColor; }
// Clouds:
Anim::Damping<float>& GetCloudiness() { return _clouds._cloudiness; }
void SetCloudiness(float x) { _clouds._cloudiness = x; _clouds._cloudiness.ForceTarget(); }
// Fog:
RcVector3 GetFogColor() const { return _fog._color; }
float GetFogDensity() const { return _fog._density; }
void SetFogDensity(float d) { _fog._density = d; }
// Sun:
RcVector3 GetDirToSun() const;
RcVector3 GetSunColor() const;

View file

@ -328,7 +328,7 @@ void BaseMesh::LoadPrimaryBones()
VERUS_FOR(i, 4)
it->bi[i] = _skeleton.RemapBoneIndex(it->bi[i]);
}
BufferDataVB(_vBinding1.data(), 1);
UpdateVertexBuffer(_vBinding1.data(), 1);
}
#endif
}
@ -367,8 +367,8 @@ void BaseMesh::LoadWarp()
_vBinding2[i]._tan[3] = g * SHRT_MAX / 9;
_vBinding2[i]._bin[3] = b * SHRT_MAX / 9;
}
BufferDataVB(_vBinding0.data(), 0);
BufferDataVB(_vBinding2.data(), 2);
UpdateVertexBuffer(_vBinding0.data(), 0);
UpdateVertexBuffer(_vBinding2.data(), 2);
}
vData.clear();

View file

@ -96,7 +96,7 @@ namespace verus
// GPU:
virtual void CreateDeviceBuffers() {}
virtual void BufferDataVB(const void* p, int binding) {}
virtual void UpdateVertexBuffer(const void* p, int binding) {}
// Bounds:
void GetBounds(RPoint3 mn, RPoint3 mx) const;

488
Verus/src/Scene/Grass.cpp Normal file
View file

@ -0,0 +1,488 @@
#include "verus.h"
using namespace verus;
using namespace verus::Scene;
CGI::ShaderPwn Grass::s_shader;
Grass::UB_GrassVS Grass::s_ubGrassVS;
Grass::UB_GrassFS Grass::s_ubGrassFS;
Grass::Grass()
{
VERUS_CT_ASSERT(16 == sizeof(Vertex));
VERUS_FOR(i, 4)
{
VERUS_FOR(j, 4)
{
const char u0 = j * 25 + 1;
const char v0 = i * 25 + 1;
const char u1 = u0 + 25 - 2;
const char v1 = v0 + 25 - 2;
const int index = (i << 2) + j;
_bushTexCoords[index][0][0] = u0; _bushTexCoords[index][0][1] = v1;
_bushTexCoords[index][1][0] = u0; _bushTexCoords[index][1][1] = v0;
_bushTexCoords[index][2][0] = u1; _bushTexCoords[index][2][1] = v0;
_bushTexCoords[index][3][0] = u1; _bushTexCoords[index][3][1] = v1;
_bushTexCoords[index][4][0] = u0; _bushTexCoords[index][4][1] = v1;
_bushTexCoords[index][5][0] = u0; _bushTexCoords[index][5][1] = v0;
_bushTexCoords[index][6][0] = u1; _bushTexCoords[index][6][1] = v0;
_bushTexCoords[index][7][0] = u1; _bushTexCoords[index][7][1] = v1;
}
}
}
Grass::~Grass()
{
Done();
}
void Grass::InitStatic()
{
s_shader.Init("[Shaders]:DS_Grass.hlsl");
s_shader->CreateDescriptorSet(0, &s_ubGrassVS, sizeof(s_ubGrassVS), 100,
{
CGI::Sampler::linearMipL,
CGI::Sampler::linearMipN,
CGI::Sampler::nearestMipN,
}, CGI::ShaderStageFlags::vs);
s_shader->CreateDescriptorSet(1, &s_ubGrassFS, sizeof(s_ubGrassFS), 100,
{
CGI::Sampler::aniso
}, CGI::ShaderStageFlags::fs);
s_shader->CreatePipelineLayout();
}
void Grass::DoneStatic()
{
s_shader.Done();
}
void Grass::Init(RTerrain terrain)
{
VERUS_INIT();
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
_pTerrain = &terrain;
_bushMask = 0;
if (!Math::IsPowerOfTwo(_pTerrain->GetMapSide()))
throw VERUS_RECOVERABLE << "Init(), mapSide must be power of two";
_mapSide = _pTerrain->GetMapSide();
_mapShift = Math::HighestBit(_mapSide);
const int patchSide = _mapSide >> 4;
const int patchShift = _mapShift - 4;
const int patchCount = patchSide * patchSide;
const int maxInstances = 128 * 8;
_vPatches.resize(patchCount);
CreateBuffers();
_vInstanceBuffer.resize(maxInstances);
CGI::GeometryDesc geoDesc;
const CGI::VertexInputAttrDesc viaDesc[] =
{
{ 0, offsetof(Vertex, _pos), CGI::IeType::shorts, 4, CGI::IeUsage::position, 0},
{ 0, offsetof(Vertex, _tc), CGI::IeType::shorts, 4, CGI::IeUsage::texCoord, 0},
{-1, offsetof(PerInstanceData, _patchPos), CGI::IeType::shorts, 4, CGI::IeUsage::instData, 0},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(Vertex), sizeof(PerInstanceData), 0 };
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
_geo->CreateVertexBuffer(_vPatchMeshVB.size(), 0);
_geo->CreateVertexBuffer(maxInstances, 1);
_geo->CreateIndexBuffer(_vPatchMeshIB.size());
_geo->UpdateVertexBuffer(_vPatchMeshVB.data(), 0);
_geo->UpdateIndexBuffer(_vPatchMeshIB.data());
{
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
_pipe[PIPE_MAIN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Billboards", renderer.GetDS().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
_pipe[PIPE_BILLBOARDS].Init(pipeDesc);
}
const int texW = 1024;
const int texH = 1024;
_vTextureSubresData.clear();
_vTextureSubresData.resize(texW * texH);
CGI::TextureDesc texDesc;
texDesc._format = CGI::Format::srgbR8G8B8A8;
texDesc._width = texW;
texDesc._height = texH;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::generateMips;
_tex.Init(texDesc);
_tex->UpdateSubresource(_vTextureSubresData.data());
_tex->GenerateMips();
s_shader->FreeDescriptorSet(_cshVS);
_cshVS = s_shader->BindDescriptorSetTextures(0,
{
_pTerrain->GetHeightmapTexture(),
_pTerrain->GetNormalsTexture(),
_pTerrain->GetMainLayerTexture(),
});
s_shader->FreeDescriptorSet(_cshFS);
_cshFS = s_shader->BindDescriptorSetTextures(1,
{
_tex
});
_vMagnets.resize(16);
std::fill(_vMagnets.begin(), _vMagnets.end(), Magnet());
}
void Grass::Done()
{
s_shader->FreeDescriptorSet(_cshVS);
s_shader->FreeDescriptorSet(_cshFS);
VERUS_DONE(Grass);
}
void Grass::Update()
{
VERUS_UPDATE_ONCE_CHECK;
// Async texture loading:
VERUS_FOR(i, s_maxBushTypes)
{
if (_texLoaded[i].IsInitialized() && _texLoaded[i].IsLoaded())
OnTextureLoaded(i);
}
}
void Grass::Layout()
{
VERUS_QREF_SM;
const float zFar = sm.GetCamera()->GetZFar();
sm.GetCamera()->SetZFar(128);
sm.GetCamera()->Update();
Math::RQuadtreeIntegral quadtree = _pTerrain->GetQuadtree();
_visiblePatchCount = 0;
quadtree.SetDelegate(this);
quadtree.TraverseVisible();
quadtree.SetDelegate(_pTerrain);
sm.GetCamera()->SetZFar(zFar);
sm.GetCamera()->Update();
}
void Grass::Draw()
{
if (!_visiblePatchCount)
return;
VERUS_QREF_ATMO;
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_RT_ASSERT(_pTerrain->GetMapSide() == _mapSide);
auto cb = renderer.GetCommandBuffer();
const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(Scene::DrawDepth::automatic);
const UINT32 bushMask = _bushMask & 0xFF; // Use only first 8 bushes, next 8 are reserved.
const int half = _mapSide >> 1;
s_ubGrassVS._matW = Transform3::UniformBufferFormatIdentity();
s_ubGrassVS._matWV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubGrassVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubGrassVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubGrassVS._phase_mapSideInv_bushMask.x = _phase;
s_ubGrassVS._phase_mapSideInv_bushMask.y = 1.f / _mapSide;
s_ubGrassVS._phase_mapSideInv_bushMask.z = *(float*)&bushMask;
s_ubGrassVS._posEye = float4(atmo.GetEyePosition().GLM(), 0);
s_ubGrassVS._viewportSize = cb->GetViewportSize().GLM();
//s_ubGrassVS._wind = Vector3(VMath::normalize(atmo.GetWindVelocity()) * bendByWind);
//s_ubGrassVS._wind.w = m_shaker.Get();
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);
s_shader->BeginBindDescriptors();
cb->BindPipeline(_pipe[PIPE_BILLBOARDS]);
cb->BindDescriptors(s_shader, 0, _cshVS);
cb->BindDescriptors(s_shader, 1, _cshFS);
int pointSpriteInstCount = 0;
VERUS_FOR(i, _visiblePatchCount)
{
RcPatch patch = _vPatches[i];
if (patch.type & 0x2)
{
const int at = _instanceCount + pointSpriteInstCount;
_vInstanceBuffer[at]._patchPos[0] = patch.j - half;
_vInstanceBuffer[at]._patchPos[1] = patch.h;
_vInstanceBuffer[at]._patchPos[2] = patch.i - half;
_vInstanceBuffer[at]._patchPos[3] = 0;
pointSpriteInstCount++;
}
}
cb->Draw(_bbVertCount, pointSpriteInstCount, _vertCount, _instanceCount);
_instanceCount += pointSpriteInstCount;
cb->BindPipeline(_pipe[PIPE_MAIN]);
cb->BindDescriptors(s_shader, 0, _cshVS);
cb->BindDescriptors(s_shader, 1, _cshFS);
int meshInstCount = 0;
VERUS_FOR(i, _visiblePatchCount)
{
RcPatch patch = _vPatches[i];
if (patch.type & 0x1)
{
const int at = _instanceCount + meshInstCount;
_vInstanceBuffer[at]._patchPos[0] = patch.j - half;
_vInstanceBuffer[at]._patchPos[1] = patch.h;
_vInstanceBuffer[at]._patchPos[2] = patch.i - half;
_vInstanceBuffer[at]._patchPos[3] = 0;
meshInstCount++;
}
}
cb->DrawIndexed(_vPatchMeshIB.size(), meshInstCount, 0, 0, _instanceCount);
_instanceCount += meshInstCount;
s_shader->EndBindDescriptors();
_geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 1);
}
void Grass::ResetInstanceCount()
{
_instanceCount = 0;
}
void Grass::QuadtreeIntegral_ProcessVisibleNode(const short* ij, RcPoint3 center)
{
VERUS_QREF_ATMO;
const RcPoint3 eyePos = atmo.GetEyePosition();
const float distSq = VMath::distSqr(eyePos, center);
if (distSq >= 128 * 128.f)
return;
Patch patch;
patch.i = ij[0];
patch.j = ij[1];
patch.h = center.getY() * 100;
patch.type = 0;
if (distSq <= 64 * 64.f)
patch.type |= 0x1;
if (distSq >= 16 * 16.f)
patch.type |= 0x2;
_vPatches[_visiblePatchCount++] = patch;
}
void Grass::QuadtreeIntegral_GetHeights(const short* ij, float height[2])
{
VERUS_RT_FAIL(__FUNCTION__);
}
void Grass::CreateBuffers()
{
VERUS_QREF_CONST_SETTINGS;
const int density = settings._sceneGrassDensity;
const int side = static_cast<int>(sqrt(float(density)));
const int count = side * side;
const float step = 16.f / side;
Random random(9052);
auto RandomStep = [&random, step]()
{
return (0.1f + 0.8f * random.NextFloat()) * step;
};
auto RandomScale = [&random]()
{
return random.NextFloat() * 0.4f;
};
static const Point3 bushVerts[8] =
{
Point3(-0.5f, 0.f, 0.f), // A (0)
Point3(-0.5f, 1.f, 0.f), // B (1)
Point3(+0.5f, 1.f, 0.f), // C (2)
Point3(+0.5f, 0.f, 0.f), // D (3)
Point3(0.f, 0.f, -0.5f), // A2 (4)
Point3(0.f, 1.f, -0.5f), // B2 (5)
Point3(0.f, 1.f, +0.5f), // C2 (6)
Point3(0.f, 0.f, +0.5f) // D2 (7)
};
static const UINT16 bushIndices[12] =
{
1, 0, 2,
2, 0, 3,
5, 6, 4,
4, 6, 7
};
struct Bush
{
float _x, _z;
Point3 _vertPos[8];
float _phaseShift;
};
Vector<Bush> vBushes;
vBushes.reserve(count);
VERUS_FOR(i, side)
{
VERUS_FOR(j, side)
{
const Point3 bushPos(
j * step + RandomStep(),
0,
i * step + RandomStep());
const Vector3 scale(
0.8f + RandomScale(),
0.8f + RandomScale(),
0.8f + RandomScale());
const float phaseSin =
sin(bushPos.getX() * (VERUS_2PI / 16)) *
sin(bushPos.getZ() * (VERUS_2PI / 16)) * 0.5f + 0.5f;
const float phase = phaseSin * 0.75f + random.NextFloat() * 0.25f;
const float angle = random.NextFloat() * VERUS_2PI;
const Matrix3 matR = Matrix3::rotationY(angle);
const Transform3 tr = VMath::appendScale(Transform3(matR, Vector3(bushPos)), scale);
Bush bush;
bush._x = bushPos.getX();
bush._z = bushPos.getZ();
VERUS_FOR(k, 8)
bush._vertPos[k] = tr * bushVerts[k];
bush._phaseShift = phase;
vBushes.push_back(bush);
}
}
std::shuffle(vBushes.begin(), vBushes.end(), random.GetGenerator());
const int indexedMeshVertCount = count * 8;
_vertCount = 0;
_bbVertCount = 0;
_vPatchMeshVB.clear();
_vPatchMeshVB.resize(indexedMeshVertCount + count);
_vPatchMeshIB.clear();
_vPatchMeshIB.reserve(count * 12);
for (const auto& bush : vBushes)
{
const int indexOffset = _vertCount;
VERUS_FOR(i, 8)
{
Vertex vertex;
vertex._pos[0] = static_cast<short>(bush._vertPos[i].getX() * 1000);
vertex._pos[1] = static_cast<short>(bush._vertPos[i].getY() * 1000);
vertex._pos[2] = static_cast<short>(bush._vertPos[i].getZ() * 1000);
vertex._pos[3] = bush._phaseShift * 99;
vertex._tc[0] = _bushTexCoords[0][i][0];
vertex._tc[1] = _bushTexCoords[0][i][1];
vertex._tc[2] = static_cast<short>(bush._x * 1000);
vertex._tc[3] = static_cast<short>(bush._z * 1000);
_vPatchMeshVB[_vertCount++] = vertex;
if (1 == i) // Index with top-left tex coords:
{
const int offset = indexedMeshVertCount + _bbVertCount;
_vPatchMeshVB[offset] = vertex;
_bbVertCount++;
}
}
VERUS_FOR(i, 12)
_vPatchMeshIB.push_back(bushIndices[i] + indexOffset);
}
}
void Grass::ResetAllTextures()
{
_bushMask = 0;
}
void Grass::SetTexture(int layer, CSZ url, CSZ url2)
{
VERUS_RT_ASSERT(url);
_texLoaded[layer].LoadDDS(url);
if (layer < 8)
SetTexture(layer + 8, url2 ? url2 : url);
}
void Grass::OnTextureLoaded(int layer)
{
VERUS_QREF_RENDERER;
const int srcW = 256;
const int srcH = 256;
const int dstW = 1024;
const int xFrom = (layer & 0x3) << 8;
const int yFrom = (layer >> 2) << 8;
const UINT32* pSrc = reinterpret_cast<const UINT32*>(_texLoaded[layer].GetData());
VERUS_FOR(y, srcH)
{
const int ySrcOffset = y * srcW;
const int yDstOffset = (yFrom + y) * dstW;
memcpy(_vTextureSubresData.data() + yDstOffset + xFrom, pSrc + ySrcOffset, srcW * sizeof(UINT32));
}
_texLoaded[layer].Done();
_tex->UpdateSubresource(_vTextureSubresData.data());
_tex->GenerateMips();
_bushMask |= (1 << layer);
}
int Grass::BeginMagnet(RcPoint3 pos, float radius)
{
const int count = _vMagnets.size();
VERUS_FOR(i, count)
{
if (!_vMagnets[i]._active)
{
_vMagnets[i]._active = true;
_vMagnets[i]._pos = pos;
_vMagnets[i]._radius = radius;
_vMagnets[i]._radiusSq = radius * radius;
_vMagnets[i]._radiusSqInv = 1 / _vMagnets[i]._radiusSq;
_vMagnets[i]._strength = 0.5f;
return i;
}
}
return -1;
}
void Grass::EndMagnet(int index)
{
_vMagnets[index]._active = false;
}
void Grass::UpdateMagnet(int index, RcPoint3 pos, float radius)
{
_vMagnets[index]._active = true;
_vMagnets[index]._pos = pos;
if (radius)
{
_vMagnets[index]._radius = radius;
_vMagnets[index]._radiusSq = radius * radius;
_vMagnets[index]._radiusSqInv = 1 / _vMagnets[index]._radiusSq;
}
}

114
Verus/src/Scene/Grass.h Normal file
View file

@ -0,0 +1,114 @@
#pragma once
namespace verus
{
namespace Scene
{
class Grass : public Object, public Math::QuadtreeIntegralDelegate
{
public:
#include "../Shaders/DS_Grass.inc.hlsl"
enum PIPE
{
PIPE_MAIN,
PIPE_BILLBOARDS,
PIPE_COUNT
};
struct Vertex
{
short _pos[4]; // {xyz, phaseShift}.
short _tc[4]; // {tc0, center.xz}.
};
VERUS_TYPEDEFS(Vertex);
struct PerInstanceData
{
short _patchPos[4];
};
VERUS_TYPEDEFS(PerInstanceData);
struct Patch
{
short i;
short j;
short h;
short type;
};
VERUS_TYPEDEFS(Patch);
class Magnet
{
public:
Point3 _pos;
float _radius = 1;
float _radiusSq = 1;
float _radiusSqInv = 1;
float _strength = 1;
bool _active = false;
};
VERUS_TYPEDEFS(Magnet);
static const int s_maxBushTypes = 16;
private:
static CGI::ShaderPwn s_shader;
static UB_GrassVS s_ubGrassVS;
static UB_GrassFS s_ubGrassFS;
CGI::GeometryPwn _geo;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwn _tex;
CGI::TextureRAM _texLoaded[s_maxBushTypes];
PTerrain _pTerrain = nullptr;
Vector<Vertex> _vPatchMeshVB;
Vector<UINT16> _vPatchMeshIB;
Vector<PerInstanceData> _vInstanceBuffer;
Vector<UINT32> _vTextureSubresData;
Vector<Patch> _vPatches;
Vector<Magnet> _vMagnets;
int _mapSide = 0;
int _mapShift = 0;
int _vertCount = 0;
int _bbVertCount = 0;
int _instanceCount = 0;
int _visiblePatchCount = 0;
CGI::CSHandle _cshVS;
CGI::CSHandle _cshFS;
char _bushTexCoords[s_maxBushTypes][8][2];
UINT32 _bushMask = 0;
float _phase = 0;
public:
Grass();
~Grass();
static void InitStatic();
static void DoneStatic();
void Init(RTerrain terrain);
void Done();
void Update();
void Layout();
void Draw();
void ResetInstanceCount();
virtual void QuadtreeIntegral_ProcessVisibleNode(const short* ij, RcPoint3 center) override;
virtual void QuadtreeIntegral_GetHeights(const short* ij, float height[2]) override;
VERUS_P(void CreateBuffers());
void ResetAllTextures();
void SetTexture(int layer, CSZ url, CSZ url2 = nullptr);
VERUS_P(void OnTextureLoaded(int layer));
int BeginMagnet(RcPoint3 pos, float radius);
void EndMagnet(int index);
void UpdateMagnet(int index, RcPoint3 pos, float radius = 0);
};
VERUS_TYPEDEFS(Grass);
}
}

View file

@ -14,7 +14,7 @@ Texture::~Texture()
Done();
}
void Texture::Init(CSZ url, bool streamParts, bool sync)
void Texture::Init(CSZ url, bool streamParts, bool sync, CGI::PcSamplerDesc pSamplerDesc)
{
if (_refCount)
return;
@ -26,6 +26,7 @@ void Texture::Init(CSZ url, bool streamParts, bool sync)
CGI::TextureDesc texDesc;
texDesc._url = url;
texDesc._texturePart = _streamParts ? 512 : 0;
texDesc._pSamplerDesc = pSamplerDesc;
if (sync)
texDesc._flags = CGI::TextureDesc::Flags::sync;
_texTiny.Init(texDesc);
@ -81,12 +82,12 @@ void Texture::Update()
// TexturePtr:
void TexturePtr::Init(CSZ url, bool streamParts, bool sync)
void TexturePtr::Init(CSZ url, bool streamParts, bool sync, CGI::PcSamplerDesc pSamplerDesc)
{
VERUS_QREF_MM;
VERUS_RT_ASSERT(!_p);
_p = mm.InsertTexture(url);
_p->Init(url, streamParts, sync);
_p->Init(url, streamParts, sync, pSamplerDesc);
}
void TexturePwn::Done()
@ -368,9 +369,10 @@ void Material::FromString(CSZ txt)
void Material::BindDescriptorSetTextures()
{
VERUS_RT_ASSERT(-1 == _csh);
VERUS_RT_ASSERT(!_csh.IsSet());
VERUS_RT_ASSERT(IsLoaded());
_csh = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex() });
VERUS_QREF_MM;
_csh = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
}
bool Material::UpdateMeshUniformBuffer(float motionBlur)
@ -449,12 +451,23 @@ void MaterialManager::Init()
void MaterialManager::InitCmd()
{
CGI::SamplerDesc strassSamplerDesc;
strassSamplerDesc.SetFilter("a");
strassSamplerDesc.SetAddressMode("rr");
strassSamplerDesc._mipLodBias = -2;
_texDefaultAlbedo.Init("[Textures]:Default.dds", false, true);
_texDefaultNormal.Init("[Textures]:Default.NM.dds", false, true);
//_texDetail.Init("[Textures]:Detail.FX.dds");
//_texStrass.Init("[Textures]:Strass.dds");
_texDetail.Init("[Textures]:Detail.FX.dds", false, true);
_texStrass.Init("[Textures]:Strass.dds", false, true, &strassSamplerDesc);
_cshDefault = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1, { _texDefaultAlbedo->GetTex(), _texDefaultNormal->GetTex() });
_cshDefault = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1,
{
_texDefaultAlbedo->GetTex(),
_texDefaultNormal->GetTex(),
_texDetail->GetTex(),
_texStrass->GetTex()
});
}
void MaterialManager::Done()

View file

@ -17,7 +17,7 @@ namespace verus
Texture();
~Texture();
void Init(CSZ url, bool streamParts = false, bool sync = false);
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
bool Done();
void AddRef() { _refCount++; }
@ -33,7 +33,7 @@ namespace verus
class TexturePtr : public Ptr<Texture>
{
public:
void Init(CSZ url, bool streamParts = false, bool sync = false);
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
};
VERUS_TYPEDEFS(TexturePtr);
@ -127,7 +127,7 @@ namespace verus
glm::vec4 _userColor = glm::vec4(0, 0, 0, 0);
Pick _userPick;
Blending _blending = Blending::opaque;
int _csh = -1;
CGI::CSHandle _csh;
int _refCount = 0;
Material();
@ -152,7 +152,7 @@ namespace verus
void FromString(CSZ txt);
// Mesh interaction:
int GetComplexSetHandle() const { return _csh; }
CGI::CSHandle GetComplexSetHandle() const { return _csh; }
void BindDescriptorSetTextures();
bool UpdateMeshUniformBuffer(float motionBlur = 1);
@ -183,7 +183,7 @@ namespace verus
TexturePwn _texDefaultNormal;
TexturePwn _texDetail;
TexturePwn _texStrass;
int _cshDefault = -1; // For missing, non-mandatory materials.
CGI::CSHandle _cshDefault; // For missing, non-mandatory materials.
public:
MaterialManager();
@ -200,7 +200,7 @@ namespace verus
CGI::TexturePtr GetDetailTexture() { return _texDetail->GetTex(); }
CGI::TexturePtr GetStrassTexture() { return _texStrass->GetTex(); }
int GetDefaultComplexSetHandle() const { return _cshDefault; }
CGI::CSHandle GetDefaultComplexSetHandle() const { return _cshDefault; }
// Textures:
PTexture InsertTexture(CSZ url);

View file

@ -4,7 +4,7 @@ using namespace verus;
using namespace verus::Scene;
CGI::ShaderPwn Mesh::s_shader;
CGI::PipelinePwns<Mesh::PIPE_MAX> Mesh::s_pipe;
CGI::PipelinePwns<Mesh::PIPE_COUNT> Mesh::s_pipe;
Mesh::UB_PerFrame Mesh::s_ubPerFrame;
Mesh::UB_PerMaterialFS Mesh::s_ubPerMaterialFS;
@ -28,11 +28,13 @@ void Mesh::InitStatic()
VERUS_QREF_CONST_SETTINGS;
s_shader.Init("[Shaders]:DS_Mesh.hlsl");
s_shader->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity);
s_shader->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity, {}, CGI::ShaderStageFlags::vs_hs_ds_fs);
s_shader->CreateDescriptorSet(1, &s_ubPerMaterialFS, sizeof(s_ubPerMaterialFS), settings.GetLimits()._mesh_ubPerMaterialFSCapacity,
{
CGI::Sampler::aniso,
CGI::Sampler::aniso
CGI::Sampler::aniso,
CGI::Sampler::aniso,
CGI::Sampler::custom
}, CGI::ShaderStageFlags::fs);
s_shader->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings.GetLimits()._mesh_ubPerMeshVSCapacity, {}, CGI::ShaderStageFlags::vs);
s_shader->CreateDescriptorSet(3, &s_ubSkeletonVS, sizeof(s_ubSkeletonVS), settings.GetLimits()._mesh_ubSkinningVSCapacity, {}, CGI::ShaderStageFlags::vs);
@ -69,29 +71,92 @@ void Mesh::Done()
void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
{
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_ATMO;
if (!settings._gpuTessellation) // Fallback:
{
switch (pipe)
{
case PIPE_TESS: pipe = PIPE_MAIN; break;
case PIPE_TESS_ROBOTIC: pipe = PIPE_ROBOTIC; break;
case PIPE_TESS_SKINNED: pipe = PIPE_SKINNED; break;
};
}
if (!s_pipe[pipe])
{
static CSZ branches[] =
{
"#",
"#Robotic",
"#Skinned",
"#Instanced",
"#Depth",
"#DepthRobotic",
"#DepthSkinned",
"#Instanced",
"#Robotic",
"#Skinned"
"#Tess",
"#TessRobotic",
"#TessSkinned",
"#SolidColor",
"#SolidColorRobotic",
"#SolidColorSkinned",
};
CGI::PipelineDesc pipeDesc(_geo, s_shader, branches[pipe], renderer.GetDS().GetRenderPassHandle());
switch (pipe)
auto SetBlendEqsForDS = [&pipeDesc]()
{
case PIPE_DEPTH_ROBOTIC:
case PIPE_DEPTH_SKINNED:
pipeDesc._colorAttachBlendEqs[0] = "";
pipeDesc.EnableDepthBias();
default:
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
};
switch (pipe)
{
case PIPE_MAIN:
case PIPE_ROBOTIC:
case PIPE_SKINNED:
{
SetBlendEqsForDS();
}
break;
case PIPE_DEPTH:
case PIPE_DEPTH_ROBOTIC:
case PIPE_DEPTH_SKINNED:
{
pipeDesc._colorAttachBlendEqs[0] = "";
pipeDesc._renderPassHandle = atmo.GetShadowMap().GetRenderPassHandle();
}
break;
case PIPE_TESS:
case PIPE_TESS_ROBOTIC:
case PIPE_TESS_SKINNED:
{
SetBlendEqsForDS();
if (settings._gpuTessellation)
pipeDesc._topology = CGI::PrimitiveTopology::patchList3;
}
break;
case PIPE_WIREFRAME:
case PIPE_WIREFRAME_ROBOTIC:
case PIPE_WIREFRAME_SKINNED:
{
SetBlendEqsForDS();
pipeDesc._rasterizationState._polygonMode = CGI::PolygonMode::line;
pipeDesc._rasterizationState._depthBiasEnable = true;
pipeDesc._rasterizationState._depthBiasConstantFactor = -1000;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
}
break;
default:
{
SetBlendEqsForDS();
}
}
pipeDesc._vertexInputBindingsFilter = _bindingsMask;
s_pipe[pipe].Init(pipeDesc);
@ -99,6 +164,29 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
cb->BindPipeline(s_pipe[pipe]);
}
void Mesh::BindPipeline(CGI::CommandBufferPtr cb, bool allowTess)
{
VERUS_QREF_ATMO;
if (_skeleton.IsInitialized())
{
if (atmo.GetShadowMap().IsRendering())
BindPipeline(Scene::Mesh::PIPE_DEPTH_SKINNED, cb);
else if (allowTess)
BindPipeline(Scene::Mesh::PIPE_TESS_SKINNED, cb);
else
BindPipeline(Scene::Mesh::PIPE_SKINNED, cb);
}
else
{
if (atmo.GetShadowMap().IsRendering())
BindPipeline(Scene::Mesh::PIPE_DEPTH, cb);
else if (allowTess)
BindPipeline(Scene::Mesh::PIPE_TESS, cb);
else
BindPipeline(Scene::Mesh::PIPE_MAIN, cb);
}
}
void Mesh::BindGeo(CGI::CommandBufferPtr cb)
{
BindGeo(cb, _bindingsMask);
@ -112,10 +200,12 @@ void Mesh::BindGeo(CGI::CommandBufferPtr cb, UINT32 bindingsFilter)
void Mesh::UpdateUniformBufferPerFrame()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubPerFrame._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubPerFrame._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubPerFrame._viewportSize = renderer.GetCommandBuffer()->GetViewportSize().GLM();
}
void Mesh::UpdateUniformBufferPerMaterialFS()
@ -144,17 +234,17 @@ void Mesh::UpdateUniformBufferSkeletonVS()
_skeleton.UpdateUniformBufferArray(s_ubSkeletonVS._vMatBones);
}
void Mesh::UpdateUniformBufferPerObject(RcTransform3 tr)
void Mesh::UpdateUniformBufferPerObject(RcTransform3 tr, RcVector4 color)
{
s_ubPerObject._matW = tr.UniformBufferFormat();
s_ubPerObject._userColor = Vector4(1, 0, 0, 1).GLM();
s_ubPerObject._userColor = color.GLM();
}
void Mesh::UpdateUniformBufferPerObject(Point3 pos)
void Mesh::UpdateUniformBufferPerObject(Point3 pos, RcVector4 color)
{
const Transform3 matT = Transform3::translation(Vector3(pos));
s_ubPerObject._matW = matT.UniformBufferFormat();
s_ubPerObject._userColor = Vector4(1, 0, 0, 1).GLM();
s_ubPerObject._userColor = color.GLM();
}
void Mesh::CreateDeviceBuffers()
@ -162,25 +252,25 @@ void Mesh::CreateDeviceBuffers()
_bindingsMask = 0;
CGI::GeometryDesc geoDesc;
const CGI::InputElementDesc ied[] =
const CGI::VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(VertexInputBinding0, _pos), CGI::IeType::shorts, 4, CGI::IeUsage::position, 0},
{0, offsetof(VertexInputBinding0, _tc0), CGI::IeType::shorts, 2, CGI::IeUsage::texCoord, 0},
{0, offsetof(VertexInputBinding0, _nrm), CGI::IeType::ubytes, 4, CGI::IeUsage::normal, 0},
{1, offsetof(VertexInputBinding1, _bw), CGI::IeType::shorts, 4, CGI::IeUsage::texCoord, 4},
{1, offsetof(VertexInputBinding1, _bi), CGI::IeType::shorts, 4, CGI::IeUsage::texCoord, 5},
{2, offsetof(VertexInputBinding2, _tan), CGI::IeType::shorts, 4, CGI::IeUsage::tangent, 6},
{2, offsetof(VertexInputBinding2, _bin), CGI::IeType::shorts, 4, CGI::IeUsage::binormal, 7},
{1, offsetof(VertexInputBinding1, _bw), CGI::IeType::shorts, 4, CGI::IeUsage::blendWeights, 0},
{1, offsetof(VertexInputBinding1, _bi), CGI::IeType::shorts, 4, CGI::IeUsage::blendIndices, 0},
{2, offsetof(VertexInputBinding2, _tan), CGI::IeType::shorts, 4, CGI::IeUsage::tangent, 0},
{2, offsetof(VertexInputBinding2, _bin), CGI::IeType::shorts, 4, CGI::IeUsage::binormal, 0},
{3, offsetof(VertexInputBinding3, _tc1), CGI::IeType::shorts, 2, CGI::IeUsage::texCoord, 1},
{3, offsetof(VertexInputBinding3, _clr), CGI::IeType::ubytes, 4, CGI::IeUsage::color, 0},
{-4, offsetof(PerInstanceData, _matPart0), CGI::IeType::floats, 4, CGI::IeUsage::texCoord, 8},
{-4, offsetof(PerInstanceData, _matPart1), CGI::IeType::floats, 4, CGI::IeUsage::texCoord, 9},
{-4, offsetof(PerInstanceData, _matPart2), CGI::IeType::floats, 4, CGI::IeUsage::texCoord, 10},
{-4, offsetof(PerInstanceData, _instData), CGI::IeType::floats, 4, CGI::IeUsage::texCoord, 11},
CGI::InputElementDesc::End()
{-4, offsetof(PerInstanceData, _matPart0), CGI::IeType::floats, 4, CGI::IeUsage::instData, 0},
{-4, offsetof(PerInstanceData, _matPart1), CGI::IeType::floats, 4, CGI::IeUsage::instData, 1},
{-4, offsetof(PerInstanceData, _matPart2), CGI::IeType::floats, 4, CGI::IeUsage::instData, 2},
{-4, offsetof(PerInstanceData, _instData), CGI::IeType::floats, 4, CGI::IeUsage::instData, 3},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pInputElementDesc = ied;
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(VertexInputBinding0), sizeof(VertexInputBinding1), sizeof(VertexInputBinding2), sizeof(VertexInputBinding3), sizeof(PerInstanceData), 0 };
geoDesc._pStrides = strides;
geoDesc._32BitIndices = _vIndices.empty();
@ -236,7 +326,7 @@ void Mesh::CreateDeviceBuffers()
}
}
void Mesh::BufferDataVB(const void* p, int binding)
void Mesh::UpdateVertexBuffer(const void* p, int binding)
{
_geo->UpdateVertexBuffer(p, binding);
}

View file

@ -12,12 +12,24 @@ namespace verus
enum PIPE
{
PIPE_MAIN,
PIPE_DEPTH_ROBOTIC,
PIPE_DEPTH_SKINNED,
PIPE_INSTANCED,
PIPE_ROBOTIC,
PIPE_SKINNED,
PIPE_MAX
PIPE_INSTANCED,
PIPE_DEPTH,
PIPE_DEPTH_ROBOTIC,
PIPE_DEPTH_SKINNED,
PIPE_TESS,
PIPE_TESS_ROBOTIC,
PIPE_TESS_SKINNED,
PIPE_WIREFRAME,
PIPE_WIREFRAME_ROBOTIC,
PIPE_WIREFRAME_SKINNED,
PIPE_COUNT
};
struct PerInstanceData
@ -30,7 +42,7 @@ namespace verus
private:
static CGI::ShaderPwn s_shader;
static CGI::PipelinePwns<PIPE_MAX> s_pipe;
static CGI::PipelinePwns<PIPE_COUNT> s_pipe;
static UB_PerFrame s_ubPerFrame;
static UB_PerMaterialFS s_ubPerMaterialFS;
static UB_PerMeshVS s_ubPerMeshVS;
@ -64,6 +76,7 @@ namespace verus
void Done();
void BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb);
void BindPipeline(CGI::CommandBufferPtr cb, bool allowTess = true);
void BindGeo(CGI::CommandBufferPtr cb);
void BindGeo(CGI::CommandBufferPtr cb, UINT32 bindingsFilter);
@ -73,12 +86,12 @@ namespace verus
void UpdateUniformBufferPerMaterialFS();
void UpdateUniformBufferPerMeshVS();
void UpdateUniformBufferSkeletonVS();
void UpdateUniformBufferPerObject(RcTransform3 tr);
void UpdateUniformBufferPerObject(Point3 pos);
void UpdateUniformBufferPerObject(RcTransform3 tr, RcVector4 color = Vector4(0.5f, 0.5f, 0.5f, 1));
void UpdateUniformBufferPerObject(Point3 pos, RcVector4 color = Vector4(0.5f, 0.5f, 0.5f, 1));
CGI::GeometryPtr GetGeometry() const { return _geo; }
virtual void CreateDeviceBuffers() override;
virtual void BufferDataVB(const void* p, int binding) override;
virtual void UpdateVertexBuffer(const void* p, int binding) override;
// Instancing:
void PushInstance(RcTransform3 matW, RcVector4 instData);

View file

@ -8,9 +8,11 @@ namespace verus
Scene::MaterialManager::Make();
Scene::SceneManager::Make();
Scene::Atmosphere::Make();
Scene::Water::Make();
}
void Free_Scene()
{
Scene::Water::Free();
Scene::Atmosphere::Free();
Scene::SceneManager::Free();
Scene::MaterialManager::Free();

View file

@ -6,8 +6,10 @@
#include "Mesh.h"
#include "Terrain.h"
#include "EditorTerrain.h"
#include "Grass.h"
#include "ShadowMap.h"
#include "Atmosphere.h"
#include "Water.h"
#include "MaterialManager.h"
#include "SceneManager.h"
#include "Helpers.h"

View file

@ -24,24 +24,17 @@ void ShadowMap::Init(int side)
_side = side;
_rp = renderer->CreateRenderPass(
{
CGI::RP::Attachment("Depth", CGI::Format::unormD16).LoadOpClear().Layout(CGI::ImageLayout::depthStencilReadOnly),
},
{
CGI::RP::Subpass("Sp0").Color({}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment)),
},
{});
_rph = renderer->CreateShadowRenderPass(CGI::Format::unormD24uintS8);
CGI::TextureDesc texDesc;
texDesc._clearValue = Vector4(1);
texDesc._format = CGI::Format::unormD16;
texDesc._format = CGI::Format::unormD24uintS8;
texDesc._width = _side;
texDesc._height = _side;
texDesc._flags = CGI::TextureDesc::Flags::depthSampled;
texDesc._flags = CGI::TextureDesc::Flags::depthSampledR;
_tex.Init(texDesc);
_fb = renderer->CreateFramebuffer(_rp,
_fbh = renderer->CreateFramebuffer(_rph,
{
_tex
},
@ -61,9 +54,9 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar)
const Vector3 up(0, 1, 0);
Point3 eye, at;
const float size = 4096 * 0.01f;
const float size = 4096 * 0.005f;
if (0 == zFar)
zFar = 0x10000 * 0.005f;
zFar = 1001;
at = sm.GetCamera()->GetEyePosition() + sm.GetCamera()->GetFrontDirection() * (size * (1 / 3.f));
if (_snapToTexels)
@ -77,7 +70,7 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar)
atPosShadowSpaceSnapped.setY(atPosShadowSpaceSnapped.getY() - fmod(static_cast<float>(atPosShadowSpaceSnapped.getY()), texelSize));
at = (matFromShadowSpace * atPosShadowSpaceSnapped).getXYZ();
}
eye = at + dirToSun * ((zNear + zFar) * 0.5f);
eye = at + dirToSun * ((zFar - zNear) * 0.5f);
// Setup light space camera and use it (used for terrain draw, etc.):
_camera.SetUpDirection(up);
@ -91,9 +84,9 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar)
_camera.Update();
_pSceneCamera = sm.SetCamera(&_camera);
_config.setX((zFar - zNear) * 2);
_config._penumbraScale = (zFar - zNear) * 2;
renderer.GetCommandBuffer()->BeginRenderPass(_rp, _fb,
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex->GetClearValue()
});
@ -199,25 +192,20 @@ void CascadedShadowMap::Init(int side)
VERUS_QREF_RENDERER;
_side = side;
if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra)
_side *= 2;
_rp = renderer->CreateRenderPass(
{
CGI::RP::Attachment("Depth", CGI::Format::floatD32).LoadOpClear().Layout(CGI::ImageLayout::depthStencilReadOnly),
},
{
CGI::RP::Subpass("Sp0").Color({}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment)),
},
{});
_rph = renderer->CreateShadowRenderPass(CGI::Format::unormD24uintS8);
CGI::TextureDesc texDesc;
texDesc._clearValue = Vector4(1);
texDesc._format = CGI::Format::floatD32;
texDesc._format = CGI::Format::unormD24uintS8;
texDesc._width = _side;
texDesc._height = _side;
texDesc._flags = CGI::TextureDesc::Flags::depthSampled;
texDesc._flags = CGI::TextureDesc::Flags::depthSampledR;
_tex.Init(texDesc);
_fb = renderer->CreateFramebuffer(_rp,
_fbh = renderer->CreateFramebuffer(_rph,
{
_tex
},
@ -251,12 +239,14 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
const Vector3 up(0, 1, 0);
Point3 eye, at;
int sideW, sideH, side;
float sizeW, sizeH;
float zNearFrustum, zFarFrustum;
const float closerToLight = 10000;
const float closerToLight = 1500;
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
const float range = Math::Min(1000.f, cam.GetZFar() - cam.GetZNear()); // Clip terrain, etc.
const float maxRange = (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra) ? 850 : 350;
const float range = Math::Min<float>(maxRange, cam.GetZFar() - cam.GetZNear()); // Clip terrain, etc.
_camera = cam;
if (0 == _currentSplit)
@ -277,8 +267,10 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
if (0 == zFar)
zFar = abs(zFarFrustum - zNearFrustum) + closerToLight;
sizeW = static_cast<float>(int(frustumBounds.getZ() - frustumBounds.getX() + 0.5f) + 2);
sizeH = static_cast<float>(int(frustumBounds.getW() - frustumBounds.getY() + 0.5f) + 2);
sideW = static_cast<int>(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
sideH = static_cast<int>(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
sizeW = sideW;
sizeH = sideH;
// Setup CSM light space camera for full range (used for terrain layout, etc.):
_cameraCSM.SetUpDirection(up);
@ -327,14 +319,26 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
(frustumBounds.getY() + frustumBounds.getW()) * 0.5f,
zNearFrustum);
sizeW = static_cast<float>(int(frustumBounds.getZ() - frustumBounds.getX() + 0.5f) + 2);
sizeH = static_cast<float>(int(frustumBounds.getW() - frustumBounds.getY() + 0.5f) + 2);
sideW = static_cast<int>(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
sideH = static_cast<int>(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
if (_currentSplit < 3)
{
side = (sideW < sideH) ? sideH : sideW;
side = Math::NextPowerOfTwo(side);
sizeW = side;
sizeH = side;
}
else
{
sizeW = sideW;
sizeH = sideH;
}
if (_snapToTexels)
{
const float sideInv = 2.f / _side;
pos.setX(pos.getX() - fmod(static_cast<float>(pos.getX()), sizeW* sideInv));
pos.setY(pos.getY() - fmod(static_cast<float>(pos.getY()), sizeH* sideInv));
pos.setX(pos.getX() - fmod(static_cast<float>(pos.getX()), sizeW * sideInv));
pos.setY(pos.getY() - fmod(static_cast<float>(pos.getY()), sizeH * sideInv));
}
pos = (VMath::orthoInverse(matToLightSpace) * pos).getXYZ(); // To world space.
@ -357,11 +361,11 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
_camera.Update();
_pSceneCamera = sm.SetCamera(&_camera);
_config.setX((zFar - zNear) * 2);
_config._penumbraScale = (zFar - zNear) * 2;
if (0 == _currentSplit)
{
renderer.GetCommandBuffer()->BeginRenderPass(_rp, _fb,
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex->GetClearValue()
});

View file

@ -6,16 +6,26 @@ namespace verus
{
class ShadowMap : public Object
{
public:
struct Config
{
float _penumbraScale = 0;
float _penumbraLamBiasScale = 2.5f;
float _normalDepthBias = 0.012f;
float _csmContrastScale = 2.8f;
};
VERUS_TYPEDEFS(Config);
protected:
Matrix4 _matShadow;
Matrix4 _matShadowDS;
Vector4 _config = Vector4(0);
Config _config;
CGI::TexturePwn _tex;
Camera _camera;
PCamera _pSceneCamera = nullptr;
int _side = 0;
int _rp = -1;
int _fb = -1;
CGI::RPHandle _rph;
CGI::FBHandle _fbh;
bool _snapToTexels = true;
bool _rendering = false;
@ -29,7 +39,7 @@ namespace verus
void SetSnapToTexels(bool b) { _snapToTexels = b; }
bool IsRendering() const { return _rendering; }
int GetRenderPassHandle() const { return _rp; }
CGI::RPHandle GetRenderPassHandle() const { return _rph; }
void Begin(RcVector3 dirToSun, float zNear = 1, float zFar = 0);
void BeginLight(RcPoint3 pos, RcPoint3 target, float side = 10);
@ -38,7 +48,7 @@ namespace verus
RcMatrix4 GetShadowMatrix() const;
RcMatrix4 GetShadowMatrixDS() const;
RcVector4 GetConfig() { return _config; }
RConfig GetConfig() { return _config; }
CGI::TexturePtr GetTexture() const;

View file

@ -3,9 +3,11 @@
using namespace verus;
using namespace verus::Scene;
CGI::ShaderPwn Terrain::s_shader;
Terrain::UB_DrawDepth Terrain::s_ubDrawDepth;
Terrain::UB_PerMaterialFS Terrain::s_ubPerMaterialFS;
CGI::ShaderPwns<Terrain::SHADER_COUNT> Terrain::s_shader;
Terrain::UB_TerrainVS Terrain::s_ubTerrainVS;
Terrain::UB_TerrainFS Terrain::s_ubTerrainFS;
Terrain::UB_SimpleTerrainVS Terrain::s_ubSimpleTerrainVS;
Terrain::UB_SimpleTerrainFS Terrain::s_ubSimpleTerrainFS;
// TerrainPhysics:
@ -76,19 +78,67 @@ void TerrainPhysics::EnableDebugDraw(bool b)
// TerrainLOD:
void TerrainLOD::Init(int sidePoly, int step)
void TerrainLOD::Init(int sidePoly, int step, bool addEdgeTess)
{
_side = sidePoly + 1;
_vertCount = _side * _side;
if (1 == step)
Math::BuildListGrid(sidePoly, sidePoly, _vIB);
Math::CreateListGrid(sidePoly, sidePoly, _vIB);
else
Math::BuildStripGrid(sidePoly, sidePoly, _vIB);
_indexCount = Utils::Cast32(_vIB.size());
Math::CreateStripGrid(sidePoly, sidePoly, _vIB);
_firstIndex = 0;
if (addEdgeTess)
{
const int extraVerts = sidePoly * 4;
_vIB.reserve(_vIB.capacity() + extraVerts * 4);
_vIB.push_back(0xFFFF);
auto ComputeIndex = [this](int i, int j)
{
return i * _side + j;
};
// Bottom, forwards:
VERUS_FOR(i, sidePoly)
{
_vIB.push_back(ComputeIndex(sidePoly, i));
_vIB.push_back(_vertCount + i);
_vIB.push_back(ComputeIndex(sidePoly, i + 1));
_vIB.push_back(0xFFFF);
}
// Right, backwards:
VERUS_FOR(i, sidePoly)
{
_vIB.push_back(ComputeIndex(sidePoly - i, sidePoly));
_vIB.push_back(_vertCount + sidePoly + i);
_vIB.push_back(ComputeIndex(sidePoly - i - 1, sidePoly));
_vIB.push_back(0xFFFF);
}
// Top, backwards:
VERUS_FOR(i, sidePoly)
{
_vIB.push_back(ComputeIndex(0, sidePoly - i));
_vIB.push_back(_vertCount + sidePoly * 2 + i);
_vIB.push_back(ComputeIndex(0, sidePoly - i - 1));
_vIB.push_back(0xFFFF);
}
// Left, forwards:
VERUS_FOR(i, sidePoly)
{
_vIB.push_back(ComputeIndex(i, 0));
_vIB.push_back(_vertCount + sidePoly * 3 + i);
_vIB.push_back(ComputeIndex(i + 1, 0));
if (_vIB.size() < _vIB.capacity())
_vIB.push_back(0xFFFF);
}
_vertCount += extraVerts;
VERUS_RT_ASSERT(Math::CheckIndexBuffer(_vIB, _vertCount - 1));
}
_indexCount = Utils::Cast32(_vIB.size());
}
void TerrainLOD::InitGeo(short* pV, UINT16* pI, int vertexOffset)
void TerrainLOD::InitGeo(short* pV, UINT16* pI, int vertexOffset, bool addEdgeTess)
{
const int edge = _side - 1;
const int step = 16 / edge;
@ -121,6 +171,39 @@ void TerrainLOD::InitGeo(short* pV, UINT16* pI, int vertexOffset)
if (_vIB[i] != 0xFFFF)
_vIB[i] -= vertexOffset;
}
if (addEdgeTess)
{
const int halfStep = step / 2;
const int vertCount = _side * _side;
const int sidePoly = _side - 1;
const short minPos = 0;
const short maxPos = 16;
VERUS_FOR(i, sidePoly)
{
pV[((vertCount + i) << 2) + 0] = halfStep + i * step;
pV[((vertCount + i) << 2) + 2] = maxPos;
pV[((vertCount + i) << 2) + 3] = -1;
}
VERUS_FOR(i, sidePoly)
{
pV[((vertCount + sidePoly + i) << 2) + 0] = maxPos;
pV[((vertCount + sidePoly + i) << 2) + 2] = halfStep + (sidePoly - i - 1) * step;
pV[((vertCount + sidePoly + i) << 2) + 1] = -1;
}
VERUS_FOR(i, sidePoly)
{
pV[((vertCount + sidePoly * 2 + i) << 2) + 0] = halfStep + (sidePoly - i - 1) * step;
pV[((vertCount + sidePoly * 2 + i) << 2) + 2] = minPos;
pV[((vertCount + sidePoly * 2 + i) << 2) + 3] = 1;
}
VERUS_FOR(i, sidePoly)
{
pV[((vertCount + sidePoly * 3 + i) << 2) + 0] = minPos;
pV[((vertCount + sidePoly * 3 + i) << 2) + 2] = halfStep + i * step;
pV[((vertCount + sidePoly * 3 + i) << 2) + 1] = 1;
}
}
}
// TerrainPatch:
@ -297,17 +380,35 @@ void Terrain::InitStatic()
{
VERUS_QREF_CONST_SETTINGS;
s_shader.Init("[Shaders]:DS_Terrain.hlsl");
s_shader->CreateDescriptorSet(0, &s_ubDrawDepth, sizeof(s_ubDrawDepth), settings.GetLimits()._terrain_ubDrawDepthCapacity,
s_shader[SHADER_MAIN].Init("[Shaders]:DS_Terrain.hlsl");
s_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubTerrainVS, sizeof(s_ubTerrainVS), settings.GetLimits()._terrain_ubDrawDepthCapacity,
{
CGI::Sampler::linear2D
});
s_shader->CreateDescriptorSet(1, &s_ubPerMaterialFS, sizeof(s_ubPerMaterialFS), 1000,
CGI::Sampler::linearMipN, // Height
CGI::Sampler::linearMipN // Normal
}, CGI::ShaderStageFlags::vs_hs_ds);
s_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubTerrainFS, sizeof(s_ubTerrainFS), 1000,
{
CGI::Sampler::aniso, CGI::Sampler::aniso,
CGI::Sampler::aniso, CGI::Sampler::aniso
CGI::Sampler::aniso, // Normal
CGI::Sampler::aniso, // Blend
CGI::Sampler::aniso, // Layers
CGI::Sampler::aniso, // LayersNM
CGI::Sampler::aniso // Detail
}, CGI::ShaderStageFlags::fs);
s_shader->CreatePipelineLayout();
s_shader[SHADER_MAIN]->CreatePipelineLayout();
s_shader[SHADER_SIMPLE].Init("[Shaders]:SimpleTerrain.hlsl");
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(0, &s_ubSimpleTerrainVS, sizeof(s_ubSimpleTerrainVS), settings.GetLimits()._terrain_ubDrawDepthCapacity,
{
CGI::Sampler::linearMipN, // Height
CGI::Sampler::linearMipN // Normal
}, CGI::ShaderStageFlags::vs);
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(1, &s_ubSimpleTerrainFS, sizeof(s_ubSimpleTerrainFS), 1000,
{
CGI::Sampler::linearMipN, // Normal
CGI::Sampler::linearMipN, // Blend
CGI::Sampler::linearMipN, // Layers
}, CGI::ShaderStageFlags::fs);
s_shader[SHADER_SIMPLE]->CreatePipelineLayout();
}
void Terrain::DoneStatic()
@ -319,6 +420,7 @@ void Terrain::Init(RcDesc desc)
{
VERUS_INIT();
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
if (!Math::IsPowerOfTwo(desc._mapSide))
throw VERUS_RECOVERABLE << "Init(), mapSide must be power of two";
@ -329,6 +431,8 @@ void Terrain::Init(RcDesc desc)
const int patchSide = _mapSide >> 4;
const int patchShift = _mapShift - 4;
const int patchCount = patchSide * patchSide;
const int maxInstances = patchCount * 8;
_vPatches.resize(patchCount);
_vPatchTBNs.resize(patchCount * 3);
VERUS_P_FOR(i, patchSide)
@ -345,6 +449,22 @@ void Terrain::Init(RcDesc desc)
}
});
if (desc._debugHills)
{
if (desc._debugHills < 0)
{
VERUS_P_FOR(i, _mapSide)
{
VERUS_FOR(j, _mapSide)
{
const int ij[] = { i, j };
if (((i >> 4) + (j >> 4)) & 0x1)
SetHeightAt(ij, (i & 0xF) * 100);
else
SetHeightAt(ij, (j & 0xF) * 100);
}
});
}
else
{
const float scale = 1.f / desc._debugHills;
VERUS_P_FOR(i, _mapSide)
@ -358,6 +478,7 @@ void Terrain::Init(RcDesc desc)
SetHeightAt(ij, short(res * 1000.f));
}
});
}
VERUS_FOR(lod, 5)
{
@ -368,11 +489,10 @@ void Terrain::Init(RcDesc desc)
}
}
_vSortedPatchIndices.resize(patchCount);
const int maxInstances = patchCount * 8;
// Init LODs:
VERUS_FOR(i, VERUS_COUNT_OF(_lods))
_lods[i].Init(16 >> i, 1 << i);
_lods[i].Init(16 >> i, 1 << i, i > 0);
Vector<short> vVB;
Vector<UINT16> vIB;
@ -387,21 +507,22 @@ void Terrain::Init(RcDesc desc)
vbSize = 0, ibSize = 0;
VERUS_FOR(i, VERUS_COUNT_OF(_lods))
{
_lods[i].InitGeo(&vVB[vbSize * 4], &vIB[ibSize], vbSize);
_lods[i].InitGeo(&vVB[vbSize * 4], &vIB[ibSize], vbSize, i > 0);
_lods[i]._firstIndex = ibSize;
vbSize += _lods[i]._vertCount;
ibSize += _lods[i]._indexCount;
}
_vInstanceBuffer.resize(maxInstances);
CGI::GeometryDesc geoDesc;
const CGI::InputElementDesc ied[] =
const CGI::VertexInputAttrDesc viaDesc[] =
{
{ 0, 0, CGI::IeType::shorts, 4, CGI::IeUsage::position, 0},
{-1, offsetof(PerInstanceData, _posPatch), CGI::IeType::shorts, 4, CGI::IeUsage::texCoord, 8},
{-1, offsetof(PerInstanceData, _layers), CGI::IeType::shorts, 4, CGI::IeUsage::texCoord, 9},
CGI::InputElementDesc::End()
{-1, offsetof(PerInstanceData, _posPatch), CGI::IeType::shorts, 4, CGI::IeUsage::instData, 0},
{-1, offsetof(PerInstanceData, _layers), CGI::IeType::shorts, 4, CGI::IeUsage::instData, 1},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pInputElementDesc = ied;
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(short) * 4, sizeof(PerInstanceData), 0 };
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
@ -411,14 +532,11 @@ void Terrain::Init(RcDesc desc)
_geo->UpdateVertexBuffer(vVB.data(), 0);
_geo->UpdateIndexBuffer(vIB.data());
_vInstanceBuffer.resize(maxInstances);
{
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle());
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#", renderer.GetDS().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
_pipe[PIPE_LIST].Init(pipeDesc);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._primitiveRestartEnable = true;
@ -426,14 +544,36 @@ void Terrain::Init(RcDesc desc)
}
{
VERUS_QREF_ATMO;
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Depth", atmo.GetShadowMap().GetRenderPassHandle());
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#Depth", atmo.GetShadowMap().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = "";
pipeDesc.EnableDepthBias();
_pipe[PIPE_DEPTH_LIST].Init(pipeDesc);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._primitiveRestartEnable = true;
_pipe[PIPE_DEPTH_STRIP].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#SolidColor", renderer.GetDS().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._rasterizationState._polygonMode = CGI::PolygonMode::line;
pipeDesc._rasterizationState._depthBiasEnable = true;
pipeDesc._rasterizationState._depthBiasConstantFactor = -50;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_WIREFRAME_LIST].Init(pipeDesc);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._primitiveRestartEnable = true;
_pipe[PIPE_WIREFRAME_STRIP].Init(pipeDesc);
}
if (settings._gpuTessellation)
{
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#Tess", renderer.GetDS().GetRenderPassHandle());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = CGI::PrimitiveTopology::patchList3;
_pipe[PIPE_TESS].Init(pipeDesc);
}
CGI::TextureDesc texDesc;
texDesc._format = CGI::Format::floatR16;
@ -447,12 +587,20 @@ void Terrain::Init(RcDesc desc)
texDesc._width = _mapSide;
texDesc._height = _mapSide;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::generateMips;
texDesc._flags = CGI::TextureDesc::Flags::anyShaderResource | CGI::TextureDesc::Flags::generateMips;
_tex[TEX_NORMALS].Init(texDesc);
texDesc._flags = CGI::TextureDesc::Flags::generateMips;
_tex[TEX_BLEND].Init(texDesc);
s_shader->FreeDescriptorSet(_cshVS);
_cshVS = s_shader->BindDescriptorSetTextures(0, { _tex[TEX_HEIGHTMAP] });
texDesc.Reset();
texDesc._format = CGI::Format::unormR8;
texDesc._width = _mapSide;
texDesc._height = _mapSide;
texDesc._flags = CGI::TextureDesc::Flags::anyShaderResource;
_tex[TEX_MAIN_LAYER].Init(texDesc);
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshVS);
_cshVS = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(0, { _tex[TEX_HEIGHTMAP], _tex[TEX_NORMALS] });
_vBlendBuffer.resize(_mapSide * _mapSide);
VERUS_P_FOR(i, _vBlendBuffer.size())
@ -460,6 +608,7 @@ void Terrain::Init(RcDesc desc)
_vBlendBuffer[i] = VERUS_COLOR_RGBA(255, 0, 0, 255);
});
UpdateBlendTexture();
UpdateMainLayerTexture();
OnHeightModified();
AddNewRigidBody();
@ -469,8 +618,8 @@ void Terrain::Init(RcDesc desc)
void Terrain::Done()
{
s_shader->FreeDescriptorSet(_cshVS);
s_shader->FreeDescriptorSet(_cshFS);
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshVS);
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshFS);
_tex.Done();
_pipe.Done();
@ -481,17 +630,6 @@ void Terrain::Done()
VERUS_DONE(Terrain);
}
int Terrain::UserPtr_GetType()
{
return 0;
//return +NodeType::terrain;
}
void Terrain::ResetInstanceCount()
{
_instanceCount = 0;
}
void Terrain::Layout()
{
VERUS_QREF_CONST_SETTINGS;
@ -520,39 +658,48 @@ void Terrain::Layout()
sm.SetCamera(pPrevCamera);
}
void Terrain::Draw()
void Terrain::Draw(RcDrawDesc dd)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
VERUS_QREF_CONST_SETTINGS;
if (!_visiblePatchCount)
return;
auto cb = renderer.GetCommandBuffer();
const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(Scene::DrawDepth::automatic);
s_ubDrawDepth._matW = mataff(1);
s_ubDrawDepth._matWV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubDrawDepth._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubDrawDepth._posEye_mapSideInv = float4(atmo.GetEyePosition().GLM(), 0);
s_ubDrawDepth._posEye_mapSideInv.w = 1.f / _mapSide;
const Transform3 matW = Transform3::identity();
s_ubTerrainVS._matW = matW.UniformBufferFormat();
s_ubTerrainVS._matWV = Transform3(sm.GetCamera()->GetMatrixV() * matW).UniformBufferFormat();
s_ubTerrainVS._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubTerrainVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubTerrainVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubTerrainVS._eyePos_mapSideInv = float4(atmo.GetEyePosition().GLM(), 0);
s_ubTerrainVS._eyePos_mapSideInv.w = 1.f / _mapSide;
s_ubTerrainVS._viewportSize = cb->GetViewportSize().GLM();
s_ubTerrainFS._matWV = s_ubTerrainVS._matWV;
VERUS_FOR(i, VERUS_COUNT_OF(_layerData))
{
s_ubPerMaterialFS._vSpecStrength[i >> 2][i & 0x3] = _layerData[i]._specStrength;
s_ubPerMaterialFS._vDetailStrength[i >> 2][i & 0x3] = _layerData[i]._detailStrength;
s_ubTerrainFS._vSpecStrength[i >> 2][i & 0x3] = _layerData[i]._specStrength;
s_ubTerrainFS._vDetailStrength[i >> 2][i & 0x3] = _layerData[i]._detailStrength;
}
s_ubTerrainFS._lamScaleBias.x = _lamScale;
s_ubTerrainFS._lamScaleBias.y = _lamBias;
renderer.GetCommandBuffer()->BindVertexBuffers(_geo);
renderer.GetCommandBuffer()->BindIndexBuffer(_geo);
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);
s_shader->BeginBindDescriptors();
bool strip = false;
bool bindStrip = true;
const int half = _mapSide >> 1;
int firstInstance = 0;
int edge = _visiblePatchCount - 1;
int lod = _vPatches[_vSortedPatchIndices.front()]._quadtreeLOD;
s_shader[SHADER_MAIN]->BeginBindDescriptors();
VERUS_FOR(i, _visiblePatchCount)
{
RcTerrainPatch patch = _vPatches[_vSortedPatchIndices[i]];
@ -563,35 +710,28 @@ void Terrain::Draw()
if (!lod)
{
if (drawingDepth)
{
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_DEPTH_LIST]);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 0, _cshVS);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 1, _cshFS);
}
if (dd._wireframe)
cb->BindPipeline(_pipe[PIPE_WIREFRAME_LIST]);
else if (drawingDepth)
cb->BindPipeline(_pipe[PIPE_DEPTH_LIST]);
else if (dd._tess && settings._gpuTessellation)
cb->BindPipeline(_pipe[PIPE_TESS]);
else
{
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_LIST]);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 0, _cshVS);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 1, _cshFS);
cb->BindPipeline(_pipe[PIPE_LIST]);
cb->BindDescriptors(s_shader[SHADER_MAIN], 0, _cshVS);
cb->BindDescriptors(s_shader[SHADER_MAIN], 1, _cshFS);
}
}
else if (!strip)
else if (bindStrip)
{
if (drawingDepth)
{
strip = true;
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_DEPTH_STRIP]);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 0, _cshVS);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 1, _cshFS);
}
bindStrip = false;
if (dd._wireframe)
cb->BindPipeline(_pipe[PIPE_WIREFRAME_STRIP]);
else if (drawingDepth)
cb->BindPipeline(_pipe[PIPE_DEPTH_STRIP]);
else
{
strip = true;
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_STRIP]);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 0, _cshVS);
renderer.GetCommandBuffer()->BindDescriptors(s_shader, 1, _cshFS);
}
cb->BindPipeline(_pipe[PIPE_STRIP]);
cb->BindDescriptors(s_shader[SHADER_MAIN], 0, _cshVS);
cb->BindDescriptors(s_shader[SHADER_MAIN], 1, _cshFS);
}
const int instanceCount = i - firstInstance; // Drawing patches [firstInstance, i).
@ -603,22 +743,43 @@ void Terrain::Draw()
_vInstanceBuffer[at]._posPatch[1] = patchToDraw._patchHeight;
_vInstanceBuffer[at]._posPatch[2] = patchToDraw._ijCoord[0] - half;
_vInstanceBuffer[at]._posPatch[3] = 0;
VERUS_ZERO_MEM(_vInstanceBuffer[at]._layers);
if (dd._wireframe)
{
switch (patchToDraw._usedChannelCount)
{
case 1: _vInstanceBuffer[at]._layers[0] = 0; _vInstanceBuffer[at]._layers[1] = 0; _vInstanceBuffer[at]._layers[2] = 1; break;
case 2: _vInstanceBuffer[at]._layers[0] = 0; _vInstanceBuffer[at]._layers[1] = 1; _vInstanceBuffer[at]._layers[2] = 0; break;
case 3: _vInstanceBuffer[at]._layers[0] = 1; _vInstanceBuffer[at]._layers[1] = 1; _vInstanceBuffer[at]._layers[2] = 0; break;
case 4: _vInstanceBuffer[at]._layers[0] = 1; _vInstanceBuffer[at]._layers[1] = 0; _vInstanceBuffer[at]._layers[2] = 0; break;
}
}
else
{
VERUS_FOR(ch, 4)
_vInstanceBuffer[at]._layers[ch] = patchToDraw._layerForChannel[ch];
}
}
renderer.GetCommandBuffer()->DrawIndexed(_lods[lod]._indexCount, instanceCount, _lods[lod]._firstIndex, 0, _instanceCount + firstInstance);
cb->DrawIndexed(_lods[lod]._indexCount, instanceCount, _lods[lod]._firstIndex, 0, _instanceCount + firstInstance);
lod = patch._quadtreeLOD;
firstInstance = i;
}
}
s_shader[SHADER_MAIN]->EndBindDescriptors();
_instanceCount += _visiblePatchCount;
_geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 1);
}
s_shader->EndBindDescriptors();
void Terrain::DrawReflection()
{
}
void Terrain::ResetInstanceCount()
{
_instanceCount = 0;
}
void Terrain::SortVisiblePatches()
@ -635,6 +796,12 @@ void Terrain::SortVisiblePatches()
});
}
int Terrain::UserPtr_GetType()
{
return 0;
//return +NodeType::terrain;
}
void Terrain::QuadtreeIntegral_ProcessVisibleNode(const short ij[2], RcPoint3 center)
{
VERUS_QREF_ATMO;
@ -647,6 +814,9 @@ void Terrain::QuadtreeIntegral_ProcessVisibleNode(const short ij[2], RcPoint3 ce
const float lodF = log2(Math::Clamp((dist - 12) * (2 / 100.f), 1.f, 18.f));
const int lod = Math::Clamp<int>(int(lodF), 0, 4);
if (4 == lod && center.getY() <= -20) // Cull underwater patches:
return;
// Locate this patch:
const int shiftPatch = _mapShift - 4;
const int iPatch = ij[0] >> 4;
@ -850,7 +1020,9 @@ void Terrain::LoadLayerTextures()
if (_vLayerUrls.empty())
return;
VERUS_QREF_MM;
VERUS_QREF_RENDERER;
renderer->WaitIdle();
_tex[TEX_LAYERS].Done();
@ -884,8 +1056,8 @@ void Terrain::LoadLayerTextures()
texDesc._urls = vLayerUrlsPtrNM.data();
_tex[TEX_LAYERS_NM].Init(texDesc);
s_shader->FreeDescriptorSet(_cshFS);
_cshFS = s_shader->BindDescriptorSetTextures(1, { _tex[TEX_NORMALS], _tex[TEX_BLEND], _tex[TEX_LAYERS], _tex[TEX_LAYERS_NM] });
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshFS);
_cshFS = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(1, { _tex[TEX_NORMALS], _tex[TEX_BLEND], _tex[TEX_LAYERS], _tex[TEX_LAYERS_NM], mm.GetDetailTexture() });
}
int Terrain::GetMainLayerAt(const int ij[2]) const
@ -1019,7 +1191,7 @@ void Terrain::UpdateMainLayerTexture()
_vMainLayerSubresData[offset + j] = GetMainLayerAt(ij) * 16 + 4;
}
});
//_tex[TEX_MAIN_LAYER]->UpdateSubresource(_vMainLayerSubresData.data());
_tex[TEX_MAIN_LAYER]->UpdateSubresource(_vMainLayerSubresData.data());
}
CGI::TexturePtr Terrain::GetMainLayerTexture() const
@ -1039,6 +1211,7 @@ void Terrain::OnHeightModified()
void Terrain::AddNewRigidBody()
{
_physics.Done();
_physics.Init(this, _mapSide, _mapSide, _vHeightBuffer.data(), ConvertHeight(static_cast<short>(1)));
}
@ -1175,7 +1348,7 @@ void Terrain::Deserialize(IO::RStream stream)
}
else
{
_vPatches[i]._layerForChannel[j] = -1;
_vPatches[i]._layerForChannel[j] = 0;
}
}
}
@ -1194,12 +1367,13 @@ void Terrain::Deserialize(IO::RStream stream)
{
UINT16 data;
stream >> data;
_vBlendBuffer[offset + j] = Convert::Uint4x4ToUint8x4(data);
_vBlendBuffer[offset + j] = Convert::Uint4x4ToUint8x4(data, true);
const int ij[] = { i, j };
UpdateMainLayerAt(ij);
}
}
UpdateBlendTexture();
UpdateMainLayerTexture();
// </Blend>
OnHeightModified();

View file

@ -40,8 +40,8 @@ namespace verus
int _indexCount = 0;
int _firstIndex = 0;
void Init(int sidePoly, int step);
void InitGeo(short* pV, UINT16* pI, int vertexOffset);
void Init(int sidePoly, int step, bool addEdgeTess);
void InitGeo(short* pV, UINT16* pI, int vertexOffset, bool addEdgeTess);
};
VERUS_TYPEDEFS(TerrainLOD);
@ -80,6 +80,14 @@ namespace verus
{
public:
#include "../Shaders/DS_Terrain.inc.hlsl"
#include "../Shaders/SimpleTerrain.inc.hlsl"
enum SHADER
{
SHADER_MAIN,
SHADER_SIMPLE,
SHADER_COUNT
};
enum PIPE
{
@ -87,7 +95,10 @@ namespace verus
PIPE_STRIP,
PIPE_DEPTH_LIST,
PIPE_DEPTH_STRIP,
PIPE_MAX
PIPE_WIREFRAME_LIST,
PIPE_WIREFRAME_STRIP,
PIPE_TESS,
PIPE_COUNT
};
enum TEX
@ -98,7 +109,7 @@ namespace verus
TEX_LAYERS,
TEX_LAYERS_NM,
TEX_MAIN_LAYER,
TEX_MAX
TEX_COUNT
};
static const int s_maxLayers = 32;
@ -116,13 +127,15 @@ namespace verus
};
protected:
static CGI::ShaderPwn s_shader;
static UB_DrawDepth s_ubDrawDepth;
static UB_PerMaterialFS s_ubPerMaterialFS;
static CGI::ShaderPwns<SHADER_COUNT> s_shader;
static UB_TerrainVS s_ubTerrainVS;
static UB_TerrainFS s_ubTerrainFS;
static UB_SimpleTerrainVS s_ubSimpleTerrainVS;
static UB_SimpleTerrainFS s_ubSimpleTerrainFS;
CGI::GeometryPwn _geo;
CGI::PipelinePwns<PIPE_MAX> _pipe;
CGI::TexturePwns<TEX_MAX> _tex;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
Vector<TerrainPatch> _vPatches;
Vector<TerrainPatch::TBN> _vPatchTBNs;
Vector<UINT16> _vSortedPatchIndices;
@ -136,18 +149,21 @@ namespace verus
float _quadtreeFatten = 0.5f;
int _mapSide = 0;
int _mapShift = 0;
int _visiblePatchCount = 0;
int _vertCount = 0;
int _indexCount = 0;
int _instanceCount = 0;
int _cshVS = -1;
int _cshFS = -1;
int _visiblePatchCount = 0;
CGI::CSHandle _cshVS;
CGI::CSHandle _cshFS;
TerrainLOD _lods[5]; // Level of detail data for (16x16, 8x8, 4x4, 2x2, 1x1).
LayerData _layerData[s_maxLayers];
TerrainPhysics _physics;
Math::QuadtreeIntegral _quadtree;
public:
float _lamScale = 1.9f;
float _lamBias = -0.9f;
struct Desc
{
int _mapSide = 256;
@ -159,6 +175,18 @@ namespace verus
};
VERUS_TYPEDEFS(Desc);
struct DrawDesc
{
bool _tess = false;
bool _wireframe = false;
void Reset()
{
*this = DrawDesc();
}
};
VERUS_TYPEDEFS(DrawDesc);
Terrain();
virtual ~Terrain();
@ -168,14 +196,16 @@ namespace verus
void Init(RcDesc desc = Desc());
void Done();
virtual int UserPtr_GetType() override;
void Layout();
void Draw(RcDrawDesc dd = DrawDesc());
void DrawReflection();
void ResetInstanceCount();
void Layout();
void Draw();
void SortVisiblePatches();
virtual int UserPtr_GetType() override;
int GetMapSide() const { return _mapSide; }
RTerrainPatch GetPatch(int index) { return _vPatches[index]; }

513
Verus/src/Scene/Water.cpp Normal file
View file

@ -0,0 +1,513 @@
#include "verus.h"
using namespace verus;
using namespace verus::Scene;
Water::UB_WaterVS Water::s_ubWaterVS;
Water::UB_WaterFS Water::s_ubWaterFS;
Water::UB_Gen Water::s_ubGen;
Water::UB_GenHeightmapFS Water::s_ubGenHeightmapFS;
Water::UB_GenNormalsFS Water::s_ubGenNormalsFS;
Water::Water()
{
}
Water::~Water()
{
Done();
}
void Water::Init(RTerrain terrain)
{
VERUS_INIT();
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
_pTerrain = &terrain;
_rphGenHeightmap = renderer->CreateSimpleRenderPass(CGI::Format::floatR16, CGI::ImageLayout::xsReadOnly);
_rphGenNormals = renderer->CreateSimpleRenderPass(CGI::Format::unormR10G10B10A2);
_rphReflection = renderer->CreateRenderPass(
{
CGI::RP::Attachment("Color", CGI::Format::floatR11G11B10).LoadOpDontCare().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("Depth", CGI::Format::unormD24uintS8).LoadOpClear().Layout(CGI::ImageLayout::depthStencilAttachment),
},
{
CGI::RP::Subpass("Sp0").Color(
{
CGI::RP::Ref("Color", CGI::ImageLayout::colorAttachment)
}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment)),
},
{});
_shader[SHADER_MAIN].Init("[Shaders]:Water.hlsl");
_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubWaterVS, sizeof(s_ubWaterVS), 100,
{
CGI::Sampler::linearClampMipL,
CGI::Sampler::linearMipL
}, CGI::ShaderStageFlags::vs);
_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubWaterFS, sizeof(s_ubWaterFS), 100,
{
CGI::Sampler::linearClampMipL,
CGI::Sampler::linearMipL,
CGI::Sampler::custom,
CGI::Sampler::aniso
}, CGI::ShaderStageFlags::fs);
_shader[SHADER_MAIN]->CreatePipelineLayout();
_shader[SHADER_GEN].Init("[Shaders]:WaterGen.hlsl");
_shader[SHADER_GEN]->CreateDescriptorSet(0, &s_ubGen, sizeof(s_ubGen), 100, {}, CGI::ShaderStageFlags::vs);
_shader[SHADER_GEN]->CreateDescriptorSet(1, &s_ubGenHeightmapFS, sizeof(s_ubGenHeightmapFS), 100, { CGI::Sampler::linearMipN }, CGI::ShaderStageFlags::fs);
_shader[SHADER_GEN]->CreateDescriptorSet(2, &s_ubGenNormalsFS, sizeof(s_ubGenNormalsFS), 100, { CGI::Sampler::linearMipN }, CGI::ShaderStageFlags::fs);
_shader[SHADER_GEN]->CreatePipelineLayout();
Vector<UINT16> vIndices;
Math::CreateStripGrid(_gridWidth - 1, _gridHeight - 1, vIndices);
_indexCount = vIndices.size();
CGI::GeometryDesc geoDesc;
const CGI::VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(Vertex, _pos), CGI::IeType::floats, 4, CGI::IeUsage::position, 0},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(Vertex), 0 };
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
_geo->CreateVertexBuffer(_gridWidth * _gridHeight, 0);
_geo->CreateIndexBuffer(vIndices.size());
_geo->UpdateIndexBuffer(vIndices.data());
CreateWaterPlane();
{
CGI::PipelineDesc pipeDesc(_geo, _shader[SHADER_MAIN], "#0", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
//pipeDesc._rasterizationState._polygonMode = CGI::PolygonMode::line;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
_pipe[PIPE_MAIN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_GEN], "#GenHeightmap", _rphGenHeightmap);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_GEN_HEIGHTMAP].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_GEN], "#GenNormals", _rphGenNormals);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_GEN_NORMALS].Init(pipeDesc);
}
CGI::TextureDesc texDesc;
texDesc._url = "[Textures]:Water/Foam.dds";
_tex[TEX_FOAM].Init(texDesc);
texDesc._url = "[Textures]:Water/Heightmap.FX.dds";
_tex[TEX_SOURCE_HEIGHTMAP].Init(texDesc);
CGI::SamplerDesc normalsSamplerDesc;
normalsSamplerDesc.SetFilter("a");
normalsSamplerDesc.SetAddressMode("rr");
normalsSamplerDesc._mipLodBias = 0.5f;
normalsSamplerDesc._minLod = 1;
texDesc.Reset();
texDesc._format = CGI::Format::floatR16;
texDesc._width = _genSide;
texDesc._height = _genSide;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::anyShaderResource | CGI::TextureDesc::Flags::generateMips;
_tex[TEX_GEN_HEIGHTMAP].Init(texDesc);
texDesc._format = CGI::Format::unormR10G10B10A2;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips;
texDesc._pSamplerDesc = &normalsSamplerDesc;
_tex[TEX_GEN_NORMALS].Init(texDesc);
_fbhGenHeightmap = renderer->CreateFramebuffer(_rphGenHeightmap, { _tex[TEX_GEN_HEIGHTMAP] }, _genSide, _genSide);
_fbhGenNormals = renderer->CreateFramebuffer(_rphGenNormals, { _tex[TEX_GEN_NORMALS] }, _genSide, _genSide);
_cshWaterVS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(0, { _pTerrain->GetHeightmapTexture(), _tex[TEX_GEN_HEIGHTMAP] });
_cshGenNormals = _shader[SHADER_GEN]->BindDescriptorSetTextures(2, { _tex[TEX_GEN_HEIGHTMAP] });
texDesc.Reset();
texDesc._format = CGI::Format::floatR11G11B10;
texDesc._width = settings._screenSizeWidth;
texDesc._height = settings._screenSizeHeight;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
_tex[TEX_REFLECTION].Init(texDesc);
texDesc._format = CGI::Format::unormD24uintS8;
texDesc._flags = CGI::TextureDesc::Flags::none;
_tex[TEX_REFLECTION_DEPTH].Init(texDesc);
_fbhReflection = renderer->CreateFramebuffer(_rphReflection,
{
_tex[TEX_REFLECTION],
_tex[TEX_REFLECTION_DEPTH]
},
texDesc._width,
texDesc._height);
// Texture for rendering reflection onto:
/*
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::simpleReflection)
{
texDesc.Reset();
texDesc._format = CGI::Format::unormR8G8B8A8;
texDesc._width = 512;
texDesc._height = 512;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::generateMips;
_tex[TEX_REFLECT].Init(texDesc);
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction)
_tex[TEX_REFRACT].Init(texDesc);
texDesc._format = CGI::Format::unormD16;
_tex[TEX_REFLECT_DEPTH].Init(texDesc);
}
*/
VERUS_FOR(i, s_maxHarmonics)
_amplitudes[i] = PhillipsSpectrum(0.5f + i / 2.f);
}
void Water::Done()
{
VERUS_DONE(Water);
}
void Water::Update()
{
VERUS_UPDATE_ONCE_CHECK;
VERUS_QREF_TIMER;
_phase = fmod(_phase + dt * (1 / 29.f), 1.f);
_phaseWave = fmod(_phaseWave + dt * (1 / 61.f), 1.f);
}
void Water::Draw()
{
VERUS_UPDATE_ONCE_CHECK_DRAW;
if (!_cshWaterFS.IsSet())
{
if (_tex[TEX_FOAM]->IsLoaded())
{
_cshWaterFS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(1,
{
_pTerrain->GetHeightmapTexture(),
_tex[TEX_GEN_HEIGHTMAP],
_tex[TEX_GEN_NORMALS],
_tex[TEX_FOAM]
});
}
else
return;
}
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_TIMER;
VERUS_QREF_ATMO;
auto cb = renderer.GetCommandBuffer();
RCamera cam = *sm.GetCamera();
Transform3 matW;
Point3 eyePosAtGroundLevel = cam.GetEyePosition();
eyePosAtGroundLevel.setY(0);
Vector3 flatDir = cam.GetFrontDirection();
flatDir.setY(0);
flatDir = VMath::normalizeApprox(flatDir);
const float angle = atan2(
static_cast<float>(flatDir.getX()),
static_cast<float>(flatDir.getZ())); // Align with high density sector.
const Matrix3 matR = Matrix3::rotationY(angle);
matW = Transform3(matR, Vector3(eyePosAtGroundLevel - flatDir * 5 * abs(cam.GetFrontDirection().getY())));
const Matrix4 matWVP = cam.GetMatrixVP() * matW;
s_ubWaterVS._matW = matW.UniformBufferFormat();
s_ubWaterVS._matVP = cam.GetMatrixVP().UniformBufferFormat();
s_ubWaterVS._eyePos = float4(cam.GetEyePosition().GLM(), 0);
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.x = 1 / _patchSide;
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.y = Math::ComputeDistToMipScale(_genSide << 6, renderer.GetSwapChainHeight(), _patchSide, cam.GetFOV());
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.z = 1.f / _pTerrain->GetMapSide();
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.w = Math::ComputeDistToMipScale(_pTerrain->GetMapSide(), renderer.GetSwapChainHeight(), _pTerrain->GetMapSide(), cam.GetFOV());
s_ubWaterFS._phase.x = _phase;
s_ubWaterFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
s_ubWaterFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);
cb->BindPipeline(_pipe[PIPE_MAIN]);
_shader[SHADER_MAIN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_MAIN], 0, _cshWaterVS);
cb->BindDescriptors(_shader[SHADER_MAIN], 1, _cshWaterFS);
cb->DrawIndexed(_indexCount);
_shader[SHADER_MAIN]->EndBindDescriptors();
//ms_cbPerObject.matWVP = matWVP.ConstBufferFormat();
//ms_cbPerObject.matW = matW.ConstBufferFormat();
//ms_cbPerObject.matV = cam.GetMatrixV().ConstBufferFormat();
if (false)
{
//_sb[SB_DEPTH]->Apply(sbad);
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP] }, 0 + VERUS_ST_VS_OFFSET);
//renderer->SetTextures({ _texLand }, 5 + VERUS_ST_VS_OFFSET);
}
//_s->Bind("TDepth");
//_s->UpdateBuffer(0);
//_geo->BeginDraw(0x1);
//renderer->DrawIndexedPrimitive(CGI::PT_TRIANGLESTRIP, 0, _indexCount);
//_geo->EndDraw(0x1);
}
else
{
VERUS_QREF_ATMO;
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction) // True refraction:
{
//renderer->StretchRect(m_tex[TEX_REFRACT], renderer.GetOffscreenColorTexture());
//_tex[TEX_REFRACT]->GenerateMipmaps();
}
//renderer->SetRenderTargets({ renderer.GetOffscreenColorTexture(), renderer.GetDS().GetGBuffer(1) }, renderer.GetOffscreenDepthTexture());
//_sb[SB_MASTER]->Apply(sbad);
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP] }, 0 + VERUS_ST_VS_OFFSET);
//renderer->SetTextures({ _texLand }, 5 + VERUS_ST_VS_OFFSET);
}
Matrix4 matTexSpace = Matrix4::identity();
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::solidColor)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP_BASE] });
//renderer->SetTextures({ _tex[TEX_FOAM] }, 2);
//renderer->SetTextures({ _texLand }, 5);
//renderer->SetTextures({ atmo.GetSunShadowTexture() }, 6);
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::simpleReflection)
{
//renderer->SetTextures({ _tex[TEX_REFLECT] }, 3);
const Transform3 matShift = Transform3::translation(Vector3(0, -0.01f, 0)); // Sky-waterline bleeding fix.
//matTexSpace = Matrix4(Math::ToUVMatrix(0, Math::TOUV_RENDER_TARGET_VFLIP | Math::TOUV_MAP_TEXELS_TO_PIXELS, _tex[TEX_REFLECT]->GetSize()) * matShift) * matWVP;
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP], _tex[TEX_NORMALMAP] });
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction)
{
//renderer->SetTextures({ _tex[TEX_REFRACT] }, 4);
}
//ms_cbPerFrame.matReflect = matTexSpace.ConstBufferFormat();
//ms_cbPerFrame.shadowTexSize = atmo.GetSunShadowTexture() ? atmo.GetSunShadowTexture()->GetSize() : CVector4(0);
//ms_cbPerFrame.matSunShadow = atmo.GetSunShadowMatrix(0).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM1 = atmo.GetSunShadowMatrix(1).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM2 = atmo.GetSunShadowMatrix(2).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM3 = atmo.GetSunShadowMatrix(3).ConstBufferFormat();
//ms_cbPerFrame.csmParams = atmo.GetParamsCSM();
//ms_cbPerFrame.phases_mapSideInv.x = _phase;
//ms_cbPerFrame.phases_mapSideInv.y = _phaseWave;
//ms_cbPerFrame.phases_mapSideInv.z = 1.f / _mapSide;
//ms_cbPerFrame.eyePos = cam.GetPositionEye();
//ms_cbPerFrame.colorAmbient = atmo.GetAmbientColor();
//ms_cbPerFrame.dirToSun = atmo.GetDirToSun();
//ms_cbPerFrame.colorSun = atmo.GetSunColor();
//ms_cbPerFrame.colorSunSpec = atmo.GetSunColor();
//ms_cbPerFrame.fogColor = atmo.GetFogColor();
//char tech[8];
//sprintf_s(tech, "T_%d", settings._sceneWaterQuality);
//_s->Bind(tech);
//_s->UpdateBuffer(0);
//_s->UpdateBuffer(1);
//_geo->BeginDraw(0x1);
//renderer->DrawIndexedPrimitive(CGI::PT_TRIANGLESTRIP, 0, _indexCount);
//_geo->EndDraw(0x1);
}
///renderer->SetTextures({ nullptr }, 0 + VERUS_ST_VS_OFFSET);
//renderer.DrawQuad(m_tex[HTEX_HEIGHTMAP]);
}
void Water::BeginReflection(CGI::PBaseCommandBuffer pCB)
{
VERUS_QREF_SM;
VERUS_QREF_RENDERER;
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
_reflectionMode = sm.GetCamera()->GetEyePosition().getY() >= 0;
_renderToTexture = true;
pCB->BeginRenderPass(_rphReflection, _fbhReflection,
{
_tex[TEX_REFLECTION]->GetClearValue(),
_tex[TEX_REFLECTION_DEPTH]->GetClearValue()
});
}
void Water::EndReflection(CGI::PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
pCB->EndRenderPass();
_reflectionMode = false;
_renderToTexture = false;
}
void Water::GenerateTextures()
{
if (!_cshGenHeightmap.IsSet())
{
if (_tex[TEX_SOURCE_HEIGHTMAP]->IsLoaded())
_cshGenHeightmap = _shader[SHADER_GEN]->BindDescriptorSetTextures(1, { _tex[TEX_SOURCE_HEIGHTMAP] });
else
return;
}
GenerateHeightmapTexture();
GenerateNormalsTexture();
}
void Water::GenerateHeightmapTexture()
{
VERUS_QREF_RENDERER;
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenHeightmapFS._phase.x = _phase;
memcpy(&s_ubGenHeightmapFS._amplitudes, _amplitudes, sizeof(_amplitudes));
auto cb = renderer.GetCommandBuffer();
cb->BeginRenderPass(_rphGenHeightmap, _fbhGenHeightmap, { _tex[TEX_GEN_HEIGHTMAP]->GetClearValue(), });
cb->BindPipeline(_pipe[PIPE_GEN_HEIGHTMAP]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 1, _cshGenHeightmap);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(&(*cb));
cb->EndRenderPass();
_tex[TEX_GEN_HEIGHTMAP]->GenerateMips();
}
void Water::GenerateNormalsTexture()
{
VERUS_QREF_RENDERER;
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenNormalsFS._textureSize = _tex[TEX_GEN_HEIGHTMAP]->GetSize().GLM();
s_ubGenNormalsFS._waterScale.x = 1 / _patchSide;
auto cb = renderer.GetCommandBuffer();
cb->BeginRenderPass(_rphGenNormals, _fbhGenNormals, { _tex[TEX_GEN_NORMALS]->GetClearValue(), });
cb->BindPipeline(_pipe[PIPE_GEN_NORMALS]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 2, _cshGenNormals);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(&(*cb));
cb->EndRenderPass();
_tex[TEX_GEN_NORMALS]->GenerateMips();
}
CGI::TexturePtr Water::GetCausticsTexture() const
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
return _tex[TEX_GEN_NORMALS];
else
return _tex[TEX_SOURCE_HEIGHTMAP];
}
void Water::CreateWaterPlane()
{
VERUS_QREF_SM;
const float maxRadius = Math::Min(sm.GetCamera()->GetZFar(), 5000.f);
const float stepW = 1.f / (_gridWidth - 1);
const float stepH = 1.f / (_gridHeight - 1);
float xPolar = 0;
float zPolar = 0;
Vector<glm::vec4> vVB;
vVB.resize(_gridWidth * _gridHeight);
const float maxAngle = atan(maxRadius / 10); // Assume best height is 10 meters.
VERUS_FOR(i, _gridHeight)
{
const float radius = tan(zPolar * maxAngle) * 10;
VERUS_FOR(j, _gridWidth)
{
float xSqueeze = xPolar;
VERUS_FOR(k, 6)
xSqueeze = Math::EaseInOutSine(xSqueeze);
xSqueeze = Math::Lerp(xSqueeze, xPolar, 0.2f);
const float xCartesian = radius * sin(xSqueeze * VERUS_2PI);
const float zCartesian = radius * cos(xSqueeze * VERUS_2PI);
vVB[i * _gridWidth + j] = glm::vec4(xCartesian, 0, zCartesian, 1);
xPolar += stepW;
}
xPolar = 0;
zPolar += stepH;
}
// Watertight mesh, pun intended:
VERUS_FOR(i, _gridHeight)
vVB[i * _gridWidth + (_gridWidth - 1)] = vVB[i * _gridWidth];
_geo->UpdateVertexBuffer(vVB.data(), 0);
}
float Water::PhillipsSpectrum(float k)
{
const float kl = k;
const float k2 = k * k;
return exp(-1 / (kl * kl)) / (k2 * k2);
}

119
Verus/src/Scene/Water.h Normal file
View file

@ -0,0 +1,119 @@
#pragma once
namespace verus
{
namespace Scene
{
class Water : public Singleton<Water>, public Object
{
public:
#include "../Shaders/Water.inc.hlsl"
#include "../Shaders/WaterGen.inc.hlsl"
enum SHADER
{
SHADER_MAIN,
SHADER_GEN,
SHADER_COUNT
};
enum PIPE
{
PIPE_MAIN,
PIPE_GEN_HEIGHTMAP,
PIPE_GEN_NORMALS,
PIPE_COUNT
};
enum TEX
{
TEX_FOAM,
TEX_SOURCE_HEIGHTMAP,
TEX_GEN_HEIGHTMAP,
TEX_GEN_NORMALS,
TEX_REFLECTION,
TEX_REFLECTION_DEPTH,
TEX_REFRACT,
TEX_REFLECT,
TEX_REFLECT_DEPTH,
TEX_COUNT
};
private:
static const int s_maxHarmonics = 4;
struct Vertex
{
glm::vec4 _pos;
};
static UB_WaterVS s_ubWaterVS;
static UB_WaterFS s_ubWaterFS;
static UB_Gen s_ubGen;
static UB_GenHeightmapFS s_ubGenHeightmapFS;
static UB_GenNormalsFS s_ubGenNormalsFS;
PTerrain _pTerrain = nullptr;
Vector<Vertex> _vSwapBuffer;
CGI::GeometryPwn _geo;
CGI::ShaderPwns<SHADER_COUNT> _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::TexturePtr _texLand;
CGI::CSHandle _cshWaterVS;
CGI::CSHandle _cshWaterFS;
CGI::RPHandle _rphGenHeightmap;
CGI::FBHandle _fbhGenHeightmap;
CGI::CSHandle _cshGenHeightmap;
CGI::RPHandle _rphGenNormals;
CGI::FBHandle _fbhGenNormals;
CGI::CSHandle _cshGenNormals;
CGI::RPHandle _rphReflection;
CGI::FBHandle _fbhReflection;
const int _genSide = 1024;
const int _sideReflect = 256;
int _gridWidth = 128;
int _gridHeight = 512;
int _indexCount = 0;
const float _patchSide = 64;
float _phase = 0;
float _phaseWave = 0;
float _amplitudes[s_maxHarmonics];
bool _reflectionMode = false;
bool _renderToTexture = false;
bool _geoReady = false;
public:
Water();
~Water();
void Init(RTerrain terrain);
void Done();
void Update();
void Draw();
void BeginReflection(CGI::PBaseCommandBuffer pCB = nullptr);
void EndReflection(CGI::PBaseCommandBuffer pCB = nullptr);
void GenerateTextures();
VERUS_P(void GenerateHeightmapTexture());
VERUS_P(void GenerateNormalsTexture());
// Caustics are highlights on ocean floor.
CGI::TexturePtr GetCausticsTexture() const;
// Render reflection when above or normal view when below water level.
bool IsReflectionMode() const { return _reflectionMode; }
// Is rendering done to water's renderer target?
bool IsRenderToTexture() const { return _renderToTexture; }
VERUS_P(void CreateWaterPlane());
static float PhillipsSpectrum(float k);
};
VERUS_TYPEDEFS(Water);
}
}

View file

@ -18,7 +18,7 @@ ConstantBuffer<UB_PerObject> g_ubPerObject : register(b0, space4);
VK_SUBPASS_INPUT(0, g_texGBuffer0, g_samGBuffer0, t1, s1, space1);
VK_SUBPASS_INPUT(1, g_texGBuffer1, g_samGBuffer1, t2, s2, space1);
VK_SUBPASS_INPUT(2, g_texGBuffer2, g_samGBuffer2, t3, s3, space1);
VK_SUBPASS_INPUT(3, g_texGBuffer3, g_samGBuffer3, t4, s4, space1);
VK_SUBPASS_INPUT(3, g_texDepth, g_samDepth, t4, s4, space1);
Texture2D g_texShadowCmp : register(t5, space1);
SamplerComparisonState g_samShadowCmp : register(s5, space1);
Texture2D g_texShadow : register(t6, space1);
@ -26,18 +26,16 @@ SamplerState g_samShadow : register(s6, space1);
struct VSI
{
// Binding 0:
VK_LOCATION_POSITION int4 pos : POSITION;
VK_LOCATION_NORMAL float3 nrm : NORMAL;
VK_LOCATION(8) int4 tc0 : TEXCOORD0;
_PER_INSTANCE_DATA
};
struct VSO
{
float4 pos /**/ : SV_Position;
float4 posFS /**/ : TEXCOORD0;
float4 clipSpacePos /**/ : TEXCOORD0;
#if defined(DEF_OMNI) || defined(DEF_SPOT)
float3 radius_radiusSq_invRadiusSq /**/ : TEXCOORD1;
float3 lightPosWV /**/ : TEXCOORD2;
@ -56,8 +54,6 @@ VSO mainVS(VSI si)
{
VSO so;
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
// World matrix, instance data:
#ifdef DEF_INSTANCED
const mataff matW = GetInstMatrix(
@ -84,13 +80,15 @@ VSO mainVS(VSI si)
const float3x3 matV33 = (float3x3)g_ubPerFrame._matV;
const float3x3 matWV33 = (float3x3)matWV;
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
#ifdef DEF_DIR
so.pos = float4(mul(float4(intactPos, 1), g_ubPerFrame._matQuad), 1);
so.posFS = float4(intactPos, 1);
so.clipSpacePos = float4(intactPos, 1);
#else
const float3 posW = mul(float4(intactPos, 1), matW);
so.pos = mul(float4(posW, 1), g_ubPerFrame._matVP);
so.posFS = so.pos;
so.clipSpacePos = so.pos;
#endif
// <MoreLightParams>
@ -128,15 +126,13 @@ DS_ACC_FSO mainFS(VSO si)
{
DS_ACC_FSO so;
// Clip-space position:
#ifdef DEF_DIR
const float3 posCS = si.posFS.xyz;
const float3 ndcPos = si.clipSpacePos.xyz;
#else
const float3 posCS = si.posFS.xyz / si.posFS.w;
const float3 ndcPos = si.clipSpacePos.xyz / si.clipSpacePos.w;
#endif
// GBuffer tex. coord. from posCS:
const float2 tc0 = mul(float4(posCS.xy, 0, 1), g_ubPerFrame._matToUV).xy;
const float2 tc0 = mul(float4(ndcPos.xy, 0, 1), g_ubPerFrame._matToUV).xy;
// For Omni & Spot: light's radius and position:
#if defined(DEF_OMNI) || defined(DEF_SPOT)
@ -163,8 +159,8 @@ DS_ACC_FSO mainFS(VSO si)
#endif
// GBuffer1:
const float rawGBuffer1 = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0).r;
const float3 posWV = DS_GetPosition(rawGBuffer1, g_ubPerFrame._matInvP, posCS.xy);
const float depth = VK_SUBPASS_LOAD(g_texDepth, g_samDepth, tc0).r;
const float3 posWV = DS_GetPosition(depth, g_ubPerFrame._matInvP, ndcPos.xy);
so.target0 = 0.0;
so.target1 = 0.0;
@ -174,35 +170,34 @@ DS_ACC_FSO mainFS(VSO si)
#endif
{
// Light's diffuse & specular color:
const float3 colorDiff = si.color_coneOut.rgb;
const float3 colorSpec = saturate(colorDiff + dot(colorDiff, 0.1));
const float3 hdrLightColor = si.color_coneOut.rgb;
// GBuffer0 (color, spec):
// GBuffer0 (albedo, spec):
const float4 rawGBuffer0 = VK_SUBPASS_LOAD(g_texGBuffer0, g_samGBuffer0, tc0);
const float spec = rawGBuffer0.a;
const float3 dirToEyeWV = normalize(-posWV);
// GBuffer2 (normal, emission, motion):
const float4 rawGBuffer2 = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
const float3 normalWV = DS_GetNormal(rawGBuffer2);
const float2 emission = DS_GetEmission(rawGBuffer2);
const float4 rawGBuffer1 = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0);
const float3 normalWV = DS_GetNormal(rawGBuffer1);
const float2 emission = DS_GetEmission(rawGBuffer1);
// GBuffer3 (lam, metal, gloss):
const float4 rawGBuffer3 = VK_SUBPASS_LOAD(g_texGBuffer3, g_samGBuffer3, tc0);
const float3 anisoWV = DS_GetAnisoSpec(rawGBuffer3);
const float2 lamScaleBias = DS_GetLamScaleBias(rawGBuffer3);
const float2 metal = DS_GetMetallicity(rawGBuffer3);
const float gloss64 = rawGBuffer3.a * 64.0;
const float4 rawGBuffer2 = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
const float3 anisoWV = DS_GetAnisoSpec(rawGBuffer2);
const float2 lamScaleBias = DS_GetLamScaleBias(rawGBuffer2);
const float2 metal = DS_GetMetallicity(rawGBuffer2);
const float gloss64 = rawGBuffer2.a * 64.0;
const float gloss64Scaled = gloss64 * glossScale;
// Special:
const float skinAlpha = emission.y;
const float hairAlpha = metal.y;
const float eyeAlpha = saturate(1.0 - gloss64);
const float rim = pow(1.0 - normalWV.z, 2.0) * (0.05 + 0.2 * skinAlpha);
const float glossEye = 25.0 * glossScale;
const float skinMask = emission.y;
const float hairMask = metal.y;
const float eyeMask = saturate(1.0 - gloss64);
const float eyeGloss = 25.0 * glossScale;
const float2 lamScaleBiasWithHair = lerp(lamScaleBias, float2(1, 0.4), hairMask);
const float gloss = lerp(gloss64Scaled * gloss64Scaled * gloss64Scaled, glossEye * glossEye * glossEye, eyeAlpha);
const float gloss = lerp(gloss64Scaled * gloss64Scaled * gloss64Scaled, eyeGloss * eyeGloss * eyeGloss, eyeMask);
#ifdef DEF_DIR
const float3 dirToLightWV = -lightDirWV;
@ -225,63 +220,65 @@ DS_ACC_FSO mainFS(VSO si)
#endif
const float4 litRet = VerusLit(dirToLightWV, normalWV, dirToEyeWV,
lerp(gloss * (2.0 - lightFalloff), 12.0, hairAlpha),
lerp(lamScaleBias, float2(1, 0.4), hairAlpha),
float4(anisoWV, hairAlpha));
lerp(gloss * (2.0 - lightFalloff), 12.0, hairMask),
lamScaleBiasWithHair,
float4(anisoWV, hairMask));
// Shadow:
// <Shadow>
float shadowMask = 1.0;
{
#ifdef DEF_DIR
const float4 tcShadow = ShadowCoords(float4(posWV, 1), g_ubShadowFS._matSunShadow, -posWV.z);
const float shadowAlpha = ShadowMapCSM(
float4 config = g_ubShadowFS._shadowConfig;
const float lamBiasMask = saturate(lamScaleBiasWithHair.y * config.y);
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
const float scale = -posWV.z - 5.0;
const float3 posForShadow = posWV + normalWV * 0.012 * max(1.0, scale * 0.2) + dirToLightWV * max(0.0, scale * 0.002);
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubShadowFS._matSunShadow, -posForShadow.z);
shadowMask = ShadowMapCSM(
g_texShadowCmp,
g_samShadowCmp,
g_texShadow,
g_samShadow,
tcShadow,
g_ubShadowFS._shadowConfig,
config,
g_ubShadowFS._splitRanges,
g_ubShadowFS._matSunShadow,
g_ubShadowFS._matSunShadowCSM1,
g_ubShadowFS._matSunShadowCSM2,
g_ubShadowFS._matSunShadowCSM3);
#else
const float shadowAlpha = 1.0;
#endif
}
// </Shadow>
const float intensityDiff = lightFalloff * coneIntensity * shadowAlpha;
const float intensitySpec = saturate(intensityDiff * 2.0) * shadowAlpha;
const float maxSpecAdd = lerp(0.2 * spec, 0.1 + spec * 0.5, metal.x);
const float lightFalloffWithCone = lightFalloff * coneIntensity;
const float diffLightMask = lightFalloffWithCone * shadowMask;
const float specLightMask = saturate(lightFalloffWithCone * 2.0) * shadowMask;
const float maxSpecAdd = (1.0 - spec) * lerp(0.01, 0.5, metal.x);
// Subsurface scattering effect for front & back faces:
const float3 colorSkinSSS_Face = float3(1.6, 1.2, 0.3);
const float3 colorSkinSSS_Back = float3(1.6, 0.8, 0.5);
const float3 colorDiffSSS_Face = lerp(colorDiff, colorDiff * colorSkinSSS_Face, skinAlpha * pow(1.0 - litRet.y, 2.0));
const float3 colorDiffSSS_Back = lerp(colorDiffSSS_Face, colorDiff * colorSkinSSS_Back, skinAlpha * litRet.x);
const float3 frontSkinSSSColor = float3(1.6, 1.2, 0.3);
const float3 backSkinSSSColor = float3(1.6, 0.8, 0.5);
const float frontSkinSSSMask = 1.0 - litRet.y;
const float3 hdrLightFaceColor = hdrLightColor * lerp(1.0, frontSkinSSSColor, skinMask * frontSkinSSSMask * frontSkinSSSMask);
const float3 hdrLightColorSSS = lerp(hdrLightFaceColor, hdrLightColor * backSkinSSSColor, skinMask * litRet.x);
const float gray = Grayscale(rawGBuffer0.rgb);
const float3 metalSpec = saturate(rawGBuffer0.rgb / (gray + _SINGULARITY_FIX));
const float3 matSpec = lerp(float3(1, 1, 1), metalSpec, saturate(metal.x + (hairAlpha - eyeAlpha) * 0.4)) * FresnelSchlick(spec, maxSpecAdd, litRet.w);
const float3 maxDiff = colorDiffSSS_Back * intensityDiff;
const float3 maxSpec = matSpec * colorSpec + float3(-0.03, 0.0, 0.05) * skinAlpha;
#ifdef DEF_DIR
const float skyIntensity = 1.0;
const float3 skySpec = skyColor * matSpec * skyIntensity;
#endif
// Very bright light:
const float3 overbright = saturate(dot(maxDiff, 1.0 / 3.0) - 1.0); // Intensity above one.
const float3 diffBoost = overbright * maxDiff * litRet.y * (0.25 + rawGBuffer0.rgb);
const float3 specHue = saturate(lerp(float3(1, 1, 1), metalSpec, saturate(metal.x + (hairMask - eyeMask) * 0.4)) +
float3(-0.03, 0.0, 0.05) * skinMask);
const float3 hdrMaxDiff = hdrLightColorSSS * diffLightMask;
const float3 hdrMaxSpec = hdrLightColorSSS * specLightMask * specHue * FresnelSchlick(spec, maxSpecAdd, litRet.w);
#ifdef DEF_DIR
so.target0.rgb = maxDiff * litRet.y; // Lambert's cosine law.
so.target1.rgb = maxSpec * saturate(litRet.z * intensitySpec + rim) + diffBoost;
so.target0.rgb = hdrMaxDiff * litRet.y;
so.target1.rgb = hdrMaxSpec * litRet.z;
#else
so.target0.rgb = maxDiff * litRet.y; // Lambert's cosine law.
so.target1.rgb = maxSpec * saturate(litRet.z * intensitySpec) + diffBoost;
so.target0.rgb = hdrMaxDiff * litRet.y;
so.target1.rgb = hdrMaxSpec * litRet.z;
#endif
so.target0.rgb = max(so.target0.rgb, emission.x);
so.target1.rgb = min(so.target1.rgb, 1.0 - emission.x);
//so.target0.rgb = max(so.target0.rgb, emission.x);
//so.target1.rgb = min(so.target1.rgb, 1.0 - emission.x);
so.target0.a = 1.0;
so.target1.a = 1.0;
}

View file

@ -15,8 +15,8 @@ Texture2D g_texGBuffer1 : register(t2, space1);
SamplerState g_samGBuffer1 : register(s2, space1);
Texture2D g_texGBuffer2 : register(t3, space1);
SamplerState g_samGBuffer2 : register(s3, space1);
Texture2D g_texGBuffer3 : register(t4, space1);
SamplerState g_samGBuffer3 : register(s4, space1);
Texture2D g_texDepth : register(t4, space1);
SamplerState g_samDepth : register(s4, space1);
Texture2D g_texAccDiff : register(t5, space1);
SamplerState g_samAccDiff : register(s5, space1);
Texture2D g_texAccSpec : register(t6, space1);
@ -31,6 +31,7 @@ struct VSO
{
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
float2 clipSpacePos : TEXCOORD1;
};
struct FSO
@ -46,6 +47,7 @@ VSO mainVS(VSI si)
// Standard quad:
so.pos = float4(mul(si.pos, g_ubComposeVS._matW), 1);
so.tc0 = mul(si.pos, g_ubComposeVS._matV).xy;
so.clipSpacePos = so.pos.xy;
return so;
}
@ -56,14 +58,17 @@ FSO mainFS(VSO si)
{
FSO so;
#ifdef DEF_COMPOSE
const float3 colorAmbient = g_ubComposeFS._colorAmbient.rgb;
const float2 ndcPos = si.clipSpacePos.xy;
const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0);
const float1 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0).r; // Depth for fog.
const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0);
const float4 rawGBuffer2 = g_texGBuffer2.Sample(g_samGBuffer2, si.tc0);
const float4 rawGBuffer3 = g_texGBuffer3.Sample(g_samGBuffer3, si.tc0);
const float3 normalWV = DS_GetNormal(rawGBuffer2);
const float2 emission = DS_GetEmission(rawGBuffer2);
const float1 rawDepth = g_texDepth.Sample(g_samDepth, si.tc0).r;
const float3 normalWV = DS_GetNormal(rawGBuffer1);
const float2 emission = DS_GetEmission(rawGBuffer1);
const float4 rawAccDiff = g_texAccDiff.Sample(g_samAccDiff, si.tc0);
const float4 rawAccSpec = g_texAccSpec.Sample(g_samAccSpec, si.tc0);
@ -74,28 +79,40 @@ FSO mainFS(VSO si)
const float ssaoSpec = 1.0;
const float ssaoAmb = 1.0;
const float3 albedo = rawGBuffer0.rgb;
const float3 albedo = max(rawGBuffer0.rgb * g_ubComposeFS._toneMappingConfig.z, 0.0001);
const float depth = ToLinearDepth(rawGBuffer1, g_ubComposeFS._zNearFarEx);
const float fog = ComputeFog(depth, g_ubComposeFS._fogColor.a);
const float depth = ToLinearDepth(rawDepth, g_ubComposeFS._zNearFarEx);
const float3 posW = DS_GetPosition(rawDepth, g_ubComposeFS._matInvVP, ndcPos);
const float fog = ComputeFog(depth, g_ubComposeFS._fogColor.a, posW.y);
const float3 normalW = mul(normalWV, (float3x3)g_ubComposeFS._matInvV);
const float gray = Grayscale(colorAmbient);
const float3 colorGround = lerp(colorAmbient, float3(1, 0.88, 0.47) * gray, saturate(gray * 14.0));
const float grayAmbient = Grayscale(colorAmbient);
const float3 colorGround = lerp(colorAmbient, float3(1, 0.88, 0.47) * grayAmbient, saturate(grayAmbient * 14.0));
const float3 colorAmbientFinal = lerp(colorGround, colorAmbient, saturate(normalW.y * 2.0 + 0.5));
const float3 color =
albedo * saturate(accDiff.rgb * ssaoDiff + colorAmbientFinal * ssaoAmb) +
albedo * (accDiff.rgb * ssaoDiff + colorAmbientFinal * ssaoAmb) +
accSpec.rgb * ssaoSpec +
albedo * emission.x;
const float3 colorWithFog = lerp(color, g_ubComposeFS._fogColor.rgb, fog);
so.color.rgb = lerp(colorWithFog, g_ubComposeFS._colorBackground.rgb, floor(rawGBuffer1) * g_ubComposeFS._colorBackground.a);
so.color.rgb = colorWithFog;
so.color.rgb = lerp(so.color.rgb, g_ubComposeFS._colorBackground.rgb, floor(rawDepth) * g_ubComposeFS._colorBackground.a);
so.color.a = 1.0;
#endif
#ifdef DEF_TONE_MAPPING
const float4 rawComposed = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0);
so.color.rgb = VerusToneMapping(rawComposed.rgb * g_ubComposeFS._toneMappingConfig.x, g_ubComposeFS._toneMappingConfig.y);
so.color.a = 1.0;
#endif
return so;
}
#endif
//@main:#
//@main:#Compose COMPOSE
//@main:#ToneMapping TONE_MAPPING

View file

@ -9,8 +9,10 @@ VERUS_UBUFFER UB_ComposeVS
VERUS_UBUFFER UB_ComposeFS
{
mataff _matInvV;
matrix _matInvVP;
float4 _colorAmbient;
float4 _colorBackground;
float4 _fogColor;
float4 _zNearFarEx;
float4 _toneMappingConfig;
};

View file

@ -0,0 +1,237 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibSurface.hlsl"
#include "LibVertex.hlsl"
#include "DS_Grass.inc.hlsl"
ConstantBuffer<UB_GrassVS> g_ubGrassVS : register(b0, space0);
ConstantBuffer<UB_GrassFS> g_ubGrassFS : register(b0, space1);
Texture2D g_texHeightVS : register(t1, space0);
SamplerState g_samHeightVS : register(s1, space0);
Texture2D g_texNormalVS : register(t2, space0);
SamplerState g_samNormalVS : register(s2, space0);
Texture2D g_texMLayerVS : register(t3, space0);
SamplerState g_samMLayerVS : register(s3, space0);
Texture2D g_texAlbedo : register(t1, space1);
SamplerState g_samAlbedo : register(s1, space1);
struct VSI
{
VK_LOCATION_POSITION int4 pos : POSITION;
VK_LOCATION(8) int4 tc : TEXCOORD0;
VK_LOCATION(16) int4 patchPos : INSTDATA0;
uint vertexID : SV_VertexID;
};
struct VSO
{
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
float3 tcOffset_phaseShift : TEXCOORD1;
float4 normal_top : TEXCOORD2;
float2 psize : PSIZE;
};
#ifdef _VS
VSO mainVS(VSI si)
{
VSO so;
const float phase = g_ubGrassVS._phase_mapSideInv_bushMask.x;
const float mapSideInv = g_ubGrassVS._phase_mapSideInv_bushMask.y;
const float bushMask = g_ubGrassVS._phase_mapSideInv_bushMask.z;
const float3 warp = g_ubGrassVS._warp_turb.xyz;
const float turbulence = g_ubGrassVS._warp_turb.w;
#ifdef DEF_BILLBOARDS
const uint bushID = si.vertexID;
#else
const uint bushID = si.vertexID >> 3; // 8 vertices per bush.
#endif
// <FromTextures>
float3 intactPos;
float3 pos;
float2 center;
float2 pointSpriteScale = 1.0;
float groundHeight;
float3 normal;
float2 tc0;
bool bushMaskOK = true;
{
intactPos = si.pos.xyz * (1.0 / 1000.0);
pos = intactPos + float3(si.patchPos.x, 0, si.patchPos.z);
center = si.tc.zw * (1.0 / 1000.0) + si.patchPos.xz;
#ifdef DEF_BILLBOARDS
pointSpriteScale = intactPos.y;
pos = float3(center.x, 0.45 * pointSpriteScale.y, center.y);
#endif
const float bestPrecision = 50.0;
const float distToEye = distance(pos + float3(0, si.patchPos.y * 0.01, 0), g_ubGrassVS._posEye.xyz);
const float geomipsLod = log2(clamp(distToEye * (2.0 / 100.0), 1.0, 18.0));
const float texelCenter = 0.5 * mapSideInv;
const float mipTexelCenter = texelCenter * exp2(geomipsLod);
const float2 tcMap = pos.xz * mapSideInv + 0.5;
const float2 tcUniform = center * mapSideInv + 0.5;
groundHeight = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + mipTexelCenter, geomipsLod).r + bestPrecision;
pos.y += groundHeight;
const float4 rawNormal = g_texNormalVS.SampleLevel(g_samNormalVS, tcUniform + texelCenter, 0.0);
normal = float3(rawNormal.x, 0, rawNormal.y) * 2.0 - 1.0;
normal.y = ComputeNormalZ(normal.xz);
const float layer = g_texMLayerVS.SampleLevel(g_samMLayerVS, tcUniform, 0.0).r * 4.0;
const float uShift = frac(layer) - (16.0 / 256.0);
const float vShift = floor(layer) * 0.25;
float vShiftAlt = 0.0;
if (!(bushID & 0xF))
vShiftAlt = 0.5; // Every 16th bush uses alternative texture.
tc0 = si.tc.xy * (1.0 / 100.0) + float2(uShift, vShift + vShiftAlt);
// Cull blank bushes:
const int mainLayer = round(layer * 4.0);
const int ibushMask = asint(bushMask);
if (!((ibushMask >> mainLayer) & 0x1))
{
bushMaskOK = false;
}
}
// </FromTextures>
// <Special>
float phaseShift = 0.0;
float2 windWarp = 0.0;
float top = 0.0;
{
#ifdef DEF_BILLBOARDS
phaseShift = frac(si.pos.w * (1.0 / 100.0));
windWarp = 0.0;
top = 0.28;
#else
if (intactPos.y >= 0.1)
{
phaseShift = frac(si.pos.w * (1.0 / 100.0));
windWarp = warp.xz * (1.0 + turbulence * sin((phase + phaseShift) * (_PI * 2.0)));
top = 1.0;
}
#endif
}
// </Special>
// <Warp>
float3 posWarped = pos;
{
const float distToEye = -mul(float4(posWarped, 1), g_ubGrassVS._matWV).z;
const float distant = saturate((distToEye - 50.0) * (1.0 / 50.0)); // [50.0 to 100.0] -> [0.0 to 1.0].
const float distExt = saturate((distToEye - 25.0) * (1.0 / 25.0)); // [25.0 to 50.0] -> [0.0 to 1.0].
const float cliff = dot(normal.xz, normal.xz);
float hide = cliff + step(groundHeight, 1.0) + distant;
if (!bushMaskOK)
hide = 1.0;
posWarped.xz -= normal.xz;
#ifdef DEF_BILLBOARDS
const float distExtInv = 1.0 - distExt;
posWarped.xz += windWarp * 0.5;
hide += distExtInv * distExtInv;
#else
posWarped.xz += windWarp;
posWarped.y -= dot(windWarp, windWarp);
hide += distExt * distExt;
#endif
hide = saturate(hide);
#ifdef DEF_BILLBOARDS
pointSpriteScale = lerp(pointSpriteScale, float2(0.0, pointSpriteScale.y), hide);
#else
posWarped = lerp(posWarped, float3(center.x, posWarped.y, center.y), hide); // Optimize by morphing to center point.
#endif
}
// </Warp>
const float3 posW = mul(float4(posWarped, 1), g_ubGrassVS._matW).xyz;
so.pos = mul(float4(posW, 1), g_ubGrassVS._matVP);
so.tc0 = tc0;
so.tcOffset_phaseShift = float3(0, 0, phaseShift);
so.normal_top.xyz = mul(normal, (float3x3)g_ubGrassVS._matWV);
so.normal_top.w = top;
so.psize = 1.0;
#ifdef DEF_BILLBOARDS
so.tcOffset_phaseShift.xy = tc0;
const float2 pointSize = g_ubGrassVS._viewportSize.yx * g_ubGrassVS._viewportSize.z * pointSpriteScale;
so.psize = pointSize * g_ubGrassVS._matP._m11;
#else
so.normal_top.xyz += float3(0, 0, top * top * 0.25);
#endif
return so;
}
#endif
#ifdef _GS
[maxvertexcount(4)]
void mainGS(point VSO si[1], inout TriangleStream<VSO> stream)
{
VSO so;
so = si[0];
const float2 center = so.pos.xy;
for (int i = 0; i < 4; ++i)
{
so.pos.xy = center + _POINT_SPRITE_POS_OFFSETS[i] * so.psize;
so.tc0.xy = _POINT_SPRITE_TEX_COORDS[i];
stream.Append(so);
}
}
#endif
#ifdef _FS
DS_FSO mainFS(VSO si)
{
DS_FSO so;
const float3 rand = Rand(si.pos.xy);
float2 tc = si.tc0;
#ifdef DEF_BILLBOARDS
tc = si.tc0 * 0.23 + si.tcOffset_phaseShift.xy;
#endif
const float4 rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, tc);
const float3 normal = normalize(si.normal_top.xyz);
const float gray = Grayscale(rawAlbedo.rgb);
const float mask = saturate((gray - 0.25) * 4.0 + 0.25);
const float top = si.normal_top.w;
const float spec = saturate(top * top * (mask + si.tcOffset_phaseShift.z * 0.1));
const float gloss = lerp(4.0, 12.0, spec);
{
DS_Reset(so);
DS_SetAlbedo(so, rawAlbedo.rgb);
DS_SetSpec(so, spec);
DS_SetNormal(so, normal + NormalDither(rand));
DS_SetEmission(so, 0.0, 0.0);
DS_SetLamScaleBias(so, float2(1.2, -0.2), 0.0);
DS_SetMetallicity(so, 0.05, 0.0);
DS_SetGloss(so, gloss);
}
clip(rawAlbedo.a - 0.5);
return so;
}
#endif
//@main:#
//@main:#Billboards BILLBOARDS (VGF)

View file

@ -0,0 +1,18 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
VERUS_UBUFFER UB_GrassVS
{
mataff _matW;
mataff _matWV;
matrix _matVP;
matrix _matP;
float4 _phase_mapSideInv_bushMask;
float4 _posEye;
float4 _viewportSize;
float4 _warp_turb;
};
VERUS_UBUFFER UB_GrassFS
{
float4 _dummy;
};

View file

@ -3,6 +3,8 @@
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibSurface.hlsl"
#include "LibTessellation.hlsl"
#include "LibVertex.hlsl"
#include "DS_Mesh.inc.hlsl"
@ -17,8 +19,10 @@ Texture2D g_texAlbedo : register(t1, space1);
SamplerState g_samAlbedo : register(s1, space1);
Texture2D g_texNormal : register(t2, space1);
SamplerState g_samNormal : register(s2, space1);
//Texture2D g_texDetail : register(t3, space1);
//SamplerState g_samDetail : register(s3, space1);
Texture2D g_texDetail : register(t3, space1);
SamplerState g_samDetail : register(s3, space1);
Texture2D g_texStrass : register(t4, space1);
SamplerState g_samStrass : register(s4, space1);
struct VSI
{
@ -28,18 +32,17 @@ struct VSI
VK_LOCATION(8) int4 tc0 : TEXCOORD0;
// Binding 1:
#ifdef DEF_SKINNED
VK_LOCATION(12) int4 bw : TEXCOORD4;
VK_LOCATION(13) int4 bi : TEXCOORD5;
VK_LOCATION_BLENDWEIGHTS int4 bw : BLENDWEIGHTS;
VK_LOCATION_BLENDINDICES int4 bi : BLENDINDICES;
#endif
// Binding 2:
VK_LOCATION(14) float4 tan : TEXCOORD6;
VK_LOCATION(15) float4 bin : TEXCOORD7;
VK_LOCATION_TANGENT float4 tan : TANGENT;
VK_LOCATION_BINORMAL float4 bin : BINORMAL;
// Binding 3:
#if 0
VK_LOCATION(9) int4 tc1 : TEXCOORD1;
VK_LOCATION_COLOR0 float4 color : COLOR0;
#endif
_PER_INSTANCE_DATA
};
@ -47,13 +50,14 @@ struct VSO
{
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
#ifndef DEF_DEPTH
float4 matTBN0 : TEXCOORD2;
float4 matTBN1 : TEXCOORD3;
float4 matTBN2 : TEXCOORD4;
#if !defined(DEF_DEPTH)
float4 color0 : COLOR0;
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
float4 matTBN0 : TEXCOORD1;
float4 matTBN1 : TEXCOORD2;
float4 matTBN2 : TEXCOORD3;
#endif
#endif
float2 depth : TEXCOORD6;
};
#ifdef _VS
@ -142,15 +146,76 @@ VSO mainVS(VSI si)
#endif
}
so.pos = mul(float4(posW, 1), g_ubPerFrame._matVP);
so.pos = MulTessPos(float4(posW, 1), g_ubPerFrame._matV, g_ubPerFrame._matVP);
so.tc0 = intactTc0;
#ifndef DEF_DEPTH
#if !defined(DEF_DEPTH)
so.color0 = userColor;
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
so.matTBN0 = float4(tanWV, posW.x);
so.matTBN1 = float4(binWV, posW.y);
so.matTBN2 = float4(nrmWV, posW.z);
so.color0 = userColor;
#endif
so.depth = so.pos.zw;
#endif
return so;
}
#endif
_HSO_STRUCT;
#ifdef _HS
PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
{
PCFO so;
_HS_PCF_BODY(g_ubPerFrame._matP);
return so;
}
[domain("tri")]
//[maxtessfactor(7.0)]
[outputcontrolpoints(3)]
[outputtopology("triangle_cw")]
[partitioning(_PARTITION_METHOD)]
[patchconstantfunc("PatchConstFunc")]
HSO mainHS(InputPatch<VSO, 3> inputPatch, uint id : SV_OutputControlPointID)
{
HSO so;
_HS_PN_BODY(matTBN2, g_ubPerFrame._matP, g_ubPerFrame._viewportSize);
_HS_COPY(pos);
_HS_COPY(tc0);
#if !defined(DEF_DEPTH)
_HS_COPY(color0);
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
_HS_COPY(matTBN0);
_HS_COPY(matTBN1);
_HS_COPY(matTBN2);
#endif
#endif
return so;
}
#endif
#ifdef _DS
[domain("tri")]
VSO mainDS(_IN_DS)
{
VSO so;
_DS_INIT_SMOOTH_POS;
so.pos = ApplyProjection(smoothPosWV, g_ubPerFrame._matP);
_DS_COPY(tc0);
#if !defined(DEF_DEPTH)
_DS_COPY(color0);
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
_DS_COPY(matTBN0);
_DS_COPY(matTBN1);
_DS_COPY(matTBN2);
#endif
#endif
return so;
}
@ -170,13 +235,8 @@ DS_FSO mainFS(VSO si)
{
DS_FSO so;
#ifdef DEF_SOLID
DS_Reset(so);
DS_SetAlbedo(so, si.color0.rgb);
DS_SetDepth(so, si.depth.x / si.depth.y);
DS_SetNormal(so, float3(0, 0, 1));
DS_SetEmission(so, 1.0, 0.0);
DS_SetMetallicity(so, 1.0, 0.0);
#ifdef DEF_SOLID_COLOR
DS_SolidColor(so, si.color0.rgb);
#else
_TBN_SPACE(
si.matTBN0.xyz,
@ -185,11 +245,16 @@ DS_FSO mainFS(VSO si)
const float3 rand = Rand(si.pos.xy);
// <Albedo>
float4 rawAlbedo;
{
const float texAlbedoEnable = ceil(g_ubPerMaterialFS._texEnableAlbedo.a);
float4 rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, si.tc0 * texAlbedoEnable);
rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, si.tc0 * texAlbedoEnable);
rawAlbedo.rgb = lerp(g_ubPerMaterialFS._texEnableAlbedo.rgb, rawAlbedo.rgb, g_ubPerMaterialFS._texEnableAlbedo.a);
const float2 alpha_spec = AlphaSwitch(rawAlbedo, si.tc0, g_ubPerMaterialFS._ssb_as.zw);
}
const float gray = Grayscale(rawAlbedo.rgb);
// </Albedo>
const float2 alpha_spec = AlphaSwitch(rawAlbedo, si.tc0, g_ubPerMaterialFS._ssb_as.zw);
const float emitAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._emitPick, 16.0);
const float emitXAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._emitXPick, 16.0);
const float eyeAlpha = PickAlphaRound(g_ubPerMaterialFS._eyePick, si.tc0);
@ -199,61 +264,79 @@ DS_FSO mainFS(VSO si)
const float skinAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._skinPick, 16.0);
const float userAlpha = PickAlphaHue(rawAlbedo.rgb, g_ubPerMaterialFS._userPick, 32.0);
// Add details:
#if 0
const float3 colorDetail = (g_texDetail.Sample(g_samDetail, frac(si.tc0 * g_ubPerMaterialFS._ds_scale.zw)).rgb - 0.5) *
g_ubPerMaterialFS._ds_scale.x + 0.5;
rawAlbedo.rgb = rawAlbedo.rgb * colorDetail * 2.0;
#endif
const float gray = Grayscale(rawAlbedo.rgb);
rawAlbedo.rgb = lerp(rawAlbedo.rgb, Overlay(gray, si.color0.rgb), userAlpha * si.color0.a);
// </Albedo>
const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * g_ubPerMaterialFS._hairParams.w));
// <Gloss>
//float gloss = lerp(g_ubPerMaterialFS._lsb_gloss_lp.z, g_ubPerMaterialFS._motionBlur_glossX.y, glossXAlpha);
float gloss = lerp(4.4, 16.0, alpha_spec.y);
gloss = lerp(gloss, 4.0 + alpha_spec.y, skinAlpha);
gloss = lerp(gloss, 0.0, eyeAlpha);
// </Gloss>
// <Normal>
float3 normalWV;
float toksvigFactor;
float lightPassStrength;
float3 anisoWV;
{
const float texNormalEnable = ceil(g_ubPerMaterialFS._texEnableNormal.a);
float4 rawNormal = g_texNormal.Sample(g_samNormal, si.tc0 * texNormalEnable);
rawNormal = lerp(g_ubPerMaterialFS._texEnableNormal.rgbr, rawNormal, g_ubPerMaterialFS._texEnableNormal.a);
const float4 normalAA = NormalMapAA(rawNormal);
const float3 normalTBN = normalAA.xyz;
const float3 normalWV = normalize(mul(normalTBN, matFromTBN));
const float3 anisoWV = normalize(mul(cross(normalTBN, cross(g_ubPerMaterialFS._hairParams.xyz, normalTBN)), matFromTBN));
// Almost solid hair color is used for picking.
// Final albedo is calculated using specualar component.
const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * g_ubPerMaterialFS._hairParams.w));
normalWV = normalize(mul(normalTBN, matFromTBN));
toksvigFactor = ComputeToksvigFactor(normalAA.a, gloss);
lightPassStrength = rawNormal.r;
anisoWV = normalize(mul(cross(normalTBN, cross(g_ubPerMaterialFS._hairParams.xyz, normalTBN)), matFromTBN));
}
// </Normal>
// <Detail>
{
const float3 rawDetail = g_texDetail.Sample(g_samDetail, si.tc0 * g_ubPerMaterialFS._ds_scale.zw).rgb;
rawAlbedo.rgb = rawAlbedo.rgb * lerp(0.5, rawDetail, g_ubPerMaterialFS._ds_scale.x) * 2.0;
}
// </Detail>
// <Strass>
float strass;
{
const float rawStrass = g_texStrass.Sample(g_samStrass, si.tc0 * g_ubPerMaterialFS._ds_scale.zw * 2.0).r;
strass = saturate(rawStrass * (0.3 + 0.7 * alpha_spec.y) * 4.0) * g_ubPerMaterialFS._ds_scale.y;
}
// </Strass>
// <LambertianScaleBias>
float2 lamScaleBias = g_ubPerMaterialFS._lsb_gloss_lp.xy + float2(0, rawNormal.r * 8.0 * g_ubPerMaterialFS._lsb_gloss_lp.w);
float2 lamScaleBias = g_ubPerMaterialFS._lsb_gloss_lp.xy + float2(0, lightPassStrength * 8.0 * g_ubPerMaterialFS._lsb_gloss_lp.w);
lamScaleBias += float2(-0.1, -0.3) * alpha_spec.y + float2(0.1, 0.2); // We bring the noise!
lamScaleBias = lerp(lamScaleBias, float2(1, 0.45), skinAlpha);
// </LambertianScaleBias>
// <Gloss>
float gloss = lerp(g_ubPerMaterialFS._lsb_gloss_lp.z, g_ubPerMaterialFS._motionBlur_glossX.y, glossXAlpha);
gloss = lerp(gloss, 4.0 + alpha_spec.y, skinAlpha);
gloss = lerp(gloss, 0.0, eyeAlpha);
// </Gloss>
const float strass = 0.0;
// <RimAlbedo>
//const float rimA = lerp(0.3 + alpha_spec.y*0.3, 0.7, skinAlpha);
//const float3 rimAlbedo = saturate(rawAlbedo.rgb*rimA*2.0);
//const float rimAlbedoAmount = 1.0 - abs(normalWV.z);
//rawAlbedo.rgb = lerp(rawAlbedo.rgb, rimAlbedo, rimAlbedoAmount*rimAlbedoAmount);
{
const float3 newColor = saturate((rawAlbedo.rgb + gray) * 0.6);
const float mask = 1.0 - abs(normalWV.z);
rawAlbedo.rgb = lerp(rawAlbedo.rgb, newColor, mask * mask * (1.0 - alpha_spec.y));
}
// </RimAlbedo>
{
DS_Reset(so);
DS_SetAlbedo(so, lerp(rawAlbedo.rgb, hairAlbedo, hairAlpha));
DS_SetSpec(so, normalAA.w * max(eyeAlpha, max(strass,
DS_SetSpec(so, max(eyeAlpha, max(strass,
alpha_spec.y * (1.0 + hairAlpha * 0.75) * g_ubPerMaterialFS._ssb_as.x + g_ubPerMaterialFS._ssb_as.y)));
DS_SetDepth(so, si.depth.x / si.depth.y);
DS_SetNormal(so, normalWV + NormalDither(rand));
DS_SetEmission(so, max(emitAlpha, emitXAlpha) * alpha_spec.y, skinAlpha);
DS_SetLamScaleBias(so, lamScaleBias, float4(anisoWV, hairAlpha));
DS_SetMetallicity(so, metalAlpha, hairAlpha);
DS_SetGloss(so, normalAA.w * gloss);
DS_SetGloss(so, gloss * lerp(toksvigFactor, 1.0, eyeAlpha));
}
clip(alpha_spec.x - 0.5);
#endif
return so;
@ -262,8 +345,19 @@ DS_FSO mainFS(VSO si)
#endif
//@main:#
//@main:#DepthRobotic DEPTH ROBOTIC (V)
//@main:#DepthSkinned DEPTH SKINNED (V)
//@main:#Instanced INSTANCED
//@main:#Robotic ROBOTIC
//@main:#Skinned SKINNED
//@main:#Instanced INSTANCED
//@main:#Depth DEPTH (V)
//@main:#DepthRobotic DEPTH ROBOTIC (V)
//@main:#DepthSkinned DEPTH SKINNED (V)
//@main:#SolidColor SOLID_COLOR
//@main:#SolidColorRobotic SOLID_COLOR ROBOTIC
//@main:#SolidColorSkinned SOLID_COLOR SKINNED
//@main:#Tess TESS (VHDF)
//@main:#TessRobotic TESS ROBOTIC (VHDF)
//@main:#TessSkinned TESS SKINNED (VHDF)

View file

@ -3,8 +3,9 @@
VERUS_UBUFFER UB_PerFrame
{
mataff _matV;
matrix _matP;
matrix _matVP;
matrix _matP;
float4 _viewportSize;
};
VERUS_UBUFFER UB_PerMaterialFS

View file

@ -3,15 +3,20 @@
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibSurface.hlsl"
#include "LibTessellation.hlsl"
#include "DS_Terrain.inc.hlsl"
#define HEIGHT_SCALE 0.01
#define DETAIL_TC_SCALE 8.0
ConstantBuffer<UB_DrawDepth> g_ubDrawDepth : register(b0, space0);
ConstantBuffer<UB_PerMaterialFS> g_ubPerMaterialFS : register(b0, space1);
ConstantBuffer<UB_TerrainVS> g_ubTerrainVS : register(b0, space0);
ConstantBuffer<UB_TerrainFS> g_ubTerrainFS : register(b0, space1);
Texture2D g_texHeightVS : register(t1, space0);
SamplerState g_samHeightVS : register(s1, space0);
Texture2D g_texNormalVS : register(t2, space0);
SamplerState g_samNormalVS : register(s2, space0);
Texture2D g_texHeight : register(t1, space0);
SamplerState g_samHeight : register(s1, space0);
Texture2D g_texNormal : register(t1, space1);
SamplerState g_samNormal : register(s1, space1);
Texture2D g_texBlend : register(t2, space1);
@ -20,60 +25,145 @@ Texture2DArray g_texLayers : register(t3, space1);
SamplerState g_samLayers : register(s3, space1);
Texture2DArray g_texLayersNM : register(t4, space1);
SamplerState g_samLayersNM : register(s4, space1);
Texture2D g_texDetail : register(t5, space1);
SamplerState g_samDetail : register(s5, space1);
struct VSI
{
VK_LOCATION_POSITION int4 pos : POSITION;
VK_LOCATION(16) int4 posPatch : TEXCOORD8;
VK_LOCATION(17) int4 layerForChannel : TEXCOORD9;
VK_LOCATION(16) int4 posPatch : INSTDATA0;
VK_LOCATION(17) int4 layerForChannel : INSTDATA1;
};
struct VSO
{
float4 pos : SV_Position;
float4 layerForChannel : TEXCOORD0;
#ifndef DEF_DEPTH
float3 tcBlend : TEXCOORD1;
float4 tcLayer_tcMap : TEXCOORD2;
float3 nrmWV : TEXCOORD0;
#if !defined(DEF_DEPTH)
float4 layerForChannel : TEXCOORD1;
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
float3 tcBlend : TEXCOORD2;
float4 tcLayer_tcMap : TEXCOORD3;
#endif
#endif
float2 depth : TEXCOORD3;
};
static const float g_bestPrecision = 50.0;
static const float g_layerScale = 1.0 / 8.0;
#ifdef _VS
VSO mainVS(VSI si)
{
VSO so;
const float3 posEye = g_ubDrawDepth._posEye_mapSideInv.xyz;
const float mapSideInv = g_ubDrawDepth._posEye_mapSideInv.w;
const float3 eyePos = g_ubTerrainVS._eyePos_mapSideInv.xyz;
const float mapSideInv = g_ubTerrainVS._eyePos_mapSideInv.w;
const float2 edgeCorrection = si.pos.yw;
si.pos.yw = 0.0;
float3 pos = si.pos.xyz + si.posPatch.xyz * float3(1, HEIGHT_SCALE, 1);
float3 pos = si.pos.xyz + si.posPatch.xyz;
const float2 tcMap = pos.xz * mapSideInv + 0.5; // Range [0, 1).
const float2 posBlend = pos.xz + edgeCorrection * 0.5;
const float bestPrecision = 50.0;
const float2 tcMap = pos.xz * mapSideInv + 0.5; // Range [0, 1).
const float distToEye = distance(pos, posEye);
// <HeightAndNormal>
float3 intactNrm;
{
const float approxHeight = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r + g_bestPrecision;
pos.y = approxHeight;
const float distToEye = distance(pos, eyePos);
const float geomipsLod = log2(clamp(distToEye * (2.0 / 100.0), 1.0, 18.0));
const float geomipsLodFrac = frac(geomipsLod);
const float geomipsLodBase = floor(geomipsLod);
const float geomipsLodNext = geomipsLodBase + 1.0;
const float2 halfTexelAB = (0.5 * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
const float yA = g_texHeight.SampleLevel(g_samHeight, tcMap + halfTexelAB.xx, geomipsLodBase).r + bestPrecision;
const float yB = g_texHeight.SampleLevel(g_samHeight, tcMap + halfTexelAB.yy, geomipsLodNext).r + bestPrecision;
const float2 texelCenterAB = (0.5 * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
const float yA = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.xx, geomipsLodBase).r + g_bestPrecision;
const float yB = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.yy, geomipsLodNext).r + g_bestPrecision;
pos.y = lerp(yA, yB, geomipsLodFrac);
so.pos = mul(float4(pos, 1), g_ubDrawDepth._matVP);
const float4 rawNormal = g_texNormalVS.SampleLevel(g_samNormalVS, tcMap + texelCenterAB.xx, geomipsLodBase);
intactNrm = float3(rawNormal.x, 0, rawNormal.y) * 2.0 - 1.0;
intactNrm.y = ComputeNormalZ(intactNrm.xz);
}
// </HeightAndNormal>
so.pos = MulTessPos(float4(pos, 1), g_ubTerrainVS._matV, g_ubTerrainVS._matVP);
so.nrmWV = mul(intactNrm, (float3x3)g_ubTerrainVS._matWV);
#if !defined(DEF_DEPTH)
so.layerForChannel = si.layerForChannel;
#ifndef DEF_DEPTH
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
so.tcBlend.xy = posBlend * mapSideInv + 0.5;
so.tcBlend.z = pos.y + 0.75;
so.tcLayer_tcMap.xy = pos.xz * (1.0 / 8.0);
so.tcBlend.z = pos.y;
so.tcLayer_tcMap.xy = pos.xz * g_layerScale;
so.tcLayer_tcMap.zw = (pos.xz + 0.5) * mapSideInv + 0.5; // Texel's center.
#endif
so.depth = so.pos.zw;
#endif
return so;
}
#endif
_HSO_STRUCT;
#ifdef _HS
PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
{
PCFO so;
_HS_PCF_BODY(g_ubTerrainVS._matP);
return so;
}
[domain("tri")]
//[maxtessfactor(7.0)]
[outputcontrolpoints(3)]
[outputtopology("triangle_cw")]
[partitioning(_PARTITION_METHOD)]
[patchconstantfunc("PatchConstFunc")]
HSO mainHS(InputPatch<VSO, 3> inputPatch, uint id : SV_OutputControlPointID)
{
HSO so;
_HS_PN_BODY(nrmWV, g_ubTerrainVS._matP, g_ubTerrainVS._viewportSize);
_HS_COPY(pos);
_HS_COPY(nrmWV);
#if !defined(DEF_DEPTH)
_HS_COPY(layerForChannel);
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
_HS_COPY(tcBlend);
_HS_COPY(tcLayer_tcMap);
#endif
#endif
return so;
}
#endif
#ifdef _DS
[domain("tri")]
VSO mainDS(_IN_DS)
{
VSO so;
_DS_INIT_FLAT_POS;
_DS_INIT_SMOOTH_POS;
so.pos = ApplyProjection(smoothPosWV, g_ubTerrainVS._matP);
_DS_COPY(nrmWV);
#if !defined(DEF_DEPTH)
_DS_COPY(layerForChannel);
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
_DS_COPY(tcBlend);
_DS_COPY(tcLayer_tcMap);
#endif
#endif
#ifndef DEF_DEPTH
// Fade to non-tess mesh at 80 meters. LOD 1 starts at 100 meters.
const float tessStrength = saturate((1.0 - saturate(smoothPosWV.z / -80.0)) * 4.0);
const float3 posWV = lerp(flatPosWV, smoothPosWV, tessStrength);
so.pos = ApplyProjection(posWV, g_ubTerrainVS._matP);
#endif
return so;
}
@ -84,15 +174,15 @@ DS_FSO mainFS(VSO si)
{
DS_FSO so;
#ifdef DEF_SOLID_COLOR
DS_SolidColor(so, si.layerForChannel.rgb);
#else
const float3 rand = Rand(si.pos.xy);
const float4 layerForChannel = round(si.layerForChannel);
const float2 tcLayer = si.tcLayer_tcMap.xy;
const float2 tcMap = si.tcLayer_tcMap.zw;
const float gloss = 4.0;
const float4 layerForChannel = round(si.layerForChannel);
const float4 rawBlend = g_texBlend.Sample(g_samBlend, si.tcBlend.xy);
float4 weights = float4(rawBlend.rgb, 1.0 - dot(rawBlend.rgb, float3(1, 1, 1)));
@ -108,9 +198,9 @@ DS_FSO mainFS(VSO si)
basisBin = cross(basisTan, basisNrm);
}
_TBN_SPACE(
mul(basisTan, (float3x3)g_ubDrawDepth._matWV),
mul(basisBin, (float3x3)g_ubDrawDepth._matWV),
mul(basisNrm, (float3x3)g_ubDrawDepth._matWV));
mul(basisTan, (float3x3)g_ubTerrainFS._matWV),
mul(basisBin, (float3x3)g_ubTerrainFS._matWV),
mul(basisNrm, (float3x3)g_ubTerrainFS._matWV));
// </Basis>
// <Albedo>
@ -140,8 +230,8 @@ DS_FSO mainFS(VSO si)
accAlbedo += rawAlbedos[3] * weights.a;
albedo = accAlbedo;
static float vSpecStrength[_MAX_TERRAIN_LAYERS] = (float[_MAX_TERRAIN_LAYERS])g_ubPerMaterialFS._vSpecStrength;
static float vDetailStrength[_MAX_TERRAIN_LAYERS] = (float[_MAX_TERRAIN_LAYERS])g_ubPerMaterialFS._vDetailStrength;
static float vSpecStrength[_MAX_TERRAIN_LAYERS] = (float[_MAX_TERRAIN_LAYERS])g_ubTerrainFS._vSpecStrength;
static float vDetailStrength[_MAX_TERRAIN_LAYERS] = (float[_MAX_TERRAIN_LAYERS])g_ubTerrainFS._vDetailStrength;
const float4 specStrengthForChannel = float4(
vSpecStrength[layerForChannel.r],
vSpecStrength[layerForChannel.g],
@ -157,26 +247,58 @@ DS_FSO mainFS(VSO si)
}
// </Albedo>
// <Water>
float waterGlossBoost = 0.0;
{
const float dryMask = saturate(si.tcBlend.z);
const float dryMask3 = dryMask * dryMask * dryMask;
const float wetMask = 1.0 - dryMask;
const float wetMask3 = wetMask * wetMask * wetMask;
albedo.rgb *= dryMask3 * 0.5 + 0.5;
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3);
waterGlossBoost = min(32.0, dryMask * wetMask3 * 128.0);
}
// </Water>
const float gloss = lerp(3.3, 15.0, specStrength) + waterGlossBoost;
// <Normal>
float3 normalWV;
float4 normalAA;
float toksvigFactor;
{
float4 accNormal = 0.0;
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.r)) * weights.r;
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.g)) * weights.g;
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.b)) * weights.b;
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.a)) * weights.a;
normalAA = NormalMapAA(accNormal);
accNormal = lerp(accNormal, float4(0, 0.5, 0.5, 0.5), 0.5);
const float4 normalAA = NormalMapAA(accNormal);
normalWV = normalize(mul(normalAA.xyz, matFromTBN));
toksvigFactor = ComputeToksvigFactor(normalAA.a, gloss);
}
// </Normal>
DS_Test(so, 0.0, 0.5, 16.0);
// <Detail>
{
const float3 rawDetail = g_texDetail.Sample(g_samDetail, tcLayer * DETAIL_TC_SCALE).rgb;
albedo.rgb = albedo.rgb * lerp(0.5, rawDetail, detailStrength) * 2.0;
}
// </Detail>
{
DS_Reset(so);
DS_SetAlbedo(so, albedo.rgb);
DS_SetDepth(so, si.depth.x / si.depth.y);
DS_SetSpec(so, specStrength);
DS_SetNormal(so, normalWV + NormalDither(rand));
DS_SetSpec(so, normalAA.w * specStrength);
DS_SetGloss(so, normalAA.w * gloss);
DS_SetEmission(so, 0.0, 0.0);
DS_SetLamScaleBias(so, g_ubTerrainFS._lamScaleBias.xy, float4(0, 0, 1, 0));
DS_SetMetallicity(so, 0.05, 0.0);
DS_SetGloss(so, gloss * toksvigFactor);
}
#endif
return so;
}
@ -184,3 +306,5 @@ DS_FSO mainFS(VSO si)
//@main:#
//@main:#Depth DEPTH (V)
//@main:#SolidColor SOLID_COLOR
//@main:#Tess TESS (VHDF)

View file

@ -1,15 +1,20 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
VERUS_UBUFFER UB_DrawDepth
VERUS_UBUFFER UB_TerrainVS
{
mataff _matW;
mataff _matWV;
mataff _matWV; // For normal.
mataff _matV; // For tess.
matrix _matVP;
float4 _posEye_mapSideInv;
matrix _matP; // For tess.
float4 _eyePos_mapSideInv;
float4 _viewportSize;
};
VERUS_UBUFFER UB_PerMaterialFS
VERUS_UBUFFER UB_TerrainFS
{
mataff _matWV; // For basis.
float4 _vSpecStrength[8];
float4 _vDetailStrength[8];
float4 _lamScaleBias;
};

View file

@ -16,8 +16,8 @@ RWTexture2D<float4> g_uavOutMip4 : register(u5, space0);
struct CSI
{
uint3 _DispatchThreadID : SV_DispatchThreadID;
uint _GroupIndex : SV_GroupIndex;
uint3 dispatchThreadID : SV_DispatchThreadID;
uint groupIndex : SV_GroupIndex;
};
#define THREAD_GROUP_SIZE 8
@ -67,14 +67,14 @@ void mainCS(CSI si)
{
case DIM_CASE_WE_HE:
{
const float2 tc = g_ub._texelSize * (si._DispatchThreadID.xy + 0.5);
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + 0.5);
srcColor1 = g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel);
}
break;
case DIM_CASE_WO_HE:
{
const float2 tc = g_ub._texelSize * (si._DispatchThreadID.xy + float2(0.25, 0.5));
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.5));
const float2 offset = g_ub._texelSize * float2(0.5, 0.0);
srcColor1 = lerp(
@ -85,7 +85,7 @@ void mainCS(CSI si)
break;
case DIM_CASE_WE_HO:
{
const float2 tc = g_ub._texelSize * (si._DispatchThreadID.xy + float2(0.5, 0.25));
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.5, 0.25));
const float2 offset = g_ub._texelSize * float2(0.0, 0.5);
srcColor1 = lerp(
@ -96,7 +96,7 @@ void mainCS(CSI si)
break;
case DIM_CASE_WO_HO:
{
const float2 tc = g_ub._texelSize * (si._DispatchThreadID.xy + float2(0.25, 0.25));
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.25));
const float2 offset = g_ub._texelSize * 0.5;
srcColor1 = lerp(
@ -112,24 +112,24 @@ void mainCS(CSI si)
break;
}
g_uavOutMip1[si._DispatchThreadID.xy] = PackColor(srcColor1);
g_uavOutMip1[si.dispatchThreadID.xy] = PackColor(srcColor1);
if (1 == g_ub._mipLevelCount)
return;
StoreColor(si._GroupIndex, srcColor1);
StoreColor(si.groupIndex, srcColor1);
GroupMemoryBarrierWithGroupSync();
if ((si._GroupIndex & 0x9) == 0) // 16 threads:
if ((si.groupIndex & 0x9) == 0) // 16 threads:
{
const float4 srcColor2 = LoadColor(si._GroupIndex + 0x01); // {+0, +1}
const float4 srcColor3 = LoadColor(si._GroupIndex + 0x08); // {+1, +0}
const float4 srcColor4 = LoadColor(si._GroupIndex + 0x09); // {+1, +1}
const float4 srcColor2 = LoadColor(si.groupIndex + 0x01); // {+0, +1}
const float4 srcColor3 = LoadColor(si.groupIndex + 0x08); // {+1, +0}
const float4 srcColor4 = LoadColor(si.groupIndex + 0x09); // {+1, +1}
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
g_uavOutMip2[si._DispatchThreadID.xy >> 1] = PackColor(srcColor1);
StoreColor(si._GroupIndex, srcColor1);
g_uavOutMip2[si.dispatchThreadID.xy >> 1] = PackColor(srcColor1);
StoreColor(si.groupIndex, srcColor1);
}
if (2 == g_ub._mipLevelCount)
@ -137,15 +137,15 @@ void mainCS(CSI si)
GroupMemoryBarrierWithGroupSync();
if ((si._GroupIndex & 0x1B) == 0) // 4 threads:
if ((si.groupIndex & 0x1B) == 0) // 4 threads:
{
const float4 srcColor2 = LoadColor(si._GroupIndex + 0x02); // {+0, +2}
const float4 srcColor3 = LoadColor(si._GroupIndex + 0x10); // {+2, +0}
const float4 srcColor4 = LoadColor(si._GroupIndex + 0x12); // {+2, +2}
const float4 srcColor2 = LoadColor(si.groupIndex + 0x02); // {+0, +2}
const float4 srcColor3 = LoadColor(si.groupIndex + 0x10); // {+2, +0}
const float4 srcColor4 = LoadColor(si.groupIndex + 0x12); // {+2, +2}
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
g_uavOutMip3[si._DispatchThreadID.xy >> 2] = PackColor(srcColor1);
StoreColor(si._GroupIndex, srcColor1);
g_uavOutMip3[si.dispatchThreadID.xy >> 2] = PackColor(srcColor1);
StoreColor(si.groupIndex, srcColor1);
}
if (3 == g_ub._mipLevelCount)
@ -153,14 +153,14 @@ void mainCS(CSI si)
GroupMemoryBarrierWithGroupSync();
if (si._GroupIndex == 0) // 1 thread:
if (si.groupIndex == 0) // 1 thread:
{
const float4 srcColor2 = LoadColor(si._GroupIndex + 0x04); // {+0, +4}
const float4 srcColor3 = LoadColor(si._GroupIndex + 0x20); // {+4, +0}
const float4 srcColor4 = LoadColor(si._GroupIndex + 0x24); // {+4, +4}
const float4 srcColor2 = LoadColor(si.groupIndex + 0x04); // {+0, +4}
const float4 srcColor3 = LoadColor(si.groupIndex + 0x20); // {+4, +0}
const float4 srcColor4 = LoadColor(si.groupIndex + 0x24); // {+4, +4}
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
g_uavOutMip4[si._DispatchThreadID.xy >> 3] = PackColor(srcColor1);
g_uavOutMip4[si.dispatchThreadID.xy >> 3] = PackColor(srcColor1);
}
}
#endif

View file

@ -6,12 +6,14 @@
#ifdef _VULKAN
# define VK_LOCATION(x) [[vk::location(x)]]
# define VK_LOCATION_POSITION [[vk::location(0)]]
# define VK_LOCATION_BLENDWEIGHT [[vk::location(1)]]
# define VK_LOCATION_BLENDWEIGHTS [[vk::location(1)]]
# define VK_LOCATION_BLENDINDICES [[vk::location(6)]]
# define VK_LOCATION_NORMAL [[vk::location(2)]]
# define VK_LOCATION_PSIZE [[vk::location(7)]]
# define VK_LOCATION_TANGENT [[vk::location(14)]]
# define VK_LOCATION_BINORMAL [[vk::location(15)]]
# define VK_LOCATION_COLOR0 [[vk::location(3)]]
# define VK_LOCATION_COLOR1 [[vk::location(4)]]
# define VK_LOCATION_PSIZE [[vk::location(7)]]
# define VK_PUSH_CONSTANT [[vk::push_constant]]
# define VK_SUBPASS_INPUT(index, tex, sam, t, s, space) layout(input_attachment_index = index) SubpassInput<float4> tex : register(t, space)
@ -26,12 +28,14 @@
#else
# define VK_LOCATION(x)
# define VK_LOCATION_POSITION
# define VK_LOCATION_BLENDWEIGHT
# define VK_LOCATION_BLENDWEIGHTS
# define VK_LOCATION_BLENDINDICES
# define VK_LOCATION_NORMAL
# define VK_LOCATION_PSIZE
# define VK_LOCATION_TANGENT
# define VK_LOCATION_BINORMAL
# define VK_LOCATION_COLOR0
# define VK_LOCATION_COLOR1
# define VK_LOCATION_PSIZE
# define VK_PUSH_CONSTANT
# define VK_SUBPASS_INPUT(index, tex, sam, t, s, space)\
@ -45,10 +49,10 @@
#ifdef DEF_INSTANCED
# define _PER_INSTANCE_DATA\
VK_LOCATION(16) float4 matPart0 : TEXCOORD8;\
VK_LOCATION(17) float4 matPart1 : TEXCOORD9;\
VK_LOCATION(18) float4 matPart2 : TEXCOORD10;\
VK_LOCATION(19) float4 instData : TEXCOORD11;
VK_LOCATION(16) float4 matPart0 : INSTDATA0;\
VK_LOCATION(17) float4 matPart1 : INSTDATA1;\
VK_LOCATION(18) float4 matPart2 : INSTDATA2;\
VK_LOCATION(19) float4 instData : INSTDATA3;
#else
# define _PER_INSTANCE_DATA
#endif
@ -57,6 +61,8 @@
const float3x3 matFromTBN = float3x3(tan, bin, nrm);\
const float3x3 matToTBN = transpose(matFromTBN);
#define _PI 3.141592654
#define _SINGULARITY_FIX 0.001
#define _MAX_TERRAIN_LAYERS 32
@ -70,18 +76,6 @@ matrix ToFloat4x4(mataff m)
float4(m[3], 1));
}
float ComputeNormalZ(float2 v)
{
return sqrt(saturate(1.0 - dot(v.rg, v.rg)));
}
float4 NormalMapAA(float4 rawNormal)
{
float3 normal = rawNormal.agb * -2.0 + 1.0; // Dmitry's reverse!
normal.b = ComputeNormalZ(normal.rg);
return float4(normal, 0.8 + rawNormal.b * 0.8);
}
float3 Rand(float2 uv)
{
return frac(sin(dot(uv, float2(12.9898, 78.233)) * float3(1, 2, 3)) * 43758.5453);
@ -92,3 +86,19 @@ float3 NormalDither(float3 rand)
const float2 rr = rand.xy * (1.0 / 333.0) - (0.5 / 333.0);
return float3(rr, 0);
}
static const float2 _POINT_SPRITE_POS_OFFSETS[4] =
{
float2(-0.5, 0.5),
float2(-0.5, -0.5),
float2(0.5, 0.5),
float2(0.5, -0.5)
};
static const float2 _POINT_SPRITE_TEX_COORDS[4] =
{
float2(0, 0),
float2(0, 1),
float2(1, 0),
float2(1, 1)
};

View file

@ -1,37 +1,5 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
// See: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
float4 ColorToLinear(float4 x)
{
const float3 rgb = x.rgb < 0.04045 ? x.rgb * (1.0 / 12.92) : pow(abs(x.rgb + 0.055) / 1.055, 2.4);
return float4(rgb, x.a);
}
float4 ColorToSRGB(float4 x)
{
const float3 rgb = x.rgb < 0.0031308 ? 12.92 * x.rgb : 1.055 * pow(abs(x.rgb), 1.0 / 2.4) - 0.055;
return float4(rgb, x.a);
}
float4 HDRColorToLinear(float4 x)
{
return float4(x.rgb * x.rgb * 12.0, x.a);
}
float4 HDRColorToSRGB(float4 x)
{
return float4(sqrt(saturate(x.rgb * (1.0 / 12.0))), x.a);
}
// See: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
float3 ToneMappingACES(float3 x)
{
const float a = 2.51f;
const float b = 0.03f;
const float c = 2.43f;
const float d = 0.59f;
const float e = 0.14f;
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
}
// See: https://en.wikipedia.org/wiki/Grayscale
float Grayscale(float3 color)
{
@ -44,12 +12,6 @@ float3 Desaturate(float3 color, float alpha, float lum = 1.0)
return lerp(color, gray, alpha);
}
float3 DesaturateFilmic(float3 color)
{
const float gray = Grayscale(color);
return lerp(color, gray, saturate(gray * gray * gray));
}
// See: http://www.chilliant.com/rgb2hsv.html
float3 ConvertRGBtoHCV(float3 color)
{
@ -96,3 +58,41 @@ float2 AlphaSwitch(float4 albedo, float2 tc, float2 alphaSwitch)
else
return saturate(float2(albedo.a * 8.0, (albedo.a - 0.15) / 0.85)); // 5-bit alpha.
}
// See: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
float4 ColorToLinear(float4 x)
{
const float3 rgb = x.rgb < 0.04045 ? x.rgb * (1.0 / 12.92) : pow(abs(x.rgb + 0.055) / 1.055, 2.4);
return float4(rgb, x.a);
}
float4 ColorToSRGB(float4 x)
{
const float3 rgb = x.rgb < 0.0031308 ? 12.92 * x.rgb : 1.055 * pow(abs(x.rgb), 1.0 / 2.4) - 0.055;
return float4(rgb, x.a);
}
float4 HDRColorToLinear(float4 x)
{
return float4(x.rgb * x.rgb * 12.0, x.a);
}
float4 HDRColorToSRGB(float4 x)
{
return float4(sqrt(saturate(x.rgb * (1.0 / 12.0))), x.a);
}
// See: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
float3 ToneMappingACES(float3 x)
{
const float a = 2.51f;
const float b = 0.03f;
const float c = 2.43f;
const float d = 0.59f;
const float e = 0.14f;
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
}
float3 VerusToneMapping(float3 hdr, float filmicLook = 1.0)
{
const float3 ldr = lerp(1.0 - exp(-hdr), ToneMappingACES(hdr), filmicLook);
return saturate(ldr);
}

View file

@ -2,10 +2,9 @@
struct DS_FSO
{
float4 target0 : SV_Target0; // {color, spec}
float4 target1 : SV_Target1; // {depth}
float4 target2 : SV_Target2; // {normal, emission, motion}
float4 target3 : SV_Target3; // {lam, metal, gloss}
float4 target0 : SV_Target0; // {albedo, spec}
float4 target1 : SV_Target1; // {normal, emission, motion}
float4 target2 : SV_Target2; // {lam, metal, gloss}
};
struct DS_ACC_FSO
@ -35,15 +34,20 @@ void DS_Reset(out DS_FSO so)
so.target0 = 0.0;
so.target1 = 0.0;
so.target2 = 0.0;
so.target3 = 0.0;
}
void DS_SolidColor(out DS_FSO so, float3 color)
{
so.target0 = float4(color, 0.0);
so.target1 = float4(EncodeNormal(float3(0, 0, 1)), 1.0, 0.0);
so.target2 = float4(1.0, 0.0, 0.0, 0.0);
}
void DS_Test(out DS_FSO so, float3 normal, float spec, float gloss)
{
so.target0 = float4(0.5, 0.5, 0.5, spec);
so.target1 = 0.0;
so.target2 = float4(EncodeNormal(normal), 0.25, 0.5);
so.target3 = float4(1.0 / 8.0, 0.5, 0.5, gloss * (1.0 / 64.0));
so.target1 = float4(EncodeNormal(normal), 0.25, 0.5);
so.target2 = float4(1.0 / 8.0, 0.5, 0.5, gloss * (1.0 / 64.0));
}
void DS_SetAlbedo(inout DS_FSO so, float3 albedo)
@ -56,11 +60,6 @@ void DS_SetSpec(inout DS_FSO so, float spec)
so.target0.a = spec;
}
void DS_SetDepth(inout DS_FSO so, float depth)
{
so.target1 = depth;
}
float3 DS_GetNormal(float4 gbuffer)
{
return DecodeNormal(gbuffer.rg);
@ -68,7 +67,7 @@ float3 DS_GetNormal(float4 gbuffer)
void DS_SetNormal(inout DS_FSO so, float3 normal)
{
so.target2.rg = EncodeNormal(normal);
so.target1.rg = EncodeNormal(normal);
}
float2 DS_GetEmission(float4 gbuffer)
@ -80,7 +79,7 @@ float2 DS_GetEmission(float4 gbuffer)
void DS_SetEmission(inout DS_FSO so, float emission, float skin)
{
const float em = HDRColorToSRGB(emission).r;
so.target2.b = (3.0 * em - skin) * 0.25 + 0.25;
so.target1.b = (3.0 * em - skin) * 0.25 + 0.25;
}
float2 DS_GetLamScaleBias(float4 gbuffer)
@ -90,30 +89,30 @@ float2 DS_GetLamScaleBias(float4 gbuffer)
void DS_SetLamScaleBias(inout DS_FSO so, float2 lamScaleBias, float4 aniso)
{
so.target3.rg = lerp(lamScaleBias * float2(1.0 / 8.0, 0.25) + float2(0, 0.5), EncodeNormal(aniso.xyz), aniso.w);
so.target2.rg = lerp(lamScaleBias * float2(1.0 / 8.0, 0.25) + float2(0, 0.5), EncodeNormal(aniso.xyz), aniso.w);
}
float2 DS_GetMetallicity(float4 gbuffer)
{
const float x2 = gbuffer.b * 2.0;
const float x2 = gbuffer.b * 2.02;
return float2(
saturate(x2 - 1.0),
saturate(x2 - 1.02),
saturate(1.0 - x2));
}
void DS_SetMetallicity(inout DS_FSO so, float metal, float hair)
{
so.target3.b = (metal - hair) * 0.5 + 0.5;
so.target2.b = (metal - hair) * 0.5 + 0.5;
}
void DS_SetGloss(inout DS_FSO so, float gloss)
{
so.target3.a = gloss * (1.0 / 64.0);
so.target2.a = gloss * (1.0 / 64.0);
}
float3 DS_GetPosition(float4 gbuffer, matrix matInvProj, float2 posCS)
float3 DS_GetPosition(float4 gbuffer, matrix matInvProj, float2 ndcPos)
{
float4 pos = mul(float4(posCS, gbuffer.r, 1), matInvProj);
float4 pos = mul(float4(ndcPos, gbuffer.r, 1), matInvProj);
pos /= pos.w;
return pos.xyz;
}

View file

@ -13,9 +13,10 @@ float4 ToLinearDepth(float4 d, float4 zNearFarEx)
return zNearFarEx.w / (d - zNearFarEx.z);
}
float ComputeFog(float depth, float density)
float ComputeFog(float depth, float density, float height = 0.0)
{
const float fog = 1.0 / exp(depth * density);
const float strength = 1.0 - saturate(height * 0.003);
const float fog = 1.0 / exp(depth * lerp(0.0, density, strength * strength));
return 1.0 - saturate(fog);
}
@ -76,9 +77,10 @@ float PCF(
if (dzBlockers_blockerCount.y > 0.0)
{
const float penumbraScale = config.x;
const float penumbraContrastMask = config.y;
const float dzBlockers = dzBlockers_blockerCount.x / dzBlockers_blockerCount.y;
const float penumbra = saturate(dzFrag - dzBlockers);
const float contrast = 1.0 + max(0.0, 3.0 - penumbra * penumbraScale);
const float contrast = 1.0 + max(0.0, 3.0 - penumbra * penumbraScale) * penumbraContrastMask;
return saturate((ret - 0.5) * contrast + 0.5);
}
else
@ -122,7 +124,7 @@ float ShadowMapCSM(
float ret = 1.0;
const float4 p = float4(pos.xyz, 1);
float contrast = 1.0;
const float contrastScale = 2.8;
const float contrastScale = config.w;
if (pos.w > ranges.x)
{

View file

@ -11,26 +11,26 @@ float FresnelSchlick(float minRef, float maxAdd, float power)
return saturate(minRef + maxAdd * power);
}
// See: http://www.thetenthplanet.de/archives/255
float EnergyNorm(float gloss)
{
return (gloss + 2.0) / 8.0;
return (gloss + 2.0) * (1.0 / 8.0);
}
float4 VerusLit(float3 dirToLight, float3 normal, float3 dirToEye, float gloss,
float2 lamScaleBias, float4 aniso = 0.0)
float2 lamScaleBias, float4 aniso = 0.0, float eyeFresnel = 0.0)
{
float4 ret = float4(1, 0, 0, 1);
const float3 hv = normalize(dirToEye + dirToLight);
const float nDotL = dot(normal, dirToLight);
const float nDotL = dot(normal, dirToLight) * lamScaleBias.x + lamScaleBias.y;
const float nDotE = dot(normal, dirToEye);
const float nDotH = dot(normal, hv);
const float aDotH = SinAcos(dot(aniso.xyz, hv));
const float3 spec = saturate(float3(EnergyNorm(gloss).xx, 1) *
pow(saturate(float3(nDotH, aDotH, 1.0 - nDotL)), float3(gloss, gloss * 8.0, 5)));
const float4 spec = float4(EnergyNorm(gloss).xx, 1, 1) *
pow(saturate(float4(nDotH, aDotH, 1.0 - nDotL, 1.0 - nDotE)), float4(gloss, gloss * 8.0, 5, 5));
ret.x = saturate(nDotL * -4.0); // For subsurface scattering effect.
ret.y = saturate(nDotL * lamScaleBias.x + lamScaleBias.y);
ret.y = saturate(nDotL);
ret.z = saturate(nDotL * 8.0) * max(spec.x, spec.y * aniso.w);
ret.w = spec.z; // For fresnel effect.
ret.w = lerp(spec.z, spec.w, eyeFresnel); // For fresnel effect.
return ret;
}

Some files were not shown because too many files have changed in this diff Show more