2021.1
This commit is contained in:
parent
2cbe3aa503
commit
559a017843
|
@ -128,7 +128,14 @@ void CommandBufferD3D12::EndRenderPass()
|
|||
if (_vAttachmentStates[index] != attachment._finalState)
|
||||
{
|
||||
const auto& resources = _pFramebuffer->_vResources[index];
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState, 0);
|
||||
UINT subresource = 0;
|
||||
switch (_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;
|
||||
}
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState, subresource);
|
||||
}
|
||||
index++;
|
||||
if (VERUS_MAX_RT == barrierCount)
|
||||
|
@ -313,13 +320,20 @@ void CommandBufferD3D12::PrepareSubpass()
|
|||
CD3DX12_RESOURCE_BARRIER barriers[VERUS_MAX_FB_ATTACH];
|
||||
int resIndex = 0;
|
||||
int barrierCount = 0;
|
||||
UINT subresource = 0;
|
||||
switch (_pFramebuffer->_cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: subresource = ToNativeCubeMapFace(static_cast<CubeMapFace>(resIndex)); break;
|
||||
case CubeMapFace::none: subresource = 0; break;
|
||||
default: subresource = !resIndex ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
|
||||
}
|
||||
VERUS_FOR(i, subpass._vInput.size())
|
||||
{
|
||||
const auto& ref = subpass._vInput[i];
|
||||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
const auto& resources = fs._vResources[resIndex];
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, 0);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
resIndex++;
|
||||
|
@ -330,7 +344,7 @@ void CommandBufferD3D12::PrepareSubpass()
|
|||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
const auto& resources = fs._vResources[resIndex];
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, 0);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
resIndex++;
|
||||
|
@ -340,7 +354,7 @@ void CommandBufferD3D12::PrepareSubpass()
|
|||
const auto& ref = subpass._depthStencil;
|
||||
if (_vAttachmentStates[ref._index] != ref._state)
|
||||
{
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, 0);
|
||||
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, subresource);
|
||||
_vAttachmentStates[ref._index] = ref._state;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,3 +230,17 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
default: throw VERUS_RECOVERABLE << "ToNativeFormat(), ViaType=?";
|
||||
}
|
||||
}
|
||||
|
||||
UINT CGI::ToNativeCubeMapFace(CubeMapFace face)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case CubeMapFace::posX: return 0;
|
||||
case CubeMapFace::negX: return 1;
|
||||
case CubeMapFace::posY: return 2;
|
||||
case CubeMapFace::negY: return 3;
|
||||
case CubeMapFace::posZ: return 4;
|
||||
case CubeMapFace::negZ: return 5;
|
||||
default: throw VERUS_RECOVERABLE << "ToNativeCubeMapFace()";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,5 +21,7 @@ namespace verus
|
|||
|
||||
CSZ ToNativeSemanticName(ViaUsage usage);
|
||||
DXGI_FORMAT ToNativeFormat(ViaUsage usage, ViaType type, int components);
|
||||
|
||||
UINT ToNativeCubeMapFace(CubeMapFace face);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace verus
|
|||
Vector<D3DFramebufferSubpass> _vSubpasses;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
CubeMapFace _cubeMapFace = CubeMapFace::none;
|
||||
};
|
||||
VERUS_TYPEDEFS(D3DFramebuffer);
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ void RendererD3D12::CreateSamplers()
|
|||
init.MaxLOD = D3D12_FLOAT32_MAX;
|
||||
|
||||
desc = init;
|
||||
desc.Filter = (settings._sceneShadowQuality <= App::Settings::ShadowQuality::nearest) ?
|
||||
desc.Filter = (settings._sceneShadowQuality <= App::Settings::Quality::low) ?
|
||||
D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT : D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
|
||||
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
desc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
|
@ -666,12 +666,13 @@ RPHandle RendererD3D12::CreateRenderPass(std::initializer_list<RP::Attachment> i
|
|||
return RPHandle::Make(nextIndex);
|
||||
}
|
||||
|
||||
FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
|
||||
FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex, CubeMapFace cubeMapFace)
|
||||
{
|
||||
RP::RcD3DRenderPass renderPass = GetRenderPass(renderPassHandle);
|
||||
RP::D3DFramebuffer framebuffer;
|
||||
framebuffer._width = w;
|
||||
framebuffer._height = h;
|
||||
framebuffer._cubeMapFace = cubeMapFace;
|
||||
|
||||
const Vector<TexturePtr> vTex(il);
|
||||
auto GetResource = [this, &vTex, swapChainBufferIndex](int index)
|
||||
|
@ -692,7 +693,7 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
|
|||
return texD3D12.GetD3DResource();
|
||||
}
|
||||
};
|
||||
auto GetRTV = [this, &vTex, swapChainBufferIndex](int index)
|
||||
auto GetRTV = [this, &vTex, swapChainBufferIndex, cubeMapFace](int index)
|
||||
{
|
||||
if (swapChainBufferIndex >= 0)
|
||||
{
|
||||
|
@ -707,7 +708,12 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
|
|||
else
|
||||
{
|
||||
auto& texD3D12 = static_cast<RTextureD3D12>(*vTex[index]);
|
||||
return texD3D12.GetDescriptorHeapRTV().AtCPU(0);
|
||||
switch (cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: return texD3D12.GetDescriptorHeapRTV().AtCPU(index); break;
|
||||
case CubeMapFace::none: return texD3D12.GetDescriptorHeapRTV().AtCPU(0); break;
|
||||
default: return texD3D12.GetDescriptorHeapRTV().AtCPU(!index ? +cubeMapFace : 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
auto GetDSV = [this, &vTex, swapChainBufferIndex](int index)
|
||||
|
|
|
@ -97,7 +97,8 @@ namespace verus
|
|||
virtual void DeleteTexture(PBaseTexture p) override;
|
||||
|
||||
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) override;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h,
|
||||
int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) override;
|
||||
virtual void DeleteRenderPass(RPHandle handle) override;
|
||||
virtual void DeleteFramebuffer(FBHandle handle) override;
|
||||
int GetNextRenderPassIndex() const;
|
||||
|
|
|
@ -98,6 +98,11 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
|
|||
sprintf_s(defAnisotropyLevel, "%d", settings._gpuAnisotropyLevel);
|
||||
vDefines.push_back({ "_ANISOTROPY_LEVEL", defAnisotropyLevel });
|
||||
}
|
||||
char defShaderQuality[64] = {};
|
||||
{
|
||||
sprintf_s(defShaderQuality, "%d", settings._gpuShaderQuality);
|
||||
vDefines.push_back({ "_SHADER_QUALITY", defShaderQuality });
|
||||
}
|
||||
char defShadowQuality[64] = {};
|
||||
{
|
||||
sprintf_s(defShadowQuality, "%d", settings._sceneShadowQuality);
|
||||
|
|
|
@ -37,12 +37,12 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
|
||||
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
|
||||
if (cubeMap)
|
||||
_desc._arrayLayers = 6;
|
||||
_desc._arrayLayers *= +CubeMapFace::count;
|
||||
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
|
||||
D3D12_RESOURCE_DESC resDesc = {};
|
||||
resDesc.Dimension = _desc._depth > 1 ? D3D12_RESOURCE_DIMENSION_TEXTURE3D : D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
resDesc.Dimension = (_desc._depth > 1) ? D3D12_RESOURCE_DIMENSION_TEXTURE3D : D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
resDesc.Width = _desc._width;
|
||||
resDesc.Height = _desc._height;
|
||||
resDesc.DepthOrArraySize = Math::Max(_desc._depth, _desc._arrayLayers);
|
||||
|
@ -149,8 +149,25 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
|
||||
if (renderTarget)
|
||||
{
|
||||
_dhRTV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
|
||||
pRendererD3D12->GetD3DDevice()->CreateRenderTargetView(_resource._pResource.Get(), nullptr, _dhRTV.AtCPU(0));
|
||||
if (cubeMap)
|
||||
{
|
||||
_dhRTV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, +CubeMapFace::count);
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||
rtvDesc.Format = ToNativeFormat(_desc._format, false);
|
||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
rtvDesc.Texture2DArray.MipSlice = 0;
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
{
|
||||
rtvDesc.Texture2DArray.FirstArraySlice = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
|
||||
rtvDesc.Texture2DArray.ArraySize = 1;
|
||||
pRendererD3D12->GetD3DDevice()->CreateRenderTargetView(_resource._pResource.Get(), &rtvDesc, _dhRTV.AtCPU(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dhRTV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
|
||||
pRendererD3D12->GetD3DDevice()->CreateRenderTargetView(_resource._pResource.Get(), nullptr, _dhRTV.AtCPU(0));
|
||||
}
|
||||
}
|
||||
|
||||
if (depthFormat)
|
||||
|
@ -175,14 +192,32 @@ void TextureD3D12::Init(RcTextureDesc desc)
|
|||
}
|
||||
else
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvCubeDesc = {};
|
||||
srvCubeDesc.Format = ToNativeFormat(_desc._format, false);
|
||||
srvCubeDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
srvCubeDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvCubeDesc.TextureCube.MostDetailedMip = 0;
|
||||
srvCubeDesc.TextureCube.MipLevels = _desc._mipLevels;
|
||||
_dhSRV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
|
||||
pRendererD3D12->GetD3DDevice()->CreateShaderResourceView(_resource._pResource.Get(), cubeMap ? &srvCubeDesc : nullptr, _dhSRV.AtCPU(0));
|
||||
if (cubeMap)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = ToNativeFormat(_desc._format, false);
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
if (_desc._arrayLayers > +CubeMapFace::count)
|
||||
{
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
|
||||
srvDesc.TextureCubeArray.MostDetailedMip = 0;
|
||||
srvDesc.TextureCubeArray.MipLevels = _desc._mipLevels;
|
||||
srvDesc.TextureCubeArray.NumCubes = _desc._arrayLayers / +CubeMapFace::count;
|
||||
}
|
||||
else
|
||||
{
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
srvDesc.TextureCube.MostDetailedMip = 0;
|
||||
srvDesc.TextureCube.MipLevels = _desc._mipLevels;
|
||||
}
|
||||
_dhSRV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
|
||||
pRendererD3D12->GetD3DDevice()->CreateShaderResourceView(_resource._pResource.Get(), &srvDesc, _dhSRV.AtCPU(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
_dhSRV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
|
||||
pRendererD3D12->GetD3DDevice()->CreateShaderResourceView(_resource._pResource.Get(), nullptr, _dhSRV.AtCPU(0));
|
||||
}
|
||||
}
|
||||
|
||||
if (_desc._pSamplerDesc)
|
||||
|
@ -490,7 +525,7 @@ void TextureD3D12::CreateSampler()
|
|||
}
|
||||
else if ('s' == _desc._pSamplerDesc->_filterMagMinMip[0]) // Shadow map:
|
||||
{
|
||||
if (settings._sceneShadowQuality <= App::Settings::ShadowQuality::nearest)
|
||||
if (settings._sceneShadowQuality <= App::Settings::Quality::low)
|
||||
samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
|
||||
else
|
||||
samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
|
||||
|
|
|
@ -235,3 +235,17 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
|
|||
default: throw VERUS_RECOVERABLE << "ToNativeFormat(), ViaType=?";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CGI::ToNativeCubeMapFace(CubeMapFace face)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case CubeMapFace::posX: return 0;
|
||||
case CubeMapFace::negX: return 1;
|
||||
case CubeMapFace::posY: return 2;
|
||||
case CubeMapFace::negY: return 3;
|
||||
case CubeMapFace::posZ: return 4;
|
||||
case CubeMapFace::negZ: return 5;
|
||||
default: throw VERUS_RECOVERABLE << "ToNativeCubeMapFace()";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,5 +23,7 @@ namespace verus
|
|||
|
||||
int ToNativeLocation(ViaUsage usage, int usageIndex);
|
||||
VkFormat ToNativeFormat(ViaUsage usage, ViaType type, int components);
|
||||
|
||||
uint32_t ToNativeCubeMapFace(CubeMapFace face);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ void RendererVulkan::CreateSamplers()
|
|||
};
|
||||
|
||||
vksci = init;
|
||||
if (settings._sceneShadowQuality <= App::Settings::ShadowQuality::nearest)
|
||||
if (settings._sceneShadowQuality <= App::Settings::Quality::low)
|
||||
{
|
||||
vksci.magFilter = VK_FILTER_NEAREST;
|
||||
vksci.minFilter = VK_FILTER_NEAREST;
|
||||
|
@ -1161,7 +1161,7 @@ RPHandle RendererVulkan::CreateRenderPass(std::initializer_list<RP::Attachment>
|
|||
return RPHandle::Make(nextIndex);
|
||||
}
|
||||
|
||||
FBHandle RendererVulkan::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex)
|
||||
FBHandle RendererVulkan::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex, CubeMapFace cubeMapFace)
|
||||
{
|
||||
VkResult res = VK_SUCCESS;
|
||||
|
||||
|
@ -1179,7 +1179,12 @@ FBHandle RendererVulkan::CreateFramebuffer(RPHandle renderPassHandle, std::initi
|
|||
for (const auto& x : il)
|
||||
{
|
||||
auto& texVulkan = static_cast<RTextureVulkan>(*x);
|
||||
imageViews[count] = texVulkan.GetVkImageViewForFramebuffer();
|
||||
switch (cubeMapFace)
|
||||
{
|
||||
case CubeMapFace::all: imageViews[count] = texVulkan.GetVkImageViewForFramebuffer(static_cast<CubeMapFace>(count)); break;
|
||||
case CubeMapFace::none: imageViews[count] = texVulkan.GetVkImageViewForFramebuffer(CubeMapFace::none); break;
|
||||
default: imageViews[count] = texVulkan.GetVkImageViewForFramebuffer(!count ? cubeMapFace : CubeMapFace::none);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
vkfci.attachmentCount = count;
|
||||
|
|
|
@ -158,7 +158,8 @@ namespace verus
|
|||
virtual void DeleteTexture(PBaseTexture p) override;
|
||||
|
||||
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) override;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex) override;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h,
|
||||
int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) override;
|
||||
virtual void DeleteRenderPass(RPHandle handle) override;
|
||||
virtual void DeleteFramebuffer(FBHandle handle) override;
|
||||
int GetNextRenderPassIndex() const;
|
||||
|
|
|
@ -100,6 +100,12 @@ void ShaderVulkan::Init(CSZ source, CSZ sourceName, CSZ* branches)
|
|||
vDefines.push_back("_ANISOTROPY_LEVEL");
|
||||
vDefines.push_back(defAnisotropyLevel);
|
||||
}
|
||||
char defShaderQuality[64] = {};
|
||||
{
|
||||
sprintf_s(defShaderQuality, "%d", settings._gpuShaderQuality);
|
||||
vDefines.push_back("_SHADER_QUALITY");
|
||||
vDefines.push_back(defShaderQuality);
|
||||
}
|
||||
char defShadowQuality[64] = {};
|
||||
{
|
||||
sprintf_s(defShadowQuality, "%d", settings._sceneShadowQuality);
|
||||
|
|
|
@ -35,13 +35,13 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
|
||||
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
|
||||
if (cubeMap)
|
||||
_desc._arrayLayers = 6;
|
||||
_desc._arrayLayers *= +CubeMapFace::count;
|
||||
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
|
||||
_mainLayout = ImageLayout::xsReadOnly;
|
||||
|
||||
VkImageCreateInfo vkici = {};
|
||||
vkici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
vkici.imageType = _desc._depth > 1 ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
||||
vkici.imageType = (_desc._depth > 1) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
||||
vkici.format = ToNativeFormat(_desc._format);
|
||||
vkici.extent.width = _desc._width;
|
||||
vkici.extent.height = _desc._height;
|
||||
|
@ -124,8 +124,10 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
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 (_desc._arrayLayers > 1 || (_desc._flags & TextureDesc::Flags::forceArrayTexture))
|
||||
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))
|
||||
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;
|
||||
|
@ -137,9 +139,23 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(), res=" << res;
|
||||
if (renderTarget)
|
||||
{
|
||||
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
vkivci.subresourceRange.levelCount = 1;
|
||||
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_imageViewLevelZero)))
|
||||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(LevelZero), res=" << res;
|
||||
vkivci.subresourceRange.layerCount = 1;
|
||||
if (cubeMap)
|
||||
{
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
{
|
||||
vkivci.subresourceRange.baseArrayLayer = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
|
||||
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), _imageViewForFramebuffer + i)))
|
||||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(LevelZero), res=" << res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), _imageViewForFramebuffer)))
|
||||
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(LevelZero), res=" << res;
|
||||
}
|
||||
}
|
||||
|
||||
if (_desc._pSamplerDesc)
|
||||
|
@ -149,7 +165,15 @@ void TextureVulkan::Init(RcTextureDesc desc)
|
|||
{
|
||||
CommandBufferVulkan commandBuffer;
|
||||
commandBuffer.InitOneTimeSubmit();
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, 0);
|
||||
if (cubeMap)
|
||||
{
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, 0);
|
||||
}
|
||||
commandBuffer.DoneOneTimeSubmit();
|
||||
}
|
||||
if (depthFormat)
|
||||
|
@ -175,12 +199,16 @@ void TextureVulkan::Done()
|
|||
VERUS_VULKAN_DESTROY(x._buffer, vmaDestroyBuffer(pRendererVulkan->GetVmaAllocator(), x._buffer, x._vmaAllocation));
|
||||
_vReadbackBuffers.clear();
|
||||
VERUS_VULKAN_DESTROY(_sampler, vkDestroySampler(pRendererVulkan->GetVkDevice(), _sampler, pRendererVulkan->GetAllocator()));
|
||||
VERUS_VULKAN_DESTROY(_imageViewLevelZero, vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageViewLevelZero, pRendererVulkan->GetAllocator()));
|
||||
|
||||
VERUS_FOR(i, +CubeMapFace::count)
|
||||
VERUS_VULKAN_DESTROY(_imageViewForFramebuffer[i], vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageViewForFramebuffer[i], pRendererVulkan->GetAllocator()));
|
||||
VERUS_VULKAN_DESTROY(_imageView, vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageView, pRendererVulkan->GetAllocator()));
|
||||
|
||||
for (auto view : _vStorageImageViews)
|
||||
VERUS_VULKAN_DESTROY(view, vkDestroyImageView(pRendererVulkan->GetVkDevice(), view, pRendererVulkan->GetAllocator()));
|
||||
_vStorageImageViews.clear();
|
||||
VERUS_VULKAN_DESTROY(_storageImage, vmaDestroyImage(pRendererVulkan->GetVmaAllocator(), _storageImage, _storageVmaAllocation));
|
||||
|
||||
VERUS_VULKAN_DESTROY(_image, vmaDestroyImage(pRendererVulkan->GetVmaAllocator(), _image, _vmaAllocation));
|
||||
|
||||
VERUS_DONE(TextureVulkan);
|
||||
|
@ -420,7 +448,7 @@ void TextureVulkan::CreateSampler()
|
|||
{
|
||||
vksci.compareEnable = VK_TRUE;
|
||||
vksci.compareOp = VK_COMPARE_OP_LESS;
|
||||
if (settings._sceneShadowQuality <= App::Settings::ShadowQuality::nearest)
|
||||
if (settings._sceneShadowQuality <= App::Settings::Quality::low)
|
||||
{
|
||||
vksci.magFilter = VK_FILTER_NEAREST;
|
||||
vksci.minFilter = VK_FILTER_NEAREST;
|
||||
|
@ -491,6 +519,14 @@ void TextureVulkan::CreateSampler()
|
|||
_desc._pSamplerDesc = nullptr;
|
||||
}
|
||||
|
||||
VkImageView TextureVulkan::GetVkImageViewForFramebuffer(CubeMapFace face) const
|
||||
{
|
||||
if (CubeMapFace::none == face)
|
||||
return _imageViewForFramebuffer[0] ? _imageViewForFramebuffer[0] : _imageView;
|
||||
else
|
||||
return _imageViewForFramebuffer[+face] ? _imageViewForFramebuffer[+face] : _imageView;
|
||||
}
|
||||
|
||||
ImageLayout TextureVulkan::GetSubresourceMainLayout(int mipLevel, int arrayLayer) const
|
||||
{
|
||||
return ((_vDefinedSubresources[arrayLayer] >> mipLevel) & 0x1) ? _mainLayout : ImageLayout::undefined;
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace verus
|
|||
VkImage _storageImage = VK_NULL_HANDLE;
|
||||
VmaAllocation _storageVmaAllocation = VK_NULL_HANDLE;
|
||||
VkImageView _imageView = VK_NULL_HANDLE;
|
||||
VkImageView _imageViewLevelZero = VK_NULL_HANDLE;
|
||||
VkImageView _imageViewForFramebuffer[+CubeMapFace::count] = {};
|
||||
VkSampler _sampler = VK_NULL_HANDLE;
|
||||
Vector<UINT32> _vDefinedSubresources;
|
||||
Vector<VkImageView> _vStorageImageViews;
|
||||
|
@ -49,7 +49,7 @@ namespace verus
|
|||
|
||||
VkImage GetVkImage() const { return _image; }
|
||||
VkImageView GetVkImageView() const { return _imageView; }
|
||||
VkImageView GetVkImageViewForFramebuffer() const { return _imageViewLevelZero ? _imageViewLevelZero : _imageView; }
|
||||
VkImageView GetVkImageViewForFramebuffer(CubeMapFace face) const;
|
||||
VkImageView GetStorageVkImageView(int mip) const { return _vStorageImageViews[mip]; }
|
||||
VkSampler GetVkSampler() const { return _sampler; }
|
||||
ImageLayout GetSubresourceMainLayout(int mipLevel, int arrayLayer) const;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.12\include;C:\VulkanSDK\1.2.162.0\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.12\lib\x64;C:\VulkanSDK\1.2.162.0\Lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.12\include;C:\VulkanSDK\1.2.162.1\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.12\lib\x64;C:\VulkanSDK\1.2.162.1\Lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
|
|
|
@ -136,8 +136,11 @@
|
|||
<ClInclude Include="src\Effects\Effects.h" />
|
||||
<ClInclude Include="src\Effects\Particles.h" />
|
||||
<ClInclude Include="src\Effects\Ssao.h" />
|
||||
<ClInclude Include="src\Effects\Ssr.h" />
|
||||
<ClInclude Include="src\Extra\BaseConvert.h" />
|
||||
<ClInclude Include="src\Extra\ConvertGLTF.h" />
|
||||
<ClInclude Include="src\Extra\Extra.h" />
|
||||
<ClInclude Include="src\Extra\FileParser.h" />
|
||||
<ClInclude Include="src\Extra\ConvertX.h" />
|
||||
<ClInclude Include="src\Game\BaseGame.h" />
|
||||
<ClInclude Include="src\Game\BaseCharacter.h" />
|
||||
<ClInclude Include="src\Game\ChainAward.h" />
|
||||
|
@ -236,6 +239,7 @@
|
|||
<ClInclude Include="src\Scene\BaseMesh.h" />
|
||||
<ClInclude Include="src\Scene\Camera.h" />
|
||||
<ClInclude Include="src\Scene\CameraOrbit.h" />
|
||||
<ClInclude Include="src\Scene\CubeMap.h" />
|
||||
<ClInclude Include="src\Scene\EditorTerrain.h" />
|
||||
<ClInclude Include="src\Scene\Forest.h" />
|
||||
<ClInclude Include="src\Scene\Grass.h" />
|
||||
|
@ -272,9 +276,12 @@
|
|||
<ClInclude Include="src\ThirdParty\libb64\cencode.h" />
|
||||
<ClInclude Include="src\ThirdParty\md5.h" />
|
||||
<ClInclude Include="src\ThirdParty\nativefiledialog\nfd.h" />
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.10\pugiconfig.hpp" />
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.10\pugixml.hpp" />
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.11\pugiconfig.hpp" />
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.11\pugixml.hpp" />
|
||||
<ClInclude Include="src\ThirdParty\ThirdParty.h" />
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\stb_image.h" />
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\stb_image_write.h" />
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\tiny_gltf.h" />
|
||||
<ClInclude Include="src\ThirdParty\utf8.h" />
|
||||
<ClInclude Include="src\ThirdParty\utf8\checked.h" />
|
||||
<ClInclude Include="src\ThirdParty\utf8\core.h" />
|
||||
|
@ -333,8 +340,11 @@
|
|||
<ClCompile Include="src\Effects\Effects.cpp" />
|
||||
<ClCompile Include="src\Effects\Particles.cpp" />
|
||||
<ClCompile Include="src\Effects\Ssao.cpp" />
|
||||
<ClCompile Include="src\Effects\Ssr.cpp" />
|
||||
<ClCompile Include="src\Extra\BaseConvert.cpp" />
|
||||
<ClCompile Include="src\Extra\ConvertGLTF.cpp" />
|
||||
<ClCompile Include="src\Extra\Extra.cpp" />
|
||||
<ClCompile Include="src\Extra\FileParser.cpp" />
|
||||
<ClCompile Include="src\Extra\ConvertX.cpp" />
|
||||
<ClCompile Include="src\Game\BaseGame.cpp" />
|
||||
<ClCompile Include="src\Game\BaseCharacter.cpp" />
|
||||
<ClCompile Include="src\Game\ChainAward.cpp" />
|
||||
|
@ -411,6 +421,7 @@
|
|||
<ClCompile Include="src\Scene\BaseMesh.cpp" />
|
||||
<ClCompile Include="src\Scene\Camera.cpp" />
|
||||
<ClCompile Include="src\Scene\CameraOrbit.cpp" />
|
||||
<ClCompile Include="src\Scene\CubeMap.cpp" />
|
||||
<ClCompile Include="src\Scene\EditorTerrain.cpp" />
|
||||
<ClCompile Include="src\Scene\Forest.cpp" />
|
||||
<ClCompile Include="src\Scene\Grass.cpp" />
|
||||
|
@ -484,7 +495,11 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\pugixml-1.10\pugixml.cpp">
|
||||
<ClCompile Include="src\ThirdParty\pugixml-1.11\pugixml.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\tinygltf-2.5.0\tinygltf.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -659,8 +674,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="src\ThirdParty\imgui\imgui.natvis" />
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml.natvis" />
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml_compact.natvis" />
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml.natvis" />
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml_compact.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\DebugDraw.hlsl">
|
||||
|
@ -810,6 +825,14 @@
|
|||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\Ssr.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
<None Include="src\Shaders\Ssr.inc.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
|
|
@ -76,9 +76,6 @@
|
|||
<Filter Include="src\Physics">
|
||||
<UniqueIdentifier>{85f1e663-5318-4602-82d3-cd811b5a0141}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\ThirdParty\pugixml-1.10">
|
||||
<UniqueIdentifier>{77a61380-3977-4378-9e5b-fb4f5788aaa3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\ThirdParty\imgui">
|
||||
<UniqueIdentifier>{3ee2005e-b456-4f4f-95cd-ad3ac11aaccb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -97,6 +94,12 @@
|
|||
<Filter Include="src\Scene\SceneNodes">
|
||||
<UniqueIdentifier>{07af1a9e-5cdc-4264-811b-d958ec70a709}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\ThirdParty\pugixml-1.11">
|
||||
<UniqueIdentifier>{a659491b-ee62-496a-8451-762951446c2f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\ThirdParty\tinygltf-2.5.0">
|
||||
<UniqueIdentifier>{54a71e7f-5bcd-480d-990e-0d5e79d7ded9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\CGI\BaseGeometry.h">
|
||||
|
@ -492,12 +495,6 @@
|
|||
<ClInclude Include="src\CGI\RendererParser.h">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.10\pugiconfig.hpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.10</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.10\pugixml.hpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.10</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\IO\Dictionary.h">
|
||||
<Filter>src\IO</Filter>
|
||||
</ClInclude>
|
||||
|
@ -546,9 +543,6 @@
|
|||
<ClInclude Include="src\Extra\Extra.h">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Extra\FileParser.h">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Anim\Warp.h">
|
||||
<Filter>src\Anim</Filter>
|
||||
</ClInclude>
|
||||
|
@ -708,6 +702,36 @@
|
|||
<ClInclude Include="src\Game\ChainAward.h">
|
||||
<Filter>src\Game</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.11\pugiconfig.hpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.11</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\pugixml-1.11\pugixml.hpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.11</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\stb_image.h">
|
||||
<Filter>src\ThirdParty\tinygltf-2.5.0</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\stb_image_write.h">
|
||||
<Filter>src\ThirdParty\tinygltf-2.5.0</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ThirdParty\tinygltf-2.5.0\tiny_gltf.h">
|
||||
<Filter>src\ThirdParty\tinygltf-2.5.0</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Extra\ConvertX.h">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Extra\BaseConvert.h">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Extra\ConvertGLTF.h">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Effects\Ssr.h">
|
||||
<Filter>src\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Scene\CubeMap.h">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CGI\BaseGeometry.cpp">
|
||||
|
@ -1007,9 +1031,6 @@
|
|||
<ClCompile Include="src\CGI\RendererParser.cpp">
|
||||
<Filter>src\CGI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\pugixml-1.10\pugixml.cpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.10</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\IO\Dictionary.cpp">
|
||||
<Filter>src\IO</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1055,9 +1076,6 @@
|
|||
<ClCompile Include="src\Extra\Extra.cpp">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Extra\FileParser.cpp">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\fast_atof.c">
|
||||
<Filter>src\ThirdParty</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1202,6 +1220,27 @@
|
|||
<ClCompile Include="src\Game\ChainAward.cpp">
|
||||
<Filter>src\Game</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\pugixml-1.11\pugixml.cpp">
|
||||
<Filter>src\ThirdParty\pugixml-1.11</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ThirdParty\tinygltf-2.5.0\tinygltf.cpp">
|
||||
<Filter>src\ThirdParty\tinygltf-2.5.0</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Extra\ConvertX.cpp">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Extra\BaseConvert.cpp">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Extra\ConvertGLTF.cpp">
|
||||
<Filter>src\Extra</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Effects\Ssr.cpp">
|
||||
<Filter>src\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Scene\CubeMap.cpp">
|
||||
<Filter>src\Scene</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\Lib.hlsl">
|
||||
|
@ -1366,16 +1405,22 @@
|
|||
<None Include="src\Shaders\SimpleMesh.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\Ssr.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
<None Include="src\Shaders\Ssr.inc.hlsl">
|
||||
<Filter>src\Shaders</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml.natvis">
|
||||
<Filter>src\ThirdParty\pugixml-1.10</Filter>
|
||||
</Natvis>
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.10\pugixml_compact.natvis">
|
||||
<Filter>src\ThirdParty\pugixml-1.10</Filter>
|
||||
</Natvis>
|
||||
<Natvis Include="src\ThirdParty\imgui\imgui.natvis">
|
||||
<Filter>src\ThirdParty\imgui</Filter>
|
||||
</Natvis>
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml.natvis">
|
||||
<Filter>src\ThirdParty\pugixml-1.11</Filter>
|
||||
</Natvis>
|
||||
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml_compact.natvis">
|
||||
<Filter>src\ThirdParty\pugixml-1.11</Filter>
|
||||
</Natvis>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -85,29 +85,33 @@ void Settings::SetQuality(Quality q)
|
|||
{
|
||||
case Quality::low:
|
||||
_gpuAnisotropyLevel = 0;
|
||||
_gpuShaderQuality = Quality::low;
|
||||
_gpuTrilinearFilter = false;
|
||||
_sceneShadowQuality = ShadowQuality::linear;
|
||||
_sceneGrassDensity = 500;
|
||||
_sceneShadowQuality = Quality::low;
|
||||
_sceneWaterQuality = WaterQuality::solidColor;
|
||||
break;
|
||||
case Quality::medium:
|
||||
break;
|
||||
case Quality::high:
|
||||
_gpuAnisotropyLevel = 8;
|
||||
_gpuShaderQuality = Quality::high;
|
||||
_postProcessBloom = true;
|
||||
_postProcessCinema = true;
|
||||
_postProcessSSAO = true;
|
||||
_sceneGrassDensity = 1000;
|
||||
_sceneShadowQuality = ShadowQuality::cascaded;
|
||||
_sceneShadowQuality = Quality::high;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesReflection;
|
||||
break;
|
||||
case Quality::ultra:
|
||||
_gpuAnisotropyLevel = 16;
|
||||
_gpuShaderQuality = Quality::ultra;
|
||||
_postProcessBloom = true;
|
||||
_postProcessCinema = true;
|
||||
_postProcessMotionBlur = true;
|
||||
_postProcessSSAO = true;
|
||||
_sceneGrassDensity = 1000;
|
||||
_sceneShadowQuality = ShadowQuality::ultra;
|
||||
_sceneShadowQuality = Quality::ultra;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesRefraction;
|
||||
_displaySizeHeight = 1080;
|
||||
_displaySizeWidth = 1980;
|
||||
|
@ -131,6 +135,7 @@ void Settings::Load()
|
|||
_gapi = GetI("gapi", _gapi);
|
||||
_gpuAnisotropyLevel = GetI("gpuAnisotropyLevel", _gpuAnisotropyLevel);
|
||||
_gpuAntialiasingLevel = GetI("gpuAntialiasingLevel", _gpuAntialiasingLevel);
|
||||
_gpuShaderQuality = static_cast<Quality>(GetI("gpuShaderQuality", +_gpuShaderQuality));
|
||||
_gpuTessellation = GetB("gpuTessellation", _gpuTessellation);
|
||||
_gpuTextureLodLevel = GetI("gpuTextureLodLevel", _gpuTextureLodLevel);
|
||||
_gpuTrilinearFilter = GetB("gpuTrilinearFilter", _gpuTrilinearFilter);
|
||||
|
@ -140,7 +145,7 @@ void Settings::Load()
|
|||
_postProcessMotionBlur = GetB("postProcessMotionBlur", _postProcessMotionBlur);
|
||||
_postProcessSSAO = GetB("postProcessSSAO", _postProcessSSAO);
|
||||
_sceneGrassDensity = GetI("sceneGrassDensity", _sceneGrassDensity);
|
||||
_sceneShadowQuality = static_cast<ShadowQuality>(GetI("sceneShadowQuality", +_sceneShadowQuality));
|
||||
_sceneShadowQuality = static_cast<Quality>(GetI("sceneShadowQuality", +_sceneShadowQuality));
|
||||
_sceneWaterQuality = static_cast<WaterQuality>(GetI("sceneWaterQuality", +_sceneWaterQuality));
|
||||
_uiLang = GetS("uiLang", _C(_uiLang));
|
||||
}
|
||||
|
@ -190,9 +195,10 @@ void Settings::Validate()
|
|||
_displaySizeWidth = Math::Clamp(_displaySizeWidth, 480, 0x2000);
|
||||
_gpuAnisotropyLevel = Math::Clamp(_gpuAnisotropyLevel, 0, 16);
|
||||
_gpuAntialiasingLevel = Math::Clamp(_gpuAntialiasingLevel, 0, 16);
|
||||
_gpuShaderQuality = Math::Clamp(_gpuShaderQuality, Quality::low, Quality::ultra);
|
||||
_gpuTextureLodLevel = Math::Clamp(_gpuTextureLodLevel, 0, 4);
|
||||
_sceneGrassDensity = Math::Clamp(_sceneGrassDensity, 100, 1000);
|
||||
_sceneShadowQuality = Math::Clamp(_sceneShadowQuality, ShadowQuality::none, ShadowQuality::ultra);
|
||||
_sceneShadowQuality = Math::Clamp(_sceneShadowQuality, Quality::low, Quality::ultra);
|
||||
_sceneWaterQuality = Math::Clamp(_sceneWaterQuality, WaterQuality::solidColor, WaterQuality::trueWavesRefraction);
|
||||
|
||||
if (_uiLang != "RU" && _uiLang != "EN")
|
||||
|
@ -215,6 +221,7 @@ void Settings::Save()
|
|||
Set("gapi", _gapi);
|
||||
Set("gpuAnisotropyLevel", _gpuAnisotropyLevel);
|
||||
Set("gpuAntialiasingLevel", _gpuAntialiasingLevel);
|
||||
Set("gpuShaderQuality", +_gpuShaderQuality);
|
||||
Set("gpuTessellation", _gpuTessellation);
|
||||
Set("gpuTextureLodLevel", _gpuTextureLodLevel);
|
||||
Set("gpuTrilinearFilter", _gpuTrilinearFilter);
|
||||
|
|
|
@ -61,16 +61,6 @@ namespace verus
|
|||
ultra
|
||||
};
|
||||
|
||||
enum class ShadowQuality : int
|
||||
{
|
||||
none,
|
||||
nearest,
|
||||
linear,
|
||||
multisampled,
|
||||
cascaded,
|
||||
ultra
|
||||
};
|
||||
|
||||
enum class WaterQuality : int
|
||||
{
|
||||
solidColor,
|
||||
|
@ -92,6 +82,7 @@ namespace verus
|
|||
int _gapi = 0;
|
||||
int _gpuAnisotropyLevel = 4;
|
||||
int _gpuAntialiasingLevel = 0;
|
||||
Quality _gpuShaderQuality = Quality::medium;
|
||||
bool _gpuTessellation = true;
|
||||
int _gpuTextureLodLevel = 0;
|
||||
bool _gpuTrilinearFilter = true;
|
||||
|
@ -101,8 +92,8 @@ namespace verus
|
|||
bool _postProcessCinema = false;
|
||||
bool _postProcessMotionBlur = false;
|
||||
bool _postProcessSSAO = false;
|
||||
int _sceneGrassDensity = 500;
|
||||
ShadowQuality _sceneShadowQuality = ShadowQuality::multisampled;
|
||||
int _sceneGrassDensity = 750;
|
||||
Quality _sceneShadowQuality = Quality::medium;
|
||||
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
|
||||
String _uiLang = "EN";
|
||||
CommandLine _commandLine;
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace verus
|
|||
_rasterizationState._depthBiasEnable = true;
|
||||
_rasterizationState._depthBiasConstantFactor = 14;
|
||||
_rasterizationState._depthBiasSlopeFactor = 1.1f;
|
||||
if (App::Settings::I()._sceneShadowQuality >= App::Settings::ShadowQuality::cascaded)
|
||||
if (App::Settings::I()._sceneShadowQuality >= App::Settings::Quality::high)
|
||||
_rasterizationState._depthBiasConstantFactor = 50;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -46,11 +46,11 @@ void BaseRenderer::UpdateScheduled()
|
|||
}), _vScheduled.end());
|
||||
}
|
||||
|
||||
RPHandle BaseRenderer::CreateSimpleRenderPass(Format format, ImageLayout layout)
|
||||
RPHandle BaseRenderer::CreateSimpleRenderPass(Format format, RP::Attachment::LoadOp loadOp, ImageLayout layout)
|
||||
{
|
||||
return CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("Attach", format).LoadOpDontCare().Layout(layout),
|
||||
RP::Attachment("Attach", format).SetLoadOp(loadOp).Layout(layout),
|
||||
},
|
||||
{
|
||||
RP::Subpass("Sp0").Color({RP::Ref("Attach", ImageLayout::colorAttachment)}),
|
||||
|
|
|
@ -79,10 +79,11 @@ namespace verus
|
|||
virtual void DeleteShader(PBaseShader p) = 0;
|
||||
virtual void DeleteTexture(PBaseTexture p) = 0;
|
||||
|
||||
RPHandle CreateSimpleRenderPass(Format format, ImageLayout layout = ImageLayout::fsReadOnly);
|
||||
RPHandle CreateSimpleRenderPass(Format format, RP::Attachment::LoadOp loadOp = RP::Attachment::LoadOp::dontCare, ImageLayout layout = ImageLayout::fsReadOnly);
|
||||
RPHandle CreateShadowRenderPass(Format format);
|
||||
virtual RPHandle CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> ilD) = 0;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h, int swapChainBufferIndex = -1) = 0;
|
||||
virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list<TexturePtr> il, int w, int h,
|
||||
int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) = 0;
|
||||
virtual void DeleteRenderPass(RPHandle handle) = 0;
|
||||
virtual void DeleteFramebuffer(FBHandle handle) = 0;
|
||||
|
||||
|
|
|
@ -126,11 +126,11 @@ void DeferredShading::Init()
|
|||
_shader[SHADER_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 2, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 2,
|
||||
{
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::linearClampMipN, // For bloom.
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN,
|
||||
Sampler::nearestClampMipN
|
||||
}, ShaderStageFlags::fs);
|
||||
_shader[SHADER_COMPOSE]->CreatePipelineLayout();
|
||||
|
@ -241,9 +241,9 @@ void DeferredShading::InitByBloom(TexturePtr tex)
|
|||
{
|
||||
_tex[TEX_GBUFFER_0],
|
||||
_tex[TEX_GBUFFER_1],
|
||||
tex,
|
||||
_tex[TEX_GBUFFER_2],
|
||||
_tex[TEX_COMPOSED_A],
|
||||
_tex[TEX_LIGHT_ACC_DIFF],
|
||||
tex,
|
||||
_tex[TEX_LIGHT_ACC_SPEC]
|
||||
});
|
||||
}
|
||||
|
@ -601,6 +601,7 @@ 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()->GetMatrixVi().UniformBufferFormat();
|
||||
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
|
||||
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
|
||||
|
@ -609,6 +610,7 @@ void DeferredShading::BeginCompose(RcVector4 bgColor)
|
|||
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,
|
||||
|
@ -708,12 +710,13 @@ void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool w
|
|||
cb->BindDescriptors(_shader[SHADER_LIGHT], 1, _cshLight);
|
||||
|
||||
// Shadow:
|
||||
s_ubShadowFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrixDS(0).UniformBufferFormat();
|
||||
s_ubShadowFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrixDS(1).UniformBufferFormat();
|
||||
s_ubShadowFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrixDS(2).UniformBufferFormat();
|
||||
s_ubShadowFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrixDS(3).UniformBufferFormat();
|
||||
s_ubShadowFS._matShadow = atmo.GetShadowMap().GetShadowMatrixDS(0).UniformBufferFormat();
|
||||
s_ubShadowFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrixDS(1).UniformBufferFormat();
|
||||
s_ubShadowFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrixDS(2).UniformBufferFormat();
|
||||
s_ubShadowFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrixDS(3).UniformBufferFormat();
|
||||
s_ubShadowFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixP().UniformBufferFormat();
|
||||
s_ubShadowFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubShadowFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubShadowFS._shadowConfig));
|
||||
s_ubShadowFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
cb->BindDescriptors(_shader[SHADER_LIGHT], 3);
|
||||
}
|
||||
|
||||
|
@ -772,6 +775,16 @@ TexturePtr DeferredShading::GetGBuffer(int index)
|
|||
return _tex[index];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetLightAccDiffTexture()
|
||||
{
|
||||
return _tex[TEX_LIGHT_ACC_DIFF];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetLightAccSpecTexture()
|
||||
{
|
||||
return _tex[TEX_LIGHT_ACC_SPEC];
|
||||
}
|
||||
|
||||
TexturePtr DeferredShading::GetComposedTextureA()
|
||||
{
|
||||
return _tex[TEX_COMPOSED_A];
|
||||
|
|
|
@ -90,6 +90,7 @@ namespace verus
|
|||
CSHandle _cshToneMapping;
|
||||
CSHandle _cshQuad[5];
|
||||
CSHandle _cshBakeSprites;
|
||||
float _lightGlossScale = 1;
|
||||
bool _activeGeometryPass = false;
|
||||
bool _activeLightingPass = false;
|
||||
bool _async_initPipe = false;
|
||||
|
@ -140,7 +141,8 @@ namespace verus
|
|||
void Load();
|
||||
|
||||
TexturePtr GetGBuffer(int index);
|
||||
|
||||
TexturePtr GetLightAccDiffTexture();
|
||||
TexturePtr GetLightAccSpecTexture();
|
||||
TexturePtr GetComposedTextureA();
|
||||
TexturePtr GetComposedTextureB();
|
||||
|
||||
|
@ -150,6 +152,10 @@ namespace verus
|
|||
|
||||
void BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB = nullptr);
|
||||
void BakeSpritesCleanup();
|
||||
|
||||
// For Editor:
|
||||
float GetLightGlossScale() const { return _lightGlossScale; }
|
||||
void SetLightGlossScale(float s) { _lightGlossScale = s; }
|
||||
};
|
||||
VERUS_TYPEDEFS(DeferredShading);
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ void Renderer::OnWindowResized(int w, int h)
|
|||
Scene::Water::I().OnSwapChainResized();
|
||||
Effects::Bloom::I().OnSwapChainResized();
|
||||
Effects::Ssao::I().OnSwapChainResized();
|
||||
Effects::Ssr::I().OnSwapChainResized();
|
||||
Effects::Blur::I().OnSwapChainResized();
|
||||
}
|
||||
|
||||
|
|
|
@ -137,6 +137,19 @@ namespace verus
|
|||
count
|
||||
};
|
||||
|
||||
enum class CubeMapFace : int
|
||||
{
|
||||
posX,
|
||||
negX,
|
||||
posY,
|
||||
negY,
|
||||
posZ,
|
||||
negZ,
|
||||
count,
|
||||
all,
|
||||
none = -1
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BaseHandle
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ void Bloom::Init()
|
|||
VERUS_QREF_RENDERER;
|
||||
|
||||
_rph = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_rphGodRays = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8, CGI::RP::Attachment::LoadOp::load);
|
||||
|
||||
_shader.Init("[Shaders]:Bloom.hlsl");
|
||||
_shader->CreateDescriptorSet(0, &s_ubBloomVS, sizeof(s_ubBloomVS), 100, {}, CGI::ShaderStageFlags::vs);
|
||||
|
@ -38,10 +39,17 @@ void Bloom::Init()
|
|||
_shader->CreatePipelineLayout();
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#GodRays", _rph);
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe.Init(pipeDesc);
|
||||
_pipe[PIPE_MAIN].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#GodRays", _rphGodRays);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_GOD_RAYS].Init(pipeDesc);
|
||||
}
|
||||
|
||||
OnSwapChainResized();
|
||||
|
@ -69,8 +77,9 @@ void Bloom::OnSwapChainResized()
|
|||
{
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_ATMO;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_cshGodRays);
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
|
@ -97,43 +106,81 @@ void Bloom::OnSwapChainResized()
|
|||
renderer.GetDS().InitByBloom(_tex[TEX_PING]);
|
||||
}
|
||||
|
||||
void Bloom::Generate()
|
||||
void Bloom::Generate(bool withGodRays)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
if (_editMode)
|
||||
{
|
||||
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::Checkbox("Bloom blur", &_blur);
|
||||
ImGui::Checkbox("Bloom (god rays) blur", &_blurGodRays);
|
||||
}
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubBloomVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBloomVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubBloomFS._exposure.x = renderer.GetExposure();
|
||||
s_ubBloomGodRaysFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
memcpy(&s_ubBloomGodRaysFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubBloomGodRaysFS._shadowConfig));
|
||||
s_ubBloomGodRaysFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
s_ubBloomGodRaysFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._eyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubBloomFS._colorScale_colorBias.x = _colorScale;
|
||||
s_ubBloomFS._colorScale_colorBias.y = _colorBias;
|
||||
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
|
||||
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_PING]->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe);
|
||||
cb->BindPipeline(_pipe[PIPE_MAIN]);
|
||||
_shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _csh);
|
||||
cb->BindDescriptors(_shader, 2, _cshGodRays);
|
||||
_shader->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
|
||||
Blur::I().GenerateForBloom();
|
||||
if (_blur)
|
||||
Blur::I().GenerateForBloom(false);
|
||||
|
||||
if (withGodRays)
|
||||
{
|
||||
s_ubBloomGodRaysFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._eyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.x = _maxDist;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.y = _sunGloss;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.z = _wideStrength;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.w = _sunStrength;
|
||||
s_ubBloomGodRaysFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubBloomGodRaysFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubBloomGodRaysFS._shadowConfig));
|
||||
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
|
||||
cb->BeginRenderPass(_rphGodRays, _fbh, { _tex[TEX_PING]->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_GOD_RAYS]);
|
||||
_shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _csh);
|
||||
cb->BindDescriptors(_shader, 2, _cshGodRays);
|
||||
_shader->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
|
||||
if (_blurGodRays)
|
||||
Blur::I().GenerateForBloom(true);
|
||||
}
|
||||
}
|
||||
|
||||
CGI::TexturePtr Bloom::GetTexture() const
|
||||
|
|
|
@ -9,6 +9,13 @@ namespace verus
|
|||
{
|
||||
#include "../Shaders/Bloom.inc.hlsl"
|
||||
|
||||
enum PIPE
|
||||
{
|
||||
PIPE_MAIN,
|
||||
PIPE_GOD_RAYS,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
enum TEX
|
||||
{
|
||||
TEX_PING,
|
||||
|
@ -20,14 +27,24 @@ namespace verus
|
|||
static UB_BloomFS s_ubBloomFS;
|
||||
static UB_BloomGodRaysFS s_ubBloomGodRaysFS;
|
||||
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::TexturePtr _texAtmoShadow;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshGodRays;
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwns<PIPE_COUNT> _pipe;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::TexturePtr _texAtmoShadow;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::RPHandle _rphGodRays;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshGodRays;
|
||||
float _colorScale = 0.5f;
|
||||
float _colorBias = 1.1f;
|
||||
float _maxDist = 20;
|
||||
float _sunGloss = 128;
|
||||
float _wideStrength = 0.2f;
|
||||
float _sunStrength = 0.3f;
|
||||
bool _blur = true;
|
||||
bool _blurGodRays = true;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
Bloom();
|
||||
|
@ -39,10 +56,13 @@ namespace verus
|
|||
|
||||
void OnSwapChainResized();
|
||||
|
||||
void Generate();
|
||||
void Generate(bool withGodRays = true);
|
||||
|
||||
CGI::TexturePtr GetTexture() const;
|
||||
CGI::TexturePtr GetPongTexture() const;
|
||||
|
||||
bool IsEditMode() const { return _editMode; }
|
||||
void ToggleEditMode() { _editMode = !_editMode; }
|
||||
};
|
||||
VERUS_TYPEDEFS(Bloom);
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@ Blur::UB_ExtraBlurFS Blur::s_ubExtraBlurFS;
|
|||
void Blur::Handles::FreeDescriptorSets(CGI::ShaderPtr shader)
|
||||
{
|
||||
shader->FreeDescriptorSet(_cshV);
|
||||
shader->FreeDescriptorSet(_cshH);
|
||||
shader->FreeDescriptorSet(_cshU);
|
||||
}
|
||||
|
||||
void Blur::Handles::DeleteFramebuffers()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
renderer->DeleteFramebuffer(_fbhV);
|
||||
renderer->DeleteFramebuffer(_fbhH);
|
||||
renderer->DeleteFramebuffer(_fbhU);
|
||||
}
|
||||
|
||||
// Blur:
|
||||
|
@ -39,10 +39,12 @@ void Blur::Init()
|
|||
VERUS_INIT();
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_bloomHandles._rphH = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_bloomHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_ssaoHandles._rphH = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_ssaoHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_ssaoHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::unormR8);
|
||||
_ssrHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_ssrHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_rphAntiAliasing = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
_rphMotionBlur = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
|
||||
|
||||
|
@ -60,31 +62,42 @@ void Blur::Init()
|
|||
_shader->CreatePipelineLayout();
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#H", renderer.GetRenderPassHandle_AutoWithDepth());
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#U", renderer.GetRenderPassHandle_AutoWithDepth());
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_H].Init(pipeDesc);
|
||||
_pipe[PIPE_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#V";
|
||||
_pipe[PIPE_V].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#H", _bloomHandles._rphH);
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#U", _bloomHandles._rphU);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_BLOOM_H].Init(pipeDesc);
|
||||
_pipe[PIPE_BLOOM_U].Init(pipeDesc);
|
||||
pipeDesc._shaderBranch = "#V";
|
||||
pipeDesc._renderPassHandle = _bloomHandles._rphV;
|
||||
_pipe[PIPE_BLOOM_V].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#HSsao", _ssaoHandles._rphH);
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#USsao", _ssaoHandles._rphU);
|
||||
pipeDesc._colorAttachWriteMasks[0] = "a";
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_SSAO_H].Init(pipeDesc);
|
||||
_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._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
|
@ -116,20 +129,30 @@ void Blur::OnSwapChainResized()
|
|||
{
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
VERUS_QREF_BLOOM;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSAO;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_cshMotionBlurExtra);
|
||||
_shader->FreeDescriptorSet(_cshMotionBlur);
|
||||
renderer->DeleteFramebuffer(_fbhMotionBlur);
|
||||
|
||||
_shader->FreeDescriptorSet(_cshAntiAliasingExtra);
|
||||
_shader->FreeDescriptorSet(_cshAntiAliasing);
|
||||
renderer->DeleteFramebuffer(_fbhAntiAliasing);
|
||||
|
||||
_shader->FreeDescriptorSet(_cshSsrExtra);
|
||||
_ssrHandles.FreeDescriptorSets(_shader);
|
||||
_ssrHandles.DeleteFramebuffers();
|
||||
|
||||
_ssaoHandles.FreeDescriptorSets(_shader);
|
||||
_ssaoHandles.DeleteFramebuffers();
|
||||
|
||||
_bloomHandles.FreeDescriptorSets(_shader);
|
||||
_bloomHandles.DeleteFramebuffers();
|
||||
|
||||
_tex.Done();
|
||||
}
|
||||
{
|
||||
|
@ -146,16 +169,22 @@ void Blur::OnSwapChainResized()
|
|||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
|
||||
_tex.Init(texDesc);
|
||||
|
||||
_bloomHandles._fbhH = renderer->CreateFramebuffer(_bloomHandles._rphH, { bloom.GetPongTexture() }, swapChainHalfWidth, swapChainHalfHeight);
|
||||
_bloomHandles._fbhU = renderer->CreateFramebuffer(_bloomHandles._rphU, { bloom.GetPongTexture() }, swapChainHalfWidth, swapChainHalfHeight);
|
||||
_bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, swapChainHalfWidth, swapChainHalfHeight);
|
||||
_bloomHandles._cshH = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
|
||||
_bloomHandles._cshU = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
|
||||
_bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() });
|
||||
|
||||
_ssaoHandles._fbhH = renderer->CreateFramebuffer(_ssaoHandles._rphH, { _tex }, swapChainWidth, swapChainHeight);
|
||||
_ssaoHandles._fbhU = renderer->CreateFramebuffer(_ssaoHandles._rphU, { _tex }, swapChainWidth, swapChainHeight);
|
||||
_ssaoHandles._fbhV = renderer->CreateFramebuffer(_ssaoHandles._rphV, { ssao.GetTexture() }, swapChainWidth, swapChainHeight);
|
||||
_ssaoHandles._cshH = _shader->BindDescriptorSetTextures(1, { ssao.GetTexture() });
|
||||
_ssaoHandles._cshU = _shader->BindDescriptorSetTextures(1, { ssao.GetTexture() });
|
||||
_ssaoHandles._cshV = _shader->BindDescriptorSetTextures(1, { _tex });
|
||||
|
||||
_ssrHandles._fbhU = renderer->CreateFramebuffer(_ssrHandles._rphU, { renderer.GetDS().GetLightAccDiffTexture() }, swapChainWidth, swapChainHeight);
|
||||
_ssrHandles._fbhV = renderer->CreateFramebuffer(_ssrHandles._rphV, { renderer.GetDS().GetLightAccSpecTexture() }, swapChainWidth, swapChainHeight);
|
||||
_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) });
|
||||
|
||||
_fbhAntiAliasing = renderer->CreateFramebuffer(_rphAntiAliasing, { renderer.GetDS().GetComposedTextureB() }, swapChainWidth, swapChainHeight);
|
||||
_cshAntiAliasing = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
|
||||
_cshAntiAliasingExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
|
||||
|
@ -170,28 +199,60 @@ void Blur::Generate()
|
|||
{
|
||||
}
|
||||
|
||||
void Blur::GenerateForBloom()
|
||||
void Blur::GenerateForBloom(bool forGodRays)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
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", &_bloomGodRaysRadius, 0.001f);
|
||||
}
|
||||
|
||||
const float radius = forGodRays ? _bloomGodRaysRadius : _bloomRadius;
|
||||
float samplesPerPixel = 1;
|
||||
int maxSamples = 1;
|
||||
switch (settings._gpuShaderQuality)
|
||||
{
|
||||
case App::Settings::Quality::low:
|
||||
samplesPerPixel = 0.125f;
|
||||
maxSamples = 8 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::medium:
|
||||
samplesPerPixel = 0.25f;
|
||||
maxSamples = 16 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::high:
|
||||
samplesPerPixel = 0.5f;
|
||||
maxSamples = 32 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::ultra:
|
||||
samplesPerPixel = 0.5f;
|
||||
maxSamples = 64 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize(), nullptr, 0.5f, 0).UniformBufferFormat();
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
|
||||
UpdateUniformBuffer(radius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_bloomHandles._rphH, _bloomHandles._fbhH, { bloom.GetPongTexture()->GetClearValue() });
|
||||
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_H]);
|
||||
cb->BindPipeline(_pipe[PIPE_BLOOM_U]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshH);
|
||||
cb->BindDescriptors(_shader, 1, _bloomHandles._cshU);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize(), nullptr, 0, 0.5f).UniformBufferFormat();
|
||||
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() });
|
||||
|
||||
|
@ -217,11 +278,11 @@ void Blur::GenerateForSsao()
|
|||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_ssaoHandles._rphH, _ssaoHandles._fbhH, { _tex->GetClearValue() });
|
||||
cb->BeginRenderPass(_ssaoHandles._rphU, _ssaoHandles._fbhU, { _tex->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSAO_H]);
|
||||
cb->BindPipeline(_pipe[PIPE_SSAO_U]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssaoHandles._cshH);
|
||||
cb->BindDescriptors(_shader, 1, _ssaoHandles._cshU);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
|
@ -240,6 +301,73 @@ void Blur::GenerateForSsao()
|
|||
_shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void Blur::GenerateForSsr()
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSR;
|
||||
|
||||
if (ssr.IsEditMode())
|
||||
{
|
||||
ImGui::DragFloat("SSR blur radius", &_ssrRadius, 0.001f);
|
||||
}
|
||||
|
||||
float samplesPerPixel = 1;
|
||||
int maxSamples = 1;
|
||||
switch (settings._gpuShaderQuality)
|
||||
{
|
||||
case App::Settings::Quality::low:
|
||||
samplesPerPixel = 0.25f;
|
||||
maxSamples = 8 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::medium:
|
||||
samplesPerPixel = 0.5f;
|
||||
maxSamples = 16 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::high:
|
||||
samplesPerPixel = 1;
|
||||
maxSamples = 32 - 1;
|
||||
break;
|
||||
case App::Settings::Quality::ultra:
|
||||
samplesPerPixel = 1;
|
||||
maxSamples = 64 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_shader->BeginBindDescriptors();
|
||||
{
|
||||
cb->BeginRenderPass(_ssrHandles._rphU, _ssrHandles._fbhU, { renderer.GetDS().GetLightAccDiffTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSR_U]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssrHandles._cshU);
|
||||
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
|
||||
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);
|
||||
{
|
||||
cb->BeginRenderPass(_ssrHandles._rphV, _ssrHandles._fbhV, { renderer.GetDS().GetLightAccSpecTexture()->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_SSR_V]);
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _ssrHandles._cshV);
|
||||
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
||||
_shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void Blur::GenerateForAntiAliasing()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -294,3 +422,16 @@ void Blur::GenerateForMotionBlur()
|
|||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
}
|
||||
|
||||
void Blur::UpdateUniformBuffer(float radius, int sampleCount, int texSize, float samplesPerPixel, int maxSamples)
|
||||
{
|
||||
if (!sampleCount)
|
||||
{
|
||||
sampleCount = static_cast<int>(texSize * (radius * 2) * samplesPerPixel);
|
||||
sampleCount = Math::Clamp(sampleCount, 3, maxSamples);
|
||||
}
|
||||
s_ubBlurFS._radius_invRadius_stride.x = radius;
|
||||
s_ubBlurFS._radius_invRadius_stride.y = 1 / radius;
|
||||
s_ubBlurFS._radius_invRadius_stride.z = radius * 2 / (sampleCount - 1);
|
||||
s_ubBlurFS._sampleCount = sampleCount;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,14 @@ namespace verus
|
|||
|
||||
enum PIPE
|
||||
{
|
||||
PIPE_H,
|
||||
PIPE_U,
|
||||
PIPE_V,
|
||||
PIPE_BLOOM_H,
|
||||
PIPE_BLOOM_U,
|
||||
PIPE_BLOOM_V,
|
||||
PIPE_SSAO_H,
|
||||
PIPE_SSAO_U,
|
||||
PIPE_SSAO_V,
|
||||
PIPE_SSR_U,
|
||||
PIPE_SSR_V,
|
||||
PIPE_AA,
|
||||
PIPE_MOTION_BLUR,
|
||||
PIPE_COUNT
|
||||
|
@ -24,11 +26,11 @@ namespace verus
|
|||
|
||||
struct Handles
|
||||
{
|
||||
CGI::RPHandle _rphH;
|
||||
CGI::RPHandle _rphU;
|
||||
CGI::RPHandle _rphV;
|
||||
CGI::FBHandle _fbhH;
|
||||
CGI::FBHandle _fbhU;
|
||||
CGI::FBHandle _fbhV;
|
||||
CGI::CSHandle _cshH;
|
||||
CGI::CSHandle _cshU;
|
||||
CGI::CSHandle _cshV;
|
||||
|
||||
void FreeDescriptorSets(CGI::ShaderPtr shader);
|
||||
|
@ -44,6 +46,8 @@ namespace verus
|
|||
CGI::TexturePwn _tex;
|
||||
Handles _bloomHandles;
|
||||
Handles _ssaoHandles;
|
||||
Handles _ssrHandles;
|
||||
CGI::CSHandle _cshSsrExtra;
|
||||
CGI::RPHandle _rphAntiAliasing;
|
||||
CGI::FBHandle _fbhAntiAliasing;
|
||||
CGI::CSHandle _cshAntiAliasing;
|
||||
|
@ -52,6 +56,9 @@ namespace verus
|
|||
CGI::FBHandle _fbhMotionBlur;
|
||||
CGI::CSHandle _cshMotionBlur;
|
||||
CGI::CSHandle _cshMotionBlurExtra;
|
||||
float _bloomRadius = 0.015f;
|
||||
float _bloomGodRaysRadius = 0.004f;
|
||||
float _ssrRadius = 0.03f;
|
||||
|
||||
public:
|
||||
Blur();
|
||||
|
@ -63,10 +70,13 @@ namespace verus
|
|||
void OnSwapChainResized();
|
||||
|
||||
void Generate();
|
||||
void GenerateForBloom();
|
||||
void GenerateForBloom(bool forGodRays);
|
||||
void GenerateForSsao();
|
||||
void GenerateForSsr();
|
||||
void GenerateForAntiAliasing();
|
||||
void GenerateForMotionBlur();
|
||||
|
||||
void UpdateUniformBuffer(float radius, int sampleCount, int texSize = 0, float samplesPerPixel = 1, int maxSamples = 61);
|
||||
};
|
||||
VERUS_TYPEDEFS(Blur);
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ namespace verus
|
|||
{
|
||||
Effects::Bloom::Make();
|
||||
Effects::Ssao::Make();
|
||||
Effects::Ssr::Make();
|
||||
Effects::Blur::Make();
|
||||
}
|
||||
void Free_Effects()
|
||||
{
|
||||
Effects::Blur::Free();
|
||||
Effects::Ssr::Free();
|
||||
Effects::Ssao::Free();
|
||||
Effects::Bloom::Free();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Blur.h"
|
||||
#include "Bloom.h"
|
||||
#include "Ssao.h"
|
||||
#include "Ssr.h"
|
||||
#include "Particles.h"
|
||||
|
||||
namespace verus
|
||||
|
|
|
@ -64,7 +64,9 @@ void Ssao::OnSwapChainResized()
|
|||
{
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
|
@ -79,7 +81,12 @@ void Ssao::OnSwapChainResized()
|
|||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
|
||||
_tex[TEX_GEN_AO].Init(texDesc);
|
||||
_fbh = renderer->CreateFramebuffer(_rph, { _tex[TEX_GEN_AO] }, renderer.GetSwapChainWidth(), renderer.GetSwapChainHeight());
|
||||
_csh = _shader->BindDescriptorSetTextures(1, { _tex[TEX_RAND_NORMALS], renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
_tex[TEX_RAND_NORMALS],
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil()
|
||||
});
|
||||
}
|
||||
renderer.GetDS().InitBySsao(_tex[TEX_GEN_AO]);
|
||||
}
|
||||
|
@ -89,6 +96,15 @@ void Ssao::Generate()
|
|||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
if (_editMode)
|
||||
{
|
||||
ImGui::DragFloat("SSAO smallRad", &_smallRad, 0.001f);
|
||||
ImGui::DragFloat("SSAO largeRad", &_largeRad, 0.001f);
|
||||
ImGui::DragFloat("SSAO weightScale", &_weightScale, 0.001f);
|
||||
ImGui::DragFloat("SSAO weightBias", &_weightBias, 0.001f);
|
||||
ImGui::Checkbox("SSAO blur", &_blur);
|
||||
}
|
||||
|
||||
Scene::RCamera cam = *sm.GetCamera();
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
@ -99,6 +115,10 @@ void Ssao::Generate()
|
|||
s_ubSsaoFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubSsaoFS._camScale.x = cam.GetFovScale() / cam.GetAspectRatio();
|
||||
s_ubSsaoFS._camScale.y = -cam.GetFovScale();
|
||||
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.x = _smallRad;
|
||||
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.y = _largeRad;
|
||||
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() });
|
||||
|
||||
|
@ -111,7 +131,8 @@ void Ssao::Generate()
|
|||
|
||||
cb->EndRenderPass();
|
||||
|
||||
Blur::I().GenerateForSsao();
|
||||
if (_blur)
|
||||
Blur::I().GenerateForSsao();
|
||||
}
|
||||
|
||||
void Ssao::UpdateRandNormalsTexture()
|
||||
|
|
|
@ -25,6 +25,12 @@ namespace verus
|
|||
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();
|
||||
|
@ -41,6 +47,9 @@ namespace verus
|
|||
void UpdateRandNormalsTexture();
|
||||
|
||||
CGI::TexturePtr GetTexture() const;
|
||||
|
||||
bool IsEditMode() const { return _editMode; }
|
||||
void ToggleEditMode() { _editMode = !_editMode; }
|
||||
};
|
||||
VERUS_TYPEDEFS(Ssao);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "verus.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Effects;
|
||||
|
||||
Ssr::UB_SsrVS Ssr::s_ubSsrVS;
|
||||
Ssr::UB_SsrFS Ssr::s_ubSsrFS;
|
||||
|
||||
Ssr::Ssr()
|
||||
{
|
||||
}
|
||||
|
||||
Ssr::~Ssr()
|
||||
{
|
||||
Done();
|
||||
}
|
||||
|
||||
void Ssr::Init()
|
||||
{
|
||||
VERUS_INIT();
|
||||
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)
|
||||
})
|
||||
},
|
||||
{});
|
||||
|
||||
_shader.Init("[Shaders]:Ssr.hlsl");
|
||||
_shader->CreateDescriptorSet(0, &s_ubSsrVS, sizeof(s_ubSsrVS), 1, {}, CGI::ShaderStageFlags::vs);
|
||||
_shader->CreateDescriptorSet(1, &s_ubSsrFS, sizeof(s_ubSsrFS), 1,
|
||||
{
|
||||
CGI::Sampler::linearClampMipN, // Color
|
||||
CGI::Sampler::nearestClampMipN, // Normal
|
||||
CGI::Sampler::linearClampMipN, // Depth
|
||||
CGI::Sampler::linearClampMipN // EnvMap
|
||||
}, 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);
|
||||
}
|
||||
|
||||
OnSwapChainResized();
|
||||
}
|
||||
|
||||
void Ssr::Done()
|
||||
{
|
||||
VERUS_DONE(Ssr);
|
||||
}
|
||||
|
||||
void Ssr::OnSwapChainResized()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SSAO;
|
||||
VERUS_QREF_ATMO;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
}
|
||||
{
|
||||
_fbh = renderer->CreateFramebuffer(_rph,
|
||||
{
|
||||
renderer.GetDS().GetLightAccSpecTexture(),
|
||||
ssao.GetTexture()
|
||||
},
|
||||
renderer.GetSwapChainWidth(), renderer.GetSwapChainHeight());
|
||||
if (atmo.GetCubeMap().GetColorTexture())
|
||||
{
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetDS().GetComposedTextureA(),
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil(),
|
||||
atmo.GetCubeMap().GetColorTexture()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ssr::Generate()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
VERUS_QREF_SSAO;
|
||||
VERUS_QREF_ATMO;
|
||||
|
||||
if (!_csh.IsSet())
|
||||
{
|
||||
if (atmo.GetCubeMap().GetColorTexture())
|
||||
{
|
||||
_csh = _shader->BindDescriptorSetTextures(1,
|
||||
{
|
||||
renderer.GetDS().GetComposedTextureA(),
|
||||
renderer.GetDS().GetGBuffer(1),
|
||||
renderer.GetTexDepthStencil(),
|
||||
atmo.GetCubeMap().GetColorTexture()
|
||||
});
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (_editMode)
|
||||
{
|
||||
ImGui::DragFloat("SSR radius", &_radius, 0.01f);
|
||||
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();
|
||||
|
||||
const Matrix4 matPTex = Matrix4(Math::ToUVMatrix()) * cam.GetMatrixP();
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
s_ubSsrVS._matW = Math::QuadMatrix().UniformBufferFormat();
|
||||
s_ubSsrVS._matV = Math::ToUVMatrix().UniformBufferFormat();
|
||||
s_ubSsrFS._matInvV = cam.GetMatrixVi().UniformBufferFormat();
|
||||
s_ubSsrFS._matPTex = matPTex.UniformBufferFormat();
|
||||
s_ubSsrFS._matInvP = cam.GetMatrixPi().UniformBufferFormat();
|
||||
s_ubSsrFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
|
||||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.x = _radius;
|
||||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.y = _depthBias;
|
||||
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.z = _thickness;
|
||||
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->BindPipeline(_pipe);
|
||||
_shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _csh);
|
||||
_shader->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
|
||||
if (_blur)
|
||||
Blur::I().GenerateForSsr();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Effects
|
||||
{
|
||||
class Ssr : public Singleton<Ssr>, public Object
|
||||
{
|
||||
#include "../Shaders/Ssr.inc.hlsl"
|
||||
|
||||
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 = 3;
|
||||
float _depthBias = 0.03f;
|
||||
float _thickness = 0.25f;
|
||||
float _equalizeDist = 16;
|
||||
bool _blur = true;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
Ssr();
|
||||
~Ssr();
|
||||
|
||||
void Init();
|
||||
void Done();
|
||||
|
||||
void OnSwapChainResized();
|
||||
|
||||
void Generate();
|
||||
|
||||
bool IsEditMode() const { return _editMode; }
|
||||
void ToggleEditMode() { _editMode = !_editMode; }
|
||||
};
|
||||
VERUS_TYPEDEFS(Ssr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,480 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "verus.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Extra;
|
||||
|
||||
// BaseConvert::Mesh::UberVertex:
|
||||
|
||||
BaseConvert::Mesh::UberVertex::UberVertex()
|
||||
{
|
||||
VERUS_ZERO_MEM(_bw);
|
||||
VERUS_ZERO_MEM(_bi);
|
||||
}
|
||||
|
||||
bool BaseConvert::Mesh::UberVertex::operator==(RcUberVertex that) const
|
||||
{
|
||||
const float e = 0.001f;
|
||||
return
|
||||
glm::all(glm::epsilonEqual(_pos, that._pos, e)) &&
|
||||
glm::all(glm::epsilonEqual(_nrm, that._nrm, e)) &&
|
||||
glm::all(glm::epsilonEqual(_tc0, that._tc0, e)) &&
|
||||
glm::all(glm::epsilonEqual(_tc1, that._tc1, e));
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::UberVertex::Add(float weight, UINT32 index)
|
||||
{
|
||||
if (_currentWeight < 4) // Space for one more?
|
||||
{
|
||||
_bw[_currentWeight] = weight;
|
||||
_bi[_currentWeight] = index;
|
||||
_currentWeight++;
|
||||
}
|
||||
else // No space left - check the smallest weight:
|
||||
{
|
||||
float* pMin = std::min_element(_bw, _bw + 4);
|
||||
if (weight > *pMin)
|
||||
{
|
||||
const int i = Utils::Cast32(std::distance(_bw, pMin));
|
||||
_bw[i] = weight;
|
||||
_bi[i] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::UberVertex::CompileBits(UINT32& ww, UINT32& ii) const
|
||||
{
|
||||
ww = 0;
|
||||
ii = 0;
|
||||
|
||||
int ibw[4] = {};
|
||||
VERUS_FOR(i, _currentWeight)
|
||||
ibw[i] = glm::clamp(int(_bw[i] * 255 + 0.5f), 0, 255);
|
||||
ibw[0] = glm::clamp(255 - ibw[1] - ibw[2] - ibw[3], 0, 255);
|
||||
|
||||
// Make sure that the sum is 255:
|
||||
int at = 0;
|
||||
int sum = ibw[0] + ibw[1] + ibw[2] + ibw[3];
|
||||
while (sum > 255)
|
||||
{
|
||||
if (ibw[at] > 0)
|
||||
{
|
||||
sum--;
|
||||
ibw[at]--;
|
||||
}
|
||||
at = (at + 1) & 0x3;
|
||||
}
|
||||
|
||||
VERUS_FOR(i, _currentWeight)
|
||||
{
|
||||
ww |= ibw[i] << (i << 3);
|
||||
ii |= _bi[i] << (i << 3);
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 BaseConvert::Mesh::UberVertex::GetDominantIndex()
|
||||
{
|
||||
_bw[0] = 1 - _bw[1] - _bw[2] - _bw[3];
|
||||
const int i = Utils::Cast32(std::distance(_bw, std::max_element(_bw, _bw + 4)));
|
||||
return _bi[i];
|
||||
}
|
||||
|
||||
// BaseConvert::Mesh::Aabb:
|
||||
|
||||
void BaseConvert::Mesh::Aabb::Reset()
|
||||
{
|
||||
_mn = glm::vec3(+FLT_MAX);
|
||||
_mx = glm::vec3(-FLT_MAX);
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::Aabb::Include(const glm::vec3& point)
|
||||
{
|
||||
_mn = glm::min(_mn, point);
|
||||
_mx = glm::max(_mx, point);
|
||||
}
|
||||
|
||||
glm::vec3 BaseConvert::Mesh::Aabb::GetExtents() const
|
||||
{
|
||||
return (_mx - _mn) * 0.5f;
|
||||
}
|
||||
|
||||
// BaseConvert::Mesh:
|
||||
|
||||
BaseConvert::Mesh::Mesh(BaseConvert* pBaseConvert) : _pBaseConvert(pBaseConvert)
|
||||
{
|
||||
_matBoneAxis = glm::rotate(glm::radians(-90.f), glm::vec3(0, 0, 1));
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
VERUS_FOR(j, 4)
|
||||
_matBoneAxis[i][j] = glm::round(_matBoneAxis[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
BaseConvert::Mesh::~Mesh()
|
||||
{
|
||||
}
|
||||
|
||||
BaseConvert::Mesh::PBone BaseConvert::Mesh::FindBone(CSZ name)
|
||||
{
|
||||
for (auto& bone : _vBones)
|
||||
{
|
||||
if (bone._name == name)
|
||||
return &bone;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::Optimize()
|
||||
{
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": Optimize";
|
||||
_pBaseConvert->OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
// Weld vertices, remove duplicates:
|
||||
int similarVertCount = 0;
|
||||
int degenerateFaceCount = 0;
|
||||
Vector<UberVertex> vVbOpt; // This will not contain equal vertices.
|
||||
Vector<Face> vIbOpt; // This can get smaller than current IB, if there are zero-area triangles.
|
||||
vVbOpt.reserve(_vertCount);
|
||||
vIbOpt.reserve(_faceCount);
|
||||
VERUS_FOR(face, _faceCount) // For each triangle:
|
||||
{
|
||||
_pBaseConvert->OnProgress(float(face) / _faceCount * 100);
|
||||
Face newFace;
|
||||
int pushedCount = 0;
|
||||
VERUS_FOR(i, 3) // For each vertex in triangle:
|
||||
{
|
||||
RcUberVertex test = _vUberVerts[_vFaces[face]._indices[i]]; // Fetch vertex.
|
||||
const auto similar = std::find(vVbOpt.begin(), vVbOpt.end(), test);
|
||||
const int index = (similar == vVbOpt.end()) ? -1 : Utils::Cast32(std::distance(vVbOpt.begin(), similar));
|
||||
if (index < 0) // No similar vertex found.
|
||||
{
|
||||
newFace._indices[i] = Utils::Cast32(vVbOpt.size());
|
||||
vVbOpt.push_back(test);
|
||||
pushedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFace._indices[i] = index;
|
||||
similarVertCount++;
|
||||
}
|
||||
}
|
||||
if (newFace._indices[0] != newFace._indices[1] &&
|
||||
newFace._indices[1] != newFace._indices[2] &&
|
||||
newFace._indices[2] != newFace._indices[0])
|
||||
{
|
||||
vIbOpt.push_back(newFace); // Add triangle, if it's area is more than zero.
|
||||
}
|
||||
else
|
||||
{
|
||||
degenerateFaceCount++;
|
||||
vVbOpt.resize(vVbOpt.size() - pushedCount); // Rollback.
|
||||
}
|
||||
}
|
||||
_vUberVerts.assign(vVbOpt.begin(), vVbOpt.end());
|
||||
_vFaces.assign(vIbOpt.begin(), vIbOpt.end());
|
||||
_vertCount = Utils::Cast32(_vUberVerts.size());
|
||||
_faceCount = Utils::Cast32(_vFaces.size());
|
||||
StringStream ssWeldReport;
|
||||
ssWeldReport << "Weld report: " << similarVertCount << " similar vertices removed, " << degenerateFaceCount << " degenerate faces removed";
|
||||
_pBaseConvert->OnProgressText(_C(ssWeldReport.str()));
|
||||
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": (" << _vertCount << " vertices, " << _faceCount << " faces)";
|
||||
_pBaseConvert->OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
// Optimize (using AMD Tootle):
|
||||
StringStream ss2;
|
||||
ss2 << _name << ": Optimize (Tootle)";
|
||||
_pBaseConvert->OnProgressText(_C(ss2.str()));
|
||||
if (_pBaseConvert->_pDelegate)
|
||||
_pBaseConvert->_pDelegate->BaseConvert_Optimize(_vUberVerts, _vFaces);
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::ComputeTangentSpace()
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": ComputeTangentSpace";
|
||||
_pBaseConvert->OnProgressText(_C(ss.str()));
|
||||
|
||||
Vector<glm::vec3> vPos, vN, vTan, vBin;
|
||||
vPos.resize(_vertCount);
|
||||
|
||||
Vector<glm::vec2> vTc0;
|
||||
vTc0.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
vPos[i] = _vUberVerts[i]._pos;
|
||||
vTc0[i] = _vUberVerts[i]._tc0;
|
||||
}
|
||||
|
||||
Vector<UINT16> vIndices;
|
||||
vIndices.resize(_faceCount * 3);
|
||||
VERUS_FOR(i, _faceCount)
|
||||
{
|
||||
vIndices[i * 3 + 0] = _vFaces[i]._indices[0];
|
||||
vIndices[i * 3 + 1] = _vFaces[i]._indices[1];
|
||||
vIndices[i * 3 + 2] = _vFaces[i]._indices[2];
|
||||
}
|
||||
|
||||
if (_found & Found::normals)
|
||||
{
|
||||
vN.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
vN[i] = _vUberVerts[i]._nrm;
|
||||
}
|
||||
else
|
||||
{
|
||||
Math::NormalComputer::ComputeNormals(vIndices, vPos, vN, _pBaseConvert->UseAreaBasedNormals());
|
||||
}
|
||||
|
||||
_pBaseConvert->OnProgress(50);
|
||||
Math::NormalComputer::ComputeTangentSpace(vIndices, vPos, vN, vTc0, vTan, vBin);
|
||||
|
||||
_vZipNormal.resize(_vertCount);
|
||||
_vZipTan.resize(_vertCount);
|
||||
_vZipBin.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount) // Compress them all:
|
||||
{
|
||||
Convert::SnormToSint8(&vN[i].x, &_vZipNormal[i]._x, 3);
|
||||
Convert::SnormToSint8(&vTan[i].x, &_vZipTan[i]._x, 3);
|
||||
Convert::SnormToSint8(&vBin[i].x, &_vZipBin[i]._x, 3);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::Compress()
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": Compress";
|
||||
_pBaseConvert->OnProgressText(_C(ss.str()));
|
||||
|
||||
Mesh::Aabb aabb;
|
||||
glm::vec3 extents, scale, bias;
|
||||
|
||||
// Compress position:
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(_vUberVerts[i]._pos);
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(_posScale, _posBias, extents, aabb._mn);
|
||||
_vZipPos.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec3Short pos;
|
||||
glm::vec3 v(_vUberVerts[i]._pos);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
pos._x = short(v.x);
|
||||
pos._y = short(v.y);
|
||||
pos._z = short(v.z);
|
||||
_vZipPos.push_back(pos);
|
||||
}
|
||||
|
||||
// Compress tc0:
|
||||
_pBaseConvert->OnProgress(50);
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc0, 0));
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(scale, bias, extents, aabb._mn);
|
||||
_tc0Scale = glm::vec2(scale);
|
||||
_tc0Bias = glm::vec2(bias);
|
||||
_vZipTc0.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec2Short tc;
|
||||
glm::vec3 v(_vUberVerts[i]._tc0, 0);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
tc._u = short(v.x);
|
||||
tc._v = short(v.y);
|
||||
_vZipTc0.push_back(tc);
|
||||
}
|
||||
|
||||
if (!(_found & Found::texcoordExtra))
|
||||
return;
|
||||
|
||||
// Compress tc1:
|
||||
_pBaseConvert->OnProgress(75);
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc1, 0));
|
||||
glm::vec2 normBias(-aabb._mn);
|
||||
glm::vec2 normScale(aabb._mx - aabb._mn);
|
||||
normScale.x = 1 / normScale.x;
|
||||
normScale.y = 1 / normScale.y;
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
_vUberVerts[i]._tc1 = (_vUberVerts[i]._tc1 + normBias) * normScale;
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc1, 0));
|
||||
}
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(scale, bias, extents, aabb._mn);
|
||||
_tc1Scale = glm::vec2(scale);
|
||||
_tc1Bias = glm::vec2(bias);
|
||||
_vZipTc1.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec2Short tc;
|
||||
glm::vec3 v((_vUberVerts[i]._tc1), 0);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
tc._u = short(v.x);
|
||||
tc._v = short(v.y);
|
||||
_vZipTc1.push_back(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseConvert::Mesh::SerializeX3D3(IO::RFile file)
|
||||
{
|
||||
if (!(_found & Found::vertsAndUVs))
|
||||
return;
|
||||
|
||||
Optimize();
|
||||
ComputeTangentSpace();
|
||||
Compress();
|
||||
|
||||
file.WriteText("<X3D>");
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<VN>");
|
||||
file.WriteString("3.0");
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<IX>");
|
||||
file.BeginBlock();
|
||||
file.WriteString(_C(std::to_string(_faceCount)));
|
||||
VERUS_FOR(i, _faceCount)
|
||||
file.Write(&_vFaces[i], 6);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<VX>");
|
||||
file.BeginBlock();
|
||||
file.WriteString(_C(std::to_string(_vertCount)));
|
||||
file.Write(&_posScale, 12);
|
||||
file.Write(&_posBias, 12);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipPos[i], 6);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<NL>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipNormal[i], 3);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<TS>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
file.Write(&_vZipTan[i], 3);
|
||||
file.Write(&_vZipBin[i], 3);
|
||||
}
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<T0>");
|
||||
file.BeginBlock();
|
||||
file.Write(&_tc0Scale, 8);
|
||||
file.Write(&_tc0Bias, 8);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipTc0[i], 4);
|
||||
file.EndBlock();
|
||||
|
||||
if (_found & Found::texcoordExtra)
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<T1>");
|
||||
file.BeginBlock();
|
||||
file.Write(&_tc1Scale, 8);
|
||||
file.Write(&_tc1Bias, 8);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipTc1[i], 4);
|
||||
file.EndBlock();
|
||||
}
|
||||
|
||||
if (_boneCount > 0)
|
||||
{
|
||||
// Must be the same order as in X file! Do not sort.
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<BH>");
|
||||
file.BeginBlock();
|
||||
const BYTE boneInfo = BYTE(_boneCount);
|
||||
file << boneInfo;
|
||||
VERUS_FOR(i, _boneCount)
|
||||
{
|
||||
file.WriteString(_C(_vBones[i]._name));
|
||||
file.WriteString(_C(_vBones[i]._parentName));
|
||||
file.Write(&_vBones[i]._matOffset, 64);
|
||||
}
|
||||
file.EndBlock();
|
||||
|
||||
StringStream ssDebug;
|
||||
VERUS_FOR(i, _boneCount)
|
||||
ssDebug << "Bone: " << _vBones[i]._name << "; Parent: " << _vBones[i]._parentName << ";" VERUS_CRNL;
|
||||
String pathname = _C(_pBaseConvert->GetPathname());
|
||||
Str::ReplaceExtension(pathname, "_Bones.txt");
|
||||
IO::File fileDebug;
|
||||
if (fileDebug.Open(_C(pathname), "wb"))
|
||||
fileDebug.Write(_C(ssDebug.str()), ssDebug.str().length());
|
||||
|
||||
if (!_pBaseConvert->UseRigidBones())
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<SS>");
|
||||
file.BeginBlock();
|
||||
UINT32 ww, ii;
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
_vUberVerts[i].CompileBits(ww, ii);
|
||||
file << ww << ii;
|
||||
}
|
||||
file.EndBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<SR>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file << BYTE(_vUberVerts[i].GetDominantIndex());
|
||||
file.EndBlock();
|
||||
}
|
||||
}
|
||||
|
||||
StringStream ss;
|
||||
ss << _name << ": Done";
|
||||
_pBaseConvert->OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
bool BaseConvert::Mesh::IsCopyOf(RMesh that)
|
||||
{
|
||||
if (_vertCount != that._vertCount)
|
||||
return false;
|
||||
if (!std::equal(_vUberVerts.begin(), _vUberVerts.end(), that._vUberVerts.begin(), [](RcUberVertex a, RcUberVertex b)
|
||||
{
|
||||
const glm::vec3 dpos = a._pos - b._pos;
|
||||
const glm::vec2 dtc0 = a._tc0 - b._tc0;
|
||||
const float d = 0.01f * 0.01f;
|
||||
return glm::dot(dpos, dpos) < d && glm::dot(dtc0, dtc0) < d;
|
||||
}))
|
||||
return false;
|
||||
_copyOf = that._name;
|
||||
return true;
|
||||
}
|
||||
|
||||
// BaseConvert:
|
||||
|
||||
BaseConvert::BaseConvert()
|
||||
{
|
||||
}
|
||||
|
||||
BaseConvert::~BaseConvert()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseConvert::OnProgress(float percent)
|
||||
{
|
||||
if (_pDelegate)
|
||||
_pDelegate->BaseConvert_OnProgress(percent);
|
||||
}
|
||||
|
||||
void BaseConvert::OnProgressText(CSZ txt)
|
||||
{
|
||||
if (_pDelegate)
|
||||
_pDelegate->BaseConvert_OnProgressText(txt);
|
||||
}
|
|
@ -5,10 +5,13 @@ namespace verus
|
|||
{
|
||||
namespace Extra
|
||||
{
|
||||
struct FileParserDelegate;
|
||||
struct BaseConvertDelegate;
|
||||
|
||||
class FileParser : public Singleton<FileParser>, public Object
|
||||
class BaseConvert
|
||||
{
|
||||
protected:
|
||||
BaseConvertDelegate* _pDelegate = nullptr;
|
||||
|
||||
public:
|
||||
class Mesh
|
||||
{
|
||||
|
@ -92,6 +95,7 @@ namespace verus
|
|||
glm::vec3 GetExtents() const;
|
||||
};
|
||||
|
||||
BaseConvert* _pBaseConvert = nullptr;
|
||||
String _name;
|
||||
String _copyOf;
|
||||
Vector<UberVertex> _vUberVerts;
|
||||
|
@ -119,7 +123,7 @@ namespace verus
|
|||
int _materialIndex = 0;
|
||||
|
||||
public:
|
||||
Mesh();
|
||||
Mesh(BaseConvert* pBaseConvert);
|
||||
~Mesh();
|
||||
|
||||
PBone FindBone(CSZ name);
|
||||
|
@ -167,167 +171,28 @@ namespace verus
|
|||
};
|
||||
VERUS_TYPEDEFS(Mesh);
|
||||
|
||||
struct Desc
|
||||
{
|
||||
glm::vec3 _bias = glm::vec3(0);
|
||||
float _scaleFactor = 1;
|
||||
float _angle = 0;
|
||||
float _areaBasedNormals = 0;
|
||||
bool _useRigidBones = false;
|
||||
bool _convertAsLevel = false;
|
||||
bool _useDefaultMaterial = false;
|
||||
bool _rightHanded = true;
|
||||
};
|
||||
VERUS_TYPEDEFS(Desc);
|
||||
|
||||
private:
|
||||
struct Frame
|
||||
{
|
||||
String _name;
|
||||
String _parent;
|
||||
glm::mat4 _mat;
|
||||
glm::mat4 _matAcc;
|
||||
};
|
||||
VERUS_TYPEDEFS(Frame);
|
||||
|
||||
struct SubKey
|
||||
{
|
||||
Quat _q;
|
||||
bool _redundant = false;
|
||||
};
|
||||
|
||||
struct AnimationKey
|
||||
{
|
||||
Vector<SubKey> _vFrame;
|
||||
int _type = 0;
|
||||
int _logicFrameCount = 0;
|
||||
|
||||
void DetectRedundantFrames(float threshold = 0.001f);
|
||||
};
|
||||
|
||||
struct Animation
|
||||
{
|
||||
String _name;
|
||||
Vector<AnimationKey> _vAnimKeys;
|
||||
};
|
||||
|
||||
struct AnimationSet
|
||||
{
|
||||
String _name;
|
||||
Vector<Animation> _vAnimations;
|
||||
|
||||
void CleanUp();
|
||||
};
|
||||
|
||||
struct Material
|
||||
{
|
||||
String _name;
|
||||
String _copyOf;
|
||||
String _textureFilename;
|
||||
glm::vec4 _faceColor;
|
||||
glm::vec3 _specularColor;
|
||||
glm::vec3 _emissiveColor;
|
||||
float _power = 1;
|
||||
|
||||
bool IsCopyOf(const Material& that)
|
||||
{
|
||||
const float e = 0.01f;
|
||||
return
|
||||
_textureFilename == that._textureFilename &&
|
||||
glm::all(glm::epsilonEqual(_faceColor, that._faceColor, e)) &&
|
||||
glm::all(glm::epsilonEqual(_specularColor, that._specularColor, e)) &&
|
||||
glm::all(glm::epsilonEqual(_emissiveColor, that._emissiveColor, e)) &&
|
||||
glm::epsilonEqual(_power, that._power, e);
|
||||
}
|
||||
};
|
||||
VERUS_TYPEDEFS(Material);
|
||||
|
||||
typedef Map<String, String> TMapBoneNames;
|
||||
typedef Map<String, Frame> TMapFrames;
|
||||
|
||||
Transform3 _matRoot;
|
||||
TMapBoneNames _mapBoneNames;
|
||||
String _currentMesh;
|
||||
String _pathname;
|
||||
Vector<char> _vData;
|
||||
const char* _pData;
|
||||
const char* _pDataBegin;
|
||||
Vector<PMesh> _vMesh;
|
||||
std::unique_ptr<Mesh> _pCurrentMesh;
|
||||
TMapFrames _mapFrames;
|
||||
Vector<Frame> _stackFrames;
|
||||
Vector<AnimationSet> _vAnimSets;
|
||||
Vector<Material> _vMaterials;
|
||||
FileParserDelegate* _pDelegate;
|
||||
std::future<void> _future;
|
||||
Desc _desc;
|
||||
int _depth = 0;
|
||||
StringStream _ssDebug;
|
||||
|
||||
public:
|
||||
FileParser();
|
||||
~FileParser();
|
||||
|
||||
void Init(FileParserDelegate* p, RcDesc desc);
|
||||
void Done();
|
||||
|
||||
void LoadBoneNames(CSZ pathname);
|
||||
void ParseData(CSZ pathname);
|
||||
void SerializeAll(CSZ pathname);
|
||||
|
||||
void AsyncRun(CSZ pathname);
|
||||
void AsyncJoin();
|
||||
bool IsAsyncStarted() const;
|
||||
bool IsAsyncFinished() const;
|
||||
|
||||
private:
|
||||
void LoadFromFile(CSZ pathname);
|
||||
|
||||
void StreamReadUntil(SZ dest, int destSize, CSZ separator);
|
||||
void StreamSkipWhitespace();
|
||||
void StreamSkipUntil(char c);
|
||||
|
||||
void FixBones();
|
||||
|
||||
void ParseBlockRecursive(CSZ type, CSZ blockName);
|
||||
void ParseBlockData_Mesh();
|
||||
void ParseBlockData_MeshTextureCoords();
|
||||
void ParseBlockData_MeshNormals();
|
||||
void ParseBlockData_FVFData(bool declData);
|
||||
void ParseBlockData_XSkinMeshHeader();
|
||||
void ParseBlockData_SkinWeights();
|
||||
void ParseBlockData_Frame(CSZ blockName);
|
||||
void ParseBlockData_FrameTransformMatrix();
|
||||
void ParseBlockData_AnimationSet(CSZ blockName);
|
||||
void ParseBlockData_Animation(CSZ blockName);
|
||||
void ParseBlockData_AnimationKey();
|
||||
void ParseBlockData_Material();
|
||||
void ParseBlockData_TextureFilename();
|
||||
void ParseBlockData_MeshMaterialList();
|
||||
|
||||
PMesh AddMesh(PMesh pMesh);
|
||||
PMesh FindMesh(CSZ name);
|
||||
void DeleteAll();
|
||||
BaseConvert();
|
||||
~BaseConvert();
|
||||
|
||||
void OnProgress(float percent);
|
||||
void OnProgressText(CSZ txt);
|
||||
|
||||
void Debug(CSZ txt);
|
||||
|
||||
void DetectMaterialCopies();
|
||||
String GetXmlMaterial(int i);
|
||||
String RenameBone(CSZ name);
|
||||
virtual bool UseAreaBasedNormals() { return false; }
|
||||
virtual bool UseRigidBones() { return false; }
|
||||
virtual Str GetPathname() { return ""; }
|
||||
};
|
||||
VERUS_TYPEDEFS(FileParser);
|
||||
VERUS_TYPEDEFS(BaseConvert);
|
||||
|
||||
struct FileParserDelegate
|
||||
struct BaseConvertDelegate
|
||||
{
|
||||
virtual void FileParser_OnProgress(float percent) = 0;
|
||||
virtual void FileParser_OnProgressText(CSZ txt) = 0;
|
||||
virtual void FileParser_Optimize(
|
||||
Vector<FileParser::Mesh::UberVertex>& vVb,
|
||||
Vector<FileParser::Mesh::Face>& vIb) = 0;
|
||||
virtual bool FileParser_CanOverwriteFile(CSZ filename) { return true; }
|
||||
virtual void BaseConvert_OnProgress(float percent) = 0;
|
||||
virtual void BaseConvert_OnProgressText(CSZ txt) = 0;
|
||||
virtual void BaseConvert_Optimize(
|
||||
Vector<BaseConvert::Mesh::UberVertex>& vVB,
|
||||
Vector<BaseConvert::Mesh::Face>& vIB) = 0;
|
||||
virtual bool BaseConvert_CanOverwriteFile(CSZ filename) { return true; }
|
||||
};
|
||||
VERUS_TYPEDEFS(BaseConvertDelegate);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "verus.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Extra;
|
||||
|
||||
ConvertGLTF::ConvertGLTF()
|
||||
{
|
||||
}
|
||||
|
||||
ConvertGLTF::~ConvertGLTF()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Extra
|
||||
{
|
||||
class ConvertGLTF : public Singleton<ConvertGLTF>, public Object, public BaseConvert
|
||||
{
|
||||
public:
|
||||
ConvertGLTF();
|
||||
~ConvertGLTF();
|
||||
};
|
||||
VERUS_TYPEDEFS(ConvertGLTF);
|
||||
}
|
||||
}
|
|
@ -4,462 +4,9 @@
|
|||
using namespace verus;
|
||||
using namespace verus::Extra;
|
||||
|
||||
// FileParser::Mesh::UberVertex:
|
||||
// ConvertX::AnimationKey:
|
||||
|
||||
FileParser::Mesh::UberVertex::UberVertex()
|
||||
{
|
||||
VERUS_ZERO_MEM(_bw);
|
||||
VERUS_ZERO_MEM(_bi);
|
||||
}
|
||||
|
||||
bool FileParser::Mesh::UberVertex::operator==(RcUberVertex that) const
|
||||
{
|
||||
const float e = 0.001f;
|
||||
return
|
||||
glm::all(glm::epsilonEqual(_pos, that._pos, e)) &&
|
||||
glm::all(glm::epsilonEqual(_nrm, that._nrm, e)) &&
|
||||
glm::all(glm::epsilonEqual(_tc0, that._tc0, e)) &&
|
||||
glm::all(glm::epsilonEqual(_tc1, that._tc1, e));
|
||||
}
|
||||
|
||||
void FileParser::Mesh::UberVertex::Add(float weight, UINT32 index)
|
||||
{
|
||||
if (_currentWeight < 4) // Space for one more?
|
||||
{
|
||||
_bw[_currentWeight] = weight;
|
||||
_bi[_currentWeight] = index;
|
||||
_currentWeight++;
|
||||
}
|
||||
else // No space left - check the smallest weight:
|
||||
{
|
||||
float* pMin = std::min_element(_bw, _bw + 4);
|
||||
if (weight > *pMin)
|
||||
{
|
||||
const int i = Utils::Cast32(std::distance(_bw, pMin));
|
||||
_bw[i] = weight;
|
||||
_bi[i] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileParser::Mesh::UberVertex::CompileBits(UINT32& ww, UINT32& ii) const
|
||||
{
|
||||
ww = 0;
|
||||
ii = 0;
|
||||
|
||||
int ibw[4] = {};
|
||||
VERUS_FOR(i, _currentWeight)
|
||||
ibw[i] = glm::clamp(int(_bw[i] * 255 + 0.5f), 0, 255);
|
||||
ibw[0] = glm::clamp(255 - ibw[1] - ibw[2] - ibw[3], 0, 255);
|
||||
|
||||
// Make sure that the sum is 255:
|
||||
int at = 0;
|
||||
int sum = ibw[0] + ibw[1] + ibw[2] + ibw[3];
|
||||
while (sum > 255)
|
||||
{
|
||||
if (ibw[at] > 0)
|
||||
{
|
||||
sum--;
|
||||
ibw[at]--;
|
||||
}
|
||||
at = (at + 1) & 0x3;
|
||||
}
|
||||
|
||||
VERUS_FOR(i, _currentWeight)
|
||||
{
|
||||
ww |= ibw[i] << (i << 3);
|
||||
ii |= _bi[i] << (i << 3);
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 FileParser::Mesh::UberVertex::GetDominantIndex()
|
||||
{
|
||||
_bw[0] = 1 - _bw[1] - _bw[2] - _bw[3];
|
||||
const int i = Utils::Cast32(std::distance(_bw, std::max_element(_bw, _bw + 4)));
|
||||
return _bi[i];
|
||||
}
|
||||
|
||||
// FileParser::Mesh::Aabb:
|
||||
|
||||
void FileParser::Mesh::Aabb::Reset()
|
||||
{
|
||||
_mn = glm::vec3(+FLT_MAX);
|
||||
_mx = glm::vec3(-FLT_MAX);
|
||||
}
|
||||
|
||||
void FileParser::Mesh::Aabb::Include(const glm::vec3& point)
|
||||
{
|
||||
_mn = glm::min(_mn, point);
|
||||
_mx = glm::max(_mx, point);
|
||||
}
|
||||
|
||||
glm::vec3 FileParser::Mesh::Aabb::GetExtents() const
|
||||
{
|
||||
return (_mx - _mn) * 0.5f;
|
||||
}
|
||||
|
||||
// FileParser::Mesh:
|
||||
|
||||
FileParser::Mesh::Mesh()
|
||||
{
|
||||
_matBoneAxis = glm::rotate(glm::radians(-90.f), glm::vec3(0, 0, 1));
|
||||
VERUS_FOR(i, 4)
|
||||
{
|
||||
VERUS_FOR(j, 4)
|
||||
_matBoneAxis[i][j] = glm::round(_matBoneAxis[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
FileParser::Mesh::~Mesh()
|
||||
{
|
||||
}
|
||||
|
||||
FileParser::Mesh::PBone FileParser::Mesh::FindBone(CSZ name)
|
||||
{
|
||||
for (auto& bone : _vBones)
|
||||
{
|
||||
if (bone._name == name)
|
||||
return &bone;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FileParser::Mesh::Optimize()
|
||||
{
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": Optimize";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
// Weld vertices, remove duplicates:
|
||||
int similarVertCount = 0;
|
||||
int degenerateFaceCount = 0;
|
||||
Vector<UberVertex> vVbOpt; // This will not contain equal vertices.
|
||||
Vector<Face> vIbOpt; // This can get smaller than current IB, if there are zero-area triangles.
|
||||
vVbOpt.reserve(_vertCount);
|
||||
vIbOpt.reserve(_faceCount);
|
||||
VERUS_FOR(face, _faceCount) // For each triangle:
|
||||
{
|
||||
FileParser::I().OnProgress(float(face) / _faceCount * 100);
|
||||
Face newFace;
|
||||
int pushedCount = 0;
|
||||
VERUS_FOR(i, 3) // For each vertex in triangle:
|
||||
{
|
||||
RcUberVertex test = _vUberVerts[_vFaces[face]._indices[i]]; // Fetch vertex.
|
||||
const auto similar = std::find(vVbOpt.begin(), vVbOpt.end(), test);
|
||||
const int index = (similar == vVbOpt.end()) ? -1 : Utils::Cast32(std::distance(vVbOpt.begin(), similar));
|
||||
if (index < 0) // No similar vertex found.
|
||||
{
|
||||
newFace._indices[i] = Utils::Cast32(vVbOpt.size());
|
||||
vVbOpt.push_back(test);
|
||||
pushedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFace._indices[i] = index;
|
||||
similarVertCount++;
|
||||
}
|
||||
}
|
||||
if (newFace._indices[0] != newFace._indices[1] &&
|
||||
newFace._indices[1] != newFace._indices[2] &&
|
||||
newFace._indices[2] != newFace._indices[0])
|
||||
{
|
||||
vIbOpt.push_back(newFace); // Add triangle, if it's area is more than zero.
|
||||
}
|
||||
else
|
||||
{
|
||||
degenerateFaceCount++;
|
||||
vVbOpt.resize(vVbOpt.size() - pushedCount); // Rollback.
|
||||
}
|
||||
}
|
||||
_vUberVerts.assign(vVbOpt.begin(), vVbOpt.end());
|
||||
_vFaces.assign(vIbOpt.begin(), vIbOpt.end());
|
||||
_vertCount = Utils::Cast32(_vUberVerts.size());
|
||||
_faceCount = Utils::Cast32(_vFaces.size());
|
||||
StringStream ssWeldReport;
|
||||
ssWeldReport << "Weld report: " << similarVertCount << " similar vertices removed, " << degenerateFaceCount << " degenerate faces removed";
|
||||
FileParser::I().OnProgressText(_C(ssWeldReport.str()));
|
||||
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": (" << _vertCount << " vertices, " << _faceCount << " faces)";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
// Optimize (using AMD Tootle):
|
||||
StringStream ss2;
|
||||
ss2 << _name << ": Optimize (Tootle)";
|
||||
FileParser::I().OnProgressText(_C(ss2.str()));
|
||||
if (FileParser::I()._pDelegate)
|
||||
FileParser::I()._pDelegate->FileParser_Optimize(_vUberVerts, _vFaces);
|
||||
}
|
||||
|
||||
void FileParser::Mesh::ComputeTangentSpace()
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": ComputeTangentSpace";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
|
||||
Vector<glm::vec3> vPos, vN, vTan, vBin;
|
||||
vPos.resize(_vertCount);
|
||||
|
||||
Vector<glm::vec2> vTc0;
|
||||
vTc0.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
vPos[i] = _vUberVerts[i]._pos;
|
||||
vTc0[i] = _vUberVerts[i]._tc0;
|
||||
}
|
||||
|
||||
Vector<UINT16> vIndices;
|
||||
vIndices.resize(_faceCount * 3);
|
||||
VERUS_FOR(i, _faceCount)
|
||||
{
|
||||
vIndices[i * 3 + 0] = _vFaces[i]._indices[0];
|
||||
vIndices[i * 3 + 1] = _vFaces[i]._indices[1];
|
||||
vIndices[i * 3 + 2] = _vFaces[i]._indices[2];
|
||||
}
|
||||
|
||||
if (_found & Found::normals)
|
||||
{
|
||||
vN.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
vN[i] = _vUberVerts[i]._nrm;
|
||||
}
|
||||
else
|
||||
{
|
||||
Math::NormalComputer::ComputeNormals(vIndices, vPos, vN, FileParser::I()._desc._areaBasedNormals);
|
||||
}
|
||||
|
||||
FileParser::I().OnProgress(50);
|
||||
Math::NormalComputer::ComputeTangentSpace(vIndices, vPos, vN, vTc0, vTan, vBin);
|
||||
|
||||
_vZipNormal.resize(_vertCount);
|
||||
_vZipTan.resize(_vertCount);
|
||||
_vZipBin.resize(_vertCount);
|
||||
VERUS_FOR(i, _vertCount) // Compress them all:
|
||||
{
|
||||
Convert::SnormToSint8(&vN[i].x, &_vZipNormal[i]._x, 3);
|
||||
Convert::SnormToSint8(&vTan[i].x, &_vZipTan[i]._x, 3);
|
||||
Convert::SnormToSint8(&vBin[i].x, &_vZipBin[i]._x, 3);
|
||||
}
|
||||
}
|
||||
|
||||
void FileParser::Mesh::Compress()
|
||||
{
|
||||
StringStream ss;
|
||||
ss << _name << ": Compress";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
|
||||
Mesh::Aabb aabb;
|
||||
glm::vec3 extents, scale, bias;
|
||||
|
||||
// Compress position:
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(_vUberVerts[i]._pos);
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(_posScale, _posBias, extents, aabb._mn);
|
||||
_vZipPos.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec3Short pos;
|
||||
glm::vec3 v(_vUberVerts[i]._pos);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
pos._x = short(v.x);
|
||||
pos._y = short(v.y);
|
||||
pos._z = short(v.z);
|
||||
_vZipPos.push_back(pos);
|
||||
}
|
||||
|
||||
// Compress tc0:
|
||||
FileParser::I().OnProgress(50);
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc0, 0));
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(scale, bias, extents, aabb._mn);
|
||||
_tc0Scale = glm::vec2(scale);
|
||||
_tc0Bias = glm::vec2(bias);
|
||||
_vZipTc0.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec2Short tc;
|
||||
glm::vec3 v(_vUberVerts[i]._tc0, 0);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
tc._u = short(v.x);
|
||||
tc._v = short(v.y);
|
||||
_vZipTc0.push_back(tc);
|
||||
}
|
||||
|
||||
if (!(_found & Found::texcoordExtra))
|
||||
return;
|
||||
|
||||
// Compress tc1:
|
||||
FileParser::I().OnProgress(75);
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc1, 0));
|
||||
glm::vec2 normBias(-aabb._mn);
|
||||
glm::vec2 normScale(aabb._mx - aabb._mn);
|
||||
normScale.x = 1 / normScale.x;
|
||||
normScale.y = 1 / normScale.y;
|
||||
aabb.Reset();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
_vUberVerts[i]._tc1 = (_vUberVerts[i]._tc1 + normBias) * normScale;
|
||||
aabb.Include(glm::vec3(_vUberVerts[i]._tc1, 0));
|
||||
}
|
||||
extents = aabb.GetExtents();
|
||||
Scene::BaseMesh::ComputeDeq(scale, bias, extents, aabb._mn);
|
||||
_tc1Scale = glm::vec2(scale);
|
||||
_tc1Bias = glm::vec2(bias);
|
||||
_vZipTc1.reserve(_vertCount);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Mesh::Vec2Short tc;
|
||||
glm::vec3 v((_vUberVerts[i]._tc1), 0);
|
||||
Scene::BaseMesh::QuantizeV(v, extents, aabb._mn);
|
||||
tc._u = short(v.x);
|
||||
tc._v = short(v.y);
|
||||
_vZipTc1.push_back(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void FileParser::Mesh::SerializeX3D3(IO::RFile file)
|
||||
{
|
||||
if (!(_found & Found::vertsAndUVs))
|
||||
return;
|
||||
|
||||
Optimize();
|
||||
ComputeTangentSpace();
|
||||
Compress();
|
||||
|
||||
file.WriteText("<X3D>");
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<VN>");
|
||||
file.WriteString("3.0");
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<IX>");
|
||||
file.BeginBlock();
|
||||
file.WriteString(_C(std::to_string(_faceCount)));
|
||||
VERUS_FOR(i, _faceCount)
|
||||
file.Write(&_vFaces[i], 6);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<VX>");
|
||||
file.BeginBlock();
|
||||
file.WriteString(_C(std::to_string(_vertCount)));
|
||||
file.Write(&_posScale, 12);
|
||||
file.Write(&_posBias, 12);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipPos[i], 6);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<NL>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipNormal[i], 3);
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<TS>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
file.Write(&_vZipTan[i], 3);
|
||||
file.Write(&_vZipBin[i], 3);
|
||||
}
|
||||
file.EndBlock();
|
||||
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<T0>");
|
||||
file.BeginBlock();
|
||||
file.Write(&_tc0Scale, 8);
|
||||
file.Write(&_tc0Bias, 8);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipTc0[i], 4);
|
||||
file.EndBlock();
|
||||
|
||||
if (_found & Found::texcoordExtra)
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<T1>");
|
||||
file.BeginBlock();
|
||||
file.Write(&_tc1Scale, 8);
|
||||
file.Write(&_tc1Bias, 8);
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file.Write(&_vZipTc1[i], 4);
|
||||
file.EndBlock();
|
||||
}
|
||||
|
||||
if (_boneCount > 0)
|
||||
{
|
||||
// Must be the same order as in X file! Do not sort.
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<BH>");
|
||||
file.BeginBlock();
|
||||
const BYTE boneInfo = BYTE(_boneCount);
|
||||
file << boneInfo;
|
||||
VERUS_FOR(i, _boneCount)
|
||||
{
|
||||
file.WriteString(_C(_vBones[i]._name));
|
||||
file.WriteString(_C(_vBones[i]._parentName));
|
||||
file.Write(&_vBones[i]._matOffset, 64);
|
||||
}
|
||||
file.EndBlock();
|
||||
|
||||
StringStream ssDebug;
|
||||
VERUS_FOR(i, _boneCount)
|
||||
ssDebug << "Bone: " << _vBones[i]._name << "; Parent: " << _vBones[i]._parentName << ";" VERUS_CRNL;
|
||||
String pathname = FileParser::I()._pathname;
|
||||
Str::ReplaceExtension(pathname, "_Bones.txt");
|
||||
IO::File fileDebug;
|
||||
if (fileDebug.Open(_C(pathname), "wb"))
|
||||
fileDebug.Write(_C(ssDebug.str()), ssDebug.str().length());
|
||||
|
||||
if (!FileParser::I()._desc._useRigidBones)
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<SS>");
|
||||
file.BeginBlock();
|
||||
UINT32 ww, ii;
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
_vUberVerts[i].CompileBits(ww, ii);
|
||||
file << ww << ii;
|
||||
}
|
||||
file.EndBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
file.WriteText(VERUS_CRNL VERUS_CRNL "<SR>");
|
||||
file.BeginBlock();
|
||||
VERUS_FOR(i, _vertCount)
|
||||
file << BYTE(_vUberVerts[i].GetDominantIndex());
|
||||
file.EndBlock();
|
||||
}
|
||||
}
|
||||
|
||||
StringStream ss;
|
||||
ss << _name << ": Done";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
}
|
||||
|
||||
bool FileParser::Mesh::IsCopyOf(RMesh that)
|
||||
{
|
||||
if (_vertCount != that._vertCount)
|
||||
return false;
|
||||
if (!std::equal(_vUberVerts.begin(), _vUberVerts.end(), that._vUberVerts.begin(), [](RcUberVertex a, RcUberVertex b)
|
||||
{
|
||||
const glm::vec3 dpos = a._pos - b._pos;
|
||||
const glm::vec2 dtc0 = a._tc0 - b._tc0;
|
||||
const float d = 0.01f * 0.01f;
|
||||
return glm::dot(dpos, dpos) < d && glm::dot(dtc0, dtc0) < d;
|
||||
}))
|
||||
return false;
|
||||
_copyOf = that._name;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FileParser::AnimationKey:
|
||||
|
||||
void FileParser::AnimationKey::DetectRedundantFrames(float threshold)
|
||||
void ConvertX::AnimationKey::DetectRedundantFrames(float threshold)
|
||||
{
|
||||
for (auto& subkey : _vFrame)
|
||||
subkey._redundant = false;
|
||||
|
@ -501,9 +48,9 @@ void FileParser::AnimationKey::DetectRedundantFrames(float threshold)
|
|||
}
|
||||
}
|
||||
|
||||
// FileParser::AnimationSet:
|
||||
// ConvertX::AnimationSet:
|
||||
|
||||
void FileParser::AnimationSet::CleanUp()
|
||||
void ConvertX::AnimationSet::CleanUp()
|
||||
{
|
||||
VERUS_WHILE(Vector<Animation>, _vAnimations, it)
|
||||
{
|
||||
|
@ -517,32 +64,47 @@ void FileParser::AnimationSet::CleanUp()
|
|||
}
|
||||
}
|
||||
|
||||
// FileParser:
|
||||
// ConvertX:
|
||||
|
||||
FileParser::FileParser()
|
||||
ConvertX::ConvertX()
|
||||
{
|
||||
_matRoot = Transform3::identity();
|
||||
}
|
||||
|
||||
FileParser::~FileParser()
|
||||
ConvertX::~ConvertX()
|
||||
{
|
||||
Done();
|
||||
}
|
||||
|
||||
void FileParser::Init(FileParserDelegate* p, RcDesc desc)
|
||||
void ConvertX::Init(BaseConvertDelegate* p, RcDesc desc)
|
||||
{
|
||||
VERUS_INIT();
|
||||
_pDelegate = p;
|
||||
_desc = desc;
|
||||
}
|
||||
|
||||
void FileParser::Done()
|
||||
void ConvertX::Done()
|
||||
{
|
||||
DeleteAll();
|
||||
VERUS_DONE(FileParser);
|
||||
VERUS_DONE(ConvertX);
|
||||
}
|
||||
|
||||
void FileParser::LoadBoneNames(CSZ pathname)
|
||||
bool ConvertX::UseAreaBasedNormals()
|
||||
{
|
||||
return _desc._areaBasedNormals;
|
||||
}
|
||||
|
||||
bool ConvertX::UseRigidBones()
|
||||
{
|
||||
return _desc._useRigidBones;
|
||||
}
|
||||
|
||||
Str ConvertX::GetPathname()
|
||||
{
|
||||
return _C(_pathname);
|
||||
}
|
||||
|
||||
void ConvertX::LoadBoneNames(CSZ pathname)
|
||||
{
|
||||
Vector<BYTE> vData;
|
||||
IO::FileSystem::LoadResource(pathname, vData, IO::FileSystem::LoadDesc(true));
|
||||
|
@ -557,7 +119,7 @@ void FileParser::LoadBoneNames(CSZ pathname)
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::ParseData(CSZ pathname)
|
||||
void ConvertX::ParseData(CSZ pathname)
|
||||
{
|
||||
VERUS_RT_ASSERT(IsInitialized());
|
||||
|
||||
|
@ -627,7 +189,7 @@ void FileParser::ParseData(CSZ pathname)
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::SerializeAll(CSZ pathname)
|
||||
void ConvertX::SerializeAll(CSZ pathname)
|
||||
{
|
||||
char path[256] = {};
|
||||
strcpy(path, pathname);
|
||||
|
@ -670,7 +232,7 @@ void FileParser::SerializeAll(CSZ pathname)
|
|||
strcpy(strrchr(path, '\\') + 1, _C(pMesh->GetName()));
|
||||
strcat(path, ".x3d");
|
||||
|
||||
if (_pDelegate && !_pDelegate->FileParser_CanOverwriteFile(path))
|
||||
if (_pDelegate && !_pDelegate->BaseConvert_CanOverwriteFile(path))
|
||||
{
|
||||
StringStream ss;
|
||||
ss << pMesh->GetName() << ": Cancelled, file exists";
|
||||
|
@ -706,7 +268,7 @@ void FileParser::SerializeAll(CSZ pathname)
|
|||
if (_desc._convertAsLevel)
|
||||
{
|
||||
strcpy(strrchr(path, '\\') + 1, "Level.xml");
|
||||
if (!_pDelegate || _pDelegate->FileParser_CanOverwriteFile(path))
|
||||
if (!_pDelegate || _pDelegate->BaseConvert_CanOverwriteFile(path))
|
||||
{
|
||||
IO::File file;
|
||||
if (file.Open(path, "wb"))
|
||||
|
@ -740,7 +302,7 @@ void FileParser::SerializeAll(CSZ pathname)
|
|||
|
||||
strcpy(strrchr(path, '\\') + 1, _C(set._name));
|
||||
strcat(path, ".xan");
|
||||
if (_pDelegate && !_pDelegate->FileParser_CanOverwriteFile(path))
|
||||
if (_pDelegate && !_pDelegate->BaseConvert_CanOverwriteFile(path))
|
||||
continue;
|
||||
|
||||
IO::File file;
|
||||
|
@ -840,7 +402,7 @@ void FileParser::SerializeAll(CSZ pathname)
|
|||
OnProgress(100);
|
||||
}
|
||||
|
||||
void FileParser::AsyncRun(CSZ pathname)
|
||||
void ConvertX::AsyncRun(CSZ pathname)
|
||||
{
|
||||
_future = Async([this, pathname]()
|
||||
{
|
||||
|
@ -849,22 +411,22 @@ void FileParser::AsyncRun(CSZ pathname)
|
|||
});
|
||||
}
|
||||
|
||||
void FileParser::AsyncJoin()
|
||||
void ConvertX::AsyncJoin()
|
||||
{
|
||||
_future.get();
|
||||
}
|
||||
|
||||
bool FileParser::IsAsyncStarted() const
|
||||
bool ConvertX::IsAsyncStarted() const
|
||||
{
|
||||
return _future.valid();
|
||||
}
|
||||
|
||||
bool FileParser::IsAsyncFinished() const
|
||||
bool ConvertX::IsAsyncFinished() const
|
||||
{
|
||||
return _future.valid() && _future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
|
||||
}
|
||||
|
||||
void FileParser::LoadFromFile(CSZ pathname)
|
||||
void ConvertX::LoadFromFile(CSZ pathname)
|
||||
{
|
||||
IO::File file;
|
||||
if (file.Open(pathname, "rb"))
|
||||
|
@ -878,7 +440,7 @@ void FileParser::LoadFromFile(CSZ pathname)
|
|||
throw VERUS_RECOVERABLE << "LoadFromFile() failed, " << pathname;
|
||||
}
|
||||
|
||||
void FileParser::StreamReadUntil(SZ dest, int destSize, CSZ separator)
|
||||
void ConvertX::StreamReadUntil(SZ dest, int destSize, CSZ separator)
|
||||
{
|
||||
memset(dest, 0, destSize);
|
||||
size_t len = strcspn(_pData, separator);
|
||||
|
@ -888,7 +450,7 @@ void FileParser::StreamReadUntil(SZ dest, int destSize, CSZ separator)
|
|||
_pData += len;
|
||||
}
|
||||
|
||||
void FileParser::StreamSkipWhitespace()
|
||||
void ConvertX::StreamSkipWhitespace()
|
||||
{
|
||||
const char whitespace[] = " \r\n\t";
|
||||
const size_t length = strspn(_pData, whitespace);
|
||||
|
@ -906,13 +468,13 @@ void FileParser::StreamSkipWhitespace()
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::StreamSkipUntil(char c)
|
||||
void ConvertX::StreamSkipUntil(char c)
|
||||
{
|
||||
while (*_pData && *_pData != c)
|
||||
_pData++;
|
||||
}
|
||||
|
||||
void FileParser::FixBones()
|
||||
void ConvertX::FixBones()
|
||||
{
|
||||
// Same as in ParseBlockData_Mesh:
|
||||
const float s = _desc._scaleFactor;
|
||||
|
@ -958,7 +520,7 @@ void FileParser::FixBones()
|
|||
|
||||
StringStream ss;
|
||||
ss << "Added: " << name << " (parent of " << frame._name << ")";
|
||||
FileParser::I().OnProgressText(_C(ss.str()));
|
||||
ConvertX::I().OnProgressText(_C(ss.str()));
|
||||
}
|
||||
else
|
||||
pBone->_parentName = pParent ? pParent->_name : Anim::Skeleton::RootName();
|
||||
|
@ -968,7 +530,7 @@ void FileParser::FixBones()
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockRecursive(CSZ type, CSZ blockName)
|
||||
void ConvertX::ParseBlockRecursive(CSZ type, CSZ blockName)
|
||||
{
|
||||
_depth++;
|
||||
_pData++; // Skip {
|
||||
|
@ -976,7 +538,7 @@ void FileParser::ParseBlockRecursive(CSZ type, CSZ blockName)
|
|||
|
||||
if (!strcmp(type, "Mesh"))
|
||||
{
|
||||
_pCurrentMesh.reset(new Mesh());
|
||||
_pCurrentMesh.reset(new Mesh(this));
|
||||
_pCurrentMesh->SetName(_C(_currentMesh));
|
||||
ParseBlockData_Mesh();
|
||||
bool loop = true;
|
||||
|
@ -1117,7 +679,7 @@ void FileParser::ParseBlockRecursive(CSZ type, CSZ blockName)
|
|||
StreamSkipWhitespace();
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_Mesh()
|
||||
void ConvertX::ParseBlockData_Mesh()
|
||||
{
|
||||
Debug("Mesh");
|
||||
|
||||
|
@ -1268,7 +830,7 @@ void FileParser::ParseBlockData_Mesh()
|
|||
_pCurrentMesh->AddFoundFlag(Mesh::Found::faces);
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_MeshTextureCoords()
|
||||
void ConvertX::ParseBlockData_MeshTextureCoords()
|
||||
{
|
||||
Debug("MeshTextureCoords");
|
||||
|
||||
|
@ -1314,7 +876,7 @@ void FileParser::ParseBlockData_MeshTextureCoords()
|
|||
_pCurrentMesh->AddFoundFlag(Mesh::Found::vertsAndUVs);
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_MeshNormals()
|
||||
void ConvertX::ParseBlockData_MeshNormals()
|
||||
{
|
||||
Debug("MeshNormals");
|
||||
|
||||
|
@ -1420,7 +982,7 @@ void FileParser::ParseBlockData_MeshNormals()
|
|||
_pCurrentMesh->AddFoundFlag(Mesh::Found::normals);
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_FVFData(bool declData)
|
||||
void ConvertX::ParseBlockData_FVFData(bool declData)
|
||||
{
|
||||
Debug("FVFData"); // Actually lightmap's texture coords.
|
||||
|
||||
|
@ -1489,7 +1051,7 @@ void FileParser::ParseBlockData_FVFData(bool declData)
|
|||
_pCurrentMesh->AddFoundFlag(Mesh::Found::texcoordExtra);
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_XSkinMeshHeader()
|
||||
void ConvertX::ParseBlockData_XSkinMeshHeader()
|
||||
{
|
||||
Debug("XSkinMeshHeader");
|
||||
|
||||
|
@ -1505,7 +1067,7 @@ void FileParser::ParseBlockData_XSkinMeshHeader()
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_SkinWeights()
|
||||
void ConvertX::ParseBlockData_SkinWeights()
|
||||
{
|
||||
Debug("SkinWeights");
|
||||
|
||||
|
@ -1588,7 +1150,7 @@ void FileParser::ParseBlockData_SkinWeights()
|
|||
_pCurrentMesh->AddFoundFlag(Mesh::Found::skinning);
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_Frame(CSZ blockName)
|
||||
void ConvertX::ParseBlockData_Frame(CSZ blockName)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Frame " << blockName;
|
||||
|
@ -1672,7 +1234,7 @@ void FileParser::ParseBlockData_Frame(CSZ blockName)
|
|||
_mapFrames[frame._name] = frame;
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_FrameTransformMatrix()
|
||||
void ConvertX::ParseBlockData_FrameTransformMatrix()
|
||||
{
|
||||
Debug("FrameTransformMatrix");
|
||||
|
||||
|
@ -1698,7 +1260,7 @@ void FileParser::ParseBlockData_FrameTransformMatrix()
|
|||
_stackFrames.back()._matAcc = (*it)._mat * _stackFrames.back()._matAcc;
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_AnimationSet(CSZ blockName)
|
||||
void ConvertX::ParseBlockData_AnimationSet(CSZ blockName)
|
||||
{
|
||||
AnimationSet set;
|
||||
set._name = blockName;
|
||||
|
@ -1732,7 +1294,7 @@ void FileParser::ParseBlockData_AnimationSet(CSZ blockName)
|
|||
StreamSkipWhitespace();
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_Animation(CSZ blockName)
|
||||
void ConvertX::ParseBlockData_Animation(CSZ blockName)
|
||||
{
|
||||
const int indexSet = int(_vAnimSets.size() - 1);
|
||||
Animation an;
|
||||
|
@ -1855,7 +1417,7 @@ void FileParser::ParseBlockData_Animation(CSZ blockName)
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_AnimationKey()
|
||||
void ConvertX::ParseBlockData_AnimationKey()
|
||||
{
|
||||
const int indexSet = int(_vAnimSets.size() - 1);
|
||||
const int indexAnim = int(_vAnimSets[indexSet]._vAnimations.size() - 1);
|
||||
|
@ -1950,7 +1512,7 @@ void FileParser::ParseBlockData_AnimationKey()
|
|||
}
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_Material()
|
||||
void ConvertX::ParseBlockData_Material()
|
||||
{
|
||||
Debug("Material");
|
||||
|
||||
|
@ -1973,7 +1535,7 @@ void FileParser::ParseBlockData_Material()
|
|||
StreamSkipWhitespace();
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_TextureFilename()
|
||||
void ConvertX::ParseBlockData_TextureFilename()
|
||||
{
|
||||
Debug("TextureFilename");
|
||||
|
||||
|
@ -1990,7 +1552,7 @@ void FileParser::ParseBlockData_TextureFilename()
|
|||
mat._textureFilename = filename;
|
||||
}
|
||||
|
||||
void FileParser::ParseBlockData_MeshMaterialList()
|
||||
void ConvertX::ParseBlockData_MeshMaterialList()
|
||||
{
|
||||
Debug("MeshMaterialList");
|
||||
|
||||
|
@ -2046,7 +1608,7 @@ void FileParser::ParseBlockData_MeshMaterialList()
|
|||
StreamSkipWhitespace();
|
||||
}
|
||||
|
||||
FileParser::PMesh FileParser::AddMesh(PMesh pMesh)
|
||||
ConvertX::PMesh ConvertX::AddMesh(PMesh pMesh)
|
||||
{
|
||||
VERUS_QREF_UTILS;
|
||||
VERUS_RT_ASSERT(pMesh);
|
||||
|
@ -2073,7 +1635,7 @@ FileParser::PMesh FileParser::AddMesh(PMesh pMesh)
|
|||
return pMesh;
|
||||
}
|
||||
|
||||
FileParser::PMesh FileParser::FindMesh(CSZ name)
|
||||
ConvertX::PMesh ConvertX::FindMesh(CSZ name)
|
||||
{
|
||||
for (const auto& pMesh : _vMesh)
|
||||
{
|
||||
|
@ -2083,7 +1645,7 @@ FileParser::PMesh FileParser::FindMesh(CSZ name)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void FileParser::DeleteAll()
|
||||
void ConvertX::DeleteAll()
|
||||
{
|
||||
_vData.clear();
|
||||
for (const auto& pMesh : _vMesh)
|
||||
|
@ -2091,19 +1653,19 @@ void FileParser::DeleteAll()
|
|||
_vMesh.clear();
|
||||
}
|
||||
|
||||
void FileParser::OnProgress(float percent)
|
||||
void ConvertX::OnProgress(float percent)
|
||||
{
|
||||
if (_pDelegate)
|
||||
_pDelegate->FileParser_OnProgress(percent);
|
||||
_pDelegate->BaseConvert_OnProgress(percent);
|
||||
}
|
||||
|
||||
void FileParser::OnProgressText(CSZ txt)
|
||||
void ConvertX::OnProgressText(CSZ txt)
|
||||
{
|
||||
if (_pDelegate)
|
||||
_pDelegate->FileParser_OnProgressText(txt);
|
||||
_pDelegate->BaseConvert_OnProgressText(txt);
|
||||
}
|
||||
|
||||
void FileParser::Debug(CSZ txt)
|
||||
void ConvertX::Debug(CSZ txt)
|
||||
{
|
||||
StringStream ss;
|
||||
VERUS_FOR(i, _depth)
|
||||
|
@ -2112,7 +1674,7 @@ void FileParser::Debug(CSZ txt)
|
|||
_ssDebug << ss.str();
|
||||
}
|
||||
|
||||
void FileParser::DetectMaterialCopies()
|
||||
void ConvertX::DetectMaterialCopies()
|
||||
{
|
||||
const int count = Utils::Cast32(_vMaterials.size());
|
||||
VERUS_FOR(i, count)
|
||||
|
@ -2128,7 +1690,7 @@ void FileParser::DetectMaterialCopies()
|
|||
}
|
||||
}
|
||||
|
||||
String FileParser::GetXmlMaterial(int i)
|
||||
String ConvertX::GetXmlMaterial(int i)
|
||||
{
|
||||
if (_vMaterials.empty())
|
||||
return "";
|
||||
|
@ -2137,7 +1699,7 @@ String FileParser::GetXmlMaterial(int i)
|
|||
return Str::XmlEscape(_C(_vMaterials[i]._name));
|
||||
}
|
||||
|
||||
String FileParser::RenameBone(CSZ name)
|
||||
String ConvertX::RenameBone(CSZ name)
|
||||
{
|
||||
char lowName[256];
|
||||
strcpy(lowName, name);
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Extra
|
||||
{
|
||||
class ConvertX : public Singleton<ConvertX>, public Object, public BaseConvert
|
||||
{
|
||||
public:
|
||||
struct Desc
|
||||
{
|
||||
glm::vec3 _bias = glm::vec3(0);
|
||||
float _scaleFactor = 1;
|
||||
float _angle = 0;
|
||||
float _areaBasedNormals = 0;
|
||||
bool _useRigidBones = false;
|
||||
bool _convertAsLevel = false;
|
||||
bool _useDefaultMaterial = false;
|
||||
bool _rightHanded = true;
|
||||
};
|
||||
VERUS_TYPEDEFS(Desc);
|
||||
|
||||
private:
|
||||
struct Frame
|
||||
{
|
||||
String _name;
|
||||
String _parent;
|
||||
glm::mat4 _mat;
|
||||
glm::mat4 _matAcc;
|
||||
};
|
||||
VERUS_TYPEDEFS(Frame);
|
||||
|
||||
struct SubKey
|
||||
{
|
||||
Quat _q;
|
||||
bool _redundant = false;
|
||||
};
|
||||
|
||||
struct AnimationKey
|
||||
{
|
||||
Vector<SubKey> _vFrame;
|
||||
int _type = 0;
|
||||
int _logicFrameCount = 0;
|
||||
|
||||
void DetectRedundantFrames(float threshold = 0.001f);
|
||||
};
|
||||
|
||||
struct Animation
|
||||
{
|
||||
String _name;
|
||||
Vector<AnimationKey> _vAnimKeys;
|
||||
};
|
||||
|
||||
struct AnimationSet
|
||||
{
|
||||
String _name;
|
||||
Vector<Animation> _vAnimations;
|
||||
|
||||
void CleanUp();
|
||||
};
|
||||
|
||||
struct Material
|
||||
{
|
||||
String _name;
|
||||
String _copyOf;
|
||||
String _textureFilename;
|
||||
glm::vec4 _faceColor;
|
||||
glm::vec3 _specularColor;
|
||||
glm::vec3 _emissiveColor;
|
||||
float _power = 1;
|
||||
|
||||
bool IsCopyOf(const Material& that)
|
||||
{
|
||||
const float e = 0.01f;
|
||||
return
|
||||
_textureFilename == that._textureFilename &&
|
||||
glm::all(glm::epsilonEqual(_faceColor, that._faceColor, e)) &&
|
||||
glm::all(glm::epsilonEqual(_specularColor, that._specularColor, e)) &&
|
||||
glm::all(glm::epsilonEqual(_emissiveColor, that._emissiveColor, e)) &&
|
||||
glm::epsilonEqual(_power, that._power, e);
|
||||
}
|
||||
};
|
||||
VERUS_TYPEDEFS(Material);
|
||||
|
||||
typedef Map<String, String> TMapBoneNames;
|
||||
typedef Map<String, Frame> TMapFrames;
|
||||
|
||||
Transform3 _matRoot;
|
||||
TMapBoneNames _mapBoneNames;
|
||||
String _currentMesh;
|
||||
String _pathname;
|
||||
Vector<char> _vData;
|
||||
const char* _pData;
|
||||
const char* _pDataBegin;
|
||||
Vector<PMesh> _vMesh;
|
||||
std::unique_ptr<Mesh> _pCurrentMesh;
|
||||
TMapFrames _mapFrames;
|
||||
Vector<Frame> _stackFrames;
|
||||
Vector<AnimationSet> _vAnimSets;
|
||||
Vector<Material> _vMaterials;
|
||||
std::future<void> _future;
|
||||
Desc _desc;
|
||||
int _depth = 0;
|
||||
StringStream _ssDebug;
|
||||
|
||||
public:
|
||||
ConvertX();
|
||||
~ConvertX();
|
||||
|
||||
void Init(PBaseConvertDelegate p, RcDesc desc);
|
||||
void Done();
|
||||
|
||||
virtual bool UseAreaBasedNormals() override;
|
||||
virtual bool UseRigidBones() override;
|
||||
virtual Str GetPathname() override;
|
||||
|
||||
void LoadBoneNames(CSZ pathname);
|
||||
void ParseData(CSZ pathname);
|
||||
void SerializeAll(CSZ pathname);
|
||||
|
||||
void AsyncRun(CSZ pathname);
|
||||
void AsyncJoin();
|
||||
bool IsAsyncStarted() const;
|
||||
bool IsAsyncFinished() const;
|
||||
|
||||
private:
|
||||
void LoadFromFile(CSZ pathname);
|
||||
|
||||
void StreamReadUntil(SZ dest, int destSize, CSZ separator);
|
||||
void StreamSkipWhitespace();
|
||||
void StreamSkipUntil(char c);
|
||||
|
||||
void FixBones();
|
||||
|
||||
void ParseBlockRecursive(CSZ type, CSZ blockName);
|
||||
void ParseBlockData_Mesh();
|
||||
void ParseBlockData_MeshTextureCoords();
|
||||
void ParseBlockData_MeshNormals();
|
||||
void ParseBlockData_FVFData(bool declData);
|
||||
void ParseBlockData_XSkinMeshHeader();
|
||||
void ParseBlockData_SkinWeights();
|
||||
void ParseBlockData_Frame(CSZ blockName);
|
||||
void ParseBlockData_FrameTransformMatrix();
|
||||
void ParseBlockData_AnimationSet(CSZ blockName);
|
||||
void ParseBlockData_Animation(CSZ blockName);
|
||||
void ParseBlockData_AnimationKey();
|
||||
void ParseBlockData_Material();
|
||||
void ParseBlockData_TextureFilename();
|
||||
void ParseBlockData_MeshMaterialList();
|
||||
|
||||
PMesh AddMesh(PMesh pMesh);
|
||||
PMesh FindMesh(CSZ name);
|
||||
void DeleteAll();
|
||||
|
||||
void OnProgress(float percent);
|
||||
void OnProgressText(CSZ txt);
|
||||
|
||||
void Debug(CSZ txt);
|
||||
|
||||
void DetectMaterialCopies();
|
||||
String GetXmlMaterial(int i);
|
||||
String RenameBone(CSZ name);
|
||||
};
|
||||
VERUS_TYPEDEFS(ConvertX);
|
||||
}
|
||||
}
|
|
@ -5,10 +5,12 @@ namespace verus
|
|||
{
|
||||
void Make_Extra()
|
||||
{
|
||||
Extra::FileParser::Make();
|
||||
Extra::ConvertGLTF::Make();
|
||||
Extra::ConvertX::Make();
|
||||
}
|
||||
void Free_Extra()
|
||||
{
|
||||
Extra::FileParser::Free();
|
||||
Extra::ConvertX::Free();
|
||||
Extra::ConvertGLTF::Free();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
#include "FileParser.h"
|
||||
#include "BaseConvert.h"
|
||||
#include "ConvertGLTF.h"
|
||||
#include "ConvertX.h"
|
||||
|
||||
namespace verus
|
||||
{
|
||||
|
|
|
@ -102,6 +102,7 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere
|
|||
{
|
||||
Effects::Bloom::I().Init();
|
||||
Effects::Ssao::I().Init();
|
||||
Effects::Ssr::I().Init();
|
||||
Effects::Blur::I().Init();
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
#define VERUS_COLOR_BLEND_ALPHA "s*(sa)+d*(1-sa)"
|
||||
#define VERUS_COLOR_BLEND_PA "s*(1)+d*(1-sa)"
|
||||
#define VERUS_COLOR_BLEND_ADD "s*(1)+d*(1)"
|
||||
#define VERUS_COLOR_BLEND_SUB "s*(1)-d*(1)"
|
||||
#define VERUS_COLOR_BLEND_REVSUB "d*(1)-s*(1)"
|
||||
#define VERUS_COLOR_BLEND_MUL "s*(dc)+d*(0)"
|
||||
#define VERUS_COLOR_BLEND_FILTER "s*(0)+d*(sc)"
|
||||
#define VERUS_COLOR_BLEND_TINTED_GLASS "s*(sc)+d*(1-sc)"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define VERUS_QREF_SETTINGS App::RSettings settings = App::Settings::I()
|
||||
#define VERUS_QREF_SM Scene::RSceneManager sm = Scene::SceneManager::I()
|
||||
#define VERUS_QREF_SSAO Effects::RSsao ssao = Effects::Ssao::I()
|
||||
#define VERUS_QREF_SSR Effects::RSsr ssr = Effects::Ssr::I()
|
||||
#define VERUS_QREF_TIMER RTimer timer = Timer::I(); const float dt = timer.GetDeltaTime()
|
||||
#define VERUS_QREF_TIMER_GUI RTimer timer = Timer::I(); const float dt = timer.GetDeltaTime(Timer::Type::gui)
|
||||
#define VERUS_QREF_UTILS RUtils utils = Utils::I()
|
||||
|
|
|
@ -62,7 +62,7 @@ bool KeyMapper::HandleSdlEvent(SDL_Event& event)
|
|||
if (ImGui::GetIO().WantCaptureKeyboard)
|
||||
return false;
|
||||
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
|
||||
if (App::DisplayMode::windowed == settings._displayMode && SDL_SCANCODE_KP_ENTER == event.key.keysym.scancode)
|
||||
if (SDL_SCANCODE_KP_ENTER == event.key.keysym.scancode)
|
||||
{
|
||||
const SDL_bool rel = SDL_GetRelativeMouseMode();
|
||||
SDL_SetRelativeMouseMode(rel ? SDL_FALSE : SDL_TRUE);
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace verus
|
|||
Relation ContainsAabb(RcBounds aabb) const;
|
||||
void Draw();
|
||||
|
||||
RcPoint3 GetCorner(int index) const { return _corners[index]; }
|
||||
RcPoint3 GetEyePosition() const { return _corners[8]; }
|
||||
|
||||
Vector4 GetBounds(RcMatrix4 m, float& zNear, float& zFar) const;
|
||||
|
|
|
@ -598,4 +598,32 @@ void Math::Test()
|
|||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(VMath::length(x), 1, e));
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(VMath::dot(x, v), d, e));
|
||||
}
|
||||
|
||||
{
|
||||
// Right-handed mode (default):
|
||||
Scene::Camera camera;
|
||||
camera.MoveAtTo(Point3(0, 0, 4));
|
||||
camera.MoveEyeTo(Point3(0, 0, 3));
|
||||
camera.SetFovY(VERUS_PI * 0.25f);
|
||||
camera.SetAspectRatio(1);
|
||||
camera.SetZNear(0.5f);
|
||||
camera.SetZFar(100);
|
||||
camera.Update();
|
||||
Vector4 point = camera.GetMatrixVP() * Point3(3.5f, 0, 3.5f);
|
||||
point /= point.getW();
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 0.f, e));
|
||||
point = camera.GetMatrixVP() * Point3(103, 0, 103);
|
||||
point /= point.getW();
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 1.f, e));
|
||||
|
||||
// Left-handed mode:
|
||||
camera.SetFovY(VERUS_PI * -0.25f);
|
||||
camera.Update();
|
||||
point = camera.GetMatrixVP() * Point3(2.5f, 0, 2.5f);
|
||||
point /= point.getW();
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 0.f, e));
|
||||
point = camera.GetMatrixVP() * Point3(-97, 0, -97);
|
||||
point /= point.getW();
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 1.f, e));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ 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;
|
||||
|
|
|
@ -150,21 +150,33 @@ void Matrix4::InstFormat(VMath::Vector4* p) const
|
|||
memcpy(p, &m, 3 * sizeof(Vector4));
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::MakePerspective(float fovY, float aspectRatio, float zNear, float zFar)
|
||||
Matrix4 Matrix4::MakePerspective(float fovY, float aspectRatio, float zNear, float zFar, bool rightHanded)
|
||||
{
|
||||
VERUS_RT_ASSERT(fovY);
|
||||
VERUS_RT_ASSERT(aspectRatio);
|
||||
VERUS_RT_ASSERT(zNear < zFar);
|
||||
Matrix4 m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
const float yScale = 1 / tan(fovY * 0.5f);
|
||||
const float xScale = yScale / aspectRatio;
|
||||
const float zScale = zFar / (zNear - zFar);
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.setElem(0, 0, xScale);
|
||||
m.setElem(1, 1, yScale);
|
||||
m.setElem(2, 2, zScale);
|
||||
m.setElem(3, 2, zNear * zScale);
|
||||
m.setElem(2, 3, -1);
|
||||
if (rightHanded)
|
||||
{
|
||||
const float zScale = zFar / (zNear - zFar);
|
||||
m.setElem(0, 0, xScale);
|
||||
m.setElem(1, 1, yScale);
|
||||
m.setElem(2, 2, zScale);
|
||||
m.setElem(3, 2, zNear * zScale);
|
||||
m.setElem(2, 3, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float zScale = zFar / (zFar - zNear);
|
||||
m.setElem(0, 0, xScale);
|
||||
m.setElem(1, 1, yScale);
|
||||
m.setElem(2, 2, zScale);
|
||||
m.setElem(3, 2, -zNear * zScale);
|
||||
m.setElem(2, 3, 1);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace verus
|
|||
|
||||
const float* ToPointer() const { return reinterpret_cast<const float*>(this); }
|
||||
|
||||
static Matrix4 MakePerspective(float fovY, float aspectRatio, float zNear, float zFar);
|
||||
static Matrix4 MakePerspective(float fovY, float aspectRatio, float zNear, float zFar, bool rightHanded = true);
|
||||
static Matrix4 MakeOrtho(float w, float h, float zNear, float zFar);
|
||||
};
|
||||
VERUS_TYPEDEFS(Matrix4);
|
||||
|
|
|
@ -41,17 +41,17 @@ void Vehicle::Init(RcDesc desc)
|
|||
Math::Bounds chassis = desc._chassis;
|
||||
chassis.Set(maxHeight - 0.05f, chassis.GetMax().getY(), 1);
|
||||
|
||||
const Vector3 centerOfMassOffset = chassis.GetCenter() - Vector3(0, chassis.GetExtents().getY() * 0.8f, 0);
|
||||
const Vector3 centerOfMassOffset = chassis.GetCenter() - Vector3(0, chassis.GetExtents().getY() * 0.7f, 0);
|
||||
const Transform3 transformCoM = Transform3::translation(-centerOfMassOffset);
|
||||
const float g = bullet.GetWorld()->getGravity().length();
|
||||
const float forcePerWheel = (desc._mass * g) * _invWheelCount;
|
||||
const float k = forcePerWheel / desc._suspensionRestLength; // Hooke's law.
|
||||
|
||||
_vehicleTuning.m_suspensionStiffness = k / desc._mass;
|
||||
_vehicleTuning.m_suspensionCompression = _vehicleTuning.m_suspensionStiffness * 0.2f;
|
||||
_vehicleTuning.m_suspensionDamping = _vehicleTuning.m_suspensionStiffness * 0.35f;
|
||||
_vehicleTuning.m_suspensionCompression = _vehicleTuning.m_suspensionStiffness * 0.15f;
|
||||
_vehicleTuning.m_suspensionDamping = _vehicleTuning.m_suspensionStiffness * 0.3f;
|
||||
_vehicleTuning.m_maxSuspensionTravelCm = 100 * 2 * desc._suspensionRestLength;
|
||||
_vehicleTuning.m_frictionSlip = 2.5f;
|
||||
_vehicleTuning.m_frictionSlip = 1.75f;
|
||||
_vehicleTuning.m_maxSuspensionForce = forcePerWheel * 3;
|
||||
|
||||
averageWheelPos -= centerOfMassOffset;
|
||||
|
@ -107,6 +107,11 @@ void Vehicle::Init(RcDesc desc)
|
|||
};
|
||||
AddWheels(desc._vLeftWheels, desc._suspensionRestLength);
|
||||
AddWheels(desc._vRightWheels, desc._suspensionRestLength);
|
||||
|
||||
if (_frontRightWheelIndex > 0)
|
||||
_invHandBrakeWheelCount = 1.f / (_wheelCount - 2);
|
||||
else
|
||||
_invHandBrakeWheelCount = 1.f / (_wheelCount - 1);
|
||||
}
|
||||
|
||||
void Vehicle::Done()
|
||||
|
@ -167,18 +172,58 @@ void Vehicle::ApplyAirForce(float scale)
|
|||
}
|
||||
}
|
||||
|
||||
void Vehicle::SetBrake(float amount)
|
||||
void Vehicle::SetBrake(float brake, float handBrake, int index)
|
||||
{
|
||||
const float perWheel = amount * _invWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
_pRaycastVehicle->setBrake(perWheel, i);
|
||||
bool setHandBrake = true;
|
||||
if (index >= 0)
|
||||
{
|
||||
_pRaycastVehicle->setBrake(brake, index);
|
||||
setHandBrake = false;
|
||||
}
|
||||
else if (-2 == index) // Front wheel drive?
|
||||
{
|
||||
const float perWheel = brake * (_frontRightWheelIndex > 0 ? 0.5f : 1);
|
||||
_pRaycastVehicle->setBrake(perWheel, 0);
|
||||
if (_frontRightWheelIndex > 0)
|
||||
_pRaycastVehicle->setBrake(perWheel, _frontRightWheelIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float perWheel = brake * _invWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
_pRaycastVehicle->setBrake(perWheel, i);
|
||||
}
|
||||
|
||||
if (setHandBrake)
|
||||
{
|
||||
const float perWheel = handBrake * _invHandBrakeWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
{
|
||||
if (i != 0 && i != _frontRightWheelIndex)
|
||||
_pRaycastVehicle->setBrake(perWheel, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::SetEngineForce(float force)
|
||||
void Vehicle::SetEngineForce(float force, int index)
|
||||
{
|
||||
const float perWheel = force * _invWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
_pRaycastVehicle->applyEngineForce(perWheel, i);
|
||||
if (index >= 0)
|
||||
{
|
||||
_pRaycastVehicle->applyEngineForce(force, index);
|
||||
}
|
||||
else if (-2 == index) // Front wheel drive?
|
||||
{
|
||||
const float perWheel = force * (_frontRightWheelIndex > 0 ? 0.5f : 1);
|
||||
_pRaycastVehicle->applyEngineForce(perWheel, 0);
|
||||
if (_frontRightWheelIndex > 0)
|
||||
_pRaycastVehicle->applyEngineForce(perWheel, _frontRightWheelIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float perWheel = force * _invWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
_pRaycastVehicle->applyEngineForce(perWheel, i);
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::SetSteeringAngle(float angle)
|
||||
|
@ -188,19 +233,6 @@ void Vehicle::SetSteeringAngle(float angle)
|
|||
_pRaycastVehicle->setSteeringValue(angle, _frontRightWheelIndex);
|
||||
}
|
||||
|
||||
void Vehicle::UseHandBrake(float amount)
|
||||
{
|
||||
const float perWheel = amount * _invWheelCount;
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
{
|
||||
if (i != 0 && i != _frontRightWheelIndex)
|
||||
{
|
||||
_pRaycastVehicle->setBrake(perWheel, i);
|
||||
_pRaycastVehicle->applyEngineForce(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Vehicle::UserPtr_GetType()
|
||||
{
|
||||
return +Scene::NodeType::vehicle;
|
||||
|
|
|
@ -16,13 +16,14 @@ namespace verus
|
|||
int _frontRightWheelIndex = -1;
|
||||
int _wheelCount = 0;
|
||||
float _invWheelCount = 0;
|
||||
float _invHandBrakeWheelCount = 0;
|
||||
|
||||
public:
|
||||
struct Steering
|
||||
{
|
||||
float _angle = 0;
|
||||
float _speed = 1;
|
||||
float _maxAngle = Math::ToRadians(25);
|
||||
float _maxAngle = Math::ToRadians(36);
|
||||
|
||||
void Update(float stiffness)
|
||||
{
|
||||
|
@ -80,10 +81,9 @@ namespace verus
|
|||
btRaycastVehicle* GetRaycastVehicle() { return _pRaycastVehicle.Get(); }
|
||||
|
||||
void ApplyAirForce(float scale = 2);
|
||||
void SetBrake(float amount);
|
||||
void SetEngineForce(float force);
|
||||
void SetBrake(float brake, float handBrake = 0, int index = -1);
|
||||
void SetEngineForce(float force, int index = -1);
|
||||
void SetSteeringAngle(float angle);
|
||||
void UseHandBrake(float amount);
|
||||
|
||||
virtual int UserPtr_GetType() override;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ void Atmosphere::Init()
|
|||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_UTILS;
|
||||
VERUS_QREF_BLOOM;
|
||||
|
||||
_skyDome.Init("[Models]:SkyDome.x3d");
|
||||
|
||||
|
@ -40,11 +41,11 @@ void Atmosphere::Init()
|
|||
_shader->CreateDescriptorSet(3, &s_ubPerObject, sizeof(s_ubPerObject), 100);
|
||||
_shader->CreatePipelineLayout();
|
||||
|
||||
if (settings._sceneShadowQuality > App::Settings::ShadowQuality::none)
|
||||
_shadowMap.Init(4096);
|
||||
_cubeMap.Init(512);
|
||||
_shadowMap.Init(4096);
|
||||
|
||||
renderer.GetDS().InitByAtmosphere(_shadowMap.GetTexture());
|
||||
Effects::Bloom::I().InitByAtmosphere(_shadowMap.GetTexture());
|
||||
bloom.InitByAtmosphere(_shadowMap.GetTexture());
|
||||
|
||||
CreateCelestialBodyMesh();
|
||||
|
||||
|
@ -102,17 +103,18 @@ void Atmosphere::UpdateSun(float time)
|
|||
{
|
||||
// Update time and sun's color before calling this method.
|
||||
|
||||
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(time * VERUS_2PI) * Vector3(0, -1, 0);
|
||||
const float quantTime = time - fmod(time, 1 / 18000.f);
|
||||
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(quantTime * VERUS_2PI) * Vector3(0, -1, 0);
|
||||
_night = false;
|
||||
if (_sun._dirTo.getY() < 0) // Moon light:
|
||||
{
|
||||
_night = true;
|
||||
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(time * VERUS_2PI) * Vector3(0, 1, 0);
|
||||
_sun._color = glm::saturation(0.1f, _sun._color.GLM()) * 0.5f;
|
||||
_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()) * 5, 0, 1);
|
||||
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1);
|
||||
_sun._color *= _sun._alpha;
|
||||
|
||||
if (_sun._light)
|
||||
|
@ -220,20 +222,31 @@ void Atmosphere::Update()
|
|||
|
||||
_clouds._cloudiness.Update();
|
||||
|
||||
const float cloudinessSq = sqrt(_clouds._cloudiness);
|
||||
const float cloudScaleAmb = 1 - 0.6f * _clouds._cloudiness * cloudinessSq;
|
||||
const float cloudScaleFog = 1 - 0.9f * _clouds._cloudiness * cloudinessSq;
|
||||
const float cloudScaleSun = 1 - 0.999f * _clouds._cloudiness * cloudinessSq;
|
||||
float color[3];
|
||||
GetColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(50000, 30000, 1) * cloudScaleAmb);
|
||||
GetColor(100, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(30000, 2000, 1) * cloudScaleFog);
|
||||
GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(80000, 10000, 1) * cloudScaleSun);
|
||||
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 int count = 1;
|
||||
std::stringstream ssDebug;
|
||||
VERUS_FOR(i, count)
|
||||
{
|
||||
const float time = (count > 1) ? (i / 256.f) : _time;
|
||||
float color[3];
|
||||
SampleSkyColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 32000, 8000, 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, 40000, 28000, 300) * cloudScaleSun);
|
||||
if (count > 1)
|
||||
ssDebug << static_cast<int>(glm::saturation(0.f, _fog._color.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);
|
||||
// </Cloudiness>
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (abs(_time - 0.5f) < 0.01f && glm::epsilonEqual(static_cast<float>(_clouds._cloudiness), 0.25f, 0.05f))
|
||||
|
@ -241,14 +254,16 @@ void Atmosphere::Update()
|
|||
const glm::vec3 grayAmbient = glm::saturation(0.f, _ambientColor.GLM());
|
||||
const glm::vec3 grayFog = glm::saturation(0.f, _fog._color.GLM());
|
||||
const glm::vec3 graySun = glm::saturation(0.f, _sun._color.GLM());
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual(grayAmbient.x, 6000.f, 640.f));
|
||||
VERUS_RT_ASSERT(glm::epsilonEqual(graySun.x, 32000.f, 3200.f));
|
||||
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);
|
||||
_clouds._phaseB = Vector4(_clouds._phaseB - phaseV * (dt * _clouds._speedPhaseB * 0.05f)).Mod(1);
|
||||
// </Clouds>
|
||||
|
||||
UpdateSun(_time);
|
||||
}
|
||||
|
@ -354,7 +369,7 @@ void Atmosphere::DrawSky(bool reflection)
|
|||
// </Clouds>
|
||||
}
|
||||
|
||||
void Atmosphere::GetColor(int level, float* pOut, float scale)
|
||||
void Atmosphere::SampleSkyColor(int level, float* pOut, float scale)
|
||||
{
|
||||
if (!_texSky.IsLoaded())
|
||||
return;
|
||||
|
@ -380,13 +395,25 @@ void Atmosphere::GetColor(int level, float* pOut, float scale)
|
|||
pOut[i] = Math::Clamp<float>(Math::Lerp(rgbA[i], rgbB[i], fractPart) * 0.5f * scale, 0, 1);
|
||||
}
|
||||
|
||||
float Atmosphere::GetMagnitude(float noon, float dusk, float midnight) const
|
||||
float Atmosphere::GetMagnitude(float time, float noon, float dusk, float midnight)
|
||||
{
|
||||
const float time4 = _time * 4;
|
||||
const float time4 = time * 4;
|
||||
const int interval = Math::Clamp(static_cast<int>(time4), 0, 3);
|
||||
const float fractPart = time4 - interval;
|
||||
const float controlPoints[] = { midnight, dusk, noon, dusk, midnight };
|
||||
return Math::Lerp(controlPoints[interval], controlPoints[interval + 1], glm::sineEaseInOut(fractPart));
|
||||
const float cp[] = { midnight, dusk, noon, dusk };
|
||||
const int indices[4][4] =
|
||||
{
|
||||
{3, 0, 1, 2},
|
||||
{0, 1, 2, 3},
|
||||
{1, 2, 3, 0},
|
||||
{2, 3, 0, 1}
|
||||
};
|
||||
return glm::catmullRom(
|
||||
glm::vec1(cp[indices[interval][0]]),
|
||||
glm::vec1(cp[indices[interval][1]]),
|
||||
glm::vec1(cp[indices[interval][2]]),
|
||||
glm::vec1(cp[indices[interval][3]]),
|
||||
fractPart).x;
|
||||
}
|
||||
|
||||
RcVector3 Atmosphere::GetDirToSun() const
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace verus
|
|||
Sun _sun;
|
||||
Wind _wind;
|
||||
Vector3 _ambientColor = Vector3(0);
|
||||
CubeMap _cubeMap;
|
||||
CascadedShadowMap _shadowMap;
|
||||
Mesh _skyDome;
|
||||
CGI::TextureRAM _texSky;
|
||||
|
@ -120,8 +121,8 @@ namespace verus
|
|||
void Update();
|
||||
void DrawSky(bool reflection = false);
|
||||
|
||||
void GetColor(int level, float* pOut, float scale);
|
||||
float GetMagnitude(float noon, float dusk, float midnight) const;
|
||||
void SampleSkyColor(int level, float* pOut, float scale);
|
||||
static float GetMagnitude(float time, float noon, float dusk, float midnight);
|
||||
|
||||
// Time:
|
||||
float GetTime() const { return _time; }
|
||||
|
@ -155,13 +156,17 @@ namespace verus
|
|||
RcVector3 GetWindDirection() const;
|
||||
float GetWindSpeed() const;
|
||||
|
||||
// Shadow:
|
||||
// CubeMap:
|
||||
RCubeMap GetCubeMap() { return _cubeMap; }
|
||||
|
||||
// ShadowMap:
|
||||
void BeginShadow(int split);
|
||||
void EndShadow(int split);
|
||||
RCascadedShadowMap GetShadowMap() { return _shadowMap; }
|
||||
|
||||
void CreateCelestialBodyMesh();
|
||||
|
||||
// Net:
|
||||
void GetReport(RReport report);
|
||||
void SetReport(RcReport report);
|
||||
};
|
||||
|
|
|
@ -111,14 +111,14 @@ namespace verus
|
|||
Math::Bounds GetBounds() const;
|
||||
|
||||
template<typename T>
|
||||
void ForEachVertex(const T& fn, bool matIndices = false)
|
||||
void ForEachVertex(const T& fn, bool boneIndices = false)
|
||||
{
|
||||
VERUS_FOR(i, _vertCount)
|
||||
{
|
||||
Point3 pos, uv;
|
||||
DequantizeUsingDeq3D(_vBinding0[i]._pos, _posDeq, pos);
|
||||
DequantizeUsingDeq2D(_vBinding0[i]._tc0, _tc0Deq, uv);
|
||||
if (_vBinding1.empty() || !matIndices)
|
||||
if (_vBinding1.empty() || !boneIndices)
|
||||
{
|
||||
if (Continue::no == fn(pos, -1, uv))
|
||||
break;
|
||||
|
|
|
@ -19,9 +19,18 @@ void Camera::UpdateInternal()
|
|||
}
|
||||
else
|
||||
{
|
||||
_matP = Matrix4::MakePerspective(_fovY, _aspectRatio, _zNear, _zFar);
|
||||
if (_fovY > 0)
|
||||
{
|
||||
_matP = Matrix4::MakePerspective(_fovY, _aspectRatio, _zNear, _zFar);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fovY = -_fovY;
|
||||
_matP = Matrix4::MakePerspective(_fovY, _aspectRatio, _zNear, _zFar, false);
|
||||
}
|
||||
_fovScale = 0.5f / tan(_fovY * 0.5f);
|
||||
}
|
||||
_matPi = VMath::inverse(_matP);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace verus
|
|||
Transform3 _matV = Transform3::identity();
|
||||
Transform3 _matVi = Transform3::identity();
|
||||
Matrix4 _matP = Matrix4::identity();
|
||||
Matrix4 _matPi = Matrix4::identity();
|
||||
Matrix4 _matVP = Matrix4::identity();
|
||||
VERUS_PD(Point3 _eyePos = Point3(0));
|
||||
VERUS_PD(Point3 _atPos = Point3(0, 0, -1));
|
||||
|
@ -65,6 +66,7 @@ namespace verus
|
|||
RcTransform3 GetMatrixV() const { return _matV; }
|
||||
RcTransform3 GetMatrixVi() const { return _matVi; }
|
||||
RcMatrix4 GetMatrixP() const { return _matP; }
|
||||
RcMatrix4 GetMatrixPi() const { return _matPi; }
|
||||
RcMatrix4 GetMatrixVP() const { return _matVP; }
|
||||
|
||||
// Perspective:
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "verus.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Scene;
|
||||
|
||||
CubeMap::CubeMap()
|
||||
{
|
||||
}
|
||||
|
||||
CubeMap::~CubeMap()
|
||||
{
|
||||
Done();
|
||||
}
|
||||
|
||||
void CubeMap::Init(int side)
|
||||
{
|
||||
VERUS_INIT();
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_side = side;
|
||||
|
||||
_rph = renderer->CreateRenderPass(
|
||||
{
|
||||
CGI::RP::Attachment("Color", CGI::Format::floatR11G11B10).LoadOpDontCare().Layout(CGI::ImageLayout::fsReadOnly),
|
||||
CGI::RP::Attachment("Depth", CGI::Format::unormD24uintS8).LoadOpClear().Layout(CGI::ImageLayout::depthStencilAttachment),
|
||||
},
|
||||
{
|
||||
CGI::RP::Subpass("Sp0").Color(
|
||||
{
|
||||
CGI::RP::Ref("Color", CGI::ImageLayout::colorAttachment)
|
||||
}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment)),
|
||||
},
|
||||
{});
|
||||
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._name = "CubeMap.ColorTex";
|
||||
texDesc._format = CGI::Format::floatR11G11B10;
|
||||
texDesc._width = _side;
|
||||
texDesc._height = _side;
|
||||
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::cubeMap;
|
||||
_tex[TEX_COLOR].Init(texDesc);
|
||||
texDesc.Reset();
|
||||
texDesc._name = "CubeMap.DepthTex";
|
||||
texDesc._clearValue = Vector4(1);
|
||||
texDesc._format = CGI::Format::unormD24uintS8;
|
||||
texDesc._width = _side;
|
||||
texDesc._height = _side;
|
||||
_tex[TEX_DEPTH].Init(texDesc);
|
||||
|
||||
VERUS_FOR(i, +CGI::CubeMapFace::count)
|
||||
{
|
||||
_fbh[i] = renderer->CreateFramebuffer(_rph,
|
||||
{
|
||||
_tex[TEX_COLOR],
|
||||
_tex[TEX_DEPTH]
|
||||
},
|
||||
_side,
|
||||
_side,
|
||||
-1,
|
||||
static_cast<CGI::CubeMapFace>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void CubeMap::Done()
|
||||
{
|
||||
VERUS_DONE(CubeMap);
|
||||
}
|
||||
|
||||
void CubeMap::BeginEnvMap(CGI::CubeMapFace cubeMapFace, RcPoint3 center)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
_center = center;
|
||||
|
||||
Vector3 facePos = Vector3(0);
|
||||
Vector3 up = Vector3(0, 1, 0);
|
||||
switch (cubeMapFace)
|
||||
{
|
||||
case CGI::CubeMapFace::posX: facePos = Vector3(+1, 0, 0); break;
|
||||
case CGI::CubeMapFace::negX: facePos = Vector3(-1, 0, 0); break;
|
||||
case CGI::CubeMapFace::posY: facePos = Vector3(0, +1, 0); up = Vector3(0, 0, -1); break;
|
||||
case CGI::CubeMapFace::negY: facePos = Vector3(0, -1, 0); up = Vector3(0, 0, +1); break;
|
||||
case CGI::CubeMapFace::posZ: facePos = Vector3(0, 0, +1); break;
|
||||
case CGI::CubeMapFace::negZ: facePos = Vector3(0, 0, -1); break;
|
||||
}
|
||||
|
||||
_camera.MoveEyeTo(center);
|
||||
_camera.MoveAtTo(center - facePos); // Looking at center.
|
||||
_camera.SetUpDirection(up);
|
||||
_camera.SetFovY(VERUS_PI * -0.5f); // Using left-handed coordinate system!
|
||||
_camera.SetAspectRatio(1);
|
||||
_camera.SetZNear(1);
|
||||
_camera.SetZFar(200);
|
||||
_camera.Update();
|
||||
|
||||
_pPrevCamera = sm.SetCamera(&_camera);
|
||||
|
||||
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh[+cubeMapFace],
|
||||
{
|
||||
_tex[TEX_COLOR]->GetClearValue(),
|
||||
_tex[TEX_DEPTH]->GetClearValue()
|
||||
});
|
||||
}
|
||||
|
||||
void CubeMap::EndEnvMap()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
||||
renderer.GetCommandBuffer()->EndRenderPass();
|
||||
|
||||
sm.SetCamera(_pPrevCamera);
|
||||
}
|
||||
|
||||
CGI::TexturePtr CubeMap::GetColorTexture()
|
||||
{
|
||||
return _tex[TEX_COLOR];
|
||||
}
|
||||
|
||||
CGI::TexturePtr CubeMap::GetDepthTexture()
|
||||
{
|
||||
return _tex[TEX_DEPTH];
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
class CubeMap : public Object
|
||||
{
|
||||
public:
|
||||
enum TEX
|
||||
{
|
||||
TEX_COLOR,
|
||||
TEX_DEPTH,
|
||||
TEX_COUNT
|
||||
};
|
||||
|
||||
private:
|
||||
Point3 _center;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::FBHandle _fbh[+CGI::CubeMapFace::count];
|
||||
MainCamera _camera;
|
||||
PMainCamera _pPrevCamera = nullptr;
|
||||
int _side = 0;
|
||||
|
||||
public:
|
||||
CubeMap();
|
||||
~CubeMap();
|
||||
|
||||
void Init(int side);
|
||||
void Done();
|
||||
|
||||
CGI::RPHandle GetRenderPassHandle() const { return _rph; }
|
||||
void BeginEnvMap(CGI::CubeMapFace cubeMapFace, RcPoint3 center);
|
||||
void EndEnvMap();
|
||||
|
||||
CGI::TexturePtr GetColorTexture();
|
||||
CGI::TexturePtr GetDepthTexture();
|
||||
|
||||
RcPoint3 GetCenter() const { return _center; }
|
||||
};
|
||||
VERUS_TYPEDEFS(CubeMap);
|
||||
}
|
||||
}
|
|
@ -259,12 +259,19 @@ void Forest::Update()
|
|||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
_pipe[PIPE_DEPTH].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], "#", atmo.GetCubeMap().GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
_pipe[PIPE_SIMPLE_ENV_MAP].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], "#", water.GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
|
||||
_pipe[PIPE_REFLECTION].Init(pipeDesc);
|
||||
_pipe[PIPE_SIMPLE_PLANAR_REF].Init(pipeDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +531,7 @@ void Forest::DrawAO()
|
|||
}
|
||||
}
|
||||
|
||||
void Forest::DrawReflection()
|
||||
void Forest::DrawSimple(DrawSimpleMode mode)
|
||||
{
|
||||
if (!_geo)
|
||||
return;
|
||||
|
@ -534,27 +541,35 @@ void Forest::DrawReflection()
|
|||
VERUS_QREF_SM;
|
||||
VERUS_QREF_WATER;
|
||||
|
||||
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? USHRT_MAX : 0;
|
||||
const float pointSpriteScaleY = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? 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._eyePos = float4(sm.GetCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubSimpleForestVS._eyePos_clipDistanceOffset = float4(sm.GetCamera()->GetEyePosition().GLM(), clipDistanceOffset);
|
||||
s_ubSimpleForestVS._eyePosScreen = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubSimpleForestVS._pointSpriteScale = float4(1, water.IsUnderwater() ? 1 : -1, 0, 0);
|
||||
s_ubSimpleForestVS._pointSpriteScale = float4(1, pointSpriteScaleY, 0, 0);
|
||||
s_ubSimpleForestFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat();
|
||||
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);
|
||||
s_ubSimpleForestFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubSimpleForestFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimpleForestFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubSimpleForestFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubSimpleForestFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubSimpleForestFS._shadowConfig));
|
||||
s_ubSimpleForestFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_REFLECTION]);
|
||||
switch (mode)
|
||||
{
|
||||
case DrawSimpleMode::envMap: cb->BindPipeline(_pipe[PIPE_SIMPLE_ENV_MAP]); break;
|
||||
case DrawSimpleMode::planarReflection: cb->BindPipeline(_pipe[PIPE_SIMPLE_PLANAR_REF]); break;
|
||||
}
|
||||
cb->BindVertexBuffers(_geo);
|
||||
s_shader[SHADER_SIMPLE]->BeginBindDescriptors();
|
||||
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 0);
|
||||
|
|
|
@ -21,7 +21,8 @@ namespace verus
|
|||
{
|
||||
PIPE_MAIN,
|
||||
PIPE_DEPTH,
|
||||
PIPE_REFLECTION,
|
||||
PIPE_SIMPLE_ENV_MAP,
|
||||
PIPE_SIMPLE_PLANAR_REF,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
|
@ -223,7 +224,7 @@ namespace verus
|
|||
VERUS_P(void DrawModels(bool allowTess));
|
||||
VERUS_P(void DrawSprites());
|
||||
void DrawAO();
|
||||
void DrawReflection();
|
||||
void DrawSimple(DrawSimpleMode mode);
|
||||
|
||||
void UpdateCollision(const Vector<Vector4>& vZones);
|
||||
|
||||
|
|
|
@ -119,12 +119,16 @@ void Mesh::Draw(RcDrawDesc dd, CGI::CommandBufferPtr cb)
|
|||
|
||||
void Mesh::DrawSimple(RcDrawDesc dd, CGI::CommandBufferPtr cb)
|
||||
{
|
||||
DrawSimpleMode mode = DrawSimpleMode::envMap;
|
||||
if (dd._pipe >= PIPE_SIMPLE_PLANAR_REF && dd._pipe <= PIPE_SIMPLE_PLANAR_REF_SKINNED)
|
||||
mode = DrawSimpleMode::planarReflection;
|
||||
|
||||
auto shader = GetSimpleShader();
|
||||
|
||||
BindPipeline(dd._pipe, cb);
|
||||
BindGeo(cb);
|
||||
|
||||
UpdateUniformBufferSimplePerFrame();
|
||||
UpdateUniformBufferSimplePerFrame(mode);
|
||||
cb->BindDescriptors(shader, 0);
|
||||
if (dd._bindMaterial)
|
||||
{
|
||||
|
@ -149,6 +153,7 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_WATER;
|
||||
|
||||
if (!settings._gpuTessellation) // Fallback:
|
||||
{
|
||||
|
@ -208,11 +213,17 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
"#Robotic",
|
||||
"#Skinned",
|
||||
|
||||
"#",
|
||||
"#Instanced",
|
||||
"#Robotic",
|
||||
"#Skinned",
|
||||
|
||||
"#Texture",
|
||||
"#TextureInstanced",
|
||||
"#TextureRobotic",
|
||||
"#TextureSkinned"
|
||||
};
|
||||
VERUS_CT_ASSERT(VERUS_COUNT_OF(branches) == PIPE_COUNT);
|
||||
|
||||
if (pipe >= PIPE_SIMPLE_TEX_ADD)
|
||||
{
|
||||
|
@ -223,15 +234,22 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
|
|||
pipeDesc._depthWriteEnable = false;
|
||||
s_pipe[pipe].Init(pipeDesc);
|
||||
}
|
||||
else if (pipe >= PIPE_SIMPLE_WATER_REF)
|
||||
else if (pipe >= PIPE_SIMPLE_PLANAR_REF)
|
||||
{
|
||||
VERUS_QREF_WATER;
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], water.GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
|
||||
pipeDesc._vertexInputBindingsFilter = _bindingsMask;
|
||||
s_pipe[pipe].Init(pipeDesc);
|
||||
}
|
||||
else if (pipe >= PIPE_SIMPLE_ENV_MAP)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], atmo.GetCubeMap().GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
|
||||
pipeDesc._vertexInputBindingsFilter = _bindingsMask;
|
||||
s_pipe[pipe].Init(pipeDesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_MAIN], branches[pipe], renderer.GetDS().GetRenderPassHandle());
|
||||
|
@ -426,7 +444,7 @@ void Mesh::UpdateUniformBufferPerObject(RcTransform3 tr, RcVector4 color)
|
|||
s_ubSimplePerObject._userColor = s_ubPerObject._userColor;
|
||||
}
|
||||
|
||||
void Mesh::UpdateUniformBufferSimplePerFrame()
|
||||
void Mesh::UpdateUniformBufferSimplePerFrame(DrawSimpleMode mode)
|
||||
{
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -434,19 +452,21 @@ void Mesh::UpdateUniformBufferSimplePerFrame()
|
|||
VERUS_QREF_WATER;
|
||||
|
||||
RcPoint3 eyePos = sm.GetMainCamera()->GetEyePosition();
|
||||
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? USHRT_MAX : 0;
|
||||
|
||||
s_ubSimplePerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
|
||||
s_ubSimplePerFrame._eyePos_clipDistanceOffset = float4(eyePos.GLM(), static_cast<float>(water.IsUnderwater() ? USHRT_MAX : 0));
|
||||
s_ubSimplePerFrame._eyePos_clipDistanceOffset = float4(eyePos.GLM(), clipDistanceOffset);
|
||||
s_ubSimplePerFrame._ambientColor = float4(atmo.GetAmbientColor().GLM(), 0);
|
||||
s_ubSimplePerFrame._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubSimplePerFrame._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubSimplePerFrame._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubSimplePerFrame._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimplePerFrame._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubSimplePerFrame._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubSimplePerFrame._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubSimplePerFrame._shadowConfig));
|
||||
s_ubSimplePerFrame._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
}
|
||||
|
||||
void Mesh::UpdateUniformBufferSimpleSkeletonVS()
|
||||
|
|
|
@ -49,10 +49,15 @@ namespace verus
|
|||
PIPE_WIREFRAME_ROBOTIC,
|
||||
PIPE_WIREFRAME_SKINNED,
|
||||
|
||||
PIPE_SIMPLE_WATER_REF,
|
||||
PIPE_SIMPLE_WATER_REF_INSTANCED,
|
||||
PIPE_SIMPLE_WATER_REF_ROBOTIC,
|
||||
PIPE_SIMPLE_WATER_REF_SKINNED,
|
||||
PIPE_SIMPLE_ENV_MAP,
|
||||
PIPE_SIMPLE_ENV_MAP_INSTANCED,
|
||||
PIPE_SIMPLE_ENV_MAP_ROBOTIC,
|
||||
PIPE_SIMPLE_ENV_MAP_SKINNED,
|
||||
|
||||
PIPE_SIMPLE_PLANAR_REF,
|
||||
PIPE_SIMPLE_PLANAR_REF_INSTANCED,
|
||||
PIPE_SIMPLE_PLANAR_REF_ROBOTIC,
|
||||
PIPE_SIMPLE_PLANAR_REF_SKINNED,
|
||||
|
||||
PIPE_SIMPLE_TEX_ADD,
|
||||
PIPE_SIMPLE_TEX_ADD_INSTANCED,
|
||||
|
@ -141,7 +146,7 @@ namespace verus
|
|||
|
||||
static CGI::ShaderPtr GetSimpleShader() { return s_shader[SHADER_SIMPLE]; }
|
||||
static UB_SimplePerMaterialFS& GetUbSimplePerMaterialFS() { return s_ubSimplePerMaterialFS; }
|
||||
void UpdateUniformBufferSimplePerFrame();
|
||||
void UpdateUniformBufferSimplePerFrame(DrawSimpleMode mode);
|
||||
void UpdateUniformBufferSimpleSkeletonVS();
|
||||
|
||||
CGI::GeometryPtr GetGeometry() const { return _geo; }
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
enum class DrawDepth : int
|
||||
{
|
||||
no,
|
||||
yes,
|
||||
automatic
|
||||
};
|
||||
|
||||
enum class DrawSimpleMode : int
|
||||
{
|
||||
envMap,
|
||||
planarReflection
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include "Camera.h"
|
||||
#include "CameraOrbit.h"
|
||||
#include "BaseMesh.h"
|
||||
|
@ -8,6 +27,7 @@
|
|||
#include "Terrain.h"
|
||||
#include "EditorTerrain.h"
|
||||
#include "Grass.h"
|
||||
#include "CubeMap.h"
|
||||
#include "ShadowMap.h"
|
||||
#include "Water.h"
|
||||
#include "MaterialManager.h"
|
||||
|
|
|
@ -102,7 +102,7 @@ void SceneManager::Layout()
|
|||
|
||||
PCamera pPrevCamera = nullptr;
|
||||
// For CSM we need to create geometry beyond the view frustum (1st slice):
|
||||
if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::cascaded && atmo.GetShadowMap().IsRendering())
|
||||
if (settings._sceneShadowQuality >= App::Settings::Quality::high && atmo.GetShadowMap().IsRendering())
|
||||
{
|
||||
PCamera pCameraCSM = atmo.GetShadowMap().GetCameraCSM();
|
||||
if (pCameraCSM)
|
||||
|
@ -237,7 +237,7 @@ void SceneManager::Draw()
|
|||
shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void SceneManager::DrawReflection()
|
||||
void SceneManager::DrawSimple(DrawSimpleMode mode)
|
||||
{
|
||||
if (!_visibleCountPerType[+NodeType::block])
|
||||
return;
|
||||
|
@ -285,7 +285,7 @@ void SceneManager::DrawReflection()
|
|||
if (bindPipeline)
|
||||
{
|
||||
bindPipeline = false;
|
||||
model->BindPipelineReflection(cb);
|
||||
model->BindPipelineSimple(mode, cb);
|
||||
cb->BindDescriptors(shader, 0);
|
||||
}
|
||||
model->BindGeo(cb);
|
||||
|
|
|
@ -5,13 +5,6 @@ namespace verus
|
|||
{
|
||||
namespace Scene
|
||||
{
|
||||
enum class DrawDepth : int
|
||||
{
|
||||
no,
|
||||
yes,
|
||||
automatic
|
||||
};
|
||||
|
||||
typedef StoreUnique<String, Model> TStoreModels;
|
||||
typedef StoreUnique<String, SceneParticles> TStoreSceneParticles;
|
||||
typedef StoreUnique<String, Site> TStoreSites;
|
||||
|
@ -65,7 +58,7 @@ namespace verus
|
|||
void UpdateParts();
|
||||
void Layout();
|
||||
void Draw();
|
||||
void DrawReflection();
|
||||
void DrawSimple(DrawSimpleMode mode);
|
||||
void DrawTransparent();
|
||||
void DrawLights();
|
||||
void DrawBounds();
|
||||
|
|
|
@ -291,6 +291,15 @@ void Light::LoadXML(pugi::xml_node node)
|
|||
desc._intShakerScale = node.attribute("intShakerScale").as_float(desc._intShakerScale);
|
||||
if (auto attr = node.attribute("urlIntShaker"))
|
||||
desc._urlIntShaker = attr.value();
|
||||
|
||||
// Normalize:
|
||||
desc._data._dir = VMath::normalize(desc._data._dir);
|
||||
// Convert degrees to cosine:
|
||||
if (desc._data._coneIn > 1)
|
||||
desc._data._coneIn = cos(Math::ToRadians(desc._data._coneIn));
|
||||
if (desc._data._coneOut > 1)
|
||||
desc._data._coneOut = cos(Math::ToRadians(desc._data._coneOut));
|
||||
|
||||
Init(desc);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ namespace verus
|
|||
|
||||
Transform3 GetTransformNoScale() const;
|
||||
virtual void SetTransform(RcTransform3 mat) override;
|
||||
VERUS_P(Vector3 ComputeScale());
|
||||
VERUS_P(void ComputeTransform());
|
||||
Vector3 ComputeScale();
|
||||
void ComputeTransform();
|
||||
|
||||
virtual void UpdateBounds() override;
|
||||
|
||||
|
|
|
@ -66,10 +66,14 @@ void Model::BindPipeline(CGI::CommandBufferPtr cb)
|
|||
_mesh.UpdateUniformBufferPerFrame();
|
||||
}
|
||||
|
||||
void Model::BindPipelineReflection(CGI::CommandBufferPtr cb)
|
||||
void Model::BindPipelineSimple(DrawSimpleMode mode, CGI::CommandBufferPtr cb)
|
||||
{
|
||||
_mesh.BindPipeline(Mesh::PIPE_SIMPLE_WATER_REF_INSTANCED, cb);
|
||||
_mesh.UpdateUniformBufferSimplePerFrame();
|
||||
switch (mode)
|
||||
{
|
||||
case DrawSimpleMode::envMap: _mesh.BindPipeline(Mesh::PIPE_SIMPLE_ENV_MAP_INSTANCED, cb); break;
|
||||
case DrawSimpleMode::planarReflection: _mesh.BindPipeline(Mesh::PIPE_SIMPLE_PLANAR_REF_INSTANCED, cb); break;
|
||||
}
|
||||
_mesh.UpdateUniformBufferSimplePerFrame(mode);
|
||||
}
|
||||
|
||||
void Model::BindGeo(CGI::CommandBufferPtr cb)
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace verus
|
|||
void MarkFirstInstance();
|
||||
void Draw(CGI::CommandBufferPtr cb);
|
||||
void BindPipeline(CGI::CommandBufferPtr cb);
|
||||
void BindPipelineReflection(CGI::CommandBufferPtr cb);
|
||||
void BindPipelineSimple(DrawSimpleMode mode, CGI::CommandBufferPtr cb);
|
||||
void BindGeo(CGI::CommandBufferPtr cb);
|
||||
void PushInstance(RcTransform3 matW, RcVector4 instData);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ void ShadowMap::Begin(RcVector3 dirToSun)
|
|||
|
||||
const Vector3 up(0, 1, 0);
|
||||
Point3 eye, at;
|
||||
const float texSizeInMeters = 4096 * 0.005f;
|
||||
const float texSizeInMeters = 4096 * 0.0075f;
|
||||
const float depth = texSizeInMeters * 10;
|
||||
const float zNear = 1;
|
||||
const float zFar = zNear + depth;
|
||||
|
@ -64,14 +64,14 @@ void ShadowMap::Begin(RcVector3 dirToSun)
|
|||
at = sm.GetCamera()->GetEyePosition() + sm.GetCamera()->GetFrontDirection() * (texSizeInMeters * (1 / 3.f));
|
||||
if (_snapToTexels)
|
||||
{
|
||||
const Matrix4 matToShadowSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
|
||||
const Matrix4 matFromShadowSpace = VMath::orthoInverse(matToShadowSpace);
|
||||
const Point3 atPosShadowSpace = (matToShadowSpace * at).getXYZ();
|
||||
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
|
||||
const Matrix4 matFromLightSpace = VMath::orthoInverse(matToLightSpace);
|
||||
const Point3 atPosLightSpace = (matToLightSpace * at).getXYZ();
|
||||
const float texelSizeInMeters = texSizeInMeters / _side;
|
||||
Point3 atPosShadowSpaceSnapped(atPosShadowSpace);
|
||||
atPosShadowSpaceSnapped.setX(atPosShadowSpaceSnapped.getX() - fmod(atPosShadowSpaceSnapped.getX(), texelSizeInMeters));
|
||||
atPosShadowSpaceSnapped.setY(atPosShadowSpaceSnapped.getY() - fmod(atPosShadowSpaceSnapped.getY(), texelSizeInMeters));
|
||||
at = (matFromShadowSpace * atPosShadowSpaceSnapped).getXYZ();
|
||||
Point3 atPosLightSpaceSnapped(atPosLightSpace);
|
||||
atPosLightSpaceSnapped.setX(atPosLightSpaceSnapped.getX() - fmod(atPosLightSpaceSnapped.getX(), texelSizeInMeters));
|
||||
atPosLightSpaceSnapped.setY(atPosLightSpaceSnapped.getY() - fmod(atPosLightSpaceSnapped.getY(), texelSizeInMeters));
|
||||
at = (matFromLightSpace * atPosLightSpaceSnapped).getXYZ();
|
||||
}
|
||||
eye = at + dirToSun * (depth * (2 / 3.f));
|
||||
|
||||
|
@ -149,14 +149,14 @@ CascadedShadowMap::~CascadedShadowMap()
|
|||
void CascadedShadowMap::Init(int side)
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return ShadowMap::Init(side);
|
||||
|
||||
VERUS_INIT();
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
_side = side;
|
||||
if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra)
|
||||
if (settings._sceneShadowQuality >= App::Settings::Quality::ultra)
|
||||
_side *= 2;
|
||||
|
||||
_rph = renderer->CreateShadowRenderPass(CGI::Format::unormD24uintS8);
|
||||
|
@ -192,7 +192,7 @@ void CascadedShadowMap::Done()
|
|||
void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return ShadowMap::Begin(dirToSun);
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -208,12 +208,15 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
|
||||
float zNearFrustum, zFarFrustum;
|
||||
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
|
||||
const float maxRange = (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra) ? 1000.f : 300.f;
|
||||
const float maxRange = (settings._sceneShadowQuality >= App::Settings::Quality::ultra) ? 1000.f : 300.f;
|
||||
const float range = Math::Min<float>(maxRange, cam.GetZFar() - cam.GetZNear()); // Clip terrain, etc.
|
||||
_camera = cam;
|
||||
|
||||
if (0 == _currentSplit)
|
||||
{
|
||||
_matScreenVP = _camera.GetMatrixVP();
|
||||
_matScreenP = _camera.GetMatrixP();
|
||||
|
||||
const float depth = Math::Min(range * 10, 10000.f);
|
||||
const float zNear = 1;
|
||||
const float zFar = zNear + depth;
|
||||
|
@ -235,6 +238,7 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
texWidthInMeters = ceil(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
|
||||
texHeightInMeters = ceil(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
|
||||
texSizeInMeters = Math::Max(texWidthInMeters, texHeightInMeters);
|
||||
_depth = Math::Clamp<float>(texSizeInMeters * 10, 1000, 10000); // Must be the same for all splits.
|
||||
|
||||
// Setup CSM light space camera for full range (used for terrain layout, etc.):
|
||||
_cameraCSM.SetUpDirection(up);
|
||||
|
@ -249,10 +253,14 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
}
|
||||
|
||||
// Compute split ranges:
|
||||
const float scale = 0.3f;
|
||||
const float scale2 = scale * scale;
|
||||
const float scale3 = scale2 * scale;
|
||||
const float invSum = 1.f / (1 + scale + scale2 + scale3);
|
||||
_splitRanges = Vector4(
|
||||
cam.GetZNear() + range * 0.25f,
|
||||
cam.GetZNear() + range * 0.25f * 0.25f,
|
||||
cam.GetZNear() + range * 0.25f * 0.25f * 0.25f,
|
||||
cam.GetZNear() + range * (invSum * (scale3 + scale2 + scale)),
|
||||
cam.GetZNear() + range * (invSum * (scale3 + scale2)),
|
||||
cam.GetZNear() + range * (invSum * (scale3)),
|
||||
cam.GetZNear());
|
||||
|
||||
// Default scene camera with the current split range:
|
||||
|
@ -286,9 +294,8 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
texWidthInMeters = ceil(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
|
||||
texHeightInMeters = ceil(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
|
||||
texSizeInMeters = Math::Max(texWidthInMeters, texHeightInMeters);
|
||||
const float depth = Math::Min(texSizeInMeters * 10, 10000.f);
|
||||
const float zNear = 1;
|
||||
const float zFar = zNear + depth;
|
||||
const float zFar = zNear + _depth;
|
||||
|
||||
if (_snapToTexels)
|
||||
{
|
||||
|
@ -299,7 +306,7 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
}
|
||||
pos = (VMath::orthoInverse(matToLightSpace) * pos).getXYZ(); // To world space.
|
||||
|
||||
eye = pos + dirToSun * (depth * (2 / 3.f));
|
||||
eye = pos + dirToSun * (_depth * (2 / 3.f));
|
||||
at = pos;
|
||||
|
||||
_splitRanges.setW(cam.GetZNear() + range);
|
||||
|
@ -339,7 +346,7 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, int split)
|
|||
void CascadedShadowMap::End(int split)
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return ShadowMap::End();
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -363,7 +370,7 @@ void CascadedShadowMap::End(int split)
|
|||
RcMatrix4 CascadedShadowMap::GetShadowMatrix(int split) const
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return ShadowMap::GetShadowMatrix();
|
||||
return _matShadowCSM[split];
|
||||
}
|
||||
|
@ -371,7 +378,7 @@ RcMatrix4 CascadedShadowMap::GetShadowMatrix(int split) const
|
|||
RcMatrix4 CascadedShadowMap::GetShadowMatrixDS(int split) const
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return ShadowMap::GetShadowMatrixDS();
|
||||
return _matShadowCSM_DS[split];
|
||||
}
|
||||
|
@ -379,7 +386,7 @@ RcMatrix4 CascadedShadowMap::GetShadowMatrixDS(int split) const
|
|||
PCamera CascadedShadowMap::GetCameraCSM()
|
||||
{
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
if (settings._sceneShadowQuality < App::Settings::ShadowQuality::cascaded)
|
||||
if (settings._sceneShadowQuality < App::Settings::Quality::high)
|
||||
return nullptr;
|
||||
return &_cameraCSM;
|
||||
}
|
||||
|
|
|
@ -58,9 +58,12 @@ namespace verus
|
|||
Matrix4 _matShadowCSM[4];
|
||||
Matrix4 _matShadowCSM_DS[4]; // For WV positions in Deferred Shading.
|
||||
Matrix4 _matOffset[4];
|
||||
Matrix4 _matScreenVP;
|
||||
Matrix4 _matScreenP;
|
||||
Vector4 _splitRanges = Vector4(0);
|
||||
Camera _cameraCSM;
|
||||
int _currentSplit = -1;
|
||||
float _depth = 0;
|
||||
|
||||
public:
|
||||
CascadedShadowMap();
|
||||
|
@ -75,6 +78,9 @@ namespace verus
|
|||
RcMatrix4 GetShadowMatrix(int split = 0) const;
|
||||
RcMatrix4 GetShadowMatrixDS(int split = 0) const;
|
||||
|
||||
RcMatrix4 GetScreenMatrixVP() const { return _matScreenVP; }
|
||||
RcMatrix4 GetScreenMatrixP() const { return _matScreenP; }
|
||||
|
||||
int GetCurrentSplit() const { return _currentSplit; }
|
||||
RcVector4 GetSplitRanges() const { return _splitRanges; }
|
||||
|
||||
|
|
|
@ -432,7 +432,7 @@ void Terrain::Init(RcDesc desc)
|
|||
const int patchSide = _mapSide >> 4;
|
||||
const int patchShift = _mapShift - 4;
|
||||
const int patchCount = patchSide * patchSide;
|
||||
const int maxInstances = patchCount * 8;
|
||||
const int maxInstances = patchCount * 32;
|
||||
|
||||
_vPatches.resize(patchCount);
|
||||
_vPatchTBNs.resize(patchCount * 3);
|
||||
|
@ -586,6 +586,16 @@ void Terrain::Init(RcDesc desc)
|
|||
_pipe[PIPE_WIREFRAME_STRIP].Init(pipeDesc);
|
||||
}
|
||||
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], "#", atmo.GetCubeMap().GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
|
||||
_pipe[PIPE_SIMPLE_ENV_MAP_LIST].Init(pipeDesc);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc._primitiveRestartEnable = true;
|
||||
_pipe[PIPE_SIMPLE_ENV_MAP_STRIP].Init(pipeDesc);
|
||||
}
|
||||
|
||||
CGI::TextureDesc texDesc;
|
||||
texDesc._name = "Terrain.Heightmap";
|
||||
texDesc._format = CGI::Format::floatR16;
|
||||
|
@ -642,18 +652,18 @@ void Terrain::InitByWater()
|
|||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], "#", water.GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
|
||||
_pipe[PIPE_REFLECTION_LIST].Init(pipeDesc);
|
||||
_pipe[PIPE_SIMPLE_PLANAR_REF_LIST].Init(pipeDesc);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc._primitiveRestartEnable = true;
|
||||
_pipe[PIPE_REFLECTION_STRIP].Init(pipeDesc);
|
||||
_pipe[PIPE_SIMPLE_PLANAR_REF_STRIP].Init(pipeDesc);
|
||||
}
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], "#", water.GetRenderPassHandle());
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
|
||||
_pipe[PIPE_UNDERWATER_LIST].Init(pipeDesc);
|
||||
_pipe[PIPE_SIMPLE_UNDERWATER_LIST].Init(pipeDesc);
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc._primitiveRestartEnable = true;
|
||||
_pipe[PIPE_UNDERWATER_STRIP].Init(pipeDesc);
|
||||
_pipe[PIPE_SIMPLE_UNDERWATER_STRIP].Init(pipeDesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -686,7 +696,7 @@ void Terrain::Layout()
|
|||
|
||||
PCamera pPrevCamera = nullptr;
|
||||
// For CSM we need to create geometry beyond the view frustum (1st slice):
|
||||
if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::cascaded && atmo.GetShadowMap().IsRendering())
|
||||
if (settings._sceneShadowQuality >= App::Settings::Quality::high && atmo.GetShadowMap().IsRendering())
|
||||
{
|
||||
PCamera pCameraCSM = atmo.GetShadowMap().GetCameraCSM();
|
||||
if (pCameraCSM)
|
||||
|
@ -817,7 +827,7 @@ void Terrain::Draw(RcDrawDesc dd)
|
|||
_instanceCount += _visiblePatchCount;
|
||||
}
|
||||
|
||||
void Terrain::DrawReflection()
|
||||
void Terrain::DrawSimple(DrawSimpleMode mode)
|
||||
{
|
||||
VERUS_QREF_ATMO;
|
||||
VERUS_QREF_RENDERER;
|
||||
|
@ -828,6 +838,7 @@ void Terrain::DrawReflection()
|
|||
return;
|
||||
|
||||
const Transform3 matW = Transform3::identity();
|
||||
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? USHRT_MAX : 0;
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
||||
|
@ -835,7 +846,7 @@ void Terrain::DrawReflection()
|
|||
s_ubSimpleTerrainVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
|
||||
s_ubSimpleTerrainVS._eyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.x = 1.f / _mapSide;
|
||||
s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.y = static_cast<float>(water.IsUnderwater() ? USHRT_MAX : 0);
|
||||
s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.y = clipDistanceOffset;
|
||||
VERUS_FOR(i, VERUS_COUNT_OF(_layerData))
|
||||
s_ubSimpleTerrainFS._vSpecStrength[i >> 2][i & 0x3] = _layerData[i]._specStrength;
|
||||
s_ubSimpleTerrainFS._lamScaleBias.x = _lamScale;
|
||||
|
@ -844,12 +855,13 @@ void Terrain::DrawReflection()
|
|||
s_ubSimpleTerrainFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubSimpleTerrainFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubSimpleTerrainFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubSimpleTerrainFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubSimpleTerrainFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubSimpleTerrainFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubSimpleTerrainFS._shadowConfig));
|
||||
s_ubSimpleTerrainFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
|
||||
cb->BindVertexBuffers(_geo);
|
||||
cb->BindIndexBuffer(_geo);
|
||||
|
@ -870,20 +882,24 @@ void Terrain::DrawReflection()
|
|||
|
||||
if (!lod)
|
||||
{
|
||||
if (water.IsUnderwater())
|
||||
cb->BindPipeline(_pipe[PIPE_UNDERWATER_LIST]);
|
||||
if (DrawSimpleMode::envMap == mode)
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_ENV_MAP_LIST]);
|
||||
else if (water.IsUnderwater())
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_UNDERWATER_LIST]);
|
||||
else
|
||||
cb->BindPipeline(_pipe[PIPE_REFLECTION_LIST]);
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_PLANAR_REF_LIST]);
|
||||
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 0, _cshSimpleVS);
|
||||
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 1, _cshSimpleFS);
|
||||
}
|
||||
else if (bindStrip)
|
||||
{
|
||||
bindStrip = false;
|
||||
if (water.IsUnderwater())
|
||||
cb->BindPipeline(_pipe[PIPE_UNDERWATER_STRIP]);
|
||||
if (DrawSimpleMode::envMap == mode)
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_ENV_MAP_STRIP]);
|
||||
else if (water.IsUnderwater())
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_UNDERWATER_STRIP]);
|
||||
else
|
||||
cb->BindPipeline(_pipe[PIPE_REFLECTION_STRIP]);
|
||||
cb->BindPipeline(_pipe[PIPE_SIMPLE_PLANAR_REF_STRIP]);
|
||||
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 0, _cshSimpleVS);
|
||||
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 1, _cshSimpleFS);
|
||||
}
|
||||
|
|
|
@ -102,10 +102,12 @@ namespace verus
|
|||
|
||||
PIPE_WIREFRAME_LIST,
|
||||
PIPE_WIREFRAME_STRIP,
|
||||
PIPE_REFLECTION_LIST,
|
||||
PIPE_REFLECTION_STRIP,
|
||||
PIPE_UNDERWATER_LIST,
|
||||
PIPE_UNDERWATER_STRIP,
|
||||
PIPE_SIMPLE_ENV_MAP_LIST,
|
||||
PIPE_SIMPLE_ENV_MAP_STRIP,
|
||||
PIPE_SIMPLE_PLANAR_REF_LIST,
|
||||
PIPE_SIMPLE_PLANAR_REF_STRIP,
|
||||
PIPE_SIMPLE_UNDERWATER_LIST,
|
||||
PIPE_SIMPLE_UNDERWATER_STRIP,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
|
@ -213,7 +215,7 @@ namespace verus
|
|||
void ResetInstanceCount();
|
||||
void Layout();
|
||||
void Draw(RcDrawDesc dd = DrawDesc());
|
||||
void DrawReflection();
|
||||
void DrawSimple(DrawSimpleMode mode);
|
||||
|
||||
void SortVisiblePatches();
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ void Water::Init(RTerrain terrain)
|
|||
|
||||
_pTerrain = &terrain;
|
||||
|
||||
_rphGenHeightmap = renderer->CreateSimpleRenderPass(CGI::Format::floatR16, CGI::ImageLayout::xsReadOnly);
|
||||
_rphGenHeightmap = renderer->CreateSimpleRenderPass(CGI::Format::floatR16, CGI::RP::Attachment::LoadOp::dontCare, CGI::ImageLayout::xsReadOnly);
|
||||
_rphGenNormals = renderer->CreateSimpleRenderPass(CGI::Format::unormR10G10B10A2);
|
||||
_rphReflection = renderer->CreateRenderPass(
|
||||
{
|
||||
|
@ -258,12 +258,13 @@ void Water::Draw()
|
|||
s_ubWaterFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
|
||||
s_ubWaterFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubWaterFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubWaterFS._matSunShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubWaterFS._matSunShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubWaterFS._matSunShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubWaterFS._matSunShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubWaterFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubWaterFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubWaterFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubWaterFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubWaterFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubWaterFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubWaterFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubWaterFS._shadowConfig));
|
||||
s_ubWaterFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_MAIN]);
|
||||
cb->BindVertexBuffers(_geo);
|
||||
|
@ -301,7 +302,7 @@ void Water::OnSwapChainResized()
|
|||
});
|
||||
}
|
||||
|
||||
void Water::BeginReflection(CGI::PBaseCommandBuffer pCB)
|
||||
void Water::BeginPlanarReflection(CGI::PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
@ -321,7 +322,7 @@ void Water::BeginReflection(CGI::PBaseCommandBuffer pCB)
|
|||
});
|
||||
}
|
||||
|
||||
void Water::EndReflection(CGI::PBaseCommandBuffer pCB)
|
||||
void Water::EndPlanarReflection(CGI::PBaseCommandBuffer pCB)
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
|
|
|
@ -93,8 +93,8 @@ namespace verus
|
|||
void OnSwapChainResized();
|
||||
|
||||
CGI::RPHandle GetRenderPassHandle() const { return _rphReflection; }
|
||||
void BeginReflection(CGI::PBaseCommandBuffer pCB = nullptr);
|
||||
void EndReflection(CGI::PBaseCommandBuffer pCB = nullptr);
|
||||
void BeginPlanarReflection(CGI::PBaseCommandBuffer pCB = nullptr);
|
||||
void EndPlanarReflection(CGI::PBaseCommandBuffer pCB = nullptr);
|
||||
|
||||
void GenerateTextures();
|
||||
VERUS_P(void GenerateHeightmapTexture());
|
||||
|
|
|
@ -9,8 +9,8 @@ ConstantBuffer<UB_BloomVS> g_ubBloomVS : register(b0, space0);
|
|||
ConstantBuffer<UB_BloomFS> g_ubBloomFS : register(b0, space1);
|
||||
ConstantBuffer<UB_BloomGodRaysFS> g_ubBloomGodRaysFS : register(b0, space2);
|
||||
|
||||
Texture2D g_tex : register(t1, space1);
|
||||
SamplerState g_sam : register(s1, space1);
|
||||
Texture2D g_texColor : register(t1, space1);
|
||||
SamplerState g_samColor : register(s1, space1);
|
||||
Texture2D g_texDepth : register(t1, space2);
|
||||
SamplerState g_samDepth : register(s1, space2);
|
||||
Texture2D g_texShadow : register(t2, space2);
|
||||
|
@ -50,54 +50,75 @@ FSO mainFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
const float4 rawColor = g_tex.SampleLevel(g_sam, si.tc0, 0.0);
|
||||
const float3 color = rawColor.rgb * g_ubBloomFS._exposure.x;
|
||||
const float3 bloom = saturate((color - 0.95) * 0.6);
|
||||
|
||||
#ifdef DEF_GOD_RAYS
|
||||
const float maxDist = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.x;
|
||||
const float sunGloss = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.y;
|
||||
const float wideStrength = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.z;
|
||||
const float sunStrength = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.w;
|
||||
|
||||
const float2 ndcPos = ToNdcPos(si.tc0);
|
||||
const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r;
|
||||
const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).r;
|
||||
const float3 posW = DS_GetPosition(rawDepth, g_ubBloomGodRaysFS._matInvVP, ndcPos);
|
||||
|
||||
const float3 eyePos = g_ubBloomGodRaysFS._eyePos.xyz;
|
||||
const float3 toPosW = posW - eyePos;
|
||||
const float depth = length(toPosW);
|
||||
const float3 pickingRayDir = toPosW / depth;
|
||||
const float strength = pow(saturate(dot(g_ubBloomGodRaysFS._dirToSun.xyz, pickingRayDir)), 7.0) * 0.2;
|
||||
const float2 spec = pow(saturate(dot(g_ubBloomGodRaysFS._dirToSun.xyz, pickingRayDir)), float2(7, sunGloss));
|
||||
const float strength = dot(spec, float2(wideStrength, sunStrength));
|
||||
|
||||
float3 godRays = 0.0;
|
||||
if (strength > 0.0)
|
||||
float3 godRays = 0.f;
|
||||
if (strength >= 0.0001f)
|
||||
{
|
||||
const float3 rand = Rand(si.pos.xy);
|
||||
const int sampleCount = 20;
|
||||
float acc = 0.0;
|
||||
|
||||
#if _SHADER_QUALITY <= _Q_LOW
|
||||
const int sampleCount = 8;
|
||||
#elif _SHADER_QUALITY <= _Q_MEDIUM
|
||||
const int sampleCount = 16;
|
||||
#elif _SHADER_QUALITY <= _Q_HIGH
|
||||
const int sampleCount = 32;
|
||||
#elif _SHADER_QUALITY <= _Q_ULTRA
|
||||
const int sampleCount = 64;
|
||||
#endif
|
||||
const float stride = maxDist / sampleCount;
|
||||
|
||||
float pickingRayLen = rand.y * stride;
|
||||
float acc = 0.f;
|
||||
[unroll] for (int i = 0; i < sampleCount; ++i)
|
||||
{
|
||||
const float pickingRayLen = rand.y + i;
|
||||
const float3 pos = eyePos + pickingRayDir * pickingRayLen;
|
||||
|
||||
const float4 tcShadow = ShadowCoords(float4(pos, 1), g_ubBloomGodRaysFS._matSunShadow, pickingRayLen);
|
||||
const float shadowMask = SimpleShadowMapCSM(
|
||||
g_texShadow,
|
||||
g_samShadow,
|
||||
tcShadow,
|
||||
g_ubBloomGodRaysFS._shadowConfig,
|
||||
g_ubBloomGodRaysFS._splitRanges,
|
||||
g_ubBloomGodRaysFS._matSunShadow,
|
||||
g_ubBloomGodRaysFS._matSunShadowCSM1,
|
||||
g_ubBloomGodRaysFS._matSunShadowCSM2,
|
||||
g_ubBloomGodRaysFS._matSunShadowCSM3);
|
||||
pos,
|
||||
pos,
|
||||
g_ubBloomGodRaysFS._matShadow,
|
||||
g_ubBloomGodRaysFS._matShadowCSM1,
|
||||
g_ubBloomGodRaysFS._matShadowCSM2,
|
||||
g_ubBloomGodRaysFS._matShadowCSM3,
|
||||
g_ubBloomGodRaysFS._matScreenCSM,
|
||||
g_ubBloomGodRaysFS._csmSplitRanges,
|
||||
g_ubBloomGodRaysFS._shadowConfig);
|
||||
acc += shadowMask * step(pickingRayLen, depth);
|
||||
pickingRayLen += stride;
|
||||
}
|
||||
godRays = acc * (1.0 / sampleCount) * g_ubBloomGodRaysFS._sunColor.rgb * g_ubBloomFS._exposure.x * strength;
|
||||
godRays = acc * (1.f / sampleCount) * g_ubBloomGodRaysFS._sunColor.rgb * g_ubBloomFS._exposure.x * strength;
|
||||
}
|
||||
|
||||
so.color.rgb = bloom + godRays;
|
||||
so.color.rgb = godRays;
|
||||
#else
|
||||
const float colorScale = g_ubBloomFS._colorScale_colorBias.x;
|
||||
const float colorBias = g_ubBloomFS._colorScale_colorBias.y;
|
||||
|
||||
const float4 rawColor = g_texColor.SampleLevel(g_samColor, si.tc0, 0.f);
|
||||
const float3 color = rawColor.rgb * g_ubBloomFS._exposure.x;
|
||||
const float3 bloom = saturate((color - colorBias) * colorScale);
|
||||
|
||||
so.color.rgb = bloom;
|
||||
#endif
|
||||
|
||||
so.color.a = 1.0;
|
||||
so.color.a = 1.f;
|
||||
|
||||
return so;
|
||||
}
|
||||
|
|
|
@ -9,18 +9,22 @@ VERUS_UBUFFER UB_BloomVS
|
|||
VERUS_UBUFFER UB_BloomFS
|
||||
{
|
||||
float4 _exposure;
|
||||
float4 _colorScale_colorBias;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_BloomGodRaysFS
|
||||
{
|
||||
matrix _matInvVP;
|
||||
matrix _matSunShadow;
|
||||
matrix _matSunShadowCSM1;
|
||||
matrix _matSunShadowCSM2;
|
||||
matrix _matSunShadowCSM3;
|
||||
float4 _shadowConfig;
|
||||
float4 _splitRanges;
|
||||
float4 _dirToSun;
|
||||
float4 _sunColor;
|
||||
float4 _eyePos;
|
||||
float4 _maxDist_sunGloss_wideStrength_sunStrength;
|
||||
|
||||
matrix _matShadow;
|
||||
matrix _matShadowCSM1;
|
||||
matrix _matShadowCSM2;
|
||||
matrix _matShadowCSM3;
|
||||
matrix _matScreenCSM;
|
||||
float4 _csmSplitRanges;
|
||||
float4 _shadowConfig;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,14 @@ struct FSO
|
|||
float4 color : SV_Target0;
|
||||
};
|
||||
|
||||
float GlossBoost(float gloss)
|
||||
{
|
||||
const float x = 1.f - gloss;
|
||||
return 1.f - x * x;
|
||||
}
|
||||
|
||||
// <DefaultBlur>
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainVS(VSI si)
|
||||
{
|
||||
|
@ -51,44 +59,86 @@ FSO mainFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
#if _ANISOTROPY_LEVEL > 4
|
||||
const int stride = 2;
|
||||
#ifdef DEF_SSR
|
||||
const float alpha = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f).r;
|
||||
const float gloss = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).a;
|
||||
|
||||
const float gloss64 = gloss * 64.f;
|
||||
const float eyeMask = saturate(1.f - gloss64);
|
||||
const float scaleByAlpha = 1.f - alpha;
|
||||
const float scaleByGloss = 1.f - GlossBoost(lerp(gloss, 0.75f, eyeMask));
|
||||
const float scale = max(0.001f, min(scaleByAlpha, scaleByGloss));
|
||||
|
||||
const int sampleCount = max(4, g_ubBlurFS._sampleCount * scale);
|
||||
const float radius = g_ubBlurFS._radius_invRadius_stride.x * scale;
|
||||
const float invRadius = 1.f / radius;
|
||||
const float stride = radius * 2.f / (sampleCount - 1);
|
||||
#else
|
||||
const int stride = 4;
|
||||
const int sampleCount = g_ubBlurFS._sampleCount;
|
||||
const float radius = g_ubBlurFS._radius_invRadius_stride.x;
|
||||
const float invRadius = g_ubBlurFS._radius_invRadius_stride.y;
|
||||
const float stride = g_ubBlurFS._radius_invRadius_stride.z;
|
||||
#endif
|
||||
|
||||
float4 acc = 0.0;
|
||||
#ifdef DEF_SSAO
|
||||
const float weightSum = 2.0;
|
||||
[unroll] for (int i = -1; i <= 1; i += 2)
|
||||
#else
|
||||
float weightSum = _SINGULARITY_FIX;
|
||||
[unroll] for (int i = -8; i <= 7; i += stride)
|
||||
#endif
|
||||
float4 acc = 0.f;
|
||||
float2 offset_weightSum = float2(-radius, 0);
|
||||
for (int i = 0; i < sampleCount; ++i)
|
||||
{
|
||||
#ifdef DEF_VERTICAL
|
||||
const int2 offset = int2(0, i);
|
||||
// Poor man's gaussian kernel:
|
||||
const float curve = smoothstep(1.f, 0.f, abs(offset_weightSum.x) * invRadius);
|
||||
const float weight = curve * curve;
|
||||
#ifdef DEF_V
|
||||
const float2 tc = si.tc0 + float2(0, offset_weightSum.x);
|
||||
#else
|
||||
const int2 offset = int2(i, 0);
|
||||
#endif
|
||||
|
||||
#ifdef DEF_SSAO
|
||||
const float weight = 1.0;
|
||||
#else
|
||||
const float weight = smoothstep(0.0, 1.0, (1.0 - abs(i) * 0.1));
|
||||
weightSum += weight;
|
||||
#endif
|
||||
|
||||
#if defined(DEF_SSAO) && defined(DEF_VERTICAL) // Sampling from sRGB, use alpha channel:
|
||||
acc += g_tex.SampleLevel(g_sam, si.tc0, 0.0, offset).aaaa;
|
||||
#else
|
||||
acc += g_tex.SampleLevel(g_sam, si.tc0, 0.0, offset) * weight;
|
||||
const float2 tc = si.tc0 + float2(offset_weightSum.x, 0);
|
||||
#endif
|
||||
acc += g_tex.SampleLevel(g_sam, tc, 0.f) * weight;
|
||||
offset_weightSum += float2(stride, weight);
|
||||
}
|
||||
acc *= (1.0 / weightSum);
|
||||
acc *= 1.f / offset_weightSum.y;
|
||||
|
||||
so.color = acc;
|
||||
#if defined(DEF_SSAO) && !defined(DEF_VERTICAL) // Make sure to write R channel to alpha, destination is sRGB.
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
// </DefaultBlur>
|
||||
|
||||
// <SsaoBlur>
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainSsaoVS(VSI si)
|
||||
{
|
||||
VSO so;
|
||||
|
||||
// Standard quad:
|
||||
so.pos = float4(mul(si.pos, g_ubBlurVS._matW), 1);
|
||||
so.tc0 = mul(si.pos, g_ubBlurVS._matV).xy;
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _FS
|
||||
FSO mainSsaoFS(VSO si)
|
||||
{
|
||||
FSO so;
|
||||
|
||||
// 4x4 box blur, using texture filtering.
|
||||
float4 acc = 0.f;
|
||||
[unroll] for (int i = -1; i <= 1; i += 2)
|
||||
{
|
||||
#ifdef DEF_V // Sampling from sRGB, use alpha channel:
|
||||
acc += g_tex.SampleLevel(g_sam, si.tc0, 0.f, int2(0, i)).aaaa;
|
||||
#else
|
||||
acc += g_tex.SampleLevel(g_sam, si.tc0, 0.f, int2(i, 0));
|
||||
#endif
|
||||
}
|
||||
acc *= 0.5f;
|
||||
|
||||
so.color = acc;
|
||||
#ifndef DEF_V // Make sure to write R channel to alpha, destination is sRGB.
|
||||
so.color = acc.rrrr;
|
||||
#endif
|
||||
|
||||
|
@ -96,6 +146,8 @@ FSO mainFS(VSO si)
|
|||
}
|
||||
#endif
|
||||
|
||||
// </SsaoBlur>
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainAntiAliasingVS(VSI si)
|
||||
{
|
||||
|
@ -114,7 +166,7 @@ FSO mainAntiAliasingFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f);
|
||||
const float3 normalWV = DS_GetNormal(rawGBuffer1);
|
||||
const float coarseAlpha = normalWV.b * normalWV.b * normalWV.b;
|
||||
|
||||
|
@ -123,19 +175,19 @@ FSO mainAntiAliasingFS(VSO si)
|
|||
float originDeeper;
|
||||
float depthBasedEdge;
|
||||
{
|
||||
const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r;
|
||||
const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).r;
|
||||
const float originDepth = ToLinearDepth(rawOriginDepth, g_ubExtraBlurFS._zNearFarEx);
|
||||
const float4 rawKernelDepths = float4(
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(-1, +0)).r, // L
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+0, -1)).r, // T
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+1, +0)).r, // R
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0, int2(+0, +1)).r); // B
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f, int2(-1, +0)).r, // L
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f, int2(+0, -1)).r, // T
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f, int2(+1, +0)).r, // R
|
||||
g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f, int2(+0, +1)).r); // B
|
||||
const float4 kernelDepths = ToLinearDepth(rawKernelDepths, g_ubExtraBlurFS._zNearFarEx);
|
||||
const float minDepth = min(min(kernelDepths[0], kernelDepths[1]), min(kernelDepths[2], kernelDepths[3]));
|
||||
const float equalize = 1.0 / originDepth;
|
||||
const float equalize = 1.f / originDepth;
|
||||
originDeeper = saturate((originDepth - minDepth) * equalize);
|
||||
const float4 depthOffsets = abs((originDepth - kernelDepths) * equalize);
|
||||
depthBasedEdge = saturate(dot(depthOffsets, 1.0));
|
||||
depthBasedEdge = saturate(dot(depthOffsets, 1.f));
|
||||
|
||||
const float3 v0 = float3(1, 0, kernelDepths[0] - kernelDepths[2]);
|
||||
const float3 v1 = float3(0, 1, kernelDepths[3] - kernelDepths[1]);
|
||||
|
@ -147,11 +199,11 @@ FSO mainAntiAliasingFS(VSO si)
|
|||
float normalBasedEdge;
|
||||
{
|
||||
const float4 rawNrmLT = float4(
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(-1, +0)).rg,
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+0, -1)).rg);
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f, int2(-1, +0)).rg,
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f, int2(+0, -1)).rg);
|
||||
const float4 rawNrmRB = float4(
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+1, +0)).rg,
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(+0, +1)).rg);
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f, int2(+1, +0)).rg,
|
||||
g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f, int2(+0, +1)).rg);
|
||||
const float4 diffA = rawNrmLT - rawNrmRB;
|
||||
const float4 diffB = rawNrmLT - rawNrmRB.zwxy;
|
||||
const float4 dots = float4(
|
||||
|
@ -160,40 +212,40 @@ FSO mainAntiAliasingFS(VSO si)
|
|||
dot(diffB.xy, diffB.xy),
|
||||
dot(diffB.zw, diffB.zw));
|
||||
const float maxDot = max(max(dots.x, dots.y), max(dots.z, dots.w));
|
||||
normalBasedEdge = saturate(maxDot * maxDot * 10.0);
|
||||
normalBasedEdge = saturate(maxDot * maxDot * 10.f);
|
||||
}
|
||||
// </NormalBased>
|
||||
|
||||
// Directional blur:
|
||||
const float3 normal = lerp(normalWV, coarseNorm, coarseAlpha * 0.5);
|
||||
const float3 normal = lerp(normalWV, coarseNorm, coarseAlpha * 0.5f);
|
||||
// {y, -x} is perpendicular vector. Also flip Y axis: normal XY to texture UV.
|
||||
const float3 perp = normal.yxz;
|
||||
const float omni = max(perp.z * perp.z * perp.z, originDeeper);
|
||||
const float2 dirs[4] =
|
||||
{
|
||||
lerp(perp.xy * +4.0, float2(-0.4, -0.2), omni),
|
||||
lerp(perp.xy * -2.0, float2(+0.2, -0.4), omni),
|
||||
lerp(perp.xy * -4.0, float2(-0.2, +0.4), omni),
|
||||
lerp(perp.xy * +2.0, float2(+0.4, +0.2), omni)
|
||||
lerp(perp.xy * +4.f, float2(-0.4f, -0.2f), omni),
|
||||
lerp(perp.xy * -2.f, float2(+0.2f, -0.4f), omni),
|
||||
lerp(perp.xy * -4.f, float2(-0.2f, +0.4f), omni),
|
||||
lerp(perp.xy * +2.f, float2(+0.4f, +0.2f), omni)
|
||||
};
|
||||
const float2 offsetScale = g_ubExtraBlurFS._textureSize.zw * max(normalBasedEdge, depthBasedEdge);
|
||||
const float3 kernelColors[4] =
|
||||
{
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[0] * offsetScale, 0.0).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[1] * offsetScale, 0.0).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[2] * offsetScale, 0.0).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[3] * offsetScale, 0.0).rgb
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[0] * offsetScale, 0.f).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[1] * offsetScale, 0.f).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[2] * offsetScale, 0.f).rgb,
|
||||
g_tex.SampleLevel(g_sam, si.tc0 + dirs[3] * offsetScale, 0.f).rgb
|
||||
};
|
||||
const float3 sdrKernelColors[4] =
|
||||
{
|
||||
ToneMappingReinhard(kernelColors[0] * 0.001),
|
||||
ToneMappingReinhard(kernelColors[1] * 0.001),
|
||||
ToneMappingReinhard(kernelColors[2] * 0.001),
|
||||
ToneMappingReinhard(kernelColors[3] * 0.001)
|
||||
ToneMappingReinhard(kernelColors[0] * 0.001f),
|
||||
ToneMappingReinhard(kernelColors[1] * 0.001f),
|
||||
ToneMappingReinhard(kernelColors[2] * 0.001f),
|
||||
ToneMappingReinhard(kernelColors[3] * 0.001f)
|
||||
};
|
||||
so.color.rgb = (sdrKernelColors[0] + sdrKernelColors[1] + sdrKernelColors[2] + sdrKernelColors[3]) * 0.25;
|
||||
so.color.rgb = ToneMappingInvReinhard(so.color.rgb) * 1000.0;
|
||||
so.color.a = 1.0;
|
||||
so.color.rgb = (sdrKernelColors[0] + sdrKernelColors[1] + sdrKernelColors[2] + sdrKernelColors[3]) * 0.25f;
|
||||
so.color.rgb = ToneMappingInvReinhard(so.color.rgb) * 1000.f;
|
||||
so.color.a = 1.f;
|
||||
|
||||
return so;
|
||||
}
|
||||
|
@ -218,14 +270,23 @@ FSO mainMotionFS(VSO si)
|
|||
FSO so;
|
||||
|
||||
const float3 rand = Rand(si.pos.xy);
|
||||
const float offsetScale = 0.3 + 0.2 * rand.x; // Blur 30% - 50% of frame time.
|
||||
const float offsetScale = 0.45f + 0.05f * rand.x; // Blur 45% - 50% of frame time.
|
||||
|
||||
const int sampleCount = max(4, _ANISOTROPY_LEVEL);
|
||||
#if _SHADER_QUALITY <= _Q_LOW
|
||||
const int sampleCount = 4;
|
||||
#elif _SHADER_QUALITY <= _Q_MEDIUM
|
||||
const int sampleCount = 8;
|
||||
#elif _SHADER_QUALITY <= _Q_HIGH
|
||||
const int sampleCount = 16;
|
||||
#elif _SHADER_QUALITY <= _Q_ULTRA
|
||||
const int sampleCount = 32;
|
||||
#endif
|
||||
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f);
|
||||
|
||||
const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r;
|
||||
const float rawOriginDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).r;
|
||||
const float originDepth = ToLinearDepth(rawOriginDepth, g_ubExtraBlurFS._zNearFarEx);
|
||||
const float equalize = min(0.1f, 1.f / originDepth);
|
||||
|
||||
float2 tcFrom;
|
||||
{
|
||||
|
@ -237,24 +298,24 @@ FSO mainMotionFS(VSO si)
|
|||
}
|
||||
|
||||
const float2 stride = (si.tc0 - tcFrom) * offsetScale / (sampleCount - 1);
|
||||
const float2 tcOrigin = lerp(tcFrom, si.tc0, 0.8);
|
||||
const float2 tcOrigin = lerp(tcFrom, si.tc0, 0.75f); // Start from this location up to offsetScale.
|
||||
|
||||
float4 acc = float4(g_tex.SampleLevel(g_sam, si.tc0, 0.0).rgb, 1);
|
||||
[unroll] for (int i = 0; i < sampleCount; i++)
|
||||
float4 acc = float4(g_tex.SampleLevel(g_sam, si.tc0, 0.f).rgb, 1);
|
||||
[unroll] for (int i = 0; i < sampleCount; ++i)
|
||||
{
|
||||
if (i == sampleCount / 2)
|
||||
continue;
|
||||
continue; // Midpoint already sampled.
|
||||
|
||||
const float2 kernelCoords = tcOrigin + stride * i;
|
||||
|
||||
const float rawKernelDepth = g_texDepth.SampleLevel(g_samDepth, kernelCoords, 0.0).r;
|
||||
const float rawKernelDepth = g_texDepth.SampleLevel(g_samDepth, kernelCoords, 0.f).r;
|
||||
const float kernelDepth = ToLinearDepth(rawKernelDepth, g_ubExtraBlurFS._zNearFarEx);
|
||||
const float kernelDeeper = kernelDepth - originDepth;
|
||||
const float allowed = saturate(kernelDeeper * 0.2 + 1.0) * rawGBuffer1.a;
|
||||
const float weight = saturate(kernelDeeper * 0.2) + 1.0;
|
||||
const float allowed = saturate(1.f + kernelDeeper * 2.f * equalize) * rawGBuffer1.a; // Closer points require extra care.
|
||||
const float weight = 1.f + saturate(kernelDeeper * 0.2f); // To fix the seam between foreground and background.
|
||||
|
||||
const float3 kernelColor = g_tex.SampleLevel(g_sam, kernelCoords, 0.0).rgb;
|
||||
acc += lerp(0.0, float4(kernelColor * weight, weight), allowed);
|
||||
const float3 kernelColor = g_tex.SampleLevel(g_sam, kernelCoords, 0.f).rgb;
|
||||
acc += lerp(0.f, float4(kernelColor * weight, weight), allowed);
|
||||
}
|
||||
acc /= acc.a;
|
||||
|
||||
|
@ -264,9 +325,11 @@ FSO mainMotionFS(VSO si)
|
|||
}
|
||||
#endif
|
||||
|
||||
//@main:#H
|
||||
//@main:#V VERTICAL
|
||||
//@main:#HSsao SSAO
|
||||
//@main:#VSsao SSAO VERTICAL
|
||||
//@main:#U U
|
||||
//@main:#V V
|
||||
//@mainSsao:#USsao SSAO U
|
||||
//@mainSsao:#VSsao SSAO V
|
||||
//@main:#USsr SSR U
|
||||
//@main:#VSsr SSR V
|
||||
//@mainAntiAliasing:#AntiAliasing AA
|
||||
//@mainMotion:#Motion MOTION
|
||||
|
|
|
@ -8,7 +8,8 @@ VERUS_UBUFFER UB_BlurVS
|
|||
|
||||
VERUS_UBUFFER UB_BlurFS
|
||||
{
|
||||
float4 _dummy;
|
||||
float3 _radius_invRadius_stride;
|
||||
int _sampleCount;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_ExtraBlurFS
|
||||
|
|
|
@ -68,7 +68,6 @@ VSO mainVS(VSI si)
|
|||
const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubPerFrame._matV));
|
||||
|
||||
const float3x3 matW33 = (float3x3)matW;
|
||||
const float3x3 matV33 = (float3x3)g_ubPerFrame._matV;
|
||||
const float3x3 matWV33 = (float3x3)matWV;
|
||||
|
||||
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
|
||||
|
@ -87,7 +86,7 @@ VSO mainVS(VSI si)
|
|||
const float3 posUnit = mul(float3(0, 0, 1), matW33); // Need to know the scale.
|
||||
so.radius_radiusSq_invRadiusSq.y = dot(posUnit, posUnit);
|
||||
so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y);
|
||||
so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y;
|
||||
so.radius_radiusSq_invRadiusSq.z = 1.f / so.radius_radiusSq_invRadiusSq.y;
|
||||
const float4 posOrigin = float4(0, 0, 0, 1);
|
||||
so.lightPosWV = mul(posOrigin, matWV).xyz;
|
||||
#endif
|
||||
|
@ -101,7 +100,7 @@ VSO mainVS(VSI si)
|
|||
const float3 dirCone = normalize(posCone);
|
||||
const float3 dirUnit = normalize(posUnit);
|
||||
const float coneOut = dot(dirUnit, dirCone);
|
||||
const float invConeDelta = 1.0 / (coneIn - coneOut);
|
||||
const float invConeDelta = 1.f / (coneIn - coneOut);
|
||||
so.lightDirWV_invConeDelta.w = invConeDelta;
|
||||
so.color_coneOut.a = coneOut;
|
||||
#endif
|
||||
|
@ -145,45 +144,45 @@ DS_ACC_FSO mainFS(VSO si)
|
|||
const float depth = VK_SUBPASS_LOAD(g_texDepth, g_samDepth, tc0).r;
|
||||
const float3 posWV = DS_GetPosition(depth, g_ubPerFrame._matInvP, ndcPos.xy);
|
||||
|
||||
so.target0 = 0.0;
|
||||
so.target1 = 0.0;
|
||||
so.target0 = 0.f;
|
||||
so.target1 = 0.f;
|
||||
|
||||
#if defined(DEF_OMNI) || defined(DEF_SPOT)
|
||||
if (posWV.z <= lightPosWV.z + radius)
|
||||
#endif
|
||||
{
|
||||
// Light's diffuse & specular color:
|
||||
const float3 hdrLightColor = si.color_coneOut.rgb;
|
||||
const float3 lightColor = si.color_coneOut.rgb;
|
||||
|
||||
// GBuffer0 (albedo, spec):
|
||||
// GBuffer0 {albedo, specMask}:
|
||||
const float4 rawGBuffer0 = VK_SUBPASS_LOAD(g_texGBuffer0, g_samGBuffer0, tc0);
|
||||
const float spec = rawGBuffer0.a;
|
||||
const float specMask = rawGBuffer0.a;
|
||||
const float3 dirToEyeWV = normalize(-posWV);
|
||||
|
||||
// GBuffer2 (normal, emission, motion):
|
||||
// GBuffer2 {normal, emission|skinMask, motionBlurMask}:
|
||||
const float4 rawGBuffer1 = VK_SUBPASS_LOAD(g_texGBuffer1, g_samGBuffer1, tc0);
|
||||
const float3 normalWV = DS_GetNormal(rawGBuffer1);
|
||||
const float2 emission = DS_GetEmission(rawGBuffer1);
|
||||
|
||||
// GBuffer3 (lam, metal, gloss):
|
||||
// GBuffer3 {lamScaleBias, metalMask|hairMask, gloss}:
|
||||
const float4 rawGBuffer2 = VK_SUBPASS_LOAD(g_texGBuffer2, g_samGBuffer2, tc0);
|
||||
const float3 anisoWV = DS_GetAnisoSpec(rawGBuffer2);
|
||||
const float2 lamScaleBias = DS_GetLamScaleBias(rawGBuffer2);
|
||||
const float2 metal = DS_GetMetallicity(rawGBuffer2);
|
||||
const float gloss64 = rawGBuffer2.a * 64.0;
|
||||
const float2 metalMask = DS_GetMetallicity(rawGBuffer2);
|
||||
const float gloss64 = rawGBuffer2.a * 64.f;
|
||||
|
||||
// Special:
|
||||
const float skinMask = emission.y;
|
||||
const float hairMask = metal.y;
|
||||
const float eyeMask = saturate(1.0 - gloss64);
|
||||
const float eyeGloss = 25.0;
|
||||
const float2 lamScaleBiasWithHair = lerp(lamScaleBias, float2(1, 0.4), hairMask);
|
||||
const float hairMask = metalMask.y;
|
||||
const float eyeMask = saturate(1.f - gloss64);
|
||||
const float eyeGloss = 48.f;
|
||||
const float2 lamScaleBiasWithHair = lerp(lamScaleBias, float2(1, 0.4f), hairMask);
|
||||
|
||||
const float gloss = lerp(gloss64 * gloss64, eyeGloss * eyeGloss, eyeMask);
|
||||
const float gloss4K = lerp(gloss64 * gloss64, eyeGloss * eyeGloss, eyeMask);
|
||||
|
||||
#ifdef DEF_DIR
|
||||
const float3 dirToLightWV = -lightDirWV;
|
||||
const float lightFalloff = 1.0;
|
||||
const float lightFalloff = 1.f;
|
||||
#else
|
||||
const float3 toLightWV = lightPosWV - posWV;
|
||||
const float3 dirToLightWV = normalize(toLightWV);
|
||||
|
@ -193,64 +192,62 @@ DS_ACC_FSO mainFS(VSO si)
|
|||
#ifdef DEF_SPOT // Extra step for spot light:
|
||||
const float coneIntensity = ComputeSpotLightConeIntensity(dirToLightWV, lightDirWV, coneOut, invConeDelta);
|
||||
#else
|
||||
const float coneIntensity = 1.0;
|
||||
const float coneIntensity = 1.f;
|
||||
#endif
|
||||
|
||||
const float4 litRet = VerusLit(dirToLightWV, normalWV, dirToEyeWV,
|
||||
lerp(gloss * (2.0 - lightFalloff), 12.0, hairMask),
|
||||
lerp(gloss4K * (2.f - lightFalloff), 12.f, hairMask),
|
||||
lamScaleBiasWithHair,
|
||||
float4(anisoWV, hairMask));
|
||||
|
||||
// <Shadow>
|
||||
float shadowMask = 1.0;
|
||||
float shadowMask = 1.f;
|
||||
{
|
||||
#ifdef DEF_DIR
|
||||
const float lightPassOffset = saturate((lamScaleBiasWithHair.y - 0.5) * 5.0) * 2.0;
|
||||
float4 config = g_ubShadowFS._shadowConfig;
|
||||
const float lamBiasMask = saturate(lamScaleBiasWithHair.y * config.y);
|
||||
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
|
||||
const float lightPassOffset = saturate((lamScaleBiasWithHair.y - 0.5f) * 5.f) * 2.f;
|
||||
float4 shadowConfig = g_ubShadowFS._shadowConfig;
|
||||
const float lamBiasMask = saturate(lamScaleBiasWithHair.y * shadowConfig.y);
|
||||
shadowConfig.y = 1.f - lamBiasMask; // Keep penumbra blurry.
|
||||
const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z, lightPassOffset);
|
||||
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubShadowFS._matSunShadow, -posForShadow.z);
|
||||
shadowMask = ShadowMapCSM(
|
||||
g_texShadowCmp,
|
||||
g_samShadowCmp,
|
||||
g_texShadow,
|
||||
g_samShadow,
|
||||
tcShadow,
|
||||
config,
|
||||
g_ubShadowFS._splitRanges,
|
||||
g_ubShadowFS._matSunShadow,
|
||||
g_ubShadowFS._matSunShadowCSM1,
|
||||
g_ubShadowFS._matSunShadowCSM2,
|
||||
g_ubShadowFS._matSunShadowCSM3);
|
||||
posWV,
|
||||
posForShadow,
|
||||
g_ubShadowFS._matShadow,
|
||||
g_ubShadowFS._matShadowCSM1,
|
||||
g_ubShadowFS._matShadowCSM2,
|
||||
g_ubShadowFS._matShadowCSM3,
|
||||
g_ubShadowFS._matScreenCSM,
|
||||
g_ubShadowFS._csmSplitRanges,
|
||||
shadowConfig);
|
||||
#endif
|
||||
}
|
||||
// </Shadow>
|
||||
|
||||
const float lightFalloffWithCone = lightFalloff * coneIntensity;
|
||||
const float diffLightMask = lightFalloffWithCone * shadowMask;
|
||||
const float specLightMask = saturate(lightFalloffWithCone * 2.0) * shadowMask;
|
||||
const float maxSpecAdd = (1.0 - spec) * lerp(0.01, 0.5, metal.x);
|
||||
const float specLightMask = saturate(lightFalloffWithCone * 2.f) * shadowMask;
|
||||
|
||||
// Subsurface scattering effect for front & back faces:
|
||||
const float3 frontSkinSSSColor = float3(1.6, 1.2, 0.3);
|
||||
const float3 backSkinSSSColor = float3(1.6, 0.8, 0.5);
|
||||
const float frontSkinSSSMask = 1.0 - litRet.y;
|
||||
const float3 hdrLightFaceColor = hdrLightColor * lerp(1.0, frontSkinSSSColor, skinMask * frontSkinSSSMask * frontSkinSSSMask);
|
||||
const float3 hdrLightColorSSS = lerp(hdrLightFaceColor, hdrLightColor * backSkinSSSColor, skinMask * litRet.x);
|
||||
const float3 frontSkinSSSColor = float3(1.6f, 1.2f, 0.3f);
|
||||
const float3 backSkinSSSColor = float3(1.6f, 0.8f, 0.5f);
|
||||
const float frontSkinSSSMask = 1.f - litRet.y;
|
||||
const float3 lightFaceColor = lightColor * lerp(1.f, frontSkinSSSColor, skinMask * frontSkinSSSMask * frontSkinSSSMask);
|
||||
const float3 lightColorSSS = lerp(lightFaceColor, lightColor * backSkinSSSColor, skinMask * litRet.x);
|
||||
|
||||
const float gray = Grayscale(rawGBuffer0.rgb);
|
||||
const float3 metalSpec = saturate(rawGBuffer0.rgb / (gray + _SINGULARITY_FIX));
|
||||
const float3 metalColor = ToMetalColor(rawGBuffer0.rgb);
|
||||
const float3 specColor = saturate(lerp(1.f, metalColor, saturate(metalMask.x + (hairMask - eyeMask) * 0.4f)) + float3(-0.03f, 0.f, 0.05f) * skinMask);
|
||||
|
||||
const float3 specHue = saturate(lerp(float3(1, 1, 1), metalSpec, saturate(metal.x + (hairMask - eyeMask) * 0.4)) +
|
||||
float3(-0.03, 0.0, 0.05) * skinMask);
|
||||
const float3 hdrMaxDiff = hdrLightColorSSS * diffLightMask;
|
||||
const float3 hdrMaxSpec = hdrLightColorSSS * specLightMask * specHue * FresnelSchlick(spec, maxSpecAdd, litRet.w);
|
||||
const float3 maxDiff = lightColorSSS * diffLightMask;
|
||||
const float3 maxSpec = lightColorSSS * specLightMask * specColor * specMask;
|
||||
|
||||
so.target0.rgb = hdrMaxDiff * litRet.y;
|
||||
so.target1.rgb = hdrMaxSpec * litRet.z;
|
||||
so.target0.a = 1.0;
|
||||
so.target1.a = 1.0;
|
||||
so.target0.rgb = ToSafeHDR(maxDiff * litRet.y);
|
||||
so.target1.rgb = ToSafeHDR(maxSpec * litRet.z);
|
||||
so.target0.a = 1.f;
|
||||
so.target1.a = 1.f;
|
||||
}
|
||||
#if defined(DEF_OMNI) || defined(DEF_SPOT)
|
||||
else
|
||||
|
|
|
@ -23,12 +23,13 @@ VERUS_UBUFFER UB_PerMeshVS
|
|||
|
||||
VERUS_UBUFFER UB_ShadowFS
|
||||
{
|
||||
matrix _matSunShadow;
|
||||
matrix _matSunShadowCSM1;
|
||||
matrix _matSunShadowCSM2;
|
||||
matrix _matSunShadowCSM3;
|
||||
matrix _matShadow;
|
||||
matrix _matShadowCSM1;
|
||||
matrix _matShadowCSM2;
|
||||
matrix _matShadowCSM3;
|
||||
matrix _matScreenCSM;
|
||||
float4 _csmSplitRanges;
|
||||
float4 _shadowConfig;
|
||||
float4 _splitRanges;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_PerObject
|
||||
|
|
|
@ -62,8 +62,6 @@ VSO mainVS(VSI si)
|
|||
const matrix matWV = mul(ToFloat4x4(matW), ToFloat4x4(g_ubAOPerFrame._matV));
|
||||
|
||||
const float3x3 matW33 = (float3x3)matW;
|
||||
const float3x3 matV33 = (float3x3)g_ubAOPerFrame._matV;
|
||||
const float3x3 matWV33 = (float3x3)matWV;
|
||||
|
||||
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubAOPerMeshVS._posDeqScale.xyz, g_ubAOPerMeshVS._posDeqBias.xyz);
|
||||
|
||||
|
@ -75,10 +73,10 @@ VSO mainVS(VSI si)
|
|||
const float3 posUnit = mul(float3(0, 0, 1), matW33); // Need to know the scale.
|
||||
so.radius_radiusSq_invRadiusSq.y = dot(posUnit, posUnit);
|
||||
so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y);
|
||||
so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y;
|
||||
so.radius_radiusSq_invRadiusSq.z = 1.f / so.radius_radiusSq_invRadiusSq.y;
|
||||
const float4 posOrigin = float4(0, 0, 0, 1);
|
||||
so.lightPosWV = mul(posOrigin, matWV).xyz;
|
||||
so.color_coneOut = float4(color, 1.0);
|
||||
so.color_coneOut = float4(color, 1.f);
|
||||
// </MoreAOParams>
|
||||
|
||||
return so;
|
||||
|
@ -90,7 +88,7 @@ FSO mainFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
so.color = 1.0;
|
||||
so.color = 1.f;
|
||||
|
||||
const float3 ndcPos = si.clipSpacePos.xyz / si.clipSpacePos.w;
|
||||
|
||||
|
@ -107,17 +105,17 @@ FSO mainFS(VSO si)
|
|||
|
||||
if (posWV.z <= lightPosWV.z + radius)
|
||||
{
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, tc0, 0.f);
|
||||
const float3 normalWV = DS_GetNormal(rawGBuffer1);
|
||||
|
||||
const float3 toLightWV = lightPosWV - posWV;
|
||||
const float3 dirToLightWV = normalize(toLightWV);
|
||||
const float distToLightSq = dot(toLightWV, toLightWV);
|
||||
const float lightFalloff = min(0.25, ComputePointLightIntensity(distToLightSq, radiusSq, invRadiusSq));
|
||||
const float lightFalloff = min(0.25f, ComputePointLightIntensity(distToLightSq, radiusSq, invRadiusSq));
|
||||
|
||||
const float nDotL = saturate(0.1 + dot(normalWV, dirToLightWV));
|
||||
const float nDotL = saturate(0.1f + dot(normalWV, dirToLightWV));
|
||||
|
||||
so.color = 1.0 - nDotL * lightFalloff;
|
||||
so.color = 1.f - nDotL * lightFalloff;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -43,18 +43,18 @@ DS_FSO mainFS(VSO si)
|
|||
{
|
||||
DS_FSO so;
|
||||
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0);
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.f);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.f);
|
||||
|
||||
so.target0 = rawGBuffer0;
|
||||
so.target1 = rawGBuffer1;
|
||||
so.target2 = rawGBuffer2;
|
||||
|
||||
if (rawGBuffer1.a < 0.5)
|
||||
if (rawGBuffer1.a < 0.5f)
|
||||
{
|
||||
// Defringe:
|
||||
float minDist = 1000.0;
|
||||
float minDist = 1000.f;
|
||||
[unroll] for (int i = -7; i <= 7; ++i)
|
||||
{
|
||||
[unroll] for (int j = -7; j <= 7; ++j)
|
||||
|
@ -62,15 +62,15 @@ DS_FSO mainFS(VSO si)
|
|||
const float2 offset = float2(j, i);
|
||||
const float dist = dot(offset, offset);
|
||||
|
||||
const float4 rawKernel1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0, int2(j, i));
|
||||
const float4 rawKernel1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f, int2(j, i));
|
||||
const float kernelAlpha = rawKernel1.a;
|
||||
|
||||
if (kernelAlpha >= 0.5 && dist < minDist)
|
||||
if (kernelAlpha >= 0.5f && dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
|
||||
const float4 rawKernel0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0, int2(j, i));
|
||||
const float4 rawKernel2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0, int2(j, i));
|
||||
const float4 rawKernel0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.f, int2(j, i));
|
||||
const float4 rawKernel2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.f, int2(j, i));
|
||||
|
||||
so.target0 = rawKernel0;
|
||||
so.target1.rgb = rawKernel1.rgb;
|
||||
|
|
|
@ -69,51 +69,47 @@ FSO2 mainFS(VSO si)
|
|||
|
||||
const float2 ndcPos = si.clipSpacePos.xy;
|
||||
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0);
|
||||
const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0).r;
|
||||
|
||||
const float4 rawAccDiff = g_texAccDiff.SampleLevel(g_samAccDiff, si.tc0, 0.0);
|
||||
const float4 rawAccSpec = g_texAccSpec.SampleLevel(g_samAccSpec, si.tc0, 0.0);
|
||||
const float4 accDiff = rawAccDiff;
|
||||
const float4 accSpec = rawAccSpec;
|
||||
// <Sample>
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.f);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.f);
|
||||
const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).r;
|
||||
const float4 rawAccDiff = g_texAccDiff.SampleLevel(g_samAccDiff, si.tc0, 0.f);
|
||||
const float4 rawAccSpec = g_texAccSpec.SampleLevel(g_samAccSpec, si.tc0, 0.f);
|
||||
// </Sample>
|
||||
|
||||
// White color means 50% albedo, black is not really black:
|
||||
const float3 albedo = max(rawGBuffer0.rgb * 0.5, 0.0001);
|
||||
const float3 realAlbedo = ToRealAlbedo(rawGBuffer0.rgb);
|
||||
const float3 normalWV = DS_GetNormal(rawGBuffer1);
|
||||
const float2 emission = DS_GetEmission(rawGBuffer1);
|
||||
const float3 posW = DS_GetPosition(rawDepth, g_ubComposeFS._matInvVP, ndcPos);
|
||||
const float depth = ToLinearDepth(rawDepth, g_ubComposeFS._zNearFarEx);
|
||||
|
||||
const float ssaoDiff = 0.5 + 0.5 * rawGBuffer2.r;
|
||||
const float ssaoDiff = 0.5f + 0.5f * rawGBuffer2.r;
|
||||
const float ssaoSpec = ssaoDiff;
|
||||
const float ssaoAmb = rawGBuffer2.r;
|
||||
|
||||
const float3 normalW = mul(normalWV, (float3x3)g_ubComposeFS._matInvV);
|
||||
const float grayAmbient = Grayscale(ambientColor);
|
||||
const float3 finalAmbientColor = lerp(grayAmbient * 0.2, ambientColor, normalW.y * 0.5 + 0.5);
|
||||
const float3 finalAmbientColor = lerp(grayAmbient * 0.25f, ambientColor, normalW.y * 0.5f + 0.5f);
|
||||
|
||||
const float3 color =
|
||||
albedo * (accDiff.rgb * ssaoDiff + finalAmbientColor * ssaoAmb) +
|
||||
accSpec.rgb * ssaoSpec +
|
||||
albedo * emission.x;
|
||||
const float3 color = realAlbedo * (rawAccDiff.rgb * ssaoDiff + finalAmbientColor * ssaoAmb + emission.x) + rawAccSpec.rgb * ssaoSpec;
|
||||
|
||||
// <Underwater>
|
||||
float3 underwaterColor;
|
||||
{
|
||||
const float diffuseMask = ToWaterDiffuseMask(posW.y);
|
||||
const float refractMask = saturate((diffuseMask - 0.5) * 2.0);
|
||||
const float refractMask = saturate((diffuseMask - 0.5f) * 2.f);
|
||||
const float3 waterDiffColorShallowAmbient = g_ubComposeFS._waterDiffColorShallow.rgb * ambientColor;
|
||||
const float3 waterDiffColorDeepAmbient = g_ubComposeFS._waterDiffColorDeep.rgb * ambientColor;
|
||||
const float deepAmbientColor = 0.5 + 0.5 * refractMask;
|
||||
const float deepAmbientColor = 0.5f + 0.5f * refractMask;
|
||||
const float3 planktonColor = lerp(
|
||||
waterDiffColorDeepAmbient * deepAmbientColor,
|
||||
waterDiffColorShallowAmbient,
|
||||
diffuseMask);
|
||||
underwaterColor = lerp(albedo * planktonColor * 10.0, color, refractMask);
|
||||
underwaterColor = lerp(realAlbedo * planktonColor * 10.f, color, refractMask);
|
||||
const float fog = ComputeFog(depth, g_ubComposeFS._waterDiffColorShallow.a);
|
||||
underwaterColor = lerp(underwaterColor, planktonColor * 0.1, fog * saturate(1.0 - refractMask + g_ubComposeFS._waterDiffColorDeep.a));
|
||||
underwaterColor = lerp(underwaterColor, planktonColor * 0.1f, fog * saturate(1.f - refractMask + g_ubComposeFS._waterDiffColorDeep.a));
|
||||
}
|
||||
// </Underwater>
|
||||
|
||||
|
@ -125,17 +121,28 @@ FSO2 mainFS(VSO si)
|
|||
}
|
||||
// </Fog>
|
||||
|
||||
so.target0.rgb = lerp(colorWithFog, albedo, floor(rawDepth));
|
||||
so.target0.a = 1.0;
|
||||
so.target0.rgb = lerp(colorWithFog, realAlbedo, floor(rawDepth));
|
||||
so.target0.rgb = ToSafeHDR(so.target0.rgb);
|
||||
so.target0.a = 1.f;
|
||||
|
||||
// <BackgroundColor>
|
||||
const float2 normalWasSet = ceil(rawGBuffer1.rg);
|
||||
const float bg = 1.0 - saturate(normalWasSet.r + normalWasSet.g);
|
||||
const float bg = 1.f - saturate(normalWasSet.r + normalWasSet.g);
|
||||
so.target0.rgb = lerp(so.target0.rgb, g_ubComposeFS._backgroundColor.rgb, bg * g_ubComposeFS._backgroundColor.a);
|
||||
// </BackgroundColor>
|
||||
|
||||
so.target1 = so.target0;
|
||||
|
||||
#if 0
|
||||
const float lightGlossScale = g_ubComposeFS._lightGlossScale.x;
|
||||
const float3 posWV = mul(float4(posW, 1), g_ubComposeFS._matV);
|
||||
const float3 toPosDirWV = normalize(posWV);
|
||||
const float dp = -toPosDirWV.z;
|
||||
const float smoothSpec = pow(saturate(dp), 4096.f * lightGlossScale);
|
||||
const float spec = saturate((smoothSpec - 0.5f) * 3.f + 0.5f);
|
||||
so.target0 = max(so.target0, spec * 30000.f);
|
||||
#endif
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
@ -144,32 +151,42 @@ FSO mainFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.0);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.0);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.0);
|
||||
const float4 rawComposed = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.0);
|
||||
// <Sample>
|
||||
const float4 rawGBuffer0 = g_texGBuffer0.SampleLevel(g_samGBuffer0, si.tc0, 0.f);
|
||||
const float4 rawGBuffer1 = g_texGBuffer1.SampleLevel(g_samGBuffer1, si.tc0, 0.f);
|
||||
const float4 rawGBuffer2 = g_texGBuffer2.SampleLevel(g_samGBuffer2, si.tc0, 0.f);
|
||||
float4 rawComposed = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f);
|
||||
const float4 rawAccDiff = g_texAccDiff.SampleLevel(g_samAccDiff, si.tc0, 0.f);
|
||||
const float4 rawAccSpec = g_texAccSpec.SampleLevel(g_samAccSpec, si.tc0, 0.f);
|
||||
// </Sample>
|
||||
|
||||
// Add reflection:
|
||||
const float specMask = rawGBuffer0.a;
|
||||
const float3 metalColor = ToMetalColor(rawGBuffer0.rgb);
|
||||
const float2 metalMask = DS_GetMetallicity(rawGBuffer2);
|
||||
rawComposed.rgb += rawAccSpec.rgb * lerp(1.f, metalColor, metalMask.x) * specMask;
|
||||
|
||||
const float gray = Grayscale(rawComposed.rgb);
|
||||
const float3 exposedComposed = Desaturate(rawComposed.rgb, saturate(1.0 - gray * 0.03)) * g_ubComposeFS._ambientColor_exposure.a;
|
||||
so.color.rgb = VerusToneMapping(exposedComposed, 0.5);
|
||||
so.color.a = 1.0;
|
||||
const float3 exposedComposed = Desaturate(rawComposed.rgb, saturate(1.f - gray * 0.03f)) * g_ubComposeFS._ambientColor_exposure.a;
|
||||
so.color.rgb = VerusToneMapping(exposedComposed, 0.5f);
|
||||
so.color.a = 1.f;
|
||||
|
||||
// Vignette:
|
||||
const float2 tcOffset = si.tc0 * 1.4 - 0.7;
|
||||
const float2 tcOffset = si.tc0 * 1.4f - 0.7f;
|
||||
const float lamp = saturate(dot(tcOffset, tcOffset));
|
||||
so.color.rgb = lerp(so.color.rgb, so.color.rgb * float3(0.64, 0.48, 0.36), lamp);
|
||||
so.color.rgb = lerp(so.color.rgb, so.color.rgb * float3(0.64f, 0.48f, 0.36f), lamp);
|
||||
|
||||
// SolidColor (using special value 1.0 for emission):
|
||||
// SolidColor (using special value 1.f for emission):
|
||||
so.color.rgb = lerp(so.color.rgb, rawGBuffer0.rgb, floor(rawGBuffer1.b));
|
||||
|
||||
const float3 bloom = rawGBuffer2.rgb;
|
||||
so.color.rgb += bloom * (1.0 - so.color.rgb);
|
||||
const float3 bloom = rawAccDiff.rgb;
|
||||
so.color.rgb += bloom * (1.f - so.color.rgb);
|
||||
|
||||
if (false)
|
||||
{
|
||||
const float gray = dot(rawComposed.rgb, 1.0 / 3.0);
|
||||
so.color.r = saturate((gray - 2000.0) * 0.001);
|
||||
so.color.gb *= 0.5;
|
||||
const float gray = dot(rawComposed.rgb, 1.f / 3.f);
|
||||
so.color.r = saturate((gray - 2000.f) * 0.001f);
|
||||
so.color.gb *= 0.5f;
|
||||
}
|
||||
|
||||
return so;
|
||||
|
|
|
@ -8,6 +8,7 @@ VERUS_UBUFFER UB_ComposeVS
|
|||
|
||||
VERUS_UBUFFER UB_ComposeFS
|
||||
{
|
||||
mataff _matV;
|
||||
mataff _matInvV;
|
||||
matrix _matInvVP;
|
||||
float4 _ambientColor_exposure;
|
||||
|
@ -16,4 +17,5 @@ VERUS_UBUFFER UB_ComposeFS
|
|||
float4 _zNearFarEx;
|
||||
float4 _waterDiffColorShallow;
|
||||
float4 _waterDiffColorDeep;
|
||||
float4 _lightGlossScale;
|
||||
};
|
||||
|
|
|
@ -34,31 +34,31 @@ VSO mainVS(VSI si)
|
|||
{
|
||||
VSO so;
|
||||
|
||||
const float pointSpriteSize = si.tc0.x / 500.0;
|
||||
const float angle = si.tc0.y / 32767.0;
|
||||
const float pointSpriteSize = si.tc0.x * (1.f / 500.f);
|
||||
const float angle = si.tc0.y * (1.f / 32767.f);
|
||||
|
||||
const float3 toEye = g_ubForestVS._eyePos.xyz - si.pos.xyz;
|
||||
const float distToScreen = length(g_ubForestVS._eyePosScreen.xyz - si.pos.xyz);
|
||||
|
||||
const float nearAlpha = saturate((distToScreen - 60.0) * (1.0 / 30.0));
|
||||
const float farAlpha = 1.0 - saturate((distToScreen - 900.0) * (1.0 / 100.0));
|
||||
const float nearAlpha = saturate((distToScreen - 60.f) * (1.f / 30.f)); // From 60m to 90m.
|
||||
const float farAlpha = 1.f - saturate((distToScreen - 900.f) * (1.f / 100.f)); // From 900m to 1000m.
|
||||
|
||||
so.pos = mul(si.pos, g_ubForestVS._matWVP);
|
||||
so.tc0 = 0.0;
|
||||
so.color.rgb = RandomColor(si.pos.xz, 0.3, 0.2);
|
||||
so.tc0 = 0.f;
|
||||
so.color.rgb = RandomColor(si.pos.xz, 0.3f, 0.2f);
|
||||
so.color.a = nearAlpha * farAlpha;
|
||||
so.psize.xy = pointSpriteSize * (g_ubForestVS._viewportSize.yx * g_ubForestVS._viewportSize.z) * g_ubForestVS._matP._m11;
|
||||
so.psize.xy *= ceil(so.color.a); // Hide if too close.
|
||||
so.psize.z = saturate(pointSpriteSize * 0.25 - 0.5);
|
||||
so.psize.z = saturate(pointSpriteSize * 0.25f - 0.5f);
|
||||
|
||||
float2 param0 = toEye.xy;
|
||||
float2 param1 = toEye.zz;
|
||||
param0.y = max(0.0, param0.y); // Only upper hemisphere.
|
||||
param0.y = max(0.f, param0.y); // Only upper hemisphere.
|
||||
param1.y = length(toEye.xz); // Distance in XZ-plane.
|
||||
so.angles.xy = (atan2(param0, param1) + _PI) * (0.5 / _PI); // atan2(x, z) and atan2(max(0.0, y), length(toEye.xz)). From 0 to 1.
|
||||
so.angles.y = (so.angles.y - 0.5) * 4.0; // Choose this quadrant.
|
||||
so.angles.xy = (atan2(param0, param1) + _PI) * (0.5f / _PI); // atan2(x, z) and atan2(max(0.f, y), length(toEye.xz)). From 0 to 1.
|
||||
so.angles.y = (so.angles.y - 0.5f) * 4.f; // Choose this quadrant.
|
||||
so.angles.xy = saturate(so.angles.xy);
|
||||
so.angles.x = frac(so.angles.x - angle + 0.5); // Turn.
|
||||
so.angles.x = frac(so.angles.x - angle + 0.5f); // Turn.
|
||||
|
||||
return so;
|
||||
}
|
||||
|
@ -83,21 +83,21 @@ void mainGS(point VSO si[1], inout TriangleStream<VSO> stream)
|
|||
|
||||
float2 ComputeTexCoords(float2 tc, float2 angles)
|
||||
{
|
||||
const float marginBias = 16.0 / 512.0;
|
||||
const float marginScale = 1.0 - marginBias * 2.0;
|
||||
const float marginBias = 16.f / 512.f;
|
||||
const float marginScale = 1.f - marginBias * 2.f;
|
||||
const float2 tcMargin = tc * marginScale + marginBias;
|
||||
|
||||
const float2 frameCount = float2(16, 16);
|
||||
const float2 frameScale = 1.0 / frameCount;
|
||||
const float2 frameBias = floor(min(angles * frameCount + 0.5, float2(256, frameCount.y - 0.5)));
|
||||
const float2 frameScale = 1.f / frameCount;
|
||||
const float2 frameBias = floor(min(angles * frameCount + 0.5f, float2(256, frameCount.y - 0.5f)));
|
||||
return (tcMargin + frameBias) * frameScale;
|
||||
}
|
||||
|
||||
float ComputeMask(float2 tc, float alpha)
|
||||
{
|
||||
const float2 tcCenter = tc - 0.5;
|
||||
const float rad = saturate(dot(tcCenter, tcCenter) * 4.0);
|
||||
return saturate(rad + (alpha * 2.0 - 1.0));
|
||||
const float2 tcCenter = tc - 0.5f;
|
||||
const float rad = saturate(dot(tcCenter, tcCenter) * 4.f);
|
||||
return saturate(rad + (alpha * 2.f - 1.f));
|
||||
}
|
||||
|
||||
#ifdef _FS
|
||||
|
@ -109,7 +109,7 @@ void mainFS(VSO si)
|
|||
|
||||
const float alpha = g_texGBuffer1.Sample(g_samGBuffer1, tc).a;
|
||||
|
||||
clip(alpha * mask - 0.53);
|
||||
clip(alpha * mask - 0.53f);
|
||||
}
|
||||
#else
|
||||
DS_FSO mainFS(VSO si)
|
||||
|
@ -128,10 +128,10 @@ DS_FSO mainFS(VSO si)
|
|||
so.target2 = rawGBuffer2;
|
||||
|
||||
so.target0.rgb *= si.color.rgb;
|
||||
const float lamBiasRatio = 1.0 - ComputeMask(si.tc0, 0.5);
|
||||
so.target2.g = lerp(so.target2.g, 0.25, lamBiasRatio * lamBiasRatio * si.psize.z);
|
||||
const float lamBiasRatio = 1.f - ComputeMask(si.tc0, 0.5f);
|
||||
so.target2.g = lerp(so.target2.g, 0.25f, lamBiasRatio * lamBiasRatio * si.psize.z);
|
||||
|
||||
clip(rawGBuffer1.a * mask - 0.53);
|
||||
clip(rawGBuffer1.a * mask - 0.53f);
|
||||
|
||||
return so;
|
||||
}
|
||||
|
|
|
@ -57,43 +57,43 @@ VSO mainVS(VSI si)
|
|||
float3 intactPos;
|
||||
float3 pos;
|
||||
float2 center;
|
||||
float2 pointSpriteSize = 1.0;
|
||||
float2 pointSpriteSize = 1.f;
|
||||
float groundHeight;
|
||||
float3 normal;
|
||||
float2 tc0;
|
||||
bool bushMaskOK = true;
|
||||
{
|
||||
intactPos = si.pos.xyz * (1.0 / 1000.0);
|
||||
intactPos = si.pos.xyz * (1.f / 1000.f);
|
||||
pos = intactPos + float3(si.patchPos.x, 0, si.patchPos.z);
|
||||
center = si.tc.zw * (1.0 / 1000.0) + si.patchPos.xz;
|
||||
center = si.tc.zw * (1.f / 1000.f) + si.patchPos.xz;
|
||||
#ifdef DEF_BILLBOARDS
|
||||
pointSpriteSize = intactPos.y;
|
||||
pos = float3(center.x, 0.45 * pointSpriteSize.y, center.y);
|
||||
pos = float3(center.x, 0.45f * pointSpriteSize.y, center.y);
|
||||
#endif
|
||||
|
||||
const float distToEye = distance(pos + float3(0, si.patchPos.y * 0.01, 0), g_ubGrassVS._posEye.xyz);
|
||||
const float geomipsLod = log2(clamp(distToEye * (2.0 / 100.0), 1.0, 18.0));
|
||||
const float texelCenter = 0.5 * mapSideInv;
|
||||
const float distToEye = distance(pos + float3(0, si.patchPos.y * 0.01f, 0), g_ubGrassVS._posEye.xyz);
|
||||
const float geomipsLod = log2(clamp(distToEye * (2.f / 100.f), 1.f, 18.f));
|
||||
const float texelCenter = 0.5f * mapSideInv;
|
||||
const float mipTexelCenter = texelCenter * exp2(geomipsLod);
|
||||
const float2 tcMap = pos.xz * mapSideInv + 0.5;
|
||||
const float2 tcUniform = center * mapSideInv + 0.5;
|
||||
const float2 tcMap = pos.xz * mapSideInv + 0.5f;
|
||||
const float2 tcUniform = center * mapSideInv + 0.5f;
|
||||
groundHeight = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + mipTexelCenter, geomipsLod).r);
|
||||
pos.y += groundHeight;
|
||||
|
||||
const float4 rawNormal = g_texNormalVS.SampleLevel(g_samNormalVS, tcUniform + texelCenter, 0.0);
|
||||
normal = float3(rawNormal.x, 0, rawNormal.y) * 2.0 - 1.0;
|
||||
const float4 rawNormal = g_texNormalVS.SampleLevel(g_samNormalVS, tcUniform + texelCenter, 0.f);
|
||||
normal = float3(rawNormal.x, 0, rawNormal.y) * 2.f - 1.f;
|
||||
normal.y = ComputeNormalZ(normal.xz);
|
||||
|
||||
const float layer = g_texMLayerVS.SampleLevel(g_samMLayerVS, tcUniform, 0.0).r * 4.0;
|
||||
const float uShift = frac(layer) - (16.0 / 256.0);
|
||||
const float vShift = floor(layer) * 0.25;
|
||||
float vShiftAlt = 0.0;
|
||||
const float layer = g_texMLayerVS.SampleLevel(g_samMLayerVS, tcUniform, 0.f).r * 4.f;
|
||||
const float uShift = frac(layer) - (16.f / 256.f);
|
||||
const float vShift = floor(layer) * 0.25f;
|
||||
float vShiftAlt = 0.f;
|
||||
if (!(bushID & 0xF))
|
||||
vShiftAlt = 0.5; // Every 16th bush uses alternative texture.
|
||||
tc0 = si.tc.xy * (1.0 / 100.0) + float2(uShift, vShift + vShiftAlt);
|
||||
vShiftAlt = 0.5f; // Every 16th bush uses alternative texture.
|
||||
tc0 = si.tc.xy * (1.f / 100.f) + float2(uShift, vShift + vShiftAlt);
|
||||
|
||||
// Cull blank bushes:
|
||||
const int mainLayer = round(layer * 4.0);
|
||||
const int mainLayer = round(layer * 4.f);
|
||||
const int ibushMask = asint(bushMask);
|
||||
if (!((ibushMask >> mainLayer) & 0x1))
|
||||
{
|
||||
|
@ -103,20 +103,20 @@ VSO mainVS(VSI si)
|
|||
// </FromTextures>
|
||||
|
||||
// <Special>
|
||||
float phaseShift = 0.0;
|
||||
float2 windWarp = 0.0;
|
||||
float top = 0.0;
|
||||
float phaseShift = 0.f;
|
||||
float2 windWarp = 0.f;
|
||||
float top = 0.f;
|
||||
{
|
||||
#ifdef DEF_BILLBOARDS
|
||||
phaseShift = frac(si.pos.w * (1.0 / 100.0));
|
||||
windWarp = 0.0;
|
||||
top = 0.28;
|
||||
phaseShift = frac(si.pos.w * (1.f / 100.f));
|
||||
windWarp = 0.f;
|
||||
top = 0.28f;
|
||||
#else
|
||||
if (intactPos.y >= 0.1)
|
||||
if (intactPos.y >= 0.1f)
|
||||
{
|
||||
phaseShift = frac(si.pos.w * (1.0 / 100.0));
|
||||
windWarp = warp.xz * (1.0 + turbulence * sin((phase + phaseShift) * (_PI * 2.0)));
|
||||
top = 1.0;
|
||||
phaseShift = frac(si.pos.w * (1.f / 100.f));
|
||||
windWarp = warp.xz * (1.f + turbulence * sin((phase + phaseShift) * (_PI * 2.f)));
|
||||
top = 1.f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -126,17 +126,17 @@ VSO mainVS(VSI si)
|
|||
float3 posWarped = pos;
|
||||
{
|
||||
const float distToEye = -mul(float4(posWarped, 1), g_ubGrassVS._matWV).z;
|
||||
const float distant = saturate((distToEye - 50.0) * (1.0 / 50.0)); // [50.0 to 100.0] -> [0.0 to 1.0].
|
||||
const float distExt = saturate((distToEye - 25.0) * (1.0 / 25.0)); // [25.0 to 50.0] -> [0.0 to 1.0].
|
||||
const float distant = saturate((distToEye - 50.f) * (1.f / 50.f)); // [50.f to 100.f] -> [0.f to 1.f].
|
||||
const float distExt = saturate((distToEye - 25.f) * (1.f / 25.f)); // [25.f to 50.f] -> [0.f to 1.f].
|
||||
|
||||
const float cliff = dot(normal.xz, normal.xz);
|
||||
float hide = cliff + step(groundHeight, 1.0) + distant;
|
||||
float hide = cliff + step(groundHeight, 1.f) + distant;
|
||||
if (!bushMaskOK)
|
||||
hide = 1.0;
|
||||
hide = 1.f;
|
||||
posWarped.xz -= normal.xz;
|
||||
#ifdef DEF_BILLBOARDS
|
||||
const float distExtInv = 1.0 - distExt;
|
||||
posWarped.xz += windWarp * 0.5;
|
||||
const float distExtInv = 1.f - distExt;
|
||||
posWarped.xz += windWarp * 0.5f;
|
||||
hide += distExtInv * distExtInv;
|
||||
#else
|
||||
posWarped.xz += windWarp;
|
||||
|
@ -146,7 +146,7 @@ VSO mainVS(VSI si)
|
|||
hide = saturate(hide);
|
||||
|
||||
#ifdef DEF_BILLBOARDS
|
||||
pointSpriteSize = lerp(pointSpriteSize, float2(0.0, pointSpriteSize.y), hide);
|
||||
pointSpriteSize = lerp(pointSpriteSize, float2(0.f, pointSpriteSize.y), hide);
|
||||
#else
|
||||
posWarped = lerp(posWarped, float3(center.x, posWarped.y, center.y), hide); // Optimize by morphing to center point.
|
||||
#endif
|
||||
|
@ -159,13 +159,13 @@ VSO mainVS(VSI si)
|
|||
so.tcOffset_phaseShift = float3(0, 0, phaseShift);
|
||||
so.normal_top.xyz = mul(normal, (float3x3)g_ubGrassVS._matWV);
|
||||
so.normal_top.w = top;
|
||||
so.psize = 1.0;
|
||||
so.psize = 1.f;
|
||||
|
||||
#ifdef DEF_BILLBOARDS
|
||||
so.tcOffset_phaseShift.xy = tc0;
|
||||
so.psize = pointSpriteSize * (g_ubGrassVS._viewportSize.yx * g_ubGrassVS._viewportSize.z) * g_ubGrassVS._matP._m11;
|
||||
#else
|
||||
so.normal_top.xyz += float3(0, 0, top * top * 0.25);
|
||||
so.normal_top.xyz += float3(0, 0, top * top * 0.25f);
|
||||
#endif
|
||||
|
||||
return so;
|
||||
|
@ -198,34 +198,34 @@ DS_FSO mainFS(VSO si)
|
|||
|
||||
float2 tc = si.tc0;
|
||||
#ifdef DEF_BILLBOARDS
|
||||
tc = si.tc0 * 0.23 + si.tcOffset_phaseShift.xy;
|
||||
tc = si.tc0 * 0.23f + si.tcOffset_phaseShift.xy;
|
||||
#endif
|
||||
|
||||
const float4 rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, tc);
|
||||
const float3 normal = normalize(si.normal_top.xyz);
|
||||
const float gray = Grayscale(rawAlbedo.rgb);
|
||||
const float mask = saturate((gray - 0.25) * 2.0 + 0.2);
|
||||
const float mask = saturate((gray - 0.25f) * 2.f + 0.2f);
|
||||
|
||||
const float top = si.normal_top.w;
|
||||
const float spec = saturate(top * top * (mask + si.tcOffset_phaseShift.z * 0.1));
|
||||
const float gloss = lerp(4.0, 12.0, spec);
|
||||
const float specMask = saturate(top * top * (mask + si.tcOffset_phaseShift.z * 0.1f));
|
||||
const float gloss = lerp(4.f, 12.f, specMask);
|
||||
|
||||
{
|
||||
DS_Reset(so);
|
||||
|
||||
DS_SetAlbedo(so, rawAlbedo.rgb);
|
||||
DS_SetSpec(so, spec);
|
||||
DS_SetSpecMask(so, specMask);
|
||||
|
||||
DS_SetNormal(so, normal + NormalDither(rand));
|
||||
DS_SetEmission(so, 0.0, 0.0);
|
||||
DS_SetMotionBlur(so, 1.0);
|
||||
DS_SetEmission(so, 0.f, 0.f);
|
||||
DS_SetMotionBlurMask(so, 1.f);
|
||||
|
||||
DS_SetLamScaleBias(so, float2(1.2, -0.2), 0.0);
|
||||
DS_SetMetallicity(so, 0.05, 0.0);
|
||||
DS_SetLamScaleBias(so, float2(1.2f, -0.2f), 0.f);
|
||||
DS_SetMetallicity(so, 0.05f, 0.f);
|
||||
DS_SetGloss(so, gloss);
|
||||
}
|
||||
|
||||
clip(rawAlbedo.a - 0.5);
|
||||
clip(rawAlbedo.a - 0.5f);
|
||||
|
||||
return so;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ VSO mainVS(VSI si)
|
|||
const float3 intactTan = si.tan.xyz;
|
||||
const float3 intactBin = si.bin.xyz;
|
||||
|
||||
float addLamBias = 0.0;
|
||||
float addLamBias = 0.f;
|
||||
#if defined(DEF_SKINNED) || defined(DEF_ROBOTIC)
|
||||
const float4 warpMask = float4(
|
||||
1,
|
||||
|
@ -95,14 +95,14 @@ VSO mainVS(VSI si)
|
|||
#elif defined(DEF_PLANT)
|
||||
{
|
||||
const float3 normPos = NormalizePosition(si.pos.xyz);
|
||||
const float weightY = saturate(normPos.y * normPos.y - 0.01);
|
||||
const float3 offsetXYZ = normPos - float3(0.5, 0.8, 0.5);
|
||||
const float weightXZ = saturate((dot(offsetXYZ.xz, offsetXYZ.xz) - 0.01) * 0.4);
|
||||
const float weightY = saturate(normPos.y * normPos.y - 0.01f);
|
||||
const float3 offsetXYZ = normPos - float3(0.5f, 0.8f, 0.5f);
|
||||
const float weightXZ = saturate((dot(offsetXYZ.xz, offsetXYZ.xz) - 0.01f) * 0.4f);
|
||||
|
||||
const float phaseShiftY = frac(userColor.x + userColor.z);
|
||||
const float phaseShiftXZ = frac(phaseShiftY + intactPos.x + intactPos.z);
|
||||
const float2 bending = (float2(0.7, 0.5) + float2(0.3, 0.5) *
|
||||
sin((g_ubPerObject._userColor.rg + float2(phaseShiftY, phaseShiftXZ)) * (_PI * 2.0))) * float2(weightY, weightXZ);
|
||||
const float2 bending = (float2(0.7f, 0.5f) + float2(0.3f, 0.5f) *
|
||||
sin((g_ubPerObject._userColor.rg + float2(phaseShiftY, phaseShiftXZ)) * (_PI * 2.f))) * float2(weightY, weightXZ);
|
||||
|
||||
const float3x3 matW33 = (float3x3)matW;
|
||||
const float3x3 matBending = (float3x3)g_ubPerObject._matW;
|
||||
|
@ -121,7 +121,7 @@ VSO mainVS(VSI si)
|
|||
lerp(matW33[2], matNewW33[2], userColor.a),
|
||||
matW[3]);
|
||||
|
||||
const float weight = 1.0 - saturate(dot(offsetXYZ, offsetXYZ));
|
||||
const float weight = 1.f - saturate(dot(offsetXYZ, offsetXYZ));
|
||||
addLamBias = (-(weight * weight * weight)) * saturate(userColor.a);
|
||||
}
|
||||
const float3 pos = intactPos;
|
||||
|
@ -137,13 +137,13 @@ VSO mainVS(VSI si)
|
|||
float3 binWV;
|
||||
{
|
||||
#ifdef DEF_SKINNED
|
||||
const float4 weights = si.bw * (1.0 / 255.0);
|
||||
const float4 weights = si.bw * (1.f / 255.f);
|
||||
const float4 indices = si.bi;
|
||||
|
||||
float3 posSkinned = 0.0;
|
||||
float3 nrmSkinned = 0.0;
|
||||
float3 tanSkinned = 0.0;
|
||||
float3 binSkinned = 0.0;
|
||||
float3 posSkinned = 0.f;
|
||||
float3 nrmSkinned = 0.f;
|
||||
float3 tanSkinned = 0.f;
|
||||
float3 binSkinned = 0.f;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
|
@ -190,7 +190,7 @@ VSO mainVS(VSI si)
|
|||
#if !defined(DEF_DEPTH)
|
||||
so.color0 = userColor;
|
||||
#ifdef DEF_PLANT
|
||||
so.color0.rgb = RandomColor(userColor.xz, 0.3, 0.2);
|
||||
so.color0.rgb = RandomColor(userColor.xz, 0.3f, 0.2f);
|
||||
so.color0.a = addLamBias;
|
||||
#endif
|
||||
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
|
||||
|
@ -214,7 +214,7 @@ PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
|
|||
}
|
||||
|
||||
[domain("tri")]
|
||||
[maxtessfactor(7.0)]
|
||||
[maxtessfactor(7.f)]
|
||||
[outputcontrolpoints(3)]
|
||||
[outputtopology("triangle_cw")]
|
||||
[partitioning(_PARTITION_METHOD)]
|
||||
|
@ -251,7 +251,7 @@ VSO mainDS(_IN_DS)
|
|||
|
||||
const float3 toEyeWV = g_ubPerFrame._eyePosWV_invTessDistSq.xyz - flatPosWV;
|
||||
const float distToEyeSq = dot(toEyeWV, toEyeWV);
|
||||
const float tessStrength = 1.0 - saturate(distToEyeSq * g_ubPerFrame._eyePosWV_invTessDistSq.w * 1.1 - 0.1);
|
||||
const float tessStrength = 1.f - saturate(distToEyeSq * g_ubPerFrame._eyePosWV_invTessDistSq.w * 1.1f - 0.1f);
|
||||
const float3 posWV = lerp(flatPosWV, smoothPosWV, tessStrength);
|
||||
so.pos = ApplyProjection(posWV, g_ubPerFrame._matP);
|
||||
_DS_COPY(tc0);
|
||||
|
@ -273,7 +273,7 @@ VSO mainDS(_IN_DS)
|
|||
void mainFS(VSO si)
|
||||
{
|
||||
const float rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, si.tc0).a;
|
||||
clip(rawAlbedo - 1.0 / 16.0);
|
||||
clip(rawAlbedo - 1.f / 16.f);
|
||||
}
|
||||
#else
|
||||
DS_FSO mainFS(VSO si)
|
||||
|
@ -313,7 +313,7 @@ DS_FSO mainFS(VSO si)
|
|||
const float4 mm_texEnableNormal = g_ubPerMaterialFS._texEnableNormal;
|
||||
const float4 mm_userColor = g_ubPerMaterialFS._userColor;
|
||||
const float4 mm_userPick = g_ubPerMaterialFS._userPick;
|
||||
const float motionBlur = g_ubPerMaterialFS._lamScaleBias_lightPass_motionBlur.w;
|
||||
const float motionBlurMask = g_ubPerMaterialFS._lamScaleBias_lightPass_motionBlur.w;
|
||||
// </Material>
|
||||
|
||||
const float2 tc0 = si.tc0 * mm_tc0ScaleBias.xy + mm_tc0ScaleBias.zw;
|
||||
|
@ -330,13 +330,13 @@ DS_FSO mainFS(VSO si)
|
|||
|
||||
// <Pick>
|
||||
const float2 alpha_spec = AlphaSwitch(rawAlbedo, tc0, mm_alphaSwitch);
|
||||
const float emitAlpha = PickAlpha(rawAlbedo.rgb, mm_emissionPick, 16.0);
|
||||
const float emitAlpha = PickAlpha(rawAlbedo.rgb, mm_emissionPick, 16.f);
|
||||
const float eyeAlpha = PickAlphaRound(mm_eyePick, tc0);
|
||||
const float glossAlpha = PickAlpha(rawAlbedo.rgb, mm_glossPick, 32.0);
|
||||
const float hairAlpha = round(PickAlpha(rawAlbedo.rgb, mm_hairPick, 16.0));
|
||||
const float metalAlpha = PickAlpha(rawAlbedo.rgb, mm_metalPick, 16.0);
|
||||
const float skinAlpha = PickAlpha(rawAlbedo.rgb, mm_skinPick, 16.0);
|
||||
const float userAlpha = PickAlpha(rawAlbedo.rgb, mm_userPick, 16.0);
|
||||
const float glossAlpha = PickAlpha(rawAlbedo.rgb, mm_glossPick, 32.f);
|
||||
const float hairAlpha = round(PickAlpha(rawAlbedo.rgb, mm_hairPick, 16.f));
|
||||
const float metalAlpha = PickAlpha(rawAlbedo.rgb, mm_metalPick, 16.f);
|
||||
const float skinAlpha = PickAlpha(rawAlbedo.rgb, mm_skinPick, 16.f);
|
||||
const float userAlpha = PickAlpha(rawAlbedo.rgb, mm_userPick, 16.f);
|
||||
// </Pick>
|
||||
|
||||
#ifdef DEF_PLANT
|
||||
|
@ -345,12 +345,13 @@ DS_FSO mainFS(VSO si)
|
|||
rawAlbedo.rgb = lerp(rawAlbedo.rgb, Overlay(gray, si.color0.rgb), userAlpha * si.color0.a);
|
||||
#endif
|
||||
const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * mm_hairDesat));
|
||||
const float specMask = saturate(alpha_spec.y * mm_specScaleBias.x + mm_specScaleBias.y);
|
||||
|
||||
// <Gloss>
|
||||
float gloss = lerp(4.0, 16.0, alpha_spec.y) * mm_glossScaleBias.x + mm_glossScaleBias.y;
|
||||
float gloss = lerp(4.f, 16.f, alpha_spec.y) * mm_glossScaleBias.x + mm_glossScaleBias.y;
|
||||
gloss = lerp(gloss, mm_gloss, glossAlpha);
|
||||
gloss = lerp(gloss, 4.5 + alpha_spec.y, skinAlpha);
|
||||
gloss = lerp(gloss, 0.0, eyeAlpha);
|
||||
gloss = lerp(gloss, 4.f + alpha_spec.y, skinAlpha);
|
||||
gloss = lerp(gloss, 0.f, eyeAlpha);
|
||||
// </Gloss>
|
||||
|
||||
// <Normal>
|
||||
|
@ -374,7 +375,7 @@ DS_FSO mainFS(VSO si)
|
|||
// <Detail>
|
||||
{
|
||||
const float3 rawDetail = g_texDetail.Sample(g_samDetail, tc0 * mm_detailScale).rgb;
|
||||
rawAlbedo.rgb = rawAlbedo.rgb * lerp(0.5, rawDetail, mm_detail) * 2.0;
|
||||
rawAlbedo.rgb = rawAlbedo.rgb * lerp(0.5f, rawDetail, mm_detail) * 2.f;
|
||||
}
|
||||
// </Detail>
|
||||
|
||||
|
@ -382,14 +383,14 @@ DS_FSO mainFS(VSO si)
|
|||
float strass;
|
||||
{
|
||||
const float rawStrass = g_texStrass.Sample(g_samStrass, tc0 * mm_strassScale).r;
|
||||
strass = saturate(rawStrass * (0.3 + 0.7 * alpha_spec.y) * 2.0);
|
||||
strass = saturate(rawStrass * (0.6f + 1.4f * alpha_spec.y));
|
||||
}
|
||||
// </Strass>
|
||||
|
||||
// <LambertianScaleBias>
|
||||
float2 lamScaleBias = mm_lamScaleBias + float2(0, lightPassStrength * 8.0 * mm_lightPass);
|
||||
lamScaleBias += float2(-0.1, -0.3) * alpha_spec.y + float2(0.1, 0.2); // We bring the noise!
|
||||
lamScaleBias = lerp(lamScaleBias, float2(1, 0.45), skinAlpha);
|
||||
float2 lamScaleBias = mm_lamScaleBias + float2(0, lightPassStrength * 8.f * mm_lightPass);
|
||||
lamScaleBias += float2(-0.1f, -0.3f) * alpha_spec.y + float2(0.1f, 0.2f); // We bring the noise!
|
||||
lamScaleBias = lerp(lamScaleBias, float2(1, 0.45f), skinAlpha);
|
||||
#ifdef DEF_PLANT
|
||||
lamScaleBias.y += si.color0.a;
|
||||
#endif
|
||||
|
@ -397,29 +398,37 @@ DS_FSO mainFS(VSO si)
|
|||
|
||||
// <RimAlbedo>
|
||||
{
|
||||
const float3 newColor = saturate((rawAlbedo.rgb + gray) * 0.6);
|
||||
const float mask = 1.0 - abs(normalWV.z);
|
||||
rawAlbedo.rgb = lerp(rawAlbedo.rgb, newColor, mask * mask * (1.0 - alpha_spec.y));
|
||||
const float3 newColor = saturate((rawAlbedo.rgb + gray) * 0.6f);
|
||||
const float mask = 1.f - abs(normalWV.z);
|
||||
rawAlbedo.rgb = lerp(rawAlbedo.rgb, newColor, mask * mask * (1.f - alpha_spec.y));
|
||||
}
|
||||
// </RimAlbedo>
|
||||
|
||||
// <SpecFresnel>
|
||||
float specMaskWithFresnel;
|
||||
{
|
||||
const float fresnelMask = pow(saturate(1.f - normalWV.z), 5.f);
|
||||
const float maxSpecAdd = (1.f - specMask) * lerp(0.04f + 0.2f * specMask, 0.6f, metalAlpha);
|
||||
specMaskWithFresnel = FresnelSchlick(specMask, maxSpecAdd, fresnelMask);
|
||||
}
|
||||
// </SpecFresnel>
|
||||
|
||||
{
|
||||
DS_Reset(so);
|
||||
|
||||
DS_SetAlbedo(so, lerp(rawAlbedo.rgb, hairAlbedo, hairAlpha));
|
||||
DS_SetSpec(so, max(eyeAlpha, max(strass,
|
||||
alpha_spec.y * (1.0 + hairAlpha * 0.75) * mm_specScaleBias.x + mm_specScaleBias.y)));
|
||||
DS_SetSpecMask(so, lerp(max(strass, specMaskWithFresnel), 0.15f, eyeAlpha));
|
||||
|
||||
DS_SetNormal(so, normalWV + NormalDither(rand));
|
||||
DS_SetEmission(so, emitAlpha * mm_emission, skinAlpha);
|
||||
DS_SetMotionBlur(so, motionBlur);
|
||||
DS_SetMotionBlurMask(so, motionBlurMask);
|
||||
|
||||
DS_SetLamScaleBias(so, lamScaleBias, float4(anisoWV, hairAlpha));
|
||||
DS_SetMetallicity(so, metalAlpha, hairAlpha);
|
||||
DS_SetGloss(so, gloss * lerp(toksvigFactor, 1.0, eyeAlpha));
|
||||
DS_SetGloss(so, gloss * lerp(toksvigFactor, 1.f, eyeAlpha));
|
||||
}
|
||||
|
||||
clip(alpha_spec.x - 0.5);
|
||||
clip(alpha_spec.x - 0.5f);
|
||||
#endif
|
||||
|
||||
return so;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "LibTessellation.hlsl"
|
||||
#include "DS_Terrain.inc.hlsl"
|
||||
|
||||
#define DETAIL_TC_SCALE 8.0
|
||||
#define DETAIL_TC_SCALE 8.f
|
||||
|
||||
ConstantBuffer<UB_TerrainVS> g_ubTerrainVS : register(b0, space0);
|
||||
ConstantBuffer<UB_TerrainFS> g_ubTerrainFS : register(b0, space1);
|
||||
|
@ -48,7 +48,7 @@ struct VSO
|
|||
#endif
|
||||
};
|
||||
|
||||
static const float g_layerScale = 1.0 / 8.0;
|
||||
static const float g_layerScale = 1.f / 8.f;
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainVS(VSI si)
|
||||
|
@ -59,29 +59,29 @@ VSO mainVS(VSI si)
|
|||
const float mapSideInv = g_ubTerrainVS._eyePos_mapSideInv.w;
|
||||
|
||||
const float2 edgeCorrection = si.pos.yw;
|
||||
si.pos.yw = 0.0;
|
||||
si.pos.yw = 0.f;
|
||||
float3 pos = si.pos.xyz + si.posPatch.xyz;
|
||||
const float2 tcMap = pos.xz * mapSideInv + 0.5; // Range [0, 1).
|
||||
const float2 posBlend = pos.xz + edgeCorrection * 0.5;
|
||||
const float2 tcMap = pos.xz * mapSideInv + 0.5f; // Range [0, 1).
|
||||
const float2 posBlend = pos.xz + edgeCorrection * 0.5f;
|
||||
|
||||
// <HeightAndNormal>
|
||||
float3 intactNrm;
|
||||
{
|
||||
const float approxHeight = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r);
|
||||
const float approxHeight = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5f * mapSideInv) * 16.f, 4.f).r);
|
||||
pos.y = approxHeight;
|
||||
|
||||
const float distToEye = distance(pos, eyePos);
|
||||
const float geomipsLod = log2(clamp(distToEye * (2.0 / 100.0), 1.0, 18.0));
|
||||
const float geomipsLod = log2(clamp(distToEye * (2.f / 100.f), 1.f, 18.f));
|
||||
const float geomipsLodFrac = frac(geomipsLod);
|
||||
const float geomipsLodBase = floor(geomipsLod);
|
||||
const float geomipsLodNext = geomipsLodBase + 1.0;
|
||||
const float2 texelCenterAB = (0.5 * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
|
||||
const float geomipsLodNext = geomipsLodBase + 1.f;
|
||||
const float2 texelCenterAB = (0.5f * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
|
||||
const float yA = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.xx, geomipsLodBase).r);
|
||||
const float yB = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.yy, geomipsLodNext).r);
|
||||
pos.y = lerp(yA, yB, geomipsLodFrac);
|
||||
|
||||
const float4 rawNormal = g_texNormalVS.SampleLevel(g_samNormalVS, tcMap + texelCenterAB.xx, geomipsLodBase);
|
||||
intactNrm = float3(rawNormal.x, 0, rawNormal.y) * 2.0 - 1.0;
|
||||
intactNrm = float3(rawNormal.x, 0, rawNormal.y) * 2.f - 1.f;
|
||||
intactNrm.y = ComputeNormalZ(intactNrm.xz);
|
||||
}
|
||||
// </HeightAndNormal>
|
||||
|
@ -91,10 +91,10 @@ VSO mainVS(VSI si)
|
|||
#if !defined(DEF_DEPTH)
|
||||
so.layerForChannel = si.layerForChannel;
|
||||
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
|
||||
so.tcBlend.xy = posBlend * mapSideInv + 0.5;
|
||||
so.tcBlend.xy = posBlend * mapSideInv + 0.5f;
|
||||
so.tcBlend.z = pos.y;
|
||||
so.tcLayer_tcMap.xy = pos.xz * g_layerScale;
|
||||
so.tcLayer_tcMap.zw = (pos.xz + 0.5) * mapSideInv + 0.5; // Texel's center.
|
||||
so.tcLayer_tcMap.zw = (pos.xz + 0.5f) * mapSideInv + 0.5f; // Texel's center.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -113,7 +113,7 @@ PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
|
|||
}
|
||||
|
||||
[domain("tri")]
|
||||
[maxtessfactor(7.0)]
|
||||
[maxtessfactor(7.f)]
|
||||
[outputcontrolpoints(3)]
|
||||
[outputtopology("triangle_cw")]
|
||||
[partitioning(_PARTITION_METHOD)]
|
||||
|
@ -159,7 +159,7 @@ VSO mainDS(_IN_DS)
|
|||
|
||||
#ifndef DEF_DEPTH
|
||||
// Fade to non-tess mesh at 80 meters. LOD 1 starts at 100 meters.
|
||||
const float tessStrength = saturate((1.0 - saturate(smoothPosWV.z / -80.0)) * 4.0);
|
||||
const float tessStrength = saturate((1.f - saturate(smoothPosWV.z / -80.f)) * 4.f);
|
||||
const float3 posWV = lerp(flatPosWV, smoothPosWV, tessStrength);
|
||||
so.pos = ApplyProjection(posWV, g_ubTerrainVS._matP);
|
||||
#endif
|
||||
|
@ -183,13 +183,13 @@ DS_FSO mainFS(VSO si)
|
|||
const float2 tcMap = si.tcLayer_tcMap.zw;
|
||||
|
||||
const float4 rawBlend = g_texBlend.Sample(g_samBlend, si.tcBlend.xy);
|
||||
float4 weights = float4(rawBlend.rgb, 1.0 - dot(rawBlend.rgb, float3(1, 1, 1)));
|
||||
float4 weights = float4(rawBlend.rgb, 1.f - dot(rawBlend.rgb, float3(1, 1, 1)));
|
||||
|
||||
// <Basis>
|
||||
float3 basisTan, basisBin, basisNrm;
|
||||
{
|
||||
const float4 rawBasis = g_texNormal.Sample(g_samNormal, tcMap);
|
||||
const float4 basis = rawBasis * 2.0 - 1.0;
|
||||
const float4 basis = rawBasis * 2.f - 1.f;
|
||||
basisNrm = float3(basis.x, 0, basis.y);
|
||||
basisTan = float3(0, basis.z, basis.w);
|
||||
basisNrm.y = ComputeNormalZ(basisNrm.xz);
|
||||
|
@ -204,7 +204,7 @@ DS_FSO mainFS(VSO si)
|
|||
|
||||
// <Albedo>
|
||||
float4 albedo;
|
||||
float specStrength;
|
||||
float specMask;
|
||||
float detailStrength;
|
||||
{
|
||||
const float4 rawAlbedos[4] =
|
||||
|
@ -218,11 +218,11 @@ DS_FSO mainFS(VSO si)
|
|||
Grayscale(rawAlbedos[0].rgb),
|
||||
Grayscale(rawAlbedos[1].rgb),
|
||||
Grayscale(rawAlbedos[2].rgb),
|
||||
Grayscale(rawAlbedos[3].rgb)) - 0.25) * 8.0 + 0.25);
|
||||
Grayscale(rawAlbedos[3].rgb)) - 0.25f) * 8.f + 0.25f);
|
||||
weights = saturate(weights + weights * mask);
|
||||
const float weightsSum = dot(weights, 1.0);
|
||||
const float weightsSum = dot(weights, 1.f);
|
||||
weights /= weightsSum;
|
||||
float4 accAlbedo = 0.0;
|
||||
float4 accAlbedo = 0.f;
|
||||
accAlbedo += rawAlbedos[0] * weights.r;
|
||||
accAlbedo += rawAlbedos[1] * weights.g;
|
||||
accAlbedo += rawAlbedos[2] * weights.b;
|
||||
|
@ -241,7 +241,7 @@ DS_FSO mainFS(VSO si)
|
|||
vDetailStrength[layerForChannel.g],
|
||||
vDetailStrength[layerForChannel.b],
|
||||
vDetailStrength[layerForChannel.a]);
|
||||
specStrength = dot(specStrengthForChannel, weights) * albedo.a;
|
||||
specMask = albedo.a * dot(specStrengthForChannel, weights);
|
||||
detailStrength = dot(detailStrengthForChannel, weights);
|
||||
}
|
||||
// </Albedo>
|
||||
|
@ -251,26 +251,26 @@ DS_FSO mainFS(VSO si)
|
|||
{
|
||||
const float dryMask = saturate(si.tcBlend.z);
|
||||
const float dryMask3 = dryMask * dryMask * dryMask;
|
||||
const float wetMask = 1.0 - dryMask;
|
||||
const float wetMask = 1.f - dryMask;
|
||||
const float wetMask3 = wetMask * wetMask * wetMask;
|
||||
albedo.rgb *= dryMask3 * 0.5 + 0.5;
|
||||
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3 * 0.1);
|
||||
waterGlossBoost = min(32.0, dryMask * wetMask3 * 100.0);
|
||||
albedo.rgb *= dryMask3 * 0.5f + 0.5f;
|
||||
specMask = dryMask * saturate(specMask + wetMask3 * wetMask3 * 0.1f);
|
||||
waterGlossBoost = min(32.f, dryMask * wetMask3 * 100.f);
|
||||
}
|
||||
// </Water>
|
||||
|
||||
const float gloss = lerp(3.3, 15.0, specStrength) + waterGlossBoost;
|
||||
const float gloss = lerp(3.3f, 15.f, specMask) + waterGlossBoost;
|
||||
|
||||
// <Normal>
|
||||
float3 normalWV;
|
||||
float toksvigFactor;
|
||||
{
|
||||
float4 accNormal = 0.0;
|
||||
float4 accNormal = 0.f;
|
||||
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.r)) * weights.r;
|
||||
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.g)) * weights.g;
|
||||
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.b)) * weights.b;
|
||||
accNormal += g_texLayersNM.Sample(g_samLayersNM, float3(tcLayer, layerForChannel.a)) * weights.a;
|
||||
accNormal = lerp(accNormal, float4(0, 0.5, 0.5, 0.5), 0.5);
|
||||
accNormal = lerp(accNormal, float4(0, 0.5f, 0.5f, 0.5f), 0.5f);
|
||||
const float4 normalAA = NormalMapAA(accNormal);
|
||||
normalWV = normalize(mul(normalAA.xyz, matFromTBN));
|
||||
toksvigFactor = ComputeToksvigFactor(normalAA.a, gloss);
|
||||
|
@ -280,22 +280,31 @@ DS_FSO mainFS(VSO si)
|
|||
// <Detail>
|
||||
{
|
||||
const float3 rawDetail = g_texDetail.Sample(g_samDetail, tcLayer * DETAIL_TC_SCALE).rgb;
|
||||
albedo.rgb = albedo.rgb * lerp(0.5, rawDetail, detailStrength) * 2.0;
|
||||
albedo.rgb = albedo.rgb * lerp(0.5f, rawDetail, detailStrength) * 2.f;
|
||||
}
|
||||
// </Detail>
|
||||
|
||||
// <SpecFresnel>
|
||||
float specMaskWithFresnel;
|
||||
{
|
||||
const float fresnelMask = pow(saturate(1.f - normalWV.z), 5.f);
|
||||
const float maxSpecAdd = (1.f - specMask) * (0.04f + 0.2f * specMask);
|
||||
specMaskWithFresnel = FresnelSchlick(specMask, maxSpecAdd, fresnelMask);
|
||||
}
|
||||
// </SpecFresnel>
|
||||
|
||||
{
|
||||
DS_Reset(so);
|
||||
|
||||
DS_SetAlbedo(so, albedo.rgb);
|
||||
DS_SetSpec(so, specStrength);
|
||||
DS_SetSpecMask(so, specMaskWithFresnel);
|
||||
|
||||
DS_SetNormal(so, normalWV + NormalDither(rand));
|
||||
DS_SetEmission(so, 0.0, 0.0);
|
||||
DS_SetMotionBlur(so, 1.0);
|
||||
DS_SetEmission(so, 0.f, 0.f);
|
||||
DS_SetMotionBlurMask(so, 1.f);
|
||||
|
||||
DS_SetLamScaleBias(so, g_ubTerrainFS._lamScaleBias.xy, float4(0, 0, 1, 0));
|
||||
DS_SetMetallicity(so, 0.05, 0.0);
|
||||
DS_SetMetallicity(so, 0.05f, 0.f);
|
||||
DS_SetGloss(so, gloss * toksvigFactor);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -34,7 +34,7 @@ VSO mainVS(VSI si)
|
|||
VSO so;
|
||||
|
||||
so.pos = si.pos;
|
||||
so.tc0 = si.tc0.xy / 32767.0;
|
||||
so.tc0 = si.tc0.xy / 32767.f;
|
||||
so.color = ColorToLinear(si.color);
|
||||
|
||||
return so;
|
||||
|
|
|
@ -62,54 +62,54 @@ float4 PackColor(float4 x)
|
|||
[numthreads(THREAD_GROUP_SIZE, THREAD_GROUP_SIZE, 1)]
|
||||
void mainCS(CSI si)
|
||||
{
|
||||
float4 srcColor1 = 0.0;
|
||||
float2 tc = 0.0;
|
||||
float4 srcColor1 = 0.f;
|
||||
float2 tc = 0.f;
|
||||
|
||||
switch (g_ub._srcDimensionCase)
|
||||
{
|
||||
case DIM_CASE_WE_HE:
|
||||
{
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + 0.5);
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + 0.5f);
|
||||
|
||||
srcColor1 = g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel);
|
||||
}
|
||||
break;
|
||||
case DIM_CASE_WO_HE:
|
||||
{
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.5));
|
||||
const float2 offset = g_ub._texelSize * float2(0.5, 0.0);
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25f, 0.5f));
|
||||
const float2 offset = g_ub._texelSize * float2(0.5f, 0.f);
|
||||
|
||||
srcColor1 = lerp(
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel),
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc + offset, g_ub._srcMipLevel),
|
||||
0.5);
|
||||
0.5f);
|
||||
}
|
||||
break;
|
||||
case DIM_CASE_WE_HO:
|
||||
{
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.5, 0.25));
|
||||
const float2 offset = g_ub._texelSize * float2(0.0, 0.5);
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.5f, 0.25f));
|
||||
const float2 offset = g_ub._texelSize * float2(0.f, 0.5f);
|
||||
|
||||
srcColor1 = lerp(
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel),
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc + offset, g_ub._srcMipLevel),
|
||||
0.5);
|
||||
0.5f);
|
||||
}
|
||||
break;
|
||||
case DIM_CASE_WO_HO:
|
||||
{
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.25));
|
||||
const float2 offset = g_ub._texelSize * 0.5;
|
||||
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25f, 0.25f));
|
||||
const float2 offset = g_ub._texelSize * 0.5f;
|
||||
|
||||
srcColor1 = lerp(
|
||||
lerp(
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel),
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc + float2(offset.x, 0.0), g_ub._srcMipLevel),
|
||||
0.5),
|
||||
lerp(g_texSrcMip.SampleLevel(g_samSrcMip, tc + float2(0.0, offset.y), g_ub._srcMipLevel),
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc + float2(offset.x, 0.f), g_ub._srcMipLevel),
|
||||
0.5f),
|
||||
lerp(g_texSrcMip.SampleLevel(g_samSrcMip, tc + float2(0.f, offset.y), g_ub._srcMipLevel),
|
||||
g_texSrcMip.SampleLevel(g_samSrcMip, tc + float2(offset.x, offset.y), g_ub._srcMipLevel),
|
||||
0.5),
|
||||
0.5);
|
||||
0.5f),
|
||||
0.5f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -117,14 +117,14 @@ void mainCS(CSI si)
|
|||
#ifdef DEF_EXPOSURE
|
||||
if (0 == g_ub._srcMipLevel)
|
||||
{
|
||||
const float2 delta = 0.5 - tc;
|
||||
const float2 centerWeighted = saturate((dot(delta, delta) - float2(0.1, 0.01)) * float2(4.0, 200.0));
|
||||
const float2 delta = 0.5f - tc;
|
||||
const float2 centerWeighted = saturate((dot(delta, delta) - float2(0.1f, 0.01f)) * float2(4.f, 200.f));
|
||||
const float gray = Grayscale(srcColor1.rgb);
|
||||
const float2 mask = saturate((float2(-1, 1) * gray + float2(0.1, -0.99)) * float2(10, 100));
|
||||
const float2 mask = saturate((float2(-1, 1) * gray + float2(0.1f, -0.99f)) * float2(10, 100));
|
||||
const float filter = max(mask.x, mask.y) * centerWeighted.y;
|
||||
const float alpha = max(centerWeighted.x, filter);
|
||||
srcColor1.rgb = lerp(srcColor1.rgb, 0.5, alpha);
|
||||
srcColor1.a = 1.0 - alpha;
|
||||
srcColor1.rgb = lerp(srcColor1.rgb, 0.5f, alpha);
|
||||
srcColor1.a = 1.f - alpha;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -142,7 +142,7 @@ void mainCS(CSI si)
|
|||
const float4 srcColor2 = LoadColor(si.groupIndex + 0x01); // {+0, +1}
|
||||
const float4 srcColor3 = LoadColor(si.groupIndex + 0x08); // {+1, +0}
|
||||
const float4 srcColor4 = LoadColor(si.groupIndex + 0x09); // {+1, +1}
|
||||
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
srcColor1 = 0.25f * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
|
||||
g_uavOutMip2[si.dispatchThreadID.xy >> 1] = PackColor(srcColor1);
|
||||
StoreColor(si.groupIndex, srcColor1);
|
||||
|
@ -158,7 +158,7 @@ void mainCS(CSI si)
|
|||
const float4 srcColor2 = LoadColor(si.groupIndex + 0x02); // {+0, +2}
|
||||
const float4 srcColor3 = LoadColor(si.groupIndex + 0x10); // {+2, +0}
|
||||
const float4 srcColor4 = LoadColor(si.groupIndex + 0x12); // {+2, +2}
|
||||
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
srcColor1 = 0.25f * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
|
||||
g_uavOutMip3[si.dispatchThreadID.xy >> 2] = PackColor(srcColor1);
|
||||
StoreColor(si.groupIndex, srcColor1);
|
||||
|
@ -174,7 +174,7 @@ void mainCS(CSI si)
|
|||
const float4 srcColor2 = LoadColor(si.groupIndex + 0x04); // {+0, +4}
|
||||
const float4 srcColor3 = LoadColor(si.groupIndex + 0x20); // {+4, +0}
|
||||
const float4 srcColor4 = LoadColor(si.groupIndex + 0x24); // {+4, +4}
|
||||
srcColor1 = 0.25 * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
srcColor1 = 0.25f * (srcColor1 + srcColor2 + srcColor3 + srcColor4);
|
||||
|
||||
g_uavOutMip4[si.dispatchThreadID.xy >> 3] = PackColor(srcColor1);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
#define VERUS_UBUFFER struct
|
||||
#define mataff float4x3
|
||||
|
||||
#define _Q_LOW 0
|
||||
#define _Q_MEDIUM 1
|
||||
#define _Q_HIGH 2
|
||||
#define _Q_ULTRA 3
|
||||
|
||||
#ifdef _VULKAN
|
||||
# define VK_LOCATION(x) [[vk::location(x)]]
|
||||
# define VK_LOCATION_POSITION [[vk::location(0)]]
|
||||
|
@ -24,7 +29,7 @@
|
|||
# else
|
||||
# define VK_POINT_SIZE
|
||||
# endif
|
||||
# define VK_SET_POINT_SIZE so.psize = 1.0
|
||||
# define VK_SET_POINT_SIZE so.psize = 1.f
|
||||
#else
|
||||
# define VK_LOCATION(x)
|
||||
# define VK_LOCATION_POSITION
|
||||
|
@ -41,7 +46,7 @@
|
|||
# define VK_SUBPASS_INPUT(index, tex, sam, t, s, space)\
|
||||
Texture2D tex : register(t, space);\
|
||||
SamplerState sam : register(s, space)
|
||||
# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SampleLevel(sam, tc, 0.0)
|
||||
# define VK_SUBPASS_LOAD(tex, sam, tc) tex.SampleLevel(sam, tc, 0.f)
|
||||
|
||||
# define VK_POINT_SIZE
|
||||
# define VK_SET_POINT_SIZE
|
||||
|
@ -61,9 +66,9 @@
|
|||
const float3x3 matFromTBN = float3x3(tan, bin, nrm);\
|
||||
const float3x3 matToTBN = transpose(matFromTBN);
|
||||
|
||||
#define _PI 3.141592654
|
||||
#define _PI 3.141592654f
|
||||
|
||||
#define _SINGULARITY_FIX 0.001
|
||||
#define _SINGULARITY_FIX 0.001f
|
||||
|
||||
#define _MAX_TERRAIN_LAYERS 32
|
||||
|
||||
|
@ -83,45 +88,45 @@ float2 ToNdcPos(float2 tc)
|
|||
|
||||
float2 ToTexCoords(float2 ndcPos)
|
||||
{
|
||||
return ndcPos * float2(0.5, -0.5) + 0.5;
|
||||
return ndcPos * float2(0.5f, -0.5f) + 0.5f;
|
||||
}
|
||||
|
||||
// Asymmetric abs():
|
||||
float2 AsymAbs(float2 x, float negScale = -1.0, float posScale = 1.0)
|
||||
float2 AsymAbs(float2 x, float negScale = -1.f, float posScale = 1.f)
|
||||
{
|
||||
return x * lerp(posScale, negScale, step(x, 0.0));
|
||||
return x * lerp(posScale, negScale, step(x, 0.f));
|
||||
}
|
||||
|
||||
float3 Rand(float2 uv)
|
||||
{
|
||||
return frac(sin(dot(uv, float2(12.9898, 78.233)) * float3(1, 2, 3)) * 43758.5453);
|
||||
return frac(sin(dot(uv, float2(12.9898f, 78.233f)) * float3(1, 2, 3)) * 43758.5453f);
|
||||
}
|
||||
|
||||
float4 Rand2(float2 pos)
|
||||
{
|
||||
const float4 primeA = float4(9.907, 9.923, 9.929, 9.931);
|
||||
const float4 primeB = float4(9.941, 9.949, 9.967, 9.973);
|
||||
const float4 primeA = float4(9.907f, 9.923f, 9.929f, 9.931f);
|
||||
const float4 primeB = float4(9.941f, 9.949f, 9.967f, 9.973f);
|
||||
return frac(primeA * pos.x + primeB * pos.y);
|
||||
}
|
||||
|
||||
float3 RandomColor(float2 pos, float randLum, float randRGB)
|
||||
{
|
||||
const float4 r = Rand2(pos);
|
||||
return (1.0 - randLum - randRGB) + r.a * randLum + r.rgb * randRGB;
|
||||
return (1.f - randLum - randRGB) + r.a * randLum + r.rgb * randRGB;
|
||||
}
|
||||
|
||||
float3 NormalDither(float3 rand)
|
||||
{
|
||||
const float2 rr = rand.xy * (1.0 / 333.0) - (0.5 / 333.0);
|
||||
const float2 rr = rand.xy * (1.f / 333.f) - (0.5f / 333.f);
|
||||
return float3(rr, 0);
|
||||
}
|
||||
|
||||
static const float2 _POINT_SPRITE_POS_OFFSETS[4] =
|
||||
{
|
||||
float2(-0.5, 0.5),
|
||||
float2(-0.5, -0.5),
|
||||
float2(0.5, 0.5),
|
||||
float2(0.5, -0.5)
|
||||
float2(-0.5f, 0.5f),
|
||||
float2(-0.5f, -0.5f),
|
||||
float2(0.5f, 0.5f),
|
||||
float2(0.5f, -0.5f)
|
||||
};
|
||||
|
||||
static const float2 _POINT_SPRITE_TEX_COORDS[4] =
|
||||
|
@ -132,24 +137,53 @@ static const float2 _POINT_SPRITE_TEX_COORDS[4] =
|
|||
float2(1, 1)
|
||||
};
|
||||
|
||||
// <PhysicallyBasedRendering>
|
||||
|
||||
float3 ToRealAlbedo(float3 albedo)
|
||||
{
|
||||
return max(albedo.rgb * 0.5f, 0.0001f);
|
||||
}
|
||||
|
||||
float3 ToMetalColor(float3 albedo)
|
||||
{
|
||||
const float gray = dot(albedo, 1.f / 3.f);
|
||||
return saturate(albedo / (gray + _SINGULARITY_FIX));
|
||||
}
|
||||
|
||||
// Prevent values from reaching inf and nan.
|
||||
float3 ToSafeHDR(float3 hdr)
|
||||
{
|
||||
// Typical ambient is 4000.
|
||||
// Typical sunlight is 16000.
|
||||
return clamp(hdr, 0.f, 32000.f);
|
||||
}
|
||||
|
||||
// See: https://en.wikipedia.org/wiki/Schlick%27s_approximation
|
||||
float FresnelSchlick(float minRef, float maxAdd, float power)
|
||||
{
|
||||
return saturate(minRef + maxAdd * power);
|
||||
}
|
||||
|
||||
// </PhysicallyBasedRendering>
|
||||
|
||||
float UnpackTerrainHeight(float height)
|
||||
{
|
||||
return height * 0.01;
|
||||
return height * 0.01f;
|
||||
}
|
||||
|
||||
float ToLandMask(float height)
|
||||
{
|
||||
return saturate(height * 0.2 + 1.0); // [-5 to 0] -> [0 to 1]
|
||||
return saturate(height * 0.2f + 1.f); // [-5 to 0] -> [0 to 1]
|
||||
}
|
||||
|
||||
float ToWaterDiffuseMask(float height)
|
||||
{
|
||||
const float mask = saturate(height * 0.02 + 1.0); // [-50 to 0] -> [0 to 1]
|
||||
const float mask = saturate(height * 0.02f + 1.f); // [-50 to 0] -> [0 to 1]
|
||||
return mask * mask * mask;
|
||||
}
|
||||
|
||||
float3 ReflectionDimming(float3 hdr, float scale)
|
||||
{
|
||||
const float gray = dot(hdr, 1.0 / 3.0);
|
||||
return lerp(hdr * scale, hdr, saturate(gray * (1.0 / 65536.0)));
|
||||
const float gray = dot(hdr, 1.f / 3.f);
|
||||
return lerp(hdr * scale, hdr, saturate(gray * (1.f / 65536.f)));
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
// See: https://en.wikipedia.org/wiki/Grayscale
|
||||
float Grayscale(float3 color)
|
||||
{
|
||||
return dot(color, float3(0.2126, 0.7152, 0.0722));
|
||||
return dot(color, float3(0.2126f, 0.7152f, 0.0722f));
|
||||
}
|
||||
|
||||
float3 Desaturate(float3 color, float alpha, float lum = 1.0)
|
||||
float3 Desaturate(float3 color, float alpha, float lum = 1.f)
|
||||
{
|
||||
const float gray = Grayscale(color) * lum;
|
||||
return lerp(color, gray, alpha);
|
||||
|
@ -15,29 +15,29 @@ float3 Desaturate(float3 color, float alpha, float lum = 1.0)
|
|||
// See: http://www.chilliant.com/rgb2hsv.html
|
||||
float3 ConvertRGBtoHCV(float3 color)
|
||||
{
|
||||
const float4 p = (color.g < color.b) ? float4(color.bg, -1.0, 2.0 / 3.0) : float4(color.gb, 0.0, -1.0 / 3.0);
|
||||
const float4 p = (color.g < color.b) ? float4(color.bg, -1.f, 2.f / 3.f) : float4(color.gb, 0.f, -1.f / 3.f);
|
||||
const float4 q = (color.r < p.x) ? float4(p.xyw, color.r) : float4(color.r, p.yzx);
|
||||
const float c = q.x - min(q.w, q.y);
|
||||
const float h = abs((q.w - q.y) / (6.0 * c + _SINGULARITY_FIX) + q.z);
|
||||
const float h = abs((q.w - q.y) / (6.f * c + _SINGULARITY_FIX) + q.z);
|
||||
return float3(h, c, q.x);
|
||||
}
|
||||
|
||||
float Contrast(float gray, float contrast)
|
||||
{
|
||||
return saturate(((gray - 0.5) * contrast) + 0.5);
|
||||
return saturate(((gray - 0.5f) * contrast) + 0.5f);
|
||||
}
|
||||
|
||||
float3 Overlay(float3 colorA, float3 colorB)
|
||||
{
|
||||
const float3 x = step(0.5, colorA);
|
||||
return lerp(colorA * colorB * 2.0, 1.0 - (2.0 * (1.0 - colorA) * (1.0 - colorB)), x);
|
||||
const float3 x = step(0.5f, colorA);
|
||||
return lerp(colorA * colorB * 2.f, 1.f - (2.f * (1.f - colorA) * (1.f - colorB)), x);
|
||||
}
|
||||
|
||||
// <AlbedoPick>
|
||||
float PickAlpha(float3 albedo, float4 pick, float sharp)
|
||||
{
|
||||
const float3 d = albedo - pick.rgb;
|
||||
return saturate(1.0 - dot(d, d) * sharp) * pick.a;
|
||||
return saturate(1.f - dot(d, d) * sharp) * pick.a;
|
||||
}
|
||||
|
||||
float PickAlphaRound(float4 pick, float2 tc)
|
||||
|
@ -53,29 +53,29 @@ float2 AlphaSwitch(float4 albedo, float2 tc, float2 alphaSwitch)
|
|||
if (all(frac(tc) >= alphaSwitch))
|
||||
return float2(albedo.a, Grayscale(albedo.rgb)); // 8-bit alpha.
|
||||
else
|
||||
return saturate(float2(albedo.a * 8.0, (albedo.a - 0.15) / 0.85)); // 5-bit alpha.
|
||||
return saturate(float2(albedo.a * 8.f, (albedo.a - 0.15f) / 0.85f)); // 5-bit alpha.
|
||||
}
|
||||
|
||||
// See: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
|
||||
float4 ColorToLinear(float4 x)
|
||||
{
|
||||
const float3 rgb = x.rgb < 0.04045 ? x.rgb * (1.0 / 12.92) : pow(abs(x.rgb + 0.055) / 1.055, 2.4);
|
||||
const float3 rgb = x.rgb < 0.04045f ? x.rgb * (1.f / 12.92f) : pow(abs(x.rgb + 0.055f) / 1.055f, 2.4f);
|
||||
return float4(rgb, x.a);
|
||||
}
|
||||
float4 ColorToSRGB(float4 x)
|
||||
{
|
||||
const float3 rgb = x.rgb < 0.0031308 ? 12.92 * x.rgb : 1.055 * pow(abs(x.rgb), 1.0 / 2.4) - 0.055;
|
||||
const float3 rgb = x.rgb < 0.0031308f ? 12.92f * x.rgb : 1.055f * pow(abs(x.rgb), 1.f / 2.4f) - 0.055f;
|
||||
return float4(rgb, x.a);
|
||||
}
|
||||
|
||||
float3 ToneMappingReinhard(float3 x)
|
||||
{
|
||||
return x / (1.0 + x);
|
||||
return x / (1.f + x);
|
||||
}
|
||||
|
||||
float3 ToneMappingInvReinhard(float3 x)
|
||||
{
|
||||
return -x / (x - 1.0);
|
||||
return -x / (x - 1.f);
|
||||
}
|
||||
|
||||
// See: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
|
||||
|
@ -89,11 +89,11 @@ float3 ToneMappingACES(float3 x)
|
|||
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
|
||||
}
|
||||
|
||||
float3 VerusToneMapping(float3 hdr, float filmicLook = 1.0)
|
||||
float3 VerusToneMapping(float3 hdr, float filmicLook = 1.f)
|
||||
{
|
||||
const float maxValue = max(max(hdr.r, hdr.g), hdr.b);
|
||||
const float desatMask = saturate(maxValue * 0.15);
|
||||
const float desatMask = saturate(maxValue * 0.15f);
|
||||
hdr = lerp(hdr, maxValue, desatMask * desatMask); // Color crosstalk.
|
||||
const float3 ldr = lerp(1.0 - exp(-hdr), ToneMappingACES(hdr), filmicLook);
|
||||
return saturate(ldr * 1.2 - 0.002); // Add some clipping.
|
||||
const float3 ldr = lerp(1.f - exp(-hdr), ToneMappingACES(hdr), filmicLook);
|
||||
return saturate(ldr * 1.2f - 0.002f); // Add some clipping.
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
struct DS_FSO
|
||||
{
|
||||
float4 target0 : SV_Target0; // {albedo, spec}
|
||||
float4 target1 : SV_Target1; // {normal, emission + skin, motion}
|
||||
float4 target2 : SV_Target2; // {lamScaleBias, metal + hair, gloss}
|
||||
float4 target0 : SV_Target0; // {albedo, specMask}
|
||||
float4 target1 : SV_Target1; // {normal, emission|skinMask, motionBlurMask}
|
||||
float4 target2 : SV_Target2; // {lamScaleBias, metalMask|hairMask, gloss}
|
||||
};
|
||||
|
||||
struct DS_ACC_FSO
|
||||
|
@ -16,38 +16,38 @@ struct DS_ACC_FSO
|
|||
// See: http://aras-p.info/texts/CompactNormalStorage.html#method04spheremap
|
||||
float2 EncodeNormal(float3 n)
|
||||
{
|
||||
const float rf = rsqrt(abs(8.0 * n.z + 8.0));
|
||||
return n.xy * rf + 0.5;
|
||||
const float rf = rsqrt(abs(8.f * n.z + 8.f));
|
||||
return n.xy * rf + 0.5f;
|
||||
}
|
||||
|
||||
float3 DecodeNormal(float2 enc)
|
||||
{
|
||||
const float2 fenc = enc * 4.0 - 2.0;
|
||||
const float2 fenc = enc * 4.f - 2.f;
|
||||
const float f = dot(fenc, fenc);
|
||||
const float2 f2 = 1.0 - f * float2(0.25, 0.5);
|
||||
const float2 f2 = 1.f - f * float2(0.25f, 0.5f);
|
||||
const float g = sqrt(abs(f2.x));
|
||||
return float3(fenc * g, f2.y);
|
||||
}
|
||||
|
||||
void DS_Reset(out DS_FSO so)
|
||||
{
|
||||
so.target0 = 0.0;
|
||||
so.target1 = 0.0;
|
||||
so.target2 = 0.0;
|
||||
so.target0 = 0.f;
|
||||
so.target1 = 0.f;
|
||||
so.target2 = 0.f;
|
||||
}
|
||||
|
||||
void DS_SolidColor(out DS_FSO so, float3 color)
|
||||
{
|
||||
so.target0 = float4(color, 0.0);
|
||||
so.target1 = float4(EncodeNormal(float3(0, 0, 1)), 1.0, 0.0);
|
||||
so.target2 = float4(1.0, 0.0, 0.0, 0.0);
|
||||
so.target0 = float4(color, 0.f);
|
||||
so.target1 = float4(EncodeNormal(float3(0, 0, 1)), 0.25f, 0);
|
||||
so.target2 = float4(1.f / 8.f, 0.5f, 0.5f, 0);
|
||||
}
|
||||
|
||||
void DS_Test(out DS_FSO so, float3 normal, float spec, float gloss)
|
||||
void DS_Test(out DS_FSO so, float3 normal, float specMask, float gloss)
|
||||
{
|
||||
so.target0 = float4(0.5, 0.5, 0.5, spec);
|
||||
so.target1 = float4(EncodeNormal(normal), 0.25, 0.5);
|
||||
so.target2 = float4(1.0 / 8.0, 0.5, 0.5, gloss * (1.0 / 64.0));
|
||||
so.target0 = float4(0.5f, 0.5f, 0.5f, specMask);
|
||||
so.target1 = float4(EncodeNormal(normal), 0.25f, 0.5f);
|
||||
so.target2 = float4(1.f / 8.f, 0.5f, 0.5f, gloss * (1.f / 64.f));
|
||||
}
|
||||
|
||||
void DS_SetAlbedo(inout DS_FSO so, float3 albedo)
|
||||
|
@ -55,9 +55,9 @@ void DS_SetAlbedo(inout DS_FSO so, float3 albedo)
|
|||
so.target0.rgb = albedo;
|
||||
}
|
||||
|
||||
void DS_SetSpec(inout DS_FSO so, float spec)
|
||||
void DS_SetSpecMask(inout DS_FSO so, float specMask)
|
||||
{
|
||||
so.target0.a = spec;
|
||||
so.target0.a = specMask;
|
||||
}
|
||||
|
||||
float3 DS_GetNormal(float4 gbuffer)
|
||||
|
@ -72,20 +72,20 @@ void DS_SetNormal(inout DS_FSO so, float3 normal)
|
|||
|
||||
float2 DS_GetEmission(float4 gbuffer)
|
||||
{
|
||||
const float2 em_skin = saturate((gbuffer.b - 0.25) * float2(1.0 / 0.75, -1.0 / 0.25));
|
||||
const float em = exp2(em_skin.x * 15.0) - 1.0;
|
||||
const float2 em_skin = saturate((gbuffer.b - 0.25f) * float2(1.f / 0.75f, -1.f / 0.25f));
|
||||
const float em = exp2(em_skin.x * 15.f) - 1.f;
|
||||
return float2(em, em_skin.y);
|
||||
}
|
||||
|
||||
void DS_SetEmission(inout DS_FSO so, float emission, float skin)
|
||||
void DS_SetEmission(inout DS_FSO so, float emission, float skinMask)
|
||||
{
|
||||
const float em = saturate(log2(1.0 + emission) * (1.0 / 15.0));
|
||||
so.target1.b = (3.0 * em - skin) * 0.25 + 0.25;
|
||||
const float em = saturate(log2(1.f + emission) * (1.f / 15.f));
|
||||
so.target1.b = (3.f * em - skinMask) * 0.25f + 0.25f;
|
||||
}
|
||||
|
||||
void DS_SetMotionBlur(inout DS_FSO so, float mb)
|
||||
void DS_SetMotionBlurMask(inout DS_FSO so, float motionBlurMask)
|
||||
{
|
||||
so.target1.a = mb;
|
||||
so.target1.a = motionBlurMask;
|
||||
}
|
||||
|
||||
float2 DS_GetLamScaleBias(float4 gbuffer)
|
||||
|
@ -95,25 +95,25 @@ float2 DS_GetLamScaleBias(float4 gbuffer)
|
|||
|
||||
void DS_SetLamScaleBias(inout DS_FSO so, float2 lamScaleBias, float4 aniso)
|
||||
{
|
||||
so.target2.rg = lerp(lamScaleBias * float2(1.0 / 8.0, 0.25) + float2(0, 0.5), EncodeNormal(aniso.xyz), aniso.w);
|
||||
so.target2.rg = lerp(lamScaleBias * float2(1.f / 8.f, 0.25f) + float2(0, 0.5f), EncodeNormal(aniso.xyz), aniso.w);
|
||||
}
|
||||
|
||||
float2 DS_GetMetallicity(float4 gbuffer)
|
||||
{
|
||||
const float x2 = gbuffer.b * 2.02;
|
||||
const float x2 = gbuffer.b * 2.02f;
|
||||
return float2(
|
||||
saturate(x2 - 1.02),
|
||||
saturate(1.0 - x2));
|
||||
saturate(x2 - 1.02f),
|
||||
saturate(1.f - x2));
|
||||
}
|
||||
|
||||
void DS_SetMetallicity(inout DS_FSO so, float metal, float hair)
|
||||
void DS_SetMetallicity(inout DS_FSO so, float metalMask, float hairMask)
|
||||
{
|
||||
so.target2.b = (metal - hair) * 0.5 + 0.5;
|
||||
so.target2.b = (metalMask - hairMask) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
void DS_SetGloss(inout DS_FSO so, float gloss)
|
||||
{
|
||||
so.target2.a = gloss * (1.0 / 64.0);
|
||||
so.target2.a = gloss * (1.f / 64.f);
|
||||
}
|
||||
|
||||
float3 DS_GetPosition(float4 gbuffer, matrix matInvProj, float2 ndcPos)
|
||||
|
|
|
@ -1,55 +1,41 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
|
||||
// Convert non-linear z-buffer value to positive linear form:
|
||||
float ToLinearDepth(float d, float4 zNearFarEx)
|
||||
float ToLinearDepth(float dz, float4 zNearFarEx)
|
||||
{
|
||||
// INFO: zNearFarEx.z = zFar/(zFar-zNear)
|
||||
// INFO: zNearFarEx.w = zFar*zNear/(zNear-zFar)
|
||||
return zNearFarEx.w / (d - zNearFarEx.z);
|
||||
return zNearFarEx.w / (dz - zNearFarEx.z);
|
||||
}
|
||||
float2 ToLinearDepth(float2 d, float4 zNearFarEx)
|
||||
float2 ToLinearDepth(float2 dz, float4 zNearFarEx)
|
||||
{
|
||||
return zNearFarEx.w / (d - zNearFarEx.z);
|
||||
return zNearFarEx.w / (dz - zNearFarEx.z);
|
||||
}
|
||||
float4 ToLinearDepth(float4 d, float4 zNearFarEx)
|
||||
float4 ToLinearDepth(float4 dz, float4 zNearFarEx)
|
||||
{
|
||||
return zNearFarEx.w / (d - zNearFarEx.z);
|
||||
return zNearFarEx.w / (dz - zNearFarEx.z);
|
||||
}
|
||||
|
||||
float ComputeFog(float depth, float density, float height = 0.0)
|
||||
float ComputeFog(float depth, float density, float height = 0.f)
|
||||
{
|
||||
const float strength = 1.0 - saturate(height * 0.003);
|
||||
const float power = depth * lerp(0.0, density, strength * strength);
|
||||
const float fog = 1.0 / exp(power * power);
|
||||
return 1.0 - saturate(fog);
|
||||
const float strength = 1.f - saturate(height * 0.003f);
|
||||
const float power = depth * lerp(0.f, density, strength * strength);
|
||||
const float fog = 1.f / exp(power * power);
|
||||
return 1.f - saturate(fog);
|
||||
}
|
||||
|
||||
float3 AdjustPosForShadow(float3 pos, float3 normal, float3 dirToLight, float depth, float offset = 0.0)
|
||||
float3 AdjustPosForShadow(float3 pos, float3 normal, float3 dirToLight, float depth, float offset = 0.f)
|
||||
{
|
||||
const float scale = depth - 5.0;
|
||||
return pos + normal * 0.012 * max(1.0, scale * 0.2) + dirToLight * max(0.0, scale * 0.002 + offset);
|
||||
const float scale = depth - 5.f;
|
||||
return pos +
|
||||
normal * 0.015f * max(1.f, scale * 0.2f) +
|
||||
dirToLight * max(0.f, scale * 0.002f + offset);
|
||||
}
|
||||
|
||||
float4 ShadowCoords(float4 pos, matrix mat, float depth)
|
||||
float ComputePenumbraContrast(float deltaScale, float strength, float dzFrag, float dzBlockers)
|
||||
{
|
||||
// For CSM transformation is done in PS.
|
||||
#if _SHADOW_QUALITY >= 4
|
||||
return float4(pos.xyz, depth);
|
||||
#else
|
||||
return mul(pos, mat);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsValidShadowSample(int x, int y)
|
||||
{
|
||||
int sum = abs(x) + abs(y);
|
||||
if (4 == sum)
|
||||
return false;
|
||||
#if _SHADOW_QUALITY <= 4
|
||||
if (1 == sum % 2)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
const float delta = saturate(dzFrag - dzBlockers);
|
||||
return 1.f + max(0.f, 3.f - delta * deltaScale) * strength;
|
||||
}
|
||||
|
||||
float PCF(
|
||||
|
@ -60,42 +46,100 @@ float PCF(
|
|||
float3 tc,
|
||||
float4 config)
|
||||
{
|
||||
#if _SHADOW_QUALITY <= 2
|
||||
return texCmp.SampleCmpLevelZero(samCmp, tc.xy, tc.z).r;
|
||||
#else
|
||||
const float dzFrag = tc.z;
|
||||
float2 dzBlockers_blockerCount = 0.0;
|
||||
float sum = 0.0;
|
||||
int count = 0;
|
||||
[unroll] for (int y = -2; y <= 2; ++y)
|
||||
#if _SHADOW_QUALITY <= _Q_MEDIUM
|
||||
return texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag).r;
|
||||
#elif _SHADOW_QUALITY <= _Q_HIGH
|
||||
// High quality, use 5x5 PCF:
|
||||
float sum = 0.f;
|
||||
[unroll] for (int y = -2; y <= 2; y += 2)
|
||||
{
|
||||
[unroll] for (int x = -2; x <= 2; ++x)
|
||||
[unroll] for (int x = -2; x <= 2; x += 2)
|
||||
{
|
||||
if (!IsValidShadowSample(x, y))
|
||||
continue;
|
||||
count++;
|
||||
|
||||
const float alpha = texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag, int2(x, y)).r;
|
||||
sum += alpha;
|
||||
|
||||
const float dzBlocker = tex.SampleLevel(sam, tc.xy, 0, int2(x, y)).r;
|
||||
if (dzBlocker < dzFrag)
|
||||
dzBlockers_blockerCount += float2(dzBlocker, 1);
|
||||
int2 offset = int2(x, y);
|
||||
if (abs(x) + abs(y) == 4)
|
||||
offset = clamp(offset, -1, 1);
|
||||
sum += texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag, offset).r;
|
||||
}
|
||||
}
|
||||
const float ret = sum * (1.0 / count);
|
||||
if (dzBlockers_blockerCount.y > 0.0)
|
||||
sum *= (1.f / 9.f); // 3x3
|
||||
if (sum * (1.f - sum) != 0.f)
|
||||
{
|
||||
const float penumbraScale = config.x;
|
||||
const float penumbraContrastMask = config.y;
|
||||
const float dzBlockers = dzBlockers_blockerCount.x / dzBlockers_blockerCount.y;
|
||||
const float penumbra = saturate(dzFrag - dzBlockers);
|
||||
const float contrast = 1.0 + max(0.0, 3.0 - penumbra * penumbraScale) * penumbraContrastMask;
|
||||
return saturate((ret - 0.5) * contrast + 0.5);
|
||||
float2 dzBlockers_blockerCount = 0.f;
|
||||
sum = 0.f;
|
||||
[unroll] for (int y = -2; y <= 2; ++y)
|
||||
{
|
||||
[unroll] for (int x = -2; x <= 2; ++x)
|
||||
{
|
||||
if (abs(x) + abs(y) == 4)
|
||||
continue;
|
||||
sum += texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag, int2(x, y)).r;
|
||||
const float dzBlocker = tex.SampleLevel(sam, tc.xy, 0, int2(x, y)).r;
|
||||
if (dzBlocker < dzFrag)
|
||||
dzBlockers_blockerCount += float2(dzBlocker, 1);
|
||||
}
|
||||
}
|
||||
const float ret = sum *= (1.f / 21.f); // 5x5 - 4
|
||||
if (dzBlockers_blockerCount.y > 0.f)
|
||||
{
|
||||
const float dzBlockers = dzBlockers_blockerCount.x / dzBlockers_blockerCount.y;
|
||||
const float contrast = ComputePenumbraContrast(config.x, config.y, dzFrag, dzBlockers);
|
||||
return saturate((ret - 0.5f) * contrast + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
return sum;
|
||||
}
|
||||
#else
|
||||
// Ultra quality, use 7x7 PCF:
|
||||
float sum = 0.f;
|
||||
[unroll] for (int y = -3; y <= 3; y += 2)
|
||||
{
|
||||
[unroll] for (int x = -3; x <= 3; x += 2)
|
||||
{
|
||||
int2 offset = int2(x, y);
|
||||
if (abs(x) + abs(y) == 6)
|
||||
offset = clamp(offset, -2, 2);
|
||||
sum += texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag, offset).r;
|
||||
}
|
||||
}
|
||||
sum *= (1.f / 16.f); // 4x4
|
||||
if (sum * (1.f - sum) != 0.f)
|
||||
{
|
||||
float2 dzBlockers_blockerCount = 0.f;
|
||||
sum = 0.f;
|
||||
[unroll] for (int y = -3; y <= 3; ++y)
|
||||
{
|
||||
[unroll] for (int x = -3; x <= 3; ++x)
|
||||
{
|
||||
if (abs(x) + abs(y) == 6)
|
||||
continue;
|
||||
sum += texCmp.SampleCmpLevelZero(samCmp, tc.xy, dzFrag, int2(x, y)).r;
|
||||
const float dzBlocker = tex.SampleLevel(sam, tc.xy, 0, int2(x, y)).r;
|
||||
if (dzBlocker < dzFrag)
|
||||
dzBlockers_blockerCount += float2(dzBlocker, 1);
|
||||
}
|
||||
}
|
||||
const float ret = sum *= (1.f / 45.f); // 7x7 - 4
|
||||
if (dzBlockers_blockerCount.y > 0.f)
|
||||
{
|
||||
const float dzBlockers = dzBlockers_blockerCount.x / dzBlockers_blockerCount.y;
|
||||
const float contrast = ComputePenumbraContrast(config.x, config.y, dzFrag, dzBlockers);
|
||||
return saturate((ret - 0.5f) * contrast + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return sum;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -113,16 +157,28 @@ float ShadowMap(
|
|||
SamplerComparisonState samCmp,
|
||||
Texture2D tex,
|
||||
SamplerState sam,
|
||||
float4 tc,
|
||||
float3 tc,
|
||||
float4 config)
|
||||
{
|
||||
#if _SHADOW_QUALITY <= 0
|
||||
return 1.0;
|
||||
#else
|
||||
const float ret = PCF(texCmp, samCmp, tex, sam, tc.xyz, config);
|
||||
const float2 center = tc.xy * 2.0 - 1.0;
|
||||
return max(ret, saturate(dot(center, center) * (9.0 / 4.0) - 1.0));
|
||||
#endif
|
||||
const float ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
const float2 center = tc.xy * 2.f - 1.f;
|
||||
return max(ret, saturate(dot(center, center) * (9.f / 4.f) - 1.f));
|
||||
}
|
||||
|
||||
float SimpleShadowMap(
|
||||
Texture2D texCmp,
|
||||
SamplerComparisonState samCmp,
|
||||
float3 tc)
|
||||
{
|
||||
const float ret = SimplePCF(texCmp, samCmp, tc);
|
||||
const float2 center = tc.xy * 2.f - 1.f;
|
||||
return max(ret, saturate(dot(center, center) * (9.f / 4.f) - 1.f));
|
||||
}
|
||||
|
||||
bool IsClippedCSM(float4 clipSpacePos)
|
||||
{
|
||||
const float4 absPos = abs(clipSpacePos);
|
||||
return all(absPos.xyz <= absPos.w * float3(1.01f, 1.01f, 1.f));
|
||||
}
|
||||
|
||||
float ShadowMapCSM(
|
||||
|
@ -130,99 +186,123 @@ float ShadowMapCSM(
|
|||
SamplerComparisonState samCmp,
|
||||
Texture2D tex,
|
||||
SamplerState sam,
|
||||
float4 pos,
|
||||
float4 config,
|
||||
float4 ranges,
|
||||
float3 intactPos,
|
||||
float3 biasedPos,
|
||||
matrix mat0,
|
||||
matrix mat1,
|
||||
matrix mat2,
|
||||
matrix mat3)
|
||||
matrix mat3,
|
||||
matrix matScreen,
|
||||
float4 csmSplitRanges,
|
||||
float4 config)
|
||||
{
|
||||
#if _SHADOW_QUALITY >= 4
|
||||
float ret = 1.0;
|
||||
const float4 p = float4(pos.xyz, 1);
|
||||
float contrast = 1.0;
|
||||
#if _SHADOW_QUALITY >= _Q_HIGH
|
||||
float ret = 1.f;
|
||||
float contrast = 1.f;
|
||||
const float contrastScale = config.w;
|
||||
const float4 clipSpacePos = mul(float4(intactPos, 1.f), matScreen);
|
||||
const float depth = clipSpacePos.w;
|
||||
|
||||
if (pos.w > ranges.x)
|
||||
if (IsClippedCSM(clipSpacePos))
|
||||
{
|
||||
const float fadeStart = (ranges.x + ranges.w) * 0.5;
|
||||
const float fade = saturate((pos.w - fadeStart) / (ranges.w - fadeStart));
|
||||
if (depth >= csmSplitRanges.x)
|
||||
{
|
||||
const float fadeStart = (csmSplitRanges.x + csmSplitRanges.w) * 0.5f;
|
||||
const float fade = saturate((depth - fadeStart) / (csmSplitRanges.w - fadeStart));
|
||||
|
||||
contrast = contrastScale * contrastScale * contrastScale;
|
||||
const float3 tc = mul(p, mat0).xyz;
|
||||
ret = max(PCF(texCmp, samCmp, tex, sam, tc, config), fade);
|
||||
}
|
||||
else if (pos.w > ranges.y)
|
||||
{
|
||||
contrast = contrastScale * contrastScale;
|
||||
const float3 tc = mul(p, mat1).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
}
|
||||
else if (pos.w > ranges.z)
|
||||
{
|
||||
contrast = contrastScale;
|
||||
const float3 tc = mul(p, mat2).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
contrast = contrastScale * contrastScale * contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat0).xyz;
|
||||
ret = max(PCF(texCmp, samCmp, tex, sam, tc, config), fade);
|
||||
}
|
||||
else if (depth >= csmSplitRanges.y)
|
||||
{
|
||||
contrast = contrastScale * contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat1).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
}
|
||||
else if (depth >= csmSplitRanges.z)
|
||||
{
|
||||
contrast = contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat2).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat3).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
}
|
||||
|
||||
return saturate((ret - 0.5f) * contrast + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float3 tc = mul(p, mat3).xyz;
|
||||
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
|
||||
}
|
||||
|
||||
return saturate((ret - 0.5) * contrast + 0.5);
|
||||
return 1.f;
|
||||
#else
|
||||
return ShadowMap(texCmp, samCmp, tex, sam, pos, config);
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat0).xyz;
|
||||
if (all(tc.xy >= 0.f) && all(tc.xy < 1.f))
|
||||
return ShadowMap(texCmp, samCmp, tex, sam, tc, config);
|
||||
else
|
||||
return 1.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
float SimpleShadowMapCSM(
|
||||
Texture2D texCmp,
|
||||
SamplerComparisonState samCmp,
|
||||
float4 pos,
|
||||
float4 config,
|
||||
float4 ranges,
|
||||
float3 intactPos,
|
||||
float3 biasedPos,
|
||||
matrix mat0,
|
||||
matrix mat1,
|
||||
matrix mat2,
|
||||
matrix mat3)
|
||||
matrix mat3,
|
||||
matrix matScreen,
|
||||
float4 csmSplitRanges,
|
||||
float4 config)
|
||||
{
|
||||
#if _SHADOW_QUALITY >= 4
|
||||
float ret = 1.0;
|
||||
const float4 p = float4(pos.xyz, 1);
|
||||
float contrast = 1.0;
|
||||
#if _SHADOW_QUALITY >= _Q_HIGH
|
||||
float ret = 1.f;
|
||||
float contrast = 1.f;
|
||||
const float contrastScale = config.w;
|
||||
const float4 clipSpacePos = mul(float4(intactPos, 1.f), matScreen);
|
||||
const float depth = clipSpacePos.w;
|
||||
|
||||
if (pos.w > ranges.x)
|
||||
if (IsClippedCSM(clipSpacePos))
|
||||
{
|
||||
const float fadeStart = (ranges.x + ranges.w) * 0.5;
|
||||
const float fade = saturate((pos.w - fadeStart) / (ranges.w - fadeStart));
|
||||
if (depth >= csmSplitRanges.x)
|
||||
{
|
||||
const float fadeStart = (csmSplitRanges.x + csmSplitRanges.w) * 0.5f;
|
||||
const float fade = saturate((depth - fadeStart) / (csmSplitRanges.w - fadeStart));
|
||||
|
||||
contrast = contrastScale * contrastScale * contrastScale;
|
||||
const float3 tc = mul(p, mat0).xyz;
|
||||
ret = max(SimplePCF(texCmp, samCmp, tc), fade);
|
||||
}
|
||||
else if (pos.w > ranges.y)
|
||||
{
|
||||
contrast = contrastScale * contrastScale;
|
||||
const float3 tc = mul(p, mat1).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
}
|
||||
else if (pos.w > ranges.z)
|
||||
{
|
||||
contrast = contrastScale;
|
||||
const float3 tc = mul(p, mat2).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
contrast = contrastScale * contrastScale * contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat0).xyz;
|
||||
ret = max(SimplePCF(texCmp, samCmp, tc), fade);
|
||||
}
|
||||
else if (depth >= csmSplitRanges.y)
|
||||
{
|
||||
contrast = contrastScale * contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat1).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
}
|
||||
else if (depth >= csmSplitRanges.z)
|
||||
{
|
||||
contrast = contrastScale;
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat2).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat3).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
}
|
||||
|
||||
return saturate((ret - 0.5f) * contrast + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float3 tc = mul(p, mat3).xyz;
|
||||
ret = SimplePCF(texCmp, samCmp, tc);
|
||||
}
|
||||
|
||||
return saturate((ret - 0.5) * contrast + 0.5);
|
||||
return 1.f;
|
||||
#else
|
||||
return SimplePCF(texCmp, samCmp, pos.xyz);
|
||||
const float3 tc = mul(float4(biasedPos, 1.f), mat0).xyz;
|
||||
if (all(tc.xy >= 0.f) && all(tc.xy < 1.f))
|
||||
return SimpleShadowMap(texCmp, samCmp, tc);
|
||||
else
|
||||
return 1.f;
|
||||
#endif
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue