2022.6
This commit is contained in:
parent
2d2672829e
commit
11c10dbe14
Binary file not shown.
Binary file not shown.
|
@ -46,7 +46,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{26bd6e61-e36d-464a-a312-4110adf10083}</ProjectGuid>
|
||||
<RootNamespace>HelloTexturedCube</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{bc17acd3-97eb-4d5c-a2c9-574cdaa7576b}</ProjectGuid>
|
||||
<RootNamespace>HelloTriangle</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}</ProjectGuid>
|
||||
<RootNamespace>PAKBuilder</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -42,8 +42,8 @@ void TraverseDirectory(CWSZ parentDir, CWSZ foundDir, IO::RFile pakFile);
|
|||
|
||||
void Run()
|
||||
{
|
||||
std::wcout << _T("PACK Builder 1.2.1") << std::endl;
|
||||
std::wcout << _T("Copyright (c) 2006-2020 Dmitry Maluev") << std::endl;
|
||||
std::wcout << _T("PACK Builder 1.3") << std::endl;
|
||||
std::wcout << _T("Copyright (c) 2006-2022 Dmitry Maluev") << std::endl;
|
||||
std::wcout << _T("Arguments: [PAK/folder name] [input directory] [PAK output directory]") << std::endl;
|
||||
|
||||
int argCount;
|
||||
|
|
|
@ -17,6 +17,7 @@ Verus Engine is a modern, platform-agnostic 3D game engine. It is developed usin
|
|||
* Native cross-platform code
|
||||
* Same HLSL shader code for all APIs
|
||||
* Deferred shading
|
||||
* PBR/GGX with Metallic-Roughness workflow
|
||||
* Efficient textures and streaming
|
||||
* Large terrain support
|
||||
* Built-in audio system
|
||||
|
@ -39,6 +40,7 @@ You can download the latest version of VerusEdit here: https://verushub.com/page
|
|||
These features should be implemented in version **1.x**:
|
||||
|
||||
- [x] glTF file format support
|
||||
- [x] Materials v2.0: PBR/GGX with Metallic-Roughness workflow
|
||||
- [ ] Shadow maps for all lights
|
||||
- [ ] Triggers
|
||||
- [ ] Quest system, dialogue system
|
||||
|
@ -47,11 +49,11 @@ These features should be implemented in version **1.x**:
|
|||
- [ ] Waypoints and A-Star navigation
|
||||
- [ ] Lua scripting
|
||||
- [ ] Linux support
|
||||
- [ ] OpenXR
|
||||
|
||||
These features should be implemented in version **2.x**:
|
||||
|
||||
- [ ] Signed distance field (SDF) fonts
|
||||
- [ ] Materials v2.0: separate textures for gloss, emission, etc.
|
||||
- [ ] Ray tracing
|
||||
- [ ] Mesh shaders
|
||||
- [ ] Multithreaded renderer
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{53923514-84B2-4B78-889A-8709C6BFA3A5}</ProjectGuid>
|
||||
<RootNamespace>RendererDirect3D12</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -20,6 +20,7 @@ void CommandBufferD3D12::Init()
|
|||
|
||||
_vClearValues.reserve(16);
|
||||
_vAttachmentStates.reserve(4);
|
||||
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
|
||||
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
|
||||
_pCommandLists[i] = pRendererD3D12->CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, pRendererD3D12->GetD3DCommandAllocator(i));
|
||||
}
|
||||
|
@ -31,6 +32,8 @@ void CommandBufferD3D12::Done()
|
|||
VERUS_COM_RELEASE_CHECK(_pCommandLists[i].Get());
|
||||
_pCommandLists[i].Reset();
|
||||
}
|
||||
VERUS_RT_ASSERT(_vAttachmentStates.capacity() < 100);
|
||||
VERUS_RT_ASSERT(_vBarriers.capacity() < 1000);
|
||||
VERUS_DONE(CommandBufferD3D12);
|
||||
}
|
||||
|
||||
|
@ -77,6 +80,24 @@ void CommandBufferD3D12::End()
|
|||
throw VERUS_RUNTIME_ERROR << "Close(); hr=" << VERUS_HR(hr);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers)
|
||||
{
|
||||
auto& texD3D12 = static_cast<RTextureD3D12>(*tex);
|
||||
_vBarriers.clear();
|
||||
_vBarriers.reserve(mipLevels.GetCount() * arrayLayers.GetCount());
|
||||
for (int layer : arrayLayers)
|
||||
{
|
||||
for (int mip : mipLevels)
|
||||
{
|
||||
const UINT subresource = D3D12CalcSubresource(mip, layer, 0, texD3D12.GetMipLevelCount(), texD3D12.GetArrayLayerCount());
|
||||
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
texD3D12.GetD3DResource(), ToNativeImageLayout(oldLayout), ToNativeImageLayout(newLayout), subresource));
|
||||
}
|
||||
}
|
||||
if (!_vBarriers.empty())
|
||||
GetD3DGraphicsCommandList()->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
|
||||
{
|
||||
VERUS_QREF_RENDERER_D3D12;
|
||||
|
@ -120,62 +141,37 @@ void CommandBufferD3D12::EndRenderPass()
|
|||
{
|
||||
auto pCmdList = GetD3DGraphicsCommandList();
|
||||
|
||||
CD3DX12_RESOURCE_BARRIER barriers[VERUS_MAX_CA];
|
||||
int barrierCount = 0;
|
||||
_vBarriers.clear();
|
||||
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
|
||||
int index = 0;
|
||||
for (const auto& attachment : _pRenderPass->_vAttachments)
|
||||
{
|
||||
if (_vAttachmentStates[index] != attachment._finalState)
|
||||
{
|
||||
const auto& resources = _pFramebuffer->_vResources[index];
|
||||
const auto& resource = _pFramebuffer->_vResources[index];
|
||||
UINT subresource = 0;
|
||||
switch (_pFramebuffer->_cubeMapFace)
|
||||
if (CubeMapFace::none != _pFramebuffer->_cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: subresource = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
|
||||
case CubeMapFace::none: subresource = 0; break;
|
||||
default: subresource = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
|
||||
UINT arrayLayer = 0;
|
||||
switch (_pFramebuffer->_cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: arrayLayer = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
|
||||
default: arrayLayer = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
|
||||
}
|
||||
subresource = D3D12CalcSubresource(0, arrayLayer, 0, _pFramebuffer->_mipLevels, 0);
|
||||
}
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState, subresource);
|
||||
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[index], attachment._finalState, subresource));
|
||||
}
|
||||
index++;
|
||||
if (VERUS_MAX_CA == barrierCount)
|
||||
{
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
barrierCount = 0;
|
||||
}
|
||||
}
|
||||
if (barrierCount)
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
if (!_vBarriers.empty())
|
||||
pCmdList->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
|
||||
|
||||
_pRenderPass = nullptr;
|
||||
_pFramebuffer = nullptr;
|
||||
_subpassIndex = 0;
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
|
||||
{
|
||||
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
|
||||
D3D12_VERTEX_BUFFER_VIEW views[VERUS_MAX_VB];
|
||||
const int count = geoD3D12.GetVertexBufferCount();
|
||||
int filteredCount = 0;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
if ((bindingsFilter >> i) & 0x1)
|
||||
{
|
||||
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
|
||||
views[filteredCount] = *geoD3D12.GetD3DVertexBufferView(i);
|
||||
filteredCount++;
|
||||
}
|
||||
}
|
||||
GetD3DGraphicsCommandList()->IASetVertexBuffers(0, filteredCount, views);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BindIndexBuffer(GeometryPtr geo)
|
||||
{
|
||||
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
|
||||
GetD3DGraphicsCommandList()->IASetIndexBuffer(geoD3D12.GetD3DIndexBufferView());
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BindPipeline(PipelinePtr pipe)
|
||||
{
|
||||
auto pCmdList = GetD3DGraphicsCommandList();
|
||||
|
@ -228,6 +224,30 @@ void CommandBufferD3D12::SetBlendConstants(const float* p)
|
|||
GetD3DGraphicsCommandList()->OMSetBlendFactor(p);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
|
||||
{
|
||||
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
|
||||
D3D12_VERTEX_BUFFER_VIEW views[VERUS_MAX_VB];
|
||||
const int count = geoD3D12.GetVertexBufferCount();
|
||||
int filteredCount = 0;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
if ((bindingsFilter >> i) & 0x1)
|
||||
{
|
||||
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
|
||||
views[filteredCount] = *geoD3D12.GetD3DVertexBufferView(i);
|
||||
filteredCount++;
|
||||
}
|
||||
}
|
||||
GetD3DGraphicsCommandList()->IASetVertexBuffers(0, filteredCount, views);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::BindIndexBuffer(GeometryPtr geo)
|
||||
{
|
||||
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
|
||||
GetD3DGraphicsCommandList()->IASetIndexBuffer(geoD3D12.GetD3DIndexBufferView());
|
||||
}
|
||||
|
||||
bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
|
||||
{
|
||||
bool copyDescOnly = false;
|
||||
|
@ -276,21 +296,6 @@ void CommandBufferD3D12::PushConstants(ShaderPtr shader, int offset, int size, c
|
|||
GetD3DGraphicsCommandList()->SetGraphicsRoot32BitConstants(0, size, p, offset);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer)
|
||||
{
|
||||
auto& texD3D12 = static_cast<RTextureD3D12>(*tex);
|
||||
CD3DX12_RESOURCE_BARRIER rb[16];
|
||||
VERUS_RT_ASSERT(mipLevels.GetCount() <= VERUS_COUNT_OF(rb));
|
||||
int index = 0;
|
||||
for (int mip : mipLevels)
|
||||
{
|
||||
const UINT subresource = D3D12CalcSubresource(mip, arrayLayer, 0, texD3D12.GetMipLevelCount(), texD3D12.GetArrayLayerCount());
|
||||
rb[index++] = CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
texD3D12.GetD3DResource(), ToNativeImageLayout(oldLayout), ToNativeImageLayout(newLayout), subresource);
|
||||
}
|
||||
GetD3DGraphicsCommandList()->ResourceBarrier(index, rb);
|
||||
}
|
||||
|
||||
void CommandBufferD3D12::Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
|
||||
{
|
||||
GetD3DGraphicsCommandList()->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
|
||||
|
@ -334,54 +339,62 @@ void CommandBufferD3D12::PrepareSubpass()
|
|||
RP::RcD3DFramebufferSubpass fs = _pFramebuffer->_vSubpasses[_subpassIndex];
|
||||
|
||||
// Resource transitions for this subpass:
|
||||
CD3DX12_RESOURCE_BARRIER barriers[VERUS_MAX_FB_ATTACH];
|
||||
int resIndex = 0;
|
||||
int barrierCount = 0;
|
||||
UINT subresource = 0;
|
||||
switch (_pFramebuffer->_cubeMapFace)
|
||||
_vBarriers.clear();
|
||||
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
|
||||
int index = 0;
|
||||
auto CalcSubresource = [this](int index) -> UINT
|
||||
{
|
||||
case CubeMapFace::all: subresource = ToNativeCubeMapFace(static_cast<CubeMapFace>(resIndex)); break;
|
||||
case CubeMapFace::none: subresource = 0; break;
|
||||
default: subresource = !resIndex ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
|
||||
}
|
||||
if (CubeMapFace::none == _pFramebuffer->_cubeMapFace)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT arrayLayer = 0;
|
||||
switch (_pFramebuffer->_cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: arrayLayer = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
|
||||
default: arrayLayer = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
|
||||
}
|
||||
return D3D12CalcSubresource(0, arrayLayer, 0, _pFramebuffer->_mipLevels, 0);
|
||||
}
|
||||
};
|
||||
VERUS_FOR(i, subpass._vInput.size())
|
||||
{
|
||||
const auto& ref = subpass._vInput[i];
|
||||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
|
||||
const auto& resources = fs._vResources[resIndex];
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
const auto& resource = fs._vResources[index];
|
||||
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
resIndex++;
|
||||
index++;
|
||||
}
|
||||
VERUS_FOR(i, subpass._vColor.size())
|
||||
{
|
||||
const auto& ref = subpass._vColor[i];
|
||||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
|
||||
const auto& resources = fs._vResources[resIndex];
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
const auto& resource = fs._vResources[index];
|
||||
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
resIndex++;
|
||||
index++;
|
||||
}
|
||||
if (subpass._depthStencil._index >= 0)
|
||||
{
|
||||
const auto& ref = subpass._depthStencil;
|
||||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
}
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
if (!_vBarriers.empty())
|
||||
pCmdList->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
|
||||
|
||||
// Clear attachments for this subpass:
|
||||
int index = 0;
|
||||
index = 0;
|
||||
for (const auto& ref : subpass._vColor)
|
||||
{
|
||||
const auto& attachment = _pRenderPass->_vAttachments[ref._index];
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace verus
|
|||
RP::PcD3DFramebuffer _pFramebuffer = nullptr;
|
||||
Vector<FLOAT> _vClearValues;
|
||||
Vector<D3D12_RESOURCE_STATES> _vAttachmentStates;
|
||||
Vector<D3D12_RESOURCE_BARRIER> _vBarriers;
|
||||
int _subpassIndex = 0;
|
||||
|
||||
public:
|
||||
|
@ -28,23 +29,24 @@ namespace verus
|
|||
virtual void Begin() override;
|
||||
virtual void End() override;
|
||||
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers) override;
|
||||
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
|
||||
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
|
||||
virtual void NextSubpass() override;
|
||||
virtual void EndRenderPass() override;
|
||||
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) override;
|
||||
|
||||
virtual void BindPipeline(PipelinePtr pipe) override;
|
||||
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth) override;
|
||||
virtual void SetScissor(std::initializer_list<Vector4> il) override;
|
||||
virtual void SetBlendConstants(const float* p) override;
|
||||
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) override;
|
||||
|
||||
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
|
||||
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
|
||||
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer) override;
|
||||
|
||||
virtual void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) override;
|
||||
virtual void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) override;
|
||||
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ) override;
|
||||
|
|
|
@ -132,7 +132,11 @@ DXGI_FORMAT CGI::ToNativeFormat(Format format, bool typeless)
|
|||
case Format::unormBC1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case Format::unormBC2: return DXGI_FORMAT_BC2_UNORM;
|
||||
case Format::unormBC3: return DXGI_FORMAT_BC3_UNORM;
|
||||
case Format::unormBC4: return DXGI_FORMAT_BC4_UNORM;
|
||||
case Format::unormBC5: return DXGI_FORMAT_BC5_UNORM;
|
||||
case Format::unormBC7: return DXGI_FORMAT_BC7_UNORM;
|
||||
case Format::snormBC4: return DXGI_FORMAT_BC4_SNORM;
|
||||
case Format::snormBC5: return DXGI_FORMAT_BC5_SNORM;
|
||||
case Format::srgbBC1: return DXGI_FORMAT_BC1_UNORM_SRGB;
|
||||
case Format::srgbBC2: return DXGI_FORMAT_BC2_UNORM_SRGB;
|
||||
case Format::srgbBC3: return DXGI_FORMAT_BC3_UNORM_SRGB;
|
||||
|
@ -177,6 +181,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
{
|
||||
VERUS_RT_ASSERT(components >= 1 && components <= 4);
|
||||
int index = components - 1;
|
||||
|
||||
static const DXGI_FORMAT floats[] =
|
||||
{
|
||||
DXGI_FORMAT_R32_FLOAT,
|
||||
|
@ -184,6 +189,24 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT
|
||||
};
|
||||
static const DXGI_FORMAT halfs[] =
|
||||
{
|
||||
DXGI_FORMAT_R16_FLOAT,
|
||||
DXGI_FORMAT_R16G16_FLOAT,
|
||||
DXGI_FORMAT_R16G16_FLOAT,
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||
};
|
||||
static const DXGI_FORMAT shorts[] =
|
||||
{
|
||||
DXGI_FORMAT_R16G16_SINT,
|
||||
DXGI_FORMAT_R16G16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R16G16_SNORM,
|
||||
DXGI_FORMAT_R16G16_SNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM
|
||||
};
|
||||
static const DXGI_FORMAT bytes[] =
|
||||
{
|
||||
DXGI_FORMAT_R8G8B8A8_UINT,
|
||||
|
@ -199,17 +222,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
DXGI_FORMAT_R8G8B8A8_SNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM
|
||||
};
|
||||
static const DXGI_FORMAT shorts[] =
|
||||
{
|
||||
DXGI_FORMAT_R16G16_SINT,
|
||||
DXGI_FORMAT_R16G16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R16G16_SNORM,
|
||||
DXGI_FORMAT_R16G16_SNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ViaType::floats:
|
||||
|
@ -217,15 +230,10 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
return floats[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::ubytes:
|
||||
case ViaType::halfs:
|
||||
{
|
||||
VERUS_RT_ASSERT(4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal: index += 8; break; // SNORM.
|
||||
case ViaUsage::color: index += 4; break; // UNORM.
|
||||
}
|
||||
return bytes[index];
|
||||
VERUS_RT_ASSERT(3 != components);
|
||||
return halfs[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::shorts:
|
||||
|
@ -233,6 +241,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
VERUS_RT_ASSERT(2 == components || 4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal:
|
||||
case ViaUsage::tangent:
|
||||
case ViaUsage::binormal:
|
||||
index += 4; break; // SNORM.
|
||||
|
@ -240,6 +249,21 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
return shorts[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::ubytes:
|
||||
{
|
||||
VERUS_RT_ASSERT(4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal:
|
||||
case ViaUsage::tangent:
|
||||
case ViaUsage::binormal:
|
||||
index += 8; break; // SNORM.
|
||||
case ViaUsage::color:
|
||||
index += 4; break; // UNORM.
|
||||
}
|
||||
return bytes[index];
|
||||
}
|
||||
break;
|
||||
default: throw VERUS_RECOVERABLE << "ToNativeFormat(); ViaType=?";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace verus
|
|||
Vector<D3DFramebufferSubpass> _vSubpasses;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
int _mipLevels = 1;
|
||||
CubeMapFace _cubeMapFace = CubeMapFace::none;
|
||||
};
|
||||
VERUS_TYPEDEFS(D3DFramebuffer);
|
||||
|
|
|
@ -187,6 +187,7 @@ void RendererD3D12::InitD3D()
|
|||
|
||||
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
|
||||
allocatorDesc.pDevice = _pDevice.Get();
|
||||
allocatorDesc.pAdapter = pAdapter.Get();
|
||||
if (FAILED(hr = D3D12MA::CreateAllocator(&allocatorDesc, &_pMaAllocator)))
|
||||
throw VERUS_RUNTIME_ERROR << "CreateAllocator(); hr=" << VERUS_HR(hr);
|
||||
|
||||
|
@ -732,7 +733,9 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
|
|||
return texD3D12.GetD3DResource();
|
||||
}
|
||||
else
|
||||
{
|
||||
return _vSwapChainBuffers[swapChainBufferIndex].Get();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -750,7 +753,9 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
|
|||
return texD3D12.GetDescriptorHeapRTV().AtCPU(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _dhSwapChainBuffersRTVs.AtCPU(swapChainBufferIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -787,7 +792,11 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
|
|||
|
||||
framebuffer._vResources.reserve(renderPass._vAttachments.size());
|
||||
VERUS_FOR(i, renderPass._vAttachments.size())
|
||||
{
|
||||
if (!i && -1 == swapChainBufferIndex)
|
||||
framebuffer._mipLevels = vTex.front()->GetMipLevelCount();
|
||||
framebuffer._vResources.push_back(GetResource(i));
|
||||
}
|
||||
|
||||
framebuffer._vSubpasses.reserve(renderPass._vSubpasses.size());
|
||||
for (const auto& subpass : renderPass._vSubpasses)
|
||||
|
|
|
@ -75,14 +75,15 @@ namespace verus
|
|||
// Which graphics API?
|
||||
virtual Gapi GetGapi() override { return Gapi::direct3D12; }
|
||||
|
||||
// Frame cycle:
|
||||
// <FrameCycle>
|
||||
virtual void BeginFrame(bool present) override;
|
||||
virtual void EndFrame(bool present) override;
|
||||
virtual void Present() override;
|
||||
virtual void Sync(bool present) override;
|
||||
virtual void WaitIdle() override;
|
||||
// </FrameCycle>
|
||||
|
||||
// Resources:
|
||||
// <Resources>
|
||||
virtual PBaseCommandBuffer InsertCommandBuffer() override;
|
||||
virtual PBaseGeometry InsertGeometry() override;
|
||||
virtual PBasePipeline InsertPipeline() override;
|
||||
|
@ -104,6 +105,7 @@ namespace verus
|
|||
int GetNextFramebufferIndex() const;
|
||||
RP::RcD3DRenderPass GetRenderPass(RPHandle handle) const;
|
||||
RP::RcD3DFramebuffer GetFramebuffer(FBHandle handle) const;
|
||||
// </Resources>
|
||||
|
||||
RDynamicDescriptorHeap GetViewHeap() { return _dhViews; }
|
||||
RDynamicDescriptorHeap GetSamplerHeap() { return _dhSamplers; }
|
||||
|
|
|
@ -401,7 +401,7 @@ void ShaderD3D12::CreatePipelineLayout()
|
|||
_pRootSignature->SetName(_C(Str::Utf8ToWide("RootSignature (" + _sourceName + ")")));
|
||||
}
|
||||
|
||||
CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
|
||||
CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers)
|
||||
{
|
||||
VERUS_QREF_RENDERER_D3D12;
|
||||
|
||||
|
@ -442,7 +442,9 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
|
|||
for (auto x : il)
|
||||
{
|
||||
complexSet._vTextures.push_back(x);
|
||||
const int mip = pMips ? pMips[index] : 0;
|
||||
const int mipLevelCount = x->GetMipLevelCount();
|
||||
const int mipLevel = pMipLevels ? pMipLevels[index] : 0;
|
||||
const int arrayLayer = pArrayLayers ? pArrayLayers[index] : 0;
|
||||
auto& texD3D12 = static_cast<RTextureD3D12>(*x);
|
||||
if (Sampler::storage == dsd._vSamplers[index])
|
||||
{
|
||||
|
@ -450,14 +452,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
|
|||
{
|
||||
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(complexSet._hpBase._hCPU, 1 + index, pRendererD3D12->GetViewHeap().GetHandleIncrementSize()),
|
||||
texD3D12.GetDescriptorHeapUAV().AtCPU(mip),
|
||||
texD3D12.GetDescriptorHeapUAV().AtCPU(mipLevel + arrayLayer * (mipLevelCount - 1)),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
else
|
||||
{
|
||||
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
|
||||
complexSet._dhViews.AtCPU(index),
|
||||
texD3D12.GetDescriptorHeapUAV().AtCPU(mip),
|
||||
texD3D12.GetDescriptorHeapUAV().AtCPU(mipLevel + arrayLayer * (mipLevelCount - 1)),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
}
|
||||
|
@ -467,14 +469,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
|
|||
{
|
||||
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(complexSet._hpBase._hCPU, 1 + index, pRendererD3D12->GetViewHeap().GetHandleIncrementSize()),
|
||||
texD3D12.GetDescriptorHeapSRV().AtCPU(mip),
|
||||
texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
else
|
||||
{
|
||||
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
|
||||
complexSet._dhViews.AtCPU(index),
|
||||
texD3D12.GetDescriptorHeapSRV().AtCPU(mip),
|
||||
texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
if (Sampler::custom == dsd._vSamplers[index])
|
||||
|
@ -578,7 +580,7 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, in
|
|||
if (dsd._offset + dsd._alignedSize > dsd._capacityInBytes)
|
||||
{
|
||||
VERUS_RT_FAIL("UniformBuffer is full.");
|
||||
return CD3DX12_GPU_DESCRIPTOR_HANDLE();
|
||||
return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
|
||||
}
|
||||
|
||||
VERUS_RT_ASSERT(dsd._pMappedData);
|
||||
|
@ -629,9 +631,9 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateSamplers(int setNumber, int com
|
|||
|
||||
auto& dsd = _vDescriptorSetDesc[setNumber];
|
||||
if (dsd._staticSamplersOnly)
|
||||
return CD3DX12_GPU_DESCRIPTOR_HANDLE();
|
||||
return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
|
||||
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE hOffset = CD3DX12_GPU_DESCRIPTOR_HANDLE();
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE hOffset(D3D12_DEFAULT);
|
||||
const auto& complexSet = _vComplexSets[complexSetHandle];
|
||||
const int maxCount = Utils::Cast32(complexSet._vTextures.size());
|
||||
VERUS_FOR(i, maxCount)
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace verus
|
|||
|
||||
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
|
||||
virtual void CreatePipelineLayout() override;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers) override;
|
||||
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
|
||||
|
||||
virtual void BeginBindDescriptors() override;
|
||||
|
|
|
@ -21,26 +21,29 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
VERUS_QREF_RENDERER_D3D12;
|
||||
HRESULT hr = 0;
|
||||
|
||||
_initAtFrame = renderer.GetFrameCount();
|
||||
if (desc._name)
|
||||
_name = desc._name;
|
||||
// Variables:
|
||||
_size = Vector4(
|
||||
float(desc._width),
|
||||
float(desc._height),
|
||||
1.f / desc._width,
|
||||
1.f / desc._height);
|
||||
if (desc._name)
|
||||
_name = desc._name;
|
||||
_desc = desc;
|
||||
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
|
||||
_initAtFrame = renderer.GetFrameCount();
|
||||
if (desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
|
||||
|
||||
_desc._mipLevels = _desc._mipLevels ? _desc._mipLevels : Math::ComputeMipLevels(_desc._width, _desc._height, _desc._depth);
|
||||
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
|
||||
const bool depthFormat = IsDepthFormat(desc._format);
|
||||
const bool depthFormat = IsDepthFormat(_desc._format);
|
||||
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
|
||||
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
|
||||
if (cubeMap)
|
||||
_desc._arrayLayers *= +CubeMapFace::count;
|
||||
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
|
||||
// Create:
|
||||
D3D12_RESOURCE_DESC resDesc = {};
|
||||
resDesc.Dimension = (_desc._depth > 1) ? D3D12_RESOURCE_DIMENSION_TEXTURE3D : D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
resDesc.Width = _desc._width;
|
||||
|
@ -58,7 +61,6 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
if (!depthSampled)
|
||||
resDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_STATES initialResourceState = ToNativeImageLayout(_mainLayout);
|
||||
D3D12_CLEAR_VALUE clearValue = {};
|
||||
clearValue.Format = ToNativeFormat(_desc._format, false);
|
||||
|
@ -83,8 +85,10 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT); hr=" << VERUS_HR(hr);
|
||||
_resource._pResource->SetName(_C(Str::Utf8ToWide(_name)));
|
||||
|
||||
// Optional mipmap:
|
||||
if (_desc._flags & TextureDesc::Flags::generateMips)
|
||||
{
|
||||
VERUS_RT_ASSERT(_desc._mipLevels > 1);
|
||||
// Create storage image for compute shader's output. No need to have the first mip level.
|
||||
const int uavMipLevels = Math::Max(1, _desc._mipLevels - 1);
|
||||
D3D12_RESOURCE_DESC resDescUAV = resDesc;
|
||||
|
@ -111,17 +115,38 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT); hr=" << VERUS_HR(hr);
|
||||
_uaResource._pResource->SetName(_C(Str::Utf8ToWide(_name + " (UAV)")));
|
||||
|
||||
_dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels);
|
||||
VERUS_FOR(i, uavMipLevels)
|
||||
_vCshGenerateMips.reserve(Math::DivideByMultiple<int>(_desc._mipLevels, 4));
|
||||
_dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels * _desc._arrayLayers);
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = resDescUAV.Format;
|
||||
uavDesc.ViewDimension = (_desc._arrayLayers > 1) ? D3D12_UAV_DIMENSION_TEXTURE2DARRAY : D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
VERUS_FOR(layer, _desc._arrayLayers)
|
||||
{
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = resDescUAV.Format;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
uavDesc.Texture2D.MipSlice = i;
|
||||
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(i));
|
||||
VERUS_FOR(mip, uavMipLevels)
|
||||
{
|
||||
if (D3D12_UAV_DIMENSION_TEXTURE2D == uavDesc.ViewDimension)
|
||||
{
|
||||
uavDesc.Texture2D.MipSlice = mip;
|
||||
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip));
|
||||
}
|
||||
else
|
||||
{
|
||||
uavDesc.Texture2DArray.MipSlice = mip;
|
||||
uavDesc.Texture2DArray.FirstArraySlice = layer;
|
||||
uavDesc.Texture2DArray.ArraySize = 1;
|
||||
if (cubeMap)
|
||||
{
|
||||
const int cubeIndex = layer / +CubeMapFace::count;
|
||||
const int faceIndex = layer % +CubeMapFace::count;
|
||||
uavDesc.Texture2DArray.FirstArraySlice = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast<CubeMapFace>(faceIndex));
|
||||
}
|
||||
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip + layer * uavMipLevels));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional readback buffer:
|
||||
if (_desc._readbackMip != SHRT_MAX)
|
||||
{
|
||||
if (_desc._readbackMip < 0)
|
||||
|
@ -147,6 +172,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
}
|
||||
}
|
||||
|
||||
// Create views:
|
||||
if (renderTarget)
|
||||
{
|
||||
if (cubeMap)
|
||||
|
@ -169,7 +195,6 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
pRendererD3D12->GetD3DDevice()->CreateRenderTargetView(_resource._pResource.Get(), nullptr, _dhRTV.AtCPU(0));
|
||||
}
|
||||
}
|
||||
|
||||
if (depthFormat)
|
||||
{
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
||||
|
@ -220,6 +245,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
}
|
||||
}
|
||||
|
||||
// Custom sampler:
|
||||
if (_desc._pSamplerDesc)
|
||||
CreateSampler();
|
||||
|
||||
|
@ -372,6 +398,9 @@ bool TextureD3D12::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCom
|
|||
void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
|
||||
if (_desc._flags & TextureDesc::Flags::cubeMap)
|
||||
return GenerateCubeMapMips(pCB);
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (!pCB)
|
||||
|
@ -409,10 +438,10 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
|
|||
ub._dstTexelSize.x = 1.f / dstWidth;
|
||||
ub._dstTexelSize.y = 1.f / dstHeight;
|
||||
|
||||
int mips[5] = {}; // For input texture (always mip 0) and 4 UAV mips.
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
mips[mip + 1] = srcMip + mip;
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex }, mips);
|
||||
int mipLevels[5] = {}; // For input texture (always mip 0) and 4 UAV mips.
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
mipLevels[i + 1] = srcMip + i;
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex }, mipLevels);
|
||||
_vCshGenerateMips.push_back(complexSetHandle);
|
||||
pCB->BindDescriptors(shader, 0, complexSetHandle);
|
||||
|
||||
|
@ -425,19 +454,18 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
|
|||
{
|
||||
CD3DX12_RESOURCE_BARRIER barriers[4];
|
||||
int barrierCount = 0;
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
{
|
||||
const int subUAV = srcMip + mip;
|
||||
const int subUAV = srcMip + i;
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
|
||||
}
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
|
||||
}
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
{
|
||||
const int subUAV = srcMip + mip;
|
||||
const int subUAV = srcMip + i;
|
||||
const int subSRV = subUAV + 1;
|
||||
const auto dstCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subSRV);
|
||||
const auto srcCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_uaResource._pResource.Get(), subUAV);
|
||||
|
@ -451,14 +479,13 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
|
|||
{
|
||||
CD3DX12_RESOURCE_BARRIER barriers[4];
|
||||
int barrierCount = 0;
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
{
|
||||
const int subUAV = srcMip + mip;
|
||||
const int subUAV = srcMip + i;
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, subUAV);
|
||||
}
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
|
||||
}
|
||||
|
||||
|
@ -475,6 +502,108 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
|
|||
Schedule(0);
|
||||
}
|
||||
|
||||
void TextureD3D12::GenerateCubeMapMips(PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (!pCB)
|
||||
pCB = renderer.GetCommandBuffer().Get();
|
||||
auto pCmdList = static_cast<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
|
||||
auto shader = renderer.GetShaderGenerateCubeMapMips();
|
||||
auto& ub = renderer.GetUbGenerateCubeMapMips();
|
||||
auto tex = TexturePtr::From(this);
|
||||
|
||||
const int maxMipLevel = _desc._mipLevels - 1;
|
||||
|
||||
// Transition state for sampling in compute shader:
|
||||
if (_mainLayout != ImageLayout::xsReadOnly)
|
||||
pCB->PipelineImageMemoryBarrier(tex, _mainLayout, ImageLayout::xsReadOnly, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
|
||||
|
||||
pCB->BindPipeline(renderer.GetPipelineGenerateCubeMapMips());
|
||||
|
||||
shader->BeginBindDescriptors();
|
||||
int dispatchIndex = 0;
|
||||
for (int srcMip = 0; srcMip < maxMipLevel;)
|
||||
{
|
||||
const int srcWidth = Math::Max(1, _desc._width >> srcMip);
|
||||
const int srcHeight = Math::Max(1, _desc._height >> srcMip);
|
||||
const int dstWidth = Math::Max(1, srcWidth >> 1);
|
||||
const int dstHeight = Math::Max(1, srcHeight >> 1);
|
||||
|
||||
ub._srcMipLevel = srcMip;
|
||||
ub._srgb = IsSRGBFormat(_desc._format);
|
||||
ub._dstTexelSize.x = 1.f / dstWidth;
|
||||
ub._dstTexelSize.y = 1.f / dstHeight;
|
||||
|
||||
int mipLevels[7] = {};
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
mipLevels[i + 1] = srcMip;
|
||||
int arrayLayers[7] = {};
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
arrayLayers[i + 1] = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex, tex, tex }, mipLevels, arrayLayers);
|
||||
_vCshGenerateMips.push_back(complexSetHandle);
|
||||
pCB->BindDescriptors(shader, 0, complexSetHandle);
|
||||
|
||||
pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
|
||||
|
||||
auto rb = CD3DX12_RESOURCE_BARRIER::UAV(_uaResource._pResource.Get());
|
||||
pCmdList->ResourceBarrier(1, &rb);
|
||||
|
||||
// Transition state for upcoming CopyTextureRegion():
|
||||
{
|
||||
CD3DX12_RESOURCE_BARRIER barriers[+CubeMapFace::count];
|
||||
int barrierCount = 0;
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
{
|
||||
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
|
||||
}
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, srcMip + 1, Range(0, +CubeMapFace::count));
|
||||
}
|
||||
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
{
|
||||
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
|
||||
const int subSRV = D3D12CalcSubresource(srcMip + 1, i, 0, _desc._mipLevels, _desc._arrayLayers);
|
||||
const auto dstCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subSRV);
|
||||
const auto srcCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_uaResource._pResource.Get(), subUAV);
|
||||
pCmdList->CopyTextureRegion(
|
||||
&dstCopyLoc,
|
||||
0, 0, 0,
|
||||
&srcCopyLoc,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// Transition state for next Dispatch():
|
||||
{
|
||||
CD3DX12_RESOURCE_BARRIER barriers[+CubeMapFace::count];
|
||||
int barrierCount = 0;
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
{
|
||||
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, subUAV);
|
||||
}
|
||||
pCmdList->ResourceBarrier(barrierCount, barriers);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, srcMip + 1, Range(0, +CubeMapFace::count));
|
||||
}
|
||||
|
||||
srcMip++;
|
||||
dispatchIndex++;
|
||||
}
|
||||
shader->EndBindDescriptors();
|
||||
|
||||
// Revert to main state:
|
||||
if (_mainLayout != ImageLayout::xsReadOnly)
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, _mainLayout, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
|
||||
|
||||
ClearCshGenerateMips();
|
||||
Schedule(0);
|
||||
}
|
||||
|
||||
Continue TextureD3D12::Scheduled_Update()
|
||||
{
|
||||
if (!IsScheduledAllowed())
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace verus
|
|||
virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override;
|
||||
|
||||
virtual void GenerateMips(PBaseCommandBuffer pCB) override;
|
||||
void GenerateCubeMapMips(PBaseCommandBuffer pCB);
|
||||
|
||||
virtual Continue Scheduled_Update() override;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -24,4 +24,35 @@
|
|||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!--
|
||||
Due to custom way of accesing next items in
|
||||
D3D12MA::IntrusiveLinkedList via methods in provided type traits,
|
||||
every specialization must be manually added with
|
||||
custom <NextPointer> field describing proper way of iterating the list.
|
||||
-->
|
||||
<Type Name="D3D12MA::IntrusiveLinkedList<D3D12MA::CommittedAllocationListItemTraits>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_Front</HeadPointer>
|
||||
<NextPointer>m_Committed.next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="D3D12MA::IntrusiveLinkedList<D3D12MA::PoolListItemTraits>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_Front</HeadPointer>
|
||||
<NextPointer>m_NextPool</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
|
@ -15,7 +15,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{C9195A1C-9224-4B40-BBBC-AA90EF3BE3E0}</ProjectGuid>
|
||||
<RootNamespace>RendererVulkan</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -73,6 +73,116 @@ void CommandBufferVulkan::End()
|
|||
throw VERUS_RUNTIME_ERROR << "vkEndCommandBuffer(); res=" << res;
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers)
|
||||
{
|
||||
auto& texVulkan = static_cast<RTextureVulkan>(*tex);
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // Waiting for this stage to finish (TOP_OF_PIPE means wait for nothing).
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Which stage is waiting to start (BOTTOM_OF_PIPE means nothing is waiting).
|
||||
const VkPipelineStageFlags dstStageMaskXS = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
|
||||
VkImageMemoryBarrier vkimb = {};
|
||||
vkimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
vkimb.oldLayout = ToNativeImageLayout(oldLayout);
|
||||
vkimb.newLayout = ToNativeImageLayout(newLayout);
|
||||
vkimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkimb.image = texVulkan.GetVkImage();
|
||||
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
vkimb.subresourceRange.baseMipLevel = mipLevels._begin;
|
||||
vkimb.subresourceRange.levelCount = mipLevels.GetCount();
|
||||
vkimb.subresourceRange.baseArrayLayer = arrayLayers._begin;
|
||||
vkimb.subresourceRange.layerCount = arrayLayers.GetCount();
|
||||
|
||||
// See: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples
|
||||
|
||||
auto UseDefaultsForOldLayout = [&vkimb, &srcStageMask]()
|
||||
{
|
||||
vkimb.srcAccessMask = 0;
|
||||
switch (vkimb.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.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
break;
|
||||
default:
|
||||
VERUS_RT_FAIL("Unknown oldLayout");
|
||||
}
|
||||
};
|
||||
|
||||
auto UseDefaultsForNewLayout = [&vkimb, &dstStageMask, dstStageMaskXS, newLayout, tex]()
|
||||
{
|
||||
switch (vkimb.newLayout)
|
||||
{
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
vkimb.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.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.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
break;
|
||||
default:
|
||||
VERUS_RT_FAIL("Unknown newLayout");
|
||||
}
|
||||
|
||||
if (vkimb.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
|
||||
vkimb.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
|
||||
{
|
||||
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (Format::unormD24uintS8 == tex->GetFormat())
|
||||
vkimb.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
};
|
||||
|
||||
if (vkimb.oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb.newLayout == VK_IMAGE_LAYOUT_GENERAL)
|
||||
{
|
||||
UseDefaultsForOldLayout();
|
||||
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
vkimb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
UseDefaultsForOldLayout();
|
||||
UseDefaultsForNewLayout();
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(GetVkCommandBuffer(), srcStageMask, dstStageMask, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &vkimb);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
|
||||
{
|
||||
VERUS_QREF_RENDERER_VULKAN;
|
||||
|
@ -114,34 +224,6 @@ void CommandBufferVulkan::EndRenderPass()
|
|||
vkCmdEndRenderPass(GetVkCommandBuffer());
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
|
||||
{
|
||||
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
|
||||
VkBuffer buffers[VERUS_MAX_VB];
|
||||
VkDeviceSize offsets[VERUS_MAX_VB];
|
||||
const int count = geoVulkan.GetVertexBufferCount();
|
||||
int filteredCount = 0;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
if ((bindingsFilter >> i) & 0x1)
|
||||
{
|
||||
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
|
||||
buffers[filteredCount] = geoVulkan.GetVkVertexBuffer(i);
|
||||
offsets[filteredCount] = geoVulkan.GetVkVertexBufferOffset(i);
|
||||
filteredCount++;
|
||||
}
|
||||
}
|
||||
vkCmdBindVertexBuffers(GetVkCommandBuffer(), 0, filteredCount, buffers, offsets);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BindIndexBuffer(GeometryPtr geo)
|
||||
{
|
||||
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
|
||||
VkBuffer buffer = geoVulkan.GetVkIndexBuffer();
|
||||
VkDeviceSize offset = geoVulkan.GetVkIndexBufferOffset();
|
||||
vkCmdBindIndexBuffer(GetVkCommandBuffer(), buffer, offset, geoVulkan.Has32BitIndices() ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BindPipeline(PipelinePtr pipe)
|
||||
{
|
||||
auto& pipeVulkan = static_cast<RPipelineVulkan>(*pipe);
|
||||
|
@ -196,6 +278,34 @@ void CommandBufferVulkan::SetBlendConstants(const float* p)
|
|||
vkCmdSetBlendConstants(GetVkCommandBuffer(), p);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
|
||||
{
|
||||
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
|
||||
VkBuffer buffers[VERUS_MAX_VB];
|
||||
VkDeviceSize offsets[VERUS_MAX_VB];
|
||||
const int count = geoVulkan.GetVertexBufferCount();
|
||||
int filteredCount = 0;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
if ((bindingsFilter >> i) & 0x1)
|
||||
{
|
||||
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
|
||||
buffers[filteredCount] = geoVulkan.GetVkVertexBuffer(i);
|
||||
offsets[filteredCount] = geoVulkan.GetVkVertexBufferOffset(i);
|
||||
filteredCount++;
|
||||
}
|
||||
}
|
||||
vkCmdBindVertexBuffers(GetVkCommandBuffer(), 0, filteredCount, buffers, offsets);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::BindIndexBuffer(GeometryPtr geo)
|
||||
{
|
||||
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
|
||||
VkBuffer buffer = geoVulkan.GetVkIndexBuffer();
|
||||
VkDeviceSize offset = geoVulkan.GetVkIndexBufferOffset();
|
||||
vkCmdBindIndexBuffer(GetVkCommandBuffer(), buffer, offset, geoVulkan.Has32BitIndices() ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
|
||||
{
|
||||
if (setNumber < 0)
|
||||
|
@ -226,122 +336,6 @@ void CommandBufferVulkan::PushConstants(ShaderPtr shader, int offset, int size,
|
|||
vkCmdPushConstants(GetVkCommandBuffer(), shaderVulkan.GetVkPipelineLayout(), vkssf, offset << 2, size << 2, p);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer)
|
||||
{
|
||||
auto& texVulkan = static_cast<RTextureVulkan>(*tex);
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // Waiting for this stage to finish (TOP_OF_PIPE means wait for nothing).
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Which stage is waiting to start (BOTTOM_OF_PIPE means nothing is waiting).
|
||||
const VkPipelineStageFlags dstStageMaskXS = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
VkImageMemoryBarrier vkimb[16];
|
||||
VERUS_RT_ASSERT(mipLevels.GetCount() <= VERUS_COUNT_OF(vkimb));
|
||||
int index = 0;
|
||||
for (int mip : mipLevels)
|
||||
{
|
||||
vkimb[index].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
vkimb[index].pNext = nullptr;
|
||||
vkimb[index].oldLayout = ToNativeImageLayout(oldLayout);
|
||||
vkimb[index].newLayout = ToNativeImageLayout(newLayout);
|
||||
vkimb[index].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkimb[index].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkimb[index].image = texVulkan.GetVkImage();
|
||||
vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
vkimb[index].subresourceRange.baseMipLevel = mip;
|
||||
vkimb[index].subresourceRange.levelCount = 1;
|
||||
vkimb[index].subresourceRange.baseArrayLayer = arrayLayer;
|
||||
vkimb[index].subresourceRange.layerCount = 1;
|
||||
|
||||
// See: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples
|
||||
|
||||
auto UseDefaultsForOldLayout = [&vkimb, index, &srcStageMask]()
|
||||
{
|
||||
vkimb[index].srcAccessMask = 0;
|
||||
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");
|
||||
}
|
||||
};
|
||||
|
||||
auto UseDefaultsForNewLayout = [&vkimb, index, &dstStageMask, dstStageMaskXS, newLayout, tex]()
|
||||
{
|
||||
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)
|
||||
{
|
||||
UseDefaultsForOldLayout();
|
||||
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
UseDefaultsForOldLayout();
|
||||
UseDefaultsForNewLayout();
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
vkCmdPipelineBarrier(GetVkCommandBuffer(), srcStageMask, dstStageMask, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
index, vkimb);
|
||||
}
|
||||
|
||||
void CommandBufferVulkan::Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
|
||||
{
|
||||
vkCmdDraw(GetVkCommandBuffer(), vertexCount, instanceCount, firstVertex, firstInstance);
|
||||
|
|
|
@ -23,23 +23,24 @@ namespace verus
|
|||
virtual void Begin() override;
|
||||
virtual void End() override;
|
||||
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers) override;
|
||||
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
|
||||
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
|
||||
virtual void NextSubpass() override;
|
||||
virtual void EndRenderPass() override;
|
||||
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) override;
|
||||
|
||||
virtual void BindPipeline(PipelinePtr pipe) override;
|
||||
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth) override;
|
||||
virtual void SetScissor(std::initializer_list<Vector4> il) override;
|
||||
virtual void SetBlendConstants(const float* p) override;
|
||||
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) override;
|
||||
|
||||
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
|
||||
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
|
||||
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer) override;
|
||||
|
||||
virtual void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) override;
|
||||
virtual void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) override;
|
||||
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ) override;
|
||||
|
|
|
@ -101,12 +101,12 @@ void GeometryVulkan::CreateVertexBuffer(int count, int binding)
|
|||
|
||||
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostAccess::sequentialWrite,
|
||||
vb._buffer, vb._vmaAllocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY,
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostAccess::forbidden,
|
||||
vb._buffer, vb._vmaAllocation);
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ void GeometryVulkan::UpdateVertexBuffer(const void* p, int binding, PBaseCommand
|
|||
auto& svb = _vStagingVertexBuffers[binding];
|
||||
if (VK_NULL_HANDLE == svb._buffer)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
|
||||
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
|
||||
svb._buffer, svb._vmaAllocation);
|
||||
}
|
||||
|
||||
|
@ -163,12 +163,12 @@ void GeometryVulkan::CreateIndexBuffer(int count)
|
|||
|
||||
if ((_dynBindingsMask >> 31) & 0x1)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, HostAccess::sequentialWrite,
|
||||
_indexBuffer._buffer, _indexBuffer._vmaAllocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY,
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, HostAccess::forbidden,
|
||||
_indexBuffer._buffer, _indexBuffer._vmaAllocation);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ void GeometryVulkan::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, IN
|
|||
{
|
||||
if (VK_NULL_HANDLE == _stagingIndexBuffer._buffer)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
|
||||
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
|
||||
_stagingIndexBuffer._buffer, _stagingIndexBuffer._vmaAllocation);
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,11 @@ VkFormat CGI::ToNativeFormat(Format format)
|
|||
case Format::unormBC1: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
|
||||
case Format::unormBC2: return VK_FORMAT_BC2_UNORM_BLOCK;
|
||||
case Format::unormBC3: return VK_FORMAT_BC3_UNORM_BLOCK;
|
||||
case Format::unormBC4: return VK_FORMAT_BC4_UNORM_BLOCK;
|
||||
case Format::unormBC5: return VK_FORMAT_BC5_UNORM_BLOCK;
|
||||
case Format::unormBC7: return VK_FORMAT_BC7_UNORM_BLOCK;
|
||||
case Format::snormBC4: return VK_FORMAT_BC4_SNORM_BLOCK;
|
||||
case Format::snormBC5: return VK_FORMAT_BC5_SNORM_BLOCK;
|
||||
case Format::srgbBC1: return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
|
||||
case Format::srgbBC2: return VK_FORMAT_BC2_SRGB_BLOCK;
|
||||
case Format::srgbBC3: return VK_FORMAT_BC3_SRGB_BLOCK;
|
||||
|
@ -196,6 +200,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
{
|
||||
VERUS_RT_ASSERT(components >= 1 && components <= 4);
|
||||
int index = components - 1;
|
||||
|
||||
static const VkFormat floats[] =
|
||||
{
|
||||
VK_FORMAT_R32_SFLOAT,
|
||||
|
@ -203,6 +208,24 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
VK_FORMAT_R32G32B32A32_SFLOAT
|
||||
};
|
||||
static const VkFormat halfs[] =
|
||||
{
|
||||
VK_FORMAT_R16_SFLOAT,
|
||||
VK_FORMAT_R16G16_SFLOAT,
|
||||
VK_FORMAT_R16G16_SFLOAT,
|
||||
VK_FORMAT_R16G16B16A16_SFLOAT
|
||||
};
|
||||
static const VkFormat shorts[] =
|
||||
{
|
||||
VK_FORMAT_R16G16_SINT,
|
||||
VK_FORMAT_R16G16_SINT,
|
||||
VK_FORMAT_R16G16B16A16_SINT,
|
||||
VK_FORMAT_R16G16B16A16_SINT,
|
||||
VK_FORMAT_R16G16_SNORM,
|
||||
VK_FORMAT_R16G16_SNORM,
|
||||
VK_FORMAT_R16G16B16A16_SNORM,
|
||||
VK_FORMAT_R16G16B16A16_SNORM
|
||||
};
|
||||
static const VkFormat bytes[] =
|
||||
{
|
||||
VK_FORMAT_R8G8B8A8_UINT,
|
||||
|
@ -218,17 +241,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
VK_FORMAT_R8G8B8A8_SNORM,
|
||||
VK_FORMAT_R8G8B8A8_SNORM
|
||||
};
|
||||
static const VkFormat shorts[] =
|
||||
{
|
||||
VK_FORMAT_R16G16_SINT,
|
||||
VK_FORMAT_R16G16_SINT,
|
||||
VK_FORMAT_R16G16B16A16_SINT,
|
||||
VK_FORMAT_R16G16B16A16_SINT,
|
||||
VK_FORMAT_R16G16_SNORM,
|
||||
VK_FORMAT_R16G16_SNORM,
|
||||
VK_FORMAT_R16G16B16A16_SNORM,
|
||||
VK_FORMAT_R16G16B16A16_SNORM
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ViaType::floats:
|
||||
|
@ -236,15 +249,10 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
return floats[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::ubytes:
|
||||
case ViaType::halfs:
|
||||
{
|
||||
VERUS_RT_ASSERT(4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal: index += 8; break; // SNORM.
|
||||
case ViaUsage::color: index += 4; break; // UNORM.
|
||||
}
|
||||
return bytes[index];
|
||||
VERUS_RT_ASSERT(3 != components);
|
||||
return halfs[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::shorts:
|
||||
|
@ -252,6 +260,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
VERUS_RT_ASSERT(2 == components || 4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal:
|
||||
case ViaUsage::tangent:
|
||||
case ViaUsage::binormal:
|
||||
index += 4; break; // SNORM.
|
||||
|
@ -259,6 +268,21 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
return shorts[index];
|
||||
}
|
||||
break;
|
||||
case ViaType::ubytes:
|
||||
{
|
||||
VERUS_RT_ASSERT(4 == components);
|
||||
switch (usage)
|
||||
{
|
||||
case ViaUsage::normal:
|
||||
case ViaUsage::tangent:
|
||||
case ViaUsage::binormal:
|
||||
index += 8; break; // SNORM.
|
||||
case ViaUsage::color:
|
||||
index += 4; break; // UNORM.
|
||||
}
|
||||
return bytes[index];
|
||||
}
|
||||
break;
|
||||
default: throw VERUS_RECOVERABLE << "ToNativeFormat(); ViaType=?";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,8 +85,8 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
|
|||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = desc._multiViewport;
|
||||
viewportState.scissorCount = desc._multiViewport;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = {};
|
||||
rasterizationLineState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
|
||||
|
@ -95,7 +95,7 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
|
|||
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationState = {};
|
||||
rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizationState.pNext = &rasterizationLineState;
|
||||
rasterizationState.pNext = pRendererVulkan->IsAdvancedLineRasterizationSupported() ? &rasterizationLineState : nullptr;
|
||||
rasterizationState.depthClampEnable = VK_FALSE;
|
||||
rasterizationState.polygonMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
|
||||
rasterizationState.cullMode = ToNativeCullMode(desc._rasterizationState._cullMode);
|
||||
|
|
|
@ -36,9 +36,6 @@ CSZ RendererVulkan::s_requiredValidationLayers[] =
|
|||
|
||||
CSZ RendererVulkan::s_requiredDeviceExtensions[] =
|
||||
{
|
||||
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
|
||||
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
|
||||
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
|
||||
|
@ -76,11 +73,11 @@ void RendererVulkan::Init()
|
|||
CreateDevice();
|
||||
|
||||
VmaAllocatorCreateInfo vmaaci = {};
|
||||
vmaaci.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT | VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
|
||||
vmaaci.physicalDevice = _physicalDevice;
|
||||
vmaaci.device = _device;
|
||||
vmaaci.pAllocationCallbacks = GetAllocator();
|
||||
vmaaci.frameInUseCount = s_ringBufferSize;
|
||||
vmaaci.instance = _instance;
|
||||
vmaaci.vulkanApiVersion = s_apiVersion;
|
||||
if (VK_SUCCESS != (res = vmaCreateAllocator(&vmaaci, &_vmaAllocator)))
|
||||
throw VERUS_RUNTIME_ERROR << "vmaCreateAllocator(); res=" << res;
|
||||
|
||||
|
@ -265,7 +262,7 @@ void RendererVulkan::CreateInstance()
|
|||
vkai.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
vkai.pEngineName = "Verus";
|
||||
vkai.engineVersion = VK_MAKE_VERSION(major, minor, patch);
|
||||
vkai.apiVersion = VK_API_VERSION_1_1;
|
||||
vkai.apiVersion = s_apiVersion;
|
||||
|
||||
VkInstanceCreateInfo vkici = {};
|
||||
vkici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
|
@ -410,8 +407,18 @@ void RendererVulkan::CreateDevice()
|
|||
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT lineRasterizationFeatures = {};
|
||||
lineRasterizationFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
|
||||
lineRasterizationFeatures.bresenhamLines = VK_TRUE;
|
||||
lineRasterizationFeatures.smoothLines = VK_TRUE;
|
||||
VkPhysicalDeviceFeatures2 vkpdf2 = {};
|
||||
vkpdf2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
vkpdf2.pNext = &lineRasterizationFeatures;
|
||||
vkGetPhysicalDeviceFeatures2(_physicalDevice, &vkpdf2);
|
||||
|
||||
lineRasterizationFeatures.stippledRectangularLines = VK_FALSE;
|
||||
lineRasterizationFeatures.stippledBresenhamLines = VK_FALSE;
|
||||
lineRasterizationFeatures.stippledSmoothLines = VK_FALSE;
|
||||
_advancedLineRasterization =
|
||||
lineRasterizationFeatures.rectangularLines &&
|
||||
lineRasterizationFeatures.bresenhamLines &&
|
||||
lineRasterizationFeatures.smoothLines;
|
||||
|
||||
_queueFamilyIndices = FindQueueFamilyIndices(_physicalDevice);
|
||||
VERUS_RT_ASSERT(_queueFamilyIndices.IsComplete());
|
||||
|
@ -429,14 +436,15 @@ void RendererVulkan::CreateDevice()
|
|||
vDeviceQueueCreateInfos.push_back(vkdqci);
|
||||
}
|
||||
|
||||
// Check https://vulkan.gpuinfo.org/ for device coverage:
|
||||
VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
|
||||
physicalDeviceFeatures.geometryShader = VK_TRUE;
|
||||
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE;
|
||||
physicalDeviceFeatures.fillModeNonSolid = VK_TRUE;
|
||||
physicalDeviceFeatures.multiViewport = VK_TRUE;
|
||||
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE;
|
||||
physicalDeviceFeatures.shaderClipDistance = VK_TRUE;
|
||||
physicalDeviceFeatures.fillModeNonSolid = VK_TRUE; // 79%
|
||||
physicalDeviceFeatures.geometryShader = VK_TRUE; // 80%
|
||||
physicalDeviceFeatures.independentBlend = VK_TRUE; // 99%
|
||||
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE; // 90%
|
||||
physicalDeviceFeatures.shaderClipDistance = VK_TRUE; // 85%
|
||||
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE; // 94%
|
||||
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE; // 81%
|
||||
|
||||
VkDeviceCreateInfo vkdci = {};
|
||||
vkdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
@ -1286,7 +1294,7 @@ RendererVulkan::RcFramebuffer RendererVulkan::GetFramebuffer(FBHandle handle) co
|
|||
return _vFramebuffers[handle.Get()];
|
||||
}
|
||||
|
||||
void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation)
|
||||
void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, HostAccess hostAccess, VkBuffer& buffer, VmaAllocation& vmaAllocation)
|
||||
{
|
||||
VkResult res = VK_SUCCESS;
|
||||
|
||||
|
@ -1295,7 +1303,12 @@ void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, V
|
|||
vkbci.size = size;
|
||||
vkbci.usage = usage;
|
||||
VmaAllocationCreateInfo vmaaci = {};
|
||||
vmaaci.usage = vmaUsage;
|
||||
vmaaci.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
switch (hostAccess)
|
||||
{
|
||||
case HostAccess::sequentialWrite: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; break;
|
||||
case HostAccess::random: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; break;
|
||||
}
|
||||
if (VK_SUCCESS != (res = vmaCreateBuffer(_vmaAllocator, &vkbci, &vmaaci, &buffer, &vmaAllocation, nullptr)))
|
||||
throw VERUS_RECOVERABLE << "vmaCreateBuffer(); res=" << res;
|
||||
}
|
||||
|
@ -1313,12 +1326,17 @@ void RendererVulkan::CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDevice
|
|||
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ®ion);
|
||||
}
|
||||
|
||||
void RendererVulkan::CreateImage(const VkImageCreateInfo* pImageCreateInfo, VmaMemoryUsage vmaUsage, VkImage& image, VmaAllocation& vmaAllocation)
|
||||
void RendererVulkan::CreateImage(const VkImageCreateInfo* pImageCreateInfo, HostAccess hostAccess, VkImage& image, VmaAllocation& vmaAllocation)
|
||||
{
|
||||
VkResult res = VK_SUCCESS;
|
||||
|
||||
VmaAllocationCreateInfo vmaaci = {};
|
||||
vmaaci.usage = vmaUsage;
|
||||
vmaaci.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
switch (hostAccess)
|
||||
{
|
||||
case HostAccess::sequentialWrite: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; break;
|
||||
case HostAccess::random: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; break;
|
||||
}
|
||||
if (VK_SUCCESS != (res = vmaCreateImage(_vmaAllocator, pImageCreateInfo, &vmaaci, &image, &vmaAllocation, nullptr)))
|
||||
throw VERUS_RECOVERABLE << "vmaCreateImage(); res=" << res;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,13 @@ namespace verus
|
|||
{
|
||||
namespace CGI
|
||||
{
|
||||
enum class HostAccess : int
|
||||
{
|
||||
forbidden,
|
||||
sequentialWrite,
|
||||
random
|
||||
};
|
||||
|
||||
struct BaseShaderInclude
|
||||
{
|
||||
virtual void Open(CSZ filename, void** ppData, UINT32* pBytes) = 0;
|
||||
|
@ -52,6 +59,8 @@ namespace verus
|
|||
Vector<VkPresentModeKHR> _vSurfacePresentModes;
|
||||
};
|
||||
|
||||
static const uint32_t s_apiVersion = VK_API_VERSION_1_1;
|
||||
|
||||
static CSZ s_requiredValidationLayers[];
|
||||
static CSZ s_requiredDeviceExtensions[];
|
||||
|
||||
|
@ -79,6 +88,7 @@ namespace verus
|
|||
Vector<VkSampler> _vSamplers;
|
||||
Vector<VkRenderPass> _vRenderPasses;
|
||||
Vector<Framebuffer> _vFramebuffers;
|
||||
bool _advancedLineRasterization = false;
|
||||
|
||||
public:
|
||||
RendererVulkan();
|
||||
|
@ -137,14 +147,15 @@ namespace verus
|
|||
// Which graphics API?
|
||||
virtual Gapi GetGapi() override { return Gapi::vulkan; }
|
||||
|
||||
// Frame cycle:
|
||||
// <FrameCycle>
|
||||
virtual void BeginFrame(bool present) override;
|
||||
virtual void EndFrame(bool present) override;
|
||||
virtual void Present() override;
|
||||
virtual void Sync(bool present) override;
|
||||
virtual void WaitIdle() override;
|
||||
// </FrameCycle>
|
||||
|
||||
// Resources:
|
||||
// <Resources>
|
||||
virtual PBaseCommandBuffer InsertCommandBuffer() override;
|
||||
virtual PBaseGeometry InsertGeometry() override;
|
||||
virtual PBasePipeline InsertPipeline() override;
|
||||
|
@ -166,10 +177,12 @@ namespace verus
|
|||
int GetNextFramebufferIndex() const;
|
||||
VkRenderPass GetRenderPass(RPHandle handle) const;
|
||||
RcFramebuffer GetFramebuffer(FBHandle handle) const;
|
||||
// </Resources>
|
||||
|
||||
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation);
|
||||
// <BufferAndImage>
|
||||
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, HostAccess hostAccess, VkBuffer& buffer, VmaAllocation& vmaAllocation);
|
||||
void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, PBaseCommandBuffer pCB = nullptr);
|
||||
void CreateImage(const VkImageCreateInfo* pImageCreateInfo, VmaMemoryUsage vmaUsage, VkImage& image, VmaAllocation& vmaAllocation);
|
||||
void CreateImage(const VkImageCreateInfo* pImageCreateInfo, HostAccess hostAccess, VkImage& image, VmaAllocation& vmaAllocation);
|
||||
void CopyImage(
|
||||
VkImage srcImage, uint32_t srcMipLevel, uint32_t srcArrayLayer,
|
||||
VkImage dstImage, uint32_t dstMipLevel, uint32_t dstArrayLayer,
|
||||
|
@ -185,8 +198,11 @@ namespace verus
|
|||
uint32_t width, uint32_t height,
|
||||
VkBuffer buffer,
|
||||
PBaseCommandBuffer pCB = nullptr);
|
||||
// </BufferAndImage>
|
||||
|
||||
virtual void UpdateUtilization() override;
|
||||
|
||||
bool IsAdvancedLineRasterizationSupported() const { return _advancedLineRasterization; }
|
||||
};
|
||||
VERUS_TYPEDEFS(RendererVulkan);
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ void ShaderVulkan::CreateDescriptorSet(int setNumber, const void* pSrc, int size
|
|||
if (capacity > 0)
|
||||
{
|
||||
const VkDeviceSize bufferSize = dsd._capacityInBytes * BaseRenderer::s_ringBufferSize;
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, HostAccess::sequentialWrite,
|
||||
dsd._buffer, dsd._vmaAllocation);
|
||||
}
|
||||
|
||||
|
@ -405,7 +405,7 @@ void ShaderVulkan::CreatePipelineLayout()
|
|||
}
|
||||
}
|
||||
|
||||
CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
|
||||
CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers)
|
||||
{
|
||||
VERUS_QREF_RENDERER_VULKAN;
|
||||
VkResult res = VK_SUCCESS;
|
||||
|
@ -451,11 +451,12 @@ CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer
|
|||
for (const auto& x : il)
|
||||
{
|
||||
auto& texVulkan = static_cast<RTextureVulkan>(*x);
|
||||
const int mip = pMips ? pMips[index] : 0;
|
||||
const int mipLevel = pMipLevels ? pMipLevels[index] : 0;
|
||||
const int arrayLayer = pArrayLayers ? pArrayLayers[index] : 0;
|
||||
VkDescriptorImageInfo vkdii = {};
|
||||
if (Sampler::storage == dsd._vSamplers[index])
|
||||
{
|
||||
vkdii.imageView = texVulkan.GetStorageVkImageView(mip);
|
||||
vkdii.imageView = texVulkan.GetStorageVkImageView(mipLevel, arrayLayer);
|
||||
vkdii.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
else if (Sampler::shadow == dsd._vSamplers[index])
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace verus
|
|||
|
||||
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
|
||||
virtual void CreatePipelineLayout() override;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers) override;
|
||||
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
|
||||
|
||||
virtual void BeginBindDescriptors() override;
|
||||
|
|
|
@ -21,24 +21,28 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
VERUS_QREF_RENDERER_VULKAN;
|
||||
VkResult res = VK_SUCCESS;
|
||||
|
||||
_initAtFrame = renderer.GetFrameCount();
|
||||
// Variables:
|
||||
_size = Vector4(
|
||||
float(desc._width),
|
||||
float(desc._height),
|
||||
1.f / desc._width,
|
||||
1.f / desc._height);
|
||||
_desc = desc;
|
||||
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
|
||||
_initAtFrame = renderer.GetFrameCount();
|
||||
if (desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
|
||||
|
||||
_desc._mipLevels = _desc._mipLevels ? _desc._mipLevels : Math::ComputeMipLevels(_desc._width, _desc._height, _desc._depth);
|
||||
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
|
||||
const bool depthFormat = IsDepthFormat(desc._format);
|
||||
const bool depthFormat = IsDepthFormat(_desc._format);
|
||||
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
|
||||
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
|
||||
if (cubeMap)
|
||||
_desc._arrayLayers *= +CubeMapFace::count;
|
||||
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
const bool arrayTexture = (_desc._arrayLayers > 1) || (_desc._flags & TextureDesc::Flags::forceArrayTexture);
|
||||
|
||||
// Create:
|
||||
VkImageCreateInfo vkici = {};
|
||||
vkici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
vkici.imageType = (_desc._depth > 1) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
||||
|
@ -69,10 +73,12 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
vkici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
if (cubeMap)
|
||||
vkici.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
pRendererVulkan->CreateImage(&vkici, VMA_MEMORY_USAGE_GPU_ONLY, _image, _vmaAllocation);
|
||||
pRendererVulkan->CreateImage(&vkici, HostAccess::forbidden, _image, _vmaAllocation);
|
||||
|
||||
// Optional mipmap:
|
||||
if (_desc._flags & TextureDesc::Flags::generateMips)
|
||||
{
|
||||
VERUS_RT_ASSERT(_desc._mipLevels > 1);
|
||||
// Create storage image for compute shader's output. No need to have the first mip level.
|
||||
VkImageCreateInfo vkiciStorage = vkici;
|
||||
vkiciStorage.extent.width = Math::Max(1, _desc._width >> 1);
|
||||
|
@ -85,27 +91,37 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
case VK_FORMAT_R8G8B8A8_SRGB: vkiciStorage.format = VK_FORMAT_R8G8B8A8_UNORM; break;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB: vkiciStorage.format = VK_FORMAT_B8G8R8A8_UNORM; break;
|
||||
}
|
||||
pRendererVulkan->CreateImage(&vkiciStorage, VMA_MEMORY_USAGE_GPU_ONLY, _storageImage, _storageVmaAllocation);
|
||||
pRendererVulkan->CreateImage(&vkiciStorage, HostAccess::forbidden, _storageImage, _storageVmaAllocation);
|
||||
|
||||
_vCshGenerateMips.reserve(Math::DivideByMultiple<int>(_desc._mipLevels, 4));
|
||||
_vStorageImageViews.resize(vkiciStorage.mipLevels);
|
||||
VERUS_U_FOR(mip, vkiciStorage.mipLevels)
|
||||
_vStorageImageViews.resize(vkiciStorage.mipLevels * _desc._arrayLayers);
|
||||
VkImageViewCreateInfo vkivci = {};
|
||||
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
vkivci.image = _storageImage;
|
||||
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
vkivci.format = vkiciStorage.format;
|
||||
VERUS_FOR(layer, _desc._arrayLayers)
|
||||
{
|
||||
VkImageViewCreateInfo vkivci = {};
|
||||
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
vkivci.image = _storageImage;
|
||||
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
vkivci.format = vkiciStorage.format;
|
||||
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
vkivci.subresourceRange.baseMipLevel = mip;
|
||||
vkivci.subresourceRange.levelCount = 1;
|
||||
vkivci.subresourceRange.baseArrayLayer = 0;
|
||||
vkivci.subresourceRange.layerCount = 1;
|
||||
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_vStorageImageViews[mip])))
|
||||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(); res=" << res;
|
||||
VERUS_U_FOR(mip, vkiciStorage.mipLevels)
|
||||
{
|
||||
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
vkivci.subresourceRange.baseMipLevel = mip;
|
||||
vkivci.subresourceRange.levelCount = 1;
|
||||
vkivci.subresourceRange.baseArrayLayer = layer;
|
||||
vkivci.subresourceRange.layerCount = 1;
|
||||
if (cubeMap)
|
||||
{
|
||||
const int cubeIndex = layer / +CubeMapFace::count;
|
||||
const int faceIndex = layer % +CubeMapFace::count;
|
||||
vkivci.subresourceRange.baseArrayLayer = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast<CubeMapFace>(faceIndex));
|
||||
}
|
||||
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_vStorageImageViews[mip + layer * vkiciStorage.mipLevels])))
|
||||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(); res=" << res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional readback buffer:
|
||||
if (_desc._readbackMip != SHRT_MAX)
|
||||
{
|
||||
if (_desc._readbackMip < 0)
|
||||
|
@ -116,18 +132,19 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
_vReadbackBuffers.resize(BaseRenderer::s_ringBufferSize);
|
||||
for (auto& x : _vReadbackBuffers)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU,
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, HostAccess::random,
|
||||
x._buffer, x._vmaAllocation);
|
||||
}
|
||||
}
|
||||
|
||||
// Create views:
|
||||
VkImageViewCreateInfo vkivci = {};
|
||||
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
vkivci.image = _image;
|
||||
vkivci.viewType = (_desc._depth > 1) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D;
|
||||
if (cubeMap)
|
||||
vkivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
else if (_desc._arrayLayers > 1 || (_desc._flags & TextureDesc::Flags::forceArrayTexture))
|
||||
else if (arrayTexture)
|
||||
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
vkivci.format = vkici.format;
|
||||
vkivci.subresourceRange.aspectMask = depthFormat ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
@ -158,22 +175,19 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
}
|
||||
}
|
||||
|
||||
// Custom sampler:
|
||||
if (_desc._pSamplerDesc)
|
||||
CreateSampler();
|
||||
|
||||
// Define:
|
||||
if (renderTarget)
|
||||
{
|
||||
CommandBufferVulkan commandBuffer;
|
||||
commandBuffer.InitOneTimeSubmit();
|
||||
if (cubeMap)
|
||||
{
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, i);
|
||||
}
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, Range(0, +CubeMapFace::count));
|
||||
else
|
||||
{
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, 0);
|
||||
}
|
||||
commandBuffer.DoneOneTimeSubmit();
|
||||
}
|
||||
if (depthFormat)
|
||||
|
@ -233,7 +247,7 @@ void TextureVulkan::UpdateSubresource(const void* p, int mipLevel, int arrayLaye
|
|||
auto& sb = _vStagingBuffers[sbIndex];
|
||||
if (VK_NULL_HANDLE == sb._buffer)
|
||||
{
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
|
||||
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
|
||||
sb._buffer, sb._vmaAllocation);
|
||||
}
|
||||
|
||||
|
@ -297,6 +311,9 @@ bool TextureVulkan::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCo
|
|||
void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
|
||||
if (_desc._flags & TextureDesc::Flags::cubeMap)
|
||||
return GenerateCubeMapMips(pCB);
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_RENDERER_VULKAN;
|
||||
|
||||
|
@ -351,10 +368,10 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
|
|||
|
||||
if (createComplexSets)
|
||||
{
|
||||
int mips[5] = {}; // For input texture (always mip 0) and 4 storage mips.
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
mips[mip + 1] = srcMip + mip;
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
|
||||
int mipLevels[5] = {}; // For input texture (always mip 0) and 4 storage mips.
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
mipLevels[i + 1] = srcMip + i;
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mipLevels);
|
||||
_vCshGenerateMips.push_back(complexSetHandle);
|
||||
pCB->BindDescriptors(shader, 0, complexSetHandle);
|
||||
}
|
||||
|
@ -370,12 +387,11 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
|
|||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::general, ImageLayout::transferSrc, Range(0, dispatchMipCount).OffsetBy(srcMip));
|
||||
std::swap(_image, _storageImage);
|
||||
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
|
||||
}
|
||||
VERUS_FOR(mip, dispatchMipCount)
|
||||
VERUS_FOR(i, dispatchMipCount)
|
||||
{
|
||||
const int dstMip = srcMip + 1 + mip;
|
||||
const int dstMip = srcMip + 1 + i;
|
||||
const int w = Math::Max(1, _desc._width >> dstMip);
|
||||
const int h = Math::Max(1, _desc._height >> dstMip);
|
||||
pRendererVulkan->CopyImage(
|
||||
|
@ -389,7 +405,6 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
|
|||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferSrc, ImageLayout::general, Range(0, dispatchMipCount).OffsetBy(srcMip));
|
||||
std::swap(_image, _storageImage);
|
||||
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
|
||||
}
|
||||
|
||||
|
@ -406,6 +421,116 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
|
|||
Schedule(0);
|
||||
}
|
||||
|
||||
void TextureVulkan::GenerateCubeMapMips(PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_RENDERER_VULKAN;
|
||||
|
||||
if (!pCB)
|
||||
pCB = renderer.GetCommandBuffer().Get();
|
||||
auto shader = renderer.GetShaderGenerateCubeMapMips();
|
||||
auto& ub = renderer.GetUbGenerateCubeMapMips();
|
||||
auto tex = TexturePtr::From(this);
|
||||
|
||||
const int maxMipLevel = _desc._mipLevels - 1;
|
||||
|
||||
if (!_definedStorage)
|
||||
{
|
||||
_definedStorage = true;
|
||||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::undefined, ImageLayout::general, Range(0, maxMipLevel), Range(0, +CubeMapFace::count));
|
||||
std::swap(_image, _storageImage);
|
||||
}
|
||||
|
||||
// Change layout for sampling in compute shader (assume all layers have the same layout):
|
||||
const ImageLayout firstMipLayout = GetSubresourceMainLayout(0, 0);
|
||||
const ImageLayout otherMipsLayout = GetSubresourceMainLayout(1, 0);
|
||||
if (firstMipLayout != ImageLayout::xsReadOnly)
|
||||
pCB->PipelineImageMemoryBarrier(tex, firstMipLayout, ImageLayout::xsReadOnly, 0, Range(0, +CubeMapFace::count));
|
||||
if (otherMipsLayout != ImageLayout::xsReadOnly)
|
||||
pCB->PipelineImageMemoryBarrier(tex, otherMipsLayout, ImageLayout::xsReadOnly, Range(1, _desc._mipLevels), Range(0, +CubeMapFace::count));
|
||||
VERUS_FOR(layer, +CubeMapFace::count)
|
||||
{
|
||||
VERUS_FOR(mip, _desc._mipLevels)
|
||||
MarkSubresourceDefined(mip, layer);
|
||||
}
|
||||
|
||||
pCB->BindPipeline(renderer.GetPipelineGenerateCubeMapMips());
|
||||
|
||||
shader->BeginBindDescriptors();
|
||||
const bool createComplexSets = _vCshGenerateMips.empty();
|
||||
int dispatchIndex = 0;
|
||||
for (int srcMip = 0; srcMip < maxMipLevel;)
|
||||
{
|
||||
const int srcWidth = Math::Max(1, _desc._width >> srcMip);
|
||||
const int srcHeight = Math::Max(1, _desc._height >> srcMip);
|
||||
const int dstWidth = Math::Max(1, srcWidth >> 1);
|
||||
const int dstHeight = Math::Max(1, srcHeight >> 1);
|
||||
|
||||
ub._srcMipLevel = srcMip;
|
||||
ub._srgb = IsSRGBFormat(_desc._format);
|
||||
ub._dstTexelSize.x = 1.f / dstWidth;
|
||||
ub._dstTexelSize.y = 1.f / dstHeight;
|
||||
|
||||
if (createComplexSets)
|
||||
{
|
||||
int mipLevels[7] = {};
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
mipLevels[i + 1] = srcMip;
|
||||
int arrayLayers[7] = {};
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
arrayLayers[i + 1] = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
|
||||
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex, tex, tex }, mipLevels, arrayLayers);
|
||||
_vCshGenerateMips.push_back(complexSetHandle);
|
||||
pCB->BindDescriptors(shader, 0, complexSetHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCB->BindDescriptors(shader, 0, _vCshGenerateMips[dispatchIndex]);
|
||||
}
|
||||
|
||||
pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
|
||||
|
||||
// Change layout for upcoming CopyImage():
|
||||
{
|
||||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::general, ImageLayout::transferSrc, srcMip, Range(0, +CubeMapFace::count));
|
||||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, srcMip + 1, Range(0, +CubeMapFace::count));
|
||||
}
|
||||
VERUS_FOR(layer, +CubeMapFace::count)
|
||||
{
|
||||
const int storageMip = srcMip;
|
||||
const int dstMip = srcMip + 1;
|
||||
const int w = Math::Max(1, _desc._width >> dstMip);
|
||||
const int h = Math::Max(1, _desc._height >> dstMip);
|
||||
pRendererVulkan->CopyImage(
|
||||
_storageImage, storageMip, layer,
|
||||
_image, dstMip, layer,
|
||||
w, h,
|
||||
pCB);
|
||||
}
|
||||
// Change layout for next Dispatch():
|
||||
{
|
||||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferSrc, ImageLayout::general, srcMip, Range(0, +CubeMapFace::count));
|
||||
std::swap(_image, _storageImage);
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, srcMip + 1, Range(0, +CubeMapFace::count));
|
||||
}
|
||||
|
||||
srcMip++;
|
||||
dispatchIndex++;
|
||||
}
|
||||
shader->EndBindDescriptors();
|
||||
|
||||
// Revert to main layout:
|
||||
const ImageLayout finalMipLayout = GetSubresourceMainLayout(0, 0);
|
||||
if (finalMipLayout != ImageLayout::xsReadOnly)
|
||||
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, finalMipLayout, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
|
||||
|
||||
Schedule(0);
|
||||
}
|
||||
|
||||
Continue TextureVulkan::Scheduled_Update()
|
||||
{
|
||||
if (!IsScheduledAllowed())
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace verus
|
|||
virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override;
|
||||
|
||||
virtual void GenerateMips(PBaseCommandBuffer pCB) override;
|
||||
void GenerateCubeMapMips(PBaseCommandBuffer pCB);
|
||||
|
||||
virtual Continue Scheduled_Update() override;
|
||||
|
||||
|
@ -50,7 +51,7 @@ namespace verus
|
|||
VkImage GetVkImage() const { return _image; }
|
||||
VkImageView GetVkImageView() const { return _imageView; }
|
||||
VkImageView GetVkImageViewForFramebuffer(CubeMapFace face) const;
|
||||
VkImageView GetStorageVkImageView(int mip) const { return _vStorageImageViews[mip]; }
|
||||
VkImageView GetStorageVkImageView(int mipLevel, int arrayLayer) const { return _vStorageImageViews[mipLevel + arrayLayer * (_desc._mipLevels - 1)]; }
|
||||
VkSampler GetVkSampler() const { return _sampler; }
|
||||
ImageLayout GetSubresourceMainLayout(int mipLevel, int arrayLayer) const;
|
||||
void MarkSubresourceDefined(int mipLevel, int arrayLayer);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,40 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="VmaRawList<*>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_pFront</HeadPointer>
|
||||
<NextPointer>pNext</NextPointer>
|
||||
<ValueNode>Value</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="VmaRawList<*>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_pFront</HeadPointer>
|
||||
<NextPointer>pNext</NextPointer>
|
||||
<ValueNode>Value</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="VmaList<*>">
|
||||
<DisplayString>{{ Count={m_RawList.m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_RawList.m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_RawList.m_Count</Size>
|
||||
<HeadPointer>m_RawList.m_pFront</HeadPointer>
|
||||
<NextPointer>pNext</NextPointer>
|
||||
<ValueNode>Value</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="VmaList<*>">
|
||||
<DisplayString>{{ Count={m_RawList.m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_RawList.m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_RawList.m_Count</Size>
|
||||
<HeadPointer>m_RawList.m_pFront</HeadPointer>
|
||||
<NextPointer>pNext</NextPointer>
|
||||
<ValueNode>Value</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="VmaVector<*>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<Item Name="[Capacity]">m_Capacity</Item>
|
||||
<ArrayItems>
|
||||
<Size>m_Count</Size>
|
||||
<ValuePointer>m_pArray</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="VmaVector<*>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<Item Name="[Capacity]">m_Capacity</Item>
|
||||
<ArrayItems>
|
||||
<Size>m_Count</Size>
|
||||
<ValuePointer>m_pArray</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!--
|
||||
Due to custom way of accesing next items in
|
||||
VmaIntrusiveLinkedList via methods in provided type traits,
|
||||
every specialization must be manually added with
|
||||
custom <NextPointer> field describing proper way of iterating the list.
|
||||
-->
|
||||
<Type Name="VmaIntrusiveLinkedList<VmaDedicatedAllocationListItemTraits>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_Front</HeadPointer>
|
||||
<NextPointer>m_DedicatedAllocation.m_Next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="VmaIntrusiveLinkedList<VmaPoolListItemTraits>">
|
||||
<DisplayString>{{ Count={m_Count} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Count]">m_Count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>m_Count</Size>
|
||||
<HeadPointer>m_Front</HeadPointer>
|
||||
<NextPointer>m_NextPool</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
|
@ -15,7 +15,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}</ProjectGuid>
|
||||
<RootNamespace>TextureTool</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
|
|
@ -4,86 +4,228 @@
|
|||
|
||||
using namespace verus;
|
||||
|
||||
void DeleteMipmap(CWSZ pathname);
|
||||
|
||||
CMP_BOOL CompressionCallback(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2)
|
||||
class TextureTool
|
||||
{
|
||||
std::wcout << _T("ProcessTexture progress = ") << static_cast<int>(progress) << _T("%") << std::endl;
|
||||
struct CursorGuard
|
||||
{
|
||||
CONSOLE_CURSOR_INFO _defaultCursorInfo;
|
||||
CursorGuard()
|
||||
{
|
||||
GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &_defaultCursorInfo);
|
||||
CONSOLE_CURSOR_INFO info = {};
|
||||
info.dwSize = 100;
|
||||
info.bVisible = FALSE;
|
||||
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
|
||||
}
|
||||
~CursorGuard()
|
||||
{
|
||||
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &_defaultCursorInfo);
|
||||
}
|
||||
};
|
||||
|
||||
enum class TexMode : int
|
||||
{
|
||||
automatic,
|
||||
color,
|
||||
nonColor,
|
||||
a,
|
||||
n,
|
||||
x,
|
||||
all
|
||||
};
|
||||
|
||||
String _pathname;
|
||||
TexMode _texMode = TexMode::automatic;
|
||||
bool _asIs = false;
|
||||
bool _edgePaddingUsingAlpha = false;
|
||||
bool _edgePaddingUsingFaces = false;
|
||||
bool _deleteMip = false;
|
||||
|
||||
static CMP_BOOL FeedbackProc(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2);
|
||||
|
||||
public:
|
||||
TextureTool();
|
||||
~TextureTool();
|
||||
|
||||
void Main(VERUS_MAIN_DEFAULT_ARGS);
|
||||
void ParseCommandLine(VERUS_MAIN_DEFAULT_ARGS);
|
||||
void PrintUsage();
|
||||
void ConvertTexture(TexMode currentTexMode);
|
||||
void ComputeEdgePadding();
|
||||
};
|
||||
|
||||
CMP_BOOL TextureTool::FeedbackProc(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2)
|
||||
{
|
||||
const int edge = static_cast<int>(progress * 0.5f + 0.5f);
|
||||
std::wcout << _T("\rCompressing [");
|
||||
VERUS_FOR(i, 50)
|
||||
{
|
||||
if (i < edge)
|
||||
std::wcout << _T("=");
|
||||
else
|
||||
std::wcout << _T(" ");
|
||||
}
|
||||
std::wcout << _T("] ") << std::setw(3) << static_cast<int>(progress + 0.5f) << _T("%") << std::flush;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Run()
|
||||
TextureTool::TextureTool()
|
||||
{
|
||||
int argCount = 0;
|
||||
LPWSTR* argArray = CommandLineToArgvW(GetCommandLine(), &argCount);
|
||||
WideString pathnameW;
|
||||
std::wcout << _T("TextureTool") << std::endl;
|
||||
std::wcout << _T("Copyright (c) 2016-2021 Dmitry Maluev") << std::endl;
|
||||
if (argCount < 2)
|
||||
{
|
||||
std::wcout << _T("Enter file name: ");
|
||||
std::wcin >> pathnameW;
|
||||
}
|
||||
else
|
||||
pathnameW = argArray[argCount - 1];
|
||||
String pathname = Str::WideToUtf8(pathnameW);
|
||||
bool argDeleteMipmap = false;
|
||||
bool argFade = false;
|
||||
bool argNormalMap = false;
|
||||
bool argColorData = true;
|
||||
VERUS_FOR(i, argCount)
|
||||
{
|
||||
if (!_wcsicmp(argArray[i], L"--delete-mipmap"))
|
||||
argDeleteMipmap = true;
|
||||
if (!_wcsicmp(argArray[i], L"--fade"))
|
||||
argFade = true;
|
||||
if (!_wcsicmp(argArray[i], L"--normal-map"))
|
||||
argNormalMap = true;
|
||||
if (!_wcsicmp(argArray[i], L"--non-color-data"))
|
||||
argColorData = false;
|
||||
}
|
||||
LocalFree(argArray);
|
||||
}
|
||||
|
||||
if (argDeleteMipmap)
|
||||
TextureTool::~TextureTool()
|
||||
{
|
||||
}
|
||||
|
||||
void TextureTool::Main(VERUS_MAIN_DEFAULT_ARGS)
|
||||
{
|
||||
if (argc <= 1)
|
||||
{
|
||||
DeleteMipmap(_C(pathnameW));
|
||||
PrintUsage();
|
||||
return;
|
||||
}
|
||||
ParseCommandLine(argc, argv);
|
||||
|
||||
if (_edgePaddingUsingAlpha || _edgePaddingUsingFaces)
|
||||
{
|
||||
ComputeEdgePadding();
|
||||
}
|
||||
else if (_deleteMip)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wcout << _T("Mode: ");
|
||||
switch (_texMode)
|
||||
{
|
||||
case TexMode::automatic: std::wcout << _T("automatic"); break;
|
||||
case TexMode::color: std::wcout << _T("color"); break;
|
||||
case TexMode::nonColor: std::wcout << _T("non-color"); break;
|
||||
case TexMode::a: std::wcout << _T("a"); break;
|
||||
case TexMode::n: std::wcout << _T("n"); break;
|
||||
case TexMode::x: std::wcout << _T("x"); break;
|
||||
case TexMode::all: std::wcout << _T("all"); break;
|
||||
}
|
||||
std::wcout << std::endl;
|
||||
|
||||
if (TexMode::automatic == _texMode)
|
||||
{
|
||||
const String ext = Str::GetExtension(_C(_pathname));
|
||||
if (Str::EndsWith(_C(_pathname), _C(".X." + ext)))
|
||||
ConvertTexture(TexMode::nonColor);
|
||||
else
|
||||
ConvertTexture(TexMode::color);
|
||||
}
|
||||
else if (TexMode::all == _texMode)
|
||||
{
|
||||
const String pathname = _pathname;
|
||||
const String ext = Str::GetExtension(_C(pathname));
|
||||
|
||||
ConvertTexture(TexMode::a);
|
||||
_pathname = pathname;
|
||||
Str::ReplaceExtension(_pathname, ".N.png");
|
||||
ConvertTexture(TexMode::n);
|
||||
_pathname = pathname;
|
||||
Str::ReplaceExtension(_pathname, _C(".X." + ext));
|
||||
ConvertTexture(TexMode::x);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertTexture(_texMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextureTool::ParseCommandLine(VERUS_MAIN_DEFAULT_ARGS)
|
||||
{
|
||||
VERUS_FOR(i, argc)
|
||||
{
|
||||
if (!strcmp(argv[i], "--tex-auto"))
|
||||
_texMode = TexMode::automatic;
|
||||
else if (!strcmp(argv[i], "--tex-color"))
|
||||
_texMode = TexMode::color;
|
||||
else if (!strcmp(argv[i], "--tex-non-color"))
|
||||
_texMode = TexMode::nonColor;
|
||||
else if (!strcmp(argv[i], "--tex-a"))
|
||||
_texMode = TexMode::a;
|
||||
else if (!strcmp(argv[i], "--tex-n"))
|
||||
_texMode = TexMode::n;
|
||||
else if (!strcmp(argv[i], "--tex-x"))
|
||||
_texMode = TexMode::x;
|
||||
else if (!strcmp(argv[i], "--tex-all"))
|
||||
_texMode = TexMode::all;
|
||||
else if (!strcmp(argv[i], "--as-is"))
|
||||
_asIs = true;
|
||||
else if (!strcmp(argv[i], "--edge-padding-using-alpha") || !strcmp(argv[i], "-epua"))
|
||||
_edgePaddingUsingAlpha = true;
|
||||
else if (!strcmp(argv[i], "--edge-padding-using-faces") || !strcmp(argv[i], "-epuf"))
|
||||
_edgePaddingUsingFaces = true;
|
||||
else if (!strcmp(argv[i], "--delete-mip"))
|
||||
_deleteMip = true;
|
||||
else if (i > 0 && i < argc - 1)
|
||||
{
|
||||
std::wcout << _T("WARNING: Unknown argument ") << Str::Utf8ToWide(argv[i]) << std::endl;
|
||||
std::cin.ignore();
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int argCount = 0;
|
||||
LPWSTR* argArray = CommandLineToArgvW(GetCommandLine(), &argCount);
|
||||
_pathname = Str::WideToUtf8(argArray[argCount - 1]);
|
||||
LocalFree(argArray);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextureTool::PrintUsage()
|
||||
{
|
||||
std::wcout << _T("Usage: TextureTool [options] <file>") << std::endl;
|
||||
std::wcout << std::endl;
|
||||
std::wcout << _T("TextureTool 2. Powered by Compressonator.") << std::endl;
|
||||
std::wcout << _T("Preferred output formats are DDS/BC5 for normal map and DDS/BC7 for everything else.") << std::endl;
|
||||
std::wcout << _T("Create a batch file with similar content to convert multiple files:") << std::endl;
|
||||
std::wcout << _T(" for %%f in (*.*) do TextureTool %%f") << std::endl;
|
||||
std::wcout << std::endl;
|
||||
std::wcout << _T("Options:") << std::endl;
|
||||
std::wcout << _T(" --tex-auto Use filename to select between color and non-color data (default).") << std::endl;
|
||||
std::wcout << _T(" --tex-color Convert texture with color (sRGB).") << std::endl;
|
||||
std::wcout << _T(" --tex-non-color Convert texture with non-color data (linear).") << std::endl;
|
||||
std::wcout << _T(" --tex-a Convert {Albedo.rgb, Alpha} texture.") << std::endl;
|
||||
std::wcout << _T(" --tex-n Convert Normal Map texture.") << std::endl;
|
||||
std::wcout << _T(" --tex-x Convert {Occlusion, Roughness, Metallic, Emission} texture.") << std::endl;
|
||||
std::wcout << _T(" --tex-all Convert all textures.") << std::endl;
|
||||
std::wcout << _T(" --as-is Don't use block compression.") << std::endl;
|
||||
std::wcout << _T(" --edge-padding-using-alpha, -epua Add edge padding to an image with alpha.") << std::endl;
|
||||
std::wcout << _T(" --edge-padding-using-faces, -epuf Add edge padding to an image, take alpha from Faces.png.") << std::endl;
|
||||
std::wcout << _T(" --delete-mip Delete topmost mip level.") << std::endl;
|
||||
}
|
||||
|
||||
void TextureTool::ConvertTexture(TexMode currentTexMode)
|
||||
{
|
||||
std::wcout << _T("Converting texture: ");
|
||||
switch (currentTexMode)
|
||||
{
|
||||
case TexMode::color: std::wcout << _T("COLOR"); break;
|
||||
case TexMode::nonColor: std::wcout << _T("NON-COLOR"); break;
|
||||
case TexMode::a: std::wcout << _T("A (Albedo, Alpha)"); break;
|
||||
case TexMode::n: std::wcout << _T("N (Normal Map)"); break;
|
||||
case TexMode::x: std::wcout << _T("X (Occlusion, Roughness, Metallic, Emission)"); break;
|
||||
default:
|
||||
std::wcerr << _T("ERROR: Unknown mode.") << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
std::wcout << std::endl;
|
||||
std::wcout << _T("Location: ") << Str::Utf8ToWide(_pathname) << std::endl;
|
||||
|
||||
CMP_ERROR cmpError = CMP_OK;
|
||||
|
||||
CMP_MipSet srcMipSet = {};
|
||||
cmpError = CMP_LoadTexture(_C(pathname), &srcMipSet);
|
||||
cmpError = CMP_LoadTexture(_C(_pathname), &srcMipSet);
|
||||
if (CMP_OK != cmpError)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_LoadTexture(), ") << cmpError << std::endl;
|
||||
std::wcerr << _T("ERROR: CMP_LoadTexture(); ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
// FX image with extra info:
|
||||
Vector<UINT32> vMipFX[2];
|
||||
String pathnameFX(pathname);
|
||||
Str::ReplaceExtension(pathnameFX, ".FX.png");
|
||||
if (argNormalMap && IO::FileSystem::FileExist(_C(pathnameFX)))
|
||||
{
|
||||
std::wcout << _T("FX file: ") << Str::Utf8ToWide(pathnameFX) << std::endl;
|
||||
IO::Image imageFX;
|
||||
imageFX.Init(_C(pathnameFX));
|
||||
if (imageFX._width == srcMipSet.m_nWidth && imageFX._height == srcMipSet.m_nHeight)
|
||||
{
|
||||
const int pixelCount = imageFX._width * imageFX._height;
|
||||
vMipFX[0].resize(pixelCount);
|
||||
vMipFX[1].resize(pixelCount);
|
||||
VERUS_FOR(i, pixelCount)
|
||||
memcpy(&vMipFX[0][i], imageFX._p + imageFX._bytesPerPixel * i, imageFX._bytesPerPixel);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wcerr << _T("ERROR: FX image has different dimensions: ") << imageFX._width << _T("x") << imageFX._height << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
if (srcMipSet.m_nMipLevels <= 1)
|
||||
CMP_GenerateMIPLevels(&srcMipSet, 0);
|
||||
|
||||
|
@ -92,226 +234,300 @@ void Run()
|
|||
const BYTE* pData = pMipLevel->m_pbData;
|
||||
const int pixelCount = srcMipSet.m_nWidth * srcMipSet.m_nHeight;
|
||||
|
||||
Vector<UINT32> vMip[2];
|
||||
bool normalMapToRoughness = false;
|
||||
const int bytesPerPixel = sizeof(UINT32);
|
||||
Vector<UINT32> vMip[4];
|
||||
vMip[0].resize(pixelCount);
|
||||
vMip[1].resize(pixelCount);
|
||||
if (TexMode::x == currentTexMode)
|
||||
{
|
||||
String pathname = _pathname;
|
||||
Str::ReplaceExtension(pathname, "");
|
||||
Str::ReplaceExtension(pathname, ".N.TempR.tga");
|
||||
if (IO::FileSystem::FileExist(_C(pathname)))
|
||||
{
|
||||
IO::Image image;
|
||||
image.Init(_C(pathname));
|
||||
if (image._width == srcMipSet.m_nWidth && image._height == srcMipSet.m_nHeight)
|
||||
{
|
||||
vMip[2].resize(pixelCount);
|
||||
vMip[3].resize(pixelCount);
|
||||
memcpy(vMip[3].data(), image._p, vMip[3].size() * bytesPerPixel);
|
||||
normalMapToRoughness = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wcout << _T("WARNING: Normal map for roughness has different size.") << std::endl;
|
||||
std::cin.ignore();
|
||||
}
|
||||
}
|
||||
|
||||
const float fadePerMip = pow(0.02f, 1.f / srcMipSet.m_nMipLevels);
|
||||
if (!normalMapToRoughness)
|
||||
{
|
||||
std::wcout << _T("WARNING: Normal map for roughness not found.") << std::endl;
|
||||
std::cin.ignore();
|
||||
}
|
||||
}
|
||||
|
||||
const bool sRGB = (TexMode::color == currentTexMode) || (TexMode::a == currentTexMode);
|
||||
bool normWarning = false;
|
||||
int mip = 0;
|
||||
|
||||
bool finish = false;
|
||||
do
|
||||
{
|
||||
std::wcout << _T("Processing mipmap ") << mip << std::endl;
|
||||
|
||||
const int mipW = Math::Max(1, srcMipSet.m_nWidth >> mip);
|
||||
const int mipH = Math::Max(1, srcMipSet.m_nHeight >> mip);
|
||||
|
||||
std::wcout << _T("Processing mip ") << std::setw(2) << mip << _T(" [");
|
||||
const int length = Math::HighestBit(mipW) + 1;
|
||||
VERUS_FOR(i, length)
|
||||
std::wcout << _T("=");
|
||||
std::wcout << _T("]") << std::endl;
|
||||
|
||||
// Switch between in and out:
|
||||
const int inIndex = (mip & 0x1);
|
||||
const int outIndex = ((mip + 1) & 0x1);
|
||||
|
||||
VERUS_FOR(i, mipH)
|
||||
{
|
||||
const int offsetH = i * mipW;
|
||||
VERUS_FOR(j, mipW)
|
||||
{
|
||||
int offset = 0;
|
||||
int offset = offsetH;
|
||||
UINT32 color = 0;
|
||||
UINT32 colorFX = 0;
|
||||
UINT32 color2 = 0;
|
||||
|
||||
if (mip) // Generate mipmap level 1+:
|
||||
if (mip) // Generate mip level 1+:
|
||||
{
|
||||
offset = i * mipW + j;
|
||||
offset += j;
|
||||
|
||||
const int aboveMipW = mipW << 1;
|
||||
const int aboveMipH = mipH << 1;
|
||||
const int aboveMipEdgeW = aboveMipW - 1;
|
||||
const int aboveMipEdgeH = aboveMipH - 1;
|
||||
const int srcMipW = mipW << 1;
|
||||
const int srcMipH = mipH << 1;
|
||||
const int srcMipEdgeW = srcMipW - 1;
|
||||
const int srcMipEdgeH = srcMipH - 1;
|
||||
|
||||
const int sampleA[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
|
||||
const int sampleB[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
|
||||
const int sampleC[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
|
||||
const int sampleD[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
|
||||
const int coordA[2] = { Math::Clamp((j << 1) + 0, 0, srcMipEdgeW), Math::Clamp((i << 1) + 0, 0, srcMipEdgeH) };
|
||||
const int coordB[2] = { Math::Clamp((j << 1) + 1, 0, srcMipEdgeW), Math::Clamp((i << 1) + 0, 0, srcMipEdgeH) };
|
||||
const int coordC[2] = { Math::Clamp((j << 1) + 0, 0, srcMipEdgeW), Math::Clamp((i << 1) + 1, 0, srcMipEdgeH) };
|
||||
const int coordD[2] = { Math::Clamp((j << 1) + 1, 0, srcMipEdgeW), Math::Clamp((i << 1) + 1, 0, srcMipEdgeH) };
|
||||
|
||||
const int offsetA = sampleA[1] * aboveMipW + sampleA[0];
|
||||
const int offsetB = sampleB[1] * aboveMipW + sampleB[0];
|
||||
const int offsetC = sampleC[1] * aboveMipW + sampleC[0];
|
||||
const int offsetD = sampleD[1] * aboveMipW + sampleD[0];
|
||||
const int offsetA = coordA[1] * srcMipW + coordA[0];
|
||||
const int offsetB = coordB[1] * srcMipW + coordB[0];
|
||||
const int offsetC = coordC[1] * srcMipW + coordC[0];
|
||||
const int offsetD = coordD[1] * srcMipW + coordD[0];
|
||||
|
||||
if (argNormalMap)
|
||||
BYTE computedRoughness = 0;
|
||||
if (TexMode::n == currentTexMode || normalMapToRoughness) // N or X:
|
||||
{
|
||||
// Compute average normal:
|
||||
const int inIndexEx = normalMapToRoughness ? inIndex + 2 : inIndex;
|
||||
Vector4 data[4];
|
||||
float raw[4];
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, false); data[0] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, false); data[1] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, false); data[2] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, false); data[3] = Vector4::MakeFromPointer(raw);
|
||||
float floats[4];
|
||||
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetA], floats, false); data[0] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetB], floats, false); data[1] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetC], floats, false); data[2] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetD], floats, false); data[3] = Vector4::MakeFromPointer(floats);
|
||||
|
||||
// Generate FX mipmap:
|
||||
if (!vMipFX[inIndex].empty())
|
||||
{
|
||||
const BYTE* rgbaA = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetA]);
|
||||
const BYTE* rgbaB = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetB]);
|
||||
const BYTE* rgbaC = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetC]);
|
||||
const BYTE* rgbaD = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetD]);
|
||||
BYTE rgbaOut[4] =
|
||||
{
|
||||
static_cast<BYTE>((rgbaA[0] + rgbaB[0] + rgbaC[0] + rgbaD[0]) >> 2),
|
||||
static_cast<BYTE>((rgbaA[1] + rgbaB[1] + rgbaC[1] + rgbaD[1]) >> 2),
|
||||
static_cast<BYTE>((rgbaA[2] + rgbaB[2] + rgbaC[2] + rgbaD[2]) >> 2),
|
||||
static_cast<BYTE>((rgbaA[3] + rgbaB[3] + rgbaC[3] + rgbaD[3]) >> 2)
|
||||
};
|
||||
memcpy(&colorFX, rgbaOut, 4);
|
||||
}
|
||||
|
||||
const float prevAvgLength[4] =
|
||||
{
|
||||
data[0].getW(),
|
||||
data[1].getW(),
|
||||
data[2].getW(),
|
||||
data[3].getW()
|
||||
};
|
||||
data[0].setW(0);
|
||||
data[1].setW(0);
|
||||
data[2].setW(0);
|
||||
data[3].setW(0);
|
||||
|
||||
float minAvgLength = 1;
|
||||
VERUS_FOR(i, 4) // To [-1 to 1]:
|
||||
{
|
||||
data[i] = data[i] * 2.f - Vector4(1, 1, 1, 0);
|
||||
minAvgLength = Math::Min(minAvgLength, prevAvgLength[i]);
|
||||
data[i] = data[i] * 2.f - Vector4::Replicate(1);
|
||||
data[i].setW(0);
|
||||
}
|
||||
const Vector4 averageNormal = VMath::normalize(data[0] + data[1] + data[2] + data[3]);
|
||||
Vector4 computedData = averageNormal;
|
||||
computedData = computedData * 0.5f + Vector4::Replicate(0.5f); // To [0 to 1]:
|
||||
computedData.setW(0);
|
||||
color = Convert::ColorFloatToInt32(computedData.ToPointer(), false);
|
||||
|
||||
Vector4 avg = (
|
||||
data[0] * prevAvgLength[0] +
|
||||
data[1] * prevAvgLength[1] +
|
||||
data[2] * prevAvgLength[2] +
|
||||
data[3] * prevAvgLength[3]) * 0.25f;
|
||||
float len = VMath::length(avg);
|
||||
|
||||
if (len > minAvgLength) // Don't make it too smooth.
|
||||
len = (len + minAvgLength) * 0.5f;
|
||||
|
||||
Vector4 dataOut = VMath::normalize(data[0] + data[1] + data[2] + data[3]);
|
||||
if (argFade)
|
||||
dataOut = VMath::normalize(VMath::lerp(fadePerMip, Vector4(0, 0, 1, 0), dataOut));
|
||||
dataOut = dataOut * 0.5f + Vector4(0.5f, 0.5f, 0.5f, 0); // To [0 to 1]:
|
||||
dataOut.setW(len);
|
||||
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector4 data[4];
|
||||
float raw[4];
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, argColorData); data[0] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, argColorData); data[1] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, argColorData); data[2] = Vector4::MakeFromPointer(raw);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, argColorData); data[3] = Vector4::MakeFromPointer(raw);
|
||||
Vector4 dataOut = (data[0] + data[1] + data[2] + data[3]) * 0.25f;
|
||||
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), argColorData);
|
||||
}
|
||||
}
|
||||
else // Handle topmost mipmap level:
|
||||
{
|
||||
if (argNormalMap)
|
||||
{
|
||||
const bool upsideDownBGRA = false;
|
||||
if (upsideDownBGRA)
|
||||
// Compute roughness from normal:
|
||||
const bool saveRoughnessToAlpha = TexMode::n == currentTexMode && 1 == mip;
|
||||
if (normalMapToRoughness || saveRoughnessToAlpha)
|
||||
{
|
||||
// Input image is upside down BGRA (?):
|
||||
offset = (mipH - i - 1) * mipW + j;
|
||||
UINT32 input = 0;
|
||||
memcpy(&input, &pData[offset * 4], 4);
|
||||
reinterpret_cast<BYTE*>(&input)[3] >>= 2; // Divide alpha by 4.
|
||||
color = VERUS_COLOR_TO_D3D(input);
|
||||
offset = i * mipW + j;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = i * mipW + j;
|
||||
UINT32 input = 0;
|
||||
memcpy(&input, &pData[offset * 4], 4);
|
||||
reinterpret_cast<BYTE*>(&input)[3] = 0xFF;
|
||||
color = input;
|
||||
|
||||
if (!vMipFX[inIndex].empty())
|
||||
color2 = color;
|
||||
float averageRoughness = 0;
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
colorFX = vMipFX[inIndex][offset];
|
||||
BYTE* rgbaFX = reinterpret_cast<BYTE*>(&colorFX);
|
||||
rgbaFX[0] /= 4;
|
||||
rgbaFX[1] /= 4;
|
||||
rgbaFX[2] /= 4;
|
||||
rgbaFX[3] /= 4;
|
||||
const float d = VMath::dot(averageNormal, data[i]);
|
||||
const float bias = 0.85f;
|
||||
const float scale = 1.f / (1.f - 0.85f);
|
||||
averageRoughness += 1.f - Math::Clamp<float>((d - bias) * scale, 0, 1);
|
||||
}
|
||||
averageRoughness = Math::Clamp<float>(averageRoughness * 0.25f, 0, 1);
|
||||
computedRoughness = Convert::UnormToUint8(averageRoughness);
|
||||
|
||||
if (saveRoughnessToAlpha)
|
||||
{
|
||||
BYTE* pChannels = reinterpret_cast<BYTE*>(&color);
|
||||
pChannels[3] = computedRoughness;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Simple copy for color:
|
||||
if (TexMode::n != currentTexMode)
|
||||
{
|
||||
offset = i * mipW + j;
|
||||
UINT32 input = 0;
|
||||
memcpy(&input, &pData[offset * 4], 4);
|
||||
color = input;
|
||||
// Compute average value:
|
||||
Vector4 data[4];
|
||||
float floats[4];
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], floats, sRGB); data[0] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], floats, sRGB); data[1] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], floats, sRGB); data[2] = Vector4::MakeFromPointer(floats);
|
||||
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], floats, sRGB); data[3] = Vector4::MakeFromPointer(floats);
|
||||
|
||||
Vector4 computedData = (data[0] + data[1] + data[2] + data[3]) * 0.25f;
|
||||
color = Convert::ColorFloatToInt32(computedData.ToPointer(), sRGB);
|
||||
|
||||
if (normalMapToRoughness) // For X:
|
||||
{
|
||||
BYTE* pChannels = reinterpret_cast<BYTE*>(&color);
|
||||
pChannels[1] = Math::Max(pChannels[1], computedRoughness);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Handle topmost mip level:
|
||||
{
|
||||
offset += j;
|
||||
UINT32 input = 0;
|
||||
memcpy(&input, &pData[offset * bytesPerPixel], bytesPerPixel);
|
||||
// Normalize source normal map:
|
||||
if (TexMode::n == currentTexMode)
|
||||
{
|
||||
Vector4 data;
|
||||
float floats[4];
|
||||
Convert::ColorInt32ToFloat(input, floats, false); data = Vector4::MakeFromPointer(floats);
|
||||
data = data * 2.f - Vector4::Replicate(1); // To [-1 to 1]:
|
||||
data.setW(0);
|
||||
const float length = VMath::length(data);
|
||||
if (abs(length - 1.f) >= 0.01f)
|
||||
normWarning = true;
|
||||
data /= length;
|
||||
data = data * 0.5f + Vector4::Replicate(0.5f); // To [0 to 1]:
|
||||
data.setW(0);
|
||||
input = Convert::ColorFloatToInt32(data.ToPointer(), false);
|
||||
}
|
||||
// Add computed roughness from normal map:
|
||||
if (normalMapToRoughness)
|
||||
{
|
||||
const BYTE computedRoughness = vMip[outIndex + 2][offset] >> 24;
|
||||
BYTE* pChannels = reinterpret_cast<BYTE*>(&input);
|
||||
pChannels[1] = Math::Max(pChannels[1], computedRoughness);
|
||||
}
|
||||
color = input;
|
||||
}
|
||||
|
||||
vMip[outIndex][offset] = color;
|
||||
if (!vMipFX[outIndex].empty())
|
||||
vMipFX[outIndex][offset] = colorFX;
|
||||
if (mip && normalMapToRoughness)
|
||||
vMip[outIndex + 2][offset] = color2;
|
||||
}
|
||||
}
|
||||
|
||||
if (argNormalMap)
|
||||
{
|
||||
// Shuffle channels, read from outIndex, write to inIndex:
|
||||
const int pixelCount = mipW * mipH;
|
||||
VERUS_FOR(i, pixelCount)
|
||||
{
|
||||
BYTE* rgbaFX = vMipFX[outIndex].empty() ? nullptr : reinterpret_cast<BYTE*>(&vMipFX[outIndex][i]);
|
||||
BYTE* rgba = reinterpret_cast<BYTE*>(&vMip[outIndex][i]);
|
||||
const int len = Math::Clamp(rgba[3] - 128, 0, 0xFF);
|
||||
vMip[inIndex][i] = VERUS_COLOR_RGBA(rgbaFX ? rgbaFX[0] : 0, rgba[1], len, rgba[0]);
|
||||
}
|
||||
|
||||
// Save shuffled mip level, read from inIndex:
|
||||
CMP_MipLevel* pDstMipLevel = nullptr;
|
||||
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
|
||||
memcpy(pDstMipLevel->m_pbData, vMip[inIndex].data(), mipW * mipH * sizeof(UINT32));
|
||||
}
|
||||
else
|
||||
{
|
||||
CMP_MipLevel* pDstMipLevel = nullptr;
|
||||
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
|
||||
memcpy(pDstMipLevel->m_pbData, vMip[outIndex].data(), mipW * mipH * sizeof(UINT32));
|
||||
}
|
||||
// Copy to CMP_MipLevel:
|
||||
CMP_MipLevel* pDstMipLevel = nullptr;
|
||||
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
|
||||
memcpy(pDstMipLevel->m_pbData, vMip[outIndex].data(), mipW * mipH * bytesPerPixel);
|
||||
|
||||
finish = (mipW == 1) && (mipH == 1);
|
||||
mip++; // Next level, switch between in and out.
|
||||
|
||||
if (2 == mip && TexMode::n == currentTexMode)
|
||||
{
|
||||
String pathname = _pathname;
|
||||
Str::ReplaceExtension(pathname, ".TempR.tga");
|
||||
IO::FileSystem::SaveImage(_C(pathname), vMip[outIndex].data(), mipW, mipH);
|
||||
std::wcout << _T("Saved normal map for roughness as: ") << Str::Utf8ToWide(pathname) << std::endl;
|
||||
}
|
||||
} while (!finish);
|
||||
|
||||
CMP_MipSet dstMipSet = {};
|
||||
|
||||
KernelOptions kernelOptions = {};
|
||||
kernelOptions.format = CMP_FORMAT_BC7;
|
||||
kernelOptions.fquality = 0.51f; // Tests show that 51% is production quality.
|
||||
|
||||
cmpError = CMP_ProcessTexture(&srcMipSet, &dstMipSet, kernelOptions, CompressionCallback);
|
||||
if (CMP_OK != cmpError)
|
||||
if (normWarning)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_ProcessTexture(), ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
std::wcout << _T("WARNING: Source normal map was not normalized.") << std::endl;
|
||||
std::cin.ignore();
|
||||
}
|
||||
|
||||
Str::ReplaceExtension(pathname, ".dds");
|
||||
cmpError = CMP_SaveTexture(_C(pathname), &dstMipSet);
|
||||
if (CMP_OK != cmpError)
|
||||
Str::ReplaceExtension(_pathname, ".dds");
|
||||
if (_asIs)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_SaveTexture(), ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
cmpError = CMP_SaveTexture(_C(_pathname), &srcMipSet);
|
||||
if (CMP_OK != cmpError)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_SaveTexture(); ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CMP_MipSet dstMipSet = {};
|
||||
|
||||
KernelOptions kernelOptions = {};
|
||||
if (TexMode::n == currentTexMode)
|
||||
{
|
||||
kernelOptions.format = CMP_FORMAT_BC5;
|
||||
kernelOptions.fquality = 0.8f; // Use 80% for BC5.
|
||||
}
|
||||
else
|
||||
{
|
||||
kernelOptions.format = CMP_FORMAT_BC7;
|
||||
kernelOptions.fquality = 0.6f; // Use 60% for BC7.
|
||||
}
|
||||
|
||||
{
|
||||
CursorGuard cursorGuard;
|
||||
cmpError = CMP_ProcessTexture(&srcMipSet, &dstMipSet, kernelOptions, FeedbackProc);
|
||||
std::wcout << std::endl;
|
||||
}
|
||||
if (CMP_OK != cmpError)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_ProcessTexture(), ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
cmpError = CMP_SaveTexture(_C(_pathname), &dstMipSet);
|
||||
if (CMP_OK != cmpError)
|
||||
{
|
||||
std::wcerr << _T("ERROR: CMP_SaveTexture(); ") << cmpError << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
CMP_FreeMipSet(&dstMipSet);
|
||||
}
|
||||
CMP_FreeMipSet(&srcMipSet);
|
||||
CMP_FreeMipSet(&dstMipSet);
|
||||
|
||||
std::wcout << _T("Saved as: ") << Str::Utf8ToWide(_pathname) << std::endl;
|
||||
}
|
||||
|
||||
void TextureTool::ComputeEdgePadding()
|
||||
{
|
||||
if (!IO::FileSystem::FileExist(_C(_pathname)))
|
||||
{
|
||||
std::wcerr << _T("ERROR: File not found: ") << Str::Utf8ToWide(_pathname) << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
IO::Image image;
|
||||
image.Init(_C(_pathname));
|
||||
|
||||
IO::Image imageFaces;
|
||||
if (_edgePaddingUsingFaces)
|
||||
{
|
||||
Str::ReplaceFilename(_pathname, "Faces.png");
|
||||
if (!IO::FileSystem::FileExist(_C(_pathname)))
|
||||
{
|
||||
std::wcerr << _T("ERROR: File not found: ") << Str::Utf8ToWide(_pathname) << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
imageFaces.Init(_C(_pathname));
|
||||
if (image._width != imageFaces._width || image._height != imageFaces._height)
|
||||
{
|
||||
std::wcerr << _T("ERROR: Faces image has different size.") << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
if (_edgePaddingUsingAlpha)
|
||||
Utils::ComputeEdgePadding(image._p, image._pixelStride, image._p + 3, image._pixelStride, image._width, image._height, 0, 3);
|
||||
else if (_edgePaddingUsingFaces)
|
||||
Utils::ComputeEdgePadding(image._p, image._pixelStride, imageFaces._p, imageFaces._pixelStride, image._width, image._height, 0, 4);
|
||||
|
||||
Str::ReplaceFilename(_pathname, "ComputedEdgePadding.tga");
|
||||
IO::FileSystem::SaveImage(_C(_pathname), reinterpret_cast<UINT32*>(image._p), image._width, image._height, IO::ImageFormat::tga, image._pixelStride);
|
||||
}
|
||||
|
||||
void DeleteMipmap(CWSZ pathname)
|
||||
|
@ -356,7 +572,8 @@ int main(VERUS_MAIN_DEFAULT_ARGS)
|
|||
{
|
||||
try
|
||||
{
|
||||
Run();
|
||||
TextureTool textureTool;
|
||||
textureTool.Main(argc, argv);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>C:\Compressonator_4.2.5185\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\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.21.1-bin\include;C:\Home\Middleware\SDL2-2.0.16\include;C:\VulkanSDK\1.3.204.1\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_4.2.5185\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.21.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.16\lib\x64;C:\VulkanSDK\1.3.204.1\Lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Compressonator_4.2.5185\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\libogg-1.3.5\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.22.0-bin\include;C:\Home\Middleware\SDL2-2.0.22\include;C:\VulkanSDK\1.3.216.0\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_4.2.5185\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.5\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.22.0-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.22\lib\x64;C:\VulkanSDK\1.3.216.0\Lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{B154D670-E4B1-4D8A-885C-69546A5BD833}</ProjectGuid>
|
||||
<RootNamespace>Verus</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
|
@ -673,25 +673,6 @@
|
|||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\DS.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\LibDeferredShading.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\LibLighting.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
|
@ -817,22 +798,6 @@
|
|||
<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>
|
||||
|
@ -889,6 +854,49 @@
|
|||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\GenerateCubeMapMips.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\GenerateCubeMapMips.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\DS.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\LibDeferredShading.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_Ambient.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Ambient.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
|
|
@ -489,9 +489,6 @@
|
|||
<ClInclude Include="src\Scene\EditorTerrain.h">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\CGI\DeferredShading.h">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Scene\Helpers.h">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClInclude>
|
||||
|
@ -786,6 +783,9 @@
|
|||
<ClInclude Include="src\Scene\LightMapBaker.h">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\CGI\DeferredShading.h">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CGI\BaseGeometry.cpp">
|
||||
|
@ -1073,9 +1073,6 @@
|
|||
<ClCompile Include="src\Scene\EditorTerrain.cpp">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\CGI\DeferredShading.cpp">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Scene\Helpers.cpp">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1349,6 +1346,9 @@
|
|||
<ClCompile Include="src\Scene\LightMapBaker.cpp">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\CGI\DeferredShading.cpp">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\Lib.hlsl">
|
||||
|
@ -1378,21 +1378,6 @@
|
|||
<None Include="src\Shaders\GenerateMips.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\LibDeferredShading.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\LibLighting.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
|
@ -1477,18 +1462,6 @@
|
|||
<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>
|
||||
<None Include="src\Shaders\DS_Forest.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
|
@ -1531,6 +1504,39 @@
|
|||
<None Include="src\Shaders\DS_Reflection.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\GenerateCubeMapMips.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\GenerateCubeMapMips.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Compose.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\LibDeferredShading.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>
|
||||
<None Include="src\Shaders\DS_Ambient.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\DS_Ambient.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml.natvis">
|
||||
|
|
|
@ -50,7 +50,7 @@ void QualitySettings::SetQuality(OverallQuality q)
|
|||
_postProcessBloom = false;
|
||||
_postProcessLightShafts = false;
|
||||
_postProcessSSAO = false;
|
||||
_sceneGrassDensity = 600;
|
||||
_sceneGrassDensity = 500;
|
||||
_sceneShadowQuality = Quality::low;
|
||||
_sceneWaterQuality = WaterQuality::solidColor;
|
||||
break;
|
||||
|
@ -61,7 +61,7 @@ void QualitySettings::SetQuality(OverallQuality q)
|
|||
_gpuShaderQuality = Quality::high;
|
||||
_postProcessCinema = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 900;
|
||||
_sceneGrassDensity = 700;
|
||||
_sceneShadowQuality = Quality::high;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesReflection;
|
||||
break;
|
||||
|
@ -72,7 +72,7 @@ void QualitySettings::SetQuality(OverallQuality q)
|
|||
_postProcessMotionBlur = true;
|
||||
_postProcessSSR = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 1000;
|
||||
_sceneGrassDensity = 800;
|
||||
_sceneShadowQuality = Quality::ultra;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesRefraction;
|
||||
break;
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace verus
|
|||
bool _postProcessSSAO = true;
|
||||
bool _postProcessSSR = false;
|
||||
bool _sceneAmbientOcclusion = false;
|
||||
int _sceneGrassDensity = 800;
|
||||
int _sceneGrassDensity = 600;
|
||||
Quality _sceneShadowQuality = Quality::medium;
|
||||
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
|
||||
|
||||
|
@ -83,6 +83,7 @@ namespace verus
|
|||
int _ds_ubAOTexturesFSCapacity = 2;
|
||||
int _ds_ubAOPerMeshVSCapacity = 10;
|
||||
int _generateMips_ubCapacity = 50;
|
||||
int _generateCubeMapMips_ubCapacity = 50;
|
||||
int _grass_ubVSCapacity = 4;
|
||||
int _grass_ubFSCapacity = 4;
|
||||
int _gui_ubGuiCapacity = 100;
|
||||
|
|
|
@ -23,30 +23,41 @@ namespace verus
|
|||
virtual void Begin() = 0;
|
||||
virtual void End() = 0;
|
||||
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout,
|
||||
Range mipLevels, Range arrayLayers = 0) = 0;
|
||||
|
||||
// <RenderPass>
|
||||
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
|
||||
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
|
||||
virtual void NextSubpass() = 0;
|
||||
virtual void EndRenderPass() = 0;
|
||||
// </RenderPass>
|
||||
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter = UINT32_MAX) = 0;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) = 0;
|
||||
|
||||
// <Pipeline>
|
||||
virtual void BindPipeline(PipelinePtr pipe) = 0;
|
||||
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth = 0, float maxDepth = 1) = 0;
|
||||
virtual void SetScissor(std::initializer_list<Vector4> il) = 0;
|
||||
virtual void SetBlendConstants(const float* p) = 0;
|
||||
// </Pipeline>
|
||||
|
||||
// <VertexInput>
|
||||
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter = UINT32_MAX) = 0;
|
||||
virtual void BindIndexBuffer(GeometryPtr geo) = 0;
|
||||
// </VertexInput>
|
||||
|
||||
// <Descriptors>
|
||||
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle = CSHandle()) = 0;
|
||||
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
|
||||
// </Descriptors>
|
||||
|
||||
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout,
|
||||
Range mipLevels, int arrayLayer = 0) = 0;
|
||||
|
||||
// <Draw>
|
||||
virtual void Draw(int vertexCount, int instanceCount = 1, int firstVertex = 0, int firstInstance = 0) = 0;
|
||||
virtual void DrawIndexed(int indexCount, int instanceCount = 1, int firstIndex = 0, int vertexOffset = 0, int firstInstance = 0) = 0;
|
||||
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ = 1) = 0;
|
||||
virtual void DispatchIndirect() {} // WIP.
|
||||
virtual void DispatchMesh(int groupCountX, int groupCountY, int groupCountZ) {} // WIP.
|
||||
virtual void TraceRays(int width, int height, int depth) {} // WIP.
|
||||
// </Draw>
|
||||
|
||||
RcVector4 GetViewportSize() const { return _viewportSize; }
|
||||
};
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace verus
|
|||
int _sampleCount = 1;
|
||||
RPHandle _renderPassHandle;
|
||||
int _subpass = 0;
|
||||
int _multiViewport = 1; // See SV_ViewportArrayIndex semantic output by a geometry shader.
|
||||
UINT32 _vertexInputBindingsFilter = UINT32_MAX;
|
||||
CompareOp _depthCompareOp = CompareOp::less;
|
||||
bool _depthTestEnable = true;
|
||||
|
|
|
@ -59,14 +59,15 @@ namespace verus
|
|||
// Which graphics API?
|
||||
virtual Gapi GetGapi() = 0;
|
||||
|
||||
// Frame cycle:
|
||||
// <FrameCycle>
|
||||
virtual void BeginFrame(bool present = true) = 0;
|
||||
virtual void EndFrame(bool present = true) = 0;
|
||||
virtual void Present() = 0;
|
||||
virtual void Sync(bool present = true) = 0;
|
||||
virtual void WaitIdle() = 0;
|
||||
// </FrameCycle>
|
||||
|
||||
// Resources:
|
||||
// <Resources>
|
||||
virtual PBaseCommandBuffer InsertCommandBuffer() = 0;
|
||||
virtual PBaseGeometry InsertGeometry() = 0;
|
||||
virtual PBasePipeline InsertPipeline() = 0;
|
||||
|
@ -86,6 +87,7 @@ namespace verus
|
|||
int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) = 0;
|
||||
virtual void DeleteRenderPass(RPHandle handle) = 0;
|
||||
virtual void DeleteFramebuffer(FBHandle handle) = 0;
|
||||
// </Resources>
|
||||
|
||||
static void SetAlphaBlendHelper(
|
||||
CSZ sz,
|
||||
|
|
|
@ -61,7 +61,8 @@ namespace verus
|
|||
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size,
|
||||
int capacity = 1, std::initializer_list<Sampler> il = {}, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
|
||||
virtual void CreatePipelineLayout() = 0;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips = nullptr) = 0;
|
||||
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il,
|
||||
const int* pMipLevels = nullptr, const int* pArrayLayers = nullptr) = 0;
|
||||
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) = 0;
|
||||
|
||||
virtual void BeginBindDescriptors() = 0;
|
||||
|
|
|
@ -25,6 +25,28 @@ bool BaseTexture::IsSRGB() const
|
|||
!Str::EndsWith(_C(_name), ".X.dds");
|
||||
}
|
||||
|
||||
Format BaseTexture::ToTextureBcFormat(IO::RcDDSHeader header, IO::RcDDSHeaderDXT10 header10) const
|
||||
{
|
||||
auto SelectFormat = [this](Format unorm, Format srgb)
|
||||
{
|
||||
return IsSRGB() ? srgb : unorm;
|
||||
};
|
||||
if (header.IsBC1())
|
||||
return SelectFormat(Format::unormBC1, Format::srgbBC1);
|
||||
else if (header.IsBC2())
|
||||
return SelectFormat(Format::unormBC2, Format::srgbBC2);
|
||||
else if (header.IsBC3())
|
||||
return SelectFormat(Format::unormBC3, Format::srgbBC3);
|
||||
else if (header.IsBC4U() || header.IsBC4S())
|
||||
return Format::unormBC4;
|
||||
else if (header.IsBC5U() || header.IsBC5S())
|
||||
return Format::unormBC5;
|
||||
else if (header10.IsBC7())
|
||||
return SelectFormat(Format::unormBC7, Format::srgbBC7);
|
||||
VERUS_RT_FAIL("DDS format is not BC.");
|
||||
return Format::unormR8G8B8A8;
|
||||
}
|
||||
|
||||
void BaseTexture::LoadDDS(CSZ url, int texturePart)
|
||||
{
|
||||
_name = url;
|
||||
|
@ -58,20 +80,8 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
|
|||
|
||||
if (header.IsBC())
|
||||
{
|
||||
auto SelectFormat = [this](Format unorm, Format srgb)
|
||||
{
|
||||
return IsSRGB() ? srgb : unorm;
|
||||
};
|
||||
|
||||
TextureDesc desc;
|
||||
if (header.IsBC1())
|
||||
desc._format = SelectFormat(Format::unormBC1, Format::srgbBC1);
|
||||
else if (header.IsBC2())
|
||||
desc._format = SelectFormat(Format::unormBC2, Format::srgbBC2);
|
||||
else if (header.IsBC3())
|
||||
desc._format = SelectFormat(Format::unormBC3, Format::srgbBC3);
|
||||
else if (header10.IsBC7())
|
||||
desc._format = SelectFormat(Format::unormBC7, Format::srgbBC7);
|
||||
desc._format = ToTextureBcFormat(header, header10);
|
||||
desc._width = header._width >> lod;
|
||||
desc._height = header._height >> lod;
|
||||
desc._mipLevels = header._mipMapCount - lod;
|
||||
|
@ -236,14 +246,8 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
|
|||
|
||||
if (header.IsBC())
|
||||
{
|
||||
auto SelectFormat = [this](Format unorm, Format srgb)
|
||||
{
|
||||
return IsSRGB() ? srgb : unorm;
|
||||
};
|
||||
|
||||
const int w = header._width >> lod;
|
||||
const int h = header._height >> lod;
|
||||
|
||||
if (desc._width)
|
||||
{
|
||||
VERUS_RT_ASSERT(desc._width == w);
|
||||
|
@ -253,14 +257,7 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
|
|||
VERUS_RT_ASSERT(desc._height == h);
|
||||
}
|
||||
|
||||
if (header.IsBC1())
|
||||
desc._format = SelectFormat(Format::unormBC1, Format::srgbBC1);
|
||||
else if (header.IsBC2())
|
||||
desc._format = SelectFormat(Format::unormBC2, Format::srgbBC2);
|
||||
else if (header.IsBC3())
|
||||
desc._format = SelectFormat(Format::unormBC3, Format::srgbBC3);
|
||||
else if (header10.IsBC7())
|
||||
desc._format = SelectFormat(Format::unormBC7, Format::srgbBC7);
|
||||
desc._format = ToTextureBcFormat(header, header10);
|
||||
desc._width = w;
|
||||
desc._height = h;
|
||||
desc._mipLevels = header._mipMapCount - lod;
|
||||
|
@ -350,7 +347,7 @@ bool BaseTexture::IsBC(Format format)
|
|||
|
||||
bool BaseTexture::Is4BitsBC(Format format)
|
||||
{
|
||||
return format == Format::unormBC1 || format == Format::srgbBC1;
|
||||
return format == Format::unormBC1 || format == Format::srgbBC1 || format == Format::unormBC4;
|
||||
}
|
||||
|
||||
bool BaseTexture::IsDepthFormat(Format format)
|
||||
|
|
|
@ -104,6 +104,7 @@ namespace verus
|
|||
int GetPart() const { return _part; }
|
||||
RcVector4 GetSize() const { return _size; }
|
||||
bool IsSRGB() const;
|
||||
Format ToTextureBcFormat(IO::RcDDSHeader header, IO::RcDDSHeaderDXT10 header10) const;
|
||||
|
||||
void SetLoadingFlags(TextureDesc::Flags flags) { _desc._flags = flags; }
|
||||
void SetLoadingSamplerDesc(PcSamplerDesc pSamplerDesc) { _desc._pSamplerDesc = pSamplerDesc; }
|
||||
|
|
|
@ -10,10 +10,8 @@ DeferredShading::UB_PerMeshVS DeferredShading::s_ubPerMeshVS;
|
|||
DeferredShading::UB_ShadowFS DeferredShading::s_ubShadowFS;
|
||||
DeferredShading::UB_PerObject DeferredShading::s_ubPerObject;
|
||||
|
||||
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_AmbientVS DeferredShading::s_ubAmbientVS;
|
||||
DeferredShading::UB_AmbientFS DeferredShading::s_ubAmbientFS;
|
||||
|
||||
DeferredShading::UB_ComposeVS DeferredShading::s_ubComposeVS;
|
||||
DeferredShading::UB_ComposeFS DeferredShading::s_ubComposeFS;
|
||||
|
@ -45,6 +43,8 @@ void DeferredShading::Init()
|
|||
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("GBuffer1", Format::unormR10G10B10A2).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("LightAccAmb", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("LightAccDiff", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("LightAccSpec", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("Depth", Format::unormD24uintS8).LoadOpClear().Layout(ImageLayout::depthStencilAttachment, ImageLayout::depthStencilReadOnly)
|
||||
|
@ -54,16 +54,19 @@ void DeferredShading::Init()
|
|||
{
|
||||
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
|
||||
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
|
||||
RP::Ref("GBuffer2", ImageLayout::colorAttachment)
|
||||
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
|
||||
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
|
||||
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
|
||||
RP::Subpass("Sp1").Input(
|
||||
{
|
||||
RP::Ref("GBuffer0", ImageLayout::fsReadOnly),
|
||||
RP::Ref("GBuffer1", ImageLayout::fsReadOnly),
|
||||
RP::Ref("GBuffer2", ImageLayout::fsReadOnly),
|
||||
RP::Ref("GBuffer3", ImageLayout::fsReadOnly),
|
||||
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
|
||||
}).Color(
|
||||
{
|
||||
RP::Ref("LightAccAmb", ImageLayout::colorAttachment),
|
||||
RP::Ref("LightAccDiff", ImageLayout::colorAttachment),
|
||||
RP::Ref("LightAccSpec", ImageLayout::colorAttachment)
|
||||
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
|
||||
|
@ -71,37 +74,23 @@ void DeferredShading::Init()
|
|||
{
|
||||
RP::Dependency("Sp0", "Sp1").Mode(1)
|
||||
});
|
||||
const RP::Attachment::LoadOp loadOp = settings._postProcessSSAO ? RP::Attachment::LoadOp::load : RP::Attachment::LoadOp::clear;
|
||||
_rphAO = renderer->CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("Attach", Format::unormR8).SetLoadOp(loadOp).Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly)
|
||||
},
|
||||
{
|
||||
RP::Subpass("Sp0").Input(
|
||||
{
|
||||
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
|
||||
}).Color(
|
||||
{
|
||||
RP::Ref("Attach", ImageLayout::colorAttachment)
|
||||
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
|
||||
},
|
||||
{});
|
||||
_rphCompose = renderer->CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly)
|
||||
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpDontCare().Layout(ImageLayout::fsReadOnly)
|
||||
},
|
||||
{
|
||||
RP::Subpass("Sp0").Color(
|
||||
{
|
||||
RP::Ref("ComposedA", ImageLayout::colorAttachment),
|
||||
RP::Ref("ComposedB", ImageLayout::colorAttachment)
|
||||
RP::Ref("ComposedB", ImageLayout::colorAttachment),
|
||||
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
|
||||
})
|
||||
},
|
||||
{});
|
||||
// Extra stuff, which is not using deferred shading, for example water and sky:
|
||||
_rphExtraCompose = renderer->CreateRenderPass(
|
||||
_rphForwardRendering = renderer->CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("ComposedA", Format::floatR11G11B10).Layout(ImageLayout::fsReadOnly),
|
||||
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly, ImageLayout::depthStencilAttachment)
|
||||
|
@ -120,35 +109,39 @@ void DeferredShading::Init()
|
|||
_shader[SHADER_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings._limits._ds_ubPerFrameCapacity);
|
||||
_shader[SHADER_LIGHT]->CreateDescriptorSet(1, &s_ubTexturesFS, sizeof(s_ubTexturesFS), settings._limits._ds_ubTexturesFSCapacity,
|
||||
{
|
||||
Sampler::input,
|
||||
Sampler::input,
|
||||
Sampler::input,
|
||||
Sampler::input,
|
||||
Sampler::shadow,
|
||||
Sampler::nearestClampMipN
|
||||
Sampler::input, // GBuffer0
|
||||
Sampler::input, // GBuffer1
|
||||
Sampler::input, // GBuffer2
|
||||
Sampler::input, // GBuffer3
|
||||
Sampler::input, // Depth
|
||||
Sampler::shadow, // ShadowCmp
|
||||
Sampler::nearestClampMipN // Shadow
|
||||
}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings._limits._ds_ubPerMeshVSCapacity, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), settings._limits._ds_ubShadowFSCapacity, {}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0);
|
||||
_shader[SHADER_LIGHT]->CreatePipelineLayout();
|
||||
|
||||
_shader[SHADER_AO].Init("[Shaders]:DS_AO.hlsl");
|
||||
_shader[SHADER_AO]->CreateDescriptorSet(0, &s_ubAOPerFrame, sizeof(s_ubAOPerFrame), settings._limits._ds_ubAOPerFrameCapacity);
|
||||
_shader[SHADER_AO]->CreateDescriptorSet(1, &s_ubAOTexturesFS, sizeof(s_ubAOTexturesFS), settings._limits._ds_ubAOTexturesFSCapacity,
|
||||
_shader[SHADER_AMBIENT].Init("[Shaders]:DS_Ambient.hlsl");
|
||||
_shader[SHADER_AMBIENT]->CreateDescriptorSet(0, &s_ubAmbientVS, sizeof(s_ubAmbientVS), 2);
|
||||
_shader[SHADER_AMBIENT]->CreateDescriptorSet(1, &s_ubAmbientFS, sizeof(s_ubAmbientFS), 2,
|
||||
{
|
||||
Sampler::input,
|
||||
Sampler::nearestClampMipN
|
||||
Sampler::input, // GBuffer0
|
||||
Sampler::input, // GBuffer1
|
||||
Sampler::input, // GBuffer2
|
||||
Sampler::input, // GBuffer3
|
||||
Sampler::input, // Depth
|
||||
CGI::Sampler::linearClampMipN, // TerrainHeightmap
|
||||
CGI::Sampler::anisoClamp // TerrainBlend
|
||||
}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_AO]->CreateDescriptorSet(2, &s_ubAOPerMeshVS, sizeof(s_ubAOPerMeshVS), settings._limits._ds_ubAOPerMeshVSCapacity, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_AO]->CreateDescriptorSet(3, &s_ubAOPerObject, sizeof(s_ubAOPerObject), 0);
|
||||
_shader[SHADER_AO]->CreatePipelineLayout();
|
||||
_shader[SHADER_AMBIENT]->CreatePipelineLayout();
|
||||
|
||||
ShaderDesc shaderDesc("[Shaders]:DS_Compose.hlsl");
|
||||
String userDefines;
|
||||
if (settings._postProcessCinema)
|
||||
userDefines += " CINEMA";
|
||||
if (settings._postProcessBloom)
|
||||
userDefines += " BLOOM";
|
||||
if (settings._postProcessSSAO || settings._sceneAmbientOcclusion)
|
||||
userDefines += " AO";
|
||||
if (!userDefines.empty())
|
||||
{
|
||||
userDefines = userDefines.substr(1);
|
||||
|
@ -158,12 +151,13 @@ void DeferredShading::Init()
|
|||
_shader[SHADER_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 4, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 4,
|
||||
{
|
||||
Sampler::linearClampMipN, // GBuffer0
|
||||
Sampler::linearClampMipN, // GBuffer1
|
||||
Sampler::linearClampMipN, // GBuffer2|AO
|
||||
Sampler::linearClampMipN, // Depth|Composed
|
||||
Sampler::linearClampMipN, // AccDiff|Bloom
|
||||
Sampler::linearClampMipN // AccSpec
|
||||
Sampler::nearestClampMipN, // GBuffer0
|
||||
Sampler::nearestClampMipN, // GBuffer1
|
||||
Sampler::nearestClampMipN, // GBuffer2|Bloom
|
||||
Sampler::nearestClampMipN, // Depth|Composed
|
||||
Sampler::nearestClampMipN, // Ambient
|
||||
Sampler::nearestClampMipN, // Diffuse
|
||||
Sampler::nearestClampMipN // Specular
|
||||
}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_COMPOSE]->CreatePipelineLayout();
|
||||
|
||||
|
@ -171,7 +165,6 @@ void DeferredShading::Init()
|
|||
_shader[SHADER_REFLECTION]->CreateDescriptorSet(0, &s_ubReflectionVS, sizeof(s_ubReflectionVS), 2);
|
||||
_shader[SHADER_REFLECTION]->CreateDescriptorSet(1, &s_ubReflectionFS, sizeof(s_ubReflectionFS), 2,
|
||||
{
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN
|
||||
}, ShaderStageFlags::fs);
|
||||
|
@ -181,16 +174,33 @@ void DeferredShading::Init()
|
|||
_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
|
||||
Sampler::nearestClampMipN, // GBuffer0
|
||||
Sampler::nearestClampMipN, // GBuffer1
|
||||
Sampler::nearestClampMipN, // GBuffer2
|
||||
Sampler::nearestClampMipN // GBuffer3
|
||||
}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_BAKE_SPRITES]->CreatePipelineLayout();
|
||||
|
||||
{
|
||||
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_AMBIENT], "#", _rph, 1);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[1] = "";
|
||||
pipeDesc._colorAttachWriteMasks[2] = "";
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_AMBIENT].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[1] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[2] = "b";
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_COMPOSE].Init(pipeDesc);
|
||||
|
@ -198,10 +208,18 @@ void DeferredShading::Init()
|
|||
{
|
||||
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#", _rphReflection);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_REFLECTION].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#DebugCubeMap", _rphReflection);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_REFLECTION_DEBUG].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_AutoWithDepth());
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
|
@ -225,7 +243,7 @@ void DeferredShading::InitGBuffers(int w, int h)
|
|||
TextureDesc texDesc;
|
||||
|
||||
// GB0:
|
||||
texDesc._clearValue = Vector4(0);
|
||||
texDesc._clearValue = GetClearValueForGBuffer0();
|
||||
texDesc._name = "DeferredShading.GBuffer0";
|
||||
texDesc._format = Format::srgbR8G8B8A8;
|
||||
texDesc._width = w;
|
||||
|
@ -234,7 +252,7 @@ void DeferredShading::InitGBuffers(int w, int h)
|
|||
_tex[TEX_GBUFFER_0].Init(texDesc);
|
||||
|
||||
// GB1:
|
||||
texDesc._clearValue = Vector4(0, 0, 0.25f, 1);
|
||||
texDesc._clearValue = GetClearValueForGBuffer1();
|
||||
texDesc._name = "DeferredShading.GBuffer1";
|
||||
texDesc._format = Format::unormR10G10B10A2;
|
||||
texDesc._width = w;
|
||||
|
@ -243,20 +261,30 @@ void DeferredShading::InitGBuffers(int w, int h)
|
|||
_tex[TEX_GBUFFER_1].Init(texDesc);
|
||||
|
||||
// GB2:
|
||||
texDesc._clearValue = Vector4(1 / 8.f, 0.5f, 0.5f, 0);
|
||||
texDesc._clearValue = GetClearValueForGBuffer2();
|
||||
texDesc._name = "DeferredShading.GBuffer2";
|
||||
texDesc._format = Format::unormR8G8B8A8;
|
||||
texDesc._width = w;
|
||||
texDesc._height = h;
|
||||
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
|
||||
_tex[TEX_GBUFFER_2].Init(texDesc);
|
||||
|
||||
// GB3:
|
||||
texDesc._clearValue = GetClearValueForGBuffer3();
|
||||
texDesc._name = "DeferredShading.GBuffer3";
|
||||
texDesc._format = Format::unormR8G8B8A8;
|
||||
texDesc._width = w;
|
||||
texDesc._height = h;
|
||||
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
|
||||
_tex[TEX_GBUFFER_3].Init(texDesc);
|
||||
}
|
||||
|
||||
void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_texShadowAtmo = texShadow;
|
||||
if (texShadow)
|
||||
_texAtmoShadow = texShadow;
|
||||
|
||||
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
|
||||
_cshLight = _shader[SHADER_LIGHT]->BindDescriptorSetTextures(1,
|
||||
|
@ -264,61 +292,49 @@ void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
|
|||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_GBUFFER_3],
|
||||
renderer.GetTexDepthStencil(),
|
||||
_texShadowAtmo,
|
||||
_texShadowAtmo
|
||||
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_0],
|
||||
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_1]
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredShading::InitByBloom(TexturePtr tex)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
|
||||
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
tex,
|
||||
_tex[TEX_COMPOSED_A],
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT],
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE],
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR]
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredShading::InitByTerrain(TexturePtr texHeightmap, TexturePtr texBlend, int mapSide)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (texHeightmap)
|
||||
_texTerrainHeightmap = texHeightmap;
|
||||
if (texBlend)
|
||||
_texTerrainBlend = texBlend;
|
||||
if (mapSide > 1)
|
||||
_terrainMapSide = mapSide;
|
||||
|
||||
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
|
||||
_cshAmbient = _shader[SHADER_AMBIENT]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_COMPOSED_A],
|
||||
tex,
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredShading::InitBySsao(TexturePtr tex)
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
|
||||
const int scaledSwapChainHeight = settings.Scale(renderer.GetSwapChainHeight());
|
||||
|
||||
_texAO = tex;
|
||||
|
||||
_fbhAO = renderer->CreateFramebuffer(_rphAO,
|
||||
{
|
||||
tex,
|
||||
_tex[TEX_GBUFFER_3],
|
||||
renderer.GetTexDepthStencil(),
|
||||
},
|
||||
scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
|
||||
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
|
||||
_shader[SHADER_AO]->FreeDescriptorSet(_cshAO);
|
||||
|
||||
_cshAO = _shader[SHADER_AO]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetTexDepthStencil(),
|
||||
_tex[TEX_GBUFFER_1],
|
||||
});
|
||||
_cshCompose = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
tex,
|
||||
renderer.GetTexDepthStencil(),
|
||||
_tex[TEX_LIGHT_ACC_DIFF],
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
_texTerrainHeightmap ? _texTerrainHeightmap : _tex[TEX_GBUFFER_0],
|
||||
_texTerrainBlend ? _texTerrainBlend : _tex[TEX_GBUFFER_1]
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -339,18 +355,20 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
|
|||
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
|
||||
_shader[SHADER_REFLECTION]->FreeDescriptorSet(_cshReflection);
|
||||
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
|
||||
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
|
||||
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
|
||||
|
||||
renderer->DeleteFramebuffer(_fbhReflection);
|
||||
renderer->DeleteFramebuffer(_fbhExtraCompose);
|
||||
renderer->DeleteFramebuffer(_fbhForwardRendering);
|
||||
renderer->DeleteFramebuffer(_fbhCompose);
|
||||
renderer->DeleteFramebuffer(_fbhAO);
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
|
||||
_tex[TEX_COMPOSED_B].Done();
|
||||
_tex[TEX_COMPOSED_A].Done();
|
||||
_tex[TEX_LIGHT_ACC_SPEC].Done();
|
||||
_tex[TEX_LIGHT_ACC_DIFF].Done();
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR].Done();
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE].Done();
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT].Done();
|
||||
_tex[TEX_GBUFFER_3].Done();
|
||||
_tex[TEX_GBUFFER_2].Done();
|
||||
_tex[TEX_GBUFFER_1].Done();
|
||||
_tex[TEX_GBUFFER_0].Done();
|
||||
|
@ -371,10 +389,12 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
|
|||
texDesc._width = scaledSwapChainWidth;
|
||||
texDesc._height = scaledSwapChainHeight;
|
||||
texDesc._flags = TextureDesc::Flags::colorAttachment;
|
||||
texDesc._name = "DeferredShading.LightAccDiff";
|
||||
_tex[TEX_LIGHT_ACC_DIFF].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.LightAccSpec";
|
||||
_tex[TEX_LIGHT_ACC_SPEC].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.LightAccAmbient";
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.LightAccDiffuse";
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.LightAccSpecular";
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.ComposedA";
|
||||
_tex[TEX_COMPOSED_A].Init(texDesc);
|
||||
texDesc._name = "DeferredShading.ComposedB";
|
||||
|
@ -385,18 +405,21 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
|
|||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_LIGHT_ACC_DIFF],
|
||||
_tex[TEX_LIGHT_ACC_SPEC],
|
||||
_tex[TEX_GBUFFER_3],
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT],
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE],
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR],
|
||||
renderer.GetTexDepthStencil()
|
||||
},
|
||||
scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_fbhCompose = renderer->CreateFramebuffer(_rphCompose,
|
||||
{
|
||||
_tex[TEX_COMPOSED_A],
|
||||
_tex[TEX_COMPOSED_B]
|
||||
_tex[TEX_COMPOSED_B],
|
||||
_tex[TEX_GBUFFER_3]
|
||||
},
|
||||
scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_fbhExtraCompose = renderer->CreateFramebuffer(_rphExtraCompose,
|
||||
_fbhForwardRendering = renderer->CreateFramebuffer(_rphForwardRendering,
|
||||
{
|
||||
_tex[TEX_COMPOSED_A],
|
||||
renderer.GetTexDepthStencil()
|
||||
|
@ -414,14 +437,14 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
|
|||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
renderer.GetTexDepthStencil(),
|
||||
_tex[TEX_LIGHT_ACC_DIFF],
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT],
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE],
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR]
|
||||
});
|
||||
_cshReflection = _shader[SHADER_REFLECTION]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR]
|
||||
});
|
||||
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
|
@ -429,15 +452,18 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
|
|||
_tex[TEX_GBUFFER_1],
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_COMPOSED_A],
|
||||
_tex[TEX_LIGHT_ACC_DIFF],
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT],
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE],
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR]
|
||||
});
|
||||
|
||||
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
|
||||
_cshQuad[i] = renderer.GetShaderQuad()->BindDescriptorSetTextures(1, { _tex[TEX_GBUFFER_0 + i] });
|
||||
|
||||
if (_texShadowAtmo)
|
||||
InitByAtmosphere(_texShadowAtmo);
|
||||
if (_texAtmoShadow)
|
||||
InitByAtmosphere(_texAtmoShadow);
|
||||
|
||||
InitByTerrain(_texTerrainHeightmap, _texTerrainBlend, _terrainMapSide);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,7 +486,11 @@ void DeferredShading::ResetInstanceCount()
|
|||
dl.Get(LightType::spot).ResetInstanceCount();
|
||||
}
|
||||
|
||||
void DeferredShading::Draw(int gbuffer)
|
||||
void DeferredShading::Draw(int gbuffer,
|
||||
RcVector4 rMultiplexer,
|
||||
RcVector4 gMultiplexer,
|
||||
RcVector4 bMultiplexer,
|
||||
RcVector4 aMultiplexer)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
|
@ -472,6 +502,10 @@ void DeferredShading::Draw(int gbuffer)
|
|||
|
||||
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
renderer.GetUbQuadFS()._rMultiplexer = rMultiplexer.GLM();
|
||||
renderer.GetUbQuadFS()._gMultiplexer = gMultiplexer.GLM();
|
||||
renderer.GetUbQuadFS()._bMultiplexer = bMultiplexer.GLM();
|
||||
renderer.GetUbQuadFS()._aMultiplexer = aMultiplexer.GLM();
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_QUAD]);
|
||||
|
||||
|
@ -491,16 +525,24 @@ void DeferredShading::Draw(int gbuffer)
|
|||
cb->BindDescriptors(shader, 1, _cshQuad[2]);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->SetViewport({ Vector4(w, h, w, h) });
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[3]);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
|
||||
}
|
||||
else if (-2 == gbuffer)
|
||||
{
|
||||
cb->SetViewport({ Vector4(0, 0, w, h) });
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[3]);
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[4]);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->SetViewport({ Vector4(w, 0, w, h) });
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[4]);
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[5]);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->SetViewport({ Vector4(0, h, w, h) });
|
||||
cb->BindDescriptors(shader, 1, _cshQuad[6]);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
|
||||
|
@ -513,48 +555,67 @@ void DeferredShading::Draw(int gbuffer)
|
|||
shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void DeferredShading::BeginGeometryPass(bool onlySetRT, bool spriteBaking)
|
||||
void DeferredShading::BeginGeometryPass()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
TexturePtr depth = nullptr;
|
||||
if (onlySetRT)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass);
|
||||
_activeGeometryPass = true;
|
||||
_frame = renderer.GetFrameCount();
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
|
||||
_activeGeometryPass = true;
|
||||
_frame = renderer.GetFrameCount();
|
||||
|
||||
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_1]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_2]->GetClearValue(),
|
||||
_tex[TEX_LIGHT_ACC_DIFF]->GetClearValue(),
|
||||
_tex[TEX_LIGHT_ACC_SPEC]->GetClearValue(),
|
||||
renderer.GetTexDepthStencil()->GetClearValue()
|
||||
});
|
||||
}
|
||||
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
|
||||
{
|
||||
_tex[TEX_GBUFFER_0]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_1]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_2]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_3]->GetClearValue(),
|
||||
_tex[TEX_LIGHT_ACC_AMBIENT]->GetClearValue(),
|
||||
_tex[TEX_LIGHT_ACC_DIFFUSE]->GetClearValue(),
|
||||
_tex[TEX_LIGHT_ACC_SPECULAR]->GetClearValue(),
|
||||
renderer.GetTexDepthStencil()->GetClearValue()
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredShading::EndGeometryPass(bool resetRT)
|
||||
void DeferredShading::EndGeometryPass()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
|
||||
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass);
|
||||
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
|
||||
_activeGeometryPass = false;
|
||||
}
|
||||
|
||||
bool DeferredShading::BeginLightingPass()
|
||||
bool DeferredShading::BeginLightingPass(bool ambient, bool terrainOcclusion)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
|
||||
_activeLightingPass = true;
|
||||
|
||||
renderer.GetCommandBuffer()->NextSubpass();
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
cb->NextSubpass();
|
||||
|
||||
if (ambient)
|
||||
{
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
s_ubAmbientVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubAmbientVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubAmbientFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
|
||||
s_ubAmbientFS._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
|
||||
s_ubAmbientFS._ambientColorY0 = float4(atmo.GetAmbientColorY0().GLM(), 0);
|
||||
s_ubAmbientFS._ambientColorY1 = float4(atmo.GetAmbientColorY1().GLM(), 0);
|
||||
s_ubAmbientFS._invMapSide_minOcclusion.x = 1.f / _terrainMapSide;
|
||||
s_ubAmbientFS._invMapSide_minOcclusion.y = terrainOcclusion ? 0.f : 1.f;
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_AMBIENT]);
|
||||
_shader[SHADER_AMBIENT]->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader[SHADER_AMBIENT], 0);
|
||||
cb->BindDescriptors(_shader[SHADER_AMBIENT], 1, _cshAmbient);
|
||||
_shader[SHADER_AMBIENT]->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
}
|
||||
|
||||
_shader[SHADER_LIGHT]->BeginBindDescriptors();
|
||||
|
||||
if (!IsLoaded())
|
||||
|
@ -571,6 +632,10 @@ bool DeferredShading::BeginLightingPass()
|
|||
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._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[1] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[2] = "rgb";
|
||||
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_INSTANCED_DIR].Init(pipeDesc);
|
||||
|
@ -579,6 +644,10 @@ bool DeferredShading::BeginLightingPass()
|
|||
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._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[1] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[2] = "rgb";
|
||||
pipeDesc._rasterizationState._cullMode = CullMode::front;
|
||||
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
|
||||
pipeDesc._depthCompareOp = CompareOp::greater;
|
||||
|
@ -589,21 +658,16 @@ bool DeferredShading::BeginLightingPass()
|
|||
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._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[1] = "rgb";
|
||||
pipeDesc._colorAttachWriteMasks[2] = "rgb";
|
||||
pipeDesc._rasterizationState._cullMode = CullMode::front;
|
||||
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
|
||||
pipeDesc._depthCompareOp = CompareOp::greater;
|
||||
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;
|
||||
|
@ -613,42 +677,22 @@ void DeferredShading::EndLightingPass()
|
|||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass && !_activeForwardRendering);
|
||||
_activeLightingPass = false;
|
||||
|
||||
_shader[SHADER_LIGHT]->EndBindDescriptors();
|
||||
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(RcVector4 bgColor)
|
||||
void DeferredShading::BeginComposeAndForwardRendering(bool underwaterMask)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_WATER;
|
||||
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
|
||||
_activeForwardRendering = true;
|
||||
|
||||
const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP());
|
||||
|
||||
|
@ -656,22 +700,21 @@ void DeferredShading::BeginCompose(RcVector4 bgColor)
|
|||
|
||||
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubComposeFS._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
|
||||
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
|
||||
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
|
||||
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
|
||||
s_ubComposeFS._backgroundColor = bgColor.GLM();
|
||||
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
|
||||
s_ubComposeFS._exposure_underwaterMask.y = underwaterMask ? 1.f : 0.f;
|
||||
s_ubComposeFS._backgroundColor = _backgroundColor.GLM();
|
||||
s_ubComposeFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubComposeFS._waterDiffColorShallow = float4(water.GetDiffuseColorShallow().GLM(), water.GetFogDensity());
|
||||
s_ubComposeFS._waterDiffColorDeep = float4(water.GetDiffuseColorDeep().GLM(), water.IsUnderwater() ? 1.f : 0.f);
|
||||
s_ubComposeFS._lightGlossScale.x = _lightGlossScale;
|
||||
|
||||
// Compose buffers, that is perform "final color = albedo * diffuse + specular" computation. Result is still HDR:
|
||||
cb->BeginRenderPass(_rphCompose, _fbhCompose,
|
||||
{
|
||||
_tex[TEX_COMPOSED_A]->GetClearValue(),
|
||||
_tex[TEX_COMPOSED_B]->GetClearValue()
|
||||
_tex[TEX_COMPOSED_B]->GetClearValue(),
|
||||
_tex[TEX_GBUFFER_3]->GetClearValue()
|
||||
});
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_COMPOSE]);
|
||||
|
@ -684,16 +727,19 @@ void DeferredShading::BeginCompose(RcVector4 bgColor)
|
|||
cb->EndRenderPass();
|
||||
|
||||
// Begin drawing extra stuff, which is not using deferred shading, for example water (updates depth buffer) and sky:
|
||||
cb->BeginRenderPass(_rphExtraCompose, _fbhExtraCompose,
|
||||
cb->BeginRenderPass(_rphForwardRendering, _fbhForwardRendering,
|
||||
{
|
||||
_tex[TEX_COMPOSED_A]->GetClearValue(),
|
||||
renderer.GetTexDepthStencil()->GetClearValue()
|
||||
});
|
||||
}
|
||||
|
||||
void DeferredShading::EndCompose()
|
||||
void DeferredShading::EndComposeAndForwardRendering()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
|
||||
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && _activeForwardRendering);
|
||||
_activeForwardRendering = false;
|
||||
|
||||
renderer.GetCommandBuffer()->EndRenderPass();
|
||||
}
|
||||
|
@ -701,6 +747,7 @@ void DeferredShading::EndCompose()
|
|||
void DeferredShading::DrawReflection()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSR;
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
|
@ -709,7 +756,7 @@ void DeferredShading::DrawReflection()
|
|||
|
||||
cb->BeginRenderPass(_rphReflection, _fbhReflection, { _tex[TEX_COMPOSED_A]->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_REFLECTION]);
|
||||
cb->BindPipeline(ssr.IsCubeMapDebugMode() ? _pipe[PIPE_REFLECTION_DEBUG] : _pipe[PIPE_REFLECTION]);
|
||||
_shader[SHADER_REFLECTION]->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader[SHADER_REFLECTION], 0);
|
||||
cb->BindDescriptors(_shader[SHADER_REFLECTION], 1, _cshReflection);
|
||||
|
@ -722,17 +769,12 @@ void DeferredShading::DrawReflection()
|
|||
void DeferredShading::ToneMapping()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
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()->GetMatrixInvV().UniformBufferFormat();
|
||||
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
|
||||
s_ubComposeFS._fogColor = Vector4(0.5f, 0.5f, 0.5f, 0.002f).GLM();
|
||||
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
|
||||
|
||||
// Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve:
|
||||
cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
|
||||
|
@ -756,12 +798,11 @@ void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool w
|
|||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
s_ubPerFrame._matQuad = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
|
||||
s_ubPerFrame._matInvV = sm.GetCamera()->GetMatrixInvV().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);
|
||||
s_ubPerFrame._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
@ -801,33 +842,6 @@ void DeferredShading::BindDescriptorsPerMeshVS(CommandBufferPtr cb)
|
|||
cb->BindDescriptors(_shader[SHADER_LIGHT], 2);
|
||||
}
|
||||
|
||||
void DeferredShading::OnNewAOType(CommandBufferPtr cb, LightType type)
|
||||
{
|
||||
VERUS_QREF_SM;
|
||||
|
||||
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();
|
||||
|
||||
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::BindDescriptorsAOPerMeshVS(CommandBufferPtr cb)
|
||||
{
|
||||
cb->BindDescriptors(_shader[SHADER_AO], 2);
|
||||
}
|
||||
|
||||
void DeferredShading::Load()
|
||||
{
|
||||
VERUS_QREF_HELPERS;
|
||||
|
@ -851,14 +865,19 @@ TexturePtr DeferredShading::GetGBuffer(int index)
|
|||
return _tex[index];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetLightAccDiffTexture()
|
||||
TexturePtr DeferredShading::GetLightAccAmbientTexture()
|
||||
{
|
||||
return _tex[TEX_LIGHT_ACC_DIFF];
|
||||
return _tex[TEX_LIGHT_ACC_AMBIENT];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetLightAccSpecTexture()
|
||||
TexturePtr DeferredShading::GetLightAccDiffuseTexture()
|
||||
{
|
||||
return _tex[TEX_LIGHT_ACC_SPEC];
|
||||
return _tex[TEX_LIGHT_ACC_DIFFUSE];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetLightAccSpecularTexture()
|
||||
{
|
||||
return _tex[TEX_LIGHT_ACC_SPECULAR];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetComposedTextureA()
|
||||
|
@ -871,22 +890,27 @@ TexturePtr DeferredShading::GetComposedTextureB()
|
|||
return _tex[TEX_COMPOSED_B];
|
||||
}
|
||||
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer0()
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer0(float albedo)
|
||||
{
|
||||
return Vector4(0.5f, 0.5f, 0.5f, 0.25f);
|
||||
return Vector4(albedo, albedo, albedo, 0.5f);
|
||||
}
|
||||
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer1()
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer1(float normal, float motionBlur)
|
||||
{
|
||||
return Vector4(0.5f, 0.5f, 0.25f);
|
||||
return Vector4(normal, normal, 0, motionBlur);
|
||||
}
|
||||
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer2()
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer2(float roughness)
|
||||
{
|
||||
return Vector4(0.125f, 0.5f, 0.5f, 0.125f);
|
||||
return Vector4(1, roughness, 0, 0);
|
||||
}
|
||||
|
||||
void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB)
|
||||
Vector4 DeferredShading::GetClearValueForGBuffer3(float tangent)
|
||||
{
|
||||
return Vector4(tangent, tangent, 0, 0);
|
||||
}
|
||||
|
||||
void DeferredShading::BakeSprites(TexturePtr texGBufferIn[4], TexturePtr texGBufferOut[4], PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
|
@ -902,13 +926,15 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
|
|||
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::Attachment("GBuffer3", 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)
|
||||
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
|
||||
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
|
||||
})
|
||||
},
|
||||
{});
|
||||
|
@ -917,7 +943,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
|
|||
{
|
||||
texGBufferOut[0],
|
||||
texGBufferOut[1],
|
||||
texGBufferOut[2]
|
||||
texGBufferOut[2],
|
||||
texGBufferOut[3]
|
||||
},
|
||||
w, h);
|
||||
|
||||
|
@ -925,7 +952,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
|
|||
{
|
||||
texGBufferIn[0],
|
||||
texGBufferIn[1],
|
||||
texGBufferIn[2]
|
||||
texGBufferIn[2],
|
||||
texGBufferIn[3]
|
||||
});
|
||||
|
||||
{
|
||||
|
@ -933,6 +961,7 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
|
|||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_BAKE_SPRITES].Init(pipeDesc);
|
||||
|
@ -945,7 +974,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
|
|||
{
|
||||
texGBufferOut[0]->GetClearValue(),
|
||||
texGBufferOut[1]->GetClearValue(),
|
||||
texGBufferOut[2]->GetClearValue()
|
||||
texGBufferOut[2]->GetClearValue(),
|
||||
texGBufferOut[3]->GetClearValue()
|
||||
});
|
||||
|
||||
pCB->BindPipeline(_pipe[PIPE_BAKE_SPRITES]);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace verus
|
|||
class DeferredShading : public Object
|
||||
{
|
||||
#include "../Shaders/DS.inc.hlsl"
|
||||
#include "../Shaders/DS_AO.inc.hlsl"
|
||||
#include "../Shaders/DS_Ambient.inc.hlsl"
|
||||
#include "../Shaders/DS_Compose.inc.hlsl"
|
||||
#include "../Shaders/DS_Reflection.inc.hlsl"
|
||||
#include "../Shaders/DS_BakeSprites.inc.hlsl"
|
||||
|
@ -24,7 +24,7 @@ namespace verus
|
|||
enum SHADER
|
||||
{
|
||||
SHADER_LIGHT,
|
||||
SHADER_AO,
|
||||
SHADER_AMBIENT,
|
||||
SHADER_COMPOSE,
|
||||
SHADER_REFLECTION,
|
||||
SHADER_BAKE_SPRITES,
|
||||
|
@ -36,9 +36,10 @@ namespace verus
|
|||
PIPE_INSTANCED_DIR,
|
||||
PIPE_INSTANCED_OMNI,
|
||||
PIPE_INSTANCED_SPOT,
|
||||
PIPE_INSTANCED_AO,
|
||||
PIPE_AMBIENT,
|
||||
PIPE_COMPOSE,
|
||||
PIPE_REFLECTION,
|
||||
PIPE_REFLECTION_DEBUG,
|
||||
PIPE_TONE_MAPPING,
|
||||
PIPE_QUAD,
|
||||
PIPE_BAKE_SPRITES,
|
||||
|
@ -47,13 +48,18 @@ namespace verus
|
|||
|
||||
enum TEX
|
||||
{
|
||||
TEX_GBUFFER_0, // Albedo, Spec.
|
||||
TEX_GBUFFER_1, // RG - Normals, Emission, Motion.
|
||||
TEX_GBUFFER_2, // LamScale, LamBias, Metallicity, Gloss.
|
||||
TEX_LIGHT_ACC_DIFF,
|
||||
TEX_LIGHT_ACC_SPEC,
|
||||
TEX_GBUFFER_0, // {Albedo.rgb, SSSHue}.
|
||||
TEX_GBUFFER_1, // {Normal.xy, Emission, MotionBlur}.
|
||||
TEX_GBUFFER_2, // {Occlusion, Roughness, Metallic, WrapDiffuse}.
|
||||
TEX_GBUFFER_3, // {Tangent.xy, AnisoSpec, RoughDiffuse}.
|
||||
|
||||
TEX_LIGHT_ACC_AMBIENT,
|
||||
TEX_LIGHT_ACC_DIFFUSE,
|
||||
TEX_LIGHT_ACC_SPECULAR,
|
||||
|
||||
TEX_COMPOSED_A,
|
||||
TEX_COMPOSED_B,
|
||||
|
||||
TEX_COUNT
|
||||
};
|
||||
|
||||
|
@ -63,10 +69,8 @@ namespace verus
|
|||
static UB_ShadowFS s_ubShadowFS;
|
||||
static UB_PerObject s_ubPerObject;
|
||||
|
||||
static UB_AOPerFrame s_ubAOPerFrame;
|
||||
static UB_AOTexturesFS s_ubAOTexturesFS;
|
||||
static UB_AOPerMeshVS s_ubAOPerMeshVS;
|
||||
static UB_AOPerObject s_ubAOPerObject;
|
||||
static UB_AmbientVS s_ubAmbientVS;
|
||||
static UB_AmbientFS s_ubAmbientFS;
|
||||
|
||||
static UB_ComposeVS s_ubComposeVS;
|
||||
static UB_ComposeFS s_ubComposeFS;
|
||||
|
@ -77,38 +81,40 @@ namespace verus
|
|||
static UB_BakeSpritesVS s_ubBakeSpritesVS;
|
||||
static UB_BakeSpritesFS s_ubBakeSpritesFS;
|
||||
|
||||
Vector4 _backgroundColor = Vector4(0);
|
||||
ShaderPwns<SHADER_COUNT> _shader;
|
||||
PipelinePwns<PIPE_COUNT> _pipe;
|
||||
TexturePwns<TEX_COUNT> _tex;
|
||||
TexturePtr _texShadowAtmo;
|
||||
TexturePtr _texAO;
|
||||
TexturePtr _texAtmoShadow;
|
||||
TexturePtr _texTerrainHeightmap;
|
||||
TexturePtr _texTerrainBlend;
|
||||
UINT64 _frame = 0;
|
||||
|
||||
RPHandle _rph;
|
||||
RPHandle _rphAO;
|
||||
RPHandle _rphCompose;
|
||||
RPHandle _rphExtraCompose;
|
||||
RPHandle _rphForwardRendering;
|
||||
RPHandle _rphReflection;
|
||||
RPHandle _rphBakeSprites;
|
||||
|
||||
FBHandle _fbh;
|
||||
FBHandle _fbhAO;
|
||||
FBHandle _fbhCompose;
|
||||
FBHandle _fbhExtraCompose;
|
||||
FBHandle _fbhForwardRendering;
|
||||
FBHandle _fbhReflection;
|
||||
FBHandle _fbhBakeSprites;
|
||||
|
||||
CSHandle _cshLight;
|
||||
CSHandle _cshAO;
|
||||
CSHandle _cshAmbient;
|
||||
CSHandle _cshCompose;
|
||||
CSHandle _cshReflection;
|
||||
CSHandle _cshToneMapping;
|
||||
CSHandle _cshQuad[5];
|
||||
CSHandle _cshQuad[7];
|
||||
CSHandle _cshBakeSprites;
|
||||
|
||||
float _lightGlossScale = 1;
|
||||
int _terrainMapSide = 1;
|
||||
|
||||
bool _activeGeometryPass = false;
|
||||
bool _activeLightingPass = false;
|
||||
bool _activeForwardRendering = false;
|
||||
bool _async_initPipe = false;
|
||||
|
||||
public:
|
||||
|
@ -119,7 +125,8 @@ namespace verus
|
|||
void InitGBuffers(int w, int h);
|
||||
void InitByAtmosphere(TexturePtr texShadow);
|
||||
void InitByBloom(TexturePtr tex);
|
||||
void InitBySsao(TexturePtr tex);
|
||||
void InitByTerrain(TexturePtr texHeightmap, TexturePtr texBlend, int mapSide);
|
||||
|
||||
void Done();
|
||||
|
||||
void OnSwapChainResized(bool init, bool done);
|
||||
|
@ -127,52 +134,52 @@ namespace verus
|
|||
static bool IsLoaded();
|
||||
|
||||
void ResetInstanceCount();
|
||||
void Draw(int gbuffer);
|
||||
|
||||
bool IsActiveGeometryPass() const { return _activeGeometryPass; }
|
||||
bool IsActiveLightingPass() const { return _activeLightingPass; }
|
||||
void Draw(int gbuffer,
|
||||
RcVector4 rMultiplexer = Vector4(1, 0, 0, 0),
|
||||
RcVector4 gMultiplexer = Vector4(0, 1, 0, 0),
|
||||
RcVector4 bMultiplexer = Vector4(0, 0, 1, 0),
|
||||
RcVector4 aMultiplexer = Vector4(0, 0, 0, 1));
|
||||
|
||||
RPHandle GetRenderPassHandle() const { return _rph; }
|
||||
RPHandle GetRenderPassHandle_ExtraCompose() const { return _rphExtraCompose; }
|
||||
RPHandle GetRenderPassHandle_ForwardRendering() const { return _rphForwardRendering; }
|
||||
|
||||
void BeginGeometryPass(bool onlySetRT = false, bool spriteBaking = false);
|
||||
void EndGeometryPass(bool resetRT = false);
|
||||
bool BeginLightingPass();
|
||||
// Steps:
|
||||
void BeginGeometryPass();
|
||||
void EndGeometryPass();
|
||||
bool BeginLightingPass(bool ambient = true, bool terrainOcclusion = true);
|
||||
void EndLightingPass();
|
||||
void BeginAmbientOcclusion();
|
||||
void EndAmbientOcclusion();
|
||||
void BeginCompose(RcVector4 bgColor = Vector4(0));
|
||||
void EndCompose();
|
||||
void BeginComposeAndForwardRendering(bool underwaterMask = true);
|
||||
void EndComposeAndForwardRendering();
|
||||
void DrawReflection();
|
||||
void ToneMapping();
|
||||
bool IsActiveGeometryPass() const { return _activeGeometryPass; }
|
||||
bool IsActiveLightingPass() const { return _activeLightingPass; }
|
||||
bool IsActiveForwardRendering() const { return _activeForwardRendering; }
|
||||
|
||||
// Lighting:
|
||||
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 OnNewAOType(CommandBufferPtr cb, LightType type);
|
||||
void BindDescriptorsAOPerMeshVS(CommandBufferPtr cb);
|
||||
static UB_AOPerMeshVS& GetUbAOPerMeshVS() { return s_ubAOPerMeshVS; }
|
||||
|
||||
void Load();
|
||||
|
||||
TexturePtr GetGBuffer(int index);
|
||||
TexturePtr GetLightAccDiffTexture();
|
||||
TexturePtr GetLightAccSpecTexture();
|
||||
TexturePtr GetLightAccAmbientTexture();
|
||||
TexturePtr GetLightAccDiffuseTexture();
|
||||
TexturePtr GetLightAccSpecularTexture();
|
||||
TexturePtr GetComposedTextureA();
|
||||
TexturePtr GetComposedTextureB();
|
||||
|
||||
static Vector4 GetClearValueForGBuffer0();
|
||||
static Vector4 GetClearValueForGBuffer1();
|
||||
static Vector4 GetClearValueForGBuffer2();
|
||||
static Vector4 GetClearValueForGBuffer0(float albedo = 0);
|
||||
static Vector4 GetClearValueForGBuffer1(float normal = 0, float motionBlur = 1);
|
||||
static Vector4 GetClearValueForGBuffer2(float roughness = 0);
|
||||
static Vector4 GetClearValueForGBuffer3(float tangent = 0);
|
||||
|
||||
void BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB = nullptr);
|
||||
void SetBackgroundColor(RcVector4 backgroundColor) { _backgroundColor = backgroundColor; }
|
||||
|
||||
void BakeSprites(TexturePtr texGBufferIn[4], TexturePtr texGBufferOut[4], PBaseCommandBuffer pCB = nullptr);
|
||||
void BakeSpritesCleanup();
|
||||
|
||||
// For Editor:
|
||||
float GetLightGlossScale() const { return _lightGlossScale; }
|
||||
void SetLightGlossScale(float s) { _lightGlossScale = s; }
|
||||
};
|
||||
VERUS_TYPEDEFS(DeferredShading);
|
||||
}
|
||||
|
|
|
@ -37,14 +37,18 @@ namespace verus
|
|||
floatD32,
|
||||
|
||||
// Compressed Texture Formats:
|
||||
unormBC1,
|
||||
unormBC2,
|
||||
unormBC3,
|
||||
unormBC7,
|
||||
srgbBC1,
|
||||
srgbBC2,
|
||||
srgbBC3,
|
||||
srgbBC7
|
||||
unormBC1, // Deprecated RGBA.
|
||||
unormBC2, // Deprecated RGBA.
|
||||
unormBC3, // Deprecated RGBA.
|
||||
unormBC4, // R.
|
||||
unormBC5, // RG.
|
||||
unormBC7, // RGBA.
|
||||
snormBC4, // R.
|
||||
snormBC5, // RG.
|
||||
srgbBC1, // Deprecated RGBA.
|
||||
srgbBC2, // Deprecated RGBA.
|
||||
srgbBC3, // Deprecated RGBA.
|
||||
srgbBC7 // RGBA.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,15 +119,29 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
|
|||
_shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
|
||||
_shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), settings.GetLimits()._generateMips_ubCapacity,
|
||||
{
|
||||
Sampler::linearClampMipN,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage
|
||||
Sampler::linearClampMipN, // Texture
|
||||
Sampler::storage, // Mip N
|
||||
Sampler::storage, // Mip N+1
|
||||
Sampler::storage, // Mip N+2
|
||||
Sampler::storage // Mip N+3
|
||||
},
|
||||
ShaderStageFlags::cs);
|
||||
_shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout();
|
||||
|
||||
_shader[SHADER_GENERATE_CUBE_MAP_MIPS].Init("[Shaders]:GenerateCubeMapMips.hlsl");
|
||||
_shader[SHADER_GENERATE_CUBE_MAP_MIPS]->CreateDescriptorSet(0, &_ubGenerateCubeMapMips, sizeof(_ubGenerateCubeMapMips), settings.GetLimits()._generateCubeMapMips_ubCapacity,
|
||||
{
|
||||
Sampler::linearMipN, // CubeMap
|
||||
Sampler::storage, // Face +X
|
||||
Sampler::storage, // Face -X
|
||||
Sampler::storage, // Face +Y
|
||||
Sampler::storage, // Face -Y
|
||||
Sampler::storage, // Face +Z
|
||||
Sampler::storage // Face -Z
|
||||
},
|
||||
ShaderStageFlags::cs);
|
||||
_shader[SHADER_GENERATE_CUBE_MAP_MIPS]->CreatePipelineLayout();
|
||||
|
||||
_shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl");
|
||||
_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);
|
||||
|
@ -144,6 +158,11 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
|
|||
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#Exposure");
|
||||
_pipe[PIPE_GENERATE_MIPS_EXPOSURE].Init(pipeDesc);
|
||||
}
|
||||
if (_allowInitShaders)
|
||||
{
|
||||
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_CUBE_MAP_MIPS], "#");
|
||||
_pipe[PIPE_GENERATE_CUBE_MAP_MIPS].Init(pipeDesc);
|
||||
}
|
||||
if (settings._displayOffscreenDraw)
|
||||
{
|
||||
PipelineDesc pipeDesc(_geoQuad, _shader[SHADER_QUAD], "#", _rphSwapChainWithDepth);
|
||||
|
@ -158,7 +177,9 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
|
|||
ImGuiUpdateStyle();
|
||||
|
||||
if (_allowInitShaders)
|
||||
{
|
||||
_ds.Init();
|
||||
}
|
||||
|
||||
SetExposureValue(15);
|
||||
}
|
||||
|
@ -225,18 +246,18 @@ 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.3f + 0.6f * expScale * expScale; // Dark scene exposure compensation.
|
||||
const float expScale = Math::Clamp(_exposure[1] * (1 / 16.f), 0.f, 1.f);
|
||||
const float target = -0.2f + 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) * 15;
|
||||
const float delta = target - important;
|
||||
const float speed = (delta * delta) * ((delta > 0) ? 5.f : 15.f);
|
||||
|
||||
if (important < target * 0.95f)
|
||||
if (important < target * 0.99f)
|
||||
_exposure[1] -= speed * dt;
|
||||
else if (important > target * (1 / 0.95f))
|
||||
else if (important > target * (1 / 0.99f))
|
||||
_exposure[1] += speed * dt;
|
||||
|
||||
_exposure[1] = Math::Clamp(_exposure[1], 0.f, 15.f);
|
||||
_exposure[1] = Math::Clamp(_exposure[1], 0.f, 16.f);
|
||||
SetExposureValue(_exposure[1]);
|
||||
}
|
||||
}
|
||||
|
@ -386,6 +407,7 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass)
|
|||
|
||||
_ubQuadVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
_ubQuadVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
ResetQuadMultiplexer();
|
||||
|
||||
pCB->BeginRenderPass(_rphSwapChainWithDepth, _fbhSwapChainWithDepth[_pBaseRenderer->GetSwapChainBufferIndex()], { Vector4(0), Vector4(1) });
|
||||
|
||||
|
@ -602,16 +624,31 @@ ShaderPtr Renderer::GetShaderGenerateMips() const
|
|||
return _shader[SHADER_GENERATE_MIPS];
|
||||
}
|
||||
|
||||
ShaderPtr Renderer::GetShaderGenerateCubeMapMips() const
|
||||
{
|
||||
return _shader[SHADER_GENERATE_CUBE_MAP_MIPS];
|
||||
}
|
||||
|
||||
PipelinePtr Renderer::GetPipelineGenerateMips(bool exposure) const
|
||||
{
|
||||
return _pipe[exposure ? PIPE_GENERATE_MIPS_EXPOSURE : PIPE_GENERATE_MIPS];
|
||||
}
|
||||
|
||||
PipelinePtr Renderer::GetPipelineGenerateCubeMapMips() const
|
||||
{
|
||||
return _pipe[PIPE_GENERATE_CUBE_MAP_MIPS];
|
||||
}
|
||||
|
||||
Renderer::UB_GenerateMips& Renderer::GetUbGenerateMips()
|
||||
{
|
||||
return _ubGenerateMips;
|
||||
}
|
||||
|
||||
Renderer::UB_GenerateCubeMapMips& Renderer::GetUbGenerateCubeMapMips()
|
||||
{
|
||||
return _ubGenerateCubeMapMips;
|
||||
}
|
||||
|
||||
GeometryPtr Renderer::GetGeoQuad() const
|
||||
{
|
||||
return _geoQuad;
|
||||
|
@ -632,10 +669,18 @@ Renderer::UB_QuadFS& Renderer::GetUbQuadFS()
|
|||
return _ubQuadFS;
|
||||
}
|
||||
|
||||
void Renderer::ResetQuadMultiplexer()
|
||||
{
|
||||
_ubQuadFS._rMultiplexer = float4(1, 0, 0, 0);
|
||||
_ubQuadFS._gMultiplexer = float4(0, 1, 0, 0);
|
||||
_ubQuadFS._bMultiplexer = float4(0, 0, 1, 0);
|
||||
_ubQuadFS._aMultiplexer = float4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
void Renderer::SetExposureValue(float ev)
|
||||
{
|
||||
_exposure[1] = ev;
|
||||
_exposure[0] = 1.f / exp2(_exposure[1] - 1);
|
||||
_exposure[0] = 1.f / exp2(_exposure[1]);
|
||||
}
|
||||
|
||||
void Renderer::UpdateUtilization()
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace verus
|
|||
class Renderer : public Singleton<Renderer>, public Object
|
||||
{
|
||||
#include "../Shaders/GenerateMips.inc.hlsl"
|
||||
#include "../Shaders/GenerateCubeMapMips.inc.hlsl"
|
||||
#include "../Shaders/Quad.inc.hlsl"
|
||||
|
||||
enum SHADER
|
||||
{
|
||||
SHADER_GENERATE_MIPS,
|
||||
SHADER_GENERATE_CUBE_MAP_MIPS,
|
||||
SHADER_QUAD,
|
||||
SHADER_COUNT
|
||||
};
|
||||
|
@ -30,6 +32,7 @@ namespace verus
|
|||
{
|
||||
PIPE_GENERATE_MIPS,
|
||||
PIPE_GENERATE_MIPS_EXPOSURE,
|
||||
PIPE_GENERATE_CUBE_MAP_MIPS,
|
||||
PIPE_OFFSCREEN_COLOR,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
@ -82,6 +85,7 @@ namespace verus
|
|||
FBHandle _fbhOffscreenWithDepth;
|
||||
CSHandle _cshOffscreenColor;
|
||||
UB_GenerateMips _ubGenerateMips;
|
||||
UB_GenerateCubeMapMips _ubGenerateCubeMapMips;
|
||||
UB_QuadVS _ubQuadVS;
|
||||
UB_QuadFS _ubQuadFS;
|
||||
bool _autoExposure = true;
|
||||
|
@ -152,14 +156,18 @@ namespace verus
|
|||
|
||||
// Generate mips:
|
||||
ShaderPtr GetShaderGenerateMips() const;
|
||||
ShaderPtr GetShaderGenerateCubeMapMips() const;
|
||||
PipelinePtr GetPipelineGenerateMips(bool exposure = false) const;
|
||||
PipelinePtr GetPipelineGenerateCubeMapMips() const;
|
||||
UB_GenerateMips& GetUbGenerateMips();
|
||||
UB_GenerateCubeMapMips& GetUbGenerateCubeMapMips();
|
||||
|
||||
// Quad:
|
||||
GeometryPtr GetGeoQuad() const;
|
||||
ShaderPtr GetShaderQuad() const;
|
||||
UB_QuadVS& GetUbQuadVS();
|
||||
UB_QuadFS& GetUbQuadFS();
|
||||
void ResetQuadMultiplexer();
|
||||
|
||||
// Exposure:
|
||||
bool IsAutoExposureEnabled() const { return _autoExposure; }
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace verus
|
|||
posZ,
|
||||
negZ,
|
||||
count,
|
||||
all,
|
||||
all, // Match texture index to cube map face when creating framebuffer.
|
||||
none = -1
|
||||
};
|
||||
|
||||
|
@ -130,8 +130,9 @@ namespace verus
|
|||
enum class ViaType : int
|
||||
{
|
||||
floats,
|
||||
ubytes,
|
||||
shorts
|
||||
halfs,
|
||||
shorts,
|
||||
ubytes
|
||||
};
|
||||
|
||||
// See: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3ddeclusage
|
||||
|
|
|
@ -6,12 +6,16 @@ using namespace verus::D;
|
|||
|
||||
void Log::Write(CSZ txt, std::thread::id tid, CSZ filename, UINT32 line, Severity severity)
|
||||
{
|
||||
if (strstr(txt, "VUID-StandaloneSpirv-Offset-04663"))
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-TransitionUndefinedToReadOnly"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-vkAllocateMemory-small-allocation"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-vkBindMemory-small-dedicated-allocation"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-vkCreateDevice-physical-device-features-not-retrieved"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-vkCreateInstance-specialuse-extension-debugging"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-CoreValidation-Shader-InconsistentSpirv"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-CoreValidation-Shader-OutputNotConsumed"))
|
||||
|
|
|
@ -139,10 +139,10 @@ void Bloom::Generate()
|
|||
{
|
||||
ImGui::DragFloat("Bloom colorScale", &_colorScale, 0.01f);
|
||||
ImGui::DragFloat("Bloom colorBias", &_colorBias, 0.01f);
|
||||
ImGui::DragFloat("Bloom (god rays) maxDist", &_maxDist, 0.1f);
|
||||
ImGui::DragFloat("Bloom (god rays) sunGloss", &_sunGloss, 0.1f);
|
||||
ImGui::DragFloat("Bloom (god rays) wideStrength", &_wideStrength, 0.01f);
|
||||
ImGui::DragFloat("Bloom (god rays) sunStrength", &_sunStrength, 0.01f);
|
||||
ImGui::DragFloat("Bloom (light shafts) maxDist", &_maxDist, 0.1f);
|
||||
ImGui::DragFloat("Bloom (light shafts) sunGloss", &_sunGloss, 0.1f);
|
||||
ImGui::DragFloat("Bloom (light shafts) wideStrength", &_wideStrength, 0.01f);
|
||||
ImGui::DragFloat("Bloom (light shafts) sunStrength", &_sunStrength, 0.01f);
|
||||
ImGui::Checkbox("Bloom blur", &_blur);
|
||||
ImGui::Checkbox("Bloom (light shafts) blur", &_blurLightShafts);
|
||||
}
|
||||
|
@ -151,9 +151,9 @@ void Bloom::Generate()
|
|||
|
||||
s_ubBloomVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBloomVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubBloomFS._exposure.x = renderer.GetExposure();
|
||||
s_ubBloomFS._colorScale_colorBias.x = _colorScale;
|
||||
s_ubBloomFS._colorScale_colorBias.y = _colorBias;
|
||||
s_ubBloomFS._colorScale_colorBias_exposure.x = _colorScale;
|
||||
s_ubBloomFS._colorScale_colorBias_exposure.y = _colorBias;
|
||||
s_ubBloomFS._colorScale_colorBias_exposure.z = renderer.GetExposure();
|
||||
|
||||
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_PING]->GetClearValue() });
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace verus
|
|||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshLightShafts;
|
||||
float _colorScale = 0.8f;
|
||||
float _colorBias = 1.1f;
|
||||
float _colorScale = 0.7f;
|
||||
float _colorBias = 1.4f;
|
||||
float _maxDist = 20;
|
||||
float _sunGloss = 128;
|
||||
float _wideStrength = 0.2f;
|
||||
|
|
|
@ -48,28 +48,26 @@ void Blur::Init()
|
|||
VERUS_QREF_RENDERER;
|
||||
|
||||
Vector<CSZ> vIgnoreList;
|
||||
if (settings._postProcessBloom)
|
||||
if (settings._postProcessSSAO)
|
||||
{
|
||||
_bloomHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_rphSsao = renderer->CreateSimpleRenderPass(CGI::Format::unormR8G8B8A8); // >> GBuffer2.r
|
||||
}
|
||||
else
|
||||
{
|
||||
vIgnoreList.push_back("#Ssao");
|
||||
}
|
||||
{
|
||||
_rdsHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_rdsHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
}
|
||||
{
|
||||
_dofHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_dofHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
}
|
||||
if (settings._postProcessSSAO)
|
||||
if (settings._postProcessBloom)
|
||||
{
|
||||
_ssaoHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_ssaoHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::unormR8);
|
||||
}
|
||||
else
|
||||
{
|
||||
vIgnoreList.push_back("#USsao");
|
||||
vIgnoreList.push_back("#VSsao");
|
||||
}
|
||||
{
|
||||
_ssrHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_ssrHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_bloomHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
}
|
||||
_rphAntiAliasing = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_rphMotionBlur = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
|
@ -101,9 +99,39 @@ void Blur::Init()
|
|||
pipeDesc._shaderBranch = "#V";
|
||||
_pipe[PIPE_V].Init(pipeDesc);
|
||||
}
|
||||
if (settings._postProcessSSAO)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#Ssao", _rphSsao);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_MIN;
|
||||
pipeDesc._colorAttachWriteMasks[0] = "r"; // >> GBuffer2.r
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_SSAO].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#ResolveDithering", _rdsHandles._rphU);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_RESOLVE_DITHERING].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#Sharpen";
|
||||
pipeDesc._renderPassHandle = _rdsHandles._rphV;
|
||||
_pipe[PIPE_SHARPEN].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#UDoF", _dofHandles._rphU);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_DOF_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#VDoF";
|
||||
pipeDesc._renderPassHandle = _dofHandles._rphV;
|
||||
_pipe[PIPE_DOF_V].Init(pipeDesc);
|
||||
}
|
||||
if (settings._postProcessBloom)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#U", _bloomHandles._rphU);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_BLOOM_U].Init(pipeDesc);
|
||||
|
@ -111,44 +139,16 @@ void Blur::Init()
|
|||
pipeDesc._renderPassHandle = _bloomHandles._rphV;
|
||||
_pipe[PIPE_BLOOM_V].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#UDoF", _dofHandles._rphU);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_DOF_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#VDoF";
|
||||
pipeDesc._renderPassHandle = _dofHandles._rphV;
|
||||
_pipe[PIPE_DOF_V].Init(pipeDesc);
|
||||
}
|
||||
if (settings._postProcessSSAO)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#USsao", _ssaoHandles._rphU);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "a";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_SSAO_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#VSsao";
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgba";
|
||||
pipeDesc._renderPassHandle = _ssaoHandles._rphV;
|
||||
_pipe[PIPE_SSAO_V].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#USsr", _ssrHandles._rphU);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_SSR_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#VSsr";
|
||||
pipeDesc._renderPassHandle = _ssrHandles._rphV;
|
||||
_pipe[PIPE_SSR_V].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#AntiAliasing", _rphAntiAliasing);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_AA].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#Motion", _rphMotionBlur);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "rgb";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_MOTION_BLUR].Init(pipeDesc);
|
||||
|
@ -160,18 +160,25 @@ void Blur::Init()
|
|||
void Blur::Done()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
renderer->DeleteFramebuffer(_fbhMotionBlur);
|
||||
renderer->DeleteRenderPass(_rphMotionBlur);
|
||||
|
||||
renderer->DeleteFramebuffer(_fbhAntiAliasing);
|
||||
renderer->DeleteRenderPass(_rphAntiAliasing);
|
||||
_ssrHandles.DeleteFramebuffers();
|
||||
_ssrHandles.DeleteRenderPasses();
|
||||
_ssaoHandles.DeleteFramebuffers();
|
||||
_ssaoHandles.DeleteRenderPasses();
|
||||
_dofHandles.DeleteFramebuffers();
|
||||
_dofHandles.DeleteRenderPasses();
|
||||
|
||||
_bloomHandles.DeleteFramebuffers();
|
||||
_bloomHandles.DeleteRenderPasses();
|
||||
|
||||
_dofHandles.DeleteFramebuffers();
|
||||
_dofHandles.DeleteRenderPasses();
|
||||
|
||||
_rdsHandles.DeleteFramebuffers();
|
||||
_rdsHandles.DeleteRenderPasses();
|
||||
|
||||
renderer->DeleteFramebuffer(_fbhSsao);
|
||||
renderer->DeleteRenderPass(_rphSsao);
|
||||
|
||||
VERUS_DONE(Blur);
|
||||
}
|
||||
|
||||
|
@ -183,7 +190,6 @@ void Blur::OnSwapChainResized()
|
|||
VERUS_QREF_BLOOM;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSAO;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_cshMotionBlurExtra);
|
||||
|
@ -194,21 +200,19 @@ void Blur::OnSwapChainResized()
|
|||
_shader->FreeDescriptorSet(_cshAntiAliasing);
|
||||
renderer->DeleteFramebuffer(_fbhAntiAliasing);
|
||||
|
||||
_shader->FreeDescriptorSet(_cshSsrExtra);
|
||||
_ssrHandles.FreeDescriptorSets(_shader);
|
||||
_ssrHandles.DeleteFramebuffers();
|
||||
|
||||
_ssaoHandles.FreeDescriptorSets(_shader);
|
||||
_ssaoHandles.DeleteFramebuffers();
|
||||
_bloomHandles.FreeDescriptorSets(_shader);
|
||||
_bloomHandles.DeleteFramebuffers();
|
||||
|
||||
_shader->FreeDescriptorSet(_cshDofExtra);
|
||||
_dofHandles.FreeDescriptorSets(_shader);
|
||||
_dofHandles.DeleteFramebuffers();
|
||||
|
||||
_bloomHandles.FreeDescriptorSets(_shader);
|
||||
_bloomHandles.DeleteFramebuffers();
|
||||
_shader->FreeDescriptorSet(_cshRdsExtra);
|
||||
_rdsHandles.FreeDescriptorSets(_shader);
|
||||
_rdsHandles.DeleteFramebuffers();
|
||||
|
||||
_tex.Done();
|
||||
_shader->FreeDescriptorSet(_cshSsao);
|
||||
renderer->DeleteFramebuffer(_fbhSsao);
|
||||
}
|
||||
{
|
||||
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
|
||||
|
@ -216,23 +220,24 @@ void Blur::OnSwapChainResized()
|
|||
const int scaledSwapChainHalfWidth = scaledSwapChainWidth / 2;
|
||||
const int scaledSwapChainHalfHeight = scaledSwapChainHeight / 2;
|
||||
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._name = "Blur.Tex";
|
||||
texDesc._format = CGI::Format::srgbR8G8B8A8;
|
||||
texDesc._width = scaledSwapChainWidth;
|
||||
texDesc._height = scaledSwapChainHeight;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
|
||||
_tex.Init(texDesc);
|
||||
|
||||
if (settings._postProcessBloom)
|
||||
if (settings._postProcessSSAO)
|
||||
{
|
||||
_bloomHandles._fbhU = renderer->CreateFramebuffer(_bloomHandles._rphU, { bloom.GetPongTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
|
||||
_bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
|
||||
_bloomHandles._cshU = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
|
||||
_bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() });
|
||||
// GBuffer3.r >> GBuffer2.r:
|
||||
_fbhSsao = renderer->CreateFramebuffer(_rphSsao, { renderer.GetDS().GetGBuffer(2) }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_cshSsao = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetGBuffer(3) });
|
||||
}
|
||||
|
||||
{
|
||||
// ComposedA >> ComposedB >> ComposedA:
|
||||
_rdsHandles._fbhU = renderer->CreateFramebuffer(_rdsHandles._rphU, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_rdsHandles._fbhV = renderer->CreateFramebuffer(_rdsHandles._rphV, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_rdsHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
|
||||
_rdsHandles._cshV = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureB() });
|
||||
_cshRdsExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(3), renderer.GetDS().GetGBuffer(3) });
|
||||
}
|
||||
|
||||
{
|
||||
// ComposedA >> ComposedB >> ComposedA:
|
||||
_dofHandles._fbhU = renderer->CreateFramebuffer(_dofHandles._rphU, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_dofHandles._fbhV = renderer->CreateFramebuffer(_dofHandles._rphV, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_dofHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
|
||||
|
@ -240,29 +245,24 @@ void Blur::OnSwapChainResized()
|
|||
_cshDofExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
|
||||
}
|
||||
|
||||
if (settings._postProcessSSAO)
|
||||
if (settings._postProcessBloom)
|
||||
{
|
||||
_ssaoHandles._fbhU = renderer->CreateFramebuffer(_ssaoHandles._rphU, { _tex }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_ssaoHandles._fbhV = renderer->CreateFramebuffer(_ssaoHandles._rphV, { ssao.GetTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_ssaoHandles._cshU = _shader->BindDescriptorSetTextures(1, { ssao.GetTexture() });
|
||||
_ssaoHandles._cshV = _shader->BindDescriptorSetTextures(1, { _tex });
|
||||
}
|
||||
|
||||
{
|
||||
_ssrHandles._fbhU = renderer->CreateFramebuffer(_ssrHandles._rphU, { renderer.GetDS().GetLightAccDiffTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_ssrHandles._fbhV = renderer->CreateFramebuffer(_ssrHandles._rphV, { renderer.GetDS().GetLightAccSpecTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_ssrHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetLightAccSpecTexture() });
|
||||
_ssrHandles._cshV = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetLightAccDiffTexture() });
|
||||
_cshSsrExtra = _shader->BindDescriptorSetTextures(2, { ssao.GetTexture(), renderer.GetDS().GetGBuffer(2) });
|
||||
// Ping >> Pong >> Ping:
|
||||
_bloomHandles._fbhU = renderer->CreateFramebuffer(_bloomHandles._rphU, { bloom.GetPongTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
|
||||
_bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
|
||||
_bloomHandles._cshU = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
|
||||
_bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() });
|
||||
}
|
||||
|
||||
{
|
||||
// ComposedA >> ComposedB:
|
||||
_fbhAntiAliasing = renderer->CreateFramebuffer(_rphAntiAliasing, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_cshAntiAliasing = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
|
||||
_cshAntiAliasingExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
|
||||
}
|
||||
|
||||
{
|
||||
// ComposedB >> ComposedA:
|
||||
_fbhMotionBlur = renderer->CreateFramebuffer(_rphMotionBlur, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_cshMotionBlur = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureB() });
|
||||
_cshMotionBlurExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
|
||||
|
@ -270,70 +270,56 @@ void Blur::OnSwapChainResized()
|
|||
}
|
||||
}
|
||||
|
||||
void Blur::Generate()
|
||||
void Blur::GenerateForSsao()
|
||||
{
|
||||
}
|
||||
|
||||
void Blur::GenerateForBloom(bool forLightShafts)
|
||||
{
|
||||
VERUS_QREF_BLOOM;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (bloom.IsEditMode())
|
||||
{
|
||||
ImGui::DragFloat("Bloom blur radius", &_bloomRadius, 0.001f);
|
||||
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomLightShaftsRadius, 0.001f);
|
||||
}
|
||||
|
||||
const float radius = forLightShafts ? _bloomLightShaftsRadius : _bloomRadius;
|
||||
float samplesPerPixel = 1;
|
||||
int maxSamples = 1;
|
||||
switch (settings._gpuShaderQuality)
|
||||
{
|
||||
case App::Settings::Quality::low:
|
||||
samplesPerPixel = 1 / 6.f;
|
||||
maxSamples = 12 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::medium:
|
||||
samplesPerPixel = 1 / 6.f;
|
||||
maxSamples = 16 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::high:
|
||||
samplesPerPixel = 1 / 4.f;
|
||||
maxSamples = 24 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::ultra:
|
||||
samplesPerPixel = 1 / 4.f;
|
||||
maxSamples = 32 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(radius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetGBuffer(2)->GetSize(), nullptr, 0.5f, 0.5f).UniformBufferFormat();
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() });
|
||||
cb->BeginRenderPass(_rphSsao, _fbhSsao, { renderer.GetDS().GetGBuffer(2)->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_U]);
|
||||
cb->BindPipeline(_pipe[PIPE_SSAO]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshU);
|
||||
cb->BindDescriptors(_shader, 1, _cshSsao);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(radius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
|
||||
{
|
||||
cb->BeginRenderPass(_bloomHandles._rphV, _bloomHandles._fbhV, { bloom.GetTexture()->GetClearValue() });
|
||||
_shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_V]);
|
||||
void Blur::GenerateForResolveDitheringAndSharpen()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_rdsHandles._rphU, _rdsHandles._fbhU, { renderer.GetDS().GetComposedTextureB()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_RESOLVE_DITHERING]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshV);
|
||||
cb->BindDescriptors(_shader, 1, _rdsHandles._cshU);
|
||||
cb->BindDescriptors(_shader, 2, _cshRdsExtra);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
{
|
||||
cb->BeginRenderPass(_rdsHandles._rphV, _rdsHandles._fbhV, { renderer.GetDS().GetComposedTextureA()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SHARPEN]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _rdsHandles._cshV);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
|
@ -424,52 +410,19 @@ void Blur::GenerateForDepthOfField()
|
|||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_ssaoHandles._rphU, _ssaoHandles._fbhU, { _tex->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSAO_U]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssaoHandles._cshU);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, _tex->GetSize(), nullptr, 0, 0.5f).UniformBufferFormat();
|
||||
{
|
||||
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.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
_shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void Blur::GenerateForSsr()
|
||||
void Blur::GenerateForBloom(bool forLightShafts)
|
||||
{
|
||||
VERUS_QREF_BLOOM;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSR;
|
||||
|
||||
if (ssr.IsEditMode())
|
||||
if (bloom.IsEditMode())
|
||||
{
|
||||
ImGui::DragFloat("SSR blur radius", &_ssrRadius, 0.001f);
|
||||
ImGui::DragFloat("Bloom blur radius", &_bloomRadius, 0.001f);
|
||||
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomLightShaftsRadius, 0.001f);
|
||||
}
|
||||
|
||||
const float radius = forLightShafts ? _bloomLightShaftsRadius : _bloomRadius;
|
||||
float samplesPerPixel = 1;
|
||||
int maxSamples = 1;
|
||||
switch (settings._gpuShaderQuality)
|
||||
|
@ -495,30 +448,28 @@ void Blur::GenerateForSsr()
|
|||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetLightAccDiffTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(_ssrRadius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(radius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_ssrHandles._rphU, _ssrHandles._fbhU, { renderer.GetDS().GetLightAccDiffTexture()->GetClearValue() });
|
||||
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSR_U]);
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_U]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssrHandles._cshU);
|
||||
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshU);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetLightAccSpecTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(_ssrRadius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(radius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
|
||||
{
|
||||
cb->BeginRenderPass(_ssrHandles._rphV, _ssrHandles._fbhV, { renderer.GetDS().GetLightAccSpecTexture()->GetClearValue() });
|
||||
cb->BeginRenderPass(_bloomHandles._rphV, _bloomHandles._fbhV, { bloom.GetTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSR_V]);
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_V]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssrHandles._cshV);
|
||||
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshV);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
|
|
|
@ -13,16 +13,21 @@ namespace verus
|
|||
{
|
||||
PIPE_U,
|
||||
PIPE_V,
|
||||
PIPE_BLOOM_U,
|
||||
PIPE_BLOOM_V,
|
||||
|
||||
PIPE_SSAO,
|
||||
|
||||
PIPE_RESOLVE_DITHERING,
|
||||
PIPE_SHARPEN,
|
||||
|
||||
PIPE_DOF_U,
|
||||
PIPE_DOF_V,
|
||||
PIPE_SSAO_U,
|
||||
PIPE_SSAO_V,
|
||||
PIPE_SSR_U,
|
||||
PIPE_SSR_V,
|
||||
|
||||
PIPE_BLOOM_U,
|
||||
PIPE_BLOOM_V,
|
||||
|
||||
PIPE_AA,
|
||||
PIPE_MOTION_BLUR,
|
||||
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
|
@ -46,26 +51,33 @@ namespace verus
|
|||
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwns<PIPE_COUNT> _pipe;
|
||||
CGI::TexturePwn _tex;
|
||||
Handles _bloomHandles;
|
||||
|
||||
CGI::RPHandle _rphSsao;
|
||||
CGI::FBHandle _fbhSsao;
|
||||
CGI::CSHandle _cshSsao;
|
||||
|
||||
Handles _rdsHandles;
|
||||
CGI::CSHandle _cshRdsExtra;
|
||||
|
||||
Handles _dofHandles;
|
||||
Handles _ssaoHandles;
|
||||
Handles _ssrHandles;
|
||||
CGI::CSHandle _cshDofExtra;
|
||||
CGI::CSHandle _cshSsrExtra;
|
||||
|
||||
Handles _bloomHandles;
|
||||
|
||||
CGI::RPHandle _rphAntiAliasing;
|
||||
CGI::FBHandle _fbhAntiAliasing;
|
||||
CGI::CSHandle _cshAntiAliasing;
|
||||
CGI::CSHandle _cshAntiAliasingExtra;
|
||||
|
||||
CGI::RPHandle _rphMotionBlur;
|
||||
CGI::FBHandle _fbhMotionBlur;
|
||||
CGI::CSHandle _cshMotionBlur;
|
||||
CGI::CSHandle _cshMotionBlurExtra;
|
||||
float _bloomRadius = 0.015f;
|
||||
float _bloomLightShaftsRadius = 0.004f;
|
||||
|
||||
float _dofFocusDist = 10;
|
||||
float _dofBlurStrength = 0.2f;
|
||||
float _ssrRadius = 0.025f;
|
||||
float _bloomRadius = 0.02f;
|
||||
float _bloomLightShaftsRadius = 0.004f;
|
||||
bool _enableDepthOfField = false;
|
||||
|
||||
public:
|
||||
|
@ -77,11 +89,10 @@ namespace verus
|
|||
|
||||
void OnSwapChainResized();
|
||||
|
||||
void Generate();
|
||||
void GenerateForBloom(bool forLightShafts);
|
||||
void GenerateForDepthOfField();
|
||||
void GenerateForSsao();
|
||||
void GenerateForSsr();
|
||||
void GenerateForResolveDitheringAndSharpen();
|
||||
void GenerateForDepthOfField();
|
||||
void GenerateForBloom(bool forLightShafts);
|
||||
void GenerateForAntiAliasing();
|
||||
void GenerateForMotionBlur();
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ void Cinema::Init()
|
|||
_pipe.Init(pipeDesc);
|
||||
}
|
||||
|
||||
_texFilmGrain.Init("[Textures]:FilmGrain.FX.dds");
|
||||
_texFilmGrain.Init("[Textures]:FilmGrain.X.dds");
|
||||
}
|
||||
|
||||
void Cinema::Done()
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace verus
|
|||
float _uOffset = 0;
|
||||
float _vOffset = 0;
|
||||
float _brightness = 1;
|
||||
float _flickerStrength = 0.01f;
|
||||
float _noiseStrength = 0.15f;
|
||||
float _flickerStrength = 0.02f;
|
||||
float _noiseStrength = 0.2f;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
|
|
|
@ -187,7 +187,7 @@ void Particles::Init(CSZ url)
|
|||
|
||||
if (!s_pipe[PIPE_MAIN])
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_PA;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
pipeDesc._depthWriteEnable = false;
|
||||
|
@ -221,7 +221,7 @@ void Particles::Init(CSZ url)
|
|||
|
||||
if (!s_pipe[PIPE_BILLBOARDS])
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Billboards", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Billboards", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_PA;
|
||||
pipeDesc._depthWriteEnable = false;
|
||||
s_pipe[PIPE_BILLBOARDS].Init(pipeDesc);
|
||||
|
|
|
@ -25,11 +25,10 @@ void Ssao::Init()
|
|||
if (!settings._postProcessSSAO)
|
||||
{
|
||||
VERUS_LOG_INFO("SSAO disabled");
|
||||
OnSwapChainResized();
|
||||
return;
|
||||
}
|
||||
|
||||
_rph = renderer->CreateSimpleRenderPass(CGI::Format::unormR8);
|
||||
_rph = renderer->CreateSimpleRenderPass(CGI::Format::unormR8G8B8A8); // >> GBuffer3.r
|
||||
|
||||
_shader.Init("[Shaders]:Ssao.hlsl");
|
||||
_shader->CreateDescriptorSet(0, &s_ubSsaoVS, sizeof(s_ubSsaoVS), 2, {}, CGI::ShaderStageFlags::vs);
|
||||
|
@ -37,12 +36,13 @@ void Ssao::Init()
|
|||
{
|
||||
CGI::Sampler::nearestMipN, // RandNormals
|
||||
CGI::Sampler::nearestClampMipN, // GBuffer1
|
||||
CGI::Sampler::linearClampMipN, // Depth
|
||||
CGI::Sampler::nearestClampMipN, // Depth
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
_shader->CreatePipelineLayout();
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "r"; // >> GBuffer3.r
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe.Init(pipeDesc);
|
||||
|
@ -53,7 +53,7 @@ void Ssao::Init()
|
|||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texDesc._width = 4;
|
||||
texDesc._height = 4;
|
||||
_tex[TEX_RAND_NORMALS].Init(texDesc);
|
||||
_texRandNormals.Init(texDesc);
|
||||
|
||||
OnSwapChainResized();
|
||||
}
|
||||
|
@ -84,40 +84,21 @@ void Ssao::OnSwapChainResized()
|
|||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (!settings._postProcessSSAO)
|
||||
return;
|
||||
|
||||
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
|
||||
const int scaledSwapChainHeight = settings.Scale(renderer.GetSwapChainHeight());
|
||||
|
||||
auto InitTex = [this, scaledSwapChainWidth, scaledSwapChainHeight]()
|
||||
{
|
||||
_tex[TEX_GEN_AO].Done();
|
||||
VERUS_QREF_RENDERER;
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._clearValue = Vector4::Replicate(1);
|
||||
texDesc._name = "Ssao.GenAO";
|
||||
texDesc._format = CGI::Format::unormR8;
|
||||
texDesc._width = scaledSwapChainWidth;
|
||||
texDesc._height = scaledSwapChainHeight;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
|
||||
_tex[TEX_GEN_AO].Init(texDesc);
|
||||
renderer.GetDS().InitBySsao(_tex[TEX_GEN_AO]);
|
||||
};
|
||||
|
||||
if (!settings._postProcessSSAO)
|
||||
{
|
||||
InitTex();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
}
|
||||
{
|
||||
InitTex();
|
||||
_fbh = renderer->CreateFramebuffer(_rph, { _tex[TEX_GEN_AO] }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_fbh = renderer->CreateFramebuffer(_rph, { renderer.GetDS().GetGBuffer(3) }, scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_RAND_NORMALS],
|
||||
_texRandNormals,
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil()
|
||||
});
|
||||
|
@ -148,7 +129,7 @@ void Ssao::Generate()
|
|||
|
||||
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();
|
||||
s_ubSsaoVS._matP = Math::ToUVMatrix(0, renderer.GetDS().GetGBuffer(3)->GetSize(), &_texRandNormals->GetSize()).UniformBufferFormat();
|
||||
s_ubSsaoFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubSsaoFS._camScale.x = cam.GetFovScale() / cam.GetAspectRatio();
|
||||
s_ubSsaoFS._camScale.y = -cam.GetFovScale();
|
||||
|
@ -157,7 +138,7 @@ void Ssao::Generate()
|
|||
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.z = _weightScale;
|
||||
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.w = _weightBias;
|
||||
|
||||
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_GEN_AO]->GetClearValue() });
|
||||
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetGBuffer(3)->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe);
|
||||
_shader->BeginBindDescriptors();
|
||||
|
@ -186,10 +167,5 @@ void Ssao::UpdateRandNormalsTexture()
|
|||
Vector4 v4 = Vector4(v3 * 0.5f + Vector3::Replicate(0.5f), 1);
|
||||
vData[i] = Convert::ColorFloatToInt32(v4.ToPointer(), false);
|
||||
}
|
||||
_tex[TEX_RAND_NORMALS]->UpdateSubresource(vData.data());
|
||||
}
|
||||
|
||||
CGI::TexturePtr Ssao::GetTexture() const
|
||||
{
|
||||
return _tex[TEX_GEN_AO];
|
||||
_texRandNormals->UpdateSubresource(vData.data());
|
||||
}
|
||||
|
|
|
@ -9,28 +9,21 @@ namespace verus
|
|||
{
|
||||
#include "../Shaders/Ssao.inc.hlsl"
|
||||
|
||||
enum TEX
|
||||
{
|
||||
TEX_GEN_AO,
|
||||
TEX_RAND_NORMALS,
|
||||
TEX_COUNT
|
||||
};
|
||||
|
||||
static UB_SsaoVS s_ubSsaoVS;
|
||||
static UB_SsaoFS s_ubSsaoFS;
|
||||
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
float _smallRad = 0.03f;
|
||||
float _largeRad = 0.07f;
|
||||
float _weightScale = 10;
|
||||
float _weightBias = 2.5f;
|
||||
bool _blur = true;
|
||||
bool _editMode = false;
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CGI::TexturePwn _texRandNormals;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
float _smallRad = 0.03f;
|
||||
float _largeRad = 0.07f;
|
||||
float _weightScale = 10;
|
||||
float _weightBias = 2.5f;
|
||||
bool _blur = true;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
Ssao();
|
||||
|
@ -46,8 +39,6 @@ namespace verus
|
|||
|
||||
void UpdateRandNormalsTexture();
|
||||
|
||||
CGI::TexturePtr GetTexture() const;
|
||||
|
||||
bool IsEditMode() const { return _editMode; }
|
||||
void ToggleEditMode() { _editMode = !_editMode; }
|
||||
};
|
||||
|
|
|
@ -22,19 +22,7 @@ void Ssr::Init()
|
|||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_rph = renderer->CreateRenderPass(
|
||||
{
|
||||
CGI::RP::Attachment("Color", CGI::Format::floatR11G11B10).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
|
||||
CGI::RP::Attachment("Alpha", CGI::Format::unormR8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly)
|
||||
},
|
||||
{
|
||||
CGI::RP::Subpass("Sp0").Color(
|
||||
{
|
||||
CGI::RP::Ref("Color", CGI::ImageLayout::colorAttachment),
|
||||
CGI::RP::Ref("Alpha", CGI::ImageLayout::colorAttachment)
|
||||
})
|
||||
},
|
||||
{});
|
||||
_rph = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
|
||||
CGI::ShaderDesc shaderDesc("[Shaders]:Ssr.hlsl");
|
||||
if (settings._postProcessSSR)
|
||||
|
@ -43,20 +31,27 @@ void Ssr::Init()
|
|||
_shader->CreateDescriptorSet(0, &s_ubSsrVS, sizeof(s_ubSsrVS), 2, {}, CGI::ShaderStageFlags::vs);
|
||||
_shader->CreateDescriptorSet(1, &s_ubSsrFS, sizeof(s_ubSsrFS), 2,
|
||||
{
|
||||
CGI::Sampler::linearClampMipN, // Color
|
||||
CGI::Sampler::nearestClampMipN, // Normal
|
||||
CGI::Sampler::nearestClampMipN, // GBuffer0
|
||||
CGI::Sampler::nearestClampMipN, // GBuffer1
|
||||
CGI::Sampler::nearestClampMipN, // GBuffer2
|
||||
CGI::Sampler::nearestClampMipN, // GBuffer3
|
||||
CGI::Sampler::linearClampMipN, // Scene
|
||||
CGI::Sampler::linearClampMipN, // Depth
|
||||
CGI::Sampler::linearClampMipN // EnvMap
|
||||
CGI::Sampler::linearClampMipL // Image
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
_shader->CreatePipelineLayout();
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe.Init(pipeDesc);
|
||||
_pipe[PIPE_MAIN].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#DebugCubeMap", _rph);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_DEBUG_CUBE_MAP].Init(pipeDesc);
|
||||
}
|
||||
|
||||
OnSwapChainResized();
|
||||
|
@ -77,8 +72,6 @@ void Ssr::OnSwapChainResized()
|
|||
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSAO;
|
||||
VERUS_QREF_ATMO;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
|
@ -90,47 +83,44 @@ void Ssr::OnSwapChainResized()
|
|||
|
||||
_fbh = renderer->CreateFramebuffer(_rph,
|
||||
{
|
||||
renderer.GetDS().GetLightAccSpecTexture(),
|
||||
ssao.GetTexture()
|
||||
renderer.GetDS().GetLightAccSpecularTexture()
|
||||
},
|
||||
scaledSwapChainWidth, scaledSwapChainHeight);
|
||||
if (atmo.GetCubeMapBaker().GetColorTexture())
|
||||
{
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetDS().GetComposedTextureA(),
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil(),
|
||||
atmo.GetCubeMapBaker().GetColorTexture()
|
||||
});
|
||||
}
|
||||
BindDescriptorSetTextures();
|
||||
}
|
||||
}
|
||||
|
||||
bool Ssr::BindDescriptorSetTextures()
|
||||
{
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (atmo.GetCubeMapBaker().GetColorTexture())
|
||||
{
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetDS().GetGBuffer(0),
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetDS().GetGBuffer(2),
|
||||
renderer.GetDS().GetGBuffer(3),
|
||||
renderer.GetDS().GetComposedTextureA(),
|
||||
renderer.GetTexDepthStencil(),
|
||||
atmo.GetCubeMapBaker().GetColorTexture()
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Ssr::Generate()
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
VERUS_QREF_SSAO;
|
||||
VERUS_QREF_ATMO;
|
||||
|
||||
if (!settings._postProcessSSR)
|
||||
return;
|
||||
|
||||
if (!_csh.IsSet())
|
||||
{
|
||||
if (atmo.GetCubeMapBaker().GetColorTexture())
|
||||
{
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetDS().GetComposedTextureA(),
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil(),
|
||||
atmo.GetCubeMapBaker().GetColorTexture()
|
||||
});
|
||||
}
|
||||
else
|
||||
if (!BindDescriptorSetTextures())
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -140,7 +130,6 @@ void Ssr::Generate()
|
|||
ImGui::DragFloat("SSR depthBias", &_depthBias, 0.001f);
|
||||
ImGui::DragFloat("SSR thickness", &_thickness, 0.001f);
|
||||
ImGui::DragFloat("SSR equalizeDist", &_equalizeDist, 0.01f);
|
||||
ImGui::Checkbox("SSR blur", &_blur);
|
||||
}
|
||||
|
||||
Scene::RCamera cam = *sm.GetCamera();
|
||||
|
@ -154,6 +143,7 @@ void Ssr::Generate()
|
|||
s_ubSsrFS._matInvV = cam.GetMatrixInvV().UniformBufferFormat();
|
||||
s_ubSsrFS._matPTex = matPTex.UniformBufferFormat();
|
||||
s_ubSsrFS._matInvP = cam.GetMatrixInvP().UniformBufferFormat();
|
||||
s_ubSsrFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubSsrFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.x = _radius;
|
||||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.y = _depthBias;
|
||||
|
@ -161,13 +151,9 @@ void Ssr::Generate()
|
|||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.w = _equalizeDist;
|
||||
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
|
||||
cb->BeginRenderPass(_rph, _fbh,
|
||||
{
|
||||
renderer.GetDS().GetLightAccSpecTexture()->GetClearValue(),
|
||||
ssao.GetTexture()->GetClearValue()
|
||||
});
|
||||
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetLightAccSpecularTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe);
|
||||
cb->BindPipeline(_cubeMapDebugMode ? _pipe[PIPE_DEBUG_CUBE_MAP] : _pipe[PIPE_MAIN]);
|
||||
_shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _csh);
|
||||
|
@ -176,7 +162,4 @@ void Ssr::Generate()
|
|||
|
||||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
|
||||
if (_blur)
|
||||
Blur::I().GenerateForSsr();
|
||||
}
|
||||
|
|
|
@ -9,20 +9,27 @@ namespace verus
|
|||
{
|
||||
#include "../Shaders/Ssr.inc.hlsl"
|
||||
|
||||
enum PIPE
|
||||
{
|
||||
PIPE_MAIN,
|
||||
PIPE_DEBUG_CUBE_MAP,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
static UB_SsrVS s_ubSsrVS;
|
||||
static UB_SsrFS s_ubSsrFS;
|
||||
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
float _radius = 2.5f;
|
||||
float _depthBias = 0.03f;
|
||||
float _thickness = 0.25f;
|
||||
float _equalizeDist = 12;
|
||||
bool _blur = true;
|
||||
bool _editMode = false;
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwns<PIPE_COUNT> _pipe;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
float _radius = 2.2f;
|
||||
float _depthBias = 0.03f;
|
||||
float _thickness = 0.3f;
|
||||
float _equalizeDist = 20;
|
||||
bool _cubeMapDebugMode = false;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
Ssr();
|
||||
|
@ -33,8 +40,13 @@ namespace verus
|
|||
|
||||
void OnSwapChainResized();
|
||||
|
||||
bool BindDescriptorSetTextures();
|
||||
|
||||
void Generate();
|
||||
|
||||
bool IsCubeMapDebugMode() const { return _cubeMapDebugMode; }
|
||||
void ToggleCubeMapDebugMode() { _cubeMapDebugMode = !_cubeMapDebugMode; }
|
||||
|
||||
bool IsEditMode() const { return _editMode; }
|
||||
void ToggleEditMode() { _editMode = !_editMode; }
|
||||
};
|
||||
|
|
|
@ -78,8 +78,11 @@ void ViewManager::Done()
|
|||
|
||||
_cursor.Done();
|
||||
|
||||
_shader->FreeDescriptorSet(_cshDebug);
|
||||
_shader->FreeDescriptorSet(_cshDefault);
|
||||
if (_shader)
|
||||
{
|
||||
_shader->FreeDescriptorSet(_cshDebug);
|
||||
_shader->FreeDescriptorSet(_cshDefault);
|
||||
}
|
||||
|
||||
VERUS_DONE(ViewManager);
|
||||
}
|
||||
|
|
|
@ -102,7 +102,11 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc windowDes
|
|||
Utils::TestAll();
|
||||
#endif
|
||||
|
||||
// Window and renderer:
|
||||
_window.Init(updatedWindowDesc);
|
||||
SDL_GetWindowSize(_window.GetSDL(),
|
||||
&settings._displaySizeWidth,
|
||||
&settings._displaySizeHeight); // Display size, window size and swap chain size must match.
|
||||
CGI::Renderer::I().SetMainWindow(&_window);
|
||||
_engineInit.Init(new MyRendererDelegate(this));
|
||||
|
||||
|
|
|
@ -62,6 +62,16 @@ UINT32 Convert::Uint4x4ToUint8x4(UINT16 in, bool scaleTo255)
|
|||
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3] << 0);
|
||||
}
|
||||
|
||||
half Convert::FloatToHalf(float f)
|
||||
{
|
||||
return glm::packHalf1x16(f);
|
||||
}
|
||||
|
||||
float Convert::HalfToFloat(half h)
|
||||
{
|
||||
return glm::unpackHalf1x16(h);
|
||||
}
|
||||
|
||||
float Convert::SRGBToLinear(float color)
|
||||
{
|
||||
return color < 0.04045f ? color * (1 / 12.92f) : pow((color + 0.055f) * (1 / 1.055f), 2.4f);
|
||||
|
@ -128,6 +138,8 @@ UINT32 Convert::ColorFloatToInt32(const float* in, bool sRGB)
|
|||
|
||||
void Convert::ColorTextToFloat4(CSZ sz, float* out, bool sRGB)
|
||||
{
|
||||
if (sz && '0' == sz[0] && 'x' == sz[1])
|
||||
sz += 2;
|
||||
int color[4] = {};
|
||||
if (!sz)
|
||||
{
|
||||
|
@ -170,8 +182,13 @@ void Convert::ColorTextToFloat4(CSZ sz, float* out, bool sRGB)
|
|||
|
||||
UINT32 Convert::ColorTextToInt32(CSZ sz)
|
||||
{
|
||||
if (sz && '0' == sz[0] && 'x' == sz[1])
|
||||
sz += 2;
|
||||
int color[4] = {};
|
||||
if (6 == strlen(sz) && !strchr(sz, ' '))
|
||||
if (!sz)
|
||||
{
|
||||
}
|
||||
else if (6 == strlen(sz) && !strchr(sz, ' '))
|
||||
{
|
||||
color[0] = Str::ByteFromHex(sz + 0);
|
||||
color[1] = Str::ByteFromHex(sz + 2);
|
||||
|
|
|
@ -41,6 +41,10 @@ namespace verus
|
|||
static UINT16 Uint8x4ToUint4x4(UINT32 in);
|
||||
static UINT32 Uint4x4ToUint8x4(UINT16 in, bool scaleTo255 = false);
|
||||
|
||||
// Half:
|
||||
static half FloatToHalf(float f);
|
||||
static float HalfToFloat(half h);
|
||||
|
||||
// Colors:
|
||||
static float SRGBToLinear(float color);
|
||||
static float LinearToSRGB(float color);
|
||||
|
|
|
@ -89,3 +89,5 @@
|
|||
#define VERUS_COLOR_BLEND_MAD "s*(dc)+d*(sa)"
|
||||
#define VERUS_COLOR_BLEND_FILTER "s*(0)+d*(sc)"
|
||||
#define VERUS_COLOR_BLEND_TINTED_GLASS "s*(sc)+d*(1-sc)"
|
||||
#define VERUS_COLOR_BLEND_MIN "min(s, d)"
|
||||
#define VERUS_COLOR_BLEND_MAX "max(s, d)"
|
||||
|
|
|
@ -232,6 +232,10 @@ void Str::ReplaceFilename(RString pathname, CSZ filename)
|
|||
const size_t count = pathname.length() - pos;
|
||||
pathname.replace(pos + 1, count, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathname = filename;
|
||||
}
|
||||
}
|
||||
|
||||
void Str::ReplaceExtension(RString pathname, CSZ ext)
|
||||
|
@ -262,21 +266,30 @@ String Str::ToPakFriendlyUrl(CSZ url)
|
|||
glm::vec2 Str::FromStringVec2(CSZ s)
|
||||
{
|
||||
glm::vec2 v;
|
||||
sscanf(s, "%f %f", &v.x, &v.y);
|
||||
if ('[' == *s)
|
||||
sscanf(s, "[%f, %f]", &v.x, &v.y);
|
||||
else
|
||||
sscanf(s, "%f %f", &v.x, &v.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
glm::vec3 Str::FromStringVec3(CSZ s)
|
||||
{
|
||||
glm::vec3 v;
|
||||
sscanf(s, "%f %f %f", &v.x, &v.y, &v.z);
|
||||
if ('[' == *s)
|
||||
sscanf(s, "[%f, %f, %f]", &v.x, &v.y, &v.z);
|
||||
else
|
||||
sscanf(s, "%f %f %f", &v.x, &v.y, &v.z);
|
||||
return v;
|
||||
}
|
||||
|
||||
glm::vec4 Str::FromStringVec4(CSZ s)
|
||||
{
|
||||
glm::vec4 v;
|
||||
sscanf(s, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
|
||||
if ('[' == *s)
|
||||
sscanf(s, "[%f, %f, %f, %f]", &v.x, &v.y, &v.z, &v.w);
|
||||
else
|
||||
sscanf(s, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -294,24 +307,24 @@ String Str::ToString(float f)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
String Str::ToString(const glm::vec2& v)
|
||||
String Str::ToString(const glm::vec2& v, bool brackets)
|
||||
{
|
||||
char buffer[40];
|
||||
sprintf_s(buffer, "%g %g", v.x, v.y);
|
||||
sprintf_s(buffer, brackets ? "[%g, %g]" : "%g %g", v.x, v.y);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
String Str::ToString(const glm::vec3& v)
|
||||
String Str::ToString(const glm::vec3& v, bool brackets)
|
||||
{
|
||||
char buffer[60];
|
||||
sprintf_s(buffer, "%g %g %g", v.x, v.y, v.z);
|
||||
sprintf_s(buffer, brackets ? "[%g, %g, %g]" : "%g %g %g", v.x, v.y, v.z);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
String Str::ToString(const glm::vec4& v)
|
||||
String Str::ToString(const glm::vec4& v, bool brackets)
|
||||
{
|
||||
char buffer[80];
|
||||
sprintf_s(buffer, "%g %g %g %g", v.x, v.y, v.z, v.w);
|
||||
sprintf_s(buffer, brackets ? "[%g, %g, %g, %g]" : "%g %g %g %g", v.x, v.y, v.z, v.w);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -322,11 +335,11 @@ glm::vec4 Str::FromColorString(CSZ sz, bool sRGB)
|
|||
return glm::make_vec4(rgba);
|
||||
}
|
||||
|
||||
String Str::ToColorString(const glm::vec4& v, bool sRGB)
|
||||
String Str::ToColorString(const glm::vec4& v, bool sRGB, bool hexPrefix)
|
||||
{
|
||||
const UINT32 color = Convert::ColorFloatToInt32(glm::value_ptr(v), sRGB);
|
||||
char txt[20];
|
||||
sprintf_s(txt, "%02X%02X%02X%02X",
|
||||
sprintf_s(txt, hexPrefix ? "0x%02X%02X%02X%02X" : "%02X%02X%02X%02X",
|
||||
(color >> 0) & 0xFF,
|
||||
(color >> 8) & 0xFF,
|
||||
(color >> 16) & 0xFF,
|
||||
|
|
|
@ -58,11 +58,11 @@ namespace verus
|
|||
static glm::vec4 FromStringVec4(CSZ s);
|
||||
static String ToString(int i);
|
||||
static String ToString(float f);
|
||||
static String ToString(const glm::vec2& v);
|
||||
static String ToString(const glm::vec3& v);
|
||||
static String ToString(const glm::vec4& v);
|
||||
static String ToString(const glm::vec2& v, bool brackets = false);
|
||||
static String ToString(const glm::vec3& v, bool brackets = false);
|
||||
static String ToString(const glm::vec4& v, bool brackets = false);
|
||||
static glm::vec4 FromColorString(CSZ sz, bool sRGB = true);
|
||||
static String ToColorString(const glm::vec4& v, bool sRGB = true);
|
||||
static String ToColorString(const glm::vec4& v, bool sRGB = true, bool hexPrefix = false);
|
||||
|
||||
// XML:
|
||||
static String XmlEscape(CSZ s);
|
||||
|
|
|
@ -30,10 +30,21 @@ namespace verus
|
|||
typedef const char* CSZ;
|
||||
typedef wchar_t* WSZ;
|
||||
typedef const wchar_t* CWSZ;
|
||||
|
||||
typedef std::string String;
|
||||
typedef std::wstring WideString;
|
||||
typedef std::stringstream StringStream;
|
||||
typedef glm::quat Quaternion;
|
||||
|
||||
typedef glm::quat Quaternion;
|
||||
typedef glm::ivec2 int2;
|
||||
typedef glm::ivec3 int3;
|
||||
typedef glm::ivec4 int4;
|
||||
typedef glm::vec2 float2;
|
||||
typedef glm::vec3 float3;
|
||||
typedef glm::vec4 float4;
|
||||
typedef glm::mat4 matrix;
|
||||
typedef glm::mat3x4 mataff;
|
||||
typedef UINT16 half;
|
||||
|
||||
VERUS_TYPEDEFS(String);
|
||||
VERUS_TYPEDEFS(WideString);
|
||||
|
|
|
@ -109,6 +109,61 @@ void Utils::CopyIntToByte4(const int src[4], BYTE dest[4])
|
|||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
void Utils::ComputeEdgePadding(BYTE* pData, int dataPixelStride, const BYTE* pAlpha, int alphaPixelStride, int width, int height, int radius, int channelCount)
|
||||
{
|
||||
channelCount = Math::Min(channelCount, dataPixelStride); // Assume one byte per channel.
|
||||
VERUS_RT_ASSERT(channelCount >= 1 && channelCount <= 4);
|
||||
if (!radius)
|
||||
radius = Math::Clamp((width + height) / 256, 1, 16);
|
||||
const int radiusSq = radius * radius;
|
||||
VERUS_P_FOR(i, height)
|
||||
{
|
||||
const int rowOffset = i * width;
|
||||
VERUS_FOR(j, width)
|
||||
{
|
||||
const BYTE alpha = pAlpha[alphaPixelStride * (rowOffset + j)];
|
||||
if (alpha)
|
||||
continue;
|
||||
BYTE* pDataChannels = &pData[dataPixelStride * (rowOffset + j)];
|
||||
|
||||
int minRadiusSq = INT_MAX;
|
||||
BYTE color[4] = {};
|
||||
// Kernel:
|
||||
for (int di = -radius; di <= radius; ++di)
|
||||
{
|
||||
const int ki = i + di;
|
||||
if (ki < 0 || ki >= height)
|
||||
continue;
|
||||
for (int dj = -radius; dj <= radius; ++dj)
|
||||
{
|
||||
const int kj = j + dj;
|
||||
if (kj < 0 || kj >= width)
|
||||
continue;
|
||||
|
||||
if (!di && !dj)
|
||||
continue; // Skip origin.
|
||||
const int lenSq = di * di + dj * dj;
|
||||
if (lenSq > radiusSq)
|
||||
continue;
|
||||
const BYTE kernelAlpha = pAlpha[alphaPixelStride * (ki * width + kj)];
|
||||
if (!kernelAlpha)
|
||||
continue;
|
||||
|
||||
if (lenSq < minRadiusSq)
|
||||
{
|
||||
minRadiusSq = lenSq;
|
||||
BYTE* pKernelChannels = &pData[dataPixelStride * (ki * width + kj)];
|
||||
memcpy(color, pKernelChannels, channelCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minRadiusSq != INT_MAX)
|
||||
memcpy(pDataChannels, color, channelCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Utils::TestAll()
|
||||
{
|
||||
Convert::Test();
|
||||
|
|
|
@ -65,6 +65,9 @@ namespace verus
|
|||
static void CopyByteToInt4(const BYTE src[4], int dest[4]);
|
||||
static void CopyIntToByte4(const int src[4], BYTE dest[4]);
|
||||
|
||||
static void ComputeEdgePadding(BYTE* pData, int dataPixelStride, const BYTE* pAlpha, int alphaPixelStride,
|
||||
int width, int height, int radius = 0, int channelCount = 3);
|
||||
|
||||
static void TestAll();
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -38,6 +38,7 @@ void Async::Load(CSZ url, PAsyncDelegate pDelegate, RcTaskDesc desc)
|
|||
{
|
||||
VERUS_RT_ASSERT(IsInitialized());
|
||||
VERUS_RT_ASSERT(!_inUpdate); // Not allowed to call Load() in Update().
|
||||
VERUS_RT_ASSERT(url && *url);
|
||||
|
||||
// If the queue is full we must block until something gets processed:
|
||||
bool full = false;
|
||||
|
|
|
@ -52,9 +52,33 @@ bool DDSHeader::IsBC3() const
|
|||
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::dxt5 == _pixelFormat._fourCC);
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBC4U() const
|
||||
{
|
||||
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc4u == _pixelFormat._fourCC);
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBC4S() const
|
||||
{
|
||||
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc4s == _pixelFormat._fourCC);
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBC5U() const
|
||||
{
|
||||
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc5u == _pixelFormat._fourCC);
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBC5S() const
|
||||
{
|
||||
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc5s == _pixelFormat._fourCC);
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBC() const
|
||||
{
|
||||
return IsBC1() || IsBC2() || IsBC3() || IsDXT10();
|
||||
return
|
||||
IsBC1() || IsBC2() || IsBC3() ||
|
||||
IsBC4U() || IsBC4S() ||
|
||||
IsBC5U() || IsBC5S() ||
|
||||
IsDXT10();
|
||||
}
|
||||
|
||||
bool DDSHeader::IsBGRA8() const
|
||||
|
|
|
@ -100,6 +100,10 @@ namespace verus
|
|||
bool IsBC1() const;
|
||||
bool IsBC2() const;
|
||||
bool IsBC3() const;
|
||||
bool IsBC4U() const;
|
||||
bool IsBC4S() const;
|
||||
bool IsBC5U() const;
|
||||
bool IsBC5S() const;
|
||||
bool IsBC() const;
|
||||
bool IsBGRA8() const;
|
||||
bool IsBGR8() const;
|
||||
|
@ -108,6 +112,7 @@ namespace verus
|
|||
int GetPartCount() const;
|
||||
int SkipParts(int skipCount);
|
||||
};
|
||||
VERUS_TYPEDEFS(DDSHeader);
|
||||
|
||||
struct DDSHeaderDXT10
|
||||
{
|
||||
|
@ -135,5 +140,6 @@ namespace verus
|
|||
|
||||
bool IsBC7() const;
|
||||
};
|
||||
VERUS_TYPEDEFS(DDSHeaderDXT10);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,8 +120,8 @@ void FileSystem::PreloadDefaultCache()
|
|||
".primary",
|
||||
".rig",
|
||||
".txt",
|
||||
".vml",
|
||||
".xml",
|
||||
".xmt",
|
||||
".xwa",
|
||||
".xwx",
|
||||
nullptr
|
||||
|
@ -158,32 +158,32 @@ void FileSystem::LoadResource(CSZ url, Vector<BYTE>& vData, RcLoadDesc desc)
|
|||
|
||||
void FileSystem::LoadResourceFromFile(CSZ url, Vector<BYTE>& vData, RcLoadDesc desc)
|
||||
{
|
||||
String strUrl(url), projectPathname(url);
|
||||
String primaryUrl(url), secondaryUrl(url);
|
||||
const bool shader = Str::StartsWith(url, s_shaderPAK);
|
||||
const size_t pakPos = FindPosForPAK(url);
|
||||
if (pakPos != String::npos)
|
||||
{
|
||||
if (shader)
|
||||
{
|
||||
strUrl.replace(0, strlen(s_shaderPAK), "/");
|
||||
projectPathname = String(_C(Utils::I().GetProjectPath())) + strUrl;
|
||||
primaryUrl.replace(0, strlen(s_shaderPAK), "/");
|
||||
secondaryUrl = String(_C(Utils::I().GetProjectPath())) + primaryUrl;
|
||||
StringStream ss;
|
||||
ss << _C(Utils::I().GetShaderPath()) << strUrl;
|
||||
strUrl = ss.str();
|
||||
ss << _C(Utils::I().GetShaderPath()) << primaryUrl;
|
||||
primaryUrl = ss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
String folder = strUrl.substr(1, pakPos - 1);
|
||||
const String name = strUrl.substr(pakPos + 2);
|
||||
projectPathname = String(_C(Utils::I().GetProjectPath())) + s_dataFolder + folder + "/" + name;
|
||||
const String folder = primaryUrl.substr(1, pakPos - 1);
|
||||
const String name = primaryUrl.substr(pakPos + 2);
|
||||
primaryUrl = String(_C(Utils::I().GetProjectPath())) + s_dataFolder + folder + "/" + name;
|
||||
StringStream ss;
|
||||
ss << _C(Utils::I().GetModulePath()) << s_dataFolder << folder << "/" << name;
|
||||
strUrl = ss.str();
|
||||
secondaryUrl = ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
File file;
|
||||
if (file.Open(_C(strUrl)) || file.Open(_C(projectPathname)))
|
||||
if (file.Open(_C(primaryUrl)) || file.Open(_C(secondaryUrl)))
|
||||
{
|
||||
const INT64 size = file.GetSize();
|
||||
if (size >= 0)
|
||||
|
@ -201,7 +201,7 @@ void FileSystem::LoadResourceFromFile(CSZ url, Vector<BYTE>& vData, RcLoadDesc d
|
|||
}
|
||||
}
|
||||
else if (desc._mandatory)
|
||||
throw VERUS_RUNTIME_ERROR << "LoadResourceFromFile(); File not found: " << url << " (" << strUrl << ")";
|
||||
throw VERUS_RUNTIME_ERROR << "LoadResourceFromFile(); File not found: " << url << " (" << primaryUrl << ")";
|
||||
}
|
||||
|
||||
void FileSystem::LoadResourceFromCache(CSZ url, Vector<BYTE>& vData, bool mandatory)
|
||||
|
@ -473,9 +473,9 @@ String FileSystem::ReplaceFilename(CSZ pathname, CSZ filename)
|
|||
return filename;
|
||||
}
|
||||
|
||||
void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFormat format, int param)
|
||||
void FileSystem::SaveImage(CSZ pathname, const void* p, int w, int h, ImageFormat format, int pixelStride, int param)
|
||||
{
|
||||
Vector<BYTE> v(w * h * 8);
|
||||
Vector<BYTE> v(pixelStride * (w * h) * 2); // Assume this size will be enough for compressed image.
|
||||
MutableBlob context(v.data());
|
||||
|
||||
if (ImageFormat::extension == format)
|
||||
|
@ -500,19 +500,19 @@ void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFor
|
|||
{
|
||||
case ImageFormat::png:
|
||||
{
|
||||
if (!stbi_write_png_to_func(WriteFunc, &context, w, h, 4, p, param ? param : w * 4))
|
||||
if (!stbi_write_png_to_func(WriteFunc, &context, w, h, pixelStride, p, param ? param : w * pixelStride))
|
||||
throw VERUS_RUNTIME_ERROR << "stbi_write_png_to_func()";
|
||||
}
|
||||
break;
|
||||
case ImageFormat::tga:
|
||||
{
|
||||
if (!stbi_write_tga_to_func(WriteFunc, &context, w, h, 4, p))
|
||||
if (!stbi_write_tga_to_func(WriteFunc, &context, w, h, pixelStride, p))
|
||||
throw VERUS_RUNTIME_ERROR << "stbi_write_tga_to_func()";
|
||||
}
|
||||
break;
|
||||
case ImageFormat::jpg:
|
||||
{
|
||||
if (!stbi_write_jpg_to_func(WriteFunc, &context, w, h, 4, p, param ? param : 90))
|
||||
if (!stbi_write_jpg_to_func(WriteFunc, &context, w, h, pixelStride, p, param ? param : 90))
|
||||
throw VERUS_RUNTIME_ERROR << "stbi_write_jpg_to_func()";
|
||||
}
|
||||
break;
|
||||
|
@ -528,17 +528,19 @@ void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFor
|
|||
throw VERUS_RUNTIME_ERROR << "SaveImage(); Open()";
|
||||
}
|
||||
|
||||
void FileSystem::SaveDDS(CSZ pathname, const UINT32* p, int w, int h, int d)
|
||||
void FileSystem::SaveDDS(CSZ pathname, const void* p, int w, int h, int d)
|
||||
{
|
||||
IO::File file;
|
||||
if (!file.Open(pathname, "wb"))
|
||||
throw VERUS_RUNTIME_ERROR << "SaveDDS(); Open()";
|
||||
|
||||
const int pixelStride = 4;
|
||||
|
||||
DDSHeader header;
|
||||
header._flags |= DDSHeader::Flags::linearSize;
|
||||
header._height = h;
|
||||
header._width = w;
|
||||
header._pitchOrLinearSize = w * h * 4 * Math::Max(1, abs(d));
|
||||
header._pitchOrLinearSize = pixelStride * (w * h * Math::Max(1, abs(d)));
|
||||
header._depth = abs(d);
|
||||
header._pixelFormat._flags |= DDSHeader::PixelFormatFlags::alphaPixels | DDSHeader::PixelFormatFlags::rgb;
|
||||
header._pixelFormat._rgbBitCount = 32;
|
||||
|
@ -591,7 +593,7 @@ void Image::Init(CSZ url)
|
|||
{
|
||||
VERUS_INIT();
|
||||
FileSystem::LoadResourceFromFile(url, _vData);
|
||||
_p = stbi_load_from_memory(_vData.data(), Utils::Cast32(_vData.size()), &_width, &_height, &_bytesPerPixel, 0);
|
||||
_p = stbi_load_from_memory(_vData.data(), Utils::Cast32(_vData.size()), &_width, &_height, &_pixelStride, 0);
|
||||
}
|
||||
|
||||
void Image::Done()
|
||||
|
|
|
@ -66,8 +66,8 @@ namespace verus
|
|||
static String ReplaceFilename(CSZ pathname, CSZ filename);
|
||||
|
||||
// Save data:
|
||||
static void SaveImage /**/(CSZ pathname, const UINT32* p, int w, int h, ImageFormat format = ImageFormat::tga, int param = 0);
|
||||
static void SaveDDS /**/(CSZ pathname, const UINT32* p, int w, int h, int d = 0);
|
||||
static void SaveImage /**/(CSZ pathname, const void* p, int w, int h, ImageFormat format = ImageFormat::tga, int pixelStride = sizeof(UINT32), int param = 0);
|
||||
static void SaveDDS /**/(CSZ pathname, const void* p, int w, int h, int d = 0);
|
||||
static void SaveString/**/(CSZ pathname, CSZ s);
|
||||
};
|
||||
VERUS_TYPEDEFS(FileSystem);
|
||||
|
@ -79,7 +79,7 @@ namespace verus
|
|||
BYTE* _p = nullptr;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
int _bytesPerPixel = 0;
|
||||
int _pixelStride = 0;
|
||||
|
||||
Image();
|
||||
~Image();
|
||||
|
|
|
@ -416,6 +416,13 @@ int Math::ComputeMipLevels(int w, int h, int d)
|
|||
return 1 + static_cast<int>(floor(log2(Max(Max(w, h), d))));
|
||||
}
|
||||
|
||||
BYTE Math::CombineOcclusion(BYTE a, BYTE b)
|
||||
{
|
||||
const BYTE ab = a * b / 0xFF;
|
||||
const BYTE mn = Math::Min(a, b);
|
||||
return (ab + mn + mn) / 3;
|
||||
}
|
||||
|
||||
Transform3 Math::QuadMatrix(float x, float y, float w, float h)
|
||||
{
|
||||
const Transform3 matT = Transform3::translation(Vector3(x * 2 - 1, y * -2 + 1));
|
||||
|
@ -686,4 +693,23 @@ void Math::Test()
|
|||
point /= point.getW();
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 1.f, e));
|
||||
}
|
||||
|
||||
// Z VS W:
|
||||
{
|
||||
const float zn = 3;
|
||||
const float zf = 20;
|
||||
const Point3 p1(0, 0, 7);
|
||||
const Matrix4 matV = Matrix4::lookAt(Point3(0, 0, 2), p1, Vector3(0, 1, 0)); // 5 meters away from p1.
|
||||
const Matrix4 matP = Matrix4::MakePerspective(VERUS_PI * 0.25f, 4 / 3.f, zn, zf);
|
||||
const Matrix4 matVP = matP * matV;
|
||||
const Vector4 p2 = matV * p1;
|
||||
const Vector4 p3 = matVP * p1;
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(p2.getZ(), -5.f, e)); // In V space Z is negative.
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(p3.getW(), 5.f, e)); // In VP space Z turns to positive W.
|
||||
const float unormDepth = p3.getZ() / p3.getW();
|
||||
const float a = zf * zn / (zn - zf);
|
||||
const float b = zf / (zf - zn);
|
||||
const float linearDepth = a / (unormDepth - b);
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual(linearDepth, 5.f, e)); // Linear depth starts from the eye.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,15 +70,6 @@ namespace verus
|
|||
count
|
||||
};
|
||||
|
||||
typedef glm::ivec2 int2;
|
||||
typedef glm::ivec3 int3;
|
||||
typedef glm::ivec4 int4;
|
||||
typedef glm::vec2 float2;
|
||||
typedef glm::vec3 float3;
|
||||
typedef glm::vec4 float4;
|
||||
typedef glm::mat4 matrix;
|
||||
typedef glm::mat3x4 mataff;
|
||||
|
||||
namespace VMath = Vectormath::SSE;
|
||||
}
|
||||
|
||||
|
@ -155,6 +146,8 @@ namespace verus
|
|||
|
||||
int ComputeMipLevels(int w, int h, int d = 1);
|
||||
|
||||
BYTE CombineOcclusion(BYTE a, BYTE b);
|
||||
|
||||
// Matrices:
|
||||
Transform3 QuadMatrix(float x = 0, float y = 0, float w = 1, float h = 1);
|
||||
Transform3 ToUVMatrix(float zOffset = 0, RcVector4 texSize = Vector4(0), PcVector4 pTileSize = nullptr, float uOffset = 0, float vOffset = 0);
|
||||
|
|
|
@ -44,13 +44,14 @@ void Atmosphere::Init()
|
|||
_cubeMapBaker.Init(512);
|
||||
_shadowMapBaker.Init(4096);
|
||||
|
||||
renderer.GetDS().InitByAtmosphere(_shadowMapBaker.GetTexture());
|
||||
renderer.GetDS().InitByAtmosphere(_shadowMapBaker.GetTexture());
|
||||
bloom.InitByAtmosphere(_shadowMapBaker.GetTexture());
|
||||
|
||||
CreateCelestialBodyMesh();
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Sun", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Sun", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
|
@ -59,7 +60,7 @@ void Atmosphere::Init()
|
|||
_pipe[PIPE_SUN].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Moon", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Moon", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
|
@ -104,11 +105,10 @@ void Atmosphere::UpdateSun(float time)
|
|||
{
|
||||
_night = true;
|
||||
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(quantTime * VERUS_2PI) * Vector3(0, 1, 0);
|
||||
_sun._color = glm::saturation(0.25f, _sun._color.GLM()) * 0.2f;
|
||||
}
|
||||
|
||||
// Reduce light's intensity when near horizon:
|
||||
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1);
|
||||
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1) * (_night ? 0.25f : 1.f);
|
||||
_sun._color *= _sun._alpha;
|
||||
|
||||
if (_sun._light)
|
||||
|
@ -178,7 +178,7 @@ void Atmosphere::Update()
|
|||
_async_loaded = true;
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._vertexInputBindingsFilter = (1 << 0);
|
||||
pipeDesc._depthWriteEnable = false;
|
||||
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
|
||||
|
@ -188,7 +188,7 @@ void Atmosphere::Update()
|
|||
_pipe[PIPE_SKY_REFLECTION].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
|
||||
pipeDesc._vertexInputBindingsFilter = (1 << 0);
|
||||
pipeDesc._depthWriteEnable = false;
|
||||
|
@ -216,43 +216,31 @@ void Atmosphere::Update()
|
|||
|
||||
_clouds._cloudiness.Update();
|
||||
|
||||
const float cloudinessStrength = _clouds._cloudiness * sqrt(_clouds._cloudiness);
|
||||
const float cloudScaleAmb = 1 - 0.6f * cloudinessStrength;
|
||||
const float cloudScaleFog = 1 - 0.9f * cloudinessStrength;
|
||||
const float cloudScaleSun = 1 - 0.999f * cloudinessStrength;
|
||||
const float cloudinessSq = _clouds._cloudiness * _clouds._cloudiness;
|
||||
const float cloudScaleAmb = 1 - 0.9f * _clouds._cloudiness;
|
||||
const float cloudScaleSun = 1 - 0.9999f * cloudinessSq;
|
||||
const int count = 1;
|
||||
std::stringstream ssDebug;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
const float time = (count > 1) ? (i / 256.f) : _time;
|
||||
_ambientMagnitude = GetMagnitude(time, 20000, 5000, 1000) * cloudScaleAmb;
|
||||
float color[3];
|
||||
SampleSkyColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 64000, 16000, 4000) * cloudScaleAmb);
|
||||
SampleSkyColor(100, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 32000, 5000, 300) * cloudScaleFog);
|
||||
SampleSkyColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 90000, 60000, 600) * cloudScaleSun);
|
||||
SampleSkyColor(time, 200, color); _ambientColorY1 = Vector3::MakeFromPointer(color) * _ambientMagnitude;
|
||||
SampleSkyColor(time, 216, color); _ambientColorY0 = Vector3::MakeFromPointer(color) * _ambientMagnitude;
|
||||
SampleSkyColor(time, 232, color); _ambientColor = Vector3::MakeFromPointer(color) * _ambientMagnitude;
|
||||
SampleSkyColor(time, 248, color); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 40000, 20000, 1000) * cloudScaleSun * cloudScaleSun);
|
||||
if (count > 1)
|
||||
ssDebug << static_cast<int>(glm::saturation(0.f, _ambientColor.GLM()).x) << ", ";
|
||||
}
|
||||
const String debug = ssDebug.str();
|
||||
|
||||
// <Cloudiness>
|
||||
glm::vec3 ambientColor = _ambientColor.GLM();
|
||||
glm::vec3 fogColor = _fog._color.GLM();
|
||||
_ambientColor = glm::saturation(0.7f - 0.3f * _clouds._cloudiness, ambientColor);
|
||||
_fog._color = glm::saturation(0.8f - 0.2f * _clouds._cloudiness, fogColor);
|
||||
_fog._density[0] = _fog._density[1] * (1 + 9 * _clouds._cloudiness * _clouds._cloudiness);
|
||||
_ambientColor = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColor.GLM());
|
||||
_ambientColorY0 = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColorY0.GLM());
|
||||
_ambientColorY1 = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColorY1.GLM());
|
||||
// </Cloudiness>
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (abs(_time - 0.5f) < 0.01f && glm::epsilonEqual(static_cast<float>(_clouds._cloudiness), 0.25f, 0.05f))
|
||||
{
|
||||
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<float>(grayAmbient.x, 4000, 400));
|
||||
//VERUS_RT_ASSERT(glm::epsilonEqual<float>(graySun.x, 16000, 1600));
|
||||
}
|
||||
#endif
|
||||
|
||||
// <Clouds>
|
||||
const Vector4 phaseV(_wind._baseVelocity.getX(), _wind._baseVelocity.getZ());
|
||||
_clouds._phaseA = Vector4(_clouds._phaseA - phaseV * (dt * _clouds._speedPhaseA * 0.05f)).Mod(1);
|
||||
|
@ -260,6 +248,12 @@ void Atmosphere::Update()
|
|||
// </Clouds>
|
||||
|
||||
UpdateSun(_time);
|
||||
|
||||
// <Fog>
|
||||
_fog._color = VMath::lerp(0.1f, _ambientColor, _sun._color);
|
||||
_fog._color = glm::saturation(0.9f - 0.4f * cloudinessSq, _fog._color.GLM());
|
||||
_fog._density[0] = _fog._density[1] * (1 + 9 * cloudinessSq);
|
||||
// </Fog>
|
||||
}
|
||||
|
||||
void Atmosphere::DrawSky(bool reflection)
|
||||
|
@ -282,8 +276,8 @@ void Atmosphere::DrawSky(bool reflection)
|
|||
|
||||
s_ubPerFrame._time_cloudiness.x = _time;
|
||||
s_ubPerFrame._time_cloudiness.y = _clouds._cloudiness;
|
||||
s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), 0);
|
||||
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), 0);
|
||||
s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), _ambientMagnitude);
|
||||
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), _fog._density[0]);
|
||||
s_ubPerFrame._dirToSun = float4(_sun._dirTo.GLM(), 0);
|
||||
s_ubPerFrame._sunColor = float4(_sun._color.GLM(), _sun._alpha);
|
||||
s_ubPerFrame._phaseAB = float4(
|
||||
|
@ -363,11 +357,11 @@ void Atmosphere::DrawSky(bool reflection)
|
|||
// </Clouds>
|
||||
}
|
||||
|
||||
void Atmosphere::SampleSkyColor(int level, float* pOut, float scale)
|
||||
void Atmosphere::SampleSkyColor(float time, int level, float* pOut)
|
||||
{
|
||||
if (!_texSky.IsLoaded())
|
||||
return;
|
||||
const float texCoord = _time * 256;
|
||||
const float texCoord = time * 256;
|
||||
const int intPartA = static_cast<int>(texCoord) & 0xFF;
|
||||
const int intPartB = (intPartA + 1) & 0xFF;
|
||||
const float fractPart = texCoord - intPartA;
|
||||
|
@ -386,7 +380,7 @@ void Atmosphere::SampleSkyColor(int level, float* pOut, float scale)
|
|||
LoadFromSky(rgbB, offsetB);
|
||||
|
||||
VERUS_FOR(i, 3)
|
||||
pOut[i] = Math::Clamp<float>(Math::Lerp(rgbA[i], rgbB[i], fractPart) * 0.5f * scale, 0, 1);
|
||||
pOut[i] = Math::Lerp(rgbA[i], rgbB[i], fractPart);
|
||||
}
|
||||
|
||||
float Atmosphere::GetMagnitude(float time, float noon, float dusk, float midnight)
|
||||
|
@ -443,6 +437,12 @@ void Atmosphere::OnSceneResetInitSunLight()
|
|||
_sun._light->SetTransient();
|
||||
}
|
||||
|
||||
void Atmosphere::SetLatitude(float lat)
|
||||
{
|
||||
_sun._latitude = lat;
|
||||
_sun._matTilt = Matrix3::rotationX(_sun._latitude);
|
||||
}
|
||||
|
||||
RcMatrix3 Atmosphere::GetPlantBendingMatrix() const
|
||||
{
|
||||
return _wind._matPlantBending;
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace verus
|
|||
Vector3 _color = Vector3(0);
|
||||
LightPwn _light;
|
||||
float _alpha = 1;
|
||||
float _latitude = 0.7f;
|
||||
float _latitude = VERUS_PI * 0.25f;
|
||||
};
|
||||
|
||||
struct Wind
|
||||
|
@ -89,12 +89,15 @@ namespace verus
|
|||
Sun _sun;
|
||||
Wind _wind;
|
||||
Vector3 _ambientColor = Vector3(0);
|
||||
Vector3 _ambientColorY0 = Vector3(0);
|
||||
Vector3 _ambientColorY1 = Vector3(0);
|
||||
CubeMapBaker _cubeMapBaker;
|
||||
CascadedShadowMapBaker _shadowMapBaker;
|
||||
Mesh _skyDome;
|
||||
CGI::TextureRAM _texSky;
|
||||
float _time = 0.5f;
|
||||
float _timeSpeed = 1 / 300.f;
|
||||
float _ambientMagnitude = 1;
|
||||
CGI::CSHandle _cshSkyFS;
|
||||
CGI::CSHandle _cshSunFS;
|
||||
CGI::CSHandle _cshMoonFS;
|
||||
|
@ -121,7 +124,7 @@ namespace verus
|
|||
void Update();
|
||||
void DrawSky(bool reflection = false);
|
||||
|
||||
void SampleSkyColor(int level, float* pOut, float scale);
|
||||
void SampleSkyColor(float time, int level, float* pOut);
|
||||
static float GetMagnitude(float time, float noon, float dusk, float midnight);
|
||||
|
||||
// Time:
|
||||
|
@ -130,7 +133,10 @@ namespace verus
|
|||
float GetTimeSpeed() const { return _timeSpeed; }
|
||||
void SetTimeSpeed(float x) { _timeSpeed = x; }
|
||||
|
||||
float GetAmbientMagnitude() const { return _ambientMagnitude; }
|
||||
RcVector3 GetAmbientColor() const { return _ambientColor; }
|
||||
RcVector3 GetAmbientColorY0() const { return _ambientColorY0; }
|
||||
RcVector3 GetAmbientColorY1() const { return _ambientColorY1; }
|
||||
|
||||
// Clouds:
|
||||
Anim::Elastic<float>& GetCloudiness() { return _clouds._cloudiness; }
|
||||
|
@ -147,6 +153,7 @@ namespace verus
|
|||
RcVector3 GetSunColor() const;
|
||||
float GetSunAlpha() const;
|
||||
void OnSceneResetInitSunLight();
|
||||
void SetLatitude(float lat);
|
||||
|
||||
// Wind:
|
||||
RcMatrix3 GetPlantBendingMatrix() const;
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace verus
|
|||
Math::Bounds GetBounds() const;
|
||||
|
||||
template<typename T>
|
||||
void ForEachVertex(const T& fn) const
|
||||
void ForEachVertex(const T& fn, bool boneIndices = false) const
|
||||
{
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
|
@ -133,8 +133,28 @@ namespace verus
|
|||
DequantizeUsingDeq3D(_vBinding0[i]._pos, _posDeq, pos);
|
||||
DequantizeNrm(_vBinding0[i]._nrm, nrm);
|
||||
DequantizeUsingDeq2D(_vBinding0[i]._tc0, _tc0Deq, tc);
|
||||
if (Continue::no == fn(i, pos, nrm, tc))
|
||||
break;
|
||||
if (_vBinding1.empty() || !boneIndices)
|
||||
{
|
||||
if (Continue::no == fn(i, pos, nrm, tc))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool done = false;
|
||||
VERUS_FOR(j, 4)
|
||||
{
|
||||
if (_vBinding1[i]._bw[j] > 0)
|
||||
{
|
||||
if (Continue::no == fn(_vBinding1[i]._bi[j], pos, nrm, tc))
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ void CubeMapBaker::Init(int side)
|
|||
texDesc._format = CGI::Format::floatR11G11B10;
|
||||
texDesc._width = _side;
|
||||
texDesc._height = _side;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::cubeMap;
|
||||
texDesc._mipLevels = 0;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips | CGI::TextureDesc::Flags::cubeMap;
|
||||
_tex[TEX_COLOR].Init(texDesc);
|
||||
texDesc.Reset();
|
||||
texDesc._name = "CubeMapBaker.DepthTex";
|
||||
|
|
|
@ -592,7 +592,7 @@ void EditorTerrain::SplatFromFile(CSZ url, int layer)
|
|||
{
|
||||
VERUS_FOR(j, _mapSide)
|
||||
{
|
||||
const BYTE value = image._p[((i << _mapShift) + j) * image._bytesPerPixel];
|
||||
const BYTE value = image._p[image._pixelStride * ((i << _mapShift) + j)];
|
||||
const int ij[] = { i, j };
|
||||
SplatTileAtEx(ij, layer, value / 255.f);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ void Forest::InitStatic()
|
|||
s_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubForestVS, sizeof(s_ubForestVS), 100, {}, CGI::ShaderStageFlags::vs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubForestFS, sizeof(s_ubForestFS), 100,
|
||||
{
|
||||
CGI::Sampler::linearMipL,
|
||||
CGI::Sampler::linearMipL,
|
||||
CGI::Sampler::linearMipL,
|
||||
CGI::Sampler::linearMipL
|
||||
|
@ -77,12 +78,12 @@ void Forest::Init(PTerrain pTerrain, CSZ url)
|
|||
Scatter::TypeDesc(SCATTER_TYPE_5, 5),
|
||||
Scatter::TypeDesc(SCATTER_TYPE_3, 3)
|
||||
};
|
||||
_scatter.Init(32, SCATTER_TYPE_COUNT, id, 19201);
|
||||
_scatter.Init(s_scatterSide, SCATTER_TYPE_COUNT, id, 19201);
|
||||
_scatter.SetDelegate(this);
|
||||
_scatter.SetMaxDist(_maxDist * 1.25f);
|
||||
|
||||
_vPlants.reserve(16);
|
||||
_vLayerPlants.reserve(16);
|
||||
_vLayerData.reserve(16);
|
||||
_vDrawPlants.resize(_capacity);
|
||||
|
||||
_vCollisionPool.Resize(1000);
|
||||
|
@ -196,12 +197,12 @@ void Forest::Update()
|
|||
// Time to get the size of this mesh.
|
||||
plant._maxSize = plant.GetSize() * plant._maxScale;
|
||||
BakeChunks(plant);
|
||||
UpdateOcclusion(plant);
|
||||
if (plant._maxSize > _maxSizeAll)
|
||||
{
|
||||
_maxSizeAll = plant._maxSize;
|
||||
_pTerrain->FattenQuadtreeNodesBy(_maxSizeAll);
|
||||
}
|
||||
plant._aoSize = plant._mesh.GetBounds().GetAverageSize() * 1.5f;
|
||||
}
|
||||
|
||||
if (!plant._tex[0] && plant._mesh.IsLoaded() && plant._material->IsLoaded())
|
||||
|
@ -211,13 +212,15 @@ void Forest::Update()
|
|||
{
|
||||
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._tex[Plant::TEX_GBUFFER_2] && plant._tex[Plant::TEX_GBUFFER_2]->IsLoaded() &&
|
||||
plant._tex[Plant::TEX_GBUFFER_3] && plant._tex[Plant::TEX_GBUFFER_3]->IsLoaded())
|
||||
{
|
||||
plant._csh = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(1,
|
||||
{
|
||||
plant._tex[Plant::TEX_GBUFFER_0],
|
||||
plant._tex[Plant::TEX_GBUFFER_1],
|
||||
plant._tex[Plant::TEX_GBUFFER_2]
|
||||
plant._tex[Plant::TEX_GBUFFER_2],
|
||||
plant._tex[Plant::TEX_GBUFFER_3]
|
||||
});
|
||||
VERUS_QREF_ATMO;
|
||||
plant._cshSimple = s_shader[SHADER_SIMPLE]->BindDescriptorSetTextures(1,
|
||||
|
@ -244,6 +247,8 @@ void Forest::Update()
|
|||
}
|
||||
if (allLoaded)
|
||||
{
|
||||
_pTerrain->UpdateOcclusion(this);
|
||||
|
||||
int vertCount = 0;
|
||||
for (auto& plant : _vPlants)
|
||||
{
|
||||
|
@ -277,7 +282,7 @@ void Forest::Update()
|
|||
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},
|
||||
{0, offsetof(Vertex, _tc), CGI::ViaType::halfs, 2, CGI::ViaUsage::texCoord, 0},
|
||||
CGI::VertexInputAttrDesc::End()
|
||||
};
|
||||
geoDesc._pVertexInputAttrDesc = viaDesc;
|
||||
|
@ -296,6 +301,7 @@ void Forest::Update()
|
|||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
_pipe[PIPE_MAIN].Init(pipeDesc);
|
||||
}
|
||||
|
@ -492,7 +498,7 @@ void Forest::DrawSprites()
|
|||
s_ubForestVS._matWVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
|
||||
s_ubForestVS._viewportSize = cb->GetViewportSize().GLM();
|
||||
s_ubForestVS._eyePos = float4(sm.GetCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubForestVS._eyePosScreen = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubForestVS._mainCameraEyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
|
||||
cb->BindPipeline(_pipe[drawingDepth ? PIPE_DEPTH : PIPE_MAIN]);
|
||||
cb->BindVertexBuffers(_geo);
|
||||
|
@ -512,72 +518,7 @@ void Forest::DrawSprites()
|
|||
s_shader[SHADER_MAIN]->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void Forest::DrawAO()
|
||||
{
|
||||
if (!_visibleCount)
|
||||
return;
|
||||
|
||||
VERUS_QREF_HELPERS;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
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::DrawSimple(DrawSimpleMode mode)
|
||||
void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
|
||||
{
|
||||
if (!_geo)
|
||||
return;
|
||||
|
@ -587,18 +528,53 @@ void Forest::DrawSimple(DrawSimpleMode mode)
|
|||
VERUS_QREF_SM;
|
||||
VERUS_QREF_WATER;
|
||||
|
||||
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? static_cast<float>(USHRT_MAX) : 0.f;
|
||||
const float pointSpriteScaleY = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? 1.f : -1.f;
|
||||
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? static_cast<float>(USHRT_MAX) : -4.f;
|
||||
const float pointSpriteFlipY = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? 1.f : -1.f;
|
||||
|
||||
Vector3 normalFlip(1, 1, 1);
|
||||
Vector3 tcFlip(1, 1, 0);
|
||||
if (DrawSimpleMode::envMap == mode)
|
||||
{
|
||||
switch (cubeMapFace)
|
||||
{
|
||||
case CGI::CubeMapFace::posX:
|
||||
case CGI::CubeMapFace::negX:
|
||||
{
|
||||
normalFlip = Vector3(-1, 1, -1);
|
||||
tcFlip = Vector3(-1, 1, 0);
|
||||
}
|
||||
break;
|
||||
case CGI::CubeMapFace::posY:
|
||||
case CGI::CubeMapFace::negY:
|
||||
{
|
||||
normalFlip = Vector3(1, 1, -1);
|
||||
tcFlip = Vector3(1, -1, 0);
|
||||
}
|
||||
break;
|
||||
case CGI::CubeMapFace::posZ:
|
||||
case CGI::CubeMapFace::negZ:
|
||||
{
|
||||
normalFlip = Vector3(-1, 1, -1);
|
||||
tcFlip = Vector3(-1, 1, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
normalFlip = Vector3(1, -1, 1);
|
||||
}
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubSimpleForestVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
|
||||
s_ubSimpleForestVS._matWVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
|
||||
s_ubSimpleForestVS._viewportSize = renderer.GetCommandBuffer()->GetViewportSize().GLM();
|
||||
s_ubSimpleForestVS._viewportSize = cb->GetViewportSize().GLM();
|
||||
s_ubSimpleForestVS._eyePos_clipDistanceOffset = float4(sm.GetCamera()->GetEyePosition().GLM(), clipDistanceOffset);
|
||||
s_ubSimpleForestVS._eyePosScreen = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubSimpleForestVS._pointSpriteScale = float4(1, pointSpriteScaleY, 0, 0);
|
||||
s_ubSimpleForestVS._mainCameraEyePos_pointSpriteFlipY = float4(sm.GetMainCamera()->GetEyePosition().GLM(), pointSpriteFlipY);
|
||||
s_ubSimpleForestFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
|
||||
s_ubSimpleForestFS._normalFlip = float4(normalFlip.GLM(), 0);
|
||||
s_ubSimpleForestFS._tcFlip = float4(tcFlip.GLM(), 0);
|
||||
s_ubSimpleForestFS._ambientColor = float4(atmo.GetAmbientColor().GLM(), 0);
|
||||
s_ubSimpleForestFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubSimpleForestFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
|
@ -669,9 +645,9 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
|
|||
VERUS_QREF_SM;
|
||||
|
||||
const int layer = _pTerrain->GetMainLayerAt(ij);
|
||||
if (layer >= _vLayerPlants.size())
|
||||
if (layer >= _vLayerData.size())
|
||||
continue;
|
||||
const int plantIndex = _vLayerPlants[layer]._plants[type];
|
||||
const int plantIndex = _vLayerData[layer]._plants[type];
|
||||
if (plantIndex < 0)
|
||||
continue;
|
||||
RPlant plant = _vPlants[plantIndex];
|
||||
|
@ -700,7 +676,7 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
|
|||
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
|
||||
const int type = instance._type;
|
||||
const int layer = _pTerrain->GetMainLayerAt(ij);
|
||||
const int plantIndex = _vLayerPlants[layer]._plants[type];
|
||||
const int plantIndex = _vLayerData[layer]._plants[type];
|
||||
RPlant plant = _vPlants[plantIndex];
|
||||
|
||||
const float h = _pTerrain->GetHeightAt(ij);
|
||||
|
@ -775,8 +751,8 @@ float Forest::GetMinHeight(const int ij[2], float h) const
|
|||
|
||||
void Forest::SetLayer(int layer, RcLayerDesc desc)
|
||||
{
|
||||
if (_vLayerPlants.size() < layer + 1)
|
||||
_vLayerPlants.resize(layer + 1);
|
||||
if (_vLayerData.size() < layer + 1)
|
||||
_vLayerData.resize(layer + 1);
|
||||
|
||||
Random random(2247 + layer);
|
||||
|
||||
|
@ -788,11 +764,11 @@ void Forest::SetLayer(int layer, RcLayerDesc desc)
|
|||
const int plantIndex = FindPlant(plantDesc._url);
|
||||
if (plantIndex >= 0)
|
||||
{
|
||||
_vLayerPlants[layer]._plants[type] = plantIndex;
|
||||
_vLayerData[layer]._plants[type] = plantIndex;
|
||||
}
|
||||
else // Add new plant?
|
||||
{
|
||||
_vLayerPlants[layer]._plants[type] = Utils::Cast32(_vPlants.size());
|
||||
_vLayerData[layer]._plants[type] = Utils::Cast32(_vPlants.size());
|
||||
_vPlants.resize(_vPlants.size() + 1);
|
||||
RPlant plant = _vPlants[_vPlants.size() - 1];
|
||||
plant._url = plantDesc._url;
|
||||
|
@ -843,7 +819,7 @@ void Forest::BakeChunks(RPlant plant)
|
|||
const int ij[] = { iOffset + i, jOffset + j };
|
||||
|
||||
const int layer = _pTerrain->GetMainLayerAt(ij);
|
||||
if (layer >= _vLayerPlants.size())
|
||||
if (layer >= _vLayerData.size())
|
||||
continue;
|
||||
|
||||
if (_pTerrain->GetNormalAt(ij)[1] < plant._allowedNormal)
|
||||
|
@ -851,8 +827,8 @@ void Forest::BakeChunks(RPlant plant)
|
|||
|
||||
VERUS_FOR(type, SCATTER_TYPE_COUNT)
|
||||
{
|
||||
const int index = _vLayerPlants[layer]._plants[type];
|
||||
if (index >= 0 && &plant == &_vPlants[index])
|
||||
const int plantIndex = _vLayerData[layer]._plants[type];
|
||||
if (plantIndex >= 0 && &plant == &_vPlants[plantIndex])
|
||||
{
|
||||
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
|
||||
if (type == instance._type)
|
||||
|
@ -872,8 +848,8 @@ void Forest::BakeChunks(RPlant plant)
|
|||
|
||||
Vertex v;
|
||||
v._pos = pos.GLM();
|
||||
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._tc[0] = Convert::FloatToHalf(psize);
|
||||
v._tc[1] = Convert::FloatToHalf(instance._angle / VERUS_2PI);
|
||||
v._pos.y += psize * 0.5f / _margin - psize * 0.05f;
|
||||
if (!bc._vSprites.capacity())
|
||||
bc._vSprites.reserve(256);
|
||||
|
@ -897,11 +873,67 @@ void Forest::BakeChunks(RPlant plant)
|
|||
}
|
||||
}
|
||||
|
||||
void Forest::UpdateOcclusion(RPlant plant)
|
||||
{
|
||||
VERUS_FOR(layer, _vLayerData.size())
|
||||
{
|
||||
VERUS_FOR(type, SCATTER_TYPE_COUNT)
|
||||
{
|
||||
const int plantIndex = _vLayerData[layer]._plants[type];
|
||||
if (plantIndex >= 0 && &plant == &_vPlants[plantIndex])
|
||||
{
|
||||
VERUS_FOR(i, s_scatterSide)
|
||||
{
|
||||
VERUS_FOR(j, s_scatterSide)
|
||||
{
|
||||
const int ij[] = { i, j };
|
||||
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
|
||||
if (type == instance._type)
|
||||
{
|
||||
const float scale = plant._vScales[instance._rand % plant._vScales.size()];
|
||||
const float size = plant.GetSize() * scale;
|
||||
AddOcclusionAt(ij, layer, 3 + static_cast<int>(size + 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Forest::AddOcclusionAt(const int ij[2], int layer, int radius)
|
||||
{
|
||||
radius = Math::Clamp(radius, 1, 15);
|
||||
const int mask = s_scatterSide - 1;
|
||||
const int radiusSq = radius * radius;
|
||||
for (int di = -radius; di <= radius; ++di)
|
||||
{
|
||||
const int ki = ij[0] + di;
|
||||
const int mi = (ki + s_scatterSide) & mask;
|
||||
for (int dj = -radius; dj <= radius; ++dj)
|
||||
{
|
||||
const int kj = ij[1] + dj;
|
||||
const int mj = (kj + s_scatterSide) & mask;
|
||||
|
||||
const int lenSq = di * di + dj * dj;
|
||||
if (lenSq > radiusSq)
|
||||
continue;
|
||||
|
||||
const float a = static_cast<float>(lenSq) / radiusSq;
|
||||
const float b = 0xFF * pow(a, 0.3f);
|
||||
const float c = Math::Clamp(b, 128.f - radius * radius, 255.f);
|
||||
const BYTE value = static_cast<BYTE>(c);
|
||||
BYTE& dst = _vLayerData[layer]._occlusion[mi * s_scatterSide + mj];
|
||||
dst = Math::CombineOcclusion(dst, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Forest::LoadSprite(RPlant plant)
|
||||
{
|
||||
int count = 0;
|
||||
const CSZ ext[] = { "", ".FX", ".FX" };
|
||||
VERUS_FOR(i, 3)
|
||||
const CSZ ext[] = { "", ".X", ".X", ".X" };
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
String pathname = _C(plant._mesh.GetUrl());
|
||||
char filename[20];
|
||||
|
@ -916,7 +948,7 @@ bool Forest::LoadSprite(RPlant plant)
|
|||
plant._tex[i].Init(_C(pathname));
|
||||
}
|
||||
}
|
||||
return 3 == count;
|
||||
return 4 == count;
|
||||
}
|
||||
|
||||
void Forest::BakeSprite(RPlant plant, CSZ url)
|
||||
|
@ -932,7 +964,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
cb.InitOneTimeSubmit();
|
||||
|
||||
const int frameSide = 512;
|
||||
const int framePad = 16;
|
||||
const int framePad = 4;
|
||||
const int frameCountH = 16;
|
||||
const int frameCountV = 16;
|
||||
const int texWidth = frameCountH * frameSide;
|
||||
|
@ -945,6 +977,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
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("GBuffer3", CGI::Format::unormR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
|
||||
CGI::RP::Attachment("Depth", CGI::Format::unormD24uintS8).LoadOpClear().Layout(CGI::ImageLayout::depthStencilAttachment),
|
||||
},
|
||||
{
|
||||
|
@ -952,26 +985,41 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
{
|
||||
CGI::RP::Ref("GBuffer0", CGI::ImageLayout::colorAttachment),
|
||||
CGI::RP::Ref("GBuffer1", CGI::ImageLayout::colorAttachment),
|
||||
CGI::RP::Ref("GBuffer2", CGI::ImageLayout::colorAttachment)
|
||||
CGI::RP::Ref("GBuffer2", CGI::ImageLayout::colorAttachment),
|
||||
CGI::RP::Ref("GBuffer3", CGI::ImageLayout::colorAttachment)
|
||||
}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment))
|
||||
},
|
||||
{});
|
||||
|
||||
CGI::TexturePwn texGB[3], texDepth;
|
||||
if (!_pipe[PIPE_MESH_BAKE])
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(plant._mesh.GetGeometry(), Scene::Mesh::GetShader(), "#", rph);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._vertexInputBindingsFilter = plant._mesh.GetBindingsMask();
|
||||
_pipe[PIPE_MESH_BAKE].Init(pipeDesc);
|
||||
}
|
||||
|
||||
CGI::TexturePwn texGB[4], texDepth;
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._width = texWidth;
|
||||
texDesc._height = texHeight;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
|
||||
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(0.5f);
|
||||
texDesc._format = CGI::Format::srgbR8G8B8A8;
|
||||
texGB[0].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(0.5f, 0);
|
||||
texDesc._format = CGI::Format::unormR10G10B10A2;
|
||||
texGB[1].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(0.5f);
|
||||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texGB[2].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer3(0.5f);
|
||||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texGB[3].Init(texDesc);
|
||||
texDesc.Reset();
|
||||
texDesc._clearValue = Vector4(1);
|
||||
texDesc._format = CGI::Format::unormD24uintS8;
|
||||
|
@ -984,6 +1032,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
texGB[0],
|
||||
texGB[1],
|
||||
texGB[2],
|
||||
texGB[3],
|
||||
texDepth
|
||||
},
|
||||
texWidth,
|
||||
|
@ -994,13 +1043,14 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
texGB[0]->GetClearValue(),
|
||||
texGB[1]->GetClearValue(),
|
||||
texGB[2]->GetClearValue(),
|
||||
texGB[3]->GetClearValue(),
|
||||
texDepth->GetClearValue()
|
||||
});
|
||||
|
||||
plant._mesh.BindPipeline(cb, false);
|
||||
cb->BindPipeline(_pipe[PIPE_MESH_BAKE]);
|
||||
plant._mesh.BindGeo(cb);
|
||||
Mesh::GetShader()->BeginBindDescriptors();
|
||||
plant._material->UpdateMeshUniformBuffer();
|
||||
plant._material->UpdateMeshUniformBuffer(1, false);
|
||||
cb->BindDescriptors(Scene::Mesh::GetShader(), 1, plant._material->GetComplexSetHandle());
|
||||
plant._mesh.UpdateUniformBufferPerMeshVS();
|
||||
cb->BindDescriptors(Scene::Mesh::GetShader(), 2);
|
||||
|
@ -1048,7 +1098,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
|
||||
cb->EndRenderPass();
|
||||
|
||||
CGI::TexturePwn texFinalGB[3];
|
||||
CGI::TexturePwn texFinalGB[4];
|
||||
texDesc.Reset();
|
||||
texDesc._width = texWidth;
|
||||
texDesc._height = texHeight;
|
||||
|
@ -1056,19 +1106,22 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips;
|
||||
texDesc._readbackMip = 2;
|
||||
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(0.5f);
|
||||
texDesc._format = CGI::Format::srgbR8G8B8A8;
|
||||
texFinalGB[0].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(0.5f, 0);
|
||||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texFinalGB[1].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2();
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(0.5f);
|
||||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texFinalGB[2].Init(texDesc);
|
||||
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer3(0.5f);
|
||||
texDesc._format = CGI::Format::unormR8G8B8A8;
|
||||
texFinalGB[3].Init(texDesc);
|
||||
|
||||
renderer.GetDS().BakeSprites(texGB, texFinalGB, cb.Get());
|
||||
|
||||
VERUS_FOR(i, 3)
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
texFinalGB[i]->GenerateMips(cb.Get());
|
||||
texFinalGB[i]->ReadbackSubresource(nullptr, true, cb.Get());
|
||||
|
@ -1080,8 +1133,8 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
const int mipHeight = texHeight / 4;
|
||||
Vector<UINT32> vData;
|
||||
vData.resize(mipWidth * mipHeight);
|
||||
const CSZ ext[] = { "", ".FX", ".FX" };
|
||||
VERUS_FOR(i, 3)
|
||||
const CSZ ext[] = { "", ".X", ".X", ".X" };
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
texFinalGB[i]->ReadbackSubresource(vData.data(), false);
|
||||
|
||||
|
@ -1098,6 +1151,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
|
|||
renderer->DeleteFramebuffer(fbh);
|
||||
renderer->DeleteRenderPass(rph);
|
||||
renderer->DeleteCommandBuffer(cb.Detach());
|
||||
_pipe[PIPE_MESH_BAKE].Done();
|
||||
}
|
||||
|
||||
bool Forest::BakeSprites(CSZ url)
|
||||
|
@ -1120,9 +1174,9 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl
|
|||
VERUS_QREF_SM;
|
||||
|
||||
const int layer = _pTerrain->GetMainLayerAt(ij);
|
||||
if (layer >= _vLayerPlants.size())
|
||||
if (layer >= _vLayerData.size())
|
||||
return;
|
||||
const int plantIndex = _vLayerPlants[layer]._plants[type];
|
||||
const int plantIndex = _vLayerData[layer]._plants[type];
|
||||
if (plantIndex < 0)
|
||||
return;
|
||||
|
||||
|
@ -1179,3 +1233,13 @@ Continue Forest::Octree_ProcessNode(void* pToken, void* pUser)
|
|||
pBakedChunk->_visible = sm.GetMainCamera()->GetFrustum().ContainsAabb(pBakedChunk->_bounds) != Relation::outside;
|
||||
return Continue::yes;
|
||||
}
|
||||
|
||||
BYTE Forest::GetOcclusionAt(const int ij[2], int layer) const
|
||||
{
|
||||
if (layer >= _vLayerData.size())
|
||||
return 0xFF;
|
||||
const int mask = s_scatterSide - 1;
|
||||
const int i = ij[0] & mask;
|
||||
const int j = ij[1] & mask;
|
||||
return _vLayerData[layer]._occlusion[i * s_scatterSide + j];
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace verus
|
|||
PIPE_DEPTH,
|
||||
PIPE_SIMPLE_ENV_MAP,
|
||||
PIPE_SIMPLE_PLANAR_REF,
|
||||
PIPE_MESH_BAKE,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
|
@ -40,11 +41,13 @@ namespace verus
|
|||
SCATTER_TYPE_COUNT
|
||||
};
|
||||
|
||||
static const int s_scatterSide = 32;
|
||||
|
||||
private:
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 _pos;
|
||||
short _tc[2]; // psize, angle.
|
||||
half _tc[2]; // {psize, angle}
|
||||
};
|
||||
VERUS_TYPEDEFS(Vertex);
|
||||
|
||||
|
@ -101,39 +104,41 @@ namespace verus
|
|||
TEX_GBUFFER_0,
|
||||
TEX_GBUFFER_1,
|
||||
TEX_GBUFFER_2,
|
||||
TEX_GBUFFER_3,
|
||||
TEX_COUNT
|
||||
};
|
||||
|
||||
String _url;
|
||||
Mesh _mesh;
|
||||
MaterialPwn _material;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshSimple;
|
||||
Vector<BakedChunk> _vBakedChunks;
|
||||
Vector<float> _vScales;
|
||||
float _alignToNormal = 1;
|
||||
float _maxScale = 0;
|
||||
float _maxSize = 0;
|
||||
float _windBending = 1;
|
||||
float _aoSize = 1;
|
||||
char _allowedNormal = 116;
|
||||
String _url;
|
||||
Mesh _mesh;
|
||||
MaterialPwn _material;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshSimple;
|
||||
Vector<BakedChunk> _vBakedChunks;
|
||||
Vector<float> _vScales;
|
||||
float _alignToNormal = 1;
|
||||
float _maxScale = 0;
|
||||
float _maxSize = 0;
|
||||
float _windBending = 1;
|
||||
char _allowedNormal = 116;
|
||||
|
||||
float GetSize() const;
|
||||
};
|
||||
VERUS_TYPEDEFS(Plant);
|
||||
|
||||
class LayerPlants
|
||||
class LayerData
|
||||
{
|
||||
public:
|
||||
char _plants[SCATTER_TYPE_COUNT];
|
||||
BYTE _occlusion[s_scatterSide * s_scatterSide];
|
||||
|
||||
LayerPlants()
|
||||
LayerData()
|
||||
{
|
||||
std::fill(_plants, _plants + SCATTER_TYPE_COUNT, -1);
|
||||
std::fill(_occlusion, _occlusion + sizeof(_occlusion), 0xFF);
|
||||
}
|
||||
};
|
||||
VERUS_TYPEDEFS(LayerPlants);
|
||||
VERUS_TYPEDEFS(LayerData);
|
||||
|
||||
class DrawPlant
|
||||
{
|
||||
|
@ -161,7 +166,7 @@ namespace verus
|
|||
Math::Octree _octree;
|
||||
Scatter _scatter;
|
||||
Vector<Plant> _vPlants;
|
||||
Vector<LayerPlants> _vLayerPlants;
|
||||
Vector<LayerData> _vLayerData;
|
||||
Vector<DrawPlant> _vDrawPlants;
|
||||
DifferenceVector<CollisionPlant> _vCollisionPlants;
|
||||
Pool<CollisionPoolBlock> _vCollisionPool;
|
||||
|
@ -182,12 +187,12 @@ namespace verus
|
|||
public:
|
||||
CSZ _url = nullptr;
|
||||
float _alignToNormal = 1;
|
||||
float _minScale = 0.5f;
|
||||
float _maxScale = 1.5f;
|
||||
float _minScale = 0.8f;
|
||||
float _maxScale = 1.25f;
|
||||
float _windBending = 1;
|
||||
char _allowedNormal = 116;
|
||||
|
||||
void Set(CSZ url, float alignToNormal = 1, float minScale = 0.5f, float maxScale = 1.5f, float windBending = 1, char allowedNormal = 116)
|
||||
void Set(CSZ url, float alignToNormal = 1, float minScale = 0.8f, float maxScale = 1.25f, float windBending = 1, char allowedNormal = 116)
|
||||
{
|
||||
_url = url;
|
||||
_alignToNormal = alignToNormal;
|
||||
|
@ -223,8 +228,7 @@ namespace verus
|
|||
void Draw(bool allowTess = true);
|
||||
VERUS_P(void DrawModels(bool allowTess));
|
||||
VERUS_P(void DrawSprites());
|
||||
void DrawAO();
|
||||
void DrawSimple(DrawSimpleMode mode);
|
||||
void DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace = CGI::CubeMapFace::none);
|
||||
|
||||
void UpdateCollision(const Vector<Vector4>& vZones);
|
||||
|
||||
|
@ -235,6 +239,9 @@ namespace verus
|
|||
void SetLayer(int layer, RcLayerDesc desc);
|
||||
VERUS_P(int FindPlant(CSZ url) const);
|
||||
VERUS_P(void BakeChunks(RPlant plant));
|
||||
VERUS_P(void UpdateOcclusion(RPlant plant));
|
||||
VERUS_P(void AddOcclusionAt(const int ij[2], int layer, int radius));
|
||||
|
||||
bool LoadSprite(RPlant plant);
|
||||
void BakeSprite(RPlant plant, CSZ url);
|
||||
bool BakeSprites(CSZ url);
|
||||
|
@ -243,6 +250,8 @@ namespace verus
|
|||
float scale, float angle, UINT32 r) override;
|
||||
|
||||
virtual Continue Octree_ProcessNode(void* pToken, void* pUser) override;
|
||||
|
||||
BYTE GetOcclusionAt(const int ij[2], int layer) const;
|
||||
};
|
||||
VERUS_TYPEDEFS(Forest);
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
|
|||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
_pipe[PIPE_MAIN].Init(pipeDesc);
|
||||
}
|
||||
|
@ -117,6 +118,7 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
|
|||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
_pipe[PIPE_BILLBOARDS].Init(pipeDesc);
|
||||
}
|
||||
|
@ -158,8 +160,11 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
|
|||
|
||||
void Grass::Done()
|
||||
{
|
||||
s_shader->FreeDescriptorSet(_cshVS);
|
||||
s_shader->FreeDescriptorSet(_cshFS);
|
||||
if (s_shader)
|
||||
{
|
||||
s_shader->FreeDescriptorSet(_cshVS);
|
||||
s_shader->FreeDescriptorSet(_cshFS);
|
||||
}
|
||||
VERUS_DONE(Grass);
|
||||
}
|
||||
|
||||
|
@ -181,10 +186,10 @@ void Grass::Update()
|
|||
_phase = glm::fract(_phase + dt * 2.3f);
|
||||
|
||||
const float windSpeed = atmo.GetWindSpeed();
|
||||
const float warpStrength = Math::Clamp<float>(windSpeed * (1 / 13.f), 0, 1.f);
|
||||
const float turbulence = Math::Clamp<float>(windSpeed * (1 / 17.f), 0, 0.4f);
|
||||
const float warpStrength = Math::Clamp<float>(windSpeed * 0.04f, 0, 1.f);
|
||||
const float turbulence = Math::Clamp<float>(windSpeed * 0.04f, 0, 0.4f);
|
||||
|
||||
_warpSpring.Update(atmo.GetWindDirection() * (warpStrength * 30.f));
|
||||
_warpSpring.Update(atmo.GetWindDirection() * (warpStrength * 20.f));
|
||||
_turbulence = turbulence * turbulence;
|
||||
|
||||
// Async texture loading:
|
||||
|
@ -239,9 +244,9 @@ void Grass::Draw()
|
|||
s_ubGrassVS._matWV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
|
||||
s_ubGrassVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
|
||||
s_ubGrassVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
|
||||
s_ubGrassVS._phase_mapSideInv_bushMask.x = _phase;
|
||||
s_ubGrassVS._phase_mapSideInv_bushMask.y = 1.f / _mapSide;
|
||||
s_ubGrassVS._phase_mapSideInv_bushMask.z = *(float*)&bushMask;
|
||||
s_ubGrassVS._phase_invMapSide_bushMask.x = _phase;
|
||||
s_ubGrassVS._phase_invMapSide_bushMask.y = 1.f / _mapSide;
|
||||
s_ubGrassVS._phase_invMapSide_bushMask.z = *(float*)&bushMask;
|
||||
s_ubGrassVS._posEye = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubGrassVS._viewportSize = cb->GetViewportSize().GLM();
|
||||
s_ubGrassVS._warp_turb = Vector4(_warpSpring.GetOffset(), _turbulence).GLM();
|
||||
|
@ -456,7 +461,7 @@ void Grass::LoadLayersFromFile(CSZ url)
|
|||
for (auto node : root.children("grass"))
|
||||
{
|
||||
const int id = node.attribute("id").as_int();
|
||||
SetTexture(id, node.attribute("url").value(), node.attribute("urlEx").value());
|
||||
SetTexture(id, node.attribute("url").value(), node.attribute("url2").value());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,7 +478,7 @@ void Grass::SetTexture(int layer, CSZ url, CSZ url2)
|
|||
VERUS_RT_ASSERT(url);
|
||||
_texLoaded[layer].LoadDDS(url);
|
||||
if (layer < 8)
|
||||
SetTexture(layer + 8, url2 ? url2 : url);
|
||||
SetTexture(layer + 8, (url2 && *url2) ? url2 : url);
|
||||
}
|
||||
|
||||
void Grass::SaveTexture(CSZ url)
|
||||
|
|
|
@ -38,6 +38,12 @@ void LightMapBaker::Init(RcDesc desc)
|
|||
case Mode::faces:
|
||||
{
|
||||
_repsPerUpdate = Math::Max<int>(1, Utils::Cast32(_vMap.size()) / 100);
|
||||
std::fill(_vMap.begin(), _vMap.end(), VERUS_COLOR_RGBA(0, 0, 0, 255));
|
||||
}
|
||||
break;
|
||||
case Mode::ambientOcclusion:
|
||||
{
|
||||
std::fill(_vMap.begin(), _vMap.end(), VERUS_COLOR_RGBA(255, 255, 255, 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -80,6 +86,9 @@ void LightMapBaker::Init(RcDesc desc)
|
|||
_quadtree.BindElement(element);
|
||||
}
|
||||
|
||||
if (Mode::faces == GetMode())
|
||||
return;
|
||||
|
||||
_rph = renderer->CreateRenderPass(
|
||||
{
|
||||
CGI::RP::Attachment("Color", CGI::Format::floatR32).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
|
||||
|
@ -232,14 +241,25 @@ void LightMapBaker::Update()
|
|||
const BYTE value8 = Convert::UnormToUint8(Math::Clamp<float>(value * _normalizationFactor, 0, 1));
|
||||
|
||||
BYTE* pDst = reinterpret_cast<BYTE*>(_vQueued[ringBufferIndex][i]._pDst);
|
||||
VERUS_FOR(j, 3)
|
||||
pDst[j] = Math::Max(pDst[j], value8);
|
||||
pDst[3] = 0xFF;
|
||||
if (pDst[3]) // Already has some data?
|
||||
{
|
||||
VERUS_FOR(j, 3)
|
||||
pDst[j] = Math::Max(pDst[j], value8);
|
||||
}
|
||||
else // Empty?
|
||||
{
|
||||
VERUS_FOR(j, 3)
|
||||
pDst[j] = value8;
|
||||
pDst[3] = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear queued:
|
||||
memset(_vQueued[ringBufferIndex].data(), 0, sizeof(Queued) * s_batchSize);
|
||||
queuedCount = 0;
|
||||
if (!_vQueued[ringBufferIndex].empty())
|
||||
{
|
||||
memset(_vQueued[ringBufferIndex].data(), 0, sizeof(Queued) * s_batchSize);
|
||||
queuedCount = 0;
|
||||
}
|
||||
|
||||
if (_currentI >= _desc._texHeight)
|
||||
{
|
||||
|
@ -254,7 +274,8 @@ void LightMapBaker::Update()
|
|||
}
|
||||
if (finish)
|
||||
{
|
||||
ComputeEdgePadding();
|
||||
if (Mode::faces != GetMode())
|
||||
ComputeEdgePadding();
|
||||
Save();
|
||||
_desc._mode = Mode::idle;
|
||||
}
|
||||
|
@ -304,7 +325,7 @@ void LightMapBaker::Update()
|
|||
|
||||
void LightMapBaker::Draw()
|
||||
{
|
||||
if (!IsInitialized() || !IsBaking())
|
||||
if (!IsInitialized() || !IsBaking() || Mode::faces == GetMode())
|
||||
return;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -313,6 +334,10 @@ void LightMapBaker::Draw()
|
|||
auto cb = renderer.GetCommandBuffer();
|
||||
auto shader = renderer.GetShaderQuad();
|
||||
|
||||
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
renderer.ResetQuadMultiplexer();
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_QUAD]);
|
||||
shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(shader, 0);
|
||||
|
@ -351,6 +376,11 @@ void LightMapBaker::DrawHemicubeMask()
|
|||
auto shader = renderer.GetShaderQuad();
|
||||
|
||||
const float side = static_cast<float>(_desc._texLumelSide);
|
||||
|
||||
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
renderer.ResetQuadMultiplexer();
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_HEMICUBE_MASK]);
|
||||
cb->SetViewport({ Vector4(0, 0, side, side) });
|
||||
shader->BeginBindDescriptors();
|
||||
|
@ -464,6 +494,7 @@ Continue LightMapBaker::Quadtree_ProcessNode(void* pToken, void* pUser)
|
|||
RQueued queued = _vQueued[ringBufferIndex][queuedCount];
|
||||
queued._pos = pos;
|
||||
queued._nrm = glm::normalize(nrm);
|
||||
queued._pos += Vector3(nrm) * _desc._bias;
|
||||
queued._pDst = &_vMap[index];
|
||||
|
||||
_currentLayer++;
|
||||
|
@ -477,50 +508,12 @@ Continue LightMapBaker::Quadtree_ProcessNode(void* pToken, void* pUser)
|
|||
return Continue::yes;
|
||||
}
|
||||
|
||||
void LightMapBaker::ComputeEdgePadding(int radius)
|
||||
void LightMapBaker::ComputeEdgePadding()
|
||||
{
|
||||
const int radiusSq = radius * radius;
|
||||
VERUS_P_FOR(i, _desc._texHeight)
|
||||
{
|
||||
const int offset = i * _desc._texWidth;
|
||||
VERUS_FOR(j, _desc._texWidth)
|
||||
{
|
||||
BYTE* pOriginChannels = reinterpret_cast<BYTE*>(&_vMap[offset + j]);
|
||||
if (pOriginChannels[3])
|
||||
continue;
|
||||
|
||||
int minRadiusSq = INT_MAX;
|
||||
BYTE color[4] = {};
|
||||
for (int di = -radius; di <= radius; ++di)
|
||||
{
|
||||
const int ki = i + di;
|
||||
if (ki < 0 || ki >= _desc._texHeight)
|
||||
continue;
|
||||
for (int dj = -radius; dj <= radius; ++dj)
|
||||
{
|
||||
const int kj = j + dj;
|
||||
if (kj < 0 || kj >= _desc._texWidth)
|
||||
continue;
|
||||
if (!di && !dj)
|
||||
continue;
|
||||
const int lenSq = di * di + dj * dj;
|
||||
if (lenSq > radiusSq)
|
||||
continue;
|
||||
BYTE* pKernelChannels = reinterpret_cast<BYTE*>(&_vMap[ki * _desc._texWidth + kj]);
|
||||
if (!pKernelChannels[3])
|
||||
continue;
|
||||
if (lenSq < minRadiusSq)
|
||||
{
|
||||
minRadiusSq = lenSq;
|
||||
memcpy(color, pKernelChannels, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minRadiusSq != INT_MAX)
|
||||
memcpy(pOriginChannels, color, 3);
|
||||
}
|
||||
});
|
||||
Utils::ComputeEdgePadding(
|
||||
reinterpret_cast<BYTE*>(_vMap.data()) + 0, sizeof(UINT32),
|
||||
reinterpret_cast<BYTE*>(_vMap.data()) + 3, sizeof(UINT32),
|
||||
_desc._texWidth, _desc._texHeight);
|
||||
}
|
||||
|
||||
void LightMapBaker::Save()
|
||||
|
@ -528,10 +521,16 @@ void LightMapBaker::Save()
|
|||
IO::FileSystem::SaveImage(_C(_pathname), _vMap.data(), _desc._texWidth, _desc._texHeight, IO::ImageFormat::extension);
|
||||
}
|
||||
|
||||
void LightMapBaker::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
||||
void LightMapBaker::BindPipeline(RcMesh mesh, CGI::CommandBufferPtr cb)
|
||||
{
|
||||
VERUS_RT_ASSERT(pipe >= PIPE_MESH_SIMPLE_BAKE_AO && pipe <= PIPE_MESH_SIMPLE_BAKE_AO_SKINNED);
|
||||
|
||||
static const PIPE pipes[] =
|
||||
{
|
||||
PIPE_MESH_SIMPLE_BAKE_AO,
|
||||
PIPE_MESH_SIMPLE_BAKE_AO_INSTANCED,
|
||||
PIPE_MESH_SIMPLE_BAKE_AO_ROBOTIC,
|
||||
PIPE_MESH_SIMPLE_BAKE_AO_SKINNED
|
||||
};
|
||||
const PIPE pipe = pipes[mesh.GetPipelineIndex()];
|
||||
if (!_pipe[pipe])
|
||||
{
|
||||
static CSZ branches[] =
|
||||
|
@ -541,11 +540,10 @@ void LightMapBaker::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
"#BakeAORobotic",
|
||||
"#BakeAOSkinned"
|
||||
};
|
||||
CGI::PipelineDesc pipeDesc(_desc._pMesh->GetGeometry(), Mesh::GetSimpleShader(), branches[pipe], _rph);
|
||||
pipeDesc._vertexInputBindingsFilter = _desc._pMesh->GetBindingsMask();
|
||||
CGI::PipelineDesc pipeDesc(mesh.GetGeometry(), Mesh::GetSimpleShader(), branches[pipe], _rph);
|
||||
pipeDesc._vertexInputBindingsFilter = mesh.GetBindingsMask();
|
||||
_pipe[pipe].Init(pipeDesc);
|
||||
}
|
||||
|
||||
cb->BindPipeline(_pipe[pipe]);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ namespace verus
|
|||
int _texHeight = 256;
|
||||
int _texLumelSide = 128;
|
||||
float _distance = 2;
|
||||
float _bias = 0.001f;
|
||||
};
|
||||
VERUS_TYPEDEFS(Desc);
|
||||
|
||||
|
@ -147,10 +148,10 @@ namespace verus
|
|||
RcStats GetStats() const { return _stats; }
|
||||
float GetProgress() const { return _stats._progress; }
|
||||
|
||||
void ComputeEdgePadding(int radius = 32);
|
||||
void ComputeEdgePadding();
|
||||
void Save();
|
||||
|
||||
void BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb);
|
||||
void BindPipeline(RcMesh mesh, CGI::CommandBufferPtr cb);
|
||||
void SetViewportFor(CGI::CubeMapFace cubeMapFace, CGI::CommandBufferPtr cb);
|
||||
};
|
||||
VERUS_TYPEDEFS(LightMapBaker);
|
||||
|
|
|
@ -47,57 +47,62 @@ bool Texture::Done()
|
|||
|
||||
void Texture::Update()
|
||||
{
|
||||
if (_streamParts)
|
||||
UpdateStreaming();
|
||||
}
|
||||
|
||||
void Texture::UpdateStreaming()
|
||||
{
|
||||
if (!_streamParts)
|
||||
return;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
// Check if the next huge texture is loaded:
|
||||
const int nextHuge = (_currentHuge + 1) & 0x1;
|
||||
if (_loading && _texHuge[nextHuge] && _texHuge[nextHuge]->IsLoaded())
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
_loading = false;
|
||||
_currentHuge = nextHuge; // Use it.
|
||||
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize + 1;
|
||||
}
|
||||
|
||||
// Check if the next huge texture is loaded:
|
||||
const int nextHuge = (_currentHuge + 1) & 0x1;
|
||||
if (_loading && _texHuge[nextHuge] && _texHuge[nextHuge]->IsLoaded())
|
||||
const bool safeFrame = !_loading && (renderer.GetFrameCount() >= _nextSafeFrame);
|
||||
if (safeFrame)
|
||||
{
|
||||
const int prevHuge = (_currentHuge + 1) & 0x1;
|
||||
if (_texHuge[prevHuge]) // Garbage collection (next huge texture must be empty).
|
||||
_texHuge[prevHuge].Done();
|
||||
|
||||
const int maxPart = _texTiny->GetPart();
|
||||
if (maxPart > 0) // Must have at least two parts: 0 and 1.
|
||||
{
|
||||
_loading = false;
|
||||
_currentHuge = nextHuge; // Use it.
|
||||
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize + 1;
|
||||
}
|
||||
const float reqPart = Math::Min<float>(_requestedPart, SHRT_MAX);
|
||||
|
||||
const bool safeFrame = !_loading && (renderer.GetFrameCount() >= _nextSafeFrame);
|
||||
if (safeFrame)
|
||||
{
|
||||
const int prevHuge = (_currentHuge + 1) & 0x1;
|
||||
if (_texHuge[prevHuge]) // Garbage collection (next huge texture must be empty).
|
||||
_texHuge[prevHuge].Done();
|
||||
const bool hugeReady = (_texHuge[_currentHuge] && _texHuge[_currentHuge]->IsLoaded());
|
||||
const int currentPart = hugeReady ? _texHuge[_currentHuge]->GetPart() : maxPart;
|
||||
int newPart = currentPart;
|
||||
|
||||
const int maxPart = _texTiny->GetPart();
|
||||
if (maxPart > 0) // Must have at least two parts: 0 and 1.
|
||||
if (reqPart < currentPart) // Increase texture?
|
||||
newPart = static_cast<int>(reqPart);
|
||||
if (reqPart > currentPart + 1.5f) // Decrease texture?
|
||||
newPart = static_cast<int>(reqPart);
|
||||
|
||||
newPart = Math::Clamp(newPart, 0, maxPart);
|
||||
|
||||
if (_texHuge[_currentHuge] && (newPart == maxPart)) // Unload huge texture, use tiny?
|
||||
{
|
||||
const float reqPart = Math::Min<float>(_requestedPart, SHRT_MAX);
|
||||
_currentHuge = (_currentHuge + 1) & 0x1; // Go to empty huge texture.
|
||||
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
|
||||
}
|
||||
else if (newPart != currentPart) // Change part?
|
||||
{
|
||||
_loading = true;
|
||||
const int nextHuge = (_currentHuge + 1) & 0x1;
|
||||
|
||||
const bool hugeReady = (_texHuge[_currentHuge] && _texHuge[_currentHuge]->IsLoaded());
|
||||
const int currentPart = hugeReady ? _texHuge[_currentHuge]->GetPart() : maxPart;
|
||||
int newPart = currentPart;
|
||||
|
||||
if (reqPart < currentPart) // Increase texture?
|
||||
newPart = static_cast<int>(reqPart);
|
||||
if (reqPart > currentPart + 1.5f) // Decrease texture?
|
||||
newPart = static_cast<int>(reqPart);
|
||||
|
||||
newPart = Math::Clamp(newPart, 0, maxPart);
|
||||
|
||||
if (_texHuge[_currentHuge] && (newPart == maxPart)) // Unload huge texture, use tiny?
|
||||
{
|
||||
_currentHuge = (_currentHuge + 1) & 0x1; // Go to empty huge texture.
|
||||
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
|
||||
}
|
||||
else if (newPart != currentPart) // Change part?
|
||||
{
|
||||
_loading = true;
|
||||
const int nextHuge = (_currentHuge + 1) & 0x1;
|
||||
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._url = _C(_texTiny->GetName());
|
||||
texDesc._texturePart = newPart;
|
||||
_texHuge[nextHuge].Init(texDesc);
|
||||
}
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._url = _C(_texTiny->GetName());
|
||||
texDesc._texturePart = newPart;
|
||||
_texHuge[nextHuge].Init(texDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,8 +180,8 @@ void Material::Pick::FromString(CSZ sz)
|
|||
String Material::Pick::ToString()
|
||||
{
|
||||
const UINT32 color = Convert::ColorFloatToInt32(glm::value_ptr(static_cast<glm::vec4&>(*this)));
|
||||
char txt[16];
|
||||
sprintf_s(txt, "%02X%02X%02X%02X",
|
||||
char txt[20];
|
||||
sprintf_s(txt, "0x%02X%02X%02X%02X",
|
||||
(color >> 0) & 0xFF,
|
||||
(color >> 8) & 0xFF,
|
||||
(color >> 16) & 0xFF,
|
||||
|
@ -184,61 +189,6 @@ String Material::Pick::ToString()
|
|||
return txt;
|
||||
}
|
||||
|
||||
// Material::PickRound:
|
||||
|
||||
Material::PickRound::PickRound()
|
||||
{
|
||||
}
|
||||
|
||||
Material::PickRound::PickRound(const glm::vec4& v) : glm::vec4(v)
|
||||
{
|
||||
}
|
||||
|
||||
void Material::PickRound::SetUV(float u, float v)
|
||||
{
|
||||
x = u;
|
||||
y = v;
|
||||
}
|
||||
|
||||
void Material::PickRound::SetRadius(float r)
|
||||
{
|
||||
z = r;
|
||||
}
|
||||
|
||||
void Material::PickRound::SetAlpha(float x)
|
||||
{
|
||||
w = x;
|
||||
}
|
||||
|
||||
glm::vec4 Material::PickRound::ToPixels() const
|
||||
{
|
||||
if (w >= 2)
|
||||
{
|
||||
const float r = sqrt(z);
|
||||
return glm::vec4(
|
||||
glm::round(x * w),
|
||||
glm::round(y * w),
|
||||
glm::round(r * w),
|
||||
w);
|
||||
}
|
||||
else
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Material::PickRound::FromPixels(const glm::vec4& pix)
|
||||
{
|
||||
if (w >= 2)
|
||||
{
|
||||
glm::vec4::operator=(glm::vec4(
|
||||
pix.x / pix.w,
|
||||
pix.y / pix.w,
|
||||
pow(pix.z / pix.w, 2),
|
||||
w));
|
||||
}
|
||||
else
|
||||
glm::vec4::operator=(pix);
|
||||
}
|
||||
|
||||
// Material:
|
||||
|
||||
Material::Material()
|
||||
|
@ -264,9 +214,9 @@ void Material::Init(RcDesc desc)
|
|||
{
|
||||
VERUS_RT_ASSERT(
|
||||
Str::EndsWith(_C(_name), ".x3d") ||
|
||||
Str::EndsWith(_C(_name), ".xmt"));
|
||||
Str::EndsWith(_C(_name), ".vml"));
|
||||
String url(desc._name);
|
||||
Str::ReplaceExtension(url, ".xmt");
|
||||
Str::ReplaceExtension(url, ".vml");
|
||||
_name = url;
|
||||
|
||||
Vector<BYTE> vData;
|
||||
|
@ -288,8 +238,9 @@ bool Material::Done()
|
|||
Mesh::GetShader()->FreeDescriptorSet(_cshTemp);
|
||||
Mesh::GetShader()->FreeDescriptorSet(_cshTiny);
|
||||
Mesh::GetShader()->FreeDescriptorSet(_csh);
|
||||
_texAlbedo.Done();
|
||||
_texNormal.Done();
|
||||
_texX.Done();
|
||||
_texN.Done();
|
||||
_texA.Done();
|
||||
VERUS_DONE(Material);
|
||||
return true;
|
||||
}
|
||||
|
@ -301,11 +252,14 @@ bool Material::operator<(RcMaterial that) const
|
|||
if (_blending != that._blending)
|
||||
return _blending < that._blending;
|
||||
|
||||
if (_texAlbedo != that._texAlbedo)
|
||||
return _texAlbedo < that._texAlbedo;
|
||||
if (_texA != that._texA)
|
||||
return _texA < that._texA;
|
||||
|
||||
if (_texNormal != that._texNormal)
|
||||
return _texNormal < that._texNormal;
|
||||
if (_texN != that._texN)
|
||||
return _texN < that._texN;
|
||||
|
||||
if (_texX != that._texX)
|
||||
return _texX < that._texX;
|
||||
|
||||
return _name < that._name;
|
||||
}
|
||||
|
@ -321,12 +275,14 @@ void Material::Update()
|
|||
|
||||
// Request BindDescriptorSetTextures call by clearing _csh:
|
||||
const bool partChanged =
|
||||
_texAlbedo && (_albedoPart != _texAlbedo->GetPart()) ||
|
||||
_texNormal && (_normalPart != _texNormal->GetPart());
|
||||
_texA && (_aPart != _texA->GetPart()) ||
|
||||
_texN && (_nPart != _texN->GetPart()) ||
|
||||
_texX && (_xPart != _texX->GetPart());
|
||||
if (partChanged && !_cshTemp.IsSet())
|
||||
{
|
||||
_albedoPart = _texAlbedo->GetPart();
|
||||
_normalPart = _texNormal->GetPart();
|
||||
_aPart = _texA->GetPart();
|
||||
_nPart = _texN->GetPart();
|
||||
_xPart = _texX->GetPart();
|
||||
_cshTemp = _csh;
|
||||
_csh = CGI::CSHandle();
|
||||
_cshFreeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
|
||||
|
@ -339,23 +295,37 @@ void Material::Update()
|
|||
|
||||
bool Material::IsLoaded() const
|
||||
{
|
||||
if (!_texAlbedo || !_texNormal)
|
||||
if (!_texA || !_texN || !_texX)
|
||||
return false;
|
||||
return
|
||||
_texAlbedo->GetTex()->IsLoaded() &&
|
||||
_texNormal->GetTex()->IsLoaded();
|
||||
_texA->GetTex()->IsLoaded() &&
|
||||
_texN->GetTex()->IsLoaded() &&
|
||||
_texX->GetTex()->IsLoaded();
|
||||
}
|
||||
|
||||
void Material::LoadTextures(bool streamParts)
|
||||
{
|
||||
VERUS_QREF_SM;
|
||||
|
||||
_texAlbedo.Done();
|
||||
_texNormal.Done();
|
||||
_texAlbedo.Init(_dict.Find("texAlbedo"), streamParts);
|
||||
_texNormal.Init(_dict.Find("texNormal"), streamParts);
|
||||
_texEnableAlbedo.w = 1;
|
||||
_texEnableNormal.w = 1;
|
||||
_texX.Done();
|
||||
_texN.Done();
|
||||
_texA.Done();
|
||||
|
||||
String newUrl;
|
||||
auto ExpandPath = [this, &newUrl](CSZ url)
|
||||
{
|
||||
if (!strncmp(url, "./", 2))
|
||||
{
|
||||
newUrl = Str::GetPath(_C(_name));
|
||||
newUrl += url + 1;
|
||||
return _C(newUrl);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
_texA.Init(ExpandPath(_dict.Find("texA")), streamParts);
|
||||
_texN.Init(ExpandPath(_dict.Find("texN")), streamParts);
|
||||
_texX.Init(ExpandPath(_dict.Find("texX")), streamParts);
|
||||
}
|
||||
|
||||
String Material::ToString(bool cleanDict)
|
||||
|
@ -367,32 +337,30 @@ String Material::ToString(bool cleanDict)
|
|||
|
||||
CSZ empty = "";
|
||||
|
||||
CGI::PBaseTexture pTexAlbedo = _texAlbedo->GetTex().Get();
|
||||
CGI::PBaseTexture pTexNormal = _texNormal->GetTex().Get();
|
||||
CGI::PBaseTexture pTexA = _texA->GetTex().Get();
|
||||
CGI::PBaseTexture pTexN = _texN->GetTex().Get();
|
||||
CGI::PBaseTexture pTexX = _texX->GetTex().Get();
|
||||
|
||||
_dict.Insert("alphaSwitch", /**/_C(Str::ToString(_alphaSwitch)));
|
||||
_dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir)));
|
||||
_dict.Insert("detail", /**/_C(Str::ToString(_detail)));
|
||||
_dict.Insert("emission", /**/_C(Str::ToString(_emission)));
|
||||
_dict.Insert("emissionPick", /**/_C(_emissionPick.ToString()));
|
||||
_dict.Insert("eyePick", /**/_C(Str::ToString(_eyePick.ToPixels())));
|
||||
_dict.Insert("gloss", /**/_C(Str::ToString(_gloss)));
|
||||
_dict.Insert("glossPick", /**/_C(_glossPick.ToString()));
|
||||
_dict.Insert("glossScaleBias", /**/_C(Str::ToString(_glossScaleBias)));
|
||||
_dict.Insert("hairDesat", /**/_C(Str::ToString(_hairDesat)));
|
||||
_dict.Insert("hairPick", /**/_C(_hairPick.ToString()));
|
||||
_dict.Insert("lamScaleBias", /**/_C(Str::ToString(_lamScaleBias)));
|
||||
_dict.Insert("lightPass", /**/_C(Str::ToString(_lightPass)));
|
||||
_dict.Insert("metalPick", /**/_C(_metalPick.ToString()));
|
||||
_dict.Insert("skinPick", /**/_C(_skinPick.ToString()));
|
||||
_dict.Insert("specScaleBias", /**/_C(Str::ToString(_specScaleBias)));
|
||||
_dict.Insert("tc0ScaleBias", /**/_C(Str::ToString(_tc0ScaleBias)));
|
||||
_dict.Insert("texAlbedo", /**/pTexAlbedo ? _C(pTexAlbedo->GetName()) : empty);
|
||||
_dict.Insert("texEnableAlbedo", /**/_C(Str::ToColorString(_texEnableAlbedo)));
|
||||
_dict.Insert("texNormal", /**/pTexNormal ? _C(pTexNormal->GetName()) : empty);
|
||||
_dict.Insert("texEnableNormal", /**/_C(Str::ToColorString(_texEnableNormal, false)));
|
||||
_dict.Insert("userColor", /**/_C(Str::ToColorString(_userColor)));
|
||||
_dict.Insert("userPick", /**/_C(_userPick.ToString()));
|
||||
_dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir, true)));
|
||||
_dict.Insert("detail", /**/_C(Str::ToString(_detail)));
|
||||
_dict.Insert("emission", /**/_C(Str::ToString(_emission)));
|
||||
_dict.Insert("nmContrast", /**/_C(Str::ToString(_nmContrast)));
|
||||
_dict.Insert("roughDiffuse", /**/_C(Str::ToString(_roughDiffuse)));
|
||||
_dict.Insert("solidA", /**/_C(Str::ToColorString(_solidA, true, true)));
|
||||
_dict.Insert("solidN", /**/_C(Str::ToColorString(_solidN, false, true)));
|
||||
_dict.Insert("solidX", /**/_C(Str::ToColorString(_solidX, false, true)));
|
||||
_dict.Insert("sssHue", /**/_C(Str::ToString(_sssHue)));
|
||||
_dict.Insert("sssPick", /**/_C(_sssPick.ToString()));
|
||||
_dict.Insert("tc0ScaleBias", /**/_C(Str::ToString(_tc0ScaleBias, true)));
|
||||
_dict.Insert("texA", /**/pTexA ? _C(pTexA->GetName()) : empty);
|
||||
_dict.Insert("texN", /**/pTexN ? _C(pTexN->GetName()) : empty);
|
||||
_dict.Insert("texX", /**/pTexX ? _C(pTexX->GetName()) : empty);
|
||||
_dict.Insert("userColor", /**/_C(Str::ToColorString(_userColor)));
|
||||
_dict.Insert("userPick", /**/_C(_userPick.ToString()));
|
||||
_dict.Insert("xAnisoSpecScaleBias", /**/_C(Str::ToString(_xAnisoSpecScaleBias, true)));
|
||||
_dict.Insert("xMetallicScaleBias", /**/_C(Str::ToString(_xMetallicScaleBias, true)));
|
||||
_dict.Insert("xRoughnessScaleBias", /**/_C(Str::ToString(_xRoughnessScaleBias, true)));
|
||||
_dict.Insert("xWrapDiffuseScaleBias", /**/_C(Str::ToString(_xWrapDiffuseScaleBias, true)));
|
||||
|
||||
return _dict.ToString();
|
||||
}
|
||||
|
@ -401,29 +369,23 @@ void Material::FromString(CSZ txt)
|
|||
{
|
||||
_dict.FromString(txt);
|
||||
|
||||
_alphaSwitch = Str::FromStringVec2(_dict.Find("alphaSwitch", "1 1"));
|
||||
_anisoSpecDir = Str::FromStringVec2(_dict.Find("anisoSpecDir", "0 1"));
|
||||
_detail = _dict.FindFloat("detail", 0);
|
||||
_emission = _dict.FindFloat("emission", 0);
|
||||
_emissionPick.FromString(_dict.Find("emissionPick", "00000000"));
|
||||
_eyePick = Str::FromStringVec4(_dict.Find("eyePick", "0 0 0 0"));
|
||||
_gloss = _dict.FindFloat("gloss", 10);
|
||||
_glossPick.FromString(_dict.Find("glossPick", "00000000"));
|
||||
_glossScaleBias = Str::FromStringVec2(_dict.Find("glossScaleBias", "1 0"));
|
||||
_hairDesat = _dict.FindFloat("hairDesat", 0);
|
||||
_hairPick.FromString(_dict.Find("hairPick", "00000000"));
|
||||
_lamScaleBias = Str::FromStringVec2(_dict.Find("lamScaleBias", "1 0"));
|
||||
_lightPass = _dict.FindFloat("lightPass", 1);
|
||||
_metalPick.FromString(_dict.Find("metalPick", "00000000"));
|
||||
_skinPick.FromString(_dict.Find("skinPick", "00000000"));
|
||||
_specScaleBias = Str::FromStringVec2(_dict.Find("specScaleBias", "1 0"));
|
||||
_nmContrast = _dict.FindFloat("nmContrast", -2);
|
||||
_roughDiffuse = _dict.FindFloat("roughDiffuse", 0);
|
||||
_solidA = Str::FromColorString(_dict.Find("solidA", "80808000"));
|
||||
_solidN = Str::FromColorString(_dict.Find("solidN", "8080FF00"), false);
|
||||
_solidX = Str::FromColorString(_dict.Find("solidX", "FF808000"), false);
|
||||
_sssHue = _dict.FindFloat("sssHue", 0);
|
||||
_sssPick.FromString(_dict.Find("sssPick", "00000000"));
|
||||
_tc0ScaleBias = Str::FromStringVec4(_dict.Find("tc0ScaleBias", "1 1 0 0"));
|
||||
_texEnableAlbedo = Str::FromColorString(_dict.Find("texEnableAlbedo", "80808000"));
|
||||
_texEnableNormal = Str::FromColorString(_dict.Find("texEnableNormal", "8080FF00"), false);
|
||||
_userColor = Str::FromColorString(_dict.Find("userColor", "00000000"));
|
||||
_userPick.FromString(_dict.Find("userPick", "0 0 0 0"));
|
||||
|
||||
_eyePick.FromPixels(_eyePick);
|
||||
_userPick.FromString(_dict.Find("userPick", "00000000"));
|
||||
_xAnisoSpecScaleBias = Str::FromStringVec2(_dict.Find("xAnisoSpecScaleBias", "1 0"));
|
||||
_xMetallicScaleBias = Str::FromStringVec2(_dict.Find("xMetallicScaleBias", "1 0"));
|
||||
_xRoughnessScaleBias = Str::FromStringVec2(_dict.Find("xRoughnessScaleBias", "1 0"));
|
||||
_xWrapDiffuseScaleBias = Str::FromStringVec2(_dict.Find("xWrapDiffuseScaleBias", "1 0"));
|
||||
}
|
||||
|
||||
CGI::CSHandle Material::GetComplexSetHandle() const
|
||||
|
@ -445,44 +407,65 @@ void Material::BindDescriptorSetTextures()
|
|||
VERUS_QREF_MM;
|
||||
VERUS_QREF_ATMO;
|
||||
if (!_cshTiny.IsSet())
|
||||
_cshTiny = Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTinyTex(), _texNormal->GetTinyTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
|
||||
{
|
||||
_cshTiny = Mesh::GetShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_texA->GetTinyTex(),
|
||||
_texN->GetTinyTex(),
|
||||
_texX->GetTinyTex(),
|
||||
mm.GetDetailTexture(),
|
||||
mm.GetDetailNTexture(),
|
||||
mm.GetStrassTexture()
|
||||
});
|
||||
}
|
||||
if (!_cshSimple.IsSet())
|
||||
_cshSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTinyTex(), atmo.GetShadowMapBaker().GetTexture() });
|
||||
_csh = Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
|
||||
{
|
||||
_cshSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_texA->GetTinyTex(),
|
||||
_texX->GetTinyTex(),
|
||||
atmo.GetShadowMapBaker().GetTexture()
|
||||
});
|
||||
}
|
||||
_csh = Mesh::GetShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_texA->GetTex(),
|
||||
_texN->GetTex(),
|
||||
_texX->GetTex(),
|
||||
mm.GetDetailTexture(),
|
||||
mm.GetDetailNTexture(),
|
||||
mm.GetStrassTexture()
|
||||
});
|
||||
}
|
||||
|
||||
bool Material::UpdateMeshUniformBuffer(float motionBlur)
|
||||
bool Material::UpdateMeshUniformBuffer(float motionBlur, bool resolveDitheringMaskEnabled)
|
||||
{
|
||||
Mesh::UB_PerMaterialFS& ub = Mesh::GetUbPerMaterialFS();
|
||||
Mesh::UB_PerMaterialFS ubPrev;
|
||||
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
|
||||
|
||||
ub._alphaSwitch_anisoSpecDir = float4(_alphaSwitch, _anisoSpecDir);
|
||||
ub._detail_emission_gloss_hairDesat.x = _detail;
|
||||
ub._detail_emission_gloss_hairDesat.y = _emission;
|
||||
ub._detail_emission_gloss_hairDesat.z = _gloss;
|
||||
ub._detail_emission_gloss_hairDesat.w = _hairDesat;
|
||||
ub._anisoSpecDir_detail_emission = float4(_anisoSpecDir, _detail, _emission);
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.x = motionBlur;
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.y = _nmContrast;
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.z = _roughDiffuse + (resolveDitheringMaskEnabled ? 0.f : 1.f);
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.w = _sssHue;
|
||||
ub._detailScale_strassScale = float4(1, 1, 1, 1);
|
||||
ub._emissionPick = _emissionPick;
|
||||
ub._eyePick = _eyePick;
|
||||
ub._glossPick = _glossPick;
|
||||
ub._glossScaleBias_specScaleBias = float4(_glossScaleBias, _specScaleBias);
|
||||
ub._hairPick = _hairPick;
|
||||
ub._lamScaleBias_lightPass_motionBlur = float4(_lamScaleBias, _lightPass, motionBlur);
|
||||
ub._metalPick = _metalPick;
|
||||
ub._skinPick = _skinPick;
|
||||
ub._solidA = _solidA;
|
||||
ub._solidN = _solidN;
|
||||
ub._solidX = _solidX;
|
||||
ub._sssPick = _sssPick;
|
||||
ub._tc0ScaleBias = _tc0ScaleBias;
|
||||
ub._texEnableAlbedo = _texEnableAlbedo;
|
||||
ub._texEnableNormal = _texEnableNormal;
|
||||
ub._userColor = _userColor;
|
||||
ub._userPick = _userPick;
|
||||
if (_texAlbedo)
|
||||
ub._xAnisoSpecScaleBias_xMetallicScaleBias = float4(_xAnisoSpecScaleBias, _xMetallicScaleBias);
|
||||
ub._xRoughnessScaleBias_xWrapDiffuseScaleBias = float4(_xRoughnessScaleBias, _xWrapDiffuseScaleBias);
|
||||
if (_texA)
|
||||
{
|
||||
ub._detailScale_strassScale = float4(
|
||||
_texAlbedo->GetTex()->GetSize().getX() / 256 * 4,
|
||||
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4,
|
||||
_texAlbedo->GetTex()->GetSize().getX() / 256 * 8,
|
||||
_texAlbedo->GetTex()->GetSize().getY() / 256 * 8);
|
||||
_texA->GetTex()->GetSize().getX() / 256 * 4,
|
||||
_texA->GetTex()->GetSize().getY() / 256 * 4,
|
||||
_texA->GetTex()->GetSize().getX() / 256 * 8,
|
||||
_texA->GetTex()->GetSize().getY() / 256 * 8);
|
||||
}
|
||||
|
||||
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
|
||||
|
@ -492,43 +475,40 @@ bool Material::UpdateMeshUniformBufferSimple()
|
|||
{
|
||||
Mesh::UB_SimplePerMaterialFS& ub = Mesh::GetUbSimplePerMaterialFS();
|
||||
Mesh::UB_SimplePerMaterialFS ubPrev;
|
||||
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
|
||||
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_SimplePerMaterialFS));
|
||||
|
||||
ub._alphaSwitch_anisoSpecDir = float4(_alphaSwitch, _anisoSpecDir);
|
||||
ub._detail_emission_gloss_hairDesat.x = _detail;
|
||||
ub._detail_emission_gloss_hairDesat.y = _emission;
|
||||
ub._detail_emission_gloss_hairDesat.z = _gloss;
|
||||
ub._detail_emission_gloss_hairDesat.w = _hairDesat;
|
||||
ub._anisoSpecDir_detail_emission = float4(_anisoSpecDir, _detail, _emission);
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.x = 0;
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.y = _nmContrast;
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.z = _roughDiffuse;
|
||||
ub._motionBlur_nmContrast_roughDiffuse_sssHue.w = _sssHue;
|
||||
ub._detailScale_strassScale = float4(1, 1, 1, 1);
|
||||
ub._emissionPick = _emissionPick;
|
||||
ub._eyePick = _eyePick;
|
||||
ub._glossPick = _glossPick;
|
||||
ub._glossScaleBias_specScaleBias = float4(_glossScaleBias, _specScaleBias);
|
||||
ub._hairPick = _hairPick;
|
||||
ub._lamScaleBias_lightPass_motionBlur = float4(_lamScaleBias, _lightPass, 0);
|
||||
ub._metalPick = _metalPick;
|
||||
ub._skinPick = _skinPick;
|
||||
ub._solidA = _solidA;
|
||||
ub._solidN = _solidN;
|
||||
ub._solidX = _solidX;
|
||||
ub._sssPick = _sssPick;
|
||||
ub._tc0ScaleBias = _tc0ScaleBias;
|
||||
ub._texEnableAlbedo = _texEnableAlbedo;
|
||||
ub._texEnableNormal = _texEnableNormal;
|
||||
ub._userColor = _userColor;
|
||||
ub._userPick = _userPick;
|
||||
if (_texAlbedo)
|
||||
ub._xAnisoSpecScaleBias_xMetallicScaleBias = float4(_xAnisoSpecScaleBias, _xMetallicScaleBias);
|
||||
ub._xRoughnessScaleBias_xWrapDiffuseScaleBias = float4(_xRoughnessScaleBias, _xWrapDiffuseScaleBias);
|
||||
if (_texA)
|
||||
{
|
||||
ub._detailScale_strassScale = float4(
|
||||
_texAlbedo->GetTex()->GetSize().getX() / 256 * 4,
|
||||
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4,
|
||||
_texAlbedo->GetTex()->GetSize().getX() / 256 * 8,
|
||||
_texAlbedo->GetTex()->GetSize().getY() / 256 * 8);
|
||||
_texA->GetTex()->GetSize().getX() / 256 * 4,
|
||||
_texA->GetTex()->GetSize().getY() / 256 * 4,
|
||||
_texA->GetTex()->GetSize().getX() / 256 * 8,
|
||||
_texA->GetTex()->GetSize().getY() / 256 * 8);
|
||||
}
|
||||
|
||||
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
|
||||
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_SimplePerMaterialFS));
|
||||
}
|
||||
|
||||
void Material::IncludePart(float part)
|
||||
{
|
||||
_texAlbedo->IncludePart(part);
|
||||
_texNormal->IncludePart(part);
|
||||
_texA->IncludePart(part);
|
||||
_texN->IncludePart(part);
|
||||
_texX->IncludePart(part);
|
||||
}
|
||||
|
||||
// MaterialPtr:
|
||||
|
@ -568,27 +548,52 @@ void MaterialManager::Init()
|
|||
|
||||
void MaterialManager::InitCmd()
|
||||
{
|
||||
_texDefaultAlbedo.Init("[Textures]:Default.dds", false, true);
|
||||
_texDefaultNormal.Init("[Textures]:Default.NM.dds", false, true);
|
||||
_texDetail.Init("[Textures]:Detail.FX.dds", false, true);
|
||||
_texStrass.Init("[Textures]:Strass.dds", false, true);
|
||||
_texDefaultA.Init("[Textures]:Default.dds", false, true);
|
||||
_texDefaultN.Init("[Textures]:Default.N.dds", false, true);
|
||||
_texDefaultX.Init("[Textures]:Default.X.dds", false, true);
|
||||
_texDetail.Init("[Textures]:Detail.X.dds", false, true);
|
||||
_texDetailN.Init("[Textures]:Detail.N.dds", false, true);
|
||||
_texStrass.Init("[Textures]:Strass.X.dds", false, true);
|
||||
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._clearValue = Vector4(1);
|
||||
texDesc._name = "MaterialManager.DummyShadow";
|
||||
texDesc._format = CGI::Format::unormD24uintS8;
|
||||
texDesc._width = 16;
|
||||
texDesc._height = 16;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::depthSampledR;
|
||||
_texDummyShadow.Init(texDesc);
|
||||
|
||||
_cshDefault = Mesh::GetShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_texDefaultAlbedo->GetTex(),
|
||||
_texDefaultNormal->GetTex(),
|
||||
_texDefaultA->GetTex(),
|
||||
_texDefaultN->GetTex(),
|
||||
_texDefaultX->GetTex(),
|
||||
_texDetail->GetTex(),
|
||||
_texDetailN->GetTex(),
|
||||
_texStrass->GetTex()
|
||||
});
|
||||
_cshDefaultSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_texDefaultA->GetTinyTex(),
|
||||
_texDefaultX->GetTinyTex(),
|
||||
_texDummyShadow
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialManager::Done()
|
||||
{
|
||||
Mesh::GetShader()->FreeDescriptorSet(_cshDefault);
|
||||
if (Mesh::GetSimpleShader())
|
||||
Mesh::GetSimpleShader()->FreeDescriptorSet(_cshDefaultSimple);
|
||||
if (Mesh::GetShader())
|
||||
Mesh::GetShader()->FreeDescriptorSet(_cshDefault);
|
||||
_texDummyShadow.Done();
|
||||
_texStrass.Done();
|
||||
_texDetailN.Done();
|
||||
_texDetail.Done();
|
||||
_texDefaultNormal.Done();
|
||||
_texDefaultAlbedo.Done();
|
||||
_texDefaultX.Done();
|
||||
_texDefaultN.Done();
|
||||
_texDefaultA.Done();
|
||||
DeleteAll();
|
||||
VERUS_DONE(MaterialManager);
|
||||
}
|
||||
|
|
|
@ -21,11 +21,13 @@ namespace verus
|
|||
Texture();
|
||||
~Texture();
|
||||
|
||||
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
|
||||
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDesc = nullptr);
|
||||
bool Done();
|
||||
|
||||
void AddRef() { _refCount++; }
|
||||
|
||||
void Update();
|
||||
void UpdateStreaming();
|
||||
|
||||
CGI::TexturePtr GetTex() const;
|
||||
CGI::TexturePtr GetTinyTex() const;
|
||||
|
@ -40,7 +42,7 @@ namespace verus
|
|||
class TexturePtr : public Ptr<Texture>
|
||||
{
|
||||
public:
|
||||
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
|
||||
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDesc = nullptr);
|
||||
};
|
||||
VERUS_TYPEDEFS(TexturePtr);
|
||||
|
||||
|
@ -84,53 +86,37 @@ namespace verus
|
|||
String ToString();
|
||||
};
|
||||
|
||||
class PickRound : public glm::vec4
|
||||
{
|
||||
public:
|
||||
PickRound();
|
||||
PickRound(const glm::vec4& v);
|
||||
void SetUV(float u, float v);
|
||||
void SetRadius(float r);
|
||||
void SetAlpha(float x);
|
||||
glm::vec4 ToPixels() const;
|
||||
void FromPixels(const glm::vec4& pix);
|
||||
};
|
||||
|
||||
INT64 _cshFreeFrame = -1;
|
||||
String _name;
|
||||
IO::Dictionary _dict;
|
||||
glm::vec2 _alphaSwitch = glm::vec2(1, 1);
|
||||
glm::vec2 _anisoSpecDir = glm::vec2(0, 1);
|
||||
float _detail = 0;
|
||||
float _emission = 0;
|
||||
Pick _emissionPick;
|
||||
PickRound _eyePick;
|
||||
float _gloss = 10;
|
||||
Pick _glossPick;
|
||||
glm::vec2 _glossScaleBias = glm::vec2(1, 0);
|
||||
float _hairDesat = 0;
|
||||
Pick _hairPick;
|
||||
glm::vec2 _lamScaleBias = glm::vec2(1, 0);
|
||||
float _lightPass = 1;
|
||||
Pick _metalPick;
|
||||
Pick _skinPick;
|
||||
glm::vec2 _specScaleBias = glm::vec2(1, 0);
|
||||
float _nmContrast = -2;
|
||||
float _roughDiffuse = 0;
|
||||
glm::vec4 _solidA = glm::vec4(1, 1, 1, 0);
|
||||
glm::vec4 _solidN = glm::vec4(0.5f, 0.5f, 1, 0);
|
||||
glm::vec4 _solidX = glm::vec4(1, 0.5f, 0.5f, 0);
|
||||
float _sssHue = 0.5f;
|
||||
Pick _sssPick;
|
||||
glm::vec4 _tc0ScaleBias = glm::vec4(1, 1, 0, 0);
|
||||
TexturePwn _texAlbedo;
|
||||
glm::vec4 _texEnableAlbedo = glm::vec4(0.5f, 0.5f, 0.5f, 1);
|
||||
TexturePwn _texNormal;
|
||||
glm::vec4 _texEnableNormal = glm::vec4(0.5f, 0.5f, 1.0f, 1);
|
||||
TexturePwn _texPacked;
|
||||
glm::vec4 _texEnablePacked = glm::vec4(0.5f, 0.5f, 1.0f, 1);
|
||||
glm::vec4 _userColor = glm::vec4(0, 0, 0, 0);
|
||||
TexturePwn _texA;
|
||||
TexturePwn _texN;
|
||||
TexturePwn _texX;
|
||||
glm::vec4 _userColor = glm::vec4(1, 1, 1, 1);
|
||||
Pick _userPick;
|
||||
glm::vec2 _xAnisoSpecScaleBias = glm::vec2(1, 0);
|
||||
glm::vec2 _xMetallicScaleBias = glm::vec2(1, 0);
|
||||
glm::vec2 _xRoughnessScaleBias = glm::vec2(1, 0);
|
||||
glm::vec2 _xWrapDiffuseScaleBias = glm::vec2(1, 0);
|
||||
Blending _blending = Blending::opaque;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshTiny;
|
||||
CGI::CSHandle _cshTemp;
|
||||
CGI::CSHandle _cshSimple;
|
||||
int _albedoPart = -1;
|
||||
int _normalPart = -1;
|
||||
int _aPart = -1;
|
||||
int _nPart = -1;
|
||||
int _xPart = -1;
|
||||
int _refCount = 0;
|
||||
|
||||
Material();
|
||||
|
@ -157,7 +143,7 @@ namespace verus
|
|||
CGI::CSHandle GetComplexSetHandle() const;
|
||||
CGI::CSHandle GetComplexSetHandleSimple() const;
|
||||
void BindDescriptorSetTextures();
|
||||
bool UpdateMeshUniformBuffer(float motionBlur = 1);
|
||||
bool UpdateMeshUniformBuffer(float motionBlur = 1, bool resolveDitheringMaskEnabled = true);
|
||||
bool UpdateMeshUniformBufferSimple();
|
||||
|
||||
void IncludePart(float part);
|
||||
|
@ -183,12 +169,15 @@ namespace verus
|
|||
typedef StoreUnique<String, Material> TStoreMaterials;
|
||||
class MaterialManager : public Singleton<MaterialManager>, public Object, private TStoreTextures, private TStoreMaterials
|
||||
{
|
||||
TexturePwn _texDefaultAlbedo;
|
||||
TexturePwn _texDefaultNormal;
|
||||
TexturePwn _texDefaultPacked;
|
||||
TexturePwn _texDetail;
|
||||
TexturePwn _texStrass;
|
||||
CGI::CSHandle _cshDefault; // For missing, non-mandatory materials.
|
||||
TexturePwn _texDefaultA;
|
||||
TexturePwn _texDefaultN;
|
||||
TexturePwn _texDefaultX;
|
||||
TexturePwn _texDetail;
|
||||
TexturePwn _texDetailN;
|
||||
TexturePwn _texStrass;
|
||||
CGI::TexturePwn _texDummyShadow;
|
||||
CGI::CSHandle _cshDefault; // For missing, non-mandatory materials.
|
||||
CGI::CSHandle _cshDefaultSimple;
|
||||
|
||||
public:
|
||||
MaterialManager();
|
||||
|
@ -201,11 +190,12 @@ namespace verus
|
|||
|
||||
void Update();
|
||||
|
||||
CGI::TexturePtr GetDefaultTexture() { return _texDefaultAlbedo->GetTex(); }
|
||||
CGI::TexturePtr GetDefaultTexture() { return _texDefaultA->GetTex(); }
|
||||
CGI::TexturePtr GetDetailTexture() { return _texDetail->GetTex(); }
|
||||
CGI::TexturePtr GetDetailNTexture() { return _texDetailN->GetTex(); }
|
||||
CGI::TexturePtr GetStrassTexture() { return _texStrass->GetTex(); }
|
||||
|
||||
CGI::CSHandle GetDefaultComplexSetHandle() const { return _cshDefault; }
|
||||
CGI::CSHandle GetDefaultComplexSetHandle(bool simple = false) const { return simple ? _cshDefaultSimple : _cshDefault; }
|
||||
|
||||
// Textures:
|
||||
PTexture InsertTexture(CSZ url);
|
||||
|
|
|
@ -37,10 +37,12 @@ void Mesh::InitStatic()
|
|||
s_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity, {}, CGI::ShaderStageFlags::vs_hs_ds_fs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubPerMaterialFS, sizeof(s_ubPerMaterialFS), settings.GetLimits()._mesh_ubPerMaterialFSCapacity,
|
||||
{
|
||||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::lodBias
|
||||
CGI::Sampler::aniso, // A
|
||||
CGI::Sampler::aniso, // N
|
||||
CGI::Sampler::aniso, // X
|
||||
CGI::Sampler::aniso, // Detail
|
||||
CGI::Sampler::aniso, // DetailN
|
||||
CGI::Sampler::lodBias // Strass
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings.GetLimits()._mesh_ubPerMeshVSCapacity, {}, CGI::ShaderStageFlags::vs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(3, &s_ubSkeletonVS, sizeof(s_ubSkeletonVS), settings.GetLimits()._mesh_ubSkinningVSCapacity, {}, CGI::ShaderStageFlags::vs);
|
||||
|
@ -51,6 +53,7 @@ void Mesh::InitStatic()
|
|||
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(0, &s_ubSimplePerFrame, sizeof(s_ubSimplePerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity);
|
||||
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(1, &s_ubSimplePerMaterialFS, sizeof(s_ubSimplePerMaterialFS), settings.GetLimits()._mesh_ubPerMaterialFSCapacity,
|
||||
{
|
||||
CGI::Sampler::linearMipN,
|
||||
CGI::Sampler::linearMipN,
|
||||
CGI::Sampler::shadow
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
|
@ -118,7 +121,7 @@ void Mesh::Draw(RcDrawDesc drawDesc, CGI::CommandBufferPtr cb)
|
|||
cb->BindDescriptors(shader, 2);
|
||||
|
||||
// Set 3:
|
||||
if (drawDesc._bindSkeleton)
|
||||
if (drawDesc._bindSkeleton && _skeleton.IsInitialized())
|
||||
{
|
||||
UpdateUniformBufferSkeletonVS();
|
||||
cb->BindDescriptors(shader, 3);
|
||||
|
@ -161,7 +164,7 @@ void Mesh::DrawSimple(RcDrawDesc drawDesc, CGI::CommandBufferPtr cb)
|
|||
cb->BindDescriptors(shader, 2);
|
||||
|
||||
// Set 3:
|
||||
if (drawDesc._bindSkeleton)
|
||||
if (drawDesc._bindSkeleton && _skeleton.IsInitialized())
|
||||
{
|
||||
UpdateUniformBufferSimpleSkeletonVS();
|
||||
cb->BindDescriptors(shader, 3);
|
||||
|
@ -253,7 +256,7 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
|
||||
if (pipe >= PIPE_SIMPLE_TEX_ADD)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], renderer.GetDS().GetRenderPassHandle_ExtraCompose());
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], renderer.GetDS().GetRenderPassHandle_ForwardRendering());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
pipeDesc._vertexInputBindingsFilter = _bindingsMask;
|
||||
|
@ -285,6 +288,7 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
|
||||
};
|
||||
|
||||
switch (pipe)
|
||||
|
|
|
@ -40,6 +40,7 @@ void Scatter::Init(int side, int typeCount, PcTypeDesc pTypes, int seed)
|
|||
{
|
||||
type++;
|
||||
maxPermille += pTypes[type]._permille;
|
||||
|
||||
instance._type = pTypes[type]._type;
|
||||
}
|
||||
else
|
||||
|
@ -62,10 +63,10 @@ void Scatter::Init(int side, int typeCount, PcTypeDesc pTypes, int seed)
|
|||
|
||||
VERUS_FOR(i, _side)
|
||||
{
|
||||
const int offset = i * _side;
|
||||
const int rowOffset = i * _side;
|
||||
VERUS_FOR(j, _side)
|
||||
{
|
||||
const int index = offset + j;
|
||||
const int index = rowOffset + j;
|
||||
RInstance instance = _vInstances[index];
|
||||
const float mn = instance._x;
|
||||
const float mx = instance._z;
|
||||
|
|
|
@ -40,10 +40,10 @@ namespace verus
|
|||
public:
|
||||
int _type = 0;
|
||||
int _permille = 0;
|
||||
float _minOffset = 0.2f;
|
||||
float _maxOffset = 0.8f;
|
||||
float _minScale = 0.5f;
|
||||
float _maxScale = 1.5f;
|
||||
float _minOffset = 0.25f;
|
||||
float _maxOffset = 0.75f;
|
||||
float _minScale = 0.8f;
|
||||
float _maxScale = 1.25f;
|
||||
float _minAngle = 0;
|
||||
float _maxAngle = VERUS_2PI;
|
||||
TypeDesc(int type, int permille) : _type(type), _permille(permille) {}
|
||||
|
|
|
@ -97,6 +97,11 @@ void Model::Deserialize(IO::RStream stream, CSZ url)
|
|||
char mat[IO::Stream::s_bufferSize] = {};
|
||||
stream.ReadString(mat);
|
||||
|
||||
// TODO: handle old names, remove later:
|
||||
char* pOldExt = strstr(mat, ".xmt");
|
||||
if (pOldExt)
|
||||
strncpy(pOldExt, ".vml", 4);
|
||||
|
||||
Desc desc;
|
||||
desc._url = url;
|
||||
desc._mat = mat;
|
||||
|
|
|
@ -68,7 +68,7 @@ void Prefab::LoadPrefab(SZ xml)
|
|||
{
|
||||
matFrag = _url;
|
||||
Str::ReplaceFilename(matFrag, mat);
|
||||
matFrag += ".xmt";
|
||||
matFrag += ".vml";
|
||||
}
|
||||
|
||||
Block::Desc desc;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue