This commit is contained in:
Dmitry 2020-08-02 02:00:00 +03:00
parent 4fac1e6d28
commit d6d07e7883
111 changed files with 4347 additions and 1114 deletions

View File

@ -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);
}

View File

@ -6,6 +6,7 @@ namespace verus
{
class CommandBufferD3D12 : public BaseCommandBuffer
{
ComPtr<ID3D12CommandAllocator> _pOneTimeCommandAllocator;
ComPtr<ID3D12GraphicsCommandList3> _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;

View File

@ -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<PCommandBufferD3D12>(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<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
if (revertState)
{

View File

@ -418,7 +418,7 @@ void RendererD3D12::ImGuiRenderDrawData()
{
VERUS_QREF_RENDERER;
ImGui::Render();
auto pCmdList = static_cast<CommandBufferD3D12*>(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList();
auto pCmdList = static_cast<CommandBufferD3D12*>(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<CommandBufferD3D12*>(&(*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<CommandBufferD3D12*>(&(*renderer.GetCommandBuffer()))->GetD3DGraphicsCommandList() };
ID3D12CommandList* ppCommandLists[] = { static_cast<CommandBufferD3D12*>(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<CommandBufferD3D12*>(p)->GetD3DGraphicsCommandList()->SetDescriptorHeaps(2, ppHeaps);
}

View File

@ -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);
}

View File

@ -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<PCommandBufferD3D12>(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<PCommandBufferD3D12>(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<PCommandBufferD3D12>(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<BYTE*>(p);
BYTE* pSrc = static_cast<BYTE*>(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<PCommandBufferD3D12>(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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -768,7 +768,7 @@ void RendererVulkan::ImGuiRenderDrawData()
{
VERUS_QREF_RENDERER;
ImGui::Render();
VkCommandBuffer commandBuffer = static_cast<CommandBufferVulkan*>(&(*renderer.GetCommandBuffer()))->GetVkCommandBuffer();
VkCommandBuffer commandBuffer = static_cast<CommandBufferVulkan*>(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<CommandBufferVulkan*>(&(*renderer.GetCommandBuffer()))->GetVkCommandBuffer();
VkCommandBuffer commandBuffer = static_cast<CommandBufferVulkan*>(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<PCommandBufferVulkan>(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<PCommandBufferVulkan>(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<PCommandBufferVulkan>(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<PCommandBufferVulkan>(pCB)->GetVkCommandBuffer();
VkBufferImageCopy region = {};

View File

@ -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:

View File

@ -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;

12
Scripts/CompressForest.py Normal file
View File

@ -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)

View File

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.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)</IncludePath>
<LibraryPath>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)</LibraryPath>
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.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)</IncludePath>
<LibraryPath>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)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View File

@ -235,6 +235,13 @@
<ClInclude Include="src\Scene\Scatter.h" />
<ClInclude Include="src\Scene\Scene.h" />
<ClInclude Include="src\Scene\SceneManager.h" />
<ClInclude Include="src\Scene\SceneNodes\Block.h" />
<ClInclude Include="src\Scene\SceneNodes\Light.h" />
<ClInclude Include="src\Scene\SceneNodes\Model.h" />
<ClInclude Include="src\Scene\SceneNodes\SceneNode.h" />
<ClInclude Include="src\Scene\SceneNodes\SceneNodes.h" />
<ClInclude Include="src\Scene\SceneNodes\TransformGizmo.h" />
<ClInclude Include="src\Scene\SceneNodes\Types.h" />
<ClInclude Include="src\Scene\ShadowMap.h" />
<ClInclude Include="src\Scene\Terrain.h" />
<ClInclude Include="src\Scene\Water.h" />
@ -394,6 +401,12 @@
<ClCompile Include="src\Scene\Scatter.cpp" />
<ClCompile Include="src\Scene\Scene.cpp" />
<ClCompile Include="src\Scene\SceneManager.cpp" />
<ClCompile Include="src\Scene\SceneNodes\Block.cpp" />
<ClCompile Include="src\Scene\SceneNodes\Light.cpp" />
<ClCompile Include="src\Scene\SceneNodes\Model.cpp" />
<ClCompile Include="src\Scene\SceneNodes\SceneNode.cpp" />
<ClCompile Include="src\Scene\SceneNodes\SceneNodes.cpp" />
<ClCompile Include="src\Scene\SceneNodes\TransformGizmo.cpp" />
<ClCompile Include="src\Scene\ShadowMap.cpp" />
<ClCompile Include="src\Scene\Terrain.cpp" />
<ClCompile Include="src\Scene\Water.cpp" />
@ -727,6 +740,30 @@
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_AO.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_AO.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_Forest.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Forest.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -94,6 +94,9 @@
<Filter Include="src\Effects">
<UniqueIdentifier>{5ea015f8-8b97-4159-ad67-d71abdba3c91}</UniqueIdentifier>
</Filter>
<Filter Include="src\Scene\SceneNodes">
<UniqueIdentifier>{07af1a9e-5cdc-4264-811b-d958ec70a709}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\CGI\BaseGeometry.h">
@ -645,6 +648,27 @@
<ClInclude Include="src\Scene\Scatter.h">
<Filter>src\Scene</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\Block.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\Light.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\Model.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\SceneNode.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\SceneNodes.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\TransformGizmo.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
<ClInclude Include="src\Scene\SceneNodes\Types.h">
<Filter>src\Scene\SceneNodes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -1094,6 +1118,24 @@
<ClCompile Include="src\Scene\Scatter.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\Block.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\Light.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\Model.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\SceneNode.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\SceneNodes.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
<ClCompile Include="src\Scene\SceneNodes\TransformGizmo.cpp">
<Filter>src\Scene\SceneNodes</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Lib.hlsl">
@ -1222,6 +1264,18 @@
<None Include="src\Shaders\Bloom.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_AO.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_AO.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml.natvis">
@ -1234,4 +1288,12 @@
<Filter>src\ThirdParty\imgui</Filter>
</Natvis>
</ItemGroup>
<ItemGroup>
<FxCompile Include="src\Shaders\DS_Forest.hlsl">
<Filter>src\Shaders</Filter>
</FxCompile>
<FxCompile Include="src\Shaders\DS_Forest.inc.hlsl">
<Filter>src\Shaders</Filter>
</FxCompile>
</ItemGroup>
</Project>

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -161,8 +161,8 @@ void BaseRenderer::SetAlphaBlendHelper(
}
else
{
alphaBlendOp = colorBlendOp;
srcAlphaBlendFactor = srcColorBlendFactor;
dstAlphaBlendFactor = dstColorBlendFactor;
alphaBlendOp = 0;
srcAlphaBlendFactor = 1;
dstAlphaBlendFactor = 0;
}
}

View File

@ -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;

View File

@ -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>(pipe + 1);
auto cb = renderer.GetCommandBuffer();
cb->BindVertexBuffers(_geo);
cb->BindPipeline(_pipe[pipe]);
cb->BindVertexBuffers(_geo);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
_shader->EndBindDescriptors();

View File

@ -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<float>(renderer.GetSwapChainWidth() / 2);
const float h = static_cast<float>(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<float>(renderer.GetSwapChainWidth()), static_cast<float>(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<float>(renderer.GetSwapChainWidth()), static_cast<float>(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<int>(size.getX());
const int h = static_cast<int>(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);
}

View File

@ -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_COUNT> _shader;
PipelinePwns<PIPE_COUNT> _pipe;
TexturePwns<TEX_COUNT> _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);
}

View File

@ -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();

View File

@ -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());

View File

@ -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;

View File

@ -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();
}

View File

@ -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_COUNT> _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();

View File

@ -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);
}

View File

@ -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_COUNT> _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);

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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<int>(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<int>(wcslen(text));
int width = 0;
VERUS_FOR(i, len)
{

View File

@ -101,7 +101,6 @@ void Image::Draw()
cb->BindDescriptors(shader, 0);
cb->BindDescriptors(shader, 1, _solidColor ? CGI::CSHandle() : _csh);
shader->EndBindDescriptors();
renderer.DrawQuad();
}

View File

@ -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;

View File

@ -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();

View File

@ -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();
}

View File

@ -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());
}
}

View File

@ -19,7 +19,7 @@ WideStr Widget::GetText() const
void Widget::SetText(CWSZ text)
{
if (_fixedTextLength)
wcsncpy(_vFixedText.data(), text, Math::Min<int>(wcslen(text), _fixedTextLength - 1));
wcsncpy(_vFixedText.data(), text, Math::Min<int>(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();
}

View File

@ -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)

View File

@ -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:

View File

@ -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()

View File

@ -185,18 +185,25 @@ namespace verus
bool operator==(const Ptr<T>& that) const { return _p == that._p; }
bool operator!=(const Ptr<T>& that) const { return _p != that._p; }
bool operator<(const Ptr<T>& 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<typename T, int COUNT>

View File

@ -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;

View File

@ -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<String>& pieces);
static void Trim(RString s);

View File

@ -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)
{

View File

@ -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);

View File

@ -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<Entity>, _vEntities, it)
VERUS_WHILE(Vector<Client>, _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;
}
}

View File

@ -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<Entity> _vEntities;
Vector<Client> _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<Node> _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]));

