diff --git a/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp b/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp index e5e0b35..7692417 100644 --- a/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp +++ b/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp @@ -33,11 +33,39 @@ void CommandBufferD3D12::Done() VERUS_DONE(CommandBufferD3D12); } +void CommandBufferD3D12::InitOneTimeSubmit() +{ + VERUS_QREF_RENDERER; + VERUS_QREF_RENDERER_D3D12; + _pOneTimeCommandAllocator = pRendererD3D12->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT); + auto pCmdList = pRendererD3D12->CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, _pOneTimeCommandAllocator); + VERUS_FOR(i, BaseRenderer::s_ringBufferSize) + _pCommandLists[i] = pCmdList; + _pOneTimeCommandAllocator->Reset(); + Begin(); + pRendererD3D12->SetDescriptorHeaps(this); +} + +void CommandBufferD3D12::DoneOneTimeSubmit() +{ + VERUS_QREF_RENDERER; + VERUS_QREF_RENDERER_D3D12; + End(); + ID3D12CommandList* ppCommandLists[] = { _pCommandLists[0].Get() }; + pRendererD3D12->GetCommandQueue()->ExecuteCommandLists(VERUS_COUNT_OF(ppCommandLists), ppCommandLists); + pRendererD3D12->QueueWaitIdle(); + _pOneTimeCommandAllocator.Reset(); + VERUS_FOR(i, BaseRenderer::s_ringBufferSize) + _pCommandLists[i].Reset(); +} + void CommandBufferD3D12::Begin() { VERUS_QREF_RENDERER_D3D12; HRESULT hr = 0; - if (FAILED(hr = GetD3DGraphicsCommandList()->Reset(pRendererD3D12->GetD3DCommandAllocator(pRendererD3D12->GetRingBufferIndex()), nullptr))) + if (FAILED(hr = GetD3DGraphicsCommandList()->Reset( + _pOneTimeCommandAllocator ? _pOneTimeCommandAllocator.Get() : pRendererD3D12->GetD3DCommandAllocator(pRendererD3D12->GetRingBufferIndex()), + nullptr))) throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr); } diff --git a/RendererDirect3D12/src/CGI/CommandBufferD3D12.h b/RendererDirect3D12/src/CGI/CommandBufferD3D12.h index 497a24d..4911443 100644 --- a/RendererDirect3D12/src/CGI/CommandBufferD3D12.h +++ b/RendererDirect3D12/src/CGI/CommandBufferD3D12.h @@ -6,6 +6,7 @@ namespace verus { class CommandBufferD3D12 : public BaseCommandBuffer { + ComPtr _pOneTimeCommandAllocator; ComPtr _pCommandLists[BaseRenderer::s_ringBufferSize]; RP::PcD3DRenderPass _pRenderPass = nullptr; RP::PcD3DFramebuffer _pFramebuffer = nullptr; @@ -20,6 +21,9 @@ namespace verus virtual void Init() override; virtual void Done() override; + virtual void InitOneTimeSubmit() override; + virtual void DoneOneTimeSubmit() override; + virtual void Begin() override; virtual void End() override; diff --git a/RendererDirect3D12/src/CGI/GeometryD3D12.cpp b/RendererDirect3D12/src/CGI/GeometryD3D12.cpp index 1d400c6..1bb1ed7 100644 --- a/RendererDirect3D12/src/CGI/GeometryD3D12.cpp +++ b/RendererDirect3D12/src/CGI/GeometryD3D12.cpp @@ -170,7 +170,7 @@ void GeometryD3D12::UpdateVertexBuffer(const void* p, int binding, PBaseCommandB } if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); if (revertState) { @@ -241,7 +241,7 @@ void GeometryD3D12::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB) } if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); if (revertState) { diff --git a/RendererDirect3D12/src/CGI/RendererD3D12.cpp b/RendererDirect3D12/src/CGI/RendererD3D12.cpp index f7ce4d0..e2b26ac 100644 --- a/RendererDirect3D12/src/CGI/RendererD3D12.cpp +++ b/RendererDirect3D12/src/CGI/RendererD3D12.cpp @@ -418,7 +418,7 @@ void RendererD3D12::ImGuiRenderDrawData() { VERUS_QREF_RENDERER; ImGui::Render(); - auto pCmdList = static_cast(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList(); + auto pCmdList = static_cast(renderer.GetCommandBuffer().Get())->GetD3DGraphicsCommandList(); if (ImGui::GetDrawData()) ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), pCmdList); } @@ -460,10 +460,9 @@ void RendererD3D12::BeginFrame(bool present) if (FAILED(hr = pCommandAllocator->Reset())) throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr); - renderer.GetCommandBuffer()->Begin(); - - ID3D12DescriptorHeap* ppHeaps[] = { _dhViews.GetD3DDescriptorHeap(), _dhSamplers.GetD3DDescriptorHeap() }; - static_cast(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList()->SetDescriptorHeaps(2, ppHeaps); + auto cb = renderer.GetCommandBuffer(); + cb->Begin(); + SetDescriptorHeaps(cb.Get()); } void RendererD3D12::EndFrame(bool present) @@ -473,7 +472,7 @@ void RendererD3D12::EndFrame(bool present) renderer.GetCommandBuffer()->End(); - ID3D12CommandList* ppCommandLists[] = { static_cast(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList() }; + ID3D12CommandList* ppCommandLists[] = { static_cast(renderer.GetCommandBuffer().Get())->GetD3DGraphicsCommandList() }; _pCommandQueue->ExecuteCommandLists(VERUS_COUNT_OF(ppCommandLists), ppCommandLists); if (!present) @@ -814,3 +813,9 @@ RP::RcD3DFramebuffer RendererD3D12::GetFramebuffer(FBHandle handle) const { return _vFramebuffers[handle.Get()]; } + +void RendererD3D12::SetDescriptorHeaps(PBaseCommandBuffer p) +{ + ID3D12DescriptorHeap* ppHeaps[] = { _dhViews.GetD3DDescriptorHeap(), _dhSamplers.GetD3DDescriptorHeap() }; + static_cast(p)->GetD3DGraphicsCommandList()->SetDescriptorHeaps(2, ppHeaps); +} diff --git a/RendererDirect3D12/src/CGI/RendererD3D12.h b/RendererDirect3D12/src/CGI/RendererD3D12.h index 3e5540c..9d0b29f 100644 --- a/RendererDirect3D12/src/CGI/RendererD3D12.h +++ b/RendererDirect3D12/src/CGI/RendererD3D12.h @@ -60,6 +60,7 @@ namespace verus void CreateSamplers(); ID3D12Device3* GetD3DDevice() const { return _pDevice.Get(); } + ID3D12CommandQueue* GetCommandQueue() const { return _pCommandQueue.Get(); } D3D12MA::Allocator* GetMaAllocator() const { return _pMaAllocator; } ID3D12CommandAllocator* GetD3DCommandAllocator(int ringBufferIndex) const { return _mapCommandAllocators[ringBufferIndex].at(std::this_thread::get_id()).Get(); } D3D12_STATIC_SAMPLER_DESC GetStaticSamplerDesc(Sampler s) const; @@ -102,6 +103,7 @@ namespace verus RDynamicDescriptorHeap GetViewHeap() { return _dhViews; } RDynamicDescriptorHeap GetSamplerHeap() { return _dhSamplers; } + void SetDescriptorHeaps(PBaseCommandBuffer p); }; VERUS_TYPEDEFS(RendererD3D12); } diff --git a/RendererDirect3D12/src/CGI/TextureD3D12.cpp b/RendererDirect3D12/src/CGI/TextureD3D12.cpp index 101e60e..4bf1089 100644 --- a/RendererDirect3D12/src/CGI/TextureD3D12.cpp +++ b/RendererDirect3D12/src/CGI/TextureD3D12.cpp @@ -228,7 +228,7 @@ void TextureD3D12::UpdateSubresource(const void* p, int mipLevel, int arrayLayer } if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), _mainLayout, ImageLayout::transferDst, mipLevel, arrayLayer); D3D12_SUBRESOURCE_DATA sd = {}; @@ -257,7 +257,7 @@ void TextureD3D12::UpdateSubresource(const void* p, int mipLevel, int arrayLayer Schedule(); } -bool TextureD3D12::ReadbackSubresource(void* p, PBaseCommandBuffer pCB) +bool TextureD3D12::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) { VERUS_QREF_RENDERER; HRESULT hr = 0; @@ -268,32 +268,44 @@ bool TextureD3D12::ReadbackSubresource(void* p, PBaseCommandBuffer pCB) auto& rb = _vReadbackBuffers[renderer->GetRingBufferIndex()]; - // Schedule copying to readback buffer: - if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); - auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); - pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), _mainLayout, ImageLayout::transferSrc, _desc._readbackMip, 0); - D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {}; - footprint.Footprint.Format = ToNativeFormat(_desc._format, false); - footprint.Footprint.Width = w; - footprint.Footprint.Height = h; - footprint.Footprint.Depth = 1; - footprint.Footprint.RowPitch = rowPitch; - const UINT subresource = D3D12CalcSubresource(_desc._readbackMip, 0, 0, _desc._mipLevels, _desc._arrayLayers); - pCmdList->CopyTextureRegion( - &CD3DX12_TEXTURE_COPY_LOCATION(rb._pResource.Get(), footprint), - 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subresource), - nullptr); - pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0); + if (recordCopyCommand) + { + if (!pCB) + pCB = renderer.GetCommandBuffer().Get(); + auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); + pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), _mainLayout, ImageLayout::transferSrc, _desc._readbackMip, 0); + D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {}; + footprint.Footprint.Format = ToNativeFormat(_desc._format, false); + footprint.Footprint.Width = w; + footprint.Footprint.Height = h; + footprint.Footprint.Depth = 1; + footprint.Footprint.RowPitch = rowPitch; + const UINT subresource = D3D12CalcSubresource(_desc._readbackMip, 0, 0, _desc._mipLevels, _desc._arrayLayers); + pCmdList->CopyTextureRegion( + &CD3DX12_TEXTURE_COPY_LOCATION(rb._pResource.Get(), footprint), + 0, 0, 0, + &CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subresource), + nullptr); + pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0); + } - // Read current data from readback buffer: - CD3DX12_RANGE readRange(0, 0); - void* pData = nullptr; - if (FAILED(hr = rb._pResource->Map(0, &readRange, &pData))) - throw VERUS_RUNTIME_ERROR << "Map(), hr=" << VERUS_HR(hr); - memcpy(p, pData, _bytesPerPixel * w); - rb._pResource->Unmap(0, nullptr); + if (p) // Read current data from readback buffer: + { + CD3DX12_RANGE readRange(0, 0); + void* pData = nullptr; + if (FAILED(hr = rb._pResource->Map(0, &readRange, &pData))) + throw VERUS_RUNTIME_ERROR << "Map(), hr=" << VERUS_HR(hr); + BYTE* pDst = static_cast(p); + BYTE* pSrc = static_cast(pData); + VERUS_FOR(i, h) + { + memcpy( + pDst + i * _bytesPerPixel * w, + pSrc + i * rowPitch, + _bytesPerPixel * w); + } + rb._pResource->Unmap(0, nullptr); + } return _initAtFrame + BaseRenderer::s_ringBufferSize < renderer.GetFrameCount(); } @@ -304,8 +316,10 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB) VERUS_QREF_RENDERER; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList(); + auto shader = renderer.GetShaderGenerateMips(); + auto& ub = renderer.GetUbGenerateMips(); auto tex = TexturePtr::From(this); // Transition state for sampling in compute shader: @@ -314,10 +328,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB) pCB->BindPipeline(renderer.GetPipelineGenerateMips(!!(_desc._flags & TextureDesc::Flags::exposureMips))); - auto shader = renderer.GetShaderGenerateMips(); shader->BeginBindDescriptors(); - auto& ub = renderer.GetUbGenerateMips(); - const bool createComplexSets = _vCshGenerateMips.empty(); int dispatchIndex = 0; for (int srcMip = 0; srcMip < _desc._mipLevels - 1;) @@ -399,7 +410,6 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB) srcMip += dispatchMipCount; dispatchIndex++; } - shader->EndBindDescriptors(); // Revert to main state: diff --git a/RendererDirect3D12/src/CGI/TextureD3D12.h b/RendererDirect3D12/src/CGI/TextureD3D12.h index 38540c3..d5cba8c 100644 --- a/RendererDirect3D12/src/CGI/TextureD3D12.h +++ b/RendererDirect3D12/src/CGI/TextureD3D12.h @@ -31,7 +31,7 @@ namespace verus virtual void Done() override; virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override; - virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override; + virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override; virtual void GenerateMips(PBaseCommandBuffer pCB) override; diff --git a/RendererVulkan/src/CGI/CommandBufferVulkan.cpp b/RendererVulkan/src/CGI/CommandBufferVulkan.cpp index 6a3fa3a..ebedf47 100644 --- a/RendererVulkan/src/CGI/CommandBufferVulkan.cpp +++ b/RendererVulkan/src/CGI/CommandBufferVulkan.cpp @@ -26,6 +26,34 @@ void CommandBufferVulkan::Done() VERUS_DONE(CommandBufferVulkan); } +void CommandBufferVulkan::InitOneTimeSubmit() +{ + VERUS_QREF_RENDERER; + VERUS_QREF_RENDERER_VULKAN; + _oneTimeSubmit = true; + auto commandPool = pRendererVulkan->GetVkCommandPool(renderer->GetRingBufferIndex()); + auto commandBuffer = pRendererVulkan->CreateCommandBuffer(commandPool); + VERUS_FOR(i, BaseRenderer::s_ringBufferSize) + _commandBuffers[i] = commandBuffer; + Begin(); +} + +void CommandBufferVulkan::DoneOneTimeSubmit() +{ + VERUS_QREF_RENDERER; + VERUS_QREF_RENDERER_VULKAN; + End(); + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = _commandBuffers; + vkQueueSubmit(pRendererVulkan->GetVkGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(pRendererVulkan->GetVkGraphicsQueue()); + auto commandPool = pRendererVulkan->GetVkCommandPool(renderer->GetRingBufferIndex()); + vkFreeCommandBuffers(pRendererVulkan->GetVkDevice(), commandPool, 1, _commandBuffers); + _oneTimeSubmit = false; +} + void CommandBufferVulkan::Begin() { VkResult res = VK_SUCCESS; @@ -217,121 +245,87 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout vkimb[index].subresourceRange.layerCount = 1; // See: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples - if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_GENERAL) - { - // Storage image (UAV) initialization. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) - { - // Depth texture initialization. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (Format::unormD24uintS8 == tex->GetFormat()) - vkimb[index].subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) + auto UseDefaultsForOldLayout = [&vkimb, index, &srcStageMask]() { - // Shadow map initialization. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + switch (vkimb[index].oldLayout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_GENERAL: + srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + vkimb[index].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + default: + VERUS_RT_FAIL("Unknown oldLayout"); + } + }; - vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (Format::unormD24uintS8 == tex->GetFormat()) - vkimb[index].subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + auto UseDefaultsForNewLayout = [&vkimb, index, &dstStageMask, dstStageMaskXS, newLayout, tex]() { - // Render target initialization. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) + switch (vkimb[index].newLayout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_GENERAL: + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + default: + VERUS_RT_FAIL("Unknown newLayout"); + } + + if (vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || + vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) + { + vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (Format::unormD24uintS8 == tex->GetFormat()) + vkimb[index].subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + }; + + if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_GENERAL) { - // Reading to readback buffer. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - // Regular texture's first and only update (before transfer). - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_GENERAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - // To transfer data from storage image during mipmap generation. - srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - // To support vertex texture fetch. - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - // Reading to readback buffer. - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - // To update regular texture during mipmap generation. - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_GENERAL) - { - // To restore storage image after transfer during mipmap generation. - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].srcAccessMask = 0; + UseDefaultsForOldLayout(); dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - // To restore image after transfer to readback buffer. - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].srcAccessMask = 0; - dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } - else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - // To sample regular texture after update. - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - vkimb[index].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } else { - VERUS_RT_FAIL(""); + UseDefaultsForOldLayout(); + UseDefaultsForNewLayout(); } index++; @@ -362,31 +356,3 @@ VkCommandBuffer CommandBufferVulkan::GetVkCommandBuffer() const VERUS_QREF_RENDERER; return _commandBuffers[renderer->GetRingBufferIndex()]; } - -void CommandBufferVulkan::InitOneTimeSubmit() -{ - VERUS_QREF_RENDERER; - VERUS_QREF_RENDERER_VULKAN; - _oneTimeSubmit = true; - auto commandPool = pRendererVulkan->GetVkCommandPool(renderer->GetRingBufferIndex()); - auto commandBuffer = pRendererVulkan->CreateCommandBuffer(commandPool); - VERUS_FOR(i, BaseRenderer::s_ringBufferSize) - _commandBuffers[i] = commandBuffer; - Begin(); -} - -void CommandBufferVulkan::DoneOneTimeSubmit() -{ - VERUS_QREF_RENDERER; - VERUS_QREF_RENDERER_VULKAN; - End(); - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = _commandBuffers; - vkQueueSubmit(pRendererVulkan->GetVkGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(pRendererVulkan->GetVkGraphicsQueue()); - auto commandPool = pRendererVulkan->GetVkCommandPool(renderer->GetRingBufferIndex()); - vkFreeCommandBuffers(pRendererVulkan->GetVkDevice(), commandPool, 1, _commandBuffers); - _oneTimeSubmit = false; -} diff --git a/RendererVulkan/src/CGI/CommandBufferVulkan.h b/RendererVulkan/src/CGI/CommandBufferVulkan.h index bec7654..e0b9086 100644 --- a/RendererVulkan/src/CGI/CommandBufferVulkan.h +++ b/RendererVulkan/src/CGI/CommandBufferVulkan.h @@ -16,6 +16,9 @@ namespace verus virtual void Init() override; virtual void Done() override; + virtual void InitOneTimeSubmit(); + virtual void DoneOneTimeSubmit(); + virtual void Begin() override; virtual void End() override; @@ -46,9 +49,6 @@ namespace verus // VkCommandBuffer GetVkCommandBuffer() const; - - void InitOneTimeSubmit(); - void DoneOneTimeSubmit(); }; VERUS_TYPEDEFS(CommandBufferVulkan); } diff --git a/RendererVulkan/src/CGI/RendererVulkan.cpp b/RendererVulkan/src/CGI/RendererVulkan.cpp index 561f951..4f94512 100644 --- a/RendererVulkan/src/CGI/RendererVulkan.cpp +++ b/RendererVulkan/src/CGI/RendererVulkan.cpp @@ -768,7 +768,7 @@ void RendererVulkan::ImGuiRenderDrawData() { VERUS_QREF_RENDERER; ImGui::Render(); - VkCommandBuffer commandBuffer = static_cast(&(*renderer.GetCommandBuffer()))->GetVkCommandBuffer(); + VkCommandBuffer commandBuffer = static_cast(renderer.GetCommandBuffer().Get())->GetVkCommandBuffer(); if (ImGui::GetDrawData()) ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer); } @@ -825,7 +825,7 @@ void RendererVulkan::EndFrame(bool present) _acquireNextImageSemaphore = _acquireNextImageSemaphores[_ringBufferIndex]; _queueSubmitSemaphore = _queueSubmitSemaphores[_ringBufferIndex]; - VkCommandBuffer commandBuffer = static_cast(&(*renderer.GetCommandBuffer()))->GetVkCommandBuffer(); + VkCommandBuffer commandBuffer = static_cast(renderer.GetCommandBuffer().Get())->GetVkCommandBuffer(); VkSubmitInfo vksi = {}; vksi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; if (present) @@ -1260,7 +1260,7 @@ void RendererVulkan::CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDevice VERUS_QREF_RENDERER; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto commandBuffer = static_cast(pCB)->GetVkCommandBuffer(); VkBufferCopy region = {}; @@ -1287,7 +1287,7 @@ void RendererVulkan::CopyImage( VERUS_QREF_RENDERER; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto commandBuffer = static_cast(pCB)->GetVkCommandBuffer(); VkImageCopy region = {}; @@ -1313,7 +1313,7 @@ void RendererVulkan::CopyBufferToImage( VERUS_QREF_RENDERER; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto commandBuffer = static_cast(pCB)->GetVkCommandBuffer(); VkBufferImageCopy region = {}; @@ -1339,7 +1339,7 @@ void RendererVulkan::CopyImageToBuffer( VERUS_QREF_RENDERER; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); auto commandBuffer = static_cast(pCB)->GetVkCommandBuffer(); VkBufferImageCopy region = {}; diff --git a/RendererVulkan/src/CGI/TextureVulkan.cpp b/RendererVulkan/src/CGI/TextureVulkan.cpp index b817d81..11b6646 100644 --- a/RendererVulkan/src/CGI/TextureVulkan.cpp +++ b/RendererVulkan/src/CGI/TextureVulkan.cpp @@ -210,7 +210,7 @@ void TextureVulkan::UpdateSubresource(const void* p, int mipLevel, int arrayLaye vmaUnmapMemory(pRendererVulkan->GetVmaAllocator(), sb._vmaAllocation); if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), GetSubresourceMainLayout(mipLevel, arrayLayer), ImageLayout::transferDst, mipLevel, arrayLayer); pRendererVulkan->CopyBufferToImage( sb._buffer, @@ -223,7 +223,7 @@ void TextureVulkan::UpdateSubresource(const void* p, int mipLevel, int arrayLaye Schedule(); } -bool TextureVulkan::ReadbackSubresource(void* p, PBaseCommandBuffer pCB) +bool TextureVulkan::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) { VERUS_QREF_RENDERER; VERUS_QREF_RENDERER_VULKAN; @@ -235,23 +235,27 @@ bool TextureVulkan::ReadbackSubresource(void* p, PBaseCommandBuffer pCB) auto& rb = _vReadbackBuffers[renderer->GetRingBufferIndex()]; - // Schedule copying to readback buffer: - if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); - pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), GetSubresourceMainLayout(_desc._readbackMip, 0), ImageLayout::transferSrc, _desc._readbackMip, 0); - pRendererVulkan->CopyImageToBuffer( - _image, _desc._readbackMip, 0, - w, h, - rb._buffer, - pCB); - pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0); + if (recordCopyCommand) + { + if (!pCB) + pCB = renderer.GetCommandBuffer().Get(); + pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), GetSubresourceMainLayout(_desc._readbackMip, 0), ImageLayout::transferSrc, _desc._readbackMip, 0); + pRendererVulkan->CopyImageToBuffer( + _image, _desc._readbackMip, 0, + w, h, + rb._buffer, + pCB); + pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0); + } - // Read current data from readback buffer: - void* pData = nullptr; - if (VK_SUCCESS != (res = vmaMapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation, &pData))) - throw VERUS_RECOVERABLE << "vmaMapMemory(), res=" << res; - memcpy(p, pData, bufferSize); - vmaUnmapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation); + if (p) // Read current data from readback buffer: + { + void* pData = nullptr; + if (VK_SUCCESS != (res = vmaMapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation, &pData))) + throw VERUS_RECOVERABLE << "vmaMapMemory(), res=" << res; + memcpy(p, pData, bufferSize); + vmaUnmapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation); + } return _initAtFrame + BaseRenderer::s_ringBufferSize < renderer.GetFrameCount(); } @@ -263,7 +267,9 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB) VERUS_QREF_RENDERER_VULKAN; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); + auto shader = renderer.GetShaderGenerateMips(); + auto& ub = renderer.GetUbGenerateMips(); auto tex = TexturePtr::From(this); if (!_definedStorage) @@ -286,10 +292,7 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB) pCB->BindPipeline(renderer.GetPipelineGenerateMips(!!(_desc._flags & TextureDesc::Flags::exposureMips))); - auto shader = renderer.GetShaderGenerateMips(); shader->BeginBindDescriptors(); - auto& ub = renderer.GetUbGenerateMips(); - const bool createComplexSets = _vCshGenerateMips.empty(); int dispatchIndex = 0; for (int srcMip = 0; srcMip < _desc._mipLevels - 1;) @@ -357,7 +360,6 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB) srcMip += dispatchMipCount; dispatchIndex++; } - shader->EndBindDescriptors(); // Revert to main layout: diff --git a/RendererVulkan/src/CGI/TextureVulkan.h b/RendererVulkan/src/CGI/TextureVulkan.h index 81e42ba..252a09f 100644 --- a/RendererVulkan/src/CGI/TextureVulkan.h +++ b/RendererVulkan/src/CGI/TextureVulkan.h @@ -34,7 +34,7 @@ namespace verus virtual void Done() override; virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override; - virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override; + virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override; virtual void GenerateMips(PBaseCommandBuffer pCB) override; diff --git a/Scripts/CompressForest.py b/Scripts/CompressForest.py new file mode 100644 index 0000000..d1accdd --- /dev/null +++ b/Scripts/CompressForest.py @@ -0,0 +1,12 @@ +import glob, os + +exe = "C:\\Home\\Projects\\Verus\\verus\\Bin\\TextureTool.exe" + +for file in glob.glob("*.GB0.psd"): + os.system("\"" + exe + "\" " + file) + +for file in glob.glob("*.GB1.FX.psd"): + os.system("\"" + exe + "\" --non-color-data " + file) + +for file in glob.glob("*.GB2.FX.psd"): + os.system("\"" + exe + "\" --non-color-data " + file) diff --git a/Verus/Verus.props b/Verus/Verus.props index e74cb6b..3202038 100644 --- a/Verus/Verus.props +++ b/Verus/Verus.props @@ -3,8 +3,8 @@ - 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.89\src;C:\Home\Middleware\bullet3-2.89\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\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.12\include;C:\VulkanSDK\1.2.141.2\Include;$(IncludePath) - C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\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\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.12\lib\x64;C:\VulkanSDK\1.2.141.2\Lib;$(LibraryPath) + 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.89\src;C:\Home\Middleware\bullet3-2.89\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\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.12\include;C:\VulkanSDK\1.2.148.1\Include;$(IncludePath) + C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\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\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.12\lib\x64;C:\VulkanSDK\1.2.148.1\Lib;$(LibraryPath) diff --git a/Verus/Verus.vcxproj b/Verus/Verus.vcxproj index c3218c8..b6b57f4 100644 --- a/Verus/Verus.vcxproj +++ b/Verus/Verus.vcxproj @@ -235,6 +235,13 @@ + + + + + + + @@ -394,6 +401,12 @@ + + + + + + @@ -727,6 +740,30 @@ Document + + + Document + + + Document + + + + + Document + + + Document + + + + + Document + + + Document + + diff --git a/Verus/Verus.vcxproj.filters b/Verus/Verus.vcxproj.filters index daac89c..15ec388 100644 --- a/Verus/Verus.vcxproj.filters +++ b/Verus/Verus.vcxproj.filters @@ -94,6 +94,9 @@ {5ea015f8-8b97-4159-ad67-d71abdba3c91} + + {07af1a9e-5cdc-4264-811b-d958ec70a709} + @@ -645,6 +648,27 @@ src\Scene + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + @@ -1094,6 +1118,24 @@ src\Scene + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + + + src\Scene\SceneNodes + @@ -1222,6 +1264,18 @@ src\Shaders + + src\Shaders + + + src\Shaders + + + src\Shaders + + + src\Shaders + @@ -1234,4 +1288,12 @@ src\ThirdParty\imgui + + + src\Shaders + + + src\Shaders + + \ No newline at end of file diff --git a/Verus/src/App/Settings.h b/Verus/src/App/Settings.h index 7260935..315f397 100644 --- a/Verus/src/App/Settings.h +++ b/Verus/src/App/Settings.h @@ -4,15 +4,19 @@ namespace verus { namespace App { + // Capacity is per frame. 3 frames are buffered. class Limits { public: - int _d3d12_dhViewsCapacity = 10000; - int _d3d12_dhSamplersCapacity = 500; + int _d3d12_dhViewsCapacity = 10000; // D3D limit is one million. + int _d3d12_dhSamplersCapacity = 500; // D3D limit is 2048. + int _generateMips_ubCapacity = 100; int _mesh_ubPerFrameCapacity = 100; int _mesh_ubPerMaterialFSCapacity = 1000; int _mesh_ubPerMeshVSCapacity = 10000; int _mesh_ubSkinningVSCapacity = 5000; + int _quad_ubVSCapacity = 100; + int _quad_ubFSCapacity = 100; int _terrain_ubDrawDepthCapacity = 100; }; VERUS_TYPEDEFS(Limits); diff --git a/Verus/src/CGI/BaseCommandBuffer.cpp b/Verus/src/CGI/BaseCommandBuffer.cpp index 1b48043..ed1dbba 100644 --- a/Verus/src/CGI/BaseCommandBuffer.cpp +++ b/Verus/src/CGI/BaseCommandBuffer.cpp @@ -13,6 +13,14 @@ void CommandBufferPtr::Init() _p->Init(); } +void CommandBufferPtr::InitOneTimeSubmit() +{ + VERUS_QREF_RENDERER; + VERUS_RT_ASSERT(!_p); + _p = renderer->InsertCommandBuffer(); + _p->InitOneTimeSubmit(); +} + void CommandBufferPwn::Done() { if (_p) diff --git a/Verus/src/CGI/BaseCommandBuffer.h b/Verus/src/CGI/BaseCommandBuffer.h index e6422ef..a9d86df 100644 --- a/Verus/src/CGI/BaseCommandBuffer.h +++ b/Verus/src/CGI/BaseCommandBuffer.h @@ -16,6 +16,9 @@ namespace verus virtual void Init() = 0; virtual void Done() = 0; + virtual void InitOneTimeSubmit() = 0; + virtual void DoneOneTimeSubmit() = 0; + virtual void Begin() = 0; virtual void End() = 0; @@ -50,6 +53,7 @@ namespace verus { public: void Init(); + void InitOneTimeSubmit(); }; VERUS_TYPEDEFS(CommandBufferPtr); diff --git a/Verus/src/CGI/BaseRenderer.cpp b/Verus/src/CGI/BaseRenderer.cpp index eb616c5..8ab1f42 100644 --- a/Verus/src/CGI/BaseRenderer.cpp +++ b/Verus/src/CGI/BaseRenderer.cpp @@ -161,8 +161,8 @@ void BaseRenderer::SetAlphaBlendHelper( } else { - alphaBlendOp = colorBlendOp; - srcAlphaBlendFactor = srcColorBlendFactor; - dstAlphaBlendFactor = dstColorBlendFactor; + alphaBlendOp = 0; + srcAlphaBlendFactor = 1; + dstAlphaBlendFactor = 0; } } diff --git a/Verus/src/CGI/BaseTexture.h b/Verus/src/CGI/BaseTexture.h index 6d5a8c4..71d0609 100644 --- a/Verus/src/CGI/BaseTexture.h +++ b/Verus/src/CGI/BaseTexture.h @@ -112,7 +112,7 @@ namespace verus virtual void Async_Run(CSZ url, RcBlob blob) override; virtual void UpdateSubresource(const void* p, int mipLevel = 0, int arrayLayer = 0, BaseCommandBuffer* pCB = nullptr) = 0; - virtual bool ReadbackSubresource(void* p, BaseCommandBuffer* pCB = nullptr) = 0; + virtual bool ReadbackSubresource(void* p, bool recordCopyCommand = true, BaseCommandBuffer* pCB = nullptr) = 0; virtual void GenerateMips(BaseCommandBuffer* pCB = nullptr) = 0; diff --git a/Verus/src/CGI/DebugDraw.cpp b/Verus/src/CGI/DebugDraw.cpp index f163f25..6a71e11 100644 --- a/Verus/src/CGI/DebugDraw.cpp +++ b/Verus/src/CGI/DebugDraw.cpp @@ -79,6 +79,8 @@ void DebugDraw::Begin(Type type, PcTransform3 pMat, bool zEnable) VERUS_QREF_SM; VERUS_QREF_RENDERER; + auto cb = renderer.GetCommandBuffer(); + _type = type; _vertCount = 0; if (_currentFrame != renderer.GetFrameCount()) @@ -104,10 +106,8 @@ void DebugDraw::Begin(Type type, PcTransform3 pMat, bool zEnable) if (!zEnable) pipe = static_cast(pipe + 1); - auto cb = renderer.GetCommandBuffer(); - - cb->BindVertexBuffers(_geo); cb->BindPipeline(_pipe[pipe]); + cb->BindVertexBuffers(_geo); _shader->BeginBindDescriptors(); cb->BindDescriptors(_shader, 0); _shader->EndBindDescriptors(); diff --git a/Verus/src/CGI/DeferredShading.cpp b/Verus/src/CGI/DeferredShading.cpp index d7cd749..785b98f 100644 --- a/Verus/src/CGI/DeferredShading.cpp +++ b/Verus/src/CGI/DeferredShading.cpp @@ -3,13 +3,19 @@ using namespace verus; using namespace verus::CGI; -DeferredShading::UB_PerFrame DeferredShading::s_ubPerFrame; -DeferredShading::UB_TexturesFS DeferredShading::s_ubTexturesFS; -DeferredShading::UB_PerMeshVS DeferredShading::s_ubPerMeshVS; -DeferredShading::UB_ShadowFS DeferredShading::s_ubShadowFS; -DeferredShading::UB_PerObject DeferredShading::s_ubPerObject; -DeferredShading::UB_ComposeVS DeferredShading::s_ubComposeVS; -DeferredShading::UB_ComposeFS DeferredShading::s_ubComposeFS; +DeferredShading::UB_PerFrame DeferredShading::s_ubPerFrame; +DeferredShading::UB_TexturesFS DeferredShading::s_ubTexturesFS; +DeferredShading::UB_PerMeshVS DeferredShading::s_ubPerMeshVS; +DeferredShading::UB_ShadowFS DeferredShading::s_ubShadowFS; +DeferredShading::UB_PerObject DeferredShading::s_ubPerObject; +DeferredShading::UB_ComposeVS DeferredShading::s_ubComposeVS; +DeferredShading::UB_ComposeFS DeferredShading::s_ubComposeFS; +DeferredShading::UB_AOPerFrame DeferredShading::s_ubAOPerFrame; +DeferredShading::UB_AOTexturesFS DeferredShading::s_ubAOTexturesFS; +DeferredShading::UB_AOPerMeshVS DeferredShading::s_ubAOPerMeshVS; +DeferredShading::UB_AOPerObject DeferredShading::s_ubAOPerObject; +DeferredShading::UB_BakeSpritesVS DeferredShading::s_ubBakeSpritesVS; +DeferredShading::UB_BakeSpritesFS DeferredShading::s_ubBakeSpritesFS; DeferredShading::DeferredShading() { @@ -58,6 +64,16 @@ void DeferredShading::Init() { RP::Dependency("Sp0", "Sp1").Mode(1) }); + _rphAO = renderer->CreateRenderPass( + { + RP::Attachment("Attach", Format::unormR8).Layout(ImageLayout::fsReadOnly), + RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly) + }, + { + RP::Subpass("Sp0").Color( + {RP::Ref("Attach", ImageLayout::colorAttachment)}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly)) + }, + {}); _rphCompose = renderer->CreateRenderPass( { RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly), @@ -95,14 +111,14 @@ void DeferredShading::Init() Sampler::input, Sampler::shadow, Sampler::nearestClampMipN - }, CGI::ShaderStageFlags::fs); - _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); + }, ShaderStageFlags::fs); + _shader[SHADER_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), 1000, {}, ShaderStageFlags::vs); + _shader[SHADER_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), 1000, {}, ShaderStageFlags::fs); _shader[SHADER_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0); _shader[SHADER_LIGHT]->CreatePipelineLayout(); _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(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 2, {}, ShaderStageFlags::vs); _shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 2, { Sampler::nearestClampMipN, @@ -111,9 +127,30 @@ void DeferredShading::Init() Sampler::nearestClampMipN, Sampler::nearestClampMipN, Sampler::nearestClampMipN - }, CGI::ShaderStageFlags::fs); + }, ShaderStageFlags::fs); _shader[SHADER_COMPOSE]->CreatePipelineLayout(); + _shader[SHADER_AO].Init("[Shaders]:DS_AO.hlsl"); + _shader[SHADER_AO]->CreateDescriptorSet(0, &s_ubAOPerFrame, sizeof(s_ubAOPerFrame)); + _shader[SHADER_AO]->CreateDescriptorSet(1, &s_ubAOTexturesFS, sizeof(s_ubAOTexturesFS), 1, + { + Sampler::nearestClampMipN, + Sampler::nearestClampMipN + }, ShaderStageFlags::fs); + _shader[SHADER_AO]->CreateDescriptorSet(2, &s_ubAOPerMeshVS, sizeof(s_ubAOPerMeshVS), 1000, {}, ShaderStageFlags::vs); + _shader[SHADER_AO]->CreateDescriptorSet(3, &s_ubAOPerObject, sizeof(s_ubAOPerObject), 0); + _shader[SHADER_AO]->CreatePipelineLayout(); + + _shader[SHADER_BAKE_SPRITES].Init("[Shaders]:DS_BakeSprites.hlsl"); + _shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(0, &s_ubBakeSpritesVS, sizeof(s_ubBakeSpritesVS), 1000); + _shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(1, &s_ubBakeSpritesFS, sizeof(s_ubBakeSpritesFS), 1000, + { + Sampler::nearestClampMipN, + Sampler::nearestClampMipN, + Sampler::nearestClampMipN + }, ShaderStageFlags::fs); + _shader[SHADER_BAKE_SPRITES]->CreatePipelineLayout(); + { PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose); pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF; @@ -207,7 +244,24 @@ void DeferredShading::InitBySsao(TexturePtr tex) { VERUS_QREF_RENDERER; + _texAO = tex; + + _fbhAO = renderer->CreateFramebuffer(_rphAO, + { + tex, + renderer.GetTexDepthStencil(), + }, + renderer.GetSwapChainWidth(), + renderer.GetSwapChainHeight()); + _shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose); + _shader[SHADER_AO]->FreeDescriptorSet(_cshAO); + + _cshAO = _shader[SHADER_AO]->BindDescriptorSetTextures(1, + { + _tex[TEX_GBUFFER_1], + renderer.GetTexDepthStencil(), + }); _cshCompose = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1, { _tex[TEX_GBUFFER_0], @@ -236,7 +290,9 @@ void DeferredShading::OnSwapChainResized(bool init, bool done) _shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping); _shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose); + renderer->DeleteFramebuffer(_fbhExtraCompose); renderer->DeleteFramebuffer(_fbhCompose); + renderer->DeleteFramebuffer(_fbhAO); renderer->DeleteFramebuffer(_fbh); _tex[TEX_COMPOSED_B].Done(); @@ -324,9 +380,18 @@ bool DeferredShading::IsLoaded() VERUS_QREF_HELPERS; Scene::RDeferredLights dl = helpers.GetDeferredLights(); return - dl.Get(CGI::LightType::dir).IsLoaded() && - dl.Get(CGI::LightType::omni).IsLoaded() && - dl.Get(CGI::LightType::spot).IsLoaded(); + dl.Get(LightType::dir).IsLoaded() && + dl.Get(LightType::omni).IsLoaded() && + dl.Get(LightType::spot).IsLoaded(); +} + +void DeferredShading::ResetInstanceCount() +{ + VERUS_QREF_HELPERS; + Scene::RDeferredLights dl = helpers.GetDeferredLights(); + dl.Get(LightType::dir).ResetInstanceCount(); + dl.Get(LightType::omni).ResetInstanceCount(); + dl.Get(LightType::spot).ResetInstanceCount(); } void DeferredShading::Draw(int gbuffer) @@ -336,12 +401,12 @@ void DeferredShading::Draw(int gbuffer) const float w = static_cast(renderer.GetSwapChainWidth() / 2); const float h = static_cast(renderer.GetSwapChainHeight() / 2); - renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat(); - renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat(); - auto cb = renderer.GetCommandBuffer(); auto shader = renderer.GetShaderQuad(); + renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat(); + renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat(); + cb->BindPipeline(_pipe[PIPE_QUAD]); shader->BeginBindDescriptors(); @@ -350,15 +415,15 @@ void DeferredShading::Draw(int gbuffer) { cb->SetViewport({ Vector4(0, 0, w, h) }); cb->BindDescriptors(shader, 1, _cshQuad[0]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->SetViewport({ Vector4(w, 0, w, h) }); cb->BindDescriptors(shader, 1, _cshQuad[1]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->SetViewport({ Vector4(0, h, w, h) }); cb->BindDescriptors(shader, 1, _cshQuad[2]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->SetViewport({ Vector4(0, 0, static_cast(renderer.GetSwapChainWidth()), static_cast(renderer.GetSwapChainHeight())) }); } @@ -366,18 +431,18 @@ void DeferredShading::Draw(int gbuffer) { cb->SetViewport({ Vector4(0, 0, w, h) }); cb->BindDescriptors(shader, 1, _cshQuad[3]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->SetViewport({ Vector4(w, 0, w, h) }); cb->BindDescriptors(shader, 1, _cshQuad[4]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->SetViewport({ Vector4(0, 0, static_cast(renderer.GetSwapChainWidth()), static_cast(renderer.GetSwapChainHeight())) }); } else { cb->BindDescriptors(shader, 1, _cshQuad[gbuffer]); - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); } shader->EndBindDescriptors(); } @@ -437,7 +502,7 @@ bool DeferredShading::BeginLightingPass() Scene::RDeferredLights dl = helpers.GetDeferredLights(); { - PipelineDesc pipeDesc(dl.Get(CGI::LightType::dir).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedDir", _rph, 1); + PipelineDesc pipeDesc(dl.Get(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); @@ -445,7 +510,7 @@ bool DeferredShading::BeginLightingPass() _pipe[PIPE_INSTANCED_DIR].Init(pipeDesc); } { - PipelineDesc pipeDesc(dl.Get(CGI::LightType::omni).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedOmni", _rph, 1); + PipelineDesc pipeDesc(dl.Get(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; @@ -455,7 +520,7 @@ bool DeferredShading::BeginLightingPass() _pipe[PIPE_INSTANCED_OMNI].Init(pipeDesc); } { - PipelineDesc pipeDesc(dl.Get(CGI::LightType::spot).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedSpot", _rph, 1); + PipelineDesc pipeDesc(dl.Get(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; @@ -464,6 +529,15 @@ bool DeferredShading::BeginLightingPass() pipeDesc._depthWriteEnable = false; _pipe[PIPE_INSTANCED_SPOT].Init(pipeDesc); } + { + PipelineDesc pipeDesc(dl.Get(LightType::omni).GetGeometry(), _shader[SHADER_AO], "#InstancedOmni", _rphAO); + pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_MUL; + pipeDesc._rasterizationState._cullMode = CullMode::front; + pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4); + pipeDesc._depthCompareOp = CompareOp::greater; + pipeDesc._depthWriteEnable = false; + _pipe[PIPE_INSTANCED_AO].Init(pipeDesc); + } } return true; @@ -480,6 +554,29 @@ void DeferredShading::EndLightingPass() renderer.GetCommandBuffer()->EndRenderPass(); } +void DeferredShading::BeginAmbientOcclusion() +{ + VERUS_QREF_RENDERER; + + auto cb = renderer.GetCommandBuffer(); + + // Add more dark regions to SSAO buffer: + cb->BeginRenderPass(_rphAO, _fbhAO, + { + _texAO->GetClearValue(), + renderer.GetTexDepthStencil()->GetClearValue() + }); + _shader[SHADER_AO]->BeginBindDescriptors(); +} + +void DeferredShading::EndAmbientOcclusion() +{ + VERUS_QREF_RENDERER; + + _shader[SHADER_AO]->EndBindDescriptors(); + renderer.GetCommandBuffer()->EndRenderPass(); +} + void DeferredShading::BeginCompose() { VERUS_QREF_RENDERER; @@ -489,6 +586,8 @@ void DeferredShading::BeginCompose() const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP()); + auto cb = renderer.GetCommandBuffer(); + s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat(); s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat(); @@ -499,8 +598,7 @@ void DeferredShading::BeginCompose() s_ubComposeFS._waterDiffColorShallow = float4(water.GetDiffuseColorShallow().GLM(), water.GetFogDensity()); s_ubComposeFS._waterDiffColorDeep = float4(water.GetDiffuseColorDeep().GLM(), water.IsUnderwater() ? 1.f : 0.f); - auto cb = renderer.GetCommandBuffer(); - + // Compose buffers, that is perform "final color = albedo * diffuse + specular" computation. Result is still HDR: cb->BeginRenderPass(_rphCompose, _fbhCompose, { _tex[TEX_COMPOSED_A]->GetClearValue(), @@ -509,16 +607,15 @@ void DeferredShading::BeginCompose() }); cb->BindPipeline(_pipe[PIPE_COMPOSE]); - _shader[SHADER_COMPOSE]->BeginBindDescriptors(); cb->BindDescriptors(_shader[SHADER_COMPOSE], 0); cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshCompose); _shader[SHADER_COMPOSE]->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); + // Begin drawing extra stuff, which is not using deferred shading, for example water (updates depth buffer) and sky: cb->BeginRenderPass(_rphExtraCompose, _fbhExtraCompose, { _tex[TEX_COMPOSED_A]->GetClearValue(), @@ -539,6 +636,8 @@ void DeferredShading::ToneMapping(RcVector4 bgColor) VERUS_QREF_SM; VERUS_QREF_ATMO; + auto cb = renderer.GetCommandBuffer(); + s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat(); s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat(); @@ -547,20 +646,13 @@ void DeferredShading::ToneMapping(RcVector4 bgColor) s_ubComposeFS._fogColor = Vector4(0.5f, 0.5f, 0.5f, 0.002f).GLM(); s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM(); - auto cb = renderer.GetCommandBuffer(); - + // Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve: cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]); - _shader[SHADER_COMPOSE]->BeginBindDescriptors(); cb->BindDescriptors(_shader[SHADER_COMPOSE], 0); cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping); _shader[SHADER_COMPOSE]->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); -} - -void DeferredShading::AntiAliasing() -{ + renderer.DrawQuad(cb.Get()); } bool DeferredShading::IsLightUrl(CSZ url) @@ -571,26 +663,31 @@ bool DeferredShading::IsLightUrl(CSZ url) !strcmp(url, "SPOT"); } -void DeferredShading::OnNewLightType(LightType type, bool wireframe) +void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool wireframe) { - VERUS_QREF_RENDERER; VERUS_QREF_ATMO; + VERUS_QREF_SM; - auto cb = renderer.GetCommandBuffer(); + s_ubPerFrame._matQuad = Math::QuadMatrix().UniformBufferFormat(); + s_ubPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat(); + s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat(); + s_ubPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); + s_ubPerFrame._matInvP = Matrix4(VMath::inverse(sm.GetCamera()->GetMatrixP())).UniformBufferFormat(); + s_ubPerFrame._toUV = float4(0, 0, 0, 0); switch (type) { - case CGI::LightType::dir: + case LightType::dir: { cb->BindPipeline(_pipe[PIPE_INSTANCED_DIR]); } break; - case CGI::LightType::omni: + case LightType::omni: { cb->BindPipeline(_pipe[PIPE_INSTANCED_OMNI]); } break; - case CGI::LightType::spot: + case LightType::spot: { cb->BindPipeline(_pipe[PIPE_INSTANCED_SPOT]); } @@ -610,24 +707,36 @@ void DeferredShading::OnNewLightType(LightType type, bool wireframe) cb->BindDescriptors(_shader[SHADER_LIGHT], 3); } -void DeferredShading::UpdateUniformBufferPerFrame() +void DeferredShading::BindDescriptorsPerMeshVS(CommandBufferPtr cb) +{ + cb->BindDescriptors(_shader[SHADER_LIGHT], 2); +} + +void DeferredShading::OnNewAOType(CommandBufferPtr cb, LightType type) { VERUS_QREF_SM; - // Standard quad: - s_ubPerFrame._matQuad = Math::QuadMatrix().UniformBufferFormat(); - s_ubPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat(); + s_ubAOPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat(); + s_ubAOPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat(); + s_ubAOPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); + s_ubAOPerFrame._matInvP = Matrix4(VMath::inverse(sm.GetCamera()->GetMatrixP())).UniformBufferFormat(); - s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat(); - s_ubPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); - s_ubPerFrame._matInvP = Matrix4(VMath::inverse(sm.GetCamera()->GetMatrixP())).UniformBufferFormat(); - s_ubPerFrame._toUV = float4(0, 0, 0, 0); + switch (type) + { + case LightType::omni: + { + cb->BindPipeline(_pipe[PIPE_INSTANCED_AO]); + } + break; + } + + cb->BindDescriptors(_shader[SHADER_AO], 0); + cb->BindDescriptors(_shader[SHADER_AO], 1, _cshAO); } -void DeferredShading::BindDescriptorsPerMeshVS() +void DeferredShading::BindDescriptorsAOPerMeshVS(CommandBufferPtr cb) { - VERUS_QREF_RENDERER; - renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_LIGHT], 2); + cb->BindDescriptors(_shader[SHADER_AO], 2); } void DeferredShading::Load() @@ -636,16 +745,16 @@ void DeferredShading::Load() Scene::RDeferredLights dl = helpers.GetDeferredLights(); Scene::Mesh::Desc meshDesc; - meshDesc._instanceCapacity = 1000; + meshDesc._instanceCapacity = 10000; meshDesc._url = "[Models]:DS/Dir.x3d"; - dl.Get(CGI::LightType::dir).Init(meshDesc); + dl.Get(LightType::dir).Init(meshDesc); meshDesc._url = "[Models]:DS/Omni.x3d"; - dl.Get(CGI::LightType::omni).Init(meshDesc); + dl.Get(LightType::omni).Init(meshDesc); meshDesc._url = "[Models]:DS/Spot.x3d"; - dl.Get(CGI::LightType::spot).Init(meshDesc); + dl.Get(LightType::spot).Init(meshDesc); } TexturePtr DeferredShading::GetGBuffer(int index) @@ -662,3 +771,100 @@ TexturePtr DeferredShading::GetComposedTextureB() { return _tex[TEX_COMPOSED_B]; } + +Vector4 DeferredShading::GetClearValueForGBuffer0() +{ + return Vector4(0.5f, 0.5f, 0.5f, 0.25f); +} + +Vector4 DeferredShading::GetClearValueForGBuffer1() +{ + return Vector4(0.5f, 0.5f, 0.25f); +} + +Vector4 DeferredShading::GetClearValueForGBuffer2() +{ + return Vector4(0.125f, 0.5f, 0.5f, 0.125f); +} + +void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB) +{ + VERUS_QREF_RENDERER; + + if (!pCB) + pCB = renderer.GetCommandBuffer().Get(); + + RcVector4 size = texGBufferOut[0]->GetSize(); + const int w = static_cast(size.getX()); + const int h = static_cast(size.getY()); + + _rphBakeSprites = renderer->CreateRenderPass( + { + RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly), + RP::Attachment("GBuffer1", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly), + RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly), + }, + { + RP::Subpass("Sp0").Color( + { + RP::Ref("GBuffer0", ImageLayout::colorAttachment), + RP::Ref("GBuffer1", ImageLayout::colorAttachment), + RP::Ref("GBuffer2", ImageLayout::colorAttachment) + }) + }, + {}); + + _fbhBakeSprites = renderer->CreateFramebuffer(_rphBakeSprites, + { + texGBufferOut[0], + texGBufferOut[1], + texGBufferOut[2] + }, + w, h); + + _cshBakeSprites = _shader[SHADER_BAKE_SPRITES]->BindDescriptorSetTextures(1, + { + texGBufferIn[0], + texGBufferIn[1], + texGBufferIn[2] + }); + + { + PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_BAKE_SPRITES], "#", _rphBakeSprites); + pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF; + pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF; + pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF; + pipeDesc._topology = PrimitiveTopology::triangleStrip; + pipeDesc.DisableDepthTest(); + _pipe[PIPE_BAKE_SPRITES].Init(pipeDesc); + } + + s_ubBakeSpritesVS._matW = Math::QuadMatrix().UniformBufferFormat(); + s_ubBakeSpritesVS._matV = Math::ToUVMatrix().UniformBufferFormat(); + + pCB->BeginRenderPass(_rphBakeSprites, _fbhBakeSprites, + { + texGBufferOut[0]->GetClearValue(), + texGBufferOut[1]->GetClearValue(), + texGBufferOut[2]->GetClearValue() + }); + + pCB->BindPipeline(_pipe[PIPE_BAKE_SPRITES]); + _shader[SHADER_BAKE_SPRITES]->BeginBindDescriptors(); + pCB->BindDescriptors(_shader[SHADER_BAKE_SPRITES], 0); + pCB->BindDescriptors(_shader[SHADER_BAKE_SPRITES], 1, _cshBakeSprites); + _shader[SHADER_BAKE_SPRITES]->EndBindDescriptors(); + renderer.DrawQuad(pCB); + + pCB->EndRenderPass(); +} + +void DeferredShading::BakeSpritesCleanup() +{ + VERUS_QREF_RENDERER; + + _pipe[PIPE_BAKE_SPRITES].Done(); + _shader[SHADER_BAKE_SPRITES]->FreeDescriptorSet(_cshBakeSprites); + renderer->DeleteFramebuffer(_fbhBakeSprites); + renderer->DeleteRenderPass(_rphBakeSprites); +} diff --git a/Verus/src/CGI/DeferredShading.h b/Verus/src/CGI/DeferredShading.h index 60810bc..5794d7b 100644 --- a/Verus/src/CGI/DeferredShading.h +++ b/Verus/src/CGI/DeferredShading.h @@ -16,11 +16,15 @@ namespace verus { #include "../Shaders/DS.inc.hlsl" #include "../Shaders/DS_Compose.inc.hlsl" +#include "../Shaders/DS_AO.inc.hlsl" +#include "../Shaders/DS_BakeSprites.inc.hlsl" enum SHADER { SHADER_LIGHT, SHADER_COMPOSE, + SHADER_AO, + SHADER_BAKE_SPRITES, SHADER_COUNT }; @@ -32,6 +36,8 @@ namespace verus PIPE_COMPOSE, PIPE_TONE_MAPPING, PIPE_QUAD, + PIPE_INSTANCED_AO, + PIPE_BAKE_SPRITES, PIPE_COUNT }; @@ -47,29 +53,42 @@ namespace verus TEX_COUNT }; - static UB_PerFrame s_ubPerFrame; - static UB_TexturesFS s_ubTexturesFS; - static UB_PerMeshVS s_ubPerMeshVS; - static UB_ShadowFS s_ubShadowFS; - static UB_PerObject s_ubPerObject; - static UB_ComposeVS s_ubComposeVS; - static UB_ComposeFS s_ubComposeFS; + static UB_PerFrame s_ubPerFrame; + static UB_TexturesFS s_ubTexturesFS; + static UB_PerMeshVS s_ubPerMeshVS; + static UB_ShadowFS s_ubShadowFS; + static UB_PerObject s_ubPerObject; + static UB_ComposeVS s_ubComposeVS; + static UB_ComposeFS s_ubComposeFS; + static UB_AOPerFrame s_ubAOPerFrame; + static UB_AOTexturesFS s_ubAOTexturesFS; + static UB_AOPerMeshVS s_ubAOPerMeshVS; + static UB_AOPerObject s_ubAOPerObject; + static UB_BakeSpritesVS s_ubBakeSpritesVS; + static UB_BakeSpritesFS s_ubBakeSpritesFS; ShaderPwns _shader; PipelinePwns _pipe; TexturePwns _tex; TexturePtr _texShadowAtmo; + TexturePtr _texAO; UINT64 _frame = 0; RPHandle _rph; + RPHandle _rphAO; RPHandle _rphCompose; RPHandle _rphExtraCompose; + RPHandle _rphBakeSprites; FBHandle _fbh; + FBHandle _fbhAO; FBHandle _fbhCompose; FBHandle _fbhExtraCompose; + FBHandle _fbhBakeSprites; CSHandle _cshLight; + CSHandle _cshAO; CSHandle _cshCompose; CSHandle _cshToneMapping; CSHandle _cshQuad[5]; + CSHandle _cshBakeSprites; bool _activeGeometryPass = false; bool _activeLightingPass = false; bool _async_initPipe = false; @@ -89,6 +108,7 @@ namespace verus static bool IsLoaded(); + void ResetInstanceCount(); void Draw(int gbuffer); bool IsActiveGeometryPass() const { return _activeGeometryPass; } @@ -101,16 +121,20 @@ namespace verus void EndGeometryPass(bool resetRT = false); bool BeginLightingPass(); void EndLightingPass(); + void BeginAmbientOcclusion(); + void EndAmbientOcclusion(); void BeginCompose(); void EndCompose(); void ToneMapping(RcVector4 bgColor = Vector4(0)); - void AntiAliasing(); static bool IsLightUrl(CSZ url); + void OnNewLightType(CommandBufferPtr cb, LightType type, bool wireframe = false); + void BindDescriptorsPerMeshVS(CommandBufferPtr cb); static UB_PerMeshVS& GetUbPerMeshVS() { return s_ubPerMeshVS; } - void OnNewLightType(LightType type, bool wireframe = false); - void UpdateUniformBufferPerFrame(); - void BindDescriptorsPerMeshVS(); + + void OnNewAOType(CommandBufferPtr cb, LightType type); + void BindDescriptorsAOPerMeshVS(CommandBufferPtr cb); + static UB_AOPerMeshVS& GetUbAOPerMeshVS() { return s_ubAOPerMeshVS; } void Load(); @@ -118,6 +142,13 @@ namespace verus TexturePtr GetComposedTextureA(); TexturePtr GetComposedTextureB(); + + static Vector4 GetClearValueForGBuffer0(); + static Vector4 GetClearValueForGBuffer1(); + static Vector4 GetClearValueForGBuffer2(); + + void BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB = nullptr); + void BakeSpritesCleanup(); }; VERUS_TYPEDEFS(DeferredShading); } diff --git a/Verus/src/CGI/Renderer.cpp b/Verus/src/CGI/Renderer.cpp index 5e5cc48..ce713a2 100644 --- a/Verus/src/CGI/Renderer.cpp +++ b/Verus/src/CGI/Renderer.cpp @@ -108,7 +108,7 @@ void Renderer::Init(PRendererDelegate pDelegate) _geoQuad.Init(geoDesc); _shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl"); - _shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), 100, + _shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), settings.GetLimits()._generateMips_ubCapacity, { Sampler::linearClampMipN, Sampler::storage, @@ -120,8 +120,8 @@ void Renderer::Init(PRendererDelegate pDelegate) _shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout(); _shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl"); - _shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), 100, {}, ShaderStageFlags::vs); - _shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), 100, { Sampler::linearClampMipN }, ShaderStageFlags::fs); + _shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), settings.GetLimits()._quad_ubVSCapacity, {}, ShaderStageFlags::vs); + _shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), settings.GetLimits()._quad_ubFSCapacity, { Sampler::linearClampMipN }, ShaderStageFlags::fs); _shader[SHADER_QUAD]->CreatePipelineLayout(); { @@ -175,6 +175,7 @@ void Renderer::Done() _geoQuad.Done(); _commandBuffer.Done(); + Scene::Forest::DoneStatic(); Scene::Grass::DoneStatic(); Scene::Terrain::DoneStatic(); Scene::Mesh::DoneStatic(); @@ -205,10 +206,10 @@ void Renderer::Update() const float alpha = Math::Max(0.001f, floatColor[3]); const float actual = gray.r; const float expScale = Math::Clamp(_exposure[1] * (1 / 15.f), 0.f, 1.f); - const float target = -0.4f + 0.75f * expScale * expScale; // Dark scene exposure compensation. + const float target = -0.3f + 0.6f * expScale * expScale; // Dark scene exposure compensation. const float important = (actual - 0.5f * (1 - alpha)) / alpha; const float delta = abs(target - important); - const float speed = delta * sqrt(delta) * 43; + const float speed = delta * sqrt(delta) * 30; if (important < target * 0.95f) _exposure[1] -= speed * dt; @@ -312,7 +313,7 @@ void Renderer::OnSwapChainResized(bool init, bool done) void Renderer::DrawQuad(PBaseCommandBuffer pCB) { if (!pCB) - pCB = &(*_commandBuffer); + pCB = _commandBuffer.Get(); pCB->BindVertexBuffers(_geoQuad); pCB->Draw(4, 1); } @@ -323,7 +324,7 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass) return; if (!pCB) - pCB = &(*_commandBuffer); + pCB = _commandBuffer.Get(); _tex[TEX_OFFSCREEN_COLOR]->GenerateMips(); @@ -332,8 +333,8 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass) pCB->BeginRenderPass(_rphSwapChainWithDepth, _fbhSwapChainWithDepth[_pBaseRenderer->GetSwapChainBufferIndex()], { Vector4(0), Vector4(1) }); - pCB->BindVertexBuffers(_geoQuad); pCB->BindPipeline(_pipe[PIPE_OFFSCREEN_COLOR]); + pCB->BindVertexBuffers(_geoQuad); _shader[SHADER_QUAD]->BeginBindDescriptors(); pCB->BindDescriptors(_shader[SHADER_QUAD], 0); pCB->BindDescriptors(_shader[SHADER_QUAD], 1, _cshOffscreenColor); @@ -350,7 +351,7 @@ void Renderer::DrawOffscreenColorSwitchRenderPass(PBaseCommandBuffer pCB) return; if (!pCB) - pCB = &(*_commandBuffer); + pCB = _commandBuffer.Get(); pCB->EndRenderPass(); diff --git a/Verus/src/CGI/TextureRAM.cpp b/Verus/src/CGI/TextureRAM.cpp index ea254a6..7fb62ad 100644 --- a/Verus/src/CGI/TextureRAM.cpp +++ b/Verus/src/CGI/TextureRAM.cpp @@ -42,7 +42,7 @@ void TextureRAM::UpdateSubresource(const void* p, int mipLevel, int arrayLayer, memcpy(_vBuffer.data(), p, _vBuffer.size()); } -bool TextureRAM::ReadbackSubresource(void* p, PBaseCommandBuffer pCB) +bool TextureRAM::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) { VERUS_RT_ASSERT(IsLoaded()); memcpy(p, _vBuffer.data(), _vBuffer.size()); diff --git a/Verus/src/CGI/TextureRAM.h b/Verus/src/CGI/TextureRAM.h index 156b623..6a1c8ab 100644 --- a/Verus/src/CGI/TextureRAM.h +++ b/Verus/src/CGI/TextureRAM.h @@ -16,7 +16,7 @@ namespace verus virtual void Done() override; virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override; - virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override; + virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override; virtual void GenerateMips(PBaseCommandBuffer pCB) override; diff --git a/Verus/src/Effects/Bloom.cpp b/Verus/src/Effects/Bloom.cpp index 992db62..9fe90b3 100644 --- a/Verus/src/Effects/Bloom.cpp +++ b/Verus/src/Effects/Bloom.cpp @@ -3,8 +3,9 @@ using namespace verus; using namespace verus::Effects; -Bloom::UB_BloomVS Bloom::s_ubBloomVS; -Bloom::UB_BloomFS Bloom::s_ubBloomFS; +Bloom::UB_BloomVS Bloom::s_ubBloomVS; +Bloom::UB_BloomFS Bloom::s_ubBloomFS; +Bloom::UB_BloomGodRaysFS Bloom::s_ubBloomGodRaysFS; Bloom::Bloom() { @@ -26,12 +27,17 @@ void Bloom::Init() _shader->CreateDescriptorSet(0, &s_ubBloomVS, sizeof(s_ubBloomVS), 100, {}, CGI::ShaderStageFlags::vs); _shader->CreateDescriptorSet(1, &s_ubBloomFS, sizeof(s_ubBloomFS), 100, { - CGI::Sampler::nearestMipN + CGI::Sampler::linearClampMipN + }, CGI::ShaderStageFlags::fs); + _shader->CreateDescriptorSet(2, &s_ubBloomGodRaysFS, sizeof(s_ubBloomGodRaysFS), 100, + { + CGI::Sampler::linearClampMipN, + CGI::Sampler::shadow }, CGI::ShaderStageFlags::fs); _shader->CreatePipelineLayout(); { - CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph); + CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#GodRays", _rph); pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip; pipeDesc.DisableDepthTest(); _pipe.Init(pipeDesc); @@ -40,15 +46,30 @@ void Bloom::Init() OnSwapChainResized(); } +void Bloom::InitByAtmosphere(CGI::TexturePtr texShadow) +{ + VERUS_QREF_RENDERER; + + _texAtmoShadow = texShadow; + + _cshGodRays = _shader->BindDescriptorSetTextures(2, { renderer.GetTexDepthStencil(), _texAtmoShadow }); +} + void Bloom::Done() { + VERUS_QREF_RENDERER; + _shader->FreeDescriptorSet(_cshGodRays); + _shader->FreeDescriptorSet(_csh); + renderer->DeleteFramebuffer(_fbh); VERUS_DONE(Bloom); } void Bloom::OnSwapChainResized() { VERUS_QREF_RENDERER; + VERUS_QREF_ATMO; { + _shader->FreeDescriptorSet(_cshGodRays); _shader->FreeDescriptorSet(_csh); renderer->DeleteFramebuffer(_fbh); _tex.Done(); @@ -65,6 +86,9 @@ void Bloom::OnSwapChainResized() _tex[TEX_PONG].Init(texDesc); _fbh = renderer->CreateFramebuffer(_rph, { _tex[TEX_PING] }, w, h); _csh = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() }); + + if (_texAtmoShadow) + InitByAtmosphere(_texAtmoShadow); } renderer.GetDS().InitByBloom(_tex[TEX_PING]); } @@ -72,25 +96,38 @@ void Bloom::OnSwapChainResized() void Bloom::Generate() { VERUS_QREF_RENDERER; + VERUS_QREF_ATMO; + VERUS_QREF_SM; + + auto cb = renderer.GetCommandBuffer(); s_ubBloomVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubBloomVS._matV = Math::ToUVMatrix().UniformBufferFormat(); s_ubBloomFS._exposure.x = renderer.GetExposure(); + s_ubBloomGodRaysFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat(); + s_ubBloomGodRaysFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat(); + s_ubBloomGodRaysFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat(); + s_ubBloomGodRaysFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat(); + s_ubBloomGodRaysFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat(); + memcpy(&s_ubBloomGodRaysFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubBloomGodRaysFS._shadowConfig)); + s_ubBloomGodRaysFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM(); + s_ubBloomGodRaysFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0); + s_ubBloomGodRaysFS._sunColor = float4(atmo.GetSunColor().GLM(), 0); + s_ubBloomGodRaysFS._eyePos = float4(atmo.GetEyePosition().GLM(), 0); - auto cb = renderer.GetCommandBuffer(); - + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0); cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_PING]->GetClearValue() }); cb->BindPipeline(_pipe); - _shader->BeginBindDescriptors(); cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _csh); + cb->BindDescriptors(_shader, 2, _cshGodRays); _shader->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0); Blur::I().GenerateForBloom(); } diff --git a/Verus/src/Effects/Bloom.h b/Verus/src/Effects/Bloom.h index 1418fa9..f7f794b 100644 --- a/Verus/src/Effects/Bloom.h +++ b/Verus/src/Effects/Bloom.h @@ -15,21 +15,25 @@ namespace verus TEX_COUNT }; - static UB_BloomVS s_ubBloomVS; - static UB_BloomFS s_ubBloomFS; + static UB_BloomVS s_ubBloomVS; + static UB_BloomFS s_ubBloomFS; + static UB_BloomGodRaysFS s_ubBloomGodRaysFS; CGI::ShaderPwn _shader; CGI::PipelinePwn _pipe; CGI::TexturePwns _tex; + CGI::TexturePtr _texAtmoShadow; CGI::RPHandle _rph; CGI::FBHandle _fbh; CGI::CSHandle _csh; + CGI::CSHandle _cshGodRays; public: Bloom(); ~Bloom(); void Init(); + void InitByAtmosphere(CGI::TexturePtr texShadow); void Done(); void OnSwapChainResized(); diff --git a/Verus/src/Effects/Blur.cpp b/Verus/src/Effects/Blur.cpp index 5bc88d5..bd78076 100644 --- a/Verus/src/Effects/Blur.cpp +++ b/Verus/src/Effects/Blur.cpp @@ -3,8 +3,9 @@ using namespace verus; using namespace verus::Effects; -Blur::UB_BlurVS Blur::s_ubBlurVS; -Blur::UB_BlurFS Blur::s_ubBlurFS; +Blur::UB_BlurVS Blur::s_ubBlurVS; +Blur::UB_BlurFS Blur::s_ubBlurFS; +Blur::UB_ExtraBlurFS Blur::s_ubExtraBlurFS; // Blur::Handles: @@ -41,6 +42,8 @@ void Blur::Init() _bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8); _ssaoHandles._rphH = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8); _ssaoHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::unormR8); + _rphAntiAliasing = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10); + _rphMotionBlur = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10); _shader.Init("[Shaders]:Blur.hlsl"); _shader->CreateDescriptorSet(0, &s_ubBlurVS, sizeof(s_ubBlurVS), 100, {}, CGI::ShaderStageFlags::vs); @@ -48,6 +51,11 @@ void Blur::Init() { CGI::Sampler::linearClampMipN }, CGI::ShaderStageFlags::fs); + _shader->CreateDescriptorSet(2, &s_ubExtraBlurFS, sizeof(s_ubExtraBlurFS), 100, + { + CGI::Sampler::linearClampMipN, + CGI::Sampler::linearClampMipN + }, CGI::ShaderStageFlags::fs); _shader->CreatePipelineLayout(); { @@ -76,12 +84,28 @@ void Blur::Init() pipeDesc._renderPassHandle = _ssaoHandles._rphV; _pipe[PIPE_SSAO_V].Init(pipeDesc); } + { + CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#AntiAliasing", _rphAntiAliasing); + pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip; + pipeDesc.DisableDepthTest(); + _pipe[PIPE_AA].Init(pipeDesc); + } + { + CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#Motion", _rphMotionBlur); + pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip; + pipeDesc.DisableDepthTest(); + _pipe[PIPE_MOTION_BLUR].Init(pipeDesc); + } OnSwapChainResized(); } void Blur::Done() { + _shader->FreeDescriptorSet(_cshMotionBlurExtra); + _shader->FreeDescriptorSet(_cshMotionBlur); + _shader->FreeDescriptorSet(_cshAntiAliasingExtra); + _shader->FreeDescriptorSet(_cshAntiAliasing); _ssaoHandles.FreeDescriptorSets(_shader); _bloomHandles.FreeDescriptorSets(_shader); VERUS_DONE(Blur); @@ -93,6 +117,12 @@ void Blur::OnSwapChainResized() VERUS_QREF_BLOOM; VERUS_QREF_SSAO; { + _shader->FreeDescriptorSet(_cshMotionBlurExtra); + _shader->FreeDescriptorSet(_cshMotionBlur); + renderer->DeleteFramebuffer(_fbhMotionBlur); + _shader->FreeDescriptorSet(_cshAntiAliasingExtra); + _shader->FreeDescriptorSet(_cshAntiAliasing); + renderer->DeleteFramebuffer(_fbhAntiAliasing); _ssaoHandles.FreeDescriptorSets(_shader); _ssaoHandles.DeleteFramebuffers(); _bloomHandles.FreeDescriptorSets(_shader); @@ -100,24 +130,35 @@ void Blur::OnSwapChainResized() _tex.Done(); } { + const int swapChainWidth = renderer.GetSwapChainWidth(); + const int swapChainHeight = renderer.GetSwapChainHeight(); + const int swapChainHalfWidth = renderer.GetSwapChainWidth() / 2; + const int swapChainHalfHeight = renderer.GetSwapChainHeight() / 2; + CGI::TextureDesc texDesc; texDesc._format = CGI::Format::srgbR8G8B8A8; - texDesc._width = renderer.GetSwapChainWidth(); - texDesc._height = renderer.GetSwapChainHeight(); + texDesc._width = swapChainWidth; + texDesc._height = swapChainHeight; texDesc._flags = CGI::TextureDesc::Flags::colorAttachment; _tex.Init(texDesc); - const int halfW = renderer.GetSwapChainWidth() / 2; - const int halfH = renderer.GetSwapChainHeight() / 2; - _bloomHandles._fbhH = renderer->CreateFramebuffer(_bloomHandles._rphH, { bloom.GetPongTexture() }, halfW, halfH); - _bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, halfW, halfH); + _bloomHandles._fbhH = renderer->CreateFramebuffer(_bloomHandles._rphH, { bloom.GetPongTexture() }, swapChainHalfWidth, swapChainHalfHeight); + _bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, swapChainHalfWidth, swapChainHalfHeight); _bloomHandles._cshH = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() }); _bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() }); - _ssaoHandles._fbhH = renderer->CreateFramebuffer(_ssaoHandles._rphH, { _tex }, renderer.GetSwapChainWidth(), renderer.GetSwapChainHeight()); - _ssaoHandles._fbhV = renderer->CreateFramebuffer(_ssaoHandles._rphV, { ssao.GetTexture() }, renderer.GetSwapChainWidth(), renderer.GetSwapChainHeight()); + _ssaoHandles._fbhH = renderer->CreateFramebuffer(_ssaoHandles._rphH, { _tex }, swapChainWidth, swapChainHeight); + _ssaoHandles._fbhV = renderer->CreateFramebuffer(_ssaoHandles._rphV, { ssao.GetTexture() }, swapChainWidth, swapChainHeight); _ssaoHandles._cshH = _shader->BindDescriptorSetTextures(1, { ssao.GetTexture() }); _ssaoHandles._cshV = _shader->BindDescriptorSetTextures(1, { _tex }); + + _fbhAntiAliasing = renderer->CreateFramebuffer(_rphAntiAliasing, { renderer.GetDS().GetComposedTextureB() }, swapChainWidth, swapChainHeight); + _cshAntiAliasing = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() }); + _cshAntiAliasingExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() }); + + _fbhMotionBlur = renderer->CreateFramebuffer(_rphMotionBlur, { renderer.GetDS().GetComposedTextureA() }, swapChainWidth, swapChainHeight); + _cshMotionBlur = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureB() }); + _cshMotionBlurExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() }); } } @@ -130,21 +171,19 @@ void Blur::GenerateForBloom() VERUS_QREF_RENDERER; VERUS_QREF_BLOOM; + auto cb = renderer.GetCommandBuffer(); + s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize(), nullptr, 0.5f, 0).UniformBufferFormat(); - auto cb = renderer.GetCommandBuffer(); - _shader->BeginBindDescriptors(); { cb->BeginRenderPass(_bloomHandles._rphH, _bloomHandles._fbhH, { bloom.GetPongTexture()->GetClearValue() }); cb->BindPipeline(_pipe[PIPE_BLOOM_H]); - cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _bloomHandles._cshH); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); } @@ -153,11 +192,9 @@ void Blur::GenerateForBloom() cb->BeginRenderPass(_bloomHandles._rphV, _bloomHandles._fbhV, { bloom.GetTexture()->GetClearValue() }); cb->BindPipeline(_pipe[PIPE_BLOOM_V]); - cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _bloomHandles._cshV); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); } @@ -169,21 +206,19 @@ void Blur::GenerateForSsao() VERUS_QREF_RENDERER; VERUS_QREF_SSAO; + auto cb = renderer.GetCommandBuffer(); + s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubBlurVS._matV = Math::ToUVMatrix(0, _tex->GetSize(), nullptr, 0.5f, 0).UniformBufferFormat(); - auto cb = renderer.GetCommandBuffer(); - _shader->BeginBindDescriptors(); { cb->BeginRenderPass(_ssaoHandles._rphH, _ssaoHandles._fbhH, { _tex->GetClearValue() }); cb->BindPipeline(_pipe[PIPE_SSAO_H]); - cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _ssaoHandles._cshH); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); } @@ -192,21 +227,66 @@ void Blur::GenerateForSsao() cb->BeginRenderPass(_ssaoHandles._rphV, _ssaoHandles._fbhV, { ssao.GetTexture()->GetClearValue() }); cb->BindPipeline(_pipe[PIPE_SSAO_V]); - cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _ssaoHandles._cshV); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); } _shader->EndBindDescriptors(); } -void Blur::GenerateForDepthOfField() +void Blur::GenerateForAntiAliasing() { + VERUS_QREF_RENDERER; + VERUS_QREF_SM; + + auto cb = renderer.GetCommandBuffer(); + + s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat(); + s_ubBlurVS._matV = Math::ToUVMatrix().UniformBufferFormat(); + s_ubExtraBlurFS._zNearFarEx = sm.GetMainCamera()->GetZNearFarEx().GLM(); + s_ubExtraBlurFS._textureSize = renderer.GetDS().GetComposedTextureA()->GetSize().GLM(); + + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0); + cb->BeginRenderPass(_rphAntiAliasing, _fbhAntiAliasing, { renderer.GetDS().GetComposedTextureB()->GetClearValue() }); + + cb->BindPipeline(_pipe[PIPE_AA]); + _shader->BeginBindDescriptors(); + cb->BindDescriptors(_shader, 0); + cb->BindDescriptors(_shader, 1, _cshAntiAliasing); + cb->BindDescriptors(_shader, 2, _cshAntiAliasingExtra); + _shader->EndBindDescriptors(); + renderer.DrawQuad(cb.Get()); + + cb->EndRenderPass(); + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0); } void Blur::GenerateForMotionBlur() { + VERUS_QREF_RENDERER; + VERUS_QREF_SM; + + auto cb = renderer.GetCommandBuffer(); + + s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat(); + s_ubBlurVS._matV = Math::ToUVMatrix().UniformBufferFormat(); + s_ubExtraBlurFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat(); + s_ubExtraBlurFS._matPrevVP = sm.GetMainCamera()->GetMatrixPrevVP().UniformBufferFormat(); + s_ubExtraBlurFS._zNearFarEx = sm.GetMainCamera()->GetZNearFarEx().GLM(); + + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0); + cb->BeginRenderPass(_rphMotionBlur, _fbhMotionBlur, { renderer.GetDS().GetComposedTextureB()->GetClearValue() }); + + cb->BindPipeline(_pipe[PIPE_MOTION_BLUR]); + _shader->BeginBindDescriptors(); + cb->BindDescriptors(_shader, 0); + cb->BindDescriptors(_shader, 1, _cshMotionBlur); + cb->BindDescriptors(_shader, 2, _cshMotionBlurExtra); + _shader->EndBindDescriptors(); + renderer.DrawQuad(cb.Get()); + + cb->EndRenderPass(); + cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0); } diff --git a/Verus/src/Effects/Blur.h b/Verus/src/Effects/Blur.h index 3ba5126..fb0f32d 100644 --- a/Verus/src/Effects/Blur.h +++ b/Verus/src/Effects/Blur.h @@ -16,6 +16,8 @@ namespace verus PIPE_BLOOM_V, PIPE_SSAO_H, PIPE_SSAO_V, + PIPE_AA, + PIPE_MOTION_BLUR, PIPE_COUNT }; @@ -32,14 +34,23 @@ namespace verus void DeleteFramebuffers(); }; - static UB_BlurVS s_ubBlurVS; - static UB_BlurFS s_ubBlurFS; + static UB_BlurVS s_ubBlurVS; + static UB_BlurFS s_ubBlurFS; + static UB_ExtraBlurFS s_ubExtraBlurFS; CGI::ShaderPwn _shader; CGI::PipelinePwns _pipe; CGI::TexturePwn _tex; Handles _bloomHandles; Handles _ssaoHandles; + CGI::RPHandle _rphAntiAliasing; + CGI::FBHandle _fbhAntiAliasing; + CGI::CSHandle _cshAntiAliasing; + CGI::CSHandle _cshAntiAliasingExtra; + CGI::RPHandle _rphMotionBlur; + CGI::FBHandle _fbhMotionBlur; + CGI::CSHandle _cshMotionBlur; + CGI::CSHandle _cshMotionBlurExtra; public: Blur(); @@ -53,7 +64,7 @@ namespace verus void Generate(); void GenerateForBloom(); void GenerateForSsao(); - void GenerateForDepthOfField(); + void GenerateForAntiAliasing(); void GenerateForMotionBlur(); }; VERUS_TYPEDEFS(Blur); diff --git a/Verus/src/Effects/Ssao.cpp b/Verus/src/Effects/Ssao.cpp index ce58233..7252287 100644 --- a/Verus/src/Effects/Ssao.cpp +++ b/Verus/src/Effects/Ssao.cpp @@ -86,6 +86,8 @@ void Ssao::Generate() Scene::RCamera cam = *sm.GetCamera(); + auto cb = renderer.GetCommandBuffer(); + s_ubSsaoVS._matW = Math::QuadMatrix().UniformBufferFormat(); s_ubSsaoVS._matV = Math::ToUVMatrix().UniformBufferFormat(); s_ubSsaoVS._matP = Math::ToUVMatrix(0, _tex[TEX_GEN_AO]->GetSize(), &_tex[TEX_RAND_NORMALS]->GetSize()).UniformBufferFormat(); @@ -93,18 +95,14 @@ void Ssao::Generate() s_ubSsaoFS._camScale.x = cam.GetFovScale() / cam.GetAspectRatio(); s_ubSsaoFS._camScale.y = -cam.GetFovScale(); - auto cb = renderer.GetCommandBuffer(); - cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_GEN_AO]->GetClearValue() }); cb->BindPipeline(_pipe); - _shader->BeginBindDescriptors(); cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _csh); _shader->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); diff --git a/Verus/src/GUI/Container.cpp b/Verus/src/GUI/Container.cpp index 14f1868..61582ea 100644 --- a/Verus/src/GUI/Container.cpp +++ b/Verus/src/GUI/Container.cpp @@ -133,7 +133,7 @@ PWidget Container::GetWidgetById(CSZ id) int Container::GetWidgetIndex(PWidget p) { - const int size = _vWidgets.size(); + const int size = Utils::Cast32(_vWidgets.size()); VERUS_FOR(i, size) { if (_vWidgets[i] == p) diff --git a/Verus/src/GUI/Container.h b/Verus/src/GUI/Container.h index b190a8b..739fbc9 100644 --- a/Verus/src/GUI/Container.h +++ b/Verus/src/GUI/Container.h @@ -31,7 +31,7 @@ namespace verus PWidget GetHovered(float x, float y); PWidget GetWidgetById(CSZ id); - int GetWidgetCount() const { return _vWidgets.size(); } + int GetWidgetCount() const { return Utils::Cast32(_vWidgets.size()); } int GetWidgetIndex(PWidget p); }; VERUS_TYPEDEFS(Container); diff --git a/Verus/src/GUI/Font.cpp b/Verus/src/GUI/Font.cpp index 1f49cad..9d1a929 100644 --- a/Verus/src/GUI/Font.cpp +++ b/Verus/src/GUI/Font.cpp @@ -156,8 +156,8 @@ void Font::Draw(RcDrawDesc dd) auto cb = renderer.GetCommandBuffer(); - cb->BindVertexBuffers(_dynBuffer); cb->BindPipeline(_pipe); + cb->BindVertexBuffers(_dynBuffer); s_shader->BeginBindDescriptors(); cb->BindDescriptors(s_shader, 0, _csh); @@ -168,7 +168,7 @@ void Font::Draw(RcDrawDesc dd) { const float spaceLeft = (dd._x + dd._w) - xoffset; - int wordLen = wcscspn(text, wrapChars); // First occurrence of wrap chars. + int wordLen = static_cast(wcscspn(text, wrapChars)); // First occurrence of wrap chars. if (!wordLen && L'-' == *text) wordLen = 1; // Don't throw away hyphen. @@ -296,7 +296,7 @@ float Font::DrawWord(CWSZ word, int wordLen, float xoffset, float yoffset, bool int Font::GetTextWidth(CWSZ text, int textLen) { - const int len = (textLen >= 0) ? textLen : wcslen(text); + const int len = (textLen >= 0) ? textLen : static_cast(wcslen(text)); int width = 0; VERUS_FOR(i, len) { diff --git a/Verus/src/GUI/Image.cpp b/Verus/src/GUI/Image.cpp index 0d0405c..4741986 100644 --- a/Verus/src/GUI/Image.cpp +++ b/Verus/src/GUI/Image.cpp @@ -101,7 +101,6 @@ void Image::Draw() cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1, _solidColor ? CGI::CSHandle() : _csh); shader->EndBindDescriptors(); - renderer.DrawQuad(); } diff --git a/Verus/src/GUI/Table.cpp b/Verus/src/GUI/Table.cpp index 409489a..a4683cd 100644 --- a/Verus/src/GUI/Table.cpp +++ b/Verus/src/GUI/Table.cpp @@ -57,19 +57,17 @@ void Table::Draw() { if (row == _selectedRow) { - vm.GetUbGui()._matW = Math::QuadMatrix(x, yOffset, w, _rowHeight).UniformBufferFormat(); - vm.GetUbGuiFS()._color = Vector4(1, 1, 1, 0.25f).GLM(); - auto cb = renderer.GetCommandBuffer(); auto shader = vm.GetShader(); - vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); + vm.GetUbGui()._matW = Math::QuadMatrix(x, yOffset, w, _rowHeight).UniformBufferFormat(); + vm.GetUbGuiFS()._color = Vector4(1, 1, 1, 0.25f).GLM(); + vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1); shader->EndBindDescriptors(); - renderer.DrawQuad(); } @@ -178,7 +176,7 @@ void Table::UpdateRow(int index, int col, CSZ txt, UINT32 color, const void* pUs int Table::AppendRow() { - const int size = _vRows.size(); + const int size = Utils::Cast32(_vRows.size()); _vRows.resize(size + 1); _vRows[size]._vCells.resize(_cols); return size; diff --git a/Verus/src/GUI/Table.h b/Verus/src/GUI/Table.h index 84ebf91..1bf9fc3 100644 --- a/Verus/src/GUI/Table.h +++ b/Verus/src/GUI/Table.h @@ -42,7 +42,7 @@ namespace verus virtual void InputFocus_Key(int scancode) override; void Clear(); - int GetRowCount() const { return _vRows.size(); } + int GetRowCount() const { return Utils::Cast32(_vRows.size()); } int GetSelectedRow() const { return _selectedRow; } void SelectRow(int row) { _selectedRow = row; } void SelectNextRow(); diff --git a/Verus/src/GUI/TextBox.cpp b/Verus/src/GUI/TextBox.cpp index 28251d6..74c3e7f 100644 --- a/Verus/src/GUI/TextBox.cpp +++ b/Verus/src/GUI/TextBox.cpp @@ -44,20 +44,18 @@ void TextBox::Draw() PFont pFont = vm.FindFont(GetFont()); const float caretX = Font::ToFloatX(pFont->GetTextWidth(_C(GetText())), GetFontScale()); + auto cb = renderer.GetCommandBuffer(); + auto shader = vm.GetShader(); + vm.GetUbGui()._matW = Math::QuadMatrix(x + caretX, y, 0.0015f, GetH()).UniformBufferFormat(); vm.GetUbGui()._matV = Math::ToUVMatrix(0, 0).UniformBufferFormat(); vm.GetUbGuiFS()._color = Vector4(1, 1, 1, 1).GLM(); - auto cb = renderer.GetCommandBuffer(); - auto shader = vm.GetShader(); - vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); - shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1); shader->EndBindDescriptors(); - renderer.DrawQuad(); } } @@ -67,7 +65,7 @@ void TextBox::Parse(pugi::xml_node node) Label::Parse(node); _fullText = _C(GetText()); - _cursor = GetText().Length(); + _cursor = Utils::Cast32(GetText().Length()); _maxLength = node.attribute("maxLength").as_int(_maxLength); @@ -176,7 +174,7 @@ void TextBox::SetText(CWSZ txt) if (!txt) return; _fullText = txt; - _cursor = _fullText.length(); + _cursor = Utils::Cast32(_fullText.length()); UpdateLabelText(); } @@ -185,6 +183,6 @@ void TextBox::SetText(CSZ txt) if (!txt) return; _fullText = Str::Utf8ToWide(txt); - _cursor = _fullText.length(); + _cursor = Utils::Cast32(_fullText.length()); UpdateLabelText(); } diff --git a/Verus/src/GUI/View.cpp b/Verus/src/GUI/View.cpp index e086065..705601f 100644 --- a/Verus/src/GUI/View.cpp +++ b/Verus/src/GUI/View.cpp @@ -94,13 +94,11 @@ void View::Draw() ubGuiFS._color = Vector4::Replicate(1).GLM(); vm.BindPipeline(ViewManager::PIPE_MAIN, cb); - shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1, _csh); shader->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); } } else if (!GetColor().IsZero()) @@ -112,13 +110,11 @@ void View::Draw() ubGuiFS._color = GetColor().GLM(); vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); - shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle()); shader->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); } DrawWidgets(); @@ -128,17 +124,12 @@ void View::Draw() vm.GetUbGui()._matW = Transform3::UniformBufferFormatIdentity(); vm.GetUbGuiFS()._color = Vector4(0, 0, 0, _fade.GetValue()).GLM(); - auto cb = renderer.GetCommandBuffer(); - auto shader = vm.GetShader(); - vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); - shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle()); shader->EndBindDescriptors(); - - renderer.DrawQuad(&(*cb)); + renderer.DrawQuad(cb.Get()); } } diff --git a/Verus/src/GUI/Widget.cpp b/Verus/src/GUI/Widget.cpp index fa15c1b..e7220a6 100644 --- a/Verus/src/GUI/Widget.cpp +++ b/Verus/src/GUI/Widget.cpp @@ -19,7 +19,7 @@ WideStr Widget::GetText() const void Widget::SetText(CWSZ text) { if (_fixedTextLength) - wcsncpy(_vFixedText.data(), text, Math::Min(wcslen(text), _fixedTextLength - 1)); + wcsncpy(_vFixedText.data(), text, Math::Min(Utils::Cast32(wcslen(text)), _fixedTextLength - 1)); else _text = text; } @@ -65,19 +65,17 @@ void Widget::DrawInputStyle() float x, y; GetAbsolutePosition(x, y); - vm.GetUbGui()._matW = Math::QuadMatrix(x, y, GetW(), GetH()).UniformBufferFormat(); - vm.GetUbGuiFS()._color = Vector4(0, 0, 0, 0.75f * GetColor().getW()).GLM(); - auto cb = renderer.GetCommandBuffer(); auto shader = vm.GetShader(); - vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); + vm.GetUbGui()._matW = Math::QuadMatrix(x, y, GetW(), GetH()).UniformBufferFormat(); + vm.GetUbGuiFS()._color = Vector4(0, 0, 0, 0.75f * GetColor().getW()).GLM(); + vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb); shader->BeginBindDescriptors(); cb->BindDescriptors(shader, 0); cb->BindDescriptors(shader, 1); shader->EndBindDescriptors(); - renderer.DrawQuad(); } diff --git a/Verus/src/Game/BaseCharacter.cpp b/Verus/src/Game/BaseCharacter.cpp index 10ebe11..990b696 100644 --- a/Verus/src/Game/BaseCharacter.cpp +++ b/Verus/src/Game/BaseCharacter.cpp @@ -290,13 +290,14 @@ void BaseCharacter::ComputeThirdPersonCameraArgs(RcVector3 offset, RPoint3 eye, Point3 point; Vector3 norm; + const RcVector3 offsetW = GetYawMatrix() * offset; const Point3 pos = _smoothPosition; const float startAt = _cc.GetRadius() + _cc.GetHeight() * 0.5f; // Inside capsule. const Point3 origin = pos + Vector3(0, startAt, 0); - at = pos + GetYawMatrix() * offset; + at = pos + offsetW; if (sm.RayCastingTest(origin, at, nullptr, &point, &norm, &r)) at = point + norm * r; - eye = at - GetFrontDirection() * _cameraRadius.GetValue(); + eye = at - GetFrontDirection() * _cameraRadius.GetValue() + offsetW * 0.05f; } float BaseCharacter::ComputeThirdPersonCamera(Scene::RCamera camera, Anim::RcOrbit orbit, RcVector3 offset) diff --git a/Verus/src/Global/EngineInit.cpp b/Verus/src/Global/EngineInit.cpp index 5eb7d80..2d7667b 100644 --- a/Verus/src/Global/EngineInit.cpp +++ b/Verus/src/Global/EngineInit.cpp @@ -87,7 +87,7 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere Scene::Mesh::InitStatic(); Scene::Terrain::InitStatic(); Scene::Grass::InitStatic(); - //Scene::CForest::InitStatic(); + Scene::Forest::InitStatic(); } // Helpers: diff --git a/Verus/src/Global/QuickRefs.h b/Verus/src/Global/QuickRefs.h index 53aa71e..5a38a3b 100644 --- a/Verus/src/Global/QuickRefs.h +++ b/Verus/src/Global/QuickRefs.h @@ -8,13 +8,10 @@ #define VERUS_QREF_BULLET Physics::RBullet bullet = Physics::Bullet::I() #define VERUS_QREF_CONST_SETTINGS App::RcSettings settings = App::Settings::IConst() #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() #define VERUS_QREF_HELPERS Scene::RHelpers helpers = Scene::Helpers::I() #define VERUS_QREF_KM Input::RKeyMapper km = Input::KeyMapper::I() -#define VERUS_QREF_LS Scene::RLandscape ls = Scene::Landscape::I() #define VERUS_QREF_MM Scene::RMaterialManager mm = Scene::MaterialManager::I() #define VERUS_QREF_MP Net::RMultiplayer mp = Net::Multiplayer::I() #define VERUS_QREF_PHYSICS Physics::RPhysics physics = Physics::Physics::I() diff --git a/Verus/src/Global/Store.h b/Verus/src/Global/Store.h index ec94cff..355c659 100644 --- a/Verus/src/Global/Store.h +++ b/Verus/src/Global/Store.h @@ -185,18 +185,25 @@ namespace verus bool operator==(const Ptr& that) const { return _p == that._p; } bool operator!=(const Ptr& that) const { return _p != that._p; } bool operator<(const Ptr& that) const { return _p < that._p; } + T* Attach(T* ptr) { T* p = _p; _p = ptr; return p; } + T* Detach() { T* p = _p; _p = nullptr; return p; } + + T* Get() const + { + return _p; + } }; template diff --git a/Verus/src/Global/Str.cpp b/Verus/src/Global/Str.cpp index 6190e34..d8fdd0d 100644 --- a/Verus/src/Global/Str.cpp +++ b/Verus/src/Global/Str.cpp @@ -146,6 +146,21 @@ String Str::GetFilename(CSZ pathname) return pathname; } +String Str::ToPakFriendlyUrl(CSZ url) +{ + if (!url || !url[0] || url[0] != '[') + return url; + String ret(url + 1); + const size_t pos = ret.find("]:"); + if (pos != String::npos) + { + ret.replace(pos, 2, "-"); + ReplaceAll(ret, "/", "."); + return ret; + } + return url; +} + String Str::FromInt(int n) { StringStream ss; diff --git a/Verus/src/Global/Str.h b/Verus/src/Global/Str.h index 0516914..732cbc6 100644 --- a/Verus/src/Global/Str.h +++ b/Verus/src/Global/Str.h @@ -39,6 +39,7 @@ namespace verus static void ReplaceFilename(RString pathname, CSZ filename); static String GetPath(CSZ pathname); static String GetFilename(CSZ pathname); + static String ToPakFriendlyUrl(CSZ url); static String FromInt(int n); static void Explode(CSZ s, CSZ delimiter, Vector& pieces); static void Trim(RString s); diff --git a/Verus/src/IO/FileSystem.cpp b/Verus/src/IO/FileSystem.cpp index 56cb0a5..a48139b 100644 --- a/Verus/src/IO/FileSystem.cpp +++ b/Verus/src/IO/FileSystem.cpp @@ -389,25 +389,24 @@ String FileSystem::ConvertFilenameToPassword(CSZ fileEntry) bool FileSystem::FileExist(CSZ url) { - String path(url), pak, projectPathname; + String pathname(url), pakPathname, projectPathname; const size_t pakPos = FindPosForPAK(url); if (pakPos != String::npos) { - StringStream ssPak; - ssPak << _C(Utils::I().GetModulePath()) << s_dataFolder << path.substr(0, pakPos) << ".pak"; - pak = ssPak.str(); + const String dataFolder(s_dataFolder); + const String pakFilename = pathname.substr(1, pakPos - 1); - path.replace(pakPos, 1, "/"); - projectPathname = String(_C(Utils::I().GetProjectPath())) + "/" + path; + pakPathname = _C(Utils::I().GetModulePath()) + dataFolder + pakFilename + ".pak"; - StringStream ss; - ss << _C(Utils::I().GetModulePath()) << s_dataFolder << path; - path = ss.str(); + pathname = pakFilename + '/' + pathname.substr(pakPos + 2); + projectPathname = _C(Utils::I().GetProjectPath()) + dataFolder + pathname; + + pathname = _C(Utils::I().GetModulePath()) + dataFolder + pathname; } File file; - if (file.Open(_C(path))) // Normal filename: + if (file.Open(_C(pathname))) // Normal filename: return true; - if (file.Open(_C(pak))) // PAK filename: + if (file.Open(_C(pakPathname))) // PAK filename: return true; if (file.Open(_C(projectPathname))) // File in another project dir: return true; @@ -430,7 +429,7 @@ String FileSystem::ConvertAbsolutePathToRelative(RcString path) const size_t data = path.rfind("\\Data\\"); if (data != String::npos) { - s = "[" + path.substr(data + 6); + s = '[' + path.substr(data + 6); const size_t colon = s.find('\\'); if (colon != String::npos) s.replace(colon, 1, "]:"); @@ -442,14 +441,15 @@ String FileSystem::ConvertAbsolutePathToRelative(RcString path) String FileSystem::ConvertRelativePathToAbsolute(RcString path, bool useProjectDir) { VERUS_QREF_UTILS; - String systemPath = path; + const String dataFolder(s_dataFolder); + String systemPath = path.substr(1); const size_t colon = systemPath.find(':'); - if (colon != String::npos) - systemPath[colon] = '/'; - if (useProjectDir && *_C(utils.GetProjectPath())) - systemPath = String(_C(utils.GetProjectPath())) + "/" + systemPath; + if (colon != String::npos && colon > 0) + systemPath = systemPath.substr(0, colon - 1) + '/' + systemPath.substr(colon + 1); + if (useProjectDir && !utils.GetProjectPath().IsEmpty()) + systemPath = _C(utils.GetProjectPath()) + dataFolder + systemPath; else - systemPath = String(_C(utils.GetModulePath())) + s_dataFolder + systemPath; + systemPath = _C(utils.GetModulePath()) + dataFolder + systemPath; return systemPath; } @@ -472,7 +472,6 @@ String FileSystem::ReplaceFilename(CSZ pathname, CSZ filename) return filename; } -#if 0 void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, bool upsideDown, ILenum type) { struct RAII @@ -511,7 +510,6 @@ void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, bool ups else throw VERUS_RUNTIME_ERROR << "SaveImage(), Open()"; } -#endif void FileSystem::SaveDDS(CSZ pathname, const UINT32* p, int w, int h, int d) { diff --git a/Verus/src/IO/FileSystem.h b/Verus/src/IO/FileSystem.h index 1881b82..4612737 100644 --- a/Verus/src/IO/FileSystem.h +++ b/Verus/src/IO/FileSystem.h @@ -57,9 +57,9 @@ namespace verus static String ReplaceFilename(CSZ pathname, CSZ filename); // Save data: - //static void SaveImage /**/(CSZ pathname, const UINT32* p, int w, int h, bool upsideDown = false, ILenum type = IL_PSD); - static void SaveDDS /**/(CSZ pathname, const UINT32* p, int w, int h, int d = 0); - static void SaveString /**/(CSZ pathname, CSZ s); + static void SaveImage /**/(CSZ pathname, const UINT32* p, int w, int h, bool upsideDown = false, ILenum type = IL_PSD); + static void SaveDDS /**/(CSZ pathname, const UINT32* p, int w, int h, int d = 0); + static void SaveString/**/(CSZ pathname, CSZ s); }; VERUS_TYPEDEFS(FileSystem); diff --git a/Verus/src/Math/Octree.cpp b/Verus/src/Math/Octree.cpp index aec9367..e6eec30 100644 --- a/Verus/src/Math/Octree.cpp +++ b/Verus/src/Math/Octree.cpp @@ -23,29 +23,29 @@ bool Octree::Node::HasChildren(int currentNode, int nodeCount) return GetChildIndex(currentNode, 7) < nodeCount; } -void Octree::Node::BindEntity(RcEntity entity) +void Octree::Node::BindClient(RcClient client) { - _vEntities.push_back(entity); + _vClients.push_back(client); } -void Octree::Node::UnbindEntity(void* pToken) +void Octree::Node::UnbindClient(void* pToken) { - VERUS_WHILE(Vector, _vEntities, it) + VERUS_WHILE(Vector, _vClients, it) { if (pToken == (*it)._pToken) - it = _vEntities.erase(it); + it = _vClients.erase(it); else it++; } } -void Octree::Node::UpdateDynamicEntity(RcEntity entity) +void Octree::Node::UpdateDynamicClient(RcClient client) { - for (auto& o : _vEntities) + for (auto& o : _vClients) { - if (o._pToken == entity._pToken) + if (o._pToken == client._pToken) { - o = entity; + o = client; return; } } @@ -135,25 +135,25 @@ void Octree::Build(int currentNode, int depth) } } -bool Octree::BindEntity(RcEntity entity, bool forceRoot, int currentNode) +bool Octree::BindClient(RcClient client, bool forceRoot, int currentNode) { if (!currentNode) { if (_vNodes.empty()) return false; // Octree is not ready. - UnbindEntity(entity._pToken); + UnbindClient(client._pToken); } - Entity entityEx = entity; + Client clientEx = client; if (forceRoot) { - entityEx._bounds = _vNodes[currentNode].GetBounds(); - entityEx._sphere = entityEx._bounds.GetSphere(); + clientEx._bounds = _vNodes[currentNode].GetBounds(); + clientEx._sphere = clientEx._bounds.GetSphere(); } - if (MustBind(currentNode, entityEx._bounds)) + if (MustBind(currentNode, clientEx._bounds)) { - _vNodes[currentNode].BindEntity(entityEx); + _vNodes[currentNode].BindClient(clientEx); return true; } else if (Node::HasChildren(currentNode, Utils::Cast32(_vNodes.size()))) @@ -161,25 +161,25 @@ bool Octree::BindEntity(RcEntity entity, bool forceRoot, int currentNode) VERUS_FOR(i, 8) { const int childIndex = Node::GetChildIndex(currentNode, i); - if (BindEntity(entity, false, childIndex)) + if (BindClient(client, false, childIndex)) return true; } } return false; } -void Octree::UnbindEntity(void* pToken) +void Octree::UnbindClient(void* pToken) { for (auto& node : _vNodes) - node.UnbindEntity(pToken); + node.UnbindClient(pToken); } -void Octree::UpdateDynamicBounds(RcEntity entity) +void Octree::UpdateDynamicBounds(RcClient client) { if (_vNodes.empty()) return; // Octree is not ready. - _vNodes[0].UpdateDynamicEntity(entity); + _vNodes[0].UpdateDynamicClient(client); } bool Octree::MustBind(int currentNode, RcBounds bounds) const @@ -200,13 +200,16 @@ bool Octree::MustBind(int currentNode, RcBounds bounds) const return _vNodes[currentNode].GetBounds().IsOverlappingWith(bounds); } -Continue Octree::TraverseProper(RcFrustum frustum, PResult pResult, int currentNode, void* pUser) +Continue Octree::TraverseVisible(RcFrustum frustum, PResult pResult, int currentNode, void* pUser) { if (_vNodes.empty()) return Continue::no; if (!currentNode) { + _defaultResult = Result(); + if (!pResult) + pResult = &_defaultResult; pResult->_testCount = 0; pResult->_passedTestCount = 0; pResult->_pLastFoundToken = nullptr; @@ -225,22 +228,22 @@ Continue Octree::TraverseProper(RcFrustum frustum, PResult pResult, int currentN { { RcNode node = _vNodes[currentNode]; - const int count = node.GetEntityCount(); + const int count = node.GetClientCount(); VERUS_FOR(i, count) { - RcEntity entity = node.GetEntityAt(i); + RcClient client = node.GetClientAt(i); pResult->_testCount++; const float onePixel = Math::ComputeOnePixelDistance( - entity._sphere.GetRadius()); + client._sphere.GetRadius()); const bool notTooSmall = pResult->_depth || VMath::distSqr( - frustum.GetEyePosition(), entity._sphere.GetCenter()) < onePixel * onePixel; + frustum.GetEyePosition(), client._sphere.GetCenter()) < onePixel * onePixel; if (notTooSmall && - Relation::outside != frustum.ContainsSphere(entity._sphere) && - Relation::outside != frustum.ContainsAabb(entity._bounds)) + Relation::outside != frustum.ContainsSphere(client._sphere) && + Relation::outside != frustum.ContainsAabb(client._bounds)) { - pResult->_pLastFoundToken = entity._pToken; + pResult->_pLastFoundToken = client._pToken; pResult->_passedTestCount++; if (Continue::no == _pDelegate->Octree_ProcessNode(pResult->_pLastFoundToken, pUser)) return Continue::no; @@ -253,7 +256,7 @@ Continue Octree::TraverseProper(RcFrustum frustum, PResult pResult, int currentN VERUS_FOR(i, 8) { const int childIndex = Node::GetChildIndex(currentNode, i); - if (Continue::no == TraverseProper(frustum, pResult, childIndex, pUser)) + if (Continue::no == TraverseVisible(frustum, pResult, childIndex, pUser)) return Continue::no; } } @@ -261,13 +264,16 @@ Continue Octree::TraverseProper(RcFrustum frustum, PResult pResult, int currentN return Continue::yes; } -Continue Octree::TraverseProper(RcPoint3 point, PResult pResult, int currentNode, void* pUser) +Continue Octree::TraverseVisible(RcPoint3 point, PResult pResult, int currentNode, void* pUser) { if (_vNodes.empty()) return Continue::no; if (!currentNode) { + _defaultResult = Result(); + if (!pResult) + pResult = &_defaultResult; pResult->_testCount = 0; pResult->_passedTestCount = 0; pResult->_pLastFoundToken = nullptr; @@ -278,14 +284,14 @@ Continue Octree::TraverseProper(RcPoint3 point, PResult pResult, int currentNode { { RcNode node = _vNodes[currentNode]; - const int count = node.GetEntityCount(); + const int count = node.GetClientCount(); VERUS_FOR(i, count) { - RcEntity entity = node.GetEntityAt(i); + RcClient client = node.GetClientAt(i); pResult->_testCount++; - if (entity._bounds.IsInside(point)) + if (client._bounds.IsInside(point)) { - pResult->_pLastFoundToken = entity._pToken; + pResult->_pLastFoundToken = client._pToken; pResult->_passedTestCount++; if (Continue::no == _pDelegate->Octree_ProcessNode(pResult->_pLastFoundToken, pUser)) return Continue::no; @@ -300,7 +306,7 @@ Continue Octree::TraverseProper(RcPoint3 point, PResult pResult, int currentNode VERUS_FOR(i, 8) { const int childIndex = Node::GetChildIndex(currentNode, remapped[i]); - if (Continue::no == TraverseProper(point, pResult, childIndex, pUser)) + if (Continue::no == TraverseVisible(point, pResult, childIndex, pUser)) return Continue::no; } } diff --git a/Verus/src/Math/Octree.h b/Verus/src/Math/Octree.h index ac6ef75..175b34f 100644 --- a/Verus/src/Math/Octree.h +++ b/Verus/src/Math/Octree.h @@ -14,28 +14,38 @@ namespace verus class Octree : public Object { public: - class Entity + class Client { public: Bounds _bounds; Sphere _sphere; void* _pToken = nullptr; - Entity() {} - Entity(RcBounds bounds, void* pToken) : + Client() {} + Client(RcBounds bounds, void* pToken) : _bounds(bounds), _pToken(pToken) { _sphere = _bounds.GetSphere(); } }; - VERUS_TYPEDEFS(Entity); + VERUS_TYPEDEFS(Client); + + class Result + { + public: + void* _pLastFoundToken = nullptr; + int _testCount = 0; + int _passedTestCount = 0; + bool _depth = false; + }; + VERUS_TYPEDEFS(Result); private: class Node : public AllocatorAware { Bounds _bounds; Sphere _sphere; - Vector _vEntities; + Vector _vClients; public: Node(); @@ -48,12 +58,12 @@ namespace verus RcBounds GetBounds() const { return _bounds; } void SetBounds(RcBounds b) { _bounds = b; _sphere = b.GetSphere(); } - void BindEntity(RcEntity entity); - void UnbindEntity(void* pToken); - void UpdateDynamicEntity(RcEntity entity); + void BindClient(RcClient client); + void UnbindClient(void* pToken); + void UpdateDynamicClient(RcClient client); - int GetEntityCount() const { return Utils::Cast32(_vEntities.size()); } - RcEntity GetEntityAt(int i) const { return _vEntities[i]; } + int GetClientCount() const { return Utils::Cast32(_vClients.size()); } + RcClient GetClientAt(int i) const { return _vClients[i]; } }; VERUS_TYPEDEFS(Node); @@ -61,18 +71,9 @@ namespace verus Vector3 _limit = Vector3(0); Vector _vNodes; POctreeDelegate _pDelegate = nullptr; + Result _defaultResult; public: - class Result - { - public: - void* _pLastFoundToken = nullptr; - int _testCount = 0; - int _passedTestCount = 0; - bool _depth = false; - }; - VERUS_TYPEDEFS(Result); - Octree(); ~Octree(); @@ -83,13 +84,13 @@ namespace verus VERUS_P(void Build(int currentNode = 0, int depth = 0)); - bool BindEntity(RcEntity entity, bool forceRoot = false, int currentNode = 0); - void UnbindEntity(void* pToken); - void UpdateDynamicBounds(RcEntity entity); + bool BindClient(RcClient client, bool forceRoot = false, int currentNode = 0); + void UnbindClient(void* pToken); + void UpdateDynamicBounds(RcClient client); VERUS_P(bool MustBind(int currentNode, RcBounds bounds) const); - Continue TraverseProper(RcFrustum frustum, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr); - Continue TraverseProper(RcPoint3 point, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr); + Continue TraverseVisible(RcFrustum frustum, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr); + Continue TraverseVisible(RcPoint3 point, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr); VERUS_P(static void RemapChildIndices(RcPoint3 point, RcPoint3 center, BYTE childIndices[8])); diff --git a/Verus/src/Math/Quadtree.cpp b/Verus/src/Math/Quadtree.cpp index 06a9b59..9aa6bdb 100644 --- a/Verus/src/Math/Quadtree.cpp +++ b/Verus/src/Math/Quadtree.cpp @@ -15,17 +15,17 @@ Quadtree::Node::~Node() { } -void Quadtree::Node::BindEntity(RcEntity entity) +void Quadtree::Node::BindClient(RcClient client) { - _vEntities.push_back(entity); + _vClients.push_back(client); } -void Quadtree::Node::UnbindEntity(int index) +void Quadtree::Node::UnbindClient(int index) { - VERUS_WHILE(Vector, _vEntities, it) + VERUS_WHILE(Vector, _vClients, it) { if (index == (*it)._userIndex) - it = _vEntities.erase(it); + it = _vClients.erase(it); else it++; } @@ -110,22 +110,22 @@ void Quadtree::Build(int currentNode, int level) } } -bool Quadtree::BindEntity(RcEntity entity, bool forceRoot, int currentNode) +bool Quadtree::BindClient(RcClient client, bool forceRoot, int currentNode) { if (!currentNode) { if (_vNodes.empty()) return false; // Quadtree is not ready. - UnbindEntity(entity._userIndex); + UnbindClient(client._userIndex); } - Entity entityEx = entity; + Client clientEx = client; if (forceRoot) - entityEx._bounds = _vNodes[currentNode].GetBounds(); + clientEx._bounds = _vNodes[currentNode].GetBounds(); - if (MustBind(currentNode, entityEx._bounds)) + if (MustBind(currentNode, clientEx._bounds)) { - _vNodes[currentNode].BindEntity(entityEx); + _vNodes[currentNode].BindClient(clientEx); return true; } else @@ -135,7 +135,7 @@ bool Quadtree::BindEntity(RcEntity entity, bool forceRoot, int currentNode) const int index = _vNodes[currentNode].GetChildIndex(i); if (index >= 0) { - if (BindEntity(entity, false, index)) + if (BindClient(client, false, index)) return true; } } @@ -143,10 +143,10 @@ bool Quadtree::BindEntity(RcEntity entity, bool forceRoot, int currentNode) return false; } -void Quadtree::UnbindEntity(int index) +void Quadtree::UnbindClient(int index) { VERUS_FOREACH(Vector, _vNodes, it) - (*it).UnbindEntity(index); + (*it).UnbindClient(index); } bool Quadtree::MustBind(int currentNode, RcBounds bounds) const @@ -168,7 +168,7 @@ bool Quadtree::MustBind(int currentNode, RcBounds bounds) const return false; } -Continue Quadtree::TraverseProper(RcPoint3 point, PResult pResult, int currentNode, void* pUser) const +Continue Quadtree::TraverseVisible(RcPoint3 point, PResult pResult, int currentNode, void* pUser) const { if (_vNodes.empty()) return Continue::no; @@ -186,14 +186,14 @@ Continue Quadtree::TraverseProper(RcPoint3 point, PResult pResult, int currentNo { { RcNode node = _vNodes[currentNode]; - const int count = node.GetEntityCount(); + const int count = node.GetClientCount(); VERUS_FOR(i, count) { - RcEntity entity = node.GetEntityAt(i); + RcClient client = node.GetClientAt(i); pResult->_testCount++; - if (entity._bounds.IsInside2D(point)) + if (client._bounds.IsInside2D(point)) { - pResult->_lastFoundIndex = entity._userIndex; + pResult->_lastFoundIndex = client._userIndex; pResult->_passedTestCount++; if (Continue::no == _pDelegate->Quadtree_ProcessNode(pResult->_lastFoundIndex, pUser)) return Continue::no; @@ -208,7 +208,7 @@ Continue Quadtree::TraverseProper(RcPoint3 point, PResult pResult, int currentNo const int index = _vNodes[currentNode].GetChildIndex(childIndices[i]); if (index >= 0) { - if (Continue::no == TraverseProper(point, pResult, index, pUser)) + if (Continue::no == TraverseVisible(point, pResult, index, pUser)) return Continue::no; } } diff --git a/Verus/src/Math/Quadtree.h b/Verus/src/Math/Quadtree.h index da989c9..fc42e8a 100644 --- a/Verus/src/Math/Quadtree.h +++ b/Verus/src/Math/Quadtree.h @@ -14,23 +14,23 @@ namespace verus class Quadtree : public Object { public: - class Entity + class Client { public: Bounds _bounds; int _userIndex; - Entity() {} - Entity(RcBounds bounds, int index) : + Client() {} + Client(RcBounds bounds, int index) : _bounds(bounds), _userIndex(index) {} }; - VERUS_TYPEDEFS(Entity); + VERUS_TYPEDEFS(Client); private: class Node : public AllocatorAware { Bounds _bounds; - Vector _vEntities; + Vector _vClients; int _children[4]; public: @@ -43,11 +43,11 @@ namespace verus int GetChildIndex(int child) const { return _children[child]; } void SetChildIndex(int child, int index) { _children[child] = index; } - void BindEntity(RcEntity entity); - void UnbindEntity(int index); + void BindClient(RcClient client); + void UnbindClient(int index); - int GetEntityCount() const { return Utils::Cast32(_vEntities.size()); } - RcEntity GetEntityAt(int i) const { return _vEntities[i]; } + int GetClientCount() const { return Utils::Cast32(_vClients.size()); } + RcClient GetClientAt(int i) const { return _vClients[i]; } }; VERUS_TYPEDEFS(Node); @@ -77,11 +77,11 @@ namespace verus VERUS_P(void Build(int currentNode = 0, int level = 0)); - bool BindEntity(RcEntity entity, bool forceRoot = false, int currentNode = 0); - void UnbindEntity(int index); + bool BindClient(RcClient client, bool forceRoot = false, int currentNode = 0); + void UnbindClient(int index); VERUS_P(bool MustBind(int currentNode, RcBounds bounds) const); - Continue TraverseProper(RcPoint3 point, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr) const; + Continue TraverseVisible(RcPoint3 point, PResult pResult = nullptr, int currentNode = 0, void* pUser = nullptr) const; VERUS_P(static void ChildIndices(RcPoint3 point, RcPoint3 center, BYTE childIndices[4])); diff --git a/Verus/src/Physics/Bullet.cpp b/Verus/src/Physics/Bullet.cpp index e791e10..5cff027 100644 --- a/Verus/src/Physics/Bullet.cpp +++ b/Verus/src/Physics/Bullet.cpp @@ -46,41 +46,12 @@ void Bullet::Done() { DeleteAllCollisionObjects(); - if (_pStaticPlaneShape) - { - delete _pStaticPlaneShape; - _pStaticPlaneShape = nullptr; - } - - if (_pDiscreteDynamicsWorld) - { - delete _pDiscreteDynamicsWorld; - _pDiscreteDynamicsWorld = nullptr; - } - - if (_pConstraintSolver) - { - delete _pConstraintSolver; - _pConstraintSolver = nullptr; - } - - if (_pBroadphaseInterface) - { - delete _pBroadphaseInterface; - _pBroadphaseInterface = nullptr; - } - - if (_pDispatcher) - { - delete _pDispatcher; - _pDispatcher = nullptr; - } - - if (_pCollisionConfiguration) - { - delete _pCollisionConfiguration; - _pCollisionConfiguration = nullptr; - } + VERUS_SMART_DELETE(_pStaticPlaneShape); + VERUS_SMART_DELETE(_pDiscreteDynamicsWorld); + VERUS_SMART_DELETE(_pConstraintSolver); + VERUS_SMART_DELETE(_pBroadphaseInterface); + VERUS_SMART_DELETE(_pDispatcher); + VERUS_SMART_DELETE(_pCollisionConfiguration); VERUS_DONE(Bullet); } diff --git a/Verus/src/Scene/Atmosphere.cpp b/Verus/src/Scene/Atmosphere.cpp index b9e01b5..21c03b8 100644 --- a/Verus/src/Scene/Atmosphere.cpp +++ b/Verus/src/Scene/Atmosphere.cpp @@ -43,6 +43,7 @@ void Atmosphere::Init() _shadowMap.Init(4096); renderer.GetDS().InitByAtmosphere(_shadowMap.GetTexture()); + Effects::Bloom::I().InitByAtmosphere(_shadowMap.GetTexture()); CreateCelestialBodyMesh(); @@ -79,7 +80,7 @@ void Atmosphere::Init() _clouds._phaseB.setX(utils.GetRandom().NextFloat()); _clouds._phaseB.setY(utils.GetRandom().NextFloat()); - _fog._density[0] = _fog._density[1] = 0.0006f; + _fog._density[0] = _fog._density[1] = 0.001f; _sun._matTilt = Matrix3::rotationX(_sun._latitude); UpdateSun(_time); @@ -215,9 +216,9 @@ void Atmosphere::Update() const float cloudScaleFog = 1 - 0.9f * _clouds._cloudiness * cloudinessSq; const float cloudScaleSun = 1 - 0.999f * _clouds._cloudiness * cloudinessSq; float color[3]; - GetColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(68000, 45000, 10) * cloudScaleAmb); - GetColor(110, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(75000, 8000, 1) * cloudScaleFog); - GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(85000, 30000, 1) * cloudScaleSun); + GetColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(60000, 40000, 10) * cloudScaleAmb); + GetColor(100, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(30000, 2000, 1) * cloudScaleFog); + GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(85000, 20000, 1) * cloudScaleSun); glm::vec3 ambientColor = _ambientColor.GLM(); glm::vec3 fogColor = _fog._color.GLM(); @@ -231,7 +232,7 @@ void Atmosphere::Update() const glm::vec3 grayAmbient = glm::saturation(0.f, _ambientColor.GLM()); const glm::vec3 grayFog = glm::saturation(0.f, _fog._color.GLM()); const glm::vec3 graySun = glm::saturation(0.f, _sun._color.GLM()); - VERUS_RT_ASSERT(glm::epsilonEqual(grayAmbient.x, 6400.f, 640.f)); + VERUS_RT_ASSERT(glm::epsilonEqual(grayAmbient.x, 6000.f, 640.f)); VERUS_RT_ASSERT(glm::epsilonEqual(graySun.x, 32000.f, 3200.f)); } #endif @@ -255,12 +256,12 @@ void Atmosphere::DrawSky(bool reflection) if (water.IsUnderwater()) reflection = false; - 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())); + auto cb = renderer.GetCommandBuffer(); + s_ubPerFrame._time_cloudiness.x = _time; s_ubPerFrame._time_cloudiness.y = _clouds._cloudiness; s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), 0); @@ -278,16 +279,14 @@ void Atmosphere::DrawSky(bool reflection) // s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat(); - _skyDome.BindGeo(cb); cb->BindPipeline(_pipe[reflection ? PIPE_SKY_REFLECTION : PIPE_SKY]); - + _skyDome.BindGeo(cb); _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()); // @@ -301,16 +300,14 @@ void Atmosphere::DrawSky(bool reflection) s_ubPerObject._matW = matW.UniformBufferFormat(); s_ubPerObject._matWVP = Matrix4(cam.GetMatrixVP() * matW).UniformBufferFormat(); - cb->BindVertexBuffers(_geo); cb->BindPipeline(_pipe[PIPE_SUN]); - + cb->BindVertexBuffers(_geo); _shader->BeginBindDescriptors(); cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _cshSunFS); cb->BindDescriptors(_shader, 2); cb->BindDescriptors(_shader, 3); _shader->EndBindDescriptors(); - cb->Draw(4, 1); } // @@ -322,32 +319,28 @@ void Atmosphere::DrawSky(bool reflection) s_ubPerObject._matW = matW.UniformBufferFormat(); s_ubPerObject._matWVP = Matrix4(cam.GetMatrixVP() * matW).UniformBufferFormat(); - cb->BindVertexBuffers(_geo); cb->BindPipeline(_pipe[PIPE_MOON]); - + cb->BindVertexBuffers(_geo); _shader->BeginBindDescriptors(); cb->BindDescriptors(_shader, 0); cb->BindDescriptors(_shader, 1, _cshMoonFS); cb->BindDescriptors(_shader, 2); cb->BindDescriptors(_shader, 3); _shader->EndBindDescriptors(); - cb->Draw(4, 1); } // // s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat(); - _skyDome.BindGeo(cb); cb->BindPipeline(_pipe[reflection ? PIPE_CLOUDS_REFLECTION : PIPE_CLOUDS]); - + _skyDome.BindGeo(cb); _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()); // } diff --git a/Verus/src/Scene/BaseMesh.cpp b/Verus/src/Scene/BaseMesh.cpp index 1ebc4e3..a5aca16 100644 --- a/Verus/src/Scene/BaseMesh.cpp +++ b/Verus/src/Scene/BaseMesh.cpp @@ -29,6 +29,7 @@ void BaseMesh::Init(CSZ url) void BaseMesh::Done() { IO::Async::Cancel(this); + DoneShape(); VERUS_DONE(BaseMesh); } @@ -303,6 +304,9 @@ void BaseMesh::LoadX3D3(RcBlob blob) ComputeTangentSpace(); } + if (_initShape) + InitShape(Transform3::identity()); + CreateDeviceBuffers(); } @@ -477,6 +481,83 @@ void BaseMesh::ComputeTangentSpace() } } +btBvhTriangleMeshShape* BaseMesh::InitShape(RcTransform3 tr, CSZ url) +{ + if (!_vertCount) + return nullptr; + + DoneShape(); + + String finalUrl = url ? url : _url; + String cacheFilename; + if (!finalUrl.empty()) + { + String filename = Str::ToPakFriendlyUrl(_C(finalUrl)); + if (url) + filename += ".INST"; + filename = "[Models]:PhyCache/" + filename + ".bullet"; + cacheFilename = IO::FileSystem::ConvertRelativePathToAbsolute(filename, true); + if (IO::FileSystem::FileExist(_C(filename))) + { + Vector vMesh; + IO::FileSystem::LoadResource(_C(filename), vMesh); + + btBulletWorldImporter bwi(0); + if (!vMesh.empty() && bwi.loadFileFromMemory(reinterpret_cast(vMesh.data()), Utils::Cast32(vMesh.size()))) + { + const int count = bwi.getNumCollisionShapes(); + if (count) + _pShape = static_cast(bwi.getCollisionShapeByIndex(0)); + } + + return _pShape; + } + } + + btTriangleMesh* pTriangleMesh = new btTriangleMesh(_vIndices.empty()); + pTriangleMesh->preallocateVertices(_vertCount); + pTriangleMesh->preallocateIndices(_indexCount); + VERUS_FOR(i, _vertCount) + { + Point3 pos; + DequantizeUsingDeq3D(_vBinding0[i]._pos, _posDeq, pos); + pos = tr * pos; + pTriangleMesh->findOrAddVertex(pos.Bullet(), false); + } + VERUS_FOR(i, _faceCount) + { + const int i0 = _vIndices.empty() ? _vIndices32[i * 3 + 0] : _vIndices[i * 3 + 0]; + const int i1 = _vIndices.empty() ? _vIndices32[i * 3 + 1] : _vIndices[i * 3 + 1]; + const int i2 = _vIndices.empty() ? _vIndices32[i * 3 + 2] : _vIndices[i * 3 + 2]; + pTriangleMesh->addTriangleIndices(i0, i1, i2); + } + + _pShape = new btBvhTriangleMeshShape(pTriangleMesh, true); + + if (!cacheFilename.empty()) + { + btDefaultSerializer s; + s.startSerialization(); + _pShape->serializeSingleShape(&s); + s.finishSerialization(); + IO::File file; + if (file.Open(_C(cacheFilename), "wb")) + file.Write(s.getBufferPointer(), s.getCurrentBufferSize()); + } + + return _pShape; +} + +void BaseMesh::DoneShape() +{ + if (_pShape) + { + delete _pShape->getMeshInterface(); + delete _pShape; + _pShape = nullptr; + } +} + void BaseMesh::GetBounds(RPoint3 mn, RPoint3 mx) const { const short smin[] = { -SHRT_MAX, -SHRT_MAX, -SHRT_MAX }; diff --git a/Verus/src/Scene/BaseMesh.h b/Verus/src/Scene/BaseMesh.h index 29756b6..2050a93 100644 --- a/Verus/src/Scene/BaseMesh.h +++ b/Verus/src/Scene/BaseMesh.h @@ -42,6 +42,7 @@ namespace verus Anim::Warp _warp; String _warpUrl; String _url; + btBvhTriangleMeshShape* _pShape = nullptr; int _vertCount = 0; int _faceCount = 0; int _indexCount = 0; @@ -51,6 +52,7 @@ namespace verus float _tc1Deq[4]; bool _loadOnly = false; bool _rigidSkeleton = false; + bool _initShape = false; public: BaseMesh(); @@ -98,6 +100,11 @@ namespace verus virtual void CreateDeviceBuffers() {} virtual void UpdateVertexBuffer(const void* p, int binding) {} + // Physics: + btBvhTriangleMeshShape* GetShape() const { return _pShape; } + btBvhTriangleMeshShape* InitShape(RcTransform3 tr, CSZ url = nullptr); + void DoneShape(); + // Bounds: void GetBounds(RPoint3 mn, RPoint3 mx) const; Math::Bounds GetBounds() const; diff --git a/Verus/src/Scene/Forest.cpp b/Verus/src/Scene/Forest.cpp index 3e010c6..27470ab 100644 --- a/Verus/src/Scene/Forest.cpp +++ b/Verus/src/Scene/Forest.cpp @@ -3,9 +3,9 @@ using namespace verus; using namespace verus::Scene; -CGI::ShaderPwn Forest::s_shader; -//CGI::CStateBlockPwns Forest::ms_sb; -//Forest::CB_PerFrame Forest::ms_cbPerFrame; +CGI::ShaderPwn Forest::s_shader; +Forest::UB_ForestVS Forest::s_ubForestVS; +Forest::UB_ForestFS Forest::s_ubForestFS; // Forest::Plant: @@ -28,38 +28,20 @@ Forest::~Forest() void Forest::InitStatic() { - //VERUS_OUTPUT_DEBUG_STRING(__FUNCTION__); - // - //CGI::CShaderDesc sd; - //sd._url = "Shaders:DS_Forest.cg"; - //s_shader.Init(sd); - //s_shader->BindBufferSource(&ms_cbPerFrame, sizeof(ms_cbPerFrame), 0, "PerFrame"); - // - //CGI::CStateBlockDesc sbd; - //sbd.B(); - //sbd.R(); - //sbd.Z().depthEnable = true; - //sbd.Z().depthWriteEnable = true; - //sbd.S(0).Set("a", "ww"); - //sbd.S(1).Set("a", "ww"); - //sbd.S(2).Set("a", "ww"); - //ms_sb[SB_MASTER].Init(sbd); - // - //sbd.Reset(); - //sbd.B().rtWriteMasks[0] = CShadowMap::GetWriteMask(); - //sbd.R().depthBias = CShadowMap::GetDepthBias() * 48; - //sbd.R().slopeScaledDepthBias = CShadowMap::GetSlopeScaledDepthBias(); - //sbd.Z().depthEnable = true; - //sbd.Z().depthWriteEnable = true; - //sbd.S(0).Set("a", "ww"); - //ms_sb[SB_DEPTH].Init(sbd); + s_shader.Init("[Shaders]:DS_Forest.hlsl"); + s_shader->CreateDescriptorSet(0, &s_ubForestVS, sizeof(s_ubForestVS), 100, {}, CGI::ShaderStageFlags::vs_hs_ds_fs); + s_shader->CreateDescriptorSet(1, &s_ubForestFS, sizeof(s_ubForestFS), 100, + { + CGI::Sampler::aniso, + CGI::Sampler::aniso, + CGI::Sampler::aniso + }, CGI::ShaderStageFlags::fs); + s_shader->CreatePipelineLayout(); } void Forest::DoneStatic() { - //VERUS_OUTPUT_DEBUG_STRING(__FUNCTION__); - //ms_sb.Done(); - //s_shader.Done(); + s_shader.Done(); } void Forest::Init(PTerrain pTerrain) @@ -92,6 +74,7 @@ void Forest::Init(PTerrain pTerrain) _scatter.SetDelegate(this); _vPlants.reserve(16); + _vLayerPlants.reserve(16); _vDrawPlants.resize(_capacity); } @@ -120,6 +103,7 @@ void Forest::Update() Mesh::Desc meshDesc; meshDesc._url = _C(plant._url); meshDesc._instanceCapacity = _capacity; + meshDesc._initShape = true; plant._mesh.Init(meshDesc); Material::Desc matDesc; @@ -132,6 +116,7 @@ void Forest::Update() for (auto& plant : _vPlants) { plant._material->IncludePart(0); + if (!plant._maxSize && plant._mesh.IsLoaded()) { // Time to get the size of this mesh. @@ -142,10 +127,29 @@ void Forest::Update() _maxSizeAll = plant._maxSize; _pTerrain->FattenQuadtreeNodesBy(_maxSizeAll); } + plant._aoSize = plant._mesh.GetBounds().GetAverageSize() * 1.7f; + } + + if (!plant._tex[0] && plant._mesh.IsLoaded() && plant._material->IsLoaded()) + LoadSprite(plant); + + if (!plant._csh.IsSet()) + { + if (plant._tex[Plant::TEX_GBUFFER_0] && plant._tex[Plant::TEX_GBUFFER_0]->IsLoaded() && + plant._tex[Plant::TEX_GBUFFER_1] && plant._tex[Plant::TEX_GBUFFER_1]->IsLoaded() && + plant._tex[Plant::TEX_GBUFFER_2] && plant._tex[Plant::TEX_GBUFFER_2]->IsLoaded()) + { + plant._csh = s_shader->BindDescriptorSetTextures(1, + { + plant._tex[Plant::TEX_GBUFFER_0], + plant._tex[Plant::TEX_GBUFFER_1], + plant._tex[Plant::TEX_GBUFFER_2] + }); + } } } - if (false && !_geo) + if (!_geo) { bool allLoaded = !_vPlants.empty(); for (auto& plant : _vPlants) @@ -164,7 +168,7 @@ void Forest::Update() for (auto& bc : plant._vBakedChunks) { bc._vbOffset = vertCount; - vertCount += bc._vSprites.size(); + vertCount += Utils::Cast32(bc._vSprites.size()); } } Vector vVB; @@ -178,26 +182,45 @@ void Forest::Update() for (auto& s : bc._vSprites) bounds.Include(s._pos); bounds.FattenBy(plant.GetSize()); - _octree.BindEntity(Math::Octree::Entity(bounds, &bc)); + _octree.BindClient(Math::Octree::Client(bounds, &bc)); if (!bc._vSprites.empty()) memcpy(&vVB[vertCount], bc._vSprites.data(), bc._vSprites.size() * sizeof(Vertex)); - vertCount += bc._vSprites.size(); + vertCount += Utils::Cast32(bc._vSprites.size()); } } - //CGI::CVertexElement ve[] = - //{ - // {0, offsetof(Vertex, _pos), /**/CGI::VeType::_float, 3, CGI::VeUsage::position, 0}, - // {0, offsetof(Vertex, _tc), /**/CGI::VeType::_short, 2, CGI::VeUsage::texCoord, 0}, - // VERUS_END_DECL - //}; - //CGI::GeometryDesc gd; - //gd._pVertDecl = ve; - //gd._pShader = &(*s_shader); - //_geo.Init(gd); - //_geo->DefineVertexStream(0, sizeof(Vertex), vertCount * sizeof(Vertex)); - //_geo->BufferDataVB(vVB.data()); + CGI::GeometryDesc geoDesc; + const CGI::VertexInputAttrDesc viaDesc[] = + { + {0, offsetof(Vertex, _pos), CGI::ViaType::floats, 3, CGI::ViaUsage::position, 0}, + {0, offsetof(Vertex, _tc), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 0}, + CGI::VertexInputAttrDesc::End() + }; + geoDesc._pVertexInputAttrDesc = viaDesc; + const int strides[] = { sizeof(Vertex), 0 }; + geoDesc._pStrides = strides; + _geo.Init(geoDesc); + _geo->CreateVertexBuffer(vertCount, 0); + _geo->UpdateVertexBuffer(vVB.data(), 0); + + VERUS_QREF_RENDERER; + VERUS_QREF_ATMO; + + { + 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._topology = CGI::PrimitiveTopology::pointList; + _pipe[PIPE_MAIN].Init(pipeDesc); + } + { + CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Depth", atmo.GetShadowMap().GetRenderPassHandle()); + pipeDesc._colorAttachBlendEqs[0] = ""; + pipeDesc._topology = CGI::PrimitiveTopology::pointList; + _pipe[PIPE_DEPTH].Init(pipeDesc); + } } } } @@ -215,120 +238,140 @@ void Forest::Layout() for (auto& bc : plant._vBakedChunks) bc._visible = false; - const float zFarWas = sm.GetCamera()->GetZFar(); - if (Atmosphere::I().GetShadowMap().IsRendering()) { - const int csmSplit = Atmosphere::I().GetShadowMap().GetCurrentSplit(); - if (!csmSplit) - return; - } - else - sm.GetCamera()->SetFrustumFar(_maxDist); + const float zFarWas = sm.GetCamera()->GetZFar(); - Math::RQuadtreeIntegral qt = _pTerrain->GetQuadtree(); - qt.SetDelegate(&_scatter); - qt.TraverseVisible(); - qt.SetDelegate(_pTerrain); - sm.GetCamera()->SetFrustumFar(zFarWas); - - const Point3 eyePos = sm.GetCamera()->GetEyePosition(); - std::sort(_vDrawPlants.begin(), _vDrawPlants.begin() + _visibleCount, [&eyePos](RcDrawPlant plantA, RcDrawPlant plantB) + const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(DrawDepth::automatic); + if (drawingDepth) { + const int csmSplit = Atmosphere::I().GetShadowMap().GetCurrentSplit(); + if (!csmSplit) + return; + } + else + sm.GetCamera()->SetFrustumFar(_maxDist); + + Math::RQuadtreeIntegral qt = _pTerrain->GetQuadtree(); + qt.SetDelegate(&_scatter); + qt.TraverseVisible(); + qt.SetDelegate(_pTerrain); + + if (drawingDepth) + _octree.TraverseVisible(sm.GetCamera()->GetFrustum()); + sm.GetCamera()->SetFrustumFar(_maxDist * 8); + if (!drawingDepth) + _octree.TraverseVisible(sm.GetCamera()->GetFrustum()); + + sm.GetCamera()->SetFrustumFar(zFarWas); + } + + const float tessDistSq = _tessDist * _tessDist; + std::sort(_vDrawPlants.begin(), _vDrawPlants.begin() + _visibleCount, [tessDistSq](RDrawPlant plantA, RDrawPlant plantB) + { + const bool tessA = plantA._distToEyeSq < tessDistSq; + const bool tessB = plantB._distToEyeSq < tessDistSq; + if (tessA != tessB) + return tessA; if (plantA._plantIndex != plantB._plantIndex) return plantA._plantIndex < plantB._plantIndex; - const float distA = VMath::distSqr(eyePos, plantA._pos); - const float distB = VMath::distSqr(eyePos, plantB._pos); - return distA < distB; + return plantA._distToEyeSq < plantB._distToEyeSq; }); } -void Forest::Draw() +void Forest::Draw(bool allowTess) { if (!IsInitialized()) return; VERUS_UPDATE_ONCE_CHECK_DRAW; - //for (auto& plant : _vPlants) - //{ - // if (!plant._tex[0] && plant._mesh.IsLoaded() && plant._material->IsLoaded()) - // { - // if (!LoadSprite(plant)) - // BakeSprite(plant); - // } - //} - - DrawModels(); + DrawModels(allowTess); DrawSprites(); } -void Forest::DrawModels() +void Forest::DrawModels(bool allowTess) { if (!_visibleCount) return; VERUS_QREF_RENDERER; + VERUS_QREF_CONST_SETTINGS; PMesh pMesh = nullptr; MaterialPtr material; - bool bindPipeline = true; + int bindPipelineStage = -1; + bool tess = true; + const float tessDistSq = _tessDist * _tessDist; auto cb = renderer.GetCommandBuffer(); auto shader = Scene::Mesh::GetShader(); - // Draw all visible assets: + auto DrawMesh = [cb](PMesh pMesh) + { + if (pMesh && !pMesh->IsInstanceBufferEmpty(true)) + { + pMesh->UpdateInstanceBuffer(); + cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance()); + } + }; + shader->BeginBindDescriptors(); for (int i = 0; i <= _visibleCount; ++i) { if (i == _visibleCount) // The end? { - if (pMesh && !pMesh->IsInstanceBufferEmpty(true)) - { - pMesh->UpdateInstanceBuffer(); - cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance()); - } + DrawMesh(pMesh); break; } RcDrawPlant drawPlant = _vDrawPlants[i]; RPlant plant = _vPlants[drawPlant._plantIndex]; - PMesh pNewMesh = &plant._mesh; - MaterialPtr newMaterial = plant._material; + PMesh pNextMesh = &plant._mesh; + MaterialPtr nextMaterial = plant._material; + const bool nextTess = drawPlant._distToEyeSq < tessDistSq; - if (!pNewMesh->IsLoaded() || !newMaterial->IsLoaded()) + if (!pNextMesh->IsLoaded() || !nextMaterial->IsLoaded()) continue; - if (pNewMesh != pMesh) // New pMesh? + if (pNextMesh != pMesh || nextTess != tess) { - if (pMesh && !pMesh->IsInstanceBufferEmpty(true)) - { - pMesh->UpdateInstanceBuffer(); - cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance()); - } - pMesh = pNewMesh; - pMesh->MarkFirstInstance(); - if (bindPipeline) - { - bindPipeline = false; - pMesh->BindPipelineInstanced(cb, false); - } - pMesh->BindGeo(cb); + DrawMesh(pMesh); - pMesh->UpdateUniformBufferPerFrame(); - cb->BindDescriptors(shader, 0); + pMesh = pNextMesh; + pMesh->MarkFirstInstance(); + if (bindPipelineStage) + { + if (-1 == bindPipelineStage) + { + bindPipelineStage = (nextTess && allowTess && settings._gpuTessellation) ? 1 : 0; + pMesh->BindPipelineInstanced(cb, 1 == bindPipelineStage, true); + pMesh->UpdateUniformBufferPerFrame(1 / (_tessDist - 10)); + cb->BindDescriptors(shader, 0); + } + else if (1 == bindPipelineStage && !nextTess) + { + bindPipelineStage = 0; + pMesh->BindPipelineInstanced(cb, false, true); + pMesh->UpdateUniformBufferPerFrame(); + cb->BindDescriptors(shader, 0); + } + } + tess = nextTess; + pMesh->BindGeo(cb); pMesh->UpdateUniformBufferPerMeshVS(); cb->BindDescriptors(shader, 2); } - if (newMaterial != material) // Switch material? + if (nextMaterial != material) { - material = newMaterial; + material = nextMaterial; material->UpdateMeshUniformBuffer(); cb->BindDescriptors(shader, 1, material->GetComplexSetHandle()); } - if (pMesh) // Draw this pMesh: + + if (pMesh) { const Transform3 matW = VMath::appendScale(Transform3(drawPlant._basis * Matrix3::rotationY(drawPlant._angle), Vector3(drawPlant._pos + drawPlant._pushBack)), Vector3::Replicate(drawPlant._scale)); - pMesh->PushInstance(matW, Vector4::Replicate(1)); + pMesh->PushInstance(matW, Vector4(Vector3(drawPlant._pos), 1)); } } shader->EndBindDescriptors(); @@ -336,51 +379,104 @@ void Forest::DrawModels() void Forest::DrawSprites() { - //if (!_geo) - // return; - // - //VERUS_QREF_RENDER; - //VERUS_QREF_SM; - // - //const bool depth = Utils::IsDrawingDepth(DrawDepth::automatic); - // - //if (depth) - // ms_sb[SB_DEPTH]->Apply(); - //else - // ms_sb[SB_MASTER]->Apply(); - // - //ms_cbPerFrame.matP = sm.GetCamera()->GetMatrixP().ConstBufferFormat(); - //ms_cbPerFrame.matWVP = sm.GetCamera()->GetMatrixVP().ConstBufferFormat(); - //ms_cbPerFrame.viewportSize = render.GetViewportSize(); - //ms_cbPerFrame.eyePos = sm.GetCamera()->GetPositionEye(); - //ms_cbPerFrame.posEyeScreen = Atmosphere::I().GetEyePosition(); - // - //s_shader->Bind(depth ? "TDepth" : "T"); - //s_shader->UpdateBuffer(0); - // - //_geo->BeginDraw(0x1); - //for (auto& plant : _vPlants) - //{ - // if (depth) - // { - // render->SetTextures({ plant._tex[Plant::TEX_GBUFFER_0] }); - // } - // else - // { - // render->SetTextures( - // { - // plant._tex[Plant::TEX_GBUFFER_0], - // plant._tex[Plant::TEX_GBUFFER_2], - // plant._tex[Plant::TEX_GBUFFER_3] - // }); - // } - // for (auto& bc : plant._vBakedChunks) - // { - // if (bc._visible) - // render->DrawPrimitive(CGI::PT_POINTLIST, bc._vbOffset, bc._vSprites.size()); - // } - //} - //_geo->EndDraw(0x1); + if (!_geo) + return; + + VERUS_QREF_RENDERER; + VERUS_QREF_SM; + VERUS_QREF_ATMO; + + const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(DrawDepth::automatic); + + auto cb = renderer.GetCommandBuffer(); + + s_ubForestVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat(); + s_ubForestVS._matWVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); + s_ubForestVS._viewportSize = renderer.GetCommandBuffer()->GetViewportSize().GLM(); + s_ubForestVS._eyePos = float4(sm.GetCamera()->GetEyePosition().GLM(), 0); + s_ubForestVS._eyePosScreen = float4(atmo.GetEyePosition().GLM(), 0); + + cb->BindPipeline(_pipe[drawingDepth ? PIPE_DEPTH : PIPE_MAIN]); + cb->BindVertexBuffers(_geo); + s_shader->BeginBindDescriptors(); + cb->BindDescriptors(s_shader, 0); + for (auto& plant : _vPlants) + { + if (!plant._csh.IsSet()) + continue; + cb->BindDescriptors(s_shader, 1, plant._csh); + for (auto& bc : plant._vBakedChunks) + { + if (bc._visible) + cb->Draw(bc._vSprites.size(), 1, bc._vbOffset); + } + } + s_shader->EndBindDescriptors(); +} + +void Forest::DrawAO() +{ + if (!_visibleCount) + return; + + VERUS_QREF_RENDERER; + VERUS_QREF_HELPERS; + + CGI::LightType type = CGI::LightType::none; + PMesh pMesh = nullptr; + + auto& ds = renderer.GetDS(); + auto cb = renderer.GetCommandBuffer(); + + auto DrawMesh = [cb](PMesh pMesh) + { + if (pMesh && !pMesh->IsInstanceBufferEmpty(true)) + { + pMesh->UpdateInstanceBuffer(); + cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance()); + } + }; + + for (int i = 0; i <= _visibleCount; ++i) + { + if (i == _visibleCount) // The end? + { + DrawMesh(pMesh); + break; + } + + RcDrawPlant drawPlant = _vDrawPlants[i]; + RPlant plant = _vPlants[drawPlant._plantIndex]; + + const CGI::LightType nextType = CGI::LightType::omni; + + if (nextType != type) + { + DrawMesh(pMesh); + + type = nextType; + ds.OnNewAOType(cb, type); + + pMesh = (type != CGI::LightType::none) ? &helpers.GetDeferredLights().Get(type) : nullptr; + + if (pMesh) + { + pMesh->MarkFirstInstance(); + pMesh->BindGeo(cb, (1 << 0) | (1 << 4)); + pMesh->CopyPosDeqScale(&ds.GetUbAOPerMeshVS()._posDeqScale.x); + pMesh->CopyPosDeqBias(&ds.GetUbAOPerMeshVS()._posDeqBias.x); + ds.BindDescriptorsAOPerMeshVS(cb); + } + } + + if (pMesh) + { + const float size = drawPlant._scale * plant._aoSize; + const Transform3 matW = VMath::appendScale(Transform3(Matrix3::identity(), + Vector3(drawPlant._pos + drawPlant._pushBack + Vector3(0, size * 0.25f, 0))), Vector3::Replicate(size)); + pMesh->PushInstance(matW, Vector4::Replicate(1)); + } + } } void Forest::SetLayer(int layer, RcLayerDesc desc) @@ -402,18 +498,19 @@ void Forest::SetLayer(int layer, RcLayerDesc desc) } else // Add new plant? { - _vLayerPlants[layer]._plants[type] = _vPlants.size(); + _vLayerPlants[layer]._plants[type] = Utils::Cast32(_vPlants.size()); _vPlants.resize(_vPlants.size() + 1); RPlant plant = _vPlants[_vPlants.size() - 1]; plant._url = plantDesc._url; - plant._normal = plantDesc._normal; + plant._alignToNormal = plantDesc._alignToNormal; + plant._maxScale = plantDesc._maxScale; + plant._allowedNormal = plantDesc._allowedNormal; const float ds = plantDesc._maxScale - plantDesc._minScale; const int count = 64; plant._vScales.resize(count); VERUS_FOR(i, count) plant._vScales[i] = plantDesc._minScale + ds * (i * i * i) / (count * count * count); std::shuffle(plant._vScales.begin(), plant._vScales.end(), random.GetGenerator()); - plant._maxScale = plantDesc._maxScale; } } } @@ -450,7 +547,7 @@ void Forest::BakeChunks(RPlant plant) if (layer >= _vLayerPlants.size()) continue; - if (_pTerrain->GetNormalAt(ij)[1] < plant._normal) + if (_pTerrain->GetNormalAt(ij)[1] < plant._allowedNormal) continue; VERUS_FOR(type, SCATTER_TYPE_COUNT) @@ -480,8 +577,8 @@ void Forest::BakeChunks(RPlant plant) xOffset - half + instance._x, hMin - psize * 0.05f, zOffset - half + instance._z); - v._tc[0] = Math::Clamp(psize * 500, 0, SHRT_MAX); - v._tc[1] = Math::Clamp(instance._angle * SHRT_MAX / VERUS_2PI, 0, SHRT_MAX); + v._tc[0] = Math::Clamp(static_cast(psize * 500), 0, SHRT_MAX); + v._tc[1] = Math::Clamp(static_cast(instance._angle * SHRT_MAX / VERUS_2PI), 0, SHRT_MAX); v._pos.y += psize * 0.5f / _margin; if (!bc._vSprites.capacity()) bc._vSprites.reserve(256); @@ -506,119 +603,216 @@ void Forest::BakeChunks(RPlant plant) bool Forest::LoadSprite(RPlant plant) { int count = 0; - const CSZ ext2[] = { "", ".NM", ".FX" }; - VERUS_FOR(gb, 3) + const CSZ ext[] = { "", ".FX", ".FX" }; + VERUS_FOR(i, 3) { - const int gbIndices[3] = { 0, 2, 3 }; - const int gbIndex = gbIndices[gb]; + String pathname = _C(plant._mesh.GetUrl()); + char filename[20]; + sprintf_s(filename, "GB%d%s.dds", i, ext[i]); + Str::ReplaceFilename(pathname, filename); + pathname = Str::ToPakFriendlyUrl(_C(pathname)); + pathname = "[Textures]:Forest/" + pathname; - String path = _C(plant._mesh.GetUrl()); - char name[20]; - sprintf_s(name, "GB%d%s.dds", gbIndex, ext2[gb]); - Str::ReplaceFilename(path, name); - Str::ReplaceAll(path, ":", "-"); - Str::ReplaceAll(path, "/", "."); - - const String url = "Textures:Forest/" + path; - - if (IO::FileSystem::FileExist(_C(url))) + if (IO::FileSystem::FileExist(_C(pathname))) { count++; - CGI::TextureDesc td; - td._url = _C(url); - plant._tex[gb].Init(td); + plant._tex[i].Init(_C(pathname)); } } return 3 == count; } -void Forest::BakeSprite(RPlant plant) +void Forest::BakeSprite(RPlant plant, CSZ url) { - //#ifdef _DEBUG - // const bool depth = Utils::IsDrawingDepth(DrawDepth::automatic); - // if (depth) - // return; - // - // VERUS_QREF_RENDER; - // VERUS_QREF_SM; - // VERUS_RT_ASSERT(render.GetDS().IsActiveGeometryPass()); - // - // const int frameSide = 512; - // const int framePad = 16; - // const int numFramesH = 8; - // const int numFramesV = 4; - // const int texW = numFramesH * frameSide; - // const int texH = numFramesV * frameSide; - // const float stepH = VERUS_2PI / numFramesH; - // const float stepV = VERUS_PI / 2 / numFramesV; - // - // CGI::DeferredShading ds; - // ds.InitGBuffers(texW, texH, true, true); - // - // ds.BeginGeometryPass(false, true); - // VERUS_FOR(i, numFramesV) - // { - // const Matrix3 matV = Matrix3::rotationX(-stepV * i); - // VERUS_FOR(j, numFramesH) - // { - // int vp[4] = - // { - // j * frameSide + framePad, - // i * frameSide + framePad, - // frameSide - framePad * 2, - // frameSide - framePad * 2, - // }; - // render->SetViewport(vp); - // - // const float size = plant.GetSize(); - // const Matrix3 matH = Matrix3::rotationY(stepH * j); - // const Matrix3 matR = matH * matV; - // const Vector3 offset = matR * Vector3(0, 0, size); - // - // Camera cam; - // cam.MoveAtTo(Vector3(0, size * 0.5f / m_margin, 0)); - // cam.MoveEyeTo(Vector3(0, size * 0.5f / m_margin, 0) + offset); - // cam.SetFOV(0); - // cam.SetWidth(size * m_margin); - // cam.SetHeight(size * m_margin); - // cam.SetAspectRatio(1); - // cam.SetZNear(0); - // cam.SetZFar(size * 2); - // cam.Update(); - // PCamera pPrevCamera = sm.SetCamera(&cam); - // - // Mesh::CDrawDesc dd; - // dd._material = plant._material; - // dd._spriteBaking = true; - // plant._mesh.Draw(dd); - // - // sm.SetCamera(pPrevCamera); - // } - // } - // ds.EndGeometryPass(); - // - // Vector vData; - // vData.resize(texW * texH); - // VERUS_FOR(gb, 3) - // { - // const int gbIndices[3] = { 0, 2, 3 }; - // const int gbIndex = gbIndices[gb]; - // - // ds.GetGBuffer(gbIndex)->GetTexImage(reinterpret_cast(vData.data())); - // - // String path = _C(plant._mesh.GetUrl()); - // char name[20]; - // sprintf_s(name, "GB%d.psd", gbIndex); - // Str::ReplaceFilename(path, name); - // Str::ReplaceAll(path, ":", "-"); - // Str::ReplaceAll(path, "/", "."); - // path = "D:\\Stuff\\Gulman\\Data\\Textures\\Forest/" + path; - // IO::FileSystem::SaveImage(_C(path), vData.data(), texW, texH); - // } - // - // render.GetDS().BeginGeometryPass(true); - // VERUS_RT_ASSERT(false); - //#endif + const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(DrawDepth::automatic); + if (drawingDepth) + return; + + VERUS_QREF_RENDERER; + VERUS_QREF_SM; + + CGI::CommandBufferPtr cb; + cb.InitOneTimeSubmit(); + + const int frameSide = 512; + const int framePad = 16; + const int frameCountH = 16; + const int frameCountV = 16; + const int texWidth = frameCountH * frameSide; + const int texHeight = frameCountV * frameSide; + const float stepH = VERUS_2PI / frameCountH; + const float stepV = VERUS_PI / 2 / frameCountV; + + CGI::RPHandle rph = renderer->CreateRenderPass( + { + CGI::RP::Attachment("GBuffer0", CGI::Format::srgbR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly), + CGI::RP::Attachment("GBuffer1", CGI::Format::unormR10G10B10A2).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly), + CGI::RP::Attachment("GBuffer2", CGI::Format::unormR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly), + CGI::RP::Attachment("Depth", CGI::Format::unormD24uintS8).LoadOpClear().Layout(CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly), + }, + { + CGI::RP::Subpass("Sp0").Color( + { + CGI::RP::Ref("GBuffer0", CGI::ImageLayout::colorAttachment), + CGI::RP::Ref("GBuffer1", CGI::ImageLayout::colorAttachment), + CGI::RP::Ref("GBuffer2", CGI::ImageLayout::colorAttachment) + }).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment)) + }, + {}); + + CGI::TexturePwn texGB[3], texDepth; + CGI::TextureDesc texDesc; + texDesc._width = texWidth; + texDesc._height = texHeight; + texDesc._flags = CGI::TextureDesc::Flags::colorAttachment; + + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(); + texDesc._format = CGI::Format::srgbR8G8B8A8; + texGB[0].Init(texDesc); + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(); + texDesc._format = CGI::Format::unormR10G10B10A2; + texGB[1].Init(texDesc); + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(); + texDesc._format = CGI::Format::unormR8G8B8A8; + texGB[2].Init(texDesc); + texDesc.Reset(); + texDesc._clearValue = Vector4(1); + texDesc._format = CGI::Format::unormD24uintS8; + texDesc._width = texWidth; + texDesc._height = texHeight; + texDepth.Init(texDesc); + + CGI::FBHandle fbh = renderer->CreateFramebuffer(rph, + { + texGB[0], + texGB[1], + texGB[2], + texDepth + }, + texWidth, + texHeight); + + cb->BeginRenderPass(rph, fbh, + { + texGB[0]->GetClearValue(), + texGB[1]->GetClearValue(), + texGB[2]->GetClearValue(), + texDepth->GetClearValue() + }); + + plant._mesh.BindPipeline(cb, false); + plant._mesh.BindGeo(cb); + Mesh::GetShader()->BeginBindDescriptors(); + plant._material->UpdateMeshUniformBuffer(); + cb->BindDescriptors(Scene::Mesh::GetShader(), 1, plant._material->GetComplexSetHandle()); + plant._mesh.UpdateUniformBufferPerMeshVS(); + cb->BindDescriptors(Scene::Mesh::GetShader(), 2); + plant._mesh.UpdateUniformBufferSkeletonVS(); + cb->BindDescriptors(Scene::Mesh::GetShader(), 3); + plant._mesh.UpdateUniformBufferPerObject(Transform3::identity()); + cb->BindDescriptors(Scene::Mesh::GetShader(), 4); + VERUS_FOR(i, frameCountV) + { + const Matrix3 matV = Matrix3::rotationX(-stepV * i); + VERUS_FOR(j, frameCountH) + { + const Vector4 vp( + static_cast(j * frameSide + framePad), + static_cast(i * frameSide + framePad), + static_cast(frameSide - framePad * 2), + static_cast(frameSide - framePad * 2)); + cb->SetViewport({ vp }); + + const float size = plant.GetSize(); + const Matrix3 matH = Matrix3::rotationY(stepH * j); + const Matrix3 matR = matH * matV; + const Vector3 offset = matR * Vector3(0, 0, size); + + Camera cam; + cam.MoveAtTo(Vector3(0, size * 0.5f / _margin, 0)); + cam.MoveEyeTo(Vector3(0, size * 0.5f / _margin, 0) + offset); + cam.SetFovY(0); + cam.SetWidth(size * _margin); + cam.SetHeight(size * _margin); + cam.SetAspectRatio(1); + cam.SetZNear(0); + cam.SetZFar(size * 2); + cam.Update(); + PCamera pPrevCamera = sm.SetCamera(&cam); + + plant._mesh.UpdateUniformBufferPerFrame(); + cb->BindDescriptors(Scene::Mesh::GetShader(), 0); + cb->DrawIndexed(plant._mesh.GetIndexCount()); + + sm.SetCamera(pPrevCamera); + } + } + Mesh::GetShader()->EndBindDescriptors(); + + cb->EndRenderPass(); + + CGI::TexturePwn texFinalGB[3]; + texDesc.Reset(); + texDesc._width = texWidth; + texDesc._height = texHeight; + texDesc._mipLevels = 0; + texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips; + texDesc._readbackMip = 2; + + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(); + texDesc._format = CGI::Format::srgbR8G8B8A8; + texFinalGB[0].Init(texDesc); + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(); + texDesc._format = CGI::Format::unormR8G8B8A8; + texFinalGB[1].Init(texDesc); + texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(); + texDesc._format = CGI::Format::unormR8G8B8A8; + texFinalGB[2].Init(texDesc); + + renderer.GetDS().BakeSprites(texGB, texFinalGB, cb.Get()); + + VERUS_FOR(i, 3) + { + texFinalGB[i]->GenerateMips(cb.Get()); + texFinalGB[i]->ReadbackSubresource(nullptr, true, cb.Get()); + } + + cb->DoneOneTimeSubmit(); + + const int mipWidth = texWidth / 4; + const int mipHeight = texHeight / 4; + Vector vData; + vData.resize(mipWidth * mipHeight); + const CSZ ext[] = { "", ".FX", ".FX" }; + VERUS_FOR(i, 3) + { + texFinalGB[i]->ReadbackSubresource(vData.data(), false); + + String pathname = _C(plant._mesh.GetUrl()); + char filename[20]; + sprintf_s(filename, "GB%d%s.psd", i, ext[i]); + Str::ReplaceFilename(pathname, filename); + pathname = Str::ToPakFriendlyUrl(_C(pathname)); + pathname = String(url) + '/' + pathname; + IO::FileSystem::SaveImage(_C(pathname), vData.data(), mipWidth, mipHeight); + } + + renderer.GetDS().BakeSpritesCleanup(); + renderer->DeleteFramebuffer(fbh); + renderer->DeleteRenderPass(rph); + renderer->DeleteCommandBuffer(cb.Detach()); +} + +bool Forest::BakeSprites(CSZ url) +{ + for (auto& plant : _vPlants) + { + if (plant._mesh.IsLoaded() && plant._material->IsLoaded()) + BakeSprite(plant, url); + else + return false; + } + return true; } void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, float scale, float angle, UINT32 r) @@ -626,6 +820,8 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl if (_visibleCount == _vDrawPlants.size()) return; + VERUS_QREF_ATMO; + const int layer = _pTerrain->GetMainLayerAt(ij); if (layer >= _vLayerPlants.size()) return; @@ -635,14 +831,15 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl const float h = _pTerrain->GetHeightAt(ij); Point3 pos(x, h, z); - RcPoint3 eyePos = Atmosphere::I().GetEyePosition(); + RcPoint3 eyePos = atmo.GetEyePosition(); const float distSq = VMath::distSqr(eyePos, pos); - if (distSq >= _maxDist * _maxDist) + const float maxDistSq = _maxDist * _maxDist; + if (distSq >= maxDistSq) return; RPlant plant = _vPlants[plantIndex]; - if (_pTerrain->GetNormalAt(ij)[1] < plant._normal) + if (_pTerrain->GetNormalAt(ij)[1] < plant._allowedNormal) return; int ij4[2] = { ij[0], ij[1] }; @@ -652,26 +849,32 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl ij4[1]++; h4[2] = _pTerrain->GetHeightAt(ij4); ij4[0]--; h4[3] = _pTerrain->GetHeightAt(ij4); pos.setY(*std::min_element(h4 + 0, h4 + 4)); - const float ratio = 1 - sqrt(distSq) / _maxDist; - const float t = Math::Clamp((ratio - 0.1f) / 0.8f, 0, 1); + + const float distFractionSq = distSq / maxDistSq; + const float alignToNormal = (1 - distFractionSq) * plant._alignToNormal; + const float t = Math::Clamp((alignToNormal - 0.1f) / 0.8f, 0, 1); + Vector3 pushBack(0); Matrix3 matScale = Matrix3::identity(); - if (ratio < 0.25f) + if (Scene::SceneManager::IsDrawingDepth(DrawDepth::automatic)) { - const float a = ratio * 4; - //if (Utils::IsDrawingDepth(DrawDepth::automatic)) - //{ - // const float b = Math::Clamp((a - 0.5f) * 2, 0, 1); - // matScale = Matrix3::scale(Vector3(b, 1, b)); - //} - pushBack = VMath::normalizeApprox(pos - eyePos) * plant._maxSize * (1 - a) * 0.4f; + const float strength = Math::Clamp((1 - distFractionSq) * 1.25f, 0, 1); + matScale = Matrix3::scale(Vector3(strength, 0.5f + 0.5f * strength, strength)); } + else + { + const float strength = Math::Clamp((distFractionSq - 0.5f) * 2, 0, 1); + const Point3 center = pos + Vector3(0, plant._maxSize * 0.5f, 0); + pushBack = VMath::normalizeApprox(center - eyePos) * plant._maxSize * strength; + } + DrawPlant drawPlant; drawPlant._basis = Matrix3::Lerp(Matrix3::identity(), _pTerrain->GetBasisAt(ij), t) * matScale; drawPlant._pos = pos; drawPlant._pushBack = pushBack; drawPlant._scale = plant._vScales[r % plant._vScales.size()]; drawPlant._angle = angle; + drawPlant._distToEyeSq = distSq; drawPlant._plantIndex = plantIndex; _vDrawPlants[_visibleCount++] = drawPlant; } diff --git a/Verus/src/Scene/Forest.h b/Verus/src/Scene/Forest.h index e36b902..976caf4 100644 --- a/Verus/src/Scene/Forest.h +++ b/Verus/src/Scene/Forest.h @@ -6,7 +6,14 @@ namespace verus { class Forest : public Object, public ScatterDelegate, public Math::OctreeDelegate { - //#include "../Cg/DS_Forest.inc.cg" +#include "../Shaders/DS_Forest.inc.hlsl" + + enum PIPE + { + PIPE_MAIN, + PIPE_DEPTH, + PIPE_COUNT + }; public: enum SCATTER_TYPE @@ -45,8 +52,8 @@ namespace verus enum TEX { TEX_GBUFFER_0, + TEX_GBUFFER_1, TEX_GBUFFER_2, - TEX_GBUFFER_3, TEX_COUNT }; @@ -54,11 +61,14 @@ namespace verus Mesh _mesh; MaterialPwn _material; CGI::TexturePwns _tex; + CGI::CSHandle _csh; Vector _vBakedChunks; Vector _vScales; + float _alignToNormal = 1; float _maxScale = 0; float _maxSize = 0; - char _normal = 116; + float _aoSize = 1; + char _allowedNormal = 116; float GetSize() const; }; @@ -84,42 +94,48 @@ namespace verus Vector3 _pushBack = Vector3(0); float _scale = 1; float _angle = 0; + float _distToEyeSq = 0; int _plantIndex = 0; }; VERUS_TYPEDEFS(DrawPlant); static CGI::ShaderPwn s_shader; - //static CGI::CStateBlockPwns ms_sb; + static UB_ForestVS s_ubForestVS; + static UB_ForestFS s_ubForestFS; - PTerrain _pTerrain = nullptr; - CGI::GeometryPwn _geo; - Math::Octree _octree; - Scatter _scatter; - Vector _vPlants; - Vector _vLayerPlants; - Vector _vDrawPlants; - const float _margin = 1.1f; - float _maxDist = 100; - float _maxSizeAll = 0; - int _capacity = 4000; - int _visibleCount = 0; - bool _async_initPlants = false; + PTerrain _pTerrain = nullptr; + CGI::GeometryPwn _geo; + CGI::PipelinePwns _pipe; + Math::Octree _octree; + Scatter _scatter; + Vector _vPlants; + Vector _vLayerPlants; + Vector _vDrawPlants; + const float _margin = 1.1f; + float _maxDist = 100; + float _tessDist = 50; + float _maxSizeAll = 0; + int _capacity = 4000; + int _visibleCount = 0; + bool _async_initPlants = false; public: class PlantDesc { public: CSZ _url = nullptr; + float _alignToNormal = 1; float _minScale = 0.5f; float _maxScale = 1.5f; - char _normal = 116; + char _allowedNormal = 116; - void Set(CSZ url, float minScale = 0.5f, float maxScale = 1.5f, char normal = 116) + void Set(CSZ url, float alignToNormal = 1, float minScale = 0.5f, float maxScale = 1.5f, char allowedNormal = 116) { _url = url; + _alignToNormal = alignToNormal; _minScale = minScale; _maxScale = maxScale; - _normal = normal; + _allowedNormal = allowedNormal; } }; VERUS_TYPEDEFS(PlantDesc); @@ -143,12 +159,12 @@ namespace verus void Done(); void ResetInstanceCount(); - void Update(); void Layout(); - void Draw(); - VERUS_P(void DrawModels()); + void Draw(bool allowTess = true); + VERUS_P(void DrawModels(bool allowTess)); VERUS_P(void DrawSprites()); + void DrawAO(); PTerrain SetTerrain(PTerrain p) { return Utils::Swap(_pTerrain, p); } @@ -156,7 +172,8 @@ namespace verus VERUS_P(int FindPlant(CSZ url) const); VERUS_P(void BakeChunks(RPlant plant)); bool LoadSprite(RPlant plant); - void BakeSprite(RPlant plant); + void BakeSprite(RPlant plant, CSZ url); + bool BakeSprites(CSZ url); virtual void Scatter_AddInstance(const int ij[2], int type, float x, float z, float scale, float angle, UINT32 r) override; diff --git a/Verus/src/Scene/Grass.cpp b/Verus/src/Scene/Grass.cpp index e75e4d5..9009826 100644 --- a/Verus/src/Scene/Grass.cpp +++ b/Verus/src/Scene/Grass.cpp @@ -157,6 +157,11 @@ void Grass::Done() VERUS_DONE(Grass); } +void Grass::ResetInstanceCount() +{ + _instanceCount = 0; +} + void Grass::Update() { VERUS_UPDATE_ONCE_CHECK; @@ -209,13 +214,13 @@ void Grass::Draw() 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; + auto cb = renderer.GetCommandBuffer(); + s_ubGrassVS._matW = Transform3::UniformBufferFormatIdentity(); s_ubGrassVS._matWV = sm.GetCamera()->GetMatrixV().UniformBufferFormat(); s_ubGrassVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); @@ -277,11 +282,6 @@ void Grass::Draw() _geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 1); } -void Grass::ResetInstanceCount() -{ - _instanceCount = 0; -} - void Grass::QuadtreeIntegral_ProcessVisibleNode(const short ij[2], RcPoint3 center) { VERUS_QREF_ATMO; diff --git a/Verus/src/Scene/Grass.h b/Verus/src/Scene/Grass.h index 31431a7..f9f1f0c 100644 --- a/Verus/src/Scene/Grass.h +++ b/Verus/src/Scene/Grass.h @@ -92,12 +92,11 @@ namespace verus void Init(RTerrain terrain); void Done(); + void ResetInstanceCount(); void Update(); void Layout(); void Draw(); - void ResetInstanceCount(); - virtual void QuadtreeIntegral_ProcessVisibleNode(const short ij[2], RcPoint3 center) override; virtual void QuadtreeIntegral_GetHeights(const short ij[2], float height[2]) override; diff --git a/Verus/src/Scene/MaterialManager.cpp b/Verus/src/Scene/MaterialManager.cpp index 81a9381..9b5d319 100644 --- a/Verus/src/Scene/MaterialManager.cpp +++ b/Verus/src/Scene/MaterialManager.cpp @@ -335,8 +335,8 @@ String Material::ToString(bool cleanDict) CSZ empty = ""; - CGI::PBaseTexture pTexAlbedo = &(*_texAlbedo->GetTex()); - CGI::PBaseTexture pTexNormal = &(*_texNormal->GetTex()); + CGI::PBaseTexture pTexAlbedo = _texAlbedo->GetTex().Get(); + CGI::PBaseTexture pTexNormal = _texNormal->GetTex().Get(); _dict.Insert("alphaSwitch", /**/_C(Str::ToString(_alphaSwitch))); _dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir))); diff --git a/Verus/src/Scene/Mesh.cpp b/Verus/src/Scene/Mesh.cpp index f774827..cea38a1 100644 --- a/Verus/src/Scene/Mesh.cpp +++ b/Verus/src/Scene/Mesh.cpp @@ -59,6 +59,7 @@ void Mesh::Init(RcDesc desc) } _instanceCapacity = desc._instanceCapacity; + _initShape = desc._initShape; BaseMesh::Init(desc._url); } @@ -70,19 +71,19 @@ void Mesh::Done() void Mesh::Draw(RcDrawDesc dd, CGI::CommandBufferPtr cb) { - BindGeo(cb); BindPipeline(cb, dd._allowTess); + BindGeo(cb); UpdateUniformBufferPerFrame(); - cb->BindDescriptors(Scene::Mesh::GetShader(), 0); - UpdateUniformBufferPerMaterialFS(); - cb->BindDescriptors(Scene::Mesh::GetShader(), 1, dd._cshMaterial); + cb->BindDescriptors(GetShader(), 0); + // Material buffer should already be updated. For example call Material::UpdateMeshUniformBuffer. + cb->BindDescriptors(GetShader(), 1, dd._cshMaterial); UpdateUniformBufferPerMeshVS(); - cb->BindDescriptors(Scene::Mesh::GetShader(), 2); + cb->BindDescriptors(GetShader(), 2); UpdateUniformBufferSkeletonVS(); - cb->BindDescriptors(Scene::Mesh::GetShader(), 3); + cb->BindDescriptors(GetShader(), 3); UpdateUniformBufferPerObject(dd._matW); - cb->BindDescriptors(Scene::Mesh::GetShader(), 4); + cb->BindDescriptors(GetShader(), 4); cb->DrawIndexed(GetIndexCount()); } @@ -97,9 +98,17 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb) { 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; + case PIPE_TESS: pipe = PIPE_MAIN; break; + case PIPE_TESS_INSTANCED: pipe = PIPE_INSTANCED; break; + case PIPE_TESS_PLANT: pipe = PIPE_PLANT; break; + case PIPE_TESS_ROBOTIC: pipe = PIPE_ROBOTIC; break; + case PIPE_TESS_SKINNED: pipe = PIPE_SKINNED; break; + + case PIPE_DEPTH_TESS: pipe = PIPE_DEPTH; break; + case PIPE_DEPTH_TESS_INSTANCED: pipe = PIPE_DEPTH_INSTANCED; break; + case PIPE_DEPTH_TESS_PLANT: pipe = PIPE_DEPTH_PLANT; break; + case PIPE_DEPTH_TESS_ROBOTIC: pipe = PIPE_DEPTH_ROBOTIC; break; + case PIPE_DEPTH_TESS_SKINNED: pipe = PIPE_DEPTH_SKINNED; break; }; } @@ -109,18 +118,27 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb) { "#", "#Instanced", + "#Plant", "#Robotic", "#Skinned", + "#Tess", + "#TessInstanced", + "#TessPlant", + "#TessRobotic", + "#TessSkinned", + "#Depth", "#DepthInstanced", + "#DepthPlant", "#DepthRobotic", "#DepthSkinned", - "#Tess", - "#TessInstanced", - "#TessRobotic", - "#TessSkinned", + "#DepthTess", + "#DepthTessInstanced", + "#DepthTessPlant", + "#DepthTessRobotic", + "#DepthTessSkinned", "#SolidColor", "#SolidColorInstanced", @@ -141,14 +159,27 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb) { case PIPE_MAIN: case PIPE_INSTANCED: + case PIPE_PLANT: case PIPE_ROBOTIC: case PIPE_SKINNED: { SetBlendEqsForDS(); } break; + case PIPE_TESS: + case PIPE_TESS_INSTANCED: + case PIPE_TESS_PLANT: + case PIPE_TESS_ROBOTIC: + case PIPE_TESS_SKINNED: + { + SetBlendEqsForDS(); + if (settings._gpuTessellation) + pipeDesc._topology = CGI::PrimitiveTopology::patchList3; + } + break; case PIPE_DEPTH: case PIPE_DEPTH_INSTANCED: + case PIPE_DEPTH_PLANT: case PIPE_DEPTH_ROBOTIC: case PIPE_DEPTH_SKINNED: { @@ -156,12 +187,14 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb) pipeDesc._renderPassHandle = atmo.GetShadowMap().GetRenderPassHandle(); } break; - case PIPE_TESS: - case PIPE_TESS_INSTANCED: - case PIPE_TESS_ROBOTIC: - case PIPE_TESS_SKINNED: + case PIPE_DEPTH_TESS: + case PIPE_DEPTH_TESS_INSTANCED: + case PIPE_DEPTH_TESS_PLANT: + case PIPE_DEPTH_TESS_ROBOTIC: + case PIPE_DEPTH_TESS_SKINNED: { - SetBlendEqsForDS(); + pipeDesc._colorAttachBlendEqs[0] = ""; + pipeDesc._renderPassHandle = atmo.GetShadowMap().GetRenderPassHandle(); if (settings._gpuTessellation) pipeDesc._topology = CGI::PrimitiveTopology::patchList3; } @@ -195,32 +228,56 @@ void Mesh::BindPipeline(CGI::CommandBufferPtr cb, bool allowTess) if (_skeleton.IsInitialized()) { if (atmo.GetShadowMap().IsRendering()) - BindPipeline(Scene::Mesh::PIPE_DEPTH_SKINNED, cb); - else if (allowTess) - BindPipeline(Scene::Mesh::PIPE_TESS_SKINNED, cb); + { + if (allowTess) + BindPipeline(PIPE_DEPTH_TESS_SKINNED, cb); + else + BindPipeline(PIPE_DEPTH_SKINNED, cb); + } else - BindPipeline(Scene::Mesh::PIPE_SKINNED, cb); + { + if (allowTess) + BindPipeline(PIPE_TESS_SKINNED, cb); + else + BindPipeline(PIPE_SKINNED, cb); + } } else { if (atmo.GetShadowMap().IsRendering()) - BindPipeline(Scene::Mesh::PIPE_DEPTH, cb); - else if (allowTess) - BindPipeline(Scene::Mesh::PIPE_TESS, cb); + { + if (allowTess) + BindPipeline(PIPE_DEPTH_TESS, cb); + else + BindPipeline(PIPE_DEPTH, cb); + } else - BindPipeline(Scene::Mesh::PIPE_MAIN, cb); + { + if (allowTess) + BindPipeline(PIPE_TESS, cb); + else + BindPipeline(PIPE_MAIN, cb); + } } } -void Mesh::BindPipelineInstanced(CGI::CommandBufferPtr cb, bool allowTess) +void Mesh::BindPipelineInstanced(CGI::CommandBufferPtr cb, bool allowTess, bool plant) { VERUS_QREF_ATMO; if (atmo.GetShadowMap().IsRendering()) - BindPipeline(Scene::Mesh::PIPE_DEPTH_INSTANCED, cb); - else if (allowTess) - BindPipeline(Scene::Mesh::PIPE_TESS_INSTANCED, cb); + { + if (allowTess) + BindPipeline(plant ? PIPE_DEPTH_TESS_PLANT : PIPE_DEPTH_TESS_INSTANCED, cb); + else + BindPipeline(plant ? PIPE_DEPTH_PLANT : PIPE_DEPTH_INSTANCED, cb); + } else - BindPipeline(Scene::Mesh::PIPE_INSTANCED, cb); + { + if (allowTess) + BindPipeline(plant ? PIPE_TESS_PLANT : PIPE_TESS_INSTANCED, cb); + else + BindPipeline(plant ? PIPE_PLANT : PIPE_INSTANCED, cb); + } } void Mesh::BindGeo(CGI::CommandBufferPtr cb) @@ -234,18 +291,20 @@ void Mesh::BindGeo(CGI::CommandBufferPtr cb, UINT32 bindingsFilter) cb->BindIndexBuffer(_geo); } -void Mesh::UpdateUniformBufferPerFrame() +void Mesh::UpdateUniformBufferPerFrame(float invTessDist) { VERUS_QREF_RENDERER; VERUS_QREF_SM; + VERUS_QREF_ATMO; + + RcPoint3 eyePos = atmo.GetEyePosition(); + Point3 eyePosWV = sm.GetCamera()->GetMatrixV() * eyePos; + s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().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() -{ + s_ubPerFrame._eyePosWV_invTessDistSq = float4(eyePosWV.GLM(), invTessDist * invTessDist); } void Mesh::UpdateUniformBufferPerMeshVS() @@ -354,7 +413,7 @@ void Mesh::CreateDeviceBuffers() } // Instance buffer: - if (_instanceCapacity > 1) + if (_instanceCapacity > 0) { _vInstanceBuffer.resize(_instanceCapacity); _bindingsMask |= (1 << 4); @@ -367,8 +426,15 @@ void Mesh::UpdateVertexBuffer(const void* p, int binding) _geo->UpdateVertexBuffer(p, binding); } +void Mesh::ResetInstanceCount() +{ + _instanceCount = 0; + _firstInstance = 0; +} + void Mesh::PushInstance(RcTransform3 matW, RcVector4 instData) { + VERUS_RT_ASSERT(!_vInstanceBuffer.empty()); if (!_vertCount) return; if (IsInstanceBufferFull()) @@ -380,6 +446,7 @@ void Mesh::PushInstance(RcTransform3 matW, RcVector4 instData) bool Mesh::IsInstanceBufferFull() { + VERUS_RT_ASSERT(!_vInstanceBuffer.empty()); if (!_vertCount) return false; return _instanceCount >= _instanceCapacity; @@ -387,18 +454,14 @@ bool Mesh::IsInstanceBufferFull() bool Mesh::IsInstanceBufferEmpty(bool fromFirstInstance) { + VERUS_RT_ASSERT(!_vInstanceBuffer.empty()); if (!_vertCount) return true; return GetInstanceCount(fromFirstInstance) <= 0; } -void Mesh::ResetInstanceCount() -{ - _instanceCount = 0; - _firstInstance = 0; -} - void Mesh::UpdateInstanceBuffer() { + VERUS_RT_ASSERT(!_vInstanceBuffer.empty()); _geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 4); } diff --git a/Verus/src/Scene/Mesh.h b/Verus/src/Scene/Mesh.h index 40ddd8f..608ecbd 100644 --- a/Verus/src/Scene/Mesh.h +++ b/Verus/src/Scene/Mesh.h @@ -13,18 +13,27 @@ namespace verus { PIPE_MAIN, PIPE_INSTANCED, + PIPE_PLANT, PIPE_ROBOTIC, PIPE_SKINNED, + PIPE_TESS, + PIPE_TESS_INSTANCED, + PIPE_TESS_PLANT, + PIPE_TESS_ROBOTIC, + PIPE_TESS_SKINNED, + PIPE_DEPTH, PIPE_DEPTH_INSTANCED, + PIPE_DEPTH_PLANT, PIPE_DEPTH_ROBOTIC, PIPE_DEPTH_SKINNED, - PIPE_TESS, - PIPE_TESS_INSTANCED, - PIPE_TESS_ROBOTIC, - PIPE_TESS_SKINNED, + PIPE_DEPTH_TESS, + PIPE_DEPTH_TESS_INSTANCED, + PIPE_DEPTH_TESS_PLANT, + PIPE_DEPTH_TESS_ROBOTIC, + PIPE_DEPTH_TESS_SKINNED, PIPE_WIREFRAME, PIPE_WIREFRAME_INSTANCED, @@ -61,9 +70,10 @@ namespace verus public: struct Desc { - CSZ _url = nullptr; - CSZ _warpUrl = nullptr; - int _instanceCapacity = 1; + CSZ _url = nullptr; + CSZ _warpUrl = nullptr; + int _instanceCapacity = 0; + bool _initShape = false; Desc(CSZ url = nullptr) : _url(url) {} }; @@ -90,14 +100,13 @@ namespace verus void BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb); void BindPipeline(CGI::CommandBufferPtr cb, bool allowTess = true); - void BindPipelineInstanced(CGI::CommandBufferPtr cb, bool allowTess = true); + void BindPipelineInstanced(CGI::CommandBufferPtr cb, bool allowTess = true, bool plant = false); void BindGeo(CGI::CommandBufferPtr cb); void BindGeo(CGI::CommandBufferPtr cb, UINT32 bindingsFilter); static CGI::ShaderPtr GetShader() { return s_shader; } static UB_PerMaterialFS& GetUbPerMaterialFS() { return s_ubPerMaterialFS; } - void UpdateUniformBufferPerFrame(); - void UpdateUniformBufferPerMaterialFS(); + void UpdateUniformBufferPerFrame(float invTessDist = 0); void UpdateUniformBufferPerMeshVS(); void UpdateUniformBufferSkeletonVS(); void UpdateUniformBufferPerObject(RcTransform3 tr, RcVector4 color = Vector4(0.5f, 0.5f, 0.5f, 1)); @@ -108,11 +117,12 @@ namespace verus virtual void UpdateVertexBuffer(const void* p, int binding) override; // Instancing: + void ResetInstanceCount(); + void MarkFirstInstance() { _firstInstance = _instanceCount; } void PushInstance(RcTransform3 matW, RcVector4 instData); bool IsInstanceBufferFull(); bool IsInstanceBufferEmpty(bool fromFirstInstance = false); - void ResetInstanceCount(); - void MarkFirstInstance() { _firstInstance = _instanceCount; } + void UpdateInstanceBuffer(); int GetInstanceCount(bool fromFirstInstance = false) const { return fromFirstInstance ? _instanceCount - _firstInstance : _instanceCount; } int GetInstanceCapacity() const { return _instanceCapacity; } diff --git a/Verus/src/Scene/Scatter.cpp b/Verus/src/Scene/Scatter.cpp index 50336fa..8705d5e 100644 --- a/Verus/src/Scene/Scatter.cpp +++ b/Verus/src/Scene/Scatter.cpp @@ -24,7 +24,7 @@ void Scatter::Init(int side, int typeCount, PcTypeDesc pTypes, int seed) // Fill 2D array of instances: _vInstances.resize(_side * _side); - const int instanceCount = _vInstances.size(); + const int instanceCount = Utils::Cast32(_vInstances.size()); int type = 0; int maxPermille = (typeCount >= 1) ? pTypes[0]._permille : 1000; VERUS_FOR(i, instanceCount) diff --git a/Verus/src/Scene/Scene.h b/Verus/src/Scene/Scene.h index 3ed2f23..7019c0a 100644 --- a/Verus/src/Scene/Scene.h +++ b/Verus/src/Scene/Scene.h @@ -11,6 +11,7 @@ #include "Atmosphere.h" #include "Water.h" #include "MaterialManager.h" +#include "SceneNodes/SceneNodes.h" #include "SceneManager.h" #include "Helpers.h" #include "Scatter.h" diff --git a/Verus/src/Scene/SceneManager.cpp b/Verus/src/Scene/SceneManager.cpp index 233a2d5..fd303c2 100644 --- a/Verus/src/Scene/SceneManager.cpp +++ b/Verus/src/Scene/SceneManager.cpp @@ -5,6 +5,7 @@ using namespace verus::Scene; SceneManager::SceneManager() { + VERUS_ZERO_MEM(_visibleCountPerType); } SceneManager::~SceneManager() @@ -12,18 +13,290 @@ SceneManager::~SceneManager() Done(); } -void SceneManager::Init() +void SceneManager::Init(RcDesc desc) { VERUS_INIT(); + + SetCamera(desc._pMainCamera); + + const float hf = desc._mapSide * 0.5f; + Math::Bounds bounds; + bounds.Set( + Vector3(-hf, -hf, -hf), + Vector3(+hf, +hf, +hf)); + const Vector3 limit(hf / 14, hf / 14, hf / 14); + _octree.Done(); + _octree.Init(bounds, limit); + _octree.SetDelegate(this); } void SceneManager::Done() { + { // PBLE: + //DeleteAllPrefabs(); + DeleteAllBlocks(); + DeleteAllLights(); + //DeleteAllEmitters(); + } + DeleteAllModels(); VERUS_DONE(SceneManager); } +void SceneManager::ResetInstanceCount() +{ + for (auto& x : TStoreModels::_map) + x.second.GetMesh().ResetInstanceCount(); +} + +void SceneManager::Update() +{ + VERUS_UPDATE_ONCE_CHECK; + //for (auto& x : TStoreSites::_map) + // x.second.Update(); + { // PBLE: + //for (auto& x : TStorePrefabs::_list) + // x.Update(); + for (auto& x : TStoreBlocks::_list) + x.Update(); + for (auto& x : TStoreLights::_list) + x.Update(); + //for (auto& x : TStoreEmitters::_list) + // x.Update(); + } + //for (auto& x : TStoreSceneParticles::_map) + // x.second.Update(); +} + void SceneManager::UpdateParts() { + const RcPoint3 eyePos = _pMainCamera->GetEyePosition(); + for (auto& block : TStoreBlocks::_list) + { + const float distSq = VMath::distSqr(block.GetPosition(), eyePos); + const float part = MaterialManager::ComputePart(distSq, block.GetBounds().GetAverageSize() * 0.5f); + block.GetMaterial()->IncludePart(part); + } +} + +void SceneManager::Layout() +{ + VERUS_QREF_CONST_SETTINGS; + VERUS_QREF_ATMO; + VERUS_QREF_SM; + + // Allocate enough space: + int countAll = 0; + //countAll += TStorePrefabs::_list.size(); + countAll += TStoreBlocks::_list.size(); + countAll += TStoreLights::_list.size(); + //countAll += TStoreSites::_map.size(); + if (_vVisibleNodes.size() != countAll) + _vVisibleNodes.resize(countAll); + + _visibleCount = 0; + VERUS_ZERO_MEM(_visibleCountPerType); + + PCamera pPrevCamera = nullptr; + // For CSM we need to create geometry beyond the view frustum (1st slice): + if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::cascaded && atmo.GetShadowMap().IsRendering()) + { + PCamera pCameraCSM = atmo.GetShadowMap().GetCameraCSM(); + if (pCameraCSM) + pPrevCamera = sm.SetCamera(pCameraCSM); + } + _octree.TraverseVisible(_pCamera->GetFrustum()); + // Back to original camera: + if (pPrevCamera) + SetCamera(pPrevCamera); + + VERUS_RT_ASSERT(!_visibleCountPerType[+NodeType::unknown]); + std::sort(_vVisibleNodes.begin(), _vVisibleNodes.begin() + _visibleCount, [](PSceneNode pA, PSceneNode pB) + { + // Sort by node type? + const NodeType typeA = pA->GetType(); + const NodeType typeB = pB->GetType(); + if (typeA != typeB) + return typeA < typeB; + + // Both are blocks? + if (NodeType::block == typeA) + { + PBlock pBlockA = static_cast(pA); + PBlock pBlockB = static_cast(pB); + MaterialPtr materialA = pBlockA->GetMaterial(); + MaterialPtr materialB = pBlockB->GetMaterial(); + + if (materialA && materialB) // A and B have materials, compare them. + { + const bool ab = *materialA < *materialB; + const bool ba = *materialB < *materialA; + if (ab || ba) + return ab; + } + else if (materialA) // A is with material, B is without, so A goes first. + { + return true; + } + else if (materialB) // A is without material, B is with, so B goes first. + { + return false; + } + + // Equal materials or none have any material, compare models used: + ModelPtr modelA = pBlockA->GetModel(); + ModelPtr modelB = pBlockB->GetModel(); + if (modelA != modelB) + return modelA < modelB; + } + + // Both are lights? + if (NodeType::light == typeA) + { + PLight pLightA = static_cast(pA); + PLight pLightB = static_cast(pB); + const CGI::LightType lightTypeA = pLightA->GetLightType(); + const CGI::LightType lightTypeB = pLightB->GetLightType(); + if (lightTypeA != lightTypeB) + return lightTypeA < lightTypeB; + } + + // Draw same node types front-to-back: + return pA->GetDistToEyeSq() < pB->GetDistToEyeSq(); + }); +} + +void SceneManager::Draw() +{ + if (!_visibleCountPerType[+NodeType::block]) + return; + + VERUS_QREF_RENDERER; + + ModelPtr model; + MaterialPtr material; + bool bindPipeline = true; + + auto cb = renderer.GetCommandBuffer(); + auto shader = Scene::Mesh::GetShader(); + + const int begin = 0; + const int end = _visibleCountPerType[+NodeType::block]; + shader->BeginBindDescriptors(); + for (int i = begin; i <= end; ++i) + { + if (i == end) + { + if (model) + model->Draw(cb); + break; + } + + PSceneNode pSN = _vVisibleNodes[i]; + PBlock pBlock = static_cast(pSN); + ModelPtr nextModel = pBlock->GetModel(); + MaterialPtr nextMaterial = pBlock->GetMaterial(); + + if (!nextModel->IsLoaded() || !nextMaterial->IsLoaded()) + continue; + + if (nextModel != model) + { + if (model) + model->Draw(cb); + + model = nextModel; + model->MarkFirstInstance(); + if (bindPipeline) + { + bindPipeline = false; + model->BindPipeline(cb); + cb->BindDescriptors(shader, 0); + } + model->BindGeo(cb); + cb->BindDescriptors(shader, 2); + } + if (nextMaterial != material) + { + material = nextMaterial; + material->UpdateMeshUniformBuffer(); + cb->BindDescriptors(shader, 1, material->GetComplexSetHandle()); + } + + if (model) + model->PushInstance(pBlock->GetTransform(), pBlock->GetColor()); + } + shader->EndBindDescriptors(); +} + +void SceneManager::DrawLights() +{ + if (!_visibleCountPerType[+NodeType::light]) + return; + + VERUS_QREF_RENDERER; + VERUS_QREF_HELPERS; + + CGI::LightType type = CGI::LightType::none; + PMesh pMesh = nullptr; + bool bindPipeline = true; + + auto& ds = renderer.GetDS(); + auto cb = renderer.GetCommandBuffer(); + + auto DrawMesh = [cb](PMesh pMesh) + { + if (pMesh && !pMesh->IsInstanceBufferEmpty(true)) + { + pMesh->UpdateInstanceBuffer(); + cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance()); + } + }; + + const int begin = _visibleCountPerType[+NodeType::block]; + const int end = _visibleCountPerType[+NodeType::block] + _visibleCountPerType[+NodeType::light]; + for (int i = begin; i <= end; ++i) + { + if (i == end) + { + DrawMesh(pMesh); + break; + } + + PSceneNode pSN = _vVisibleNodes[i]; + PLight pLight = static_cast(pSN); + const CGI::LightType nextType = pLight->GetLightType(); + + if (nextType != type) + { + DrawMesh(pMesh); + + type = nextType; + ds.OnNewLightType(cb, type); + + pMesh = (type != CGI::LightType::none) ? &helpers.GetDeferredLights().Get(type) : nullptr; + + if (pMesh) + { + pMesh->MarkFirstInstance(); + pMesh->BindGeo(cb, (1 << 0) | (1 << 4)); + pMesh->CopyPosDeqScale(&ds.GetUbPerMeshVS()._posDeqScale.x); + pMesh->CopyPosDeqBias(&ds.GetUbPerMeshVS()._posDeqBias.x); + ds.BindDescriptorsPerMeshVS(cb); + } + } + +#ifdef VERUS_RELEASE_DEBUG + if (CGI::LightType::dir == type) // Must not be scaled! + { + RcTransform3 matW = pLight->GetTransform(); + const Vector3 s = matW.GetScale(); + VERUS_RT_ASSERT(glm::all(glm::epsilonEqual(s.GLM(), glm::vec3(1), glm::vec3(VERUS_FLOAT_THRESHOLD)))); + } +#endif + + if (pMesh) + pMesh->PushInstance(pLight->GetTransform(), pLight->GetInstData()); + } } bool SceneManager::IsDrawingDepth(DrawDepth dd) @@ -37,10 +310,95 @@ bool SceneManager::IsDrawingDepth(DrawDepth dd) return DrawDepth::yes == dd; } -bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock, +String SceneManager::EnsureUniqueName(CSZ name) +{ + // Compact name: + const char* s = strrchr(name, ':'); + s = s ? s + 1 : name; + const char* e = strrchr(name, '.'); + if (!e) + e = name + strlen(name); + + // Unique name: + int id = -1; + String test; + do + { + test = (id < 0) ? String(s, e) : String(s, e) + "_" + std::to_string(id); + //for (auto& it : TStorePrefabs::_list) if (it.GetName() == _C(test)) test.clear(); + for (auto& it : TStoreBlocks::_list) if (it.GetName() == _C(test)) test.clear(); + for (auto& it : TStoreLights::_list) if (it.GetName() == _C(test)) test.clear(); + //for (auto& it : TStoreEmitters::_list) if (it.GetName() == _C(test)) test.clear(); + id++; + } while (test.empty()); + + return test; +} + +PModel SceneManager::InsertModel(CSZ url) +{ + return TStoreModels::Insert(url); +} + +PModel SceneManager::FindModel(CSZ url) +{ + return TStoreModels::Find(url); +} + +void SceneManager::DeleteModel(CSZ url) +{ + TStoreModels::Delete(url); +} + +void SceneManager::DeleteAllModels() +{ + TStoreModels::DeleteAll(); +} + +PBlock SceneManager::InsertBlock() +{ + return TStoreBlocks::Insert(); +} + +void SceneManager::DeleteBlock(PBlock p) +{ + TStoreBlocks::Delete(p); +} + +void SceneManager::DeleteAllBlocks() +{ + TStoreBlocks::DeleteAll(); +} + +PLight SceneManager::InsertLight() +{ + return TStoreLights::Insert(); +} + +void SceneManager::DeleteLight(PLight p) +{ + TStoreLights::Delete(p); +} + +void SceneManager::DeleteAllLights() +{ + TStoreLights::DeleteAll(); +} + +Continue SceneManager::Octree_ProcessNode(void* pToken, void* pUser) +{ + PSceneNode pSN = static_cast(pToken); + if (pSN->IsHidden()) + return Continue::yes; + _vVisibleNodes[_visibleCount++] = pSN; + _visibleCountPerType[+pSN->GetType()]++; + return Continue::yes; +} + +bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, PBlockPtr pBlock, PPoint3 pPoint, PVector3 pNormal, const float* pRadius, Physics::Group mask) { - //VERUS_RT_ASSERT(!pBlock || *pBlock); + VERUS_RT_ASSERT(!pBlock || *pBlock); VERUS_QREF_BULLET; btVector3 from(pointA.Bullet()), to(pointB.Bullet()); if (pPoint || pNormal) @@ -59,8 +417,8 @@ bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock if (ccrc.hasHit()) { Physics::PUserPtr p = static_cast(ccrc.m_hitCollisionObject->getUserPointer()); - //if (pBlock && p->UserPtr_GetType() == +NodeType::block) - // pBlock->Attach(static_cast(p)); + if (pBlock && p->UserPtr_GetType() == +NodeType::block) + pBlock->Attach(static_cast(p)); if (pPoint) *pPoint = ccrc.m_hitPointWorld; if (pNormal) @@ -78,8 +436,8 @@ bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock if (crrc.hasHit()) { Physics::PUserPtr p = static_cast(crrc.m_collisionObject->getUserPointer()); - //if (pBlock && p->UserPtr_GetType() == +NodeType::block) - // pBlock->Attach(static_cast(p)); + if (pBlock && p->UserPtr_GetType() == +NodeType::block) + pBlock->Attach(static_cast(p)); if (pPoint) *pPoint = crrc.m_hitPointWorld; if (pNormal) @@ -106,8 +464,8 @@ bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock if (arrc.hasHit()) { Physics::PUserPtr p = static_cast(arrc.m_collisionObject->getUserPointer()); - //if (pBlock && p->UserPtr_GetType() == +NodeType::block) - // pBlock->Attach(static_cast(p)); + if (pBlock && p->UserPtr_GetType() == +NodeType::block) + pBlock->Attach(static_cast(p)); return true; } else diff --git a/Verus/src/Scene/SceneManager.h b/Verus/src/Scene/SceneManager.h index 753b967..326742b 100644 --- a/Verus/src/Scene/SceneManager.h +++ b/Verus/src/Scene/SceneManager.h @@ -11,20 +11,52 @@ namespace verus automatic }; - class SceneManager : public Singleton, public Object + typedef StoreUnique TStoreModels; + typedef Store TStoreBlocks; + typedef Store TStoreLights; + class SceneManager : public Singleton, public Object, public Math::OctreeDelegate, + private TStoreModels, private TStoreBlocks, private TStoreLights { - Math::Octree _octree; - PCamera _pCamera = nullptr; - PMainCamera _pMainCamera = nullptr; + Math::Octree _octree; + PCamera _pCamera = nullptr; + PMainCamera _pMainCamera = nullptr; + Vector _vVisibleNodes; + int _visibleCount = 0; + int _visibleCountPerType[+NodeType::count]; public: + struct Desc + { + PMainCamera _pMainCamera = nullptr; + int _mapSide = 256; + + Desc() {} + }; + VERUS_TYPEDEFS(Desc); + + struct Query + { + CSZ _name = nullptr; + CSZ _blockMesh = nullptr; + CSZ _blockMaterial = nullptr; + NodeType _type = NodeType::unknown; + + void Reset() { *this = Query(); } + }; + VERUS_TYPEDEFS(Query); + SceneManager(); virtual ~SceneManager(); - void Init(); + void Init(RcDesc desc = Desc()); void Done(); + void ResetInstanceCount(); + void Update(); void UpdateParts(); + void Layout(); + void Draw(); + void DrawLights(); // Camera: PCamera GetCamera() const { return _pCamera; } @@ -34,7 +66,89 @@ namespace verus static bool IsDrawingDepth(DrawDepth dd); - bool RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock = nullptr, + String EnsureUniqueName(CSZ name); + + // Models: + PModel InsertModel(CSZ url); + PModel FindModel(CSZ url); + void DeleteModel(CSZ url); + void DeleteAllModels(); + + // Blocks: + PBlock InsertBlock(); + void DeleteBlock(PBlock p); + void DeleteAllBlocks(); + + // Lights (and Shadows): + PLight InsertLight(); + void DeleteLight(PLight p); + void DeleteAllLights(); + + template + void ForEachNode(RcQuery query, const T& fn) + { + // Visit PBLE: + //if (NodeType::unknown == query._type || NodeType::prefab == query._type) + //{ + // VERUS_FOREACH_X(TStorePrefabs::TList, TStorePrefabs::_list, it) + // { + // auto& prefab = *it++; + // if (!query._name || prefab.GetName() == query._name) + // if (Continue::yes != fn(prefab)) + // return; + // } + //} + if (NodeType::unknown == query._type || NodeType::block == query._type) + { + VERUS_FOREACH_X(TStoreBlocks::TList, TStoreBlocks::_list, it) + { + auto& block = *it++; + if ( + (!query._name || block.GetName() == query._name) && + (!query._blockMesh || block.GetModel()->GetMesh().GetUrl() == query._blockMesh) && + (!query._blockMaterial || block.GetMaterial()->_name == query._blockMaterial)) + if (Continue::yes != fn(block)) + return; + } + } + if (NodeType::unknown == query._type || NodeType::light == query._type) + { + VERUS_FOREACH_X(TStoreLights::TList, TStoreLights::_list, it) + { + auto& light = *it++; + if (!query._name || light.GetName() == query._name) + if (Continue::yes != fn(light)) + return; + } + } + //if (NodeType::unknown == query._type || NodeType::emitter == query._type) + //{ + // VERUS_FOREACH_X(TStoreEmitters::TList, TStoreEmitters::_list, it) + // { + // auto& emitter = *it++; + // if (!query._name || emitter.GetName() == query._name) + // if (Continue::yes != fn(emitter)) + // return; + // } + //} + } + + template + void ForEachModel(const T& fn) + { + VERUS_FOREACH_X(TStoreModels::TMap, TStoreModels::_map, it) + { + auto& model = *it++; + if (Continue::yes != fn(model.second)) + return; + } + } + + // Octree (Acceleration Structure): + Math::ROctree GetOctree() { return _octree; } + virtual Continue Octree_ProcessNode(void* pToken, void* pUser) override; + + bool RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, PBlockPtr pBlock = nullptr, PPoint3 pPoint = nullptr, PVector3 pNormal = nullptr, const float* pRadius = nullptr, Physics::Group mask = Physics::Group::immovable | Physics::Group::terrain); }; diff --git a/Verus/src/Scene/SceneNodes/Block.cpp b/Verus/src/Scene/SceneNodes/Block.cpp new file mode 100644 index 0000000..1002dba --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Block.cpp @@ -0,0 +1,222 @@ +#include "verus.h" + +using namespace verus; +using namespace verus::Scene; + +// Block: + +Block::Block() +{ + _type = NodeType::block; +} + +Block::~Block() +{ + Done(); +} + +void Block::Init(RcDesc desc) +{ + VERUS_QREF_SM; + _name = sm.EnsureUniqueName(desc._name ? desc._name : desc._model); + _matIndex = desc._matIndex; + _collide = desc._collide; + + Model::Desc modelDesc; + modelDesc._url = desc._model; + modelDesc._mat = desc._modelMat; + _model.Init(modelDesc); + + if (desc._blockMat) + { + Material::Desc matDesc; + matDesc._name = desc._blockMat; + matDesc._load = true; + _material.Init(matDesc); + } + + String url = desc._model; + Str::ReplaceExtension(url, ".Extra.xml"); + Vector vData; + IO::FileSystem::I().LoadResourceFromCache(_C(url), vData, false); + if (vData.size() > 1) + LoadExtra(reinterpret_cast(vData.data())); +} + +void Block::Done() +{ + RemoveRigidBody(); + _material.Done(); + _model.Done(); + SceneManager::I().GetOctree().UnbindClient(this); + _vLights.clear(); + _vEmitters.clear(); +} + +void Block::LoadExtra(CSZ xml) +{ + //tinyxml2::XMLDocument doc; + //doc.Parse(xml); + //if (doc.Error()) + // return; + //tinyxml2::XMLElement* pRoot = doc.FirstChildElement(); + //if (!pRoot) + // return; + // + //int numLights = 0; + //for (pugi::xml_node node = pRoot->FirstChildElement("light"); pElem; pElem = pElem->NextSiblingElement("light")) + //{ + // CSZ mat = pElem->Attribute("mat"); + // if (!mat || atoi(mat) == _matIndex) + // numLights++; + //} + //int numEmitters = 0; + //for (pugi::xml_node node = pRoot->FirstChildElement("emit"); pElem; pElem = pElem->NextSiblingElement("emit")) + // numEmitters++; + // + //_vLights.resize(numLights); + //_vEmitters.resize(numEmitters); + // + //int i = 0; + //for (pugi::xml_node node = pRoot->FirstChildElement("light"); pElem; pElem = pElem->NextSiblingElement("light")) + //{ + // CSZ mat = pElem->Attribute("mat"); + // if (!mat || atoi(mat) == _matIndex) + // { + // RLightPwn light = _vLights[i]._light; + // + // Light::Desc descLight; + // descLight._pLoadXML = pElem; + // light.Init(descLight); + // _vLights[i]._tr = light->GetTransform(); + // light->SetTransform(GetTransform() * _vLights[i]._tr); + // + // i++; + // } + //} + //i = 0; + //for (pugi::xml_node node = pRoot->FirstChildElement("emit"); pElem; pElem = pElem->NextSiblingElement("emit")) + //{ + // REmitterPwn emitter = _vEmitters[i]._emitter; + // + // CEmitter::Desc descEmitter; + // descEmitter._pLoadXML = pElem; + // emitter.Init(descEmitter); + // _vEmitters[i]._tr = emitter->GetTransform(); + // emitter->SetTransform(GetTransform() * _vEmitters[i]._tr); + // + // i++; + //} +} + +void Block::Update() +{ + if (!_async_loadedModel && _model->IsLoaded()) + { + _async_loadedModel = true; + if (!_dynamic) + { + VERUS_QREF_BULLET; + const btTransform tr = GetTransform().Bullet(); + _pBody = bullet.AddNewRigidBody(0, tr, _model->GetMesh().GetShape(), +Physics::Group::immovable); + _pBody->setFriction(Physics::Bullet::GetFriction(Physics::Material::stone)); + _pBody->setRestitution(Physics::Bullet::GetRestitution(Physics::Material::stone)); + _pBody->setUserPointer(this); + SetCollisionGroup(_collide ? Physics::Group::immovable : Physics::Group::general); + } + UpdateBounds(); + } +} + +void Block::Draw() +{ + //_model->Draw(&_tr, _material); +} + +void Block::SetDynamic(bool mode) +{ + SceneNode::SetDynamic(mode); + _octreeBindOnce = false; + _async_loadedModel = false; +} + +MaterialPtr Block::GetMaterial(bool orModelMat) +{ + if (!_material && orModelMat) + return _model->GetMaterial(); + return _material; +} + +void Block::UpdateBounds() +{ + if (_model->IsLoaded()) + { + if (!_octreeBindOnce) + { + _bounds = Math::Bounds::MakeFromOrientedBox(_model->GetMesh().GetBounds(), _tr); + SceneManager::I().GetOctree().BindClient(Math::Octree::Client(_bounds, this), _dynamic); + _octreeBindOnce = _dynamic; + } + if (_dynamic) + { + _bounds = Math::Bounds::MakeFromOrientedBox(_model->GetMesh().GetBounds(), _tr); + SceneManager::I().GetOctree().UpdateDynamicBounds(Math::Octree::Client(_bounds, this)); + } + } + + for (auto& x : _vLights) + x._light->SetTransform(GetTransform() * x._tr); + //for (auto& x : _vEmitters) + // x._emitter->SetTransform(GetTransform() * x._tr); +} + +void Block::SaveXML(pugi::xml_node node) +{ + SceneNode::SaveXML(node); + + node.append_attribute("url") = _C(GetUrl()); + if (_material) + node.append_attribute("mat") = _C(_material->_name); + if (!_userColor.IsZero()) + node.append_attribute("color") = _C(_userColor.ToColorString()); +} + +void Block::LoadXML(pugi::xml_node node) +{ + SceneNode::LoadXML(node); + _name.clear(); + + _userColor = Vector4(0); + if (auto attr = node.attribute("color")) + _userColor.FromColorString(attr.value()); + + Desc desc; + desc._name = node.attribute("name").value(); + desc._model = node.attribute("url").value(); + desc._blockMat = node.attribute("mat").value(); + if (desc._blockMat) + desc._matIndex = atoi(strrchr(desc._blockMat, '.') - 1); + Init(desc); +} + +// BlockPtr: + +void BlockPtr::Init(Block::RcDesc desc) +{ + VERUS_QREF_SM; + VERUS_RT_ASSERT(!_p); + _p = sm.InsertBlock(); + if (desc._node) + _p->LoadXML(desc._node); + else + _p->Init(desc); +} + +void BlockPwn::Done() +{ + if (_p) + { + SceneManager::I().DeleteBlock(_p); + _p = nullptr; + } +} diff --git a/Verus/src/Scene/SceneNodes/Block.h b/Verus/src/Scene/SceneNodes/Block.h new file mode 100644 index 0000000..97b3190 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Block.h @@ -0,0 +1,95 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + class BlockLight + { + public: + Transform3 _tr = Transform3::identity(); + LightPwn _light; + }; + VERUS_TYPEDEFS(BlockLight); + + class BlockEmitter + { + public: + Transform3 _tr = Transform3::identity(); + //CEmitterPwn _emitter; + }; + VERUS_TYPEDEFS(BlockEmitter); + + //! Block is a scene node which has a model and material info. + //! Most blocks form the scene's so called static or immovable geometry. + class Block : public SceneNode + { + Vector4 _userColor = Vector4(0); + Vector _vLights; + Vector _vEmitters; + ModelPwn _model; + MaterialPwn _material; + int _matIndex = 0; + bool _collide = true; + bool _async_loadedModel = false; + + public: + struct Desc + { + pugi::xml_node _node; + CSZ _name = nullptr; + CSZ _model = nullptr; + CSZ _modelMat = nullptr; + CSZ _blockMat = nullptr; + int _matIndex = 0; + bool _collide = true; + }; + VERUS_TYPEDEFS(Desc); + + Block(); + ~Block(); + + void Init(RcDesc desc); + void Done(); + + VERUS_P(void LoadExtra(CSZ xml)); + + virtual void Update() override; + virtual void Draw() override; + + virtual String GetUrl() override { return _C(_model->GetMesh().GetUrl()); } + + bool IsLoadedModel() const { return _model->IsLoaded(); } + + virtual void SetDynamic(bool mode) override; + + virtual void SetColor(RcVector4 color) override { _userColor = color; } + virtual Vector4 GetColor() override { return _userColor; } + ModelPtr GetModel() { return _model; } + MaterialPtr GetMaterial(bool orModelMat = true); + int GetMaterialIndex() const { return _matIndex; } + + virtual void UpdateBounds() override; + + // Serialization: + virtual void SaveXML(pugi::xml_node node) override; + virtual void LoadXML(pugi::xml_node node) override; + }; + VERUS_TYPEDEFS(Block); + + class BlockPtr : public Ptr + { + public: + void Init(Block::RcDesc desc); + }; + VERUS_TYPEDEFS(BlockPtr); + + class BlockPwn : public BlockPtr + { + public: + ~BlockPwn() { Done(); } + void Done(); + }; + VERUS_TYPEDEFS(BlockPwn); + } +} diff --git a/Verus/src/Scene/SceneNodes/Light.cpp b/Verus/src/Scene/SceneNodes/Light.cpp new file mode 100644 index 0000000..5a2a0e4 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Light.cpp @@ -0,0 +1,283 @@ +#include "verus.h" + +using namespace verus; +using namespace verus::Scene; + +// Light: + +Light::Light() +{ + _type = NodeType::light; +} + +Light::~Light() +{ + Done(); +} + +void Light::Init(RcDesc desc) +{ + _data = desc._data; + //if (desc._urlIntShaker) + //{ + // _shaker.Load(desc._urlIntShaker); + // _shaker.Randomize(); + // _shaker.SetScaleBias(0.5f * desc._intShakerScale, 1 - 0.5f * desc._intShakerScale); + // _intMax = GetIntensity(); + //} +} + +void Light::Done() +{ + SceneManager::I().GetOctree().UnbindClient(this); +} + +void Light::Update() +{ + if (!_async_loadedMesh) + { + VERUS_QREF_HELPERS; + RMesh mesh = helpers.GetDeferredLights().Get(_data._lightType); + if (mesh.IsLoaded()) + { + _async_loadedMesh = true; + UpdateBounds(); + } + } + + //if (_shaker.IsLoaded()) + //{ + // _shaker.Update(); + // SetIntensity(_shaker.Get() * _intMax); + //} +} + +void Light::Draw() +{ +} + +void Light::SetLightType(CGI::LightType type) +{ + _data._lightType = type; + ComputeTransform(); +} + +CGI::LightType Light::GetLightType() const +{ + return _data._lightType; +} + +void Light::SetColor(RcVector4 color) +{ + _data._color = color; +} + +Vector4 Light::GetColor() +{ + return _data._color; +} + +void Light::SetIntensity(float i) +{ + _data._color.setW(i); +} + +float Light::GetIntensity() const +{ + return _data._color.getW(); +} + +void Light::SetDirection(RcVector3 dir) +{ + _data._dir = dir; + ComputeTransform(); +} + +RcVector3 Light::GetDirection() const +{ + return _data._dir; +} + +void Light::SetRadius(float r) +{ + _data._radius = r; + ComputeTransform(); +} + +float Light::GetRadius() const +{ + return _data._radius; +} + +void Light::SetCone(float coneIn, float coneOut) +{ + if (coneIn) + _data._coneIn = coneIn; + if (coneOut) + _data._coneOut = coneOut; + VERUS_RT_ASSERT(_data._coneIn >= _data._coneOut); + ComputeTransform(); +} + +float Light::GetConeIn() const +{ + return _data._coneIn; +} + +float Light::GetConeOut() const +{ + return _data._coneOut; +} + +Vector4 Light::GetInstData() const +{ + return Vector4(_data._color.getXYZ() * _data._color.getW(), _data._coneIn); +} + +void Light::DirFromPoint(RcPoint3 point, float radiusScale) +{ + const Vector3 to = point - GetPosition(); + const float len = VMath::length(to); + if (len > VERUS_FLOAT_THRESHOLD) + { + _data._dir = to / len; + if (radiusScale > 0) + _data._radius = len * radiusScale; + } + ComputeTransform(); +} + +void Light::ConeFromPoint(RcPoint3 point, bool coneIn) +{ + const Vector3 to = point - GetPosition(); + const Vector3 dir = VMath::normalize(to); + const float d = VMath::dot(dir, _data._dir); + if (coneIn) + _data._coneIn = d; + else + _data._coneIn = _data._coneOut = Math::Clamp(d, cos(Math::ToRadians(80)), cos(Math::ToRadians(10))); + const float angle = acos(_data._coneOut); + const float minIn = cos(angle - Math::ToRadians(10)); + _data._coneIn = Math::Clamp(_data._coneIn, minIn, 1); + SetCone(_data._coneIn, _data._coneOut); +} + +Transform3 Light::GetTransformNoScale() const +{ + const Matrix3 matR = Matrix3::MakeAimZ(_data._dir); + return Transform3(matR, Vector3(GetPosition())); +} + +void Light::SetTransform(RcTransform3 mat) +{ + _data._dir = VMath::normalize(mat.getCol2()); + const Transform3 tr = VMath::appendScale(mat, ComputeScale()); + SceneNode::SetTransform(tr); +} + +Vector3 Light::ComputeScale() +{ + switch (_data._lightType) + { + case CGI::LightType::dir: + return Vector3::Replicate(1); + case CGI::LightType::omni: + return Vector3::Replicate(_data._radius); + case CGI::LightType::spot: + const float angle = acos(_data._coneOut); + const float scaleXY = tan(angle); + return Vector3(_data._radius * scaleXY, _data._radius * scaleXY, _data._radius); + } + return Vector3::Replicate(_data._radius); +} + +void Light::ComputeTransform() +{ + const Matrix3 matR = Matrix3::MakeAimZ(_data._dir); + const Transform3 tr = VMath::appendScale(Transform3(matR, Vector3(GetPosition())), ComputeScale()); + SceneNode::SetTransform(tr); +} + +void Light::UpdateBounds() +{ + const bool dir = (CGI::LightType::dir == _data._lightType); + const bool octreeRoot = (_dynamic || dir); + + VERUS_QREF_HELPERS; + RMesh mesh = helpers.GetDeferredLights().Get(_data._lightType); + if (mesh.IsLoaded()) + { + if (!_octreeBindOnce) + { + _bounds = Math::Bounds::MakeFromOrientedBox(mesh.GetBounds(), _tr); + SceneManager::I().GetOctree().BindClient(Math::Octree::Client(_bounds, this), octreeRoot); + _octreeBindOnce = octreeRoot; + } + if (_dynamic) + { + _bounds = Math::Bounds::MakeFromOrientedBox(mesh.GetBounds(), _tr); + SceneManager::I().GetOctree().UpdateDynamicBounds(Math::Octree::Client(_bounds, this)); + } + } +} + +void Light::SaveXML(pugi::xml_node node) +{ + SceneNode::SaveXML(node); + + switch (_data._lightType) + { + case CGI::LightType::dir: node.append_attribute("url") = "DIR"; break; + case CGI::LightType::omni: node.append_attribute("url") = "OMNI"; break; + case CGI::LightType::spot: node.append_attribute("url") = "SPOT"; break; + } + node.append_attribute("type") = +_data._lightType; + node.append_attribute("color") = _C(_data._color.ToString(true)); + node.append_attribute("dir") = _C(_data._dir.ToString(true)); + node.append_attribute("radius") = _data._radius; + node.append_attribute("coneIn") = _data._coneIn; + node.append_attribute("coneOut") = _data._coneOut; +} + +void Light::LoadXML(pugi::xml_node node) +{ + SceneNode::LoadXML(node); + _name.clear(); + + Desc desc; + const int type = node.attribute("type").as_int(+CGI::LightType::omni); + desc._data._lightType = static_cast(type); + if (auto attr = node.attribute("color")) + desc._data._color.FromString(attr.value()); + if (auto attr = node.attribute("dir")) + desc._data._dir.FromString(attr.value()); + desc._data._radius = node.attribute("radius").as_float(desc._data._radius); + desc._data._coneIn = node.attribute("coneIn").as_float(desc._data._coneIn); + desc._data._coneOut = node.attribute("coneOut").as_float(desc._data._coneOut); + Init(desc); +} + +// LightPtr: + +void LightPtr::Init(Light::RcDesc desc) +{ + VERUS_QREF_SM; + VERUS_RT_ASSERT(!_p); + _p = sm.InsertLight(); + if (desc._node) + _p->LoadXML(desc._node); + else + { + _p->Init(desc); + _p->SetLightType(desc._data._lightType); // Call ComputeTransform(). + } +} + +void LightPwn::Done() +{ + if (_p) + { + SceneManager::I().DeleteLight(_p); + _p = nullptr; + } +} diff --git a/Verus/src/Scene/SceneNodes/Light.h b/Verus/src/Scene/SceneNodes/Light.h new file mode 100644 index 0000000..d026ef9 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Light.h @@ -0,0 +1,92 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + class LightData + { + public: + Vector4 _color = Vector4::Replicate(1); + Vector3 _dir = Vector3(0, 0, 1); + CGI::LightType _lightType = CGI::LightType::omni; + float _radius = 10; + float _coneIn = cos(Math::ToRadians(35)); // [0, coneOut-10] angle cosine. + float _coneOut = cos(Math::ToRadians(45)); // [10, 80] angle cosine. + }; + VERUS_TYPEDEFS(LightData); + + //! Light is a scene node with light's info. + class Light : public SceneNode + { + LightData _data; + //Anim::CShaker _shaker; + float _intMax = 1; + bool _async_loadedMesh = false; + + public: + struct Desc + { + pugi::xml_node _node; + CSZ _urlIntShaker = nullptr; + float _intShakerScale = 0.25f; + LightData _data; + }; + VERUS_TYPEDEFS(Desc); + + Light(); + ~Light(); + + void Init(RcDesc desc); + void Done(); + + virtual void Update() override; + virtual void Draw() override; + + void SetLightType(CGI::LightType type); + CGI::LightType GetLightType() const; + virtual void SetColor(RcVector4 color) override; + virtual Vector4 GetColor() override; + void SetIntensity(float i); + float GetIntensity() const; + void SetDirection(RcVector3 dir); + RcVector3 GetDirection() const; + void SetRadius(float r); + float GetRadius() const; + void SetCone(float coneIn = 0, float coneOut = 0); + float GetConeIn() const; + float GetConeOut() const; + Vector4 GetInstData() const; + + void DirFromPoint(RcPoint3 point, float radiusScale = 0); + void ConeFromPoint(RcPoint3 point, bool coneIn = false); + + Transform3 GetTransformNoScale() const; + virtual void SetTransform(RcTransform3 mat) override; + VERUS_P(Vector3 ComputeScale()); + VERUS_P(void ComputeTransform()); + + virtual void UpdateBounds() override; + + // Serialization: + virtual void SaveXML(pugi::xml_node node) override; + virtual void LoadXML(pugi::xml_node node) override; + }; + VERUS_TYPEDEFS(Light); + + class LightPtr : public Ptr + { + public: + void Init(Light::RcDesc desc); + }; + VERUS_TYPEDEFS(LightPtr); + + class LightPwn : public LightPtr + { + public: + ~LightPwn() { Done(); } + void Done(); + }; + VERUS_TYPEDEFS(LightPwn); + } +} diff --git a/Verus/src/Scene/SceneNodes/Model.cpp b/Verus/src/Scene/SceneNodes/Model.cpp new file mode 100644 index 0000000..dfd8b67 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Model.cpp @@ -0,0 +1,96 @@ +#include "verus.h" + +using namespace verus; +using namespace verus::Scene; + +// Model: + +Model::Model() +{ +} + +Model::~Model() +{ + Done(); +} + +void Model::Init(RcDesc desc) +{ + if (_refCount) + return; + + VERUS_INIT(); + _refCount = 1; + + Mesh::Desc meshDesc; + meshDesc._url = desc._url; + meshDesc._instanceCapacity = 1000; + meshDesc._initShape = true; + _mesh.Init(meshDesc); + + Material::Desc matDesc; + matDesc._name = desc._mat ? desc._mat : desc._url; + matDesc._load = true; + _material.Init(matDesc); +} + +bool Model::Done() +{ + _refCount--; + if (_refCount <= 0) + { + VERUS_DONE(Model); + return true; + } + return false; +} + +void Model::MarkFirstInstance() +{ + _mesh.MarkFirstInstance(); +} + +void Model::Draw(CGI::CommandBufferPtr cb) +{ + if (!_mesh.IsInstanceBufferEmpty(true)) + { + _mesh.UpdateInstanceBuffer(); + cb->DrawIndexed(_mesh.GetIndexCount(), _mesh.GetInstanceCount(true), 0, 0, _mesh.GetFirstInstance()); + } +} + +void Model::BindPipeline(CGI::CommandBufferPtr cb) +{ + _mesh.BindPipelineInstanced(cb, false); + _mesh.UpdateUniformBufferPerFrame(); +} + +void Model::BindGeo(CGI::CommandBufferPtr cb) +{ + _mesh.BindGeo(cb); + _mesh.UpdateUniformBufferPerMeshVS(); +} + +void Model::PushInstance(RcTransform3 matW, RcVector4 instData) +{ + _mesh.PushInstance(matW, instData); +} + +// ModelPtr: + +void ModelPtr::Init(Model::RcDesc desc) +{ + VERUS_QREF_SM; + VERUS_RT_ASSERT(!_p); + _p = sm.InsertModel(desc._url); + _p->Init(desc); +} + +void ModelPwn::Done() +{ + if (_p) + { + SceneManager::I().DeleteModel(_C(_p->GetMesh().GetUrl())); + _p = nullptr; + } +} diff --git a/Verus/src/Scene/SceneNodes/Model.h b/Verus/src/Scene/SceneNodes/Model.h new file mode 100644 index 0000000..6d366e3 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Model.h @@ -0,0 +1,62 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + //! Model is an element of the scene manager container + //! * has a mesh + //! * has a material + //! * has generic parameters + class Model : public Object + { + Mesh _mesh; + MaterialPwn _material; + IO::Dictionary _dict; + int _refCount = 0; + + public: + struct Desc + { + CSZ _url = nullptr; + CSZ _mat = nullptr; + }; + VERUS_TYPEDEFS(Desc); + + Model(); + ~Model(); + + void Init(RcDesc desc); + bool Done(); + + bool IsLoaded() const { return _mesh.IsLoaded(); } + + void AddRef() { _refCount++; } + + void MarkFirstInstance(); + void Draw(CGI::CommandBufferPtr cb); + void BindPipeline(CGI::CommandBufferPtr cb); + void BindGeo(CGI::CommandBufferPtr cb); + void PushInstance(RcTransform3 matW, RcVector4 instData); + + RMesh GetMesh() { return _mesh; } + MaterialPtr GetMaterial() { return _material; } + }; + VERUS_TYPEDEFS(Model); + + class ModelPtr : public Ptr + { + public: + void Init(Model::RcDesc desc); + }; + VERUS_TYPEDEFS(ModelPtr); + + class ModelPwn : public ModelPtr + { + public: + ~ModelPwn() { Done(); } + void Done(); + }; + VERUS_TYPEDEFS(ModelPwn); + } +} diff --git a/Verus/src/Scene/SceneNodes/SceneNode.cpp b/Verus/src/Scene/SceneNodes/SceneNode.cpp new file mode 100644 index 0000000..e1ba20c --- /dev/null +++ b/Verus/src/Scene/SceneNodes/SceneNode.cpp @@ -0,0 +1,137 @@ +#include "verus.h" + +using namespace verus; +using namespace verus::Scene; + +// SceneNode: + +SceneNode::SceneNode() +{ +} + +SceneNode::~SceneNode() +{ +} + +int SceneNode::UserPtr_GetType() +{ + return +_type; +} + +void SceneNode::DrawBounds() +{ + if (!_bounds.IsNull()) + { + VERUS_QREF_HELPERS; + helpers.DrawBox(&_bounds.GetDrawTransform()); + } +} + +void SceneNode::SetTransform(RcTransform3 tr) +{ + _tr = tr; + // Also update the UI values and bounds: + const Quat q(_tr.getUpper3x3()); + _uiRotation.EulerFromQuaternion(q); + _uiScale = _tr.GetScale(); + UpdateBounds(); +} + +void SceneNode::ComputeTransform() +{ + Quat q; + _uiRotation.EulerToQuaternion(q); + _tr = VMath::appendScale(Transform3(q, _tr.getTranslation()), _uiScale); +} + +Point3 SceneNode::GetPosition() const +{ + return _tr.getTranslation(); +} + +Vector3 SceneNode::GetRotation() const +{ + return _uiRotation; +} + +Vector3 SceneNode::GetScale() const +{ + return _uiScale; +} + +void SceneNode::MoveTo(RcPoint3 pos) +{ + _tr.setTranslation(Vector3(pos)); + UpdateBounds(); +} + +void SceneNode::RotateTo(RcVector3 v) +{ + _uiRotation = v; + ComputeTransform(); + UpdateBounds(); +} + +void SceneNode::ScaleTo(RcVector3 v) +{ + _uiScale = v; + ComputeTransform(); + UpdateBounds(); +} + +void SceneNode::RemoveRigidBody() +{ + if (_pBody) + { + VERUS_QREF_BULLET; + bullet.GetWorld()->removeRigidBody(_pBody); + delete _pBody->getMotionState(); + delete _pBody; + _pBody = nullptr; + } +} + +void SceneNode::SetCollisionGroup(Physics::Group g) +{ + if (_pBody && _pBody->getBroadphaseHandle()->m_collisionFilterGroup != +g) + { + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=7538 + VERUS_QREF_BULLET; + bullet.GetWorld()->removeRigidBody(_pBody); + bullet.GetWorld()->addRigidBody(_pBody, +g, -1); + } +} + +void SceneNode::MoveRigidBody() +{ + if (_pBody) + { + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6729 + VERUS_QREF_BULLET; + _pBody->setWorldTransform(_tr.Bullet()); + bullet.GetWorld()->updateSingleAabb(_pBody); + } +} + +void SceneNode::SaveXML(pugi::xml_node node) +{ + node.append_attribute("name") = _C(_name); + node.append_attribute("uiR") = _C(_uiRotation.ToString(true)); + node.append_attribute("uiS") = _C(_uiScale.ToString(true)); + node.append_attribute("m") = _C(_tr.ToString()); +} + +void SceneNode::LoadXML(pugi::xml_node node) +{ + if (auto attr = node.attribute("name")) + _name = attr.value(); + _uiRotation.FromString(node.attribute("uiR").value()); + _uiScale.FromString(node.attribute("uiS").value()); + _tr.FromString(node.attribute("m").value()); +} + +float SceneNode::GetDistToEyeSq() const +{ + VERUS_QREF_SM; + return VMath::distSqr(sm.GetCamera()->GetEyePosition(), GetPosition()); +} diff --git a/Verus/src/Scene/SceneNodes/SceneNode.h b/Verus/src/Scene/SceneNodes/SceneNode.h new file mode 100644 index 0000000..e49538c --- /dev/null +++ b/Verus/src/Scene/SceneNodes/SceneNode.h @@ -0,0 +1,82 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + //! SceneNode is an element of the scene manager container. + //! * has a name + //! * can be parent or child + //! * has generic parameters + //! * has bounds + //! * can be transformed using the gizmo + class SceneNode : public AllocatorAware, public Physics::UserPtr + { + protected: + Transform3 _tr = Transform3::identity(); //!< Main transformation matrix. + Vector3 _uiRotation = Vector3(0); //!< User-friendly rotation used in editor's UI. + Vector3 _uiScale = Vector3(1, 1, 1); //!< User-friendly scale used in editor's UI. + Math::Bounds _bounds; + IO::Dictionary _dict; + String _name; + String _parent; + btRigidBody* _pBody = nullptr; + NodeType _type = NodeType::unknown; + bool _hidden = false; + bool _dynamic = false; + bool _octreeBindOnce = false; //!< Don't rebind this node after every bounds change. + + public: + SceneNode(); + virtual ~SceneNode(); + + virtual int UserPtr_GetType() override; + + virtual void Update() {} + virtual void Draw() {} + virtual void DrawImmediate() {} + void DrawBounds(); + + Str GetName() const { return _C(_name); } + NodeType GetType() const { return _type; } + virtual String GetUrl() { return ""; } + IO::RDictionary GetDictionary() { return _dict; } + + void Hide(bool hide = true) { _hidden = hide; } + bool IsHidden() const { return _hidden; } + + virtual void SetDynamic(bool mode) { _dynamic = mode; } + bool IsDynamic() const { return _dynamic; } + + virtual Vector4 GetColor() { return Vector4(0); } + virtual void SetColor(RcVector4 color) {} + + RcTransform3 GetTransform() const { return _tr; } + virtual void SetTransform(RcTransform3 tr); + VERUS_P(void ComputeTransform()); + + Point3 GetPosition() const; //!< Gets the position from the main transformation matrix. + Vector3 GetRotation() const; //!< Gets the user-friendly rotation. + Vector3 GetScale() const; //!< Gets the user-friendly scale. + virtual void MoveTo(RcPoint3 pos); + virtual void RotateTo(RcVector3 v); + virtual void ScaleTo(RcVector3 v); + + // Bounds: + Math::RcBounds GetBounds() const { return _bounds; } + virtual void UpdateBounds() {} + + // Physics engine: + void RemoveRigidBody(); + virtual void SetCollisionGroup(Physics::Group g = Physics::Group::immovable); + virtual void MoveRigidBody(); + + // Serialization: + virtual void SaveXML(pugi::xml_node node); + virtual void LoadXML(pugi::xml_node node); + + float GetDistToEyeSq() const; + }; + VERUS_TYPEDEFS(SceneNode); + } +} diff --git a/Verus/src/Scene/SceneNodes/SceneNodes.cpp b/Verus/src/Scene/SceneNodes/SceneNodes.cpp new file mode 100644 index 0000000..cc44d60 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/SceneNodes.cpp @@ -0,0 +1 @@ +#include "verus.h" diff --git a/Verus/src/Scene/SceneNodes/SceneNodes.h b/Verus/src/Scene/SceneNodes/SceneNodes.h new file mode 100644 index 0000000..40d7eb3 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/SceneNodes.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Model.h" +//#include "SceneParticles.h" +#include "Types.h" +#include "SceneNode.h" +#include "TransformGizmo.h" +#include "Light.h" +//#include "Emitter.h" +#include "Block.h" +//#include "Prefab.h" +//#include "Site.h" diff --git a/Verus/src/Scene/SceneNodes/TransformGizmo.cpp b/Verus/src/Scene/SceneNodes/TransformGizmo.cpp new file mode 100644 index 0000000..dd879be --- /dev/null +++ b/Verus/src/Scene/SceneNodes/TransformGizmo.cpp @@ -0,0 +1,54 @@ +#include "verus.h" + +using namespace verus; +using namespace verus::Scene; + +TransformGizmo::TransformGizmo() +{ +} + +TransformGizmo::~TransformGizmo() +{ + Done(); +} + +void TransformGizmo::Init() +{ + VERUS_INIT(); +} + +void TransformGizmo::Done() +{ + VERUS_DONE(TransformGizmo); +} + +void TransformGizmo::Draw() +{ + VERUS_QREF_HELPERS; +} + +void TransformGizmo::DragController_GetParams(float& x, float& y) +{ + x = y = 0; +} + +void TransformGizmo::DragController_SetParams(float x, float y) +{ +} + +void TransformGizmo::DragController_GetRatio(float& x, float& y) +{ + x = y = 0.001f; +} + +void TransformGizmo::DragController_Begin() +{ +} + +void TransformGizmo::DragController_End() +{ +} + +void TransformGizmo::DragController_SetScale(float s) +{ +} diff --git a/Verus/src/Scene/SceneNodes/TransformGizmo.h b/Verus/src/Scene/SceneNodes/TransformGizmo.h new file mode 100644 index 0000000..9dde684 --- /dev/null +++ b/Verus/src/Scene/SceneNodes/TransformGizmo.h @@ -0,0 +1,27 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + class TransformGizmo : public Object, public SceneNode, public Input::DragControllerDelegate + { + public: + TransformGizmo(); + ~TransformGizmo(); + + void Init(); + void Done(); + + void Draw(); + + virtual void DragController_GetParams(float& x, float& y) override; + virtual void DragController_SetParams(float x, float y) override; + virtual void DragController_GetRatio(float& x, float& y) override; + virtual void DragController_Begin() override; + virtual void DragController_End() override; + virtual void DragController_SetScale(float s) override; + }; + VERUS_TYPEDEFS(TransformGizmo); + } +} diff --git a/Verus/src/Scene/SceneNodes/Types.h b/Verus/src/Scene/SceneNodes/Types.h new file mode 100644 index 0000000..790557a --- /dev/null +++ b/Verus/src/Scene/SceneNodes/Types.h @@ -0,0 +1,23 @@ +#pragma once + +namespace verus +{ + namespace Scene + { + //! SceneManager will sort nodes using their type. + enum class NodeType : int + { + unknown, + block, + light, + prefab, + emitter, + site, + terrain, + character, + vehicle, + transformGizmo, + count + }; + } +} diff --git a/Verus/src/Scene/ShadowMap.cpp b/Verus/src/Scene/ShadowMap.cpp index 9e40b7f..834f2e0 100644 --- a/Verus/src/Scene/ShadowMap.cpp +++ b/Verus/src/Scene/ShadowMap.cpp @@ -54,20 +54,20 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar) const Vector3 up(0, 1, 0); Point3 eye, at; - const float size = 4096 * 0.005f; + const float texSizeInMeters = 4096 * 0.005f; if (0 == zFar) zFar = 1001; - at = sm.GetCamera()->GetEyePosition() + sm.GetCamera()->GetFrontDirection() * (size * (1 / 3.f)); + at = sm.GetCamera()->GetEyePosition() + sm.GetCamera()->GetFrontDirection() * (texSizeInMeters * (1 / 3.f)); if (_snapToTexels) { const Matrix4 matToShadowSpace = Matrix4::lookAt(Point3(dirToSun), Point3(0), up); const Matrix4 matFromShadowSpace = VMath::orthoInverse(matToShadowSpace); const Point3 atPosShadowSpace = (matToShadowSpace * at).getXYZ(); - const float texelSize = size / _side; + const float texelSizeInMeters = texSizeInMeters / _side; Point3 atPosShadowSpaceSnapped(atPosShadowSpace); - atPosShadowSpaceSnapped.setX(atPosShadowSpaceSnapped.getX() - fmod(static_cast(atPosShadowSpaceSnapped.getX()), texelSize)); - atPosShadowSpaceSnapped.setY(atPosShadowSpaceSnapped.getY() - fmod(static_cast(atPosShadowSpaceSnapped.getY()), texelSize)); + atPosShadowSpaceSnapped.setX(atPosShadowSpaceSnapped.getX() - fmod(atPosShadowSpaceSnapped.getX(), texelSizeInMeters)); + atPosShadowSpaceSnapped.setY(atPosShadowSpaceSnapped.getY() - fmod(atPosShadowSpaceSnapped.getY(), texelSizeInMeters)); at = (matFromShadowSpace * atPosShadowSpaceSnapped).getXYZ(); } eye = at + dirToSun * ((zFar - zNear) * 0.5f); @@ -79,8 +79,8 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar) _camera.SetFovY(0); _camera.SetZNear(zNear); _camera.SetZFar(zFar); - _camera.SetWidth(size); - _camera.SetHeight(size); + _camera.SetWidth(texSizeInMeters); + _camera.SetHeight(texSizeInMeters); _camera.Update(); _pSceneCamera = sm.SetCamera(&_camera); @@ -239,8 +239,7 @@ 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 texWidthInMeters, texHeightInMeters, texSizeInMeters; float zNearFrustum, zFarFrustum; const float closerToLight = 1500; @@ -267,10 +266,9 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s if (0 == zFar) zFar = abs(zFarFrustum - zNearFrustum) + closerToLight; - sideW = static_cast(frustumBounds.getZ() - frustumBounds.getX() + 2.5f); - sideH = static_cast(frustumBounds.getW() - frustumBounds.getY() + 2.5f); - sizeW = static_cast(sideW); - sizeH = static_cast(sideH); + texWidthInMeters = ceil(frustumBounds.getZ() - frustumBounds.getX() + 2.5f); + texHeightInMeters = ceil(frustumBounds.getW() - frustumBounds.getY() + 2.5f); + texSizeInMeters = Math::Max(texWidthInMeters, texHeightInMeters); // Setup CSM light space camera for full range (used for terrain layout, etc.): _cameraCSM.SetUpDirection(up); @@ -279,8 +277,8 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s _cameraCSM.SetFovY(0); _cameraCSM.SetZNear(zNear); _cameraCSM.SetZFar(zFar); - _cameraCSM.SetWidth(sizeW); - _cameraCSM.SetHeight(sizeH); + _cameraCSM.SetWidth(texSizeInMeters); + _cameraCSM.SetHeight(texSizeInMeters); _cameraCSM.Update(); } @@ -319,26 +317,16 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s (frustumBounds.getY() + frustumBounds.getW()) * 0.5f, zNearFrustum); - sideW = static_cast(frustumBounds.getZ() - frustumBounds.getX() + 2.5f); - sideH = static_cast(frustumBounds.getW() - frustumBounds.getY() + 2.5f); - if (_currentSplit < 3) - { - side = (sideW < sideH) ? sideH : sideW; - side = Math::NextPowerOfTwo(side); - sizeW = static_cast(side); - sizeH = static_cast(side); - } - else - { - sizeW = static_cast(sideW); - sizeH = static_cast(sideH); - } + texWidthInMeters = ceil(frustumBounds.getZ() - frustumBounds.getX() + 2.5f); + texHeightInMeters = ceil(frustumBounds.getW() - frustumBounds.getY() + 2.5f); + texSizeInMeters = Math::Max(texWidthInMeters, texHeightInMeters); if (_snapToTexels) { - const float sideInv = 2.f / _side; - pos.setX(pos.getX() - fmod(static_cast(pos.getX()), sizeW * sideInv)); - pos.setY(pos.getY() - fmod(static_cast(pos.getY()), sizeH * sideInv)); + const float invSide = 2.f / _side; + const float texelSizeInMeters = texSizeInMeters * invSide; + pos.setX(pos.getX() - fmod(pos.getX(), texelSizeInMeters)); + pos.setY(pos.getY() - fmod(pos.getY(), texelSizeInMeters)); } pos = (VMath::orthoInverse(matToLightSpace) * pos).getXYZ(); // To world space. @@ -356,8 +344,8 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s _camera.SetFovY(0); _camera.SetZNear(zNear); _camera.SetZFar(zFar); - _camera.SetWidth(sizeW); - _camera.SetHeight(sizeH); + _camera.SetWidth(texSizeInMeters); + _camera.SetHeight(texSizeInMeters); _camera.Update(); _pSceneCamera = sm.SetCamera(&_camera); diff --git a/Verus/src/Scene/Terrain.cpp b/Verus/src/Scene/Terrain.cpp index f07eec9..0df7e68 100644 --- a/Verus/src/Scene/Terrain.cpp +++ b/Verus/src/Scene/Terrain.cpp @@ -422,6 +422,7 @@ void Terrain::Init(RcDesc desc) VERUS_INIT(); VERUS_QREF_RENDERER; VERUS_QREF_CONST_SETTINGS; + VERUS_QREF_ATMO; if (!Math::IsPowerOfTwo(desc._mapSide)) throw VERUS_RECOVERABLE << "Init(), mapSide must be power of two"; @@ -543,8 +544,17 @@ void Terrain::Init(RcDesc desc) pipeDesc._primitiveRestartEnable = true; _pipe[PIPE_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); + } + { - VERUS_QREF_ATMO; CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#Depth", atmo.GetShadowMap().GetRenderPassHandle()); pipeDesc._colorAttachBlendEqs[0] = ""; _pipe[PIPE_DEPTH_LIST].Init(pipeDesc); @@ -552,6 +562,14 @@ void Terrain::Init(RcDesc desc) pipeDesc._primitiveRestartEnable = true; _pipe[PIPE_DEPTH_STRIP].Init(pipeDesc); } + if (settings._gpuTessellation) + { + CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#DepthTess", atmo.GetShadowMap().GetRenderPassHandle()); + pipeDesc._colorAttachBlendEqs[0] = ""; + pipeDesc._topology = CGI::PrimitiveTopology::patchList3; + _pipe[PIPE_DEPTH_TESS].Init(pipeDesc); + } + { CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], "#SolidColor", renderer.GetDS().GetRenderPassHandle()); pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF; @@ -566,15 +584,6 @@ void Terrain::Init(RcDesc desc) 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; @@ -659,6 +668,11 @@ void Terrain::Done() VERUS_DONE(Terrain); } +void Terrain::ResetInstanceCount() +{ + _instanceCount = 0; +} + void Terrain::Layout() { VERUS_QREF_CONST_SETTINGS; @@ -696,11 +710,12 @@ void Terrain::Draw(RcDrawDesc dd) if (!_visiblePatchCount) return; - auto cb = renderer.GetCommandBuffer(); - const bool drawingDepth = Scene::SceneManager::IsDrawingDepth(Scene::DrawDepth::automatic); const Transform3 matW = Transform3::identity(); + + auto cb = renderer.GetCommandBuffer(); + s_ubTerrainVS._matW = matW.UniformBufferFormat(); s_ubTerrainVS._matWV = Transform3(sm.GetCamera()->GetMatrixV() * matW).UniformBufferFormat(); s_ubTerrainVS._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat(); @@ -709,7 +724,6 @@ void Terrain::Draw(RcDrawDesc dd) 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)) { @@ -738,14 +752,13 @@ void Terrain::Draw(RcDrawDesc dd) if (!lod) { + const bool tess = dd._allowTess && settings._gpuTessellation; 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]); + cb->BindPipeline(_pipe[tess ? PIPE_DEPTH_TESS : PIPE_DEPTH_LIST]); else - cb->BindPipeline(_pipe[PIPE_LIST]); + cb->BindPipeline(_pipe[tess ? PIPE_TESS : PIPE_LIST]); cb->BindDescriptors(s_shader[SHADER_MAIN], 0, _cshVS); cb->BindDescriptors(s_shader[SHADER_MAIN], 1, _cshFS); } @@ -812,15 +825,15 @@ void Terrain::DrawReflection() if (!_visiblePatchCount) return; + const Transform3 matW = Transform3::identity(); + auto cb = renderer.GetCommandBuffer(); - const Transform3 matW = Transform3::identity(); s_ubSimpleTerrainVS._matW = matW.UniformBufferFormat(); s_ubSimpleTerrainVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat(); s_ubSimpleTerrainVS._eyePos = float4(atmo.GetEyePosition().GLM(), 0); s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.x = 1.f / _mapSide; s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.y = static_cast(water.IsUnderwater() ? USHRT_MAX : 0); - VERUS_FOR(i, VERUS_COUNT_OF(_layerData)) s_ubSimpleTerrainFS._vSpecStrength[i >> 2][i & 0x3] = _layerData[i]._specStrength; s_ubSimpleTerrainFS._lamScaleBias.x = _lamScale; @@ -899,11 +912,6 @@ void Terrain::DrawReflection() _geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 1); } -void Terrain::ResetInstanceCount() -{ - _instanceCount = 0; -} - void Terrain::SortVisiblePatches() { std::sort(_vSortedPatchIndices.begin(), _vSortedPatchIndices.begin() + _visiblePatchCount, [this](int a, int b) diff --git a/Verus/src/Scene/Terrain.h b/Verus/src/Scene/Terrain.h index d2247fb..35bc3b4 100644 --- a/Verus/src/Scene/Terrain.h +++ b/Verus/src/Scene/Terrain.h @@ -93,11 +93,14 @@ namespace verus { PIPE_LIST, PIPE_STRIP, + PIPE_TESS, + PIPE_DEPTH_LIST, PIPE_DEPTH_STRIP, + PIPE_DEPTH_TESS, + PIPE_WIREFRAME_LIST, PIPE_WIREFRAME_STRIP, - PIPE_TESS, PIPE_REFLECTION_LIST, PIPE_REFLECTION_STRIP, PIPE_UNDERWATER_LIST, @@ -183,7 +186,7 @@ namespace verus struct DrawDesc { - bool _tess = false; + bool _allowTess = false; bool _wireframe = false; void Reset() @@ -203,12 +206,11 @@ namespace verus void InitByWater(); void Done(); + void ResetInstanceCount(); void Layout(); void Draw(RcDrawDesc dd = DrawDesc()); void DrawReflection(); - void ResetInstanceCount(); - void SortVisiblePatches(); virtual int UserPtr_GetType() override; diff --git a/Verus/src/Scene/Water.cpp b/Verus/src/Scene/Water.cpp index 764ceea..e81ab3c 100644 --- a/Verus/src/Scene/Water.cpp +++ b/Verus/src/Scene/Water.cpp @@ -210,8 +210,6 @@ void Water::Draw() return; } - auto cb = renderer.GetCommandBuffer(); - RCamera cam = *sm.GetCamera(); Transform3 matW; @@ -232,6 +230,8 @@ void Water::Draw() const Matrix4 matWVP = cam.GetMatrixVP() * matW; const Matrix4 matScreen = Matrix4(Math::ToUVMatrix()) * matShift * cam.GetMatrixVP(); + auto cb = renderer.GetCommandBuffer(); + s_ubWaterVS._matW = matW.UniformBufferFormat(); s_ubWaterVS._matVP = cam.GetMatrixVP().UniformBufferFormat(); s_ubWaterVS._matScreen = matScreen.UniformBufferFormat(); @@ -264,15 +264,14 @@ void Water::Draw() memcpy(&s_ubWaterFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubWaterFS._shadowConfig)); s_ubWaterFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM(); + cb->BindPipeline(_pipe[PIPE_MAIN]); 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(); + cb->DrawIndexed(_indexCount); } void Water::OnSwapChainResized() @@ -305,7 +304,7 @@ void Water::BeginReflection(CGI::PBaseCommandBuffer pCB) VERUS_QREF_SM; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); _camera = *sm.GetCamera(); if (!IsUnderwater(_camera.GetEyePosition())) @@ -325,7 +324,7 @@ void Water::EndReflection(CGI::PBaseCommandBuffer pCB) VERUS_QREF_SM; if (!pCB) - pCB = &(*renderer.GetCommandBuffer()); + pCB = renderer.GetCommandBuffer().Get(); pCB->EndRenderPass(); @@ -355,54 +354,50 @@ void Water::GenerateHeightmapTexture() { VERUS_QREF_RENDERER; + auto cb = renderer.GetCommandBuffer(); + 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)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); - _tex[TEX_GEN_HEIGHTMAP]->GenerateMips(&(*cb)); + _tex[TEX_GEN_HEIGHTMAP]->GenerateMips(cb.Get()); } void Water::GenerateNormalsTexture() { VERUS_QREF_RENDERER; + auto cb = renderer.GetCommandBuffer(); + 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)); + renderer.DrawQuad(cb.Get()); cb->EndRenderPass(); - _tex[TEX_GEN_NORMALS]->GenerateMips(&(*cb)); + _tex[TEX_GEN_NORMALS]->GenerateMips(cb.Get()); } CGI::TexturePtr Water::GetCausticsTexture() const diff --git a/Verus/src/Shaders/Bloom.hlsl b/Verus/src/Shaders/Bloom.hlsl index 395a44c..b67ec9d 100644 --- a/Verus/src/Shaders/Bloom.hlsl +++ b/Verus/src/Shaders/Bloom.hlsl @@ -1,13 +1,20 @@ // Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) #include "Lib.hlsl" +#include "LibDeferredShading.hlsl" +#include "LibDepth.hlsl" #include "Bloom.inc.hlsl" -ConstantBuffer g_ubBloomVS : register(b0, space0); -ConstantBuffer g_ubBloomFS : register(b0, space1); +ConstantBuffer g_ubBloomVS : register(b0, space0); +ConstantBuffer g_ubBloomFS : register(b0, space1); +ConstantBuffer g_ubBloomGodRaysFS : register(b0, space2); -Texture2D g_tex : register(t1, space1); -SamplerState g_sam : register(s1, space1); +Texture2D g_tex : register(t1, space1); +SamplerState g_sam : register(s1, space1); +Texture2D g_texDepth : register(t1, space2); +SamplerState g_samDepth : register(s1, space2); +Texture2D g_texShadow : register(t2, space2); +SamplerComparisonState g_samShadow : register(s2, space2); struct VSI { @@ -45,7 +52,51 @@ FSO mainFS(VSO si) const float4 rawColor = g_tex.SampleLevel(g_sam, si.tc0, 0.0); const float3 color = rawColor.rgb * g_ubBloomFS._exposure.x; - so.color.rgb = (color - 1.0) * 0.4; + const float3 bloom = saturate((color - 1.0) * 0.4); + +#ifdef DEF_GOD_RAYS + const float2 ndcPos = ToNdcPos(si.tc0); + const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r; + const float3 posW = DS_GetPosition(rawDepth, g_ubBloomGodRaysFS._matInvVP, ndcPos); + + const float3 eyePos = g_ubBloomGodRaysFS._eyePos.xyz; + const float3 toPosW = posW - eyePos; + const float depth = length(toPosW); + const float3 pickingRayDir = toPosW / depth; + const float strength = pow(saturate(dot(g_ubBloomGodRaysFS._dirToSun.xyz, pickingRayDir)), 7.0) * 0.2; + + float3 godRays = 0.0; + if (strength > 0.0) + { + const float3 rand = Rand(si.pos.xy); + const int sampleCount = 20; + float acc = 0.0; + [unroll] for (int i = 0; i < sampleCount; ++i) + { + const float pickingRayLen = rand.y + i; + const float3 pos = eyePos + pickingRayDir * pickingRayLen; + + const float4 tcShadow = ShadowCoords(float4(pos, 1), g_ubBloomGodRaysFS._matSunShadow, pickingRayLen); + const float shadowMask = SimpleShadowMapCSM( + g_texShadow, + g_samShadow, + tcShadow, + g_ubBloomGodRaysFS._shadowConfig, + g_ubBloomGodRaysFS._splitRanges, + g_ubBloomGodRaysFS._matSunShadow, + g_ubBloomGodRaysFS._matSunShadowCSM1, + g_ubBloomGodRaysFS._matSunShadowCSM2, + g_ubBloomGodRaysFS._matSunShadowCSM3); + acc += shadowMask * step(pickingRayLen, depth); + } + godRays = acc * (1.0 / sampleCount) * g_ubBloomGodRaysFS._sunColor.rgb * g_ubBloomFS._exposure.x * strength; + } + + so.color.rgb = bloom + godRays; +#else + so.color.rgb = bloom; +#endif + so.color.a = 1.0; return so; @@ -53,3 +104,4 @@ FSO mainFS(VSO si) #endif //@main:# +//@main:#GodRays GOD_RAYS diff --git a/Verus/src/Shaders/Bloom.inc.hlsl b/Verus/src/Shaders/Bloom.inc.hlsl index d1ca362..387b1d8 100644 --- a/Verus/src/Shaders/Bloom.inc.hlsl +++ b/Verus/src/Shaders/Bloom.inc.hlsl @@ -10,3 +10,17 @@ VERUS_UBUFFER UB_BloomFS { float4 _exposure; }; + +VERUS_UBUFFER UB_BloomGodRaysFS +{ + matrix _matInvVP; + matrix _matSunShadow; + matrix _matSunShadowCSM1; + matrix _matSunShadowCSM2; + matrix _matSunShadowCSM3; + float4 _shadowConfig; + float4 _splitRanges; + float4 _dirToSun; + float4 _sunColor; + float4 _eyePos; +}; diff --git a/Verus/src/Shaders/Blur.hlsl b/Verus/src/Shaders/Blur.hlsl index e0194bd..581c75d 100644 --- a/Verus/src/Shaders/Blur.hlsl +++ b/Verus/src/Shaders/Blur.hlsl @@ -1,13 +1,20 @@ // Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) #include "Lib.hlsl" +#include "LibDeferredShading.hlsl" +#include "LibDepth.hlsl" #include "Blur.inc.hlsl" -ConstantBuffer g_ubBlurVS : register(b0, space0); -ConstantBuffer g_ubBlurFS : register(b0, space1); +ConstantBuffer g_ubBlurVS : register(b0, space0); +ConstantBuffer g_ubBlurFS : register(b0, space1); +ConstantBuffer g_ubExtraBlurFS : register(b0, space2); -Texture2D g_tex : register(t1, space1); -SamplerState g_sam : register(s1, space1); +Texture2D g_tex : register(t1, space1); +SamplerState g_sam : register(s1, space1); +Texture2D g_texGBuffer1 : register(t1, space2); +SamplerState g_samGBuffer1 : register(s1, space2); +Texture2D g_texDepth : register(t2, space2); +SamplerState g_samDepth : register(s2, space2); struct VSI { @@ -44,9 +51,9 @@ FSO mainFS(VSO si) FSO so; #if _ANISOTROPY_LEVEL > 4 - const int step = 2; + const int stride = 2; #else - const int step = 4; + const int stride = 4; #endif float4 acc = 0.0; @@ -55,7 +62,7 @@ FSO mainFS(VSO si) [unroll] for (int i = -1; i <= 1; i += 2) #else float weightSum = _SINGULARITY_FIX; - [unroll] for (int i = -8; i <= 7; i += step) + [unroll] for (int i = -8; i <= 7; i += stride) #endif { #ifdef DEF_VERTICAL @@ -67,7 +74,7 @@ FSO mainFS(VSO si) #ifdef DEF_SSAO const float weight = 1.0; #else - const float weight = smoothstep(0.0, 1.0, (1.0 - abs(i) * (1.0 / 10.0))); + const float weight = smoothstep(0.0, 1.0, (1.0 - abs(i) * 0.1)); weightSum += weight; #endif @@ -88,7 +95,169 @@ FSO mainFS(VSO si) } #endif +#ifdef _VS +VSO mainAntiAliasingVS(VSI si) +{ + VSO so; + + // Standard quad: + so.pos = float4(mul(si.pos, g_ubBlurVS._matW), 1); + so.tc0 = mul(si.pos, g_ubBlurVS._matV).xy; + + return so; +} +#endif + +#ifdef _FS +FSO mainAntiAliasingFS(VSO si) +{ + FSO so; + + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); + const float3 normalWV = DS_GetNormal(rawGBuffer1); + const float coarseAlpha = normalWV.b * normalWV.b * normalWV.b; + + // + float3 coarseNorm; + float originDeeper; + float depthBasedEdge; + { + const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r; + const float originDepth = ToLinearDepth(rawOriginDepth, g_ubExtraBlurFS._zNearFarEx); + const float4 rawKernelDepths = float4( + g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(-2, +0)).r, // L + g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+0, -2)).r, // T + g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+2, +0)).r, // R + g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+0, +2)).r); // B + const float4 kernelDepths = ToLinearDepth(rawKernelDepths, g_ubExtraBlurFS._zNearFarEx); + const float minDepth = min(min(kernelDepths[0], kernelDepths[1]), min(kernelDepths[2], kernelDepths[3])); + const float equalize = max(1.0 / originDepth, 0.05); + originDeeper = saturate((originDepth - minDepth) * equalize); + const float4 depthOffsets = abs((originDepth - kernelDepths) * equalize); + depthBasedEdge = saturate(dot(depthOffsets, 1.0)); + + const float3 v0 = float3(1, 0, kernelDepths[0] - kernelDepths[2]); + const float3 v1 = float3(0, 1, kernelDepths[3] - kernelDepths[1]); + coarseNorm = normalize(cross(v0, v1)); + } + // + + // + float normalBasedEdge; + { + const float4 rawNrmLT = float4( + g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(-2, +0)).rg, + g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+0, -2)).rg); + const float4 rawNrmRB = float4( + g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+2, +0)).rg, + g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+0, +2)).rg); + const float4 diffA = rawNrmLT - rawNrmRB; + const float4 diffB = rawNrmLT - rawNrmRB.zwxy; + const float4 dots = float4( + dot(diffA.xy, diffA.xy), + dot(diffA.zw, diffA.zw), + dot(diffB.xy, diffB.xy), + dot(diffB.zw, diffB.zw)); + const float maxDot = max(max(dots.x, dots.y), max(dots.z, dots.w)); + normalBasedEdge = saturate(maxDot * maxDot * 10.0); + } + // + + // Directional blur: + const float3 normal = lerp(normalWV, coarseNorm, coarseAlpha * 0.5); + // {y, -x} is perpendicular vector. Also flip Y axis: normal XY to texture UV. + const float3 perp = normal.yxz; + const float omni = max(perp.z * perp.z * perp.z, originDeeper); + const float2 dirs[4] = + { + lerp(perp.xy * +4.0, float2(-0.6, -0.3), omni), + lerp(perp.xy * -2.0, float2(+0.3, -0.6), omni), + lerp(perp.xy * -4.0, float2(-0.3, +0.6), omni), + lerp(perp.xy * +2.0, float2(+0.6, +0.3), omni) + }; + const float2 offsetScale = g_ubExtraBlurFS._textureSize.zw * max(normalBasedEdge, depthBasedEdge); + const float3 kernelColors[4] = + { + g_tex.SampleLevel(g_sam, si.tc0 + dirs[0] * offsetScale, 0.0).rgb, + g_tex.SampleLevel(g_sam, si.tc0 + dirs[1] * offsetScale, 0.0).rgb, + g_tex.SampleLevel(g_sam, si.tc0 + dirs[2] * offsetScale, 0.0).rgb, + g_tex.SampleLevel(g_sam, si.tc0 + dirs[3] * offsetScale, 0.0).rgb + }; + so.color.rgb = (kernelColors[0] + kernelColors[1] + kernelColors[2] + kernelColors[3]) * 0.25; + so.color.a = 1.0; + + return so; +} +#endif + +#ifdef _VS +VSO mainMotionVS(VSI si) +{ + VSO so; + + // Standard quad: + so.pos = float4(mul(si.pos, g_ubBlurVS._matW), 1); + so.tc0 = mul(si.pos, g_ubBlurVS._matV).xy; + + return so; +} +#endif + +#ifdef _FS +FSO mainMotionFS(VSO si) +{ + FSO so; + + const float3 rand = Rand(si.pos.xy); + const float offsetScale = 0.5 + 0.3 * rand.x; // Blur 50% - 80% of frame time. + + const int sampleCount = max(4, _ANISOTROPY_LEVEL); + + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); + + const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r; + const float originDepth = ToLinearDepth(rawOriginDepth, g_ubExtraBlurFS._zNearFarEx); + + float2 tcFrom; + { + const float2 ndcPos = ToNdcPos(si.tc0); + const float3 posW = DS_GetPosition(rawOriginDepth, g_ubExtraBlurFS._matInvVP, ndcPos); + const float4 prevClipSpacePos = mul(float4(posW, 1), g_ubExtraBlurFS._matPrevVP); + const float2 prevNdcPos = prevClipSpacePos.xy / prevClipSpacePos.w; + tcFrom = ToTexCoords(prevNdcPos); + } + + const float2 stride = (si.tc0 - tcFrom) * offsetScale / (sampleCount - 1); + const float2 tcOrigin = lerp(tcFrom, si.tc0, 0.7); + + float4 acc = float4(g_tex.SampleLevel(g_sam, si.tc0, 0.0).rgb, 1); + [unroll] for (int i = 0; i < sampleCount; i++) + { + if (i == sampleCount / 2) + continue; + + const float2 kernelCoords = tcOrigin + stride * i; + + const float rawKernelDepth = g_texDepth.SampleLevel(g_samDepth, kernelCoords, 0.0).r; + const float kernelDepth = ToLinearDepth(rawKernelDepth, g_ubExtraBlurFS._zNearFarEx); + const float kernelDeeper = kernelDepth - originDepth; + const float allowed = saturate(kernelDeeper * 0.2 + 1.0) * rawGBuffer1.a; + const float weight = saturate(kernelDeeper * 0.2) + 1.0; + + const float3 kernelColor = g_tex.SampleLevel(g_sam, kernelCoords, 0.0).rgb; + acc += lerp(0.0, float4(kernelColor * weight, weight), allowed); + } + acc /= acc.a; + + so.color = float4(acc.rgb, 1); + + return so; +} +#endif + //@main:#H //@main:#V VERTICAL //@main:#HSsao SSAO //@main:#VSsao SSAO VERTICAL +//@mainAntiAliasing:#AntiAliasing AA +//@mainMotion:#Motion MOTION diff --git a/Verus/src/Shaders/Blur.inc.hlsl b/Verus/src/Shaders/Blur.inc.hlsl index 81e0c83..86ca560 100644 --- a/Verus/src/Shaders/Blur.inc.hlsl +++ b/Verus/src/Shaders/Blur.inc.hlsl @@ -10,3 +10,11 @@ VERUS_UBUFFER UB_BlurFS { float4 _dummy; }; + +VERUS_UBUFFER UB_ExtraBlurFS +{ + matrix _matInvVP; + matrix _matPrevVP; + float4 _zNearFarEx; + float4 _textureSize; +}; diff --git a/Verus/src/Shaders/DS.hlsl b/Verus/src/Shaders/DS.hlsl index 27b3618..e8c339e 100644 --- a/Verus/src/Shaders/DS.hlsl +++ b/Verus/src/Shaders/DS.hlsl @@ -34,18 +34,18 @@ struct VSI struct VSO { - float4 pos /**/ : SV_Position; - float4 clipSpacePos /**/ : TEXCOORD0; + float4 pos : SV_Position; + float4 clipSpacePos : TEXCOORD0; #if defined(DEF_OMNI) || defined(DEF_SPOT) - float3 radius_radiusSq_invRadiusSq /**/ : TEXCOORD1; - float3 lightPosWV /**/ : TEXCOORD2; + float3 radius_radiusSq_invRadiusSq : TEXCOORD1; + float3 lightPosWV : TEXCOORD2; #endif #if defined(DEF_DIR) || defined(DEF_SPOT) - float4 lightDirWV_invConeDelta /**/ : TEXCOORD3; + float4 lightDirWV_invConeDelta : TEXCOORD3; #endif - float4 color_coneOut /**/ : TEXCOORD4; + float4 color_coneOut : TEXCOORD4; #ifdef DEF_DIR - float3 dirZenithWV /**/ : TEXCOORD5; + float3 dirZenithWV : TEXCOORD5; #endif }; @@ -166,7 +166,7 @@ DS_ACC_FSO mainFS(VSO si) so.target1 = 0.0; #if defined(DEF_OMNI) || defined(DEF_SPOT) - if (lightPosWV.z - posWV.z + radius >= 0.0) // Optimize finite volume lights. + if (posWV.z <= lightPosWV.z + radius) #endif { // Light's diffuse & specular color: @@ -228,10 +228,11 @@ DS_ACC_FSO mainFS(VSO si) float shadowMask = 1.0; { #ifdef DEF_DIR + const float lightPassOffset = saturate((lamScaleBiasWithHair.y - 0.5) * 5.0) * 2.0; float4 config = g_ubShadowFS._shadowConfig; const float lamBiasMask = saturate(lamScaleBiasWithHair.y * config.y); config.y = 1.0 - lamBiasMask; // Keep penumbra blurry. - const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z); + const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z, lightPassOffset); const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubShadowFS._matSunShadow, -posForShadow.z); shadowMask = ShadowMapCSM( g_texShadowCmp, @@ -245,7 +246,6 @@ DS_ACC_FSO mainFS(VSO si) g_ubShadowFS._matSunShadowCSM1, g_ubShadowFS._matSunShadowCSM2, g_ubShadowFS._matSunShadowCSM3); - shadowMask = saturate(shadowMask + saturate(lamScaleBiasWithHair.y - 1.7)); // Light pass effect. #endif } // diff --git a/Verus/src/Shaders/DS_AO.hlsl b/Verus/src/Shaders/DS_AO.hlsl new file mode 100644 index 0000000..7c2786f --- /dev/null +++ b/Verus/src/Shaders/DS_AO.hlsl @@ -0,0 +1,132 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +#include "Lib.hlsl" +#include "LibColor.hlsl" +#include "LibDeferredShading.hlsl" +#include "LibDepth.hlsl" +#include "LibLighting.hlsl" +#include "LibVertex.hlsl" +#include "DS_AO.inc.hlsl" + +ConstantBuffer g_ubAOPerFrame : register(b0, space0); +ConstantBuffer g_ubAOTexturesFS : register(b0, space1); +ConstantBuffer g_ubAOPerMeshVS : register(b0, space2); +VK_PUSH_CONSTANT +ConstantBuffer g_ubAOPerObject : register(b0, space3); + +Texture2D g_texGBuffer1 : register(t1, space1); +SamplerState g_samGBuffer1 : register(s1, space1); +Texture2D g_texDepth : register(t2, space1); +SamplerState g_samDepth : register(s2, space1); + +struct VSI +{ + 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 clipSpacePos : TEXCOORD0; + float3 radius_radiusSq_invRadiusSq : TEXCOORD1; + float3 lightPosWV : TEXCOORD2; + float4 color_coneOut : TEXCOORD3; +}; + +struct FSO +{ + float4 color : SV_Target0; +}; + +#ifdef _VS +VSO mainVS(VSI si) +{ + VSO so; + + // World matrix, instance data: +#ifdef DEF_INSTANCED + const mataff matW = GetInstMatrix( + si.matPart0, + si.matPart1, + si.matPart2); + const float3 color = si.instData.rgb; + const float coneIn = si.instData.a; +#else + const mataff matW = g_ubAOPerObject._matW; + const float3 color = g_ubAOPerObject.rgb; + const float coneIn = g_ubAOPerObject.a; +#endif + + const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubAOPerFrame._matV)); + + const float3x3 matW33 = (float3x3)matW; + const float3x3 matV33 = (float3x3)g_ubAOPerFrame._matV; + const float3x3 matWV33 = (float3x3)matWV; + + const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubAOPerMeshVS._posDeqScale.xyz, g_ubAOPerMeshVS._posDeqBias.xyz); + + const float3 posW = mul(float4(intactPos, 1), matW); + so.pos = mul(float4(posW, 1), g_ubAOPerFrame._matVP); + so.clipSpacePos = so.pos; + + // + const float3 posUnit = mul(float3(0, 0, 1), matW33); // Need to know the scale. + so.radius_radiusSq_invRadiusSq.y = dot(posUnit, posUnit); + so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y); + so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y; + const float4 posOrigin = float4(0, 0, 0, 1); + so.lightPosWV = mul(posOrigin, matWV).xyz; + so.color_coneOut = float4(color, 1.0); + // + + return so; +} +#endif + +#ifdef _FS +FSO mainFS(VSO si) +{ + FSO so; + + so.color = 1.0; + + const float3 ndcPos = si.clipSpacePos.xyz / si.clipSpacePos.w; + + const float2 tc0 = mul(float4(ndcPos.xy, 0, 1), g_ubAOPerFrame._matToUV).xy; + + const float radius = si.radius_radiusSq_invRadiusSq.x; + const float radiusSq = si.radius_radiusSq_invRadiusSq.y; + const float invRadiusSq = si.radius_radiusSq_invRadiusSq.z; + const float3 lightPosWV = si.lightPosWV; + + // GBuffer1: + const float depth = g_texDepth.SampleLevel(g_samDepth, tc0, 0.0).r; + const float3 posWV = DS_GetPosition(depth, g_ubAOPerFrame._matInvP, ndcPos.xy); + + if (posWV.z <= lightPosWV.z + radius) + { + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, tc0, 0.0); + const float3 normalWV = DS_GetNormal(rawGBuffer1); + + const float3 toLightWV = lightPosWV - posWV; + const float3 dirToLightWV = normalize(toLightWV); + const float distToLightSq = dot(toLightWV, toLightWV); + const float lightFalloff = min(0.25, ComputePointLightIntensity(distToLightSq, radiusSq, invRadiusSq)); + + const float nDotL = saturate(0.1 + dot(normalWV, dirToLightWV)); + + so.color = 1.0 - nDotL * lightFalloff; + } + else + { + clip(-1.0); + } + + return so; +} +#endif + +//@main:#InstancedOmni INSTANCED OMNI diff --git a/Verus/src/Shaders/DS_AO.inc.hlsl b/Verus/src/Shaders/DS_AO.inc.hlsl new file mode 100644 index 0000000..b0294b9 --- /dev/null +++ b/Verus/src/Shaders/DS_AO.inc.hlsl @@ -0,0 +1,26 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +VERUS_UBUFFER UB_AOPerFrame +{ + mataff _matToUV; + mataff _matV; + matrix _matVP; + matrix _matInvP; +}; + +VERUS_UBUFFER UB_AOTexturesFS +{ + float4 _dummy; +}; + +VERUS_UBUFFER UB_AOPerMeshVS +{ + float4 _posDeqScale; + float4 _posDeqBias; +}; + +VERUS_UBUFFER UB_AOPerObject +{ + mataff _matW; + float4 _color; +}; diff --git a/Verus/src/Shaders/DS_BakeSprites.hlsl b/Verus/src/Shaders/DS_BakeSprites.hlsl new file mode 100644 index 0000000..a13c835 --- /dev/null +++ b/Verus/src/Shaders/DS_BakeSprites.hlsl @@ -0,0 +1,87 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +#include "Lib.hlsl" +#include "LibDeferredShading.hlsl" +#include "DS_BakeSprites.inc.hlsl" + +ConstantBuffer g_ubBakeSpritesVS : register(b0, space0); +ConstantBuffer g_ubBakeSpritesFS : register(b0, space1); + +Texture2D g_texGBuffer0 : register(t1, space1); +SamplerState g_samGBuffer0 : register(s1, space1); +Texture2D g_texGBuffer1 : register(t2, space1); +SamplerState g_samGBuffer1 : register(s2, space1); +Texture2D g_texGBuffer2 : register(t3, space1); +SamplerState g_samGBuffer2 : register(s3, space1); + +struct VSI +{ + VK_LOCATION_POSITION float4 pos : POSITION; +}; + +struct VSO +{ + float4 pos : SV_Position; + float2 tc0 : TEXCOORD0; +}; + +#ifdef _VS +VSO mainVS(VSI si) +{ + VSO so; + + // Standard quad: + so.pos = float4(mul(si.pos, g_ubBakeSpritesVS._matW), 1); + so.tc0 = mul(si.pos, g_ubBakeSpritesVS._matV).xy; + + return so; +} +#endif + +#ifdef _FS +DS_FSO mainFS(VSO si) +{ + DS_FSO so; + + const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0); + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); + const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0); + + so.target0 = rawGBuffer0; + so.target1 = rawGBuffer1; + so.target2 = rawGBuffer2; + + if (rawGBuffer1.a < 0.5) + { + // Defringe: + float minDist = 1000.0; + [unroll] for (int i = -7; i <= 7; ++i) + { + [unroll] for (int j = -7; j <= 7; ++j) + { + const float2 offset = float2(j, i); + const float dist = dot(offset, offset); + + const float4 rawKernel1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(j, i)); + const float kernelAlpha = rawKernel1.a; + + if (kernelAlpha >= 0.5 && dist < minDist) + { + minDist = dist; + + const float4 rawKernel0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0, int2(j, i)); + const float4 rawKernel2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0, int2(j, i)); + + so.target0 = rawKernel0; + so.target1.rgb = rawKernel1.rgb; + so.target2 = rawKernel2; + } + } + } + } + + return so; +} +#endif + +//@main:# diff --git a/Verus/src/Shaders/DS_BakeSprites.inc.hlsl b/Verus/src/Shaders/DS_BakeSprites.inc.hlsl new file mode 100644 index 0000000..0ef47d7 --- /dev/null +++ b/Verus/src/Shaders/DS_BakeSprites.inc.hlsl @@ -0,0 +1,12 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +VERUS_UBUFFER UB_BakeSpritesVS +{ + mataff _matW; + mataff _matV; +}; + +VERUS_UBUFFER UB_BakeSpritesFS +{ + float4 _dummy; +}; diff --git a/Verus/src/Shaders/DS_Compose.hlsl b/Verus/src/Shaders/DS_Compose.hlsl index 4892dcd..70f54a7 100644 --- a/Verus/src/Shaders/DS_Compose.hlsl +++ b/Verus/src/Shaders/DS_Compose.hlsl @@ -29,8 +29,8 @@ struct VSI struct VSO { - float4 pos : SV_Position; - float2 tc0 : TEXCOORD0; + float4 pos : SV_Position; + float2 tc0 : TEXCOORD0; float2 clipSpacePos : TEXCOORD1; }; @@ -69,13 +69,13 @@ FSO2 mainFS(VSO si) const float2 ndcPos = si.clipSpacePos.xy; - const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0); - const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0); - const float4 rawGBuffer2 = g_texGBuffer2.Sample(g_samGBuffer2, si.tc0); - const float1 rawDepth = g_texDepth.Sample(g_samDepth, si.tc0).r; + const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0); + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); + const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0); + const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r; - const float4 rawAccDiff = g_texAccDiff.Sample(g_samAccDiff, si.tc0); - const float4 rawAccSpec = g_texAccSpec.Sample(g_samAccSpec, si.tc0); + const float4 rawAccDiff = g_texAccDiff.SampleLevel(g_samAccDiff, si.tc0, 0.0); + const float4 rawAccSpec = g_texAccSpec.SampleLevel(g_samAccSpec, si.tc0, 0.0); const float4 accDiff = rawAccDiff; const float4 accSpec = rawAccSpec; @@ -86,13 +86,13 @@ FSO2 mainFS(VSO si) const float3 posW = DS_GetPosition(rawDepth, g_ubComposeFS._matInvVP, ndcPos); const float depth = ToLinearDepth(rawDepth, g_ubComposeFS._zNearFarEx); - const float ssaoDiff = 0.8 + 0.2 * rawGBuffer2.r; + const float ssaoDiff = 0.5 + 0.5 * rawGBuffer2.r; const float ssaoSpec = ssaoDiff; const float ssaoAmb = rawGBuffer2.r; const float3 normalW = mul(normalWV, (float3x3)g_ubComposeFS._matInvV); const float grayAmbient = Grayscale(ambientColor); - const float3 finalAmbientColor = lerp(grayAmbient * 0.5, ambientColor, normalW.y * 0.5 + 0.5); + const float3 finalAmbientColor = lerp(grayAmbient * 0.2, ambientColor, normalW.y * 0.5 + 0.5); const float3 color = albedo * (accDiff.rgb * ssaoDiff + finalAmbientColor * ssaoAmb) + @@ -125,7 +125,7 @@ FSO2 mainFS(VSO si) } // - so.target0.rgb = colorWithFog; + so.target0.rgb = lerp(colorWithFog, albedo, floor(rawDepth)); so.target0.a = 1.0; so.target1 = so.target0; @@ -138,10 +138,10 @@ FSO mainFS(VSO si) { FSO so; - const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0); - const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0); - const float4 rawGBuffer2 = g_texGBuffer2.Sample(g_samGBuffer2, si.tc0); - const float4 rawComposed = g_texDepth.Sample(g_samDepth, si.tc0); + const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0); + const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); + const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0); + const float4 rawComposed = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0); const float3 exposedComposed = rawComposed.rgb * g_ubComposeFS._ambientColor_exposure.a; so.color.rgb = VerusToneMapping(exposedComposed, 0.5); diff --git a/Verus/src/Shaders/DS_Forest.hlsl b/Verus/src/Shaders/DS_Forest.hlsl new file mode 100644 index 0000000..d2f77db --- /dev/null +++ b/Verus/src/Shaders/DS_Forest.hlsl @@ -0,0 +1,137 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +#include "Lib.hlsl" +#include "LibDeferredShading.hlsl" +#include "DS_Forest.inc.hlsl" + +ConstantBuffer g_ubForestVS : register(b0, space0); +ConstantBuffer g_ubForestFS : register(b0, space1); + +Texture2D g_texGBuffer0 : register(t1, space1); +SamplerState g_samGBuffer0 : register(s1, space1); +Texture2D g_texGBuffer1 : register(t2, space1); +SamplerState g_samGBuffer1 : register(s2, space1); +Texture2D g_texGBuffer2 : register(t3, space1); +SamplerState g_samGBuffer2 : register(s3, space1); + +struct VSI +{ + VK_LOCATION_POSITION float4 pos : POSITION; + VK_LOCATION(8) int4 tc0 : TEXCOORD0; +}; + +struct VSO +{ + float4 pos : SV_Position; + float2 tc0 : TEXCOORD0; + float2 angles : TEXCOORD1; + float4 color : COLOR0; + float2 psize : PSIZE; +}; + +#ifdef _VS +VSO mainVS(VSI si) +{ + VSO so; + + const float pointSpriteSize = si.tc0.x / 500.0; + const float angle = si.tc0.y / 32767.0; + + const float3 toEye = g_ubForestVS._eyePos.xyz - si.pos.xyz; + const float distToScreen = length(g_ubForestVS._eyePosScreen.xyz - si.pos.xyz); + + so.pos = mul(si.pos, g_ubForestVS._matWVP); + so.tc0 = 0.0; + so.color.rgb = RandomColor(si.pos.xz, 0.3, 0.2); + so.color.a = saturate((distToScreen - 60.0) / 30.0); + so.psize = pointSpriteSize * (g_ubForestVS._viewportSize.yx * g_ubForestVS._viewportSize.z) * g_ubForestVS._matP._m11; + so.psize *= ceil(so.color.a); // Hide if too close. + + float2 param0 = toEye.xy; + float2 param1 = toEye.zz; + param0.y = max(0.0, param0.y); // Only upper hemisphere. + param1.y = length(toEye.xz); // Distance in XZ-plane. + so.angles.xy = (atan2(param0, param1) + _PI) * (0.5 / _PI); // atan2(x, z) and atan2(max(0.0, y), length(toEye.xz)). From 0 to 1. + so.angles.y = (so.angles.y - 0.5) * 4.0; // Choose this quadrant. + so.angles.xy = saturate(so.angles.xy); + so.angles.x = frac(so.angles.x - angle + 0.5); // Turn. + + return so; +} +#endif + +#ifdef _GS +[maxvertexcount(4)] +void mainGS(point VSO si[1], inout TriangleStream 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 + +float2 ComputeTexCoords(float2 tc, float2 angles) +{ + const float marginBias = 16.0 / 512.0; + const float marginScale = 1.0 - marginBias * 2.0; + const float2 tcMargin = tc * marginScale + marginBias; + + const float2 frameCount = float2(16, 16); + const float2 frameScale = 1.0 / frameCount; + const float2 frameBias = floor(min(angles * frameCount + 0.5, float2(256, frameCount.y - 0.5))); + return (tcMargin + frameBias) * frameScale; +} + +float ComputeMask(float2 tc, float alpha) +{ + const float2 tcCenter = tc - 0.5; + const float rad = saturate(dot(tcCenter, tcCenter) * 4.0); + return saturate(rad + (alpha * 2.0 - 1.0)); +} + +#ifdef _FS +#ifdef DEF_DEPTH +void mainFS(VSO si) +{ + const float2 tc = ComputeTexCoords(si.tc0, si.angles); + const float mask = ComputeMask(si.tc0, si.color.a); + + const float alpha = g_texGBuffer1.Sample(g_samGBuffer1, tc).a; + + clip(alpha * mask - 0.5); +} +#else +DS_FSO mainFS(VSO si) +{ + DS_FSO so; + + const float2 tc = ComputeTexCoords(si.tc0, si.angles); + const float mask = ComputeMask(si.tc0, si.color.a); + + const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, tc); + const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, tc); + const float4 rawGBuffer2 = g_texGBuffer2.Sample(g_samGBuffer2, tc); + + so.target0 = rawGBuffer0; + so.target1 = rawGBuffer1; + so.target2 = rawGBuffer2; + + so.target0.rgb *= si.color.rgb; + so.target2.g = lerp(so.target2.g, 0.25, si.tc0.y); + + clip(rawGBuffer1.a * mask - 0.5); + + return so; +} +#endif +#endif + +//@main:# (VGF) +//@main:#Depth DEPTH (VGF) diff --git a/Verus/src/Shaders/DS_Forest.inc.hlsl b/Verus/src/Shaders/DS_Forest.inc.hlsl new file mode 100644 index 0000000..a297622 --- /dev/null +++ b/Verus/src/Shaders/DS_Forest.inc.hlsl @@ -0,0 +1,15 @@ +// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com) + +VERUS_UBUFFER UB_ForestVS +{ + matrix _matP; + matrix _matWVP; + float4 _viewportSize; + float4 _eyePos; + float4 _eyePosScreen; +}; + +VERUS_UBUFFER UB_ForestFS +{ + float4 _dummy; +}; diff --git a/Verus/src/Shaders/DS_Grass.hlsl b/Verus/src/Shaders/DS_Grass.hlsl index 3930b9b..228e2b7 100644 --- a/Verus/src/Shaders/DS_Grass.hlsl +++ b/Verus/src/Shaders/DS_Grass.hlsl @@ -57,7 +57,7 @@ VSO mainVS(VSI si) float3 intactPos; float3 pos; float2 center; - float2 pointSpriteScale = 1.0; + float2 pointSpriteSize = 1.0; float groundHeight; float3 normal; float2 tc0; @@ -67,8 +67,8 @@ VSO mainVS(VSI si) 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); + pointSpriteSize = intactPos.y; + pos = float3(center.x, 0.45 * pointSpriteSize.y, center.y); #endif const float distToEye = distance(pos + float3(0, si.patchPos.y * 0.01, 0), g_ubGrassVS._posEye.xyz); @@ -146,7 +146,7 @@ VSO mainVS(VSI si) hide = saturate(hide); #ifdef DEF_BILLBOARDS - pointSpriteScale = lerp(pointSpriteScale, float2(0.0, pointSpriteScale.y), hide); + pointSpriteSize = lerp(pointSpriteSize, float2(0.0, pointSpriteSize.y), hide); #else posWarped = lerp(posWarped, float3(center.x, posWarped.y, center.y), hide); // Optimize by morphing to center point. #endif @@ -163,8 +163,7 @@ VSO mainVS(VSI si) #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; + so.psize = pointSpriteSize * (g_ubGrassVS._viewportSize.yx * g_ubGrassVS._viewportSize.z) * g_ubGrassVS._matP._m11; #else so.normal_top.xyz += float3(0, 0, top * top * 0.25); #endif @@ -219,6 +218,7 @@ DS_FSO mainFS(VSO si) DS_SetNormal(so, normal + NormalDither(rand)); DS_SetEmission(so, 0.0, 0.0); + DS_SetMotionBlur(so, 1.0); DS_SetLamScaleBias(so, float2(1.2, -0.2), 0.0); DS_SetMetallicity(so, 0.05, 0.0); diff --git a/Verus/src/Shaders/DS_Mesh.hlsl b/Verus/src/Shaders/DS_Mesh.hlsl index 411da79..50665eb 100644 --- a/Verus/src/Shaders/DS_Mesh.hlsl +++ b/Verus/src/Shaders/DS_Mesh.hlsl @@ -50,12 +50,12 @@ struct VSO { float4 pos : SV_Position; float2 tc0 : TEXCOORD0; + float4 matTBN2 : TEXCOORD1; #if !defined(DEF_DEPTH) float4 color0 : COLOR0; #if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR) - float4 matTBN0 : TEXCOORD1; - float4 matTBN1 : TEXCOORD2; - float4 matTBN2 : TEXCOORD3; + float4 matTBN0 : TEXCOORD2; + float4 matTBN1 : TEXCOORD3; #endif #endif }; @@ -148,12 +148,19 @@ VSO mainVS(VSI si) so.pos = MulTessPos(float4(posW, 1), g_ubPerFrame._matV, g_ubPerFrame._matVP); so.tc0 = intactTc0; + so.matTBN2 = float4(nrmWV, posW.z); +#ifdef DEF_TESS + so.matTBN2.xyz = normalize(so.matTBN2.xyz); +#endif + #if !defined(DEF_DEPTH) so.color0 = userColor; +#ifdef DEF_PLANT + so.color0.rgb = RandomColor(userColor.xz, 0.3, 0.2); +#endif #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); #endif #endif @@ -185,12 +192,12 @@ HSO mainHS(InputPatch inputPatch, uint id : SV_OutputControlPointID) _HS_COPY(pos); _HS_COPY(tc0); + _HS_COPY(matTBN2); #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 @@ -204,16 +211,21 @@ VSO mainDS(_IN_DS) { VSO so; + _DS_INIT_FLAT_POS; _DS_INIT_SMOOTH_POS; - so.pos = ApplyProjection(smoothPosWV, g_ubPerFrame._matP); + const float3 toEyeWV = g_ubPerFrame._eyePosWV_invTessDistSq.xyz - flatPosWV; + const float distToEyeSq = dot(toEyeWV, toEyeWV); + const float tessStrength = 1.0 - saturate(distToEyeSq * g_ubPerFrame._eyePosWV_invTessDistSq.w * 1.1 - 0.1); + const float3 posWV = lerp(flatPosWV, smoothPosWV, tessStrength); + so.pos = ApplyProjection(posWV, g_ubPerFrame._matP); _DS_COPY(tc0); + _DS_COPY(matTBN2); #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 @@ -290,7 +302,11 @@ DS_FSO mainFS(VSO si) const float skinAlpha = PickAlpha(rawAlbedo.rgb, mm_skinPick, 16.0); const float userAlpha = PickAlphaHue(rawAlbedo.rgb, mm_userPick, 32.0); +#ifdef DEF_PLANT + rawAlbedo.rgb *= si.color0.rgb; +#else rawAlbedo.rgb = lerp(rawAlbedo.rgb, Overlay(gray, si.color0.rgb), userAlpha * si.color0.a); +#endif const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * mm_hairDesat)); // @@ -373,20 +389,29 @@ DS_FSO mainFS(VSO si) //@main:# //@main:#Instanced INSTANCED +//@main:#Plant PLANT INSTANCED //@main:#Robotic ROBOTIC //@main:#Skinned SKINNED +//@main:#Tess TESS (VHDF) +//@main:#TessInstanced TESS INSTANCED (VHDF) +//@main:#TessPlant TESS PLANT INSTANCED (VHDF) +//@main:#TessRobotic TESS ROBOTIC (VHDF) +//@main:#TessSkinned TESS SKINNED (VHDF) + //@main:#Depth DEPTH //@main:#DepthInstanced DEPTH INSTANCED +//@main:#DepthPlant DEPTH PLANT INSTANCED //@main:#DepthRobotic DEPTH ROBOTIC //@main:#DepthSkinned DEPTH SKINNED +//@main:#DepthTess DEPTH TESS (VHDF) +//@main:#DepthTessInstanced DEPTH TESS INSTANCED (VHDF) +//@main:#DepthTessPlant DEPTH TESS PLANT INSTANCED (VHDF) +//@main:#DepthTessRobotic DEPTH TESS ROBOTIC (VHDF) +//@main:#DepthTessSkinned DEPTH TESS SKINNED (VHDF) + //@main:#SolidColor SOLID_COLOR //@main:#SolidColorInstanced SOLID_COLOR INSTANCED //@main:#SolidColorRobotic SOLID_COLOR ROBOTIC //@main:#SolidColorSkinned SOLID_COLOR SKINNED - -//@main:#Tess TESS (VHDF) -//@main:#TessInstanced TESS INSTANCED (VHDF) -//@main:#TessRobotic TESS ROBOTIC (VHDF) -//@main:#TessSkinned TESS SKINNED (VHDF) diff --git a/Verus/src/Shaders/DS_Mesh.inc.hlsl b/Verus/src/Shaders/DS_Mesh.inc.hlsl index ebb8204..664df7d 100644 --- a/Verus/src/Shaders/DS_Mesh.inc.hlsl +++ b/Verus/src/Shaders/DS_Mesh.inc.hlsl @@ -6,6 +6,7 @@ VERUS_UBUFFER UB_PerFrame matrix _matVP; matrix _matP; float4 _viewportSize; + float4 _eyePosWV_invTessDistSq; }; VERUS_UBUFFER UB_PerMaterialFS diff --git a/Verus/src/Shaders/DS_Terrain.hlsl b/Verus/src/Shaders/DS_Terrain.hlsl index 24621b9..3e7d4e4 100644 --- a/Verus/src/Shaders/DS_Terrain.hlsl +++ b/Verus/src/Shaders/DS_Terrain.hlsl @@ -292,6 +292,7 @@ DS_FSO mainFS(VSO si) DS_SetNormal(so, normalWV + NormalDither(rand)); DS_SetEmission(so, 0.0, 0.0); + DS_SetMotionBlur(so, 1.0); DS_SetLamScaleBias(so, g_ubTerrainFS._lamScaleBias.xy, float4(0, 0, 1, 0)); DS_SetMetallicity(so, 0.05, 0.0); @@ -304,6 +305,9 @@ DS_FSO mainFS(VSO si) #endif //@main:# -//@main:#Depth DEPTH (V) -//@main:#SolidColor SOLID_COLOR //@main:#Tess TESS (VHDF) + +//@main:#Depth DEPTH (V) +//@main:#DepthTess DEPTH TESS (VHD) + +//@main:#SolidColor SOLID_COLOR diff --git a/Verus/src/Shaders/GenerateMips.hlsl b/Verus/src/Shaders/GenerateMips.hlsl index 8e97277..f441007 100644 --- a/Verus/src/Shaders/GenerateMips.hlsl +++ b/Verus/src/Shaders/GenerateMips.hlsl @@ -22,6 +22,7 @@ struct CSI #define THREAD_GROUP_SIZE 8 +// Width/height even/odd: #define DIM_CASE_WE_HE 0 #define DIM_CASE_WO_HE 1 #define DIM_CASE_WE_HO 2 diff --git a/Verus/src/Shaders/Lib.hlsl b/Verus/src/Shaders/Lib.hlsl index 0ce5f0b..b9b78c0 100644 --- a/Verus/src/Shaders/Lib.hlsl +++ b/Verus/src/Shaders/Lib.hlsl @@ -41,7 +41,7 @@ # define VK_SUBPASS_INPUT(index, tex, sam, t, s, space)\ Texture2D tex : register(t, space);\ SamplerState sam : register(s, space) -# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SampleLevel(sam, tc, 0) +# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SampleLevel(sam, tc, 0.0) # define VK_POINT_SIZE # define VK_SET_POINT_SIZE @@ -76,6 +76,16 @@ matrix ToFloat4x4(mataff m) float4(m[3], 1)); } +float2 ToNdcPos(float2 tc) +{ + return tc * float2(2, -2) - float2(1, -1); +} + +float2 ToTexCoords(float2 ndcPos) +{ + return ndcPos * float2(0.5, -0.5) + 0.5; +} + // Asymmetric abs(): float2 AsymAbs(float2 x, float negScale = -1.0, float posScale = 1.0) { @@ -87,6 +97,19 @@ float3 Rand(float2 uv) return frac(sin(dot(uv, float2(12.9898, 78.233)) * float3(1, 2, 3)) * 43758.5453); } +float4 Rand2(float2 pos) +{ + const float4 primeA = float4(9.907, 9.923, 9.929, 9.931); + const float4 primeB = float4(9.941, 9.949, 9.967, 9.973); + return frac(primeA * pos.x + primeB * pos.y); +} + +float3 RandomColor(float2 pos, float randLum, float randRGB) +{ + const float4 r = Rand2(pos); + return (1.0 - randLum - randRGB) + r.a * randLum + r.rgb * randRGB; +} + float3 NormalDither(float3 rand) { const float2 rr = rand.xy * (1.0 / 333.0) - (0.5 / 333.0); diff --git a/Verus/src/Shaders/LibColor.hlsl b/Verus/src/Shaders/LibColor.hlsl index b7cc7cd..b53ff75 100644 --- a/Verus/src/Shaders/LibColor.hlsl +++ b/Verus/src/Shaders/LibColor.hlsl @@ -90,8 +90,8 @@ float3 ToneMappingACES(float3 x) float3 VerusToneMapping(float3 hdr, float filmicLook = 1.0) { const float maxValue = max(max(hdr.r, hdr.g), hdr.b); - const float desatMask = saturate(maxValue * 0.1); - hdr = lerp(hdr, maxValue, desatMask * desatMask); + const float desatMask = saturate(maxValue * 0.15); + hdr = lerp(hdr, maxValue, desatMask * desatMask); // Color crosstalk. const float3 ldr = lerp(1.0 - exp(-hdr), ToneMappingACES(hdr), filmicLook); return saturate(ldr); } diff --git a/Verus/src/Shaders/LibDeferredShading.hlsl b/Verus/src/Shaders/LibDeferredShading.hlsl index 1316518..ebee59e 100644 --- a/Verus/src/Shaders/LibDeferredShading.hlsl +++ b/Verus/src/Shaders/LibDeferredShading.hlsl @@ -3,8 +3,8 @@ struct DS_FSO { float4 target0 : SV_Target0; // {albedo, spec} - float4 target1 : SV_Target1; // {normal, emission, motion} - float4 target2 : SV_Target2; // {lam, metal, gloss} + float4 target1 : SV_Target1; // {normal, emission + skin, motion} + float4 target2 : SV_Target2; // {lamScaleBias, metal + hair, gloss} }; struct DS_ACC_FSO diff --git a/Verus/src/Shaders/LibDepth.hlsl b/Verus/src/Shaders/LibDepth.hlsl index 2621ee1..719a66e 100644 --- a/Verus/src/Shaders/LibDepth.hlsl +++ b/Verus/src/Shaders/LibDepth.hlsl @@ -7,7 +7,10 @@ float ToLinearDepth(float d, float4 zNearFarEx) // INFO: zNearFarEx.w = zFar*zNear/(zNear-zFar) return zNearFarEx.w / (d - zNearFarEx.z); } - +float2 ToLinearDepth(float2 d, float4 zNearFarEx) +{ + return zNearFarEx.w / (d - zNearFarEx.z); +} float4 ToLinearDepth(float4 d, float4 zNearFarEx) { return zNearFarEx.w / (d - zNearFarEx.z); @@ -21,10 +24,10 @@ float ComputeFog(float depth, float density, float height = 0.0) return 1.0 - saturate(fog); } -float3 AdjustPosForShadow(float3 pos, float3 normal, float3 dirToLight, float depth) +float3 AdjustPosForShadow(float3 pos, float3 normal, float3 dirToLight, float depth, float offset = 0.0) { const float scale = depth - 5.0; - return pos + normal * 0.012 * max(1.0, scale * 0.2) + dirToLight * max(0.0, scale * 0.002); + return pos + normal * 0.012 * max(1.0, scale * 0.2) + dirToLight * max(0.0, scale * 0.002 + offset); } float4 ShadowCoords(float4 pos, matrix mat, float depth) diff --git a/Verus/src/Shaders/LibTessellation.hlsl b/Verus/src/Shaders/LibTessellation.hlsl index 8a59522..9242d60 100644 --- a/Verus/src/Shaders/LibTessellation.hlsl +++ b/Verus/src/Shaders/LibTessellation.hlsl @@ -113,12 +113,13 @@ float3 ComputeBezierPoint(float3 posA, float3 posB, float3 nrmA) // Optimized version of the projection transform: float4 ApplyProjection(float3 posWV, matrix matP) { - float4 clipSpacePos; - clipSpacePos[0] = matP[0][0] * posWV[0]; - clipSpacePos[1] = matP[1][1] * posWV[1]; - clipSpacePos[2] = matP[2][2] * posWV[2] + matP[3][2]; - clipSpacePos[3] = -posWV[2]; - return clipSpacePos; + return mul(float4(posWV, 1), matP); + //float4 clipSpacePos; + //clipSpacePos[0] = matP[0][0] * posWV[0]; + //clipSpacePos[1] = matP[1][1] * posWV[1]; + //clipSpacePos[2] = matP[2][2] * posWV[2] + matP[3][2]; + //clipSpacePos[3] = -posWV[2]; + //return clipSpacePos; } float2 ProjectAndScale(float3 posWV, matrix matP, float2 viewportSize) diff --git a/Verus/src/Shaders/Quad.hlsl b/Verus/src/Shaders/Quad.hlsl index 4af8947..18dcb24 100644 --- a/Verus/src/Shaders/Quad.hlsl +++ b/Verus/src/Shaders/Quad.hlsl @@ -50,5 +50,3 @@ FSO mainFS(VSO si) #endif //@main:# -//@main:#Clear CLEAR -//@main:#Depth DEPTH diff --git a/Verus/src/Shaders/Sky.hlsl b/Verus/src/Shaders/Sky.hlsl index 971d922..53ff34f 100644 --- a/Verus/src/Shaders/Sky.hlsl +++ b/Verus/src/Shaders/Sky.hlsl @@ -152,7 +152,7 @@ FSO mainFS(VSO si) const float4 rawStars = g_texStars.Sample(g_samStars, si.tcStars); const float hdrScale = Grayscale(g_ubPerFrame._ambientColor.xyz) * (10.0 + 5.0 * sunBoost); - so.color = float4(skyColor.rgb * hdrScale + rawStars.rgb * 5.0, 1); + so.color = float4(skyColor.rgb * hdrScale + rawStars.rgb * 20.0, 1); #endif return so; diff --git a/Verus/src/Shaders/Ssao.hlsl b/Verus/src/Shaders/Ssao.hlsl index 9650020..0e9a9fc 100644 --- a/Verus/src/Shaders/Ssao.hlsl +++ b/Verus/src/Shaders/Ssao.hlsl @@ -65,7 +65,7 @@ FSO mainFS(VSO si) { FSO so; - const float3 randNormal = g_texRandNormals.SampleLevel(g_samRandNormals, si.tcNorm, 0.0).xyz * 2.0 - 1.0; + const float3 randNormalWV = g_texRandNormals.SampleLevel(g_samRandNormals, si.tcNorm, 0.0).xyz * 2.0 - 1.0; const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0); const float3 normalWV = DS_GetNormal(rawGBuffer1); @@ -73,25 +73,32 @@ FSO mainFS(VSO si) const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r; const float originDepth = ToLinearDepth(rawDepth, g_ubSsaoFS._zNearFarEx); - const float perspectScale = 1.0 / originDepth; - const float3 scale = 0.025 * float3(perspectScale * g_ubSsaoFS._camScale.xy, 1); + const float smallRad = 0.02; + const float largeRad = 0.06; + const float perspectScale = max(1.0 / originDepth, 0.05); + const float4 scale = float4(smallRad, smallRad, largeRad, largeRad) * perspectScale * g_ubSsaoFS._camScale.xyxy; - float2 acc = float2(0, _SINGULARITY_FIX); + float2 acc = _SINGULARITY_FIX; [unroll] for (uint i = 0; i < 8; i++) { - const float3 randRayWV = reflect(g_rays[i], randNormal); + const float3 randRayWV = reflect(g_rays[i], randNormalWV); const float3 hemiRayWV = randRayWV + normalWV * saturate(-dot(normalWV, randRayWV)) * 2.0; const float nDotR = saturate(dot(normalWV, hemiRayWV)); - const float3 ray = hemiRayWV * scale; - const float rawKernelDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0 + ray.xy, 0.0).r; - const float kernelDepth = ToLinearDepth(rawKernelDepth, g_ubSsaoFS._zNearFarEx); + const float3 smallRay = hemiRayWV * float3(scale.xy, smallRad); + const float3 largeRay = hemiRayWV * float3(scale.zw, largeRad); - const float zOffset = kernelDepth - originDepth + ray.z; - const float visible = step(0.0, zOffset); - const float weight = saturate(0.4 + zOffset * 4.0) * nDotR; + const float2 rawKernelDepths = float2( + g_texDepth.SampleLevel(g_samDepth, si.tc0 + smallRay.xy, 0.0).r, + g_texDepth.SampleLevel(g_samDepth, si.tc0 + largeRay.xy, 0.0).r); + const float2 kernelDepths = ToLinearDepth(rawKernelDepths, g_ubSsaoFS._zNearFarEx); - acc += float2(visible * weight, weight); + const float2 kernelDeeper = kernelDepths - originDepth; + const float2 rayCloser = kernelDeeper + float2(smallRay.z, largeRay.z); + const float2 visible = step(0.0, rayCloser); + const float weight = saturate(1.2 + 5.0 * rayCloser.y) * nDotR; + + acc += float2(min(visible.x, visible.y) * weight, weight); } so.color = acc.x / acc.y; diff --git a/Verus/src/Shaders/WaterGen.hlsl b/Verus/src/Shaders/WaterGen.hlsl index 59c7b27..169b3dc 100644 --- a/Verus/src/Shaders/WaterGen.hlsl +++ b/Verus/src/Shaders/WaterGen.hlsl @@ -70,7 +70,7 @@ FSO mainGenHeightmapFS(VSO si) float accHeight = 0.0; [unroll] for (uint i = 0; i < 4; ++i) { - float height = g_texSourceHeightmap.Sample(g_samSourceHeightmap, (si.tc0 + offsets[i]) * (i / 2 + 1) + g_ubGenHeightmapFS._phase.x * dirs[i]).r - 0.5; + float height = g_texSourceHeightmap.SampleLevel(g_samSourceHeightmap, (si.tc0 + offsets[i]) * (i / 2 + 1) + g_ubGenHeightmapFS._phase.x * dirs[i], 0.0).r - 0.5; height *= amplitudes[i]; // Must be local float4 to work in D3D12! accHeight += height; }