This commit is contained in:
Dmitry 2021-01-03 02:37:27 +03:00
parent 2cbe3aa503
commit 559a017843
130 changed files with 20724 additions and 2017 deletions

View File

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

View File

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

View File

@ -21,5 +21,7 @@ namespace verus
CSZ ToNativeSemanticName(ViaUsage usage);
DXGI_FORMAT ToNativeFormat(ViaUsage usage, ViaType type, int components);
UINT ToNativeCubeMapFace(CubeMapFace face);
}
}

View File

@ -71,6 +71,7 @@ namespace verus
Vector<D3DFramebufferSubpass> _vSubpasses;
int _width = 0;
int _height = 0;
CubeMapFace _cubeMapFace = CubeMapFace::none;
};
VERUS_TYPEDEFS(D3DFramebuffer);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.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 />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include "Blur.h"
#include "Bloom.h"
#include "Ssao.h"
#include "Ssr.h"
#include "Particles.h"
namespace verus

View File

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

View File

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

167
Verus/src/Effects/Ssr.cpp Normal file
View File

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

43
Verus/src/Effects/Ssr.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

167
Verus/src/Extra/ConvertX.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

126
Verus/src/Scene/CubeMap.cpp Normal file
View File

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

45
Verus/src/Scene/CubeMap.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,8 @@ VERUS_UBUFFER UB_BlurVS
VERUS_UBUFFER UB_BlurFS
{
float4 _dummy;
float3 _radius_invRadius_stride;
int _sampleCount;
};
VERUS_UBUFFER UB_ExtraBlurFS

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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