View File

@ -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<Entity>, _vEntities, it)
VERUS_WHILE(Vector<Client>, _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<Node>, _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;
}
}

View File

@ -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<Entity> _vEntities;
Vector<Client> _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]));

View File

@ -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);
}

View File

@ -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)
// <Sky>
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());
// </Sky>
@ -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);
}
// </Sun>
@ -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);
}
// </Moon>
// <Clouds>
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());
// </Clouds>
}

View File

@ -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<BYTE> vMesh;
IO::FileSystem::LoadResource(_C(filename), vMesh);
btBulletWorldImporter bwi(0);
if (!vMesh.empty() && bwi.loadFileFromMemory(reinterpret_cast<char*>(vMesh.data()), Utils::Cast32(vMesh.size())))
{
const int count = bwi.getNumCollisionShapes();
if (count)
_pShape = static_cast<btBvhTriangleMeshShape*>(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 };

View File

@ -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;

View File

@ -3,9 +3,9 @@
using namespace verus;
using namespace verus::Scene;
CGI::ShaderPwn Forest::s_shader;
//CGI::CStateBlockPwns<Forest::SB_MAX> 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<Vertex> 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<int>(psize * 500, 0, SHRT_MAX);
v._tc[1] = Math::Clamp<int>(instance._angle * SHRT_MAX / VERUS_2PI, 0, SHRT_MAX);
v._tc[0] = Math::Clamp<int>(static_cast<int>(psize * 500), 0, SHRT_MAX);
v._tc[1] = Math::Clamp<int>(static_cast<int>(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<UINT32> 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<BYTE*>(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<float>(j * frameSide + framePad),
static_cast<float>(i * frameSide + framePad),
static_cast<float>(frameSide - framePad * 2),
static_cast<float>(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<UINT32> 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<float>((ratio - 0.1f) / 0.8f, 0, 1);
const float distFractionSq = distSq / maxDistSq;
const float alignToNormal = (1 - distFractionSq) * plant._alignToNormal;
const float t = Math::Clamp<float>((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<float>((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<float>((1 - distFractionSq) * 1.25f, 0, 1);
matScale = Matrix3::scale(Vector3(strength, 0.5f + 0.5f * strength, strength));
}
else
{
const float strength = Math::Clamp<float>((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;
}

View File

@ -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_COUNT> _tex;
CGI::CSHandle _csh;
Vector<BakedChunk> _vBakedChunks;
Vector<float> _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<SB_MAX> ms_sb;
static UB_ForestVS s_ubForestVS;
static UB_ForestFS s_ubForestFS;
PTerrain _pTerrain = nullptr;
CGI::GeometryPwn _geo;
Math::Octree _octree;
Scatter _scatter;
Vector<Plant> _vPlants;
Vector<LayerPlants> _vLayerPlants;
Vector<DrawPlant> _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_COUNT> _pipe;
Math::Octree _octree;
Scatter _scatter;
Vector<Plant> _vPlants;
Vector<LayerPlants> _vLayerPlants;
Vector<DrawPlant> _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;

View File

@ -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;

View File

@ -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;

View File

@ -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)));

View File

@ -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);
}

View File

@ -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; }

View File

@ -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)

View File

@ -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"

View File

@ -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<PBlock>(pA);
PBlock pBlockB = static_cast<PBlock>(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<PLight>(pA);
PLight pLightB = static_cast<PLight>(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<PBlock>(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<PLight>(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<PSceneNode>(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<Physics::PUserPtr>(ccrc.m_hitCollisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
if (pBlock && p->UserPtr_GetType() == +NodeType::block)
pBlock->Attach(static_cast<PBlock>(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<Physics::PUserPtr>(crrc.m_collisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
if (pBlock && p->UserPtr_GetType() == +NodeType::block)
pBlock->Attach(static_cast<PBlock>(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<Physics::PUserPtr>(arrc.m_collisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
if (pBlock && p->UserPtr_GetType() == +NodeType::block)
pBlock->Attach(static_cast<PBlock>(p));
return true;
}
else

View File

@ -11,20 +11,52 @@ namespace verus
automatic
};
class SceneManager : public Singleton<SceneManager>, public Object
typedef StoreUnique<String, Model> TStoreModels;
typedef Store<Block> TStoreBlocks;
typedef Store<Light> TStoreLights;
class SceneManager : public Singleton<SceneManager>, 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<PSceneNode> _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<typename T>
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<typename T>
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);
};

View File

@ -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<BYTE> vData;
IO::FileSystem::I().LoadResourceFromCache(_C(url), vData, false);
if (vData.size() > 1)
LoadExtra(reinterpret_cast<CSZ>(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;
}
}

View File

@ -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<BlockLight> _vLights;
Vector<BlockEmitter> _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<Block>
{
public:
void Init(Block::RcDesc desc);
};
VERUS_TYPEDEFS(BlockPtr);
class BlockPwn : public BlockPtr
{
public:
~BlockPwn() { Done(); }
void Done();
};
VERUS_TYPEDEFS(BlockPwn);
}
}

View File

@ -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<float>(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<float>(_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<CGI::LightType>(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;
}
}

View File

@ -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<Light>
{
public:
void Init(Light::RcDesc desc);
};
VERUS_TYPEDEFS(LightPtr);
class LightPwn : public LightPtr
{
public:
~LightPwn() { Done(); }
void Done();
};
VERUS_TYPEDEFS(LightPwn);
}
}

View File

@ -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;
}
}

View File

@ -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<Model>
{
public:
void Init(Model::RcDesc desc);
};
VERUS_TYPEDEFS(ModelPtr);
class ModelPwn : public ModelPtr
{
public:
~ModelPwn() { Done(); }
void Done();
};
VERUS_TYPEDEFS(ModelPwn);
}
}

View File

@ -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());
}

View File

@ -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);
}
}

View File

@ -0,0 +1 @@
#include "verus.h"

View File

@ -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"

View File

@ -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)
{
}

View File

@ -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);
}
}

View File

@ -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
};
}
}

View File

@ -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<float>(atPosShadowSpaceSnapped.getX()), texelSize));
atPosShadowSpaceSnapped.setY(atPosShadowSpaceSnapped.getY() - fmod(static_cast<float>(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<int>(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
sideH = static_cast<int>(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
sizeW = static_cast<float>(sideW);
sizeH = static_cast<float>(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<int>(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
sideH = static_cast<int>(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
if (_currentSplit < 3)
{
side = (sideW < sideH) ? sideH : sideW;
side = Math::NextPowerOfTwo(side);
sizeW = static_cast<float>(side);
sizeH = static_cast<float>(side);
}
else
{
sizeW = static_cast<float>(sideW);
sizeH = static_cast<float>(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<float>(pos.getX()), sizeW * sideInv));
pos.setY(pos.getY() - fmod(static_cast<float>(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);

View File

@ -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<float>(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)

View File

@ -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;

View File

@ -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

View File

@ -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<UB_BloomVS> g_ubBloomVS : register(b0, space0);
ConstantBuffer<UB_BloomFS> g_ubBloomFS : register(b0, space1);
ConstantBuffer<UB_BloomVS> g_ubBloomVS : register(b0, space0);
ConstantBuffer<UB_BloomFS> g_ubBloomFS : register(b0, space1);
ConstantBuffer<UB_BloomGodRaysFS> 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

View File

@ -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;
};

View File

@ -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<UB_BlurVS> g_ubBlurVS : register(b0, space0);
ConstantBuffer<UB_BlurFS> g_ubBlurFS : register(b0, space1);
ConstantBuffer<UB_BlurVS> g_ubBlurVS : register(b0, space0);
ConstantBuffer<UB_BlurFS> g_ubBlurFS : register(b0, space1);
ConstantBuffer<UB_ExtraBlurFS> 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;
// <DepthBased>
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));
}
// </DepthBased>
// <NormalBased>
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);
}
// </NormalBased>
// 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

View File

@ -10,3 +10,11 @@ VERUS_UBUFFER UB_BlurFS
{
float4 _dummy;
};
VERUS_UBUFFER UB_ExtraBlurFS
{
matrix _matInvVP;
matrix _matPrevVP;
float4 _zNearFarEx;
float4 _textureSize;
};

View File

@ -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
}
// </Shadow>

View File

@ -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<UB_AOPerFrame> g_ubAOPerFrame : register(b0, space0);
ConstantBuffer<UB_AOTexturesFS> g_ubAOTexturesFS : register(b0, space1);
ConstantBuffer<UB_AOPerMeshVS> g_ubAOPerMeshVS : register(b0, space2);
VK_PUSH_CONSTANT
ConstantBuffer<UB_AOPerObject> 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;
// <MoreAOParams>
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);
// </MoreAOParams>
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

View File

@ -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;
};

View File

@ -0,0 +1,87 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
#include "Lib.hlsl"
#include "LibDeferredShading.hlsl"
#include "DS_BakeSprites.inc.hlsl"
ConstantBuffer<UB_BakeSpritesVS> g_ubBakeSpritesVS : register(b0, space0);
ConstantBuffer<UB_BakeSpritesFS> 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:#

View File

@ -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;
};

View File

@ -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)
}
// </Fog>
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);

View File

@ -0,0 +1,137 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
#include "Lib.hlsl"
#include "LibDeferredShading.hlsl"
#include "DS_Forest.inc.hlsl"
ConstantBuffer<UB_ForestVS> g_ubForestVS : register(b0, space0);
ConstantBuffer<UB_ForestFS> 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<VSO> stream)
{
VSO so;
so = si[0];
const float2 center = so.pos.xy;
for (int i = 0; i < 4; ++i)
{
so.pos.xy = center + _POINT_SPRITE_POS_OFFSETS[i] * so.psize;
so.tc0.xy = _POINT_SPRITE_TEX_COORDS[i];
stream.Append(so);
}
}
#endif
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)

View File

@ -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;
};

View File

@ -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);

View File

@ -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<VSO, 3> 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));
// <Gloss>
@ -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)

View File

@ -6,6 +6,7 @@ VERUS_UBUFFER UB_PerFrame
matrix _matVP;
matrix _matP;
float4 _viewportSize;
float4 _eyePosWV_invTessDistSq;
};
VERUS_UBUFFER UB_PerMaterialFS

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