This commit is contained in:
Dmitry 2020-06-01 19:25:41 +03:00
parent ee5afaab96
commit 043c4c9e65
118 changed files with 5135 additions and 2467 deletions

View File

@ -324,6 +324,12 @@ void RendererD3D12::CreateSamplers()
desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
_vSamplers[+Sampler::aniso] = desc;
desc = init;
desc.Filter = D3D12_FILTER_ANISOTROPIC;
desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
_vSamplers[+Sampler::anisoClamp] = desc;
// <Wrap>
desc = init;
_vSamplers[+Sampler::linearMipL] = desc;
@ -386,7 +392,7 @@ void RendererD3D12::ImGuiInit(RPHandle renderPassHandle)
IO::FileSystem::LoadResource(_C(settings._imguiFont), vData);
void* pFontData = IM_ALLOC(vData.size());
memcpy(pFontData, vData.data(), vData.size());
io.Fonts->AddFontFromMemoryTTF(pFontData, Utils::Cast32(vData.size()), settings.GetFontSize(), nullptr, io.Fonts->GetGlyphRangesCyrillic());
io.Fonts->AddFontFromMemoryTTF(pFontData, Utils::Cast32(vData.size()), static_cast<float>(settings.GetFontSize()), nullptr, io.Fonts->GetGlyphRangesCyrillic());
}
ImGui::StyleColorsDark();

View File

@ -650,7 +650,7 @@ void ShaderD3D12::UpdateDebugInfo(
{
case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
{
VERUS_FOR(i, rootParam.DescriptorTable.NumDescriptorRanges)
VERUS_U_FOR(i, rootParam.DescriptorTable.NumDescriptorRanges)
{
auto& descRange = rootParam.DescriptorTable.pDescriptorRanges[i];
ss << " Type=";

View File

@ -16,9 +16,11 @@ void TextureD3D12::Init(RcTextureDesc desc)
{
VERUS_INIT();
VERUS_RT_ASSERT(desc._width > 0 && desc._height > 0);
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
_initAtFrame = renderer.GetFrameCount();
_size = Vector4(
float(desc._width),
float(desc._height),
@ -108,6 +110,29 @@ void TextureD3D12::Init(RcTextureDesc desc)
}
}
if (_desc._readbackMip != SHRT_MAX)
{
if (_desc._readbackMip < 0)
_desc._readbackMip = _desc._mipLevels + _desc._readbackMip;
const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
const UINT64 bufferSize = _bytesPerPixel * w * h;
_vReadbackBuffers.resize(BaseRenderer::s_ringBufferSize);
for (auto& x : _vReadbackBuffers)
{
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_READBACK;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
&CD3DX12_RESOURCE_DESC::Buffer(bufferSize),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
&x._pMaAllocation,
IID_PPV_ARGS(&x._pResource))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_READBACK), hr=" << VERUS_HR(hr);
}
}
if (renderTarget)
{
_dhRTV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
@ -150,6 +175,13 @@ void TextureD3D12::Done()
{
ForceScheduled();
for (auto& x : _vReadbackBuffers)
{
VERUS_SMART_RELEASE(x._pMaAllocation);
VERUS_COM_RELEASE_CHECK(x._pResource.Get());
x._pResource.Reset();
}
_vReadbackBuffers.clear();
_dhSampler.Reset();
_dhDSV.Reset();
_dhRTV.Reset();
@ -212,7 +244,8 @@ void TextureD3D12::UpdateSubresource(const void* p, int mipLevel, int arrayLayer
sd.SlicePitch = _bytesPerPixel * w * h;
}
const UINT subresource = D3D12CalcSubresource(mipLevel, arrayLayer, 0, _desc._mipLevels, _desc._arrayLayers);
UpdateSubresources<1>(pCmdList,
UpdateSubresources<1>(
pCmdList,
_resource._pResource.Get(),
sb._pResource.Get(),
0,
@ -224,6 +257,47 @@ void TextureD3D12::UpdateSubresource(const void* p, int mipLevel, int arrayLayer
Schedule();
}
bool TextureD3D12::ReadbackSubresource(void* p, PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
HRESULT hr = 0;
const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
const UINT rowPitch = Math::AlignUp(_bytesPerPixel * w, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
auto& rb = _vReadbackBuffers[renderer->GetRingBufferIndex()];
// Schedule copying to readback buffer:
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
auto pCmdList = static_cast<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), _mainLayout, ImageLayout::transferSrc, _desc._readbackMip, 0);
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
footprint.Footprint.Format = ToNativeFormat(_desc._format, false);
footprint.Footprint.Width = w;
footprint.Footprint.Height = h;
footprint.Footprint.Depth = 1;
footprint.Footprint.RowPitch = rowPitch;
const UINT subresource = D3D12CalcSubresource(_desc._readbackMip, 0, 0, _desc._mipLevels, _desc._arrayLayers);
pCmdList->CopyTextureRegion(
&CD3DX12_TEXTURE_COPY_LOCATION(rb._pResource.Get(), footprint),
0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subresource),
nullptr);
pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0);
// Read current data from readback buffer:
CD3DX12_RANGE readRange(0, 0);
void* pData = nullptr;
if (FAILED(hr = rb._pResource->Map(0, &readRange, &pData)))
throw VERUS_RUNTIME_ERROR << "Map(), hr=" << VERUS_HR(hr);
memcpy(p, pData, _bytesPerPixel * w);
rb._pResource->Unmap(0, nullptr);
return _initAtFrame + BaseRenderer::s_ringBufferSize < renderer.GetFrameCount();
}
void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
@ -238,7 +312,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
if (_mainLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, _mainLayout, ImageLayout::xsReadOnly, Range<int>(0, _desc._mipLevels - 1));
pCB->BindPipeline(renderer.GetPipelineGenerateMips());
pCB->BindPipeline(renderer.GetPipelineGenerateMips(!!(_desc._flags & TextureDesc::Flags::exposureMips)));
auto shader = renderer.GetShaderGenerateMips();
shader->BeginBindDescriptors();
@ -253,7 +327,7 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
const int dstWidth = Math::Max(1, srcWidth >> 1);
const int dstHeight = Math::Max(1, srcHeight >> 1);
int dispatchMipCount = 4;
int dispatchMipCount = Math::LowestBit((dstWidth == 1 ? dstHeight : dstWidth) | (dstHeight == 1 ? dstWidth : dstHeight));
dispatchMipCount = Math::Min(4, dispatchMipCount + 1);
dispatchMipCount = ((srcMip + dispatchMipCount) >= _desc._mipLevels) ? _desc._mipLevels - srcMip - 1 : dispatchMipCount; // Edge case.

View File

@ -15,6 +15,7 @@ namespace verus
ResourceEx _resource;
ResourceEx _uaResource;
Vector<ResourceEx> _vStagingBuffers;
Vector<ResourceEx> _vReadbackBuffers;
Vector<CSHandle> _vCshGenerateMips;
DescriptorHeap _dhSRV;
DescriptorHeap _dhUAV;
@ -30,6 +31,7 @@ namespace verus
virtual void Done() override;
virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override;
virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;

View File

@ -30,6 +30,6 @@ IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
// Use if you want to reset your rendering device without losing ImGui state.
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();

View File

@ -257,6 +257,14 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout
dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
// Reading to readback buffer.
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
vkimb[index].srcAccessMask = 0;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
// Regular texture's first and only update (before transfer).
@ -281,6 +289,14 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout
dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
// Reading to readback buffer.
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].srcAccessMask = 0;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
// To update regular texture during mipmap generation.
@ -297,6 +313,14 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
// To restore image after transfer to readback buffer.
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].srcAccessMask = 0;
dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
// To sample regular texture after update.

View File

@ -189,8 +189,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL RendererVulkan::DebugUtilsMessengerCallback(
severity = D::Log::Severity::warning;
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
severity = D::Log::Severity::error;
if (!strstr(pCallbackData->pMessage, "ptr to input arr[1] of struct of"))
D::Log::I().Write(pCallbackData->pMessage, std::this_thread::get_id(), __FILE__, __LINE__, severity);
D::Log::I().Write(pCallbackData->pMessage, std::this_thread::get_id(), __FILE__, __LINE__, severity);
return VK_FALSE;
}
@ -425,6 +424,7 @@ void RendererVulkan::CreateDevice()
physicalDeviceFeatures.multiViewport = VK_TRUE;
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE;
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE;
physicalDeviceFeatures.shaderClipDistance = VK_TRUE;
VkDeviceCreateInfo vkdci = {};
vkdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
vkdci.pNext = &lineRasterizationFeatures;
@ -627,6 +627,12 @@ void RendererVulkan::CreateSamplers()
vksci.maxAnisotropy = static_cast<float>(settings._gpuAnisotropyLevel);
_vSamplers[+Sampler::aniso] = Create(vksci);
vksci = init;
vksci.addressModeU = vksci.addressModeV = vksci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
vksci.anisotropyEnable = (settings._gpuAnisotropyLevel > 0) ? VK_TRUE : VK_FALSE;
vksci.maxAnisotropy = static_cast<float>(settings._gpuAnisotropyLevel);
_vSamplers[+Sampler::anisoClamp] = Create(vksci);
// <Repeat>
vksci = init;
_vSamplers[+Sampler::linearMipL] = Create(vksci);
@ -1317,3 +1323,29 @@ void RendererVulkan::CopyBufferToImage(
vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
void RendererVulkan::CopyImageToBuffer(
VkImage image, uint32_t mipLevel, uint32_t arrayLayer,
uint32_t width, uint32_t height,
VkBuffer buffer,
PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
auto commandBuffer = static_cast<PCommandBufferVulkan>(pCB)->GetVkCommandBuffer();
VkBufferImageCopy region = {};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = mipLevel;
region.imageSubresource.baseArrayLayer = arrayLayer;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { width, height, 1 };
vkCmdCopyImageToBuffer(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1, &region);
}

View File

@ -176,6 +176,11 @@ namespace verus
VkImage image, uint32_t mipLevel, uint32_t arrayLayer,
uint32_t width, uint32_t height,
PBaseCommandBuffer pCB = nullptr);
void CopyImageToBuffer(
VkImage image, uint32_t mipLevel, uint32_t arrayLayer,
uint32_t width, uint32_t height,
VkBuffer buffer,
PBaseCommandBuffer pCB = nullptr);
};
VERUS_TYPEDEFS(RendererVulkan);
}

View File

@ -16,9 +16,11 @@ void TextureVulkan::Init(RcTextureDesc desc)
{
VERUS_INIT();
VERUS_RT_ASSERT(desc._width > 0 && desc._height > 0);
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
_initAtFrame = renderer.GetFrameCount();
_size = Vector4(
float(desc._width),
float(desc._height),
@ -51,6 +53,8 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (_desc._flags & TextureDesc::Flags::generateMips)
vkici.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (_desc._readbackMip != SHRT_MAX)
vkici.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (depthFormat)
{
vkici.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
@ -79,7 +83,7 @@ void TextureVulkan::Init(RcTextureDesc desc)
_vCshGenerateMips.reserve((_desc._mipLevels + 3) / 4);
_vStorageImageViews.resize(vkiciStorage.mipLevels);
VERUS_FOR(mip, vkiciStorage.mipLevels)
VERUS_U_FOR(mip, vkiciStorage.mipLevels)
{
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@ -96,6 +100,21 @@ void TextureVulkan::Init(RcTextureDesc desc)
}
}
if (_desc._readbackMip != SHRT_MAX)
{
if (_desc._readbackMip < 0)
_desc._readbackMip = _desc._mipLevels + _desc._readbackMip;
const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
VkDeviceSize bufferSize = _bytesPerPixel * w * h;
_vReadbackBuffers.resize(BaseRenderer::s_ringBufferSize);
for (auto& x : _vReadbackBuffers)
{
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU,
x._buffer, x._vmaAllocation);
}
}
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _image;
@ -146,6 +165,9 @@ void TextureVulkan::Done()
ForceScheduled();
for (auto& x : _vReadbackBuffers)
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_VULKAN_DESTROY(_imageView, vkDestroyImageView(pRendererVulkan->GetVkDevice(), _imageView, pRendererVulkan->GetAllocator()));
@ -201,6 +223,39 @@ void TextureVulkan::UpdateSubresource(const void* p, int mipLevel, int arrayLaye
Schedule();
}
bool TextureVulkan::ReadbackSubresource(void* p, PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
const VkDeviceSize bufferSize = _bytesPerPixel * w * h;
auto& rb = _vReadbackBuffers[renderer->GetRingBufferIndex()];
// Schedule copying to readback buffer:
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), GetSubresourceMainLayout(_desc._readbackMip, 0), ImageLayout::transferSrc, _desc._readbackMip, 0);
pRendererVulkan->CopyImageToBuffer(
_image, _desc._readbackMip, 0,
w, h,
rb._buffer,
pCB);
pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferSrc, _mainLayout, _desc._readbackMip, 0);
// Read current data from readback buffer:
void* pData = nullptr;
if (VK_SUCCESS != (res = vmaMapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation, &pData)))
throw VERUS_RECOVERABLE << "vmaMapMemory(), res=" << res;
memcpy(p, pData, bufferSize);
vmaUnmapMemory(pRendererVulkan->GetVmaAllocator(), rb._vmaAllocation);
return _initAtFrame + BaseRenderer::s_ringBufferSize < renderer.GetFrameCount();
}
void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
@ -229,7 +284,7 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
VERUS_FOR(mip, _desc._mipLevels)
MarkSubresourceDefined(mip, 0);
pCB->BindPipeline(renderer.GetPipelineGenerateMips());
pCB->BindPipeline(renderer.GetPipelineGenerateMips(!!(_desc._flags & TextureDesc::Flags::exposureMips)));
auto shader = renderer.GetShaderGenerateMips();
shader->BeginBindDescriptors();
@ -244,7 +299,7 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
const int dstWidth = Math::Max(1, srcWidth >> 1);
const int dstHeight = Math::Max(1, srcHeight >> 1);
int dispatchMipCount = 4;
int dispatchMipCount = Math::LowestBit((dstWidth == 1 ? dstHeight : dstWidth) | (dstHeight == 1 ? dstWidth : dstHeight));
dispatchMipCount = Math::Min(4, dispatchMipCount + 1);
dispatchMipCount = ((srcMip + dispatchMipCount) >= _desc._mipLevels) ? _desc._mipLevels - srcMip - 1 : dispatchMipCount; // Edge case.

View File

@ -22,6 +22,7 @@ namespace verus
Vector<UINT32> _vDefinedSubresources;
Vector<VkImageView> _vStorageImageViews;
Vector<VkBufferEx> _vStagingBuffers;
Vector<VkBufferEx> _vReadbackBuffers;
Vector<CSHandle> _vCshGenerateMips;
bool _definedStorage = false;
@ -33,6 +34,7 @@ namespace verus
virtual void Done() override;
virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override;
virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;

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.88\src;C:\Home\Middleware\bullet3-2.88\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\SDL2-2.0.10\include;C:\Program Files %28x86%29\OpenAL 1.1 SDK\include;C:\VulkanSDK\1.2.131.2\Include;C:\VulkanSDK\1.2.131.2\glslang;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.88\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\SDL2-2.0.10\lib\x64;C:\Program Files %28x86%29\OpenAL 1.1 SDK\libs\Win64;C:\VulkanSDK\1.2.131.2\Lib;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\include;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.6\include;C:\Home\Middleware\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.12\include;C:\VulkanSDK\1.2.141.2\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\DevIL-Windows-SDK-1.8.0\lib\x64\Release;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.6\lib2;C:\Home\Middleware\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.12\lib\x64;C:\VulkanSDK\1.2.141.2\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View File

@ -93,7 +93,8 @@
<ClInclude Include="src\AI\Turret.h" />
<ClInclude Include="src\Anim\Anim.h" />
<ClInclude Include="src\Anim\Animation.h" />
<ClInclude Include="src\Anim\Damping.h" />
<ClInclude Include="src\Anim\Elastic.h" />
<ClInclude Include="src\Anim\Orbit.h" />
<ClInclude Include="src\Anim\Warp.h" />
<ClInclude Include="src\Anim\Motion.h" />
<ClInclude Include="src\Anim\Skeleton.h" />
@ -131,6 +132,7 @@
<ClInclude Include="src\Extra\Extra.h" />
<ClInclude Include="src\Extra\FileParser.h" />
<ClInclude Include="src\Game\BaseGame.h" />
<ClInclude Include="src\Game\BaseCharacter.h" />
<ClInclude Include="src\Game\Spirit.h" />
<ClInclude Include="src\Game\Game.h" />
<ClInclude Include="src\Game\State.h" />
@ -141,6 +143,7 @@
<ClInclude Include="src\Global\Basic.h" />
<ClInclude Include="src\Global\Blob.h" />
<ClInclude Include="src\Global\Convert.h" />
<ClInclude Include="src\Global\Cooldown.h" />
<ClInclude Include="src\Global\EngineInit.h" />
<ClInclude Include="src\Global\GlobalVarsClipboard.h" />
<ClInclude Include="src\Global\Linear.h" />
@ -252,6 +255,7 @@
<ClCompile Include="src\AI\Turret.cpp" />
<ClCompile Include="src\Anim\Anim.cpp" />
<ClCompile Include="src\Anim\Animation.cpp" />
<ClCompile Include="src\Anim\Orbit.cpp" />
<ClCompile Include="src\Anim\Warp.cpp" />
<ClCompile Include="src\Anim\Motion.cpp" />
<ClCompile Include="src\Anim\Skeleton.cpp" />
@ -283,11 +287,13 @@
<ClCompile Include="src\Extra\Extra.cpp" />
<ClCompile Include="src\Extra\FileParser.cpp" />
<ClCompile Include="src\Game\BaseGame.cpp" />
<ClCompile Include="src\Game\BaseCharacter.cpp" />
<ClCompile Include="src\Game\Spirit.cpp" />
<ClCompile Include="src\Game\State.cpp" />
<ClCompile Include="src\Game\StateMachine.cpp" />
<ClCompile Include="src\Global\AllocatorAware.cpp" />
<ClCompile Include="src\Global\Convert.cpp" />
<ClCompile Include="src\Global\Cooldown.cpp" />
<ClCompile Include="src\Global\EngineInit.cpp" />
<ClCompile Include="src\Global\Global.cpp" />
<ClCompile Include="src\Global\GlobalVarsClipboard.cpp" />

View File

@ -396,9 +396,6 @@
<ClInclude Include="src\CGI\Types.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\Anim\Damping.h">
<Filter>src\Anim</Filter>
</ClInclude>
<ClInclude Include="src\Game\Spirit.h">
<Filter>src\Game</Filter>
</ClInclude>
@ -561,6 +558,18 @@
<ClInclude Include="src\Scene\Water.h">
<Filter>src\Scene</Filter>
</ClInclude>
<ClInclude Include="src\Global\Cooldown.h">
<Filter>src\Global</Filter>
</ClInclude>
<ClInclude Include="src\Anim\Orbit.h">
<Filter>src\Anim</Filter>
</ClInclude>
<ClInclude Include="src\Game\BaseCharacter.h">
<Filter>src\Game</Filter>
</ClInclude>
<ClInclude Include="src\Anim\Elastic.h">
<Filter>src\Anim</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -935,6 +944,15 @@
<ClCompile Include="src\Scene\Water.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
<ClCompile Include="src\Global\Cooldown.cpp">
<Filter>src\Global</Filter>
</ClCompile>
<ClCompile Include="src\Anim\Orbit.cpp">
<Filter>src\Anim</Filter>
</ClCompile>
<ClCompile Include="src\Game\BaseCharacter.cpp">
<Filter>src\Game</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Lib.hlsl">

View File

@ -11,12 +11,24 @@ void Turret::Update()
if (delta <= -VERUS_PI) delta += VERUS_2PI;
if (delta >= +VERUS_PI) delta -= VERUS_2PI;
if (delta < 0)
_actualYaw -= Math::Max(_yawSpeed * dt, -delta);
_actualYaw -= Math::Min(_yawSpeed * dt, -delta);
else
_actualYaw += Math::Min(_yawSpeed * dt, delta);
_actualYaw = Math::WrapAngle(_actualYaw);
}
bool Turret::IsTargetPitchReached(float threshold) const
{
const float delta = _targetPitch - _actualPitch;
return abs(Math::WrapAngle(delta)) < threshold;
}
bool Turret::IsTargetYawReached(float threshold) const
{
const float delta = _targetYaw - _actualYaw;
return abs(Math::WrapAngle(delta)) < threshold;
}
void Turret::LookAt(RcVector3 rayFromTurret, bool instantly)
{
_targetYaw = Math::WrapAngle(atan2(

View File

@ -21,6 +21,9 @@ namespace verus
float GetActualPitch() const { return _actualPitch; }
float GetActualYaw() const { return _actualYaw; }
bool IsTargetPitchReached(float threshold) const;
bool IsTargetYawReached(float threshold) const;
// Speed:
float GetPitchSpeed() const { return _pitchSpeed; }
float GetYawSpeed() const { return _yawSpeed; }

View File

@ -1,10 +1,11 @@
#pragma once
#include "Damping.h"
#include "Elastic.h"
#include "Motion.h"
#include "Skeleton.h"
#include "Animation.h"
#include "Warp.h"
#include "Orbit.h"
namespace verus
{

View File

@ -1,96 +0,0 @@
#pragma once
namespace verus
{
namespace Anim
{
//! Change value smoothly across multiple frames.
template<typename T, bool angle = false>
class Damping
{
T _target = 0;
T _actual = 0;
float _speed = 1;
float _rate = 1;
public:
Damping() { _rate = log(10.f); }
Damping(const T& x) : _target(x), _actual(x) { _rate = log(10.f); }
Damping(const T& x, float speed) : _target(x), _actual(x), _speed(speed) { _rate = log(10.f); }
void operator=(const T& x) { _target = x; }
operator const T& () const { return _actual; }
const T& GetTarget() const { return _target; }
void SetActual(const T& x) { _actual = x; }
void SetSpeed(float s) { _speed = s; }
void ForceTarget() { _actual = _target; }
void ForceTarget(const T& x) { _actual = _target = x; }
void Update()
{
if (angle)
{
VERUS_RT_ASSERT(_target >= T(-VERUS_PI) && _target < T(VERUS_PI));
VERUS_RT_ASSERT(_actual >= T(-VERUS_PI) && _actual < T(VERUS_PI));
const T d = _target - _actual;
if (d > T(VERUS_PI))
_actual += VERUS_2PI;
else if (d < T(-VERUS_PI))
_actual -= VERUS_2PI;
}
if (0 == _speed)
{
_actual = _target;
}
else
{
VERUS_QREF_TIMER;
const float ratio = 1 / exp(_speed * dt * _rate);
_actual = Math::Lerp(_target, _actual, ratio);
if (angle)
_actual = Math::WrapAngle(_actual);
}
}
};
//! See Damping.
template<>
class Damping<Point3, false>
{
typedef Point3 T;
T _target = 0;
T _actual = 0;
float _speed = 1;
float _rate = 1;
public:
Damping() { _rate = log(10.f); }
Damping(const T& x) : _target(x), _actual(x) { _rate = log(10.f); }
Damping(const T& x, float speed) : _target(x), _actual(x), _speed(speed) { _rate = log(10.f); }
void operator=(const T& x) { _target = x; }
operator const T& () const { return _actual; }
const T& GetTarget() const { return _target; }
void SetActual(const T& x) { _actual = x; }
void SetSpeed(float s) { _speed = s; }
void ForceTarget() { _actual = _target; }
void ForceTarget(const T& x) { _actual = _target = x; }
void Update()
{
if (0 == _speed)
{
_actual = _target;
}
else
{
VERUS_QREF_TIMER;
const float ratio = 1 / exp(_speed * dt * _rate);
_actual = VMath::lerp(ratio, _target, _actual);
}
}
};
}
}

134
Verus/src/Anim/Elastic.h Normal file
View File

@ -0,0 +1,134 @@
#pragma once
namespace verus
{
namespace Anim
{
template<typename T, bool angle = false>
class Elastic
{
T _target = 0;
T _actual = 0;
float _speed = 1;
float _rate = 1;
public:
Elastic() { _rate = log(10.f); }
Elastic(const T& x) : _target(x), _actual(x) { _rate = log(10.f); }
Elastic(const T& x, float speed) : _target(x), _actual(x), _speed(speed) { _rate = log(10.f); }
void operator=(const T& x) { _target = x; }
operator const T& () const { return _actual; }
const T& GetTarget() const { return _target; }
void SetActual(const T& x) { _actual = x; }
void SetSpeed(float s) { _speed = s; }
void ForceTarget() { _actual = _target; }
void ForceTarget(const T& x) { _actual = _target = x; }
float GetDelta() const { return angle ? Math::WrapAngle(_target - _actual) : _target - _actual; }
void Update()
{
const T d = _target - _actual;
if (angle)
{
VERUS_RT_ASSERT(_target >= T(-VERUS_PI) && _target < T(VERUS_PI));
VERUS_RT_ASSERT(_actual >= T(-VERUS_PI) && _actual < T(VERUS_PI));
if (d > T(VERUS_PI))
_actual += VERUS_2PI;
else if (d < T(-VERUS_PI))
_actual -= VERUS_2PI;
}
if (abs(d) < VERUS_FLOAT_THRESHOLD)
{
_actual = _target;
}
else
{
VERUS_QREF_TIMER;
const float ratio = 1 / exp(_speed * dt * _rate); // Exponential decay.
_actual = Math::Lerp(_target, _actual, ratio);
if (angle)
_actual = Math::WrapAngle(_actual);
}
}
};
template<>
class Elastic<Vector3, false>
{
typedef Vector3 T;
T _target = 0;
T _actual = 0;
float _speed = 1;
float _rate = 1;
public:
Elastic() { _rate = log(10.f); }
Elastic(const T& x) : _target(x), _actual(x) { _rate = log(10.f); }
Elastic(const T& x, float speed) : _target(x), _actual(x), _speed(speed) { _rate = log(10.f); }
void operator=(const T& x) { _target = x; }
operator const T& () const { return _actual; }
const T& GetTarget() const { return _target; }
void SetActual(const T& x) { _actual = x; }
void SetSpeed(float s) { _speed = s; }
void ForceTarget() { _actual = _target; }
void ForceTarget(const T& x) { _actual = _target = x; }
void Update()
{
const Vector3 d = _target - _actual;
if (VMath::dot(d, d) < VERUS_FLOAT_THRESHOLD * VERUS_FLOAT_THRESHOLD)
{
_actual = _target;
}
else
{
VERUS_QREF_TIMER;
const float ratio = 1 / exp(_speed * dt * _rate); // Exponential decay.
_actual = VMath::lerp(ratio, _target, _actual);
}
}
};
template<>
class Elastic<Point3, false>
{
typedef Point3 T;
T _target = 0;
T _actual = 0;
float _speed = 1;
float _rate = 1;
public:
Elastic() { _rate = log(10.f); }
Elastic(const T& x) : _target(x), _actual(x) { _rate = log(10.f); }
Elastic(const T& x, float speed) : _target(x), _actual(x), _speed(speed) { _rate = log(10.f); }
void operator=(const T& x) { _target = x; }
operator const T& () const { return _actual; }
const T& GetTarget() const { return _target; }
void SetActual(const T& x) { _actual = x; }
void SetSpeed(float s) { _speed = s; }
void ForceTarget() { _actual = _target; }
void ForceTarget(const T& x) { _actual = _target = x; }
void Update()
{
const Vector3 d = _target - _actual;
if (VMath::dot(d, d) < VERUS_FLOAT_THRESHOLD * VERUS_FLOAT_THRESHOLD)
{
_actual = _target;
}
else
{
VERUS_QREF_TIMER;
const float ratio = 1 / exp(_speed * dt * _rate); // Exponential decay.
_actual = VMath::lerp(ratio, _target, _actual);
}
}
};
}
}

124
Verus/src/Anim/Orbit.cpp Normal file
View File

@ -0,0 +1,124 @@
#include "verus.h"
using namespace verus;
using namespace verus::Anim;
Orbit::Orbit() :
_pitch(0, 4),
_yaw(0, 4)
{
_matrix = Matrix3::identity();
}
Orbit::~Orbit()
{
}
void Orbit::Update(bool smoothRestore)
{
VERUS_QREF_TIMER;
if (!_locked && smoothRestore)
{
const float strength = 2;
if (_yaw.GetTarget() >= 0)
{
const float deltaBase = _baseYaw;
const float delta = _yaw.GetTarget();
const float speedScaleA = Math::Clamp((deltaBase - delta) * strength, 0.5f, 1.f);
const float speedScaleB = Math::Clamp(delta * strength, 0.1f, 1.f);
const float speedScale = Math::Min(speedScaleA, speedScaleB);
_yaw = _yaw.GetTarget() - Math::Clamp(_speed * dt * speedScale, 0.f, delta);
}
else
{
const float deltaBase = -_baseYaw;
const float delta = -_yaw.GetTarget();
const float speedScaleA = Math::Clamp((deltaBase - delta) * strength, 0.5f, 1.f);
const float speedScaleB = Math::Clamp(delta * strength, 0.1f, 1.f);
const float speedScale = Math::Min(speedScaleA, speedScaleB);
_yaw = _yaw.GetTarget() + Math::Clamp(_speed * dt * speedScale, 0.f, delta);
}
if (_pitch.GetTarget() >= 0)
{
const float deltaBase = _basePitch;
const float delta = _pitch.GetTarget();
const float speedScaleA = Math::Clamp((deltaBase - delta) * strength, 0.5f, 1.f);
const float speedScaleB = Math::Clamp(delta * strength, 0.1f, 1.f);
const float speedScale = Math::Min(speedScaleA, speedScaleB);
_pitch = _pitch.GetTarget() - Math::Clamp(_speed * dt * speedScale, 0.f, delta);
}
else
{
const float deltaBase = -_basePitch;
const float delta = -_pitch.GetTarget();
const float speedScaleA = Math::Clamp((deltaBase - delta) * strength, 0.5f, 1.f);
const float speedScaleB = Math::Clamp(delta * strength, 0.1f, 1.f);
const float speedScale = Math::Min(speedScaleA, speedScaleB);
_pitch = _pitch.GetTarget() + Math::Clamp(_speed * dt * speedScale, 0.f, delta);
}
}
if (smoothRestore)
{
_pitch.Update();
_yaw.Update();
}
else
{
_pitch.ForceTarget();
_yaw.ForceTarget();
}
const Matrix3 rotPitch = Matrix3::rotationX(_pitch);
const Matrix3 rotYaw = Matrix3::rotationY(_yaw);
_matrix = rotYaw * rotPitch;
const float pitchOffsetStrength = abs(_pitch) * (2 / VERUS_PI);
const float yawOffsetStrength = abs(_yaw) * (2 / VERUS_PI);
_offsetStrength = Math::Clamp<float>(Math::Max(pitchOffsetStrength, yawOffsetStrength), 0, 1);
}
void Orbit::Lock()
{
_locked = true;
}
void Orbit::Unlock()
{
if (_locked)
{
_basePitch = _pitch.GetTarget();
_baseYaw = _yaw.GetTarget();
}
_locked = false;
}
void Orbit::AddPitch(float a)
{
if (_locked)
{
_pitch = _pitch.GetTarget() - a;
_pitch = Math::Clamp(_pitch.GetTarget(), -VERUS_PI * _maxPitch, VERUS_PI * _maxPitch);
}
}
void Orbit::AddYaw(float a)
{
if (_locked)
_yaw = Math::WrapAngle(_yaw.GetTarget() - a);
}
void Orbit::AddPitchFree(float a)
{
_pitch = _pitch.GetTarget() - a;
_pitch = Math::Clamp(_pitch.GetTarget(), -VERUS_PI * _maxPitch, VERUS_PI * _maxPitch);
_basePitch = _pitch.GetTarget();
}
void Orbit::AddYawFree(float a)
{
_yaw = Math::WrapAngle(_yaw.GetTarget() - a);
_baseYaw = _yaw.GetTarget();
}

43
Verus/src/Anim/Orbit.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
namespace verus
{
namespace Anim
{
class Orbit
{
Matrix3 _matrix;
Elastic<float, true> _pitch;
Elastic<float, true> _yaw;
float _basePitch = 0;
float _baseYaw = 0;
float _speed = 1;
float _offsetStrength = 0;
float _maxPitch = 0.45f;
bool _locked = false;
public:
Orbit();
~Orbit();
void Update(bool smoothRestore = true);
void Lock();
void Unlock();
bool IsLocked() const { return _locked; }
void AddPitch(float a);
void AddYaw(float a);
void AddPitchFree(float a);
void AddYawFree(float a);
RcMatrix3 GetMatrix() const { return _matrix; }
float GetOffsetStrength() const { return _offsetStrength; }
void SetSpeed(float x) { _speed = x; }
void SetMaxPitch(float a) { _maxPitch = a; }
};
VERUS_TYPEDEFS(Orbit);
}
}

View File

@ -49,7 +49,9 @@ void Warp::Update(RSkeleton skeleton)
zone._off *= zone._maxOffset;
}
const Vector3 force = -zone._off * (zone._spring * 100) - zone._vel * zone._damping;
// Damped harmonic oscillator:
const float k = zone._spring * 100; // Stiffness.
const Vector3 force = -zone._off * k - zone._vel * zone._damping; // Hooke's law.
zone._vel += force * dt;
zone._off += zone._vel * dt;

View File

@ -38,6 +38,7 @@ void Settings::Load()
_sceneWaterQuality = static_cast<WaterQuality>(GetI("sceneWaterQuality", +_sceneWaterQuality));
_screenAllowHighDPI = GetB("screenAllowHighDPI", _screenAllowHighDPI);
_screenFOV = GetF("screenFOV", _screenFOV);
_screenOffscreenDraw = GetF("screenOffscreenDraw", _screenOffscreenDraw);
_screenSizeHeight = GetI("screenSizeHeight", _screenSizeHeight);
_screenSizeWidth = GetI("screenSizeWidth", _screenSizeWidth);
_screenVSync = GetB("screenVSync", _screenVSync);
@ -81,6 +82,7 @@ void Settings::Save()
Set("sceneWaterQuality", +_sceneWaterQuality);
Set("screenAllowHighDPI", _screenAllowHighDPI);
Set("screenFOV", _screenFOV);
Set("screenOffscreenDraw", _screenOffscreenDraw);
Set("screenSizeHeight", _screenSizeHeight);
Set("screenSizeWidth", _screenSizeWidth);
Set("screenVSync", _screenVSync);
@ -150,49 +152,29 @@ void Settings::ParseCommandLineArgs(int argc, char* argv[])
void Settings::SetQuality(Quality q)
{
_quality = q;
_gpuAnisotropyLevel = 0;
_gpuAntialiasingLevel = 0;
_gpuTextureLodLevel = 0;
_gpuTrilinearFilter = false;
_postProcessBloom = false;
_postProcessCinema = false;
_postProcessMotionBlur = false;
_postProcessSSAO = false;
_sceneGrassDensity = 1000;
_sceneShadowQuality = ShadowQuality::multisampled;
_sceneWaterQuality = WaterQuality::distortedReflection;
_screenVSync = true;
_screenWindowed = true;
switch (q)
{
case Quality::low:
_gpuAnisotropyLevel = 0;
_gpuTrilinearFilter = false;
_sceneGrassDensity = 500;
_sceneShadowQuality = ShadowQuality::linear;
_sceneWaterQuality = WaterQuality::solidColor;
_screenSizeHeight = 600;
_screenSizeWidth = 800;
break;
case Quality::medium:
_gpuAnisotropyLevel = 4;
_screenSizeHeight = 768;
_screenSizeWidth = 1024;
break;
case Quality::high:
_gpuAnisotropyLevel = 8;
_gpuTrilinearFilter = true;
_postProcessBloom = true;
_postProcessCinema = true;
_postProcessSSAO = true;
_sceneGrassDensity = 1500;
_sceneShadowQuality = ShadowQuality::cascaded;
_sceneWaterQuality = WaterQuality::trueWavesReflection;
_screenSizeHeight = 720;
_screenSizeWidth = 1280;
break;
case Quality::ultra:
_gpuAnisotropyLevel = 16;
_gpuTrilinearFilter = true;
_postProcessBloom = true;
_postProcessCinema = true;
_postProcessMotionBlur = true;
@ -204,17 +186,6 @@ void Settings::SetQuality(Quality q)
_screenSizeWidth = 1980;
break;
}
#ifdef _WIN32
# ifndef _DEBUG
//_screenSizeHeight = GetSystemMetrics(SM_CYSCREEN);
//_screenSizeWidth = GetSystemMetrics(SM_CXSCREEN);
//_screenWindowed = false;
# endif
#else // Linux?
_gapi = 0;
_gpuForcedProfile = "arb1";
#endif
}
void Settings::MatchScreen()

View File

@ -66,7 +66,7 @@ namespace verus
int _gpuAntialiasingLevel = 0;
bool _gpuTessellation = true;
int _gpuTextureLodLevel = 0;
bool _gpuTrilinearFilter = false;
bool _gpuTrilinearFilter = true;
float _inputMouseSensitivity = 1;
bool _physicsSupportDebugDraw = false;
bool _postProcessBloom = false;
@ -78,6 +78,7 @@ namespace verus
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
bool _screenAllowHighDPI = false;
float _screenFOV = 70;
bool _screenOffscreenDraw = true;
int _screenSizeHeight = 720;
int _screenSizeWidth = 1280;
bool _screenVSync = true;

View File

@ -24,12 +24,12 @@ Window::~Window()
Done();
}
void Window::Init(RcDesc descConst)
void Window::Init(RcDesc constDesc)
{
VERUS_INIT();
VERUS_QREF_SETTINGS;
Desc desc = descConst;
Desc desc = constDesc;
if (desc._useSettings)
desc.ApplySettings();

View File

@ -97,10 +97,10 @@ namespace verus
};
VERUS_TYPEDEFS(SoundPwn);
template<int NUM>
template<int COUNT>
class SoundPwns
{
SoundPwn _sounds[NUM];
SoundPwn _sounds[COUNT];
int _prev = 0;
public:
@ -116,7 +116,7 @@ namespace verus
void Init(Sound::RcDesc desc)
{
char buffer[200];
VERUS_FOR(i, NUM)
VERUS_FOR(i, COUNT)
{
sprintf_s(buffer, desc._url, i);
Sound::Desc descs = desc;
@ -127,7 +127,7 @@ namespace verus
void Done()
{
VERUS_FOR(i, NUM)
VERUS_FOR(i, COUNT)
_sounds[i].Done();
}
@ -135,9 +135,9 @@ namespace verus
{
if (i < 0)
i = Utils::I().GetRandom().Next() & 0xFF; // Only positive.
i %= NUM;
i %= COUNT;
if (i == _prev)
i = (i + 1) % NUM;
i = (i + 1) % COUNT;
_prev = i;
return _sounds[i];
}

View File

@ -61,8 +61,8 @@ namespace verus
};
VERUS_TYPEDEFS(CommandBufferPwn);
template<int NUM>
class CommandBufferPwns : public Pwns<CommandBufferPwn, NUM>
template<int COUNT>
class CommandBufferPwns : public Pwns<CommandBufferPwn, COUNT>
{
};
}

View File

@ -57,8 +57,8 @@ namespace verus
};
VERUS_TYPEDEFS(GeometryPwn);
template<int NUM>
class GeometryPwns : public Pwns<GeometryPwn, NUM>
template<int COUNT>
class GeometryPwns : public Pwns<GeometryPwn, COUNT>
{
};
}

View File

@ -78,8 +78,8 @@ namespace verus
};
VERUS_TYPEDEFS(PipelinePwn);
template<int NUM>
class PipelinePwns : public Pwns<PipelinePwn, NUM>
template<int COUNT>
class PipelinePwns : public Pwns<PipelinePwn, COUNT>
{
};
}

View File

@ -86,8 +86,8 @@ namespace verus
};
VERUS_TYPEDEFS(ShaderPwn);
template<int NUM>
class ShaderPwns : public Pwns<ShaderPwn, NUM>
template<int COUNT>
class ShaderPwns : public Pwns<ShaderPwn, COUNT>
{
};
}

View File

@ -72,6 +72,7 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
desc._width = header._width >> lod;
desc._height = header._height >> lod;
desc._mipLevels = header._mipMapCount - lod;
desc._flags = _desc._flags;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -100,6 +101,7 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._flags = _desc._flags;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -122,6 +124,7 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._flags = _desc._flags;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -156,6 +159,7 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
desc._width = header._width;
desc._height = header._height;
desc._mipLevels = header._mipMapCount;
desc._flags = _desc._flags;
desc._pSamplerDesc = _desc._pSamplerDesc;
Init(desc);
@ -189,7 +193,6 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
{
TextureDesc desc;
desc._arrayLayers = 0;
desc._flags = TextureDesc::Flags::forceArrayTexture;
CSZ* urlsCount = urls;
while (*urlsCount)
{
@ -258,6 +261,7 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
desc._width = w;
desc._height = h;
desc._mipLevels = header._mipMapCount - lod;
desc._flags = _desc._flags | TextureDesc::Flags::forceArrayTexture;
desc._pSamplerDesc = _desc._pSamplerDesc;
if (init)
@ -358,7 +362,8 @@ void TexturePtr::Init(RcTextureDesc desc)
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(!_p);
_p = renderer->InsertTexture();
_p->SetSamplerDesc(desc._pSamplerDesc);
_p->SetLoadingFlags(desc._flags);
_p->SetLoadingSamplerDesc(desc._pSamplerDesc);
if (desc._flags & TextureDesc::Flags::sync)
{
Vector<BYTE> vData;

View File

@ -37,7 +37,8 @@ namespace verus
anyShaderResource = (1 << 4), // Will use xsReadOnly as main layout.
generateMips = (1 << 5), // Allows GenerateMips calls.
forceArrayTexture = (1 << 6), // Create array texture even if arrayLayers=1.
sync = (1 << 7)
sync = (1 << 7),
exposureMips = (1 << 8)
};
Vector4 _clearValue = Vector4(0);
@ -53,6 +54,7 @@ namespace verus
short _sampleCount = 1;
Flags _flags = Flags::none;
short _texturePart = 0;
short _readbackMip = SHRT_MAX;
TextureDesc(CSZ url = nullptr) : _url(url) {}
@ -72,6 +74,7 @@ namespace verus
Vector4 _size = Vector4(0);
String _name;
TextureDesc _desc;
UINT64 _initAtFrame = 0;
ImageLayout _mainLayout = ImageLayout::fsReadOnly;
int _part = 0;
int _bytesPerPixel = 0;
@ -99,7 +102,8 @@ namespace verus
RcVector4 GetSize() const { return _size; }
bool IsSRGB() const;
void SetSamplerDesc(PcSamplerDesc pSamplerDesc) { _desc._pSamplerDesc = pSamplerDesc; }
void SetLoadingFlags(TextureDesc::Flags flags) { _desc._flags = flags; }
void SetLoadingSamplerDesc(PcSamplerDesc pSamplerDesc) { _desc._pSamplerDesc = pSamplerDesc; }
void LoadDDS(CSZ url, int texturePart = 0);
void LoadDDS(CSZ url, RcBlob blob);
@ -108,6 +112,7 @@ namespace verus
virtual void Async_Run(CSZ url, RcBlob blob) override;
virtual void UpdateSubresource(const void* p, int mipLevel = 0, int arrayLayer = 0, BaseCommandBuffer* pCB = nullptr) = 0;
virtual bool ReadbackSubresource(void* p, BaseCommandBuffer* pCB = nullptr) = 0;
virtual void GenerateMips(BaseCommandBuffer* pCB = nullptr) = 0;
@ -139,8 +144,8 @@ namespace verus
};
VERUS_TYPEDEFS(TexturePwn);
template<int NUM>
class TexturePwns : public Pwns<TexturePwn, NUM>
template<int COUNT>
class TexturePwns : public Pwns<TexturePwn, COUNT>
{
};
}

View File

@ -43,7 +43,7 @@ void DebugDraw::Init()
_offset = 0;
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._topology = PrimitiveTopology::pointList;
_pipe[PIPE_POINTS].Init(pipeDesc);
@ -51,7 +51,7 @@ void DebugDraw::Init()
_pipe[PIPE_POINTS_NO_Z].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._topology = PrimitiveTopology::lineList;
_pipe[PIPE_LINES].Init(pipeDesc);
@ -59,7 +59,7 @@ void DebugDraw::Init()
_pipe[PIPE_LINES_NO_Z].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_SwapChainDepth());
PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._rasterizationState._polygonMode = PolygonMode::line;
pipeDesc._topology = PrimitiveTopology::triangleList;
@ -87,6 +87,13 @@ void DebugDraw::Begin(Type type, PcTransform3 pMat, bool zEnable)
_offset = 0;
}
Matrix4 matWVP;
if (sm.GetCamera())
matWVP = sm.GetCamera()->GetMatrixVP();
else
matWVP = Matrix4::identity();
s_ubDebugDraw._matWVP = pMat ? Matrix4(matWVP * *pMat).UniformBufferFormat() : matWVP.UniformBufferFormat();
PIPE pipe = PIPE_POINTS;
switch (type)
{
@ -97,19 +104,12 @@ void DebugDraw::Begin(Type type, PcTransform3 pMat, bool zEnable)
if (!zEnable)
pipe = static_cast<PIPE>(pipe + 1);
renderer.GetCommandBuffer()->BindPipeline(_pipe[pipe]);
renderer.GetCommandBuffer()->BindVertexBuffers(_geo);
Matrix4 matWVP;
if (sm.GetCamera())
matWVP = sm.GetCamera()->GetMatrixVP();
else
matWVP = Matrix4::identity();
s_ubDebugDraw._matWVP = pMat ? Matrix4(matWVP * *pMat).UniformBufferFormat() : matWVP.UniformBufferFormat();
auto cb = renderer.GetCommandBuffer();
cb->BindVertexBuffers(_geo);
cb->BindPipeline(_pipe[pipe]);
_shader->BeginBindDescriptors();
renderer.GetCommandBuffer()->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 0);
_shader->EndBindDescriptors();
}

View File

@ -60,22 +60,30 @@ void DeferredShading::Init()
});
_rphCompose = renderer->CreateRenderPass(
{
RP::Attachment("Composed", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("Composed", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly)),
RP::Subpass("Sp1").Color(
{
RP::Ref("Composed", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
RP::Ref("ComposedA", ImageLayout::colorAttachment),
RP::Ref("ComposedB", ImageLayout::colorAttachment),
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
},
{});
_rphExtraCompose = renderer->CreateRenderPass(
{
RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
},
{
RP::Dependency("Sp0", "Sp1").Mode(1)
});
RP::Subpass("Sp0").Color(
{
RP::Ref("ComposedA", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment))
},
{});
_shader[SHADER_LIGHT].Init("[Shaders]:DS.hlsl");
_shader[SHADER_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame));
@ -108,18 +116,20 @@ void DeferredShading::Init()
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_COMPOSE].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_SwapChainDepth());
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_TONE_MAPPING].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), renderer.GetShaderQuad(), "#", renderer.GetRenderPassHandle_SwapChainDepth());
PipelineDesc pipeDesc(renderer.GetGeoQuad(), renderer.GetShaderQuad(), "#", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_QUAD].Init(pipeDesc);
@ -135,7 +145,7 @@ void DeferredShading::InitGBuffers(int w, int h)
TextureDesc texDesc;
// GB0:
texDesc._clearValue = Vector4(0, 0, 0, 1);
texDesc._clearValue = Vector4(0);
texDesc._format = Format::srgbR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
@ -143,7 +153,7 @@ void DeferredShading::InitGBuffers(int w, int h)
_tex[TEX_GBUFFER_0].Init(texDesc);
// GB1:
texDesc._clearValue = Vector4(0.5f, 0.5f, 0.25f, 0.5f);
texDesc._clearValue = Vector4(0);
texDesc._format = Format::unormR10G10B10A2;
texDesc._width = w;
texDesc._height = h;
@ -151,7 +161,7 @@ void DeferredShading::InitGBuffers(int w, int h)
_tex[TEX_GBUFFER_1].Init(texDesc);
// GB2:
texDesc._clearValue = Vector4(1, 1, 1, 1);
texDesc._clearValue = Vector4(0);
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
@ -164,6 +174,8 @@ void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
VERUS_QREF_RENDERER;
_texShadowAtmo = texShadow;
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
_cshLight = _shader[SHADER_LIGHT]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
@ -195,7 +207,8 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
renderer->DeleteFramebuffer(_fbhCompose);
renderer->DeleteFramebuffer(_fbh);
_tex[TEX_COMPOSED].Done();
_tex[TEX_COMPOSED_B].Done();
_tex[TEX_COMPOSED_A].Done();
_tex[TEX_LIGHT_ACC_SPEC].Done();
_tex[TEX_LIGHT_ACC_DIFF].Done();
_tex[TEX_GBUFFER_2].Done();
@ -217,7 +230,8 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
texDesc._flags = TextureDesc::Flags::colorAttachment;
_tex[TEX_LIGHT_ACC_DIFF].Init(texDesc);
_tex[TEX_LIGHT_ACC_SPEC].Init(texDesc);
_tex[TEX_COMPOSED].Init(texDesc);
_tex[TEX_COMPOSED_A].Init(texDesc);
_tex[TEX_COMPOSED_B].Init(texDesc);
_fbh = renderer->CreateFramebuffer(_rph,
{
@ -232,7 +246,15 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
renderer.GetSwapChainHeight());
_fbhCompose = renderer->CreateFramebuffer(_rphCompose,
{
_tex[TEX_COMPOSED],
_tex[TEX_COMPOSED_A],
_tex[TEX_COMPOSED_B],
renderer.GetTexDepthStencil()
},
renderer.GetSwapChainWidth(),
renderer.GetSwapChainHeight());
_fbhExtraCompose = renderer->CreateFramebuffer(_rphExtraCompose,
{
_tex[TEX_COMPOSED_A],
renderer.GetTexDepthStencil()
},
renderer.GetSwapChainWidth(),
@ -249,10 +271,10 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
});
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_COMPOSED],
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_0],
_tex[TEX_COMPOSED_A],
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
});
@ -282,52 +304,50 @@ void DeferredShading::Draw(int gbuffer)
const float w = static_cast<float>(renderer.GetSwapChainWidth() / 2);
const float h = static_cast<float>(renderer.GetSwapChainHeight() / 2);
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_QUAD]);
renderer.GetShaderQuad()->BeginBindDescriptors();
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 0);
auto cb = renderer.GetCommandBuffer();
auto shader = renderer.GetShaderQuad();
cb->BindPipeline(_pipe[PIPE_QUAD]);
shader->BeginBindDescriptors();
cb->BindDescriptors(shader, 0);
if (-1 == gbuffer)
{
renderer.GetCommandBuffer()->SetViewport({ Vector4(0, 0, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[0]);
renderer.DrawQuad();
cb->SetViewport({ Vector4(0, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[0]);
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->SetViewport({ Vector4(w, 0, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[1]);
renderer.DrawQuad();
cb->SetViewport({ Vector4(w, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[1]);
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->SetViewport({ Vector4(0, h, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[2]);
renderer.DrawQuad();
cb->SetViewport({ Vector4(0, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[2]);
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->SetViewport({ Vector4(w, h, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[3]);
renderer.DrawQuad();
renderer.GetCommandBuffer()->SetViewport({ Vector4(0, 0, w * 2, h * 2) });
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
}
else if (-2 == gbuffer)
{
renderer.GetCommandBuffer()->SetViewport({ Vector4(0, 0, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[4]);
renderer.DrawQuad();
cb->SetViewport({ Vector4(0, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[3]);
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->SetViewport({ Vector4(w, 0, w, h) });
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[5]);
renderer.DrawQuad();
cb->SetViewport({ Vector4(w, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[4]);
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->SetViewport({ Vector4(0, 0, w * 2, h * 2) });
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
}
else
{
renderer.GetCommandBuffer()->BindDescriptors(renderer.GetShaderQuad(), 1, _cshQuad[gbuffer]);
renderer.DrawQuad();
cb->BindDescriptors(shader, 1, _cshQuad[gbuffer]);
renderer.DrawQuad(&(*cb));
}
renderer.GetShaderQuad()->EndBindDescriptors();
shader->EndBindDescriptors();
}
void DeferredShading::BeginGeometryPass(bool onlySetRT, bool spriteBaking)
@ -428,39 +448,50 @@ void DeferredShading::EndLightingPass()
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::BeginCompose(RcVector4 bgColor)
void DeferredShading::BeginCompose()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
renderer.GetCommandBuffer()->BeginRenderPass(_rphCompose, _fbhCompose,
{
_tex[TEX_COMPOSED]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_COMPOSE]);
VERUS_QREF_WATER;
const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP());
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat();
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
s_ubComposeFS._colorAmbient = float4(atmo.GetAmbientColor().GLM(), 0);
s_ubComposeFS._colorBackground = bgColor.GLM();
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
s_ubComposeFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
memcpy(&s_ubComposeFS._toneMappingConfig.x, &_toneMappingConfig, sizeof(_toneMappingConfig));
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshCompose);
s_ubComposeFS._waterDiffColorShallow = float4(water.GetDiffuseColorShallow().GLM(), water.GetFogDensity());
s_ubComposeFS._waterDiffColorDeep = float4(water.GetDiffuseColorDeep().GLM(), water.IsUnderwater() ? 1.f : 0.f);
auto cb = renderer.GetCommandBuffer();
cb->BeginRenderPass(_rphCompose, _fbhCompose,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
_tex[TEX_COMPOSED_B]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
cb->BindPipeline(_pipe[PIPE_COMPOSE]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_COMPOSE], 0);
cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshCompose);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad();
renderer.DrawQuad(&(*cb));
renderer.GetCommandBuffer()->NextSubpass();
cb->EndRenderPass();
cb->BeginRenderPass(_rphExtraCompose, _fbhExtraCompose,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
void DeferredShading::EndCompose()
@ -470,27 +501,30 @@ void DeferredShading::EndCompose()
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::ToneMapping()
void DeferredShading::ToneMapping(RcVector4 bgColor)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
renderer.GetCommandBuffer()->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixVi().UniformBufferFormat();
s_ubComposeFS._colorAmbient = float4(atmo.GetAmbientColor().GLM(), 0);
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
s_ubComposeFS._backgroundColor = bgColor.GLM();
s_ubComposeFS._fogColor = Vector4(0.5f, 0.5f, 0.5f, 0.002f).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
memcpy(&s_ubComposeFS._toneMappingConfig.x, &_toneMappingConfig, sizeof(_toneMappingConfig));
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 0);
renderer.GetCommandBuffer()->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping);
auto cb = renderer.GetCommandBuffer();
cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_COMPOSE], 0);
cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad();
renderer.DrawQuad(&(*cb));
}
void DeferredShading::AntiAliasing()
@ -586,3 +620,13 @@ TexturePtr DeferredShading::GetGBuffer(int index)
{
return _tex[index];
}
TexturePtr DeferredShading::GetComposedTextureA()
{
return _tex[TEX_COMPOSED_A];
}
TexturePtr DeferredShading::GetComposedTextureB()
{
return _tex[TEX_COMPOSED_B];
}

View File

@ -42,7 +42,8 @@ namespace verus
TEX_GBUFFER_2, // LamScale, LamBias, Metallicity, Gloss.
TEX_LIGHT_ACC_DIFF,
TEX_LIGHT_ACC_SPEC,
TEX_COMPOSED,
TEX_COMPOSED_A,
TEX_COMPOSED_B,
TEX_COUNT
};
@ -61,24 +62,19 @@ namespace verus
UINT64 _frame = 0;
RPHandle _rph;
RPHandle _rphCompose;
RPHandle _rphExtraCompose;
FBHandle _fbh;
FBHandle _fbhCompose;
FBHandle _fbhExtraCompose;
CSHandle _cshLight;
CSHandle _cshCompose;
CSHandle _cshToneMapping;
CSHandle _cshQuad[6];
CSHandle _cshQuad[5];
bool _activeGeometryPass = false;
bool _activeLightingPass = false;
bool _async_initPipe = false;
public:
struct ToneMappingConfig
{
float _exposure = 0.005f;
float _filmicLook = 0.5f;
float _albedoScale = 0.5f;
} _toneMappingConfig;
DeferredShading();
~DeferredShading();
@ -97,16 +93,15 @@ namespace verus
bool IsActiveLightingPass() const { return _activeLightingPass; }
RPHandle GetRenderPassHandle() const { return _rph; }
RPHandle GetRenderPassHandle_Compose() const { return _rphCompose; }
int GetSubpass_Compose() const { return 1; }
RPHandle GetRenderPassHandle_ExtraCompose() const { return _rphExtraCompose; }
void BeginGeometryPass(bool onlySetRT = false, bool spriteBaking = false);
void EndGeometryPass(bool resetRT = false);
bool BeginLightingPass();
void EndLightingPass();
void BeginCompose(RcVector4 bgColor = Vector4(0));
void BeginCompose();
void EndCompose();
void ToneMapping();
void ToneMapping(RcVector4 bgColor = Vector4(0));
void AntiAliasing();
static bool IsLightUrl(CSZ url);
@ -118,6 +113,9 @@ namespace verus
void Load();
TexturePtr GetGBuffer(int index);
TexturePtr GetComposedTextureA();
TexturePtr GetComposedTextureB();
};
VERUS_TYPEDEFS(DeferredShading);
}

View File

@ -13,6 +13,12 @@ Attachment::Attachment(CSZ name, Format format, int sampleCount) :
{
}
RAttachment Attachment::SetLoadOp(LoadOp op)
{
_loadOp = op;
return *this;
}
RAttachment Attachment::LoadOpClear()
{
_loadOp = LoadOp::clear;
@ -24,6 +30,12 @@ RAttachment Attachment::LoadOpDontCare() {
return *this;
}
RAttachment Attachment::SetStoreOp(StoreOp op)
{
_storeOp = op;
return *this;
}
RAttachment Attachment::StoreOpDontCare()
{
_storeOp = StoreOp::dontCare;

View File

@ -34,8 +34,10 @@ namespace verus
Attachment(CSZ name, Format format, int sampleCount = 1);
Attachment& SetLoadOp(LoadOp op);
Attachment& LoadOpClear();
Attachment& LoadOpDontCare();
Attachment& SetStoreOp(StoreOp op);
Attachment& StoreOpDontCare();
Attachment& Layout(ImageLayout whenBegins, ImageLayout whenEnds);
Attachment& Layout(ImageLayout both);

View File

@ -52,17 +52,40 @@ void Renderer::Init(PRendererDelegate pDelegate)
_commandBuffer.Init();
// Draw directly to swap chain buffer:
const RP::Attachment::LoadOp loadOp = settings._screenOffscreenDraw ? RP::Attachment::LoadOp::dontCare : RP::Attachment::LoadOp::clear;
_rphSwapChain = _pBaseRenderer->CreateRenderPass(
{
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::undefined, ImageLayout::presentSrc)
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(loadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc)
},
{
RP::Subpass("Sp0").Color({RP::Ref("Color", ImageLayout::colorAttachment)})
},
{});
_rphSwapChainDepth = _pBaseRenderer->CreateRenderPass(
_rphSwapChainWithDepth = _pBaseRenderer->CreateRenderPass(
{
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::undefined, ImageLayout::presentSrc),
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(loadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("Color", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
},
{});
// Draw to offscreen buffer, then later to swap chain buffer:
_rphOffscreen = _pBaseRenderer->CreateRenderPass(
{
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly, ImageLayout::fsReadOnly)
},
{
RP::Subpass("Sp0").Color({RP::Ref("Color", ImageLayout::colorAttachment)})
},
{});
_rphOffscreenWithDepth = _pBaseRenderer->CreateRenderPass(
{
RP::Attachment("Color", Format::srgbB8G8R8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly, ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
},
{
@ -84,8 +107,8 @@ void Renderer::Init(PRendererDelegate pDelegate)
geoDesc._pStrides = strides;
_geoQuad.Init(geoDesc);
_shader[S_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
_shader[S_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), 100,
_shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
_shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), 100,
{
Sampler::linearClampMipN,
Sampler::storage,
@ -94,22 +117,37 @@ void Renderer::Init(PRendererDelegate pDelegate)
Sampler::storage
},
ShaderStageFlags::cs);
_shader[S_GENERATE_MIPS]->CreatePipelineLayout();
_shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout();
_shader[S_QUAD].Init("[Shaders]:Quad.hlsl");
_shader[S_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), 100, {}, ShaderStageFlags::vs);
_shader[S_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), 100, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
_shader[S_QUAD]->CreatePipelineLayout();
_shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl");
_shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), 100, {}, ShaderStageFlags::vs);
_shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), 100, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
_shader[SHADER_QUAD]->CreatePipelineLayout();
PipelineDesc pipeDesc(_shader[S_GENERATE_MIPS], "#");
_pipeGenerateMips.Init(pipeDesc);
{
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#");
_pipe[PIPE_GENERATE_MIPS].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#Exposure");
_pipe[PIPE_GENERATE_MIPS_EXPOSURE].Init(pipeDesc);
}
if (App::Settings::I()._screenOffscreenDraw)
{
PipelineDesc pipeDesc(_geoQuad, _shader[SHADER_QUAD], "#", _rphSwapChainWithDepth);
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc._depthTestEnable = false;
_pipe[PIPE_OFFSCREEN_COLOR].Init(pipeDesc);
}
OnSwapChainResized(true, false);
_pBaseRenderer->ImGuiInit(_rphSwapChainDepth);
_pBaseRenderer->ImGuiInit(_rphSwapChainWithDepth);
ImGuiUpdateStyle();
_ds.Init();
SetExposureValue(15);
}
void Renderer::InitCmd()
@ -131,8 +169,8 @@ void Renderer::Done()
{
_pBaseRenderer->WaitIdle();
_ds.Done();
_texDepthStencil.Done();
_pipeGenerateMips.Done();
_tex.Done();
_pipe.Done();
_shader.Done();
_geoQuad.Done();
_commandBuffer.Done();
@ -150,6 +188,37 @@ void Renderer::Done()
VERUS_DONE(Renderer);
}
void Renderer::Update()
{
VERUS_QREF_TIMER;
UINT32 color = VERUS_COLOR_RGBA(127, 127, 127, 255);
if (_autoExposure && _tex[TEX_OFFSCREEN_COLOR]->ReadbackSubresource(&color))
{
float floatColor[4];
Convert::ColorInt32ToFloat(color, floatColor);
const glm::vec3 glmColor(floatColor[2], floatColor[1], floatColor[0]);
const glm::vec3 gray = glm::saturation(0.f, glmColor);
const float alpha = Math::Max(0.001f, floatColor[3]);
const float actual = gray.r;
const float expScale = Math::Clamp(_exposure[1] * (1 / 15.f), 0.f, 1.f);
const float target = -0.4f + 0.8f * expScale * expScale; // Dark scene exposure compensation.
const float important = (actual - 0.5f * (1 - alpha)) / alpha;
const float delta = abs(target - important);
const float speed = delta * sqrt(delta) * 50;
if (important < target * 0.95f)
_exposure[1] -= speed * dt;
else if (important > target * (1 / 0.95f))
_exposure[1] += speed * dt;
_exposure[1] = Math::Clamp(_exposure[1], 0.f, 15.f);
SetExposureValue(_exposure[1]);
}
}
void Renderer::Draw()
{
if (_pRendererDelegate)
@ -176,36 +245,63 @@ void Renderer::OnWindowResized(int w, int h)
OnSwapChainResized(true, true);
_ds.OnSwapChainResized(true, true);
Scene::Water::I().OnSwapChainResized();
}
void Renderer::OnSwapChainResized(bool init, bool done)
{
if (done)
{
VERUS_FOR(i, _fbhSwapChainDepth.size())
_pBaseRenderer->DeleteFramebuffer(_fbhSwapChainDepth[i]);
_shader[SHADER_QUAD]->FreeDescriptorSet(_cshOffscreenColor);
_pBaseRenderer->DeleteFramebuffer(_fbhOffscreenWithDepth);
_pBaseRenderer->DeleteFramebuffer(_fbhOffscreen);
VERUS_FOR(i, _fbhSwapChainWithDepth.size())
_pBaseRenderer->DeleteFramebuffer(_fbhSwapChainWithDepth[i]);
VERUS_FOR(i, _fbhSwapChain.size())
_pBaseRenderer->DeleteFramebuffer(_fbhSwapChain[i]);
_texDepthStencil.Done();
_tex.Done();
}
if (init)
{
VERUS_QREF_CONST_SETTINGS;
TextureDesc texDesc;
if (settings._screenOffscreenDraw)
{
texDesc._format = Format::srgbB8G8R8A8;
texDesc._width = _swapChainWidth;
texDesc._height = _swapChainHeight;
texDesc._mipLevels = 0;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::generateMips | TextureDesc::Flags::exposureMips;
texDesc._readbackMip = -1;
_tex[TEX_OFFSCREEN_COLOR].Init(texDesc);
}
texDesc.Reset();
texDesc._clearValue = Vector4(1);
texDesc._format = Format::unormD24uintS8;
texDesc._width = _swapChainWidth;
texDesc._height = _swapChainHeight;
texDesc._flags = TextureDesc::Flags::inputAttachment | TextureDesc::Flags::depthSampledW;
_texDepthStencil.Init(texDesc);
_tex[TEX_DEPTH_STENCIL].Init(texDesc);
_fbhSwapChain.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbhSwapChain.size())
_fbhSwapChain[i] = _pBaseRenderer->CreateFramebuffer(_rphSwapChain, {}, _swapChainWidth, _swapChainHeight, i);
_fbhSwapChainDepth.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbhSwapChainDepth.size())
_fbhSwapChainDepth[i] = _pBaseRenderer->CreateFramebuffer(_rphSwapChainDepth, { _texDepthStencil }, _swapChainWidth, _swapChainHeight, i);
_fbhSwapChainWithDepth.resize(_pBaseRenderer->GetSwapChainBufferCount());
VERUS_FOR(i, _fbhSwapChainWithDepth.size())
_fbhSwapChainWithDepth[i] = _pBaseRenderer->CreateFramebuffer(_rphSwapChainWithDepth, { _tex[TEX_DEPTH_STENCIL] }, _swapChainWidth, _swapChainHeight, i);
if (settings._screenOffscreenDraw)
{
_fbhOffscreen = _pBaseRenderer->CreateFramebuffer(_rphSwapChain, { _tex[TEX_OFFSCREEN_COLOR] }, _swapChainWidth, _swapChainHeight);
_fbhOffscreenWithDepth = _pBaseRenderer->CreateFramebuffer(_rphSwapChainWithDepth, { _tex[TEX_OFFSCREEN_COLOR], _tex[TEX_DEPTH_STENCIL] }, _swapChainWidth, _swapChainHeight);
_cshOffscreenColor = _shader[SHADER_QUAD]->BindDescriptorSetTextures(1, { _tex[TEX_OFFSCREEN_COLOR] });
}
}
}
@ -217,6 +313,56 @@ void Renderer::DrawQuad(PBaseCommandBuffer pCB)
pCB->Draw(4, 1);
}
void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass)
{
if (!App::Settings::I()._screenOffscreenDraw)
return;
if (!pCB)
pCB = &(*_commandBuffer);
_tex[TEX_OFFSCREEN_COLOR]->GenerateMips();
_ubQuadVS._matW = Math::QuadMatrix().UniformBufferFormat();
_ubQuadVS._matV = Math::ToUVMatrix().UniformBufferFormat();
pCB->BeginRenderPass(_rphSwapChainWithDepth, _fbhSwapChainWithDepth[_pBaseRenderer->GetSwapChainBufferIndex()], { Vector4(0), Vector4(1) });
pCB->BindVertexBuffers(_geoQuad);
pCB->BindPipeline(_pipe[PIPE_OFFSCREEN_COLOR]);
_shader[SHADER_QUAD]->BeginBindDescriptors();
pCB->BindDescriptors(_shader[SHADER_QUAD], 0);
pCB->BindDescriptors(_shader[SHADER_QUAD], 1, _cshOffscreenColor);
_shader[SHADER_QUAD]->EndBindDescriptors();
pCB->Draw(4, 1);
if (endRenderPass)
pCB->EndRenderPass();
}
void Renderer::DrawOffscreenColorSwitchRenderPass(PBaseCommandBuffer pCB)
{
if (!App::Settings::I()._screenOffscreenDraw)
return;
if (!pCB)
pCB = &(*_commandBuffer);
pCB->EndRenderPass();
DrawOffscreenColor(pCB, false);
}
TexturePtr Renderer::GetTexOffscreenColor() const
{
return _tex[TEX_OFFSCREEN_COLOR];
}
TexturePtr Renderer::GetTexDepthStencil() const
{
return _tex[TEX_DEPTH_STENCIL];
}
void Renderer::OnShaderError(CSZ s)
{
throw VERUS_RUNTIME_ERROR << "Shader Error:\n" << s;
@ -328,3 +474,104 @@ void Renderer::ImGuiUpdateStyle()
if (settings._screenAllowHighDPI)
style.ScaleAllSizes(settings._highDpiScale);
}
RPHandle Renderer::GetRenderPassHandle_SwapChain() const
{
return _rphSwapChain;
}
RPHandle Renderer::GetRenderPassHandle_SwapChainWithDepth() const
{
return _rphSwapChainWithDepth;
}
RPHandle Renderer::GetRenderPassHandle_Offscreen() const
{
return _rphOffscreen;
}
RPHandle Renderer::GetRenderPassHandle_OffscreenWithDepth() const
{
return _rphOffscreenWithDepth;
}
RPHandle Renderer::GetRenderPassHandle_Auto() const
{
return App::Settings::I()._screenOffscreenDraw ? _rphOffscreen : _rphSwapChain;
}
RPHandle Renderer::GetRenderPassHandle_AutoWithDepth() const
{
return App::Settings::I()._screenOffscreenDraw ? _rphOffscreenWithDepth : _rphSwapChainWithDepth;
}
FBHandle Renderer::GetFramebufferHandle_SwapChain(int index) const
{
return _fbhSwapChain[index];
}
FBHandle Renderer::GetFramebufferHandle_SwapChainWithDepth(int index) const
{
return _fbhSwapChainWithDepth[index];
}
FBHandle Renderer::GetFramebufferHandle_Offscreen(int index) const
{
return _fbhOffscreen;
}
FBHandle Renderer::GetFramebufferHandle_OffscreenWithDepth(int index) const
{
return _fbhOffscreenWithDepth;
}
FBHandle Renderer::GetFramebufferHandle_Auto(int index) const
{
return App::Settings::I()._screenOffscreenDraw ? _fbhOffscreen : _fbhSwapChain[index];
}
FBHandle Renderer::GetFramebufferHandle_AutoWithDepth(int index) const
{
return App::Settings::I()._screenOffscreenDraw ? _fbhOffscreenWithDepth : _fbhSwapChainWithDepth[index];
}
ShaderPtr Renderer::GetShaderGenerateMips() const
{
return _shader[SHADER_GENERATE_MIPS];
}
PipelinePtr Renderer::GetPipelineGenerateMips(bool exposure) const
{
return _pipe[exposure ? PIPE_GENERATE_MIPS_EXPOSURE : PIPE_GENERATE_MIPS];
}
Renderer::UB_GenerateMips& Renderer::GetUbGenerateMips()
{
return _ubGenerateMips;
}
GeometryPtr Renderer::GetGeoQuad() const
{
return _geoQuad;
}
ShaderPtr Renderer::GetShaderQuad() const
{
return _shader[SHADER_QUAD];
}
Renderer::UB_QuadVS& Renderer::GetUbQuadVS()
{
return _ubQuadVS;
}
Renderer::UB_QuadFS& Renderer::GetUbQuadFS()
{
return _ubQuadFS;
}
void Renderer::SetExposureValue(float ev)
{
_exposure[1] = ev;
_exposure[0] = 1.f / exp2(_exposure[1] - 1);
}

View File

@ -18,11 +18,26 @@ namespace verus
#include "../Shaders/GenerateMips.inc.hlsl"
#include "../Shaders/Quad.inc.hlsl"
enum S
enum SHADER
{
S_GENERATE_MIPS,
S_QUAD,
S_MAX
SHADER_GENERATE_MIPS,
SHADER_QUAD,
SHADER_COUNT
};
enum PIPE
{
PIPE_GENERATE_MIPS,
PIPE_GENERATE_MIPS_EXPOSURE,
PIPE_OFFSCREEN_COLOR,
PIPE_COUNT
};
enum TEX
{
TEX_OFFSCREEN_COLOR,
TEX_DEPTH_STENCIL,
TEX_COUNT
};
struct Vertex
@ -30,27 +45,34 @@ namespace verus
glm::vec2 _pos;
};
App::PWindow _pMainWindow = nullptr;
PBaseRenderer _pBaseRenderer = nullptr;
PRendererDelegate _pRendererDelegate = nullptr;
CommandBufferPwn _commandBuffer;
GeometryPwn _geoQuad;
ShaderPwns<S_MAX> _shader;
PipelinePwn _pipeGenerateMips;
TexturePwn _texDepthStencil;
DeferredShading _ds;
UINT64 _frameCount = 0;
Gapi _gapi = Gapi::unknown;
int _swapChainWidth = 0;
int _swapChainHeight = 0;
float _fps = 30;
RPHandle _rphSwapChain;
RPHandle _rphSwapChainDepth;
Vector<FBHandle> _fbhSwapChain;
Vector<FBHandle> _fbhSwapChainDepth;
UB_GenerateMips _ubGenerateMips;
UB_QuadVS _ubQuadVS;
UB_QuadFS _ubQuadFS;
App::PWindow _pMainWindow = nullptr;
PBaseRenderer _pBaseRenderer = nullptr;
PRendererDelegate _pRendererDelegate = nullptr;
CommandBufferPwn _commandBuffer;
GeometryPwn _geoQuad;
ShaderPwns<SHADER_COUNT> _shader;
PipelinePwns<PIPE_COUNT> _pipe;
TexturePwns<TEX_COUNT> _tex;
DeferredShading _ds;
UINT64 _frameCount = 0;
Gapi _gapi = Gapi::unknown;
int _swapChainWidth = 0;
int _swapChainHeight = 0;
float _fps = 30;
float _exposure[2] = {}; // Linear and EV.
RPHandle _rphSwapChain;
RPHandle _rphSwapChainWithDepth;
Vector<FBHandle> _fbhSwapChain;
Vector<FBHandle> _fbhSwapChainWithDepth;
RPHandle _rphOffscreen;
RPHandle _rphOffscreenWithDepth;
FBHandle _fbhOffscreen;
FBHandle _fbhOffscreenWithDepth;
CSHandle _cshOffscreenColor;
UB_GenerateMips _ubGenerateMips;
UB_QuadVS _ubQuadVS;
UB_QuadFS _ubQuadFS;
bool _autoExposure = true;
public:
Renderer();
@ -65,6 +87,7 @@ namespace verus
void Done();
// Frame cycle:
void Update();
void Draw();
void Present();
@ -75,10 +98,13 @@ namespace verus
// Simple (fullscreen) quad:
void DrawQuad(PBaseCommandBuffer pCB = nullptr);
void DrawOffscreenColor(PBaseCommandBuffer pCB = nullptr, bool endRenderPass = true);
void DrawOffscreenColorSwitchRenderPass(PBaseCommandBuffer pCB = nullptr);
RDeferredShading GetDS() { return _ds; }
CommandBufferPtr GetCommandBuffer() const { return _commandBuffer; }
TexturePtr GetTexDepthStencil() const { return _texDepthStencil; }
TexturePtr GetTexOffscreenColor() const;
TexturePtr GetTexDepthStencil() const;
void OnShaderError(CSZ s);
void OnShaderWarning(CSZ s);
@ -97,21 +123,36 @@ namespace verus
UINT64 GetFrameCount() const { return _frameCount; }
// RenderPass & Framebuffer:
RPHandle GetRenderPassHandle_SwapChain() const { return _rphSwapChain; }
RPHandle GetRenderPassHandle_SwapChainDepth() const { return _rphSwapChainDepth; }
FBHandle GetFramebufferHandle_SwapChain(int index) const { return _fbhSwapChain[index]; }
FBHandle GetFramebufferHandle_SwapChainDepth(int index) const { return _fbhSwapChainDepth[index]; }
RPHandle GetRenderPassHandle_SwapChain() const;
RPHandle GetRenderPassHandle_SwapChainWithDepth() const;
RPHandle GetRenderPassHandle_Offscreen() const;
RPHandle GetRenderPassHandle_OffscreenWithDepth() const;
RPHandle GetRenderPassHandle_Auto() const;
RPHandle GetRenderPassHandle_AutoWithDepth() const;
FBHandle GetFramebufferHandle_SwapChain(int index) const;
FBHandle GetFramebufferHandle_SwapChainWithDepth(int index) const;
FBHandle GetFramebufferHandle_Offscreen(int index) const;
FBHandle GetFramebufferHandle_OffscreenWithDepth(int index) const;
FBHandle GetFramebufferHandle_Auto(int index) const;
FBHandle GetFramebufferHandle_AutoWithDepth(int index) const;
// Generate mips:
PipelinePtr GetPipelineGenerateMips() { return _pipeGenerateMips; }
ShaderPtr GetShaderGenerateMips() { return _shader[S_GENERATE_MIPS]; }
UB_GenerateMips& GetUbGenerateMips() { return _ubGenerateMips; }
ShaderPtr GetShaderGenerateMips() const;
PipelinePtr GetPipelineGenerateMips(bool exposure = false) const;
UB_GenerateMips& GetUbGenerateMips();
// Quad:
GeometryPtr GetGeoQuad() const { return _geoQuad; }
ShaderPtr GetShaderQuad() { return _shader[S_QUAD]; }
UB_QuadVS& GetUbQuadVS() { return _ubQuadVS; }
UB_QuadFS& GetUbQuadFS() { return _ubQuadFS; }
GeometryPtr GetGeoQuad() const;
ShaderPtr GetShaderQuad() const;
UB_QuadVS& GetUbQuadVS();
UB_QuadFS& GetUbQuadFS();
// Exposure:
bool IsAutoExposureEnabled() const { return _autoExposure; }
void EnableAutoExposure(bool b = true) { _autoExposure = b; }
float GetExposure() const { return _exposure[0]; }
float GetExposureValue() const { return _exposure[1]; }
void SetExposureValue(float ev);
};
VERUS_TYPEDEFS(Renderer);
}

View File

@ -42,6 +42,13 @@ void TextureRAM::UpdateSubresource(const void* p, int mipLevel, int arrayLayer,
memcpy(_vBuffer.data(), p, _vBuffer.size());
}
bool TextureRAM::ReadbackSubresource(void* p, PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(IsLoaded());
memcpy(p, _vBuffer.data(), _vBuffer.size());
return true;
}
void TextureRAM::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(__FUNCTION__);

View File

@ -16,6 +16,7 @@ namespace verus
virtual void Done() override;
virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override;
virtual bool ReadbackSubresource(void* p, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;

View File

@ -123,6 +123,7 @@ namespace verus
input,
shadow,
aniso, // Most common sampler for 3D.
anisoClamp,
linearMipL,
nearestMipL,
linearMipN,

View File

@ -0,0 +1,352 @@
#include "verus.h"
using namespace verus;
using namespace verus::Game;
BaseCharacter::BaseCharacter() :
_fallSpeed(0, 5)
{
_cameraRadius.Set(_maxCameraRadius, 3);
_cameraRadius.SetLimits(_minCameraRadius, _maxCameraRadius);
}
BaseCharacter::~BaseCharacter()
{
EndRagdoll();
DoneController();
}
void BaseCharacter::HandleInput()
{
VERUS_QREF_TIMER;
if (_accel)
{
// Normalize move vector:
_moveLen = VMath::length(_move);
if (_moveLen >= VERUS_FLOAT_THRESHOLD)
_move /= _moveLen;
if (_airborne) // Move command from user.
_velocity += _move * (dt * _accel * _airborneControl);
else
_velocity += _move * (dt * _accel);
// 2D motion rules (on the ground):
if (!_airborne)
{
Vector3 velocity2D = _velocity;
velocity2D.setY(0);
const float speed2D = VMath::length(velocity2D);
if (speed2D > _maxSpeed) // Too fast?
{
velocity2D /= speed2D;
velocity2D *= _maxSpeed;
}
else if (speed2D < VERUS_FLOAT_THRESHOLD) // Too slow slowpoke.jpg?
{
velocity2D = Vector3(0);
}
_velocity = velocity2D;
}
// Extra force:
_velocity += _extraForce * dt;
_extraForce = Vector3(0);
_move = _velocity;
}
else // No accel:
{
_velocity = _move;
}
// At this point _move == _velocity.
_cc.Move(_move);
}
void BaseCharacter::Update()
{
VERUS_QREF_TIMER;
_pitch.Update();
_yaw.Update();
// <Position>
_prevPosition = _position;
_smoothPrevPosition = _smoothPosition;
if (_ragdoll)
{
// Do nothing.
}
else if (_cc.IsInitialized())
{
_position = _cc.GetPosition();
_airborne = !_cc.GetKCC()->onGround();
}
else
{
_position += _velocity * dt;
_airborne = true;
}
_smoothPosition = _position;
_smoothPosition.Update();
// </Position>
// <Fall>
if (_airborne)
{
const float h0 = _prevPosition.getY();
const float h1 = _position.getY();
_fallSpeed = (h0 - h1) * timer.GetDeltaTimeInv();
}
else
{
BaseCharacter_OnFallImpact(_fallSpeed);
_fallSpeed.ForceTarget(0);
}
_fallSpeed.Update();
// </Fall>
_speed = VMath::dist(_smoothPosition, _smoothPrevPosition) * timer.GetDeltaTimeInv();
_smoothSpeed = _speed;
_smoothSpeed.Update();
_smoothSpeedOnGround = _airborne ? 0.f : _speed;
_smoothSpeedOnGround.Update();
// <Friction>
if (_decel && _moveLen < VERUS_FLOAT_THRESHOLD)
{
if (_airborne)
{
// No friction in the air.
}
else
{
float speed = VMath::length(_velocity);
if (speed >= VERUS_FLOAT_THRESHOLD)
{
const Vector3 dir = _velocity / speed;
speed = Math::Reduce(speed, _decel * dt);
_velocity = dir * speed;
}
}
}
// </Friction>
_move = Vector3(0);
ComputeDerivedVars(_smoothSpeedOnGround);
_cameraRadius.UpdateClamped(dt);
}
void BaseCharacter::InitController()
{
if (!_cc.IsInitialized())
{
Physics::CharacterController::Desc desc;
desc._radius = _idleRadius;
desc._height = _idleHeight;
desc._stepHeight = _stepHeight;
_cc.Init(_position, desc);
_cc.GetKCC()->setJumpSpeed(_jumpSpeed);
#ifdef _DEBUG
_cc.Visualize(true);
#endif
}
}
void BaseCharacter::DoneController()
{
_position = GetPosition();
_cc.Done();
}
void BaseCharacter::MoveTo(RcPoint3 pos)
{
Spirit::MoveTo(pos);
_fallSpeed.ForceTarget(0);
if (_cc.IsInitialized())
_cc.MoveTo(_position);
}
bool BaseCharacter::IsOnGround() const
{
if (_cc.IsInitialized())
return _cc.GetKCC()->onGround();
return false;
}
bool BaseCharacter::TryJump(bool whileAirborne)
{
if ((!_airborne || whileAirborne) && _jumpCooldown.IsFinished())
{
BaseCharacter_OnJump();
return true;
}
return false;
}
void BaseCharacter::Jump()
{
if (_cc.IsInitialized())
{
_jumpCooldown.Start();
_cc.GetKCC()->jump();
}
}
void BaseCharacter::SetJumpSpeed(float v)
{
_jumpSpeed = v;
if (_cc.IsInitialized())
_cc.GetKCC()->setJumpSpeed(_jumpSpeed);
}
bool BaseCharacter::IsStuck()
{
VERUS_QREF_TIMER;
if (!_unstuckCooldown.IsFinished())
return false;
const float desiredSpeedSq = VMath::lengthSqr(_velocity);
const bool stuck = (desiredSpeedSq >= 1) && (_speed * _speed * 10 < desiredSpeedSq);
if (stuck)
_unstuckCooldown.Start();
return stuck;
}
void BaseCharacter::ToggleRagdoll()
{
if (_ragdoll)
EndRagdoll();
else
BeginRagdoll();
}
void BaseCharacter::BeginRagdoll()
{
if (_ragdoll)
return;
_ragdoll = true;
BaseCharacter_OnInitRagdoll(GetMatrix());
_velocity = Vector3(0);
_move = Vector3(0);
_extraForce = Vector3(0);
DoneController();
}
void BaseCharacter::EndRagdoll()
{
if (!_ragdoll)
return;
_ragdoll = false;
BaseCharacter_OnDoneRagdoll();
InitController();
}
void BaseCharacter::ComputeThirdPersonAim(RPoint3 aimPos, RVector3 aimDir, RcVector3 offset)
{
VERUS_QREF_SM;
const float r = 0.1f;
Point3 point;
Vector3 norm;
// From unit's origin to it's head:
const Point3 pos = _smoothPosition;
const float startAt = _cc.GetRadius() + _cc.GetHeight() * 0.5f;
Point3 origin = pos + Vector3(0, startAt, 0);
Point3 at = pos + GetYawMatrix() * offset;
if (sm.RayCastingTest(origin, at, nullptr, &point, &norm, &r))
at = point + norm * r;
Point3 eye = at - GetFrontDirection() * _cameraRadius.GetValue();
if (sm.RayCastingTest(at, eye, nullptr, &point, &norm, &r)) // Hitting the wall?
{
eye = point + norm * r;
}
else // No collision?
{
}
if (VMath::distSqr(at, eye) < r * r) // Extremely close?
{
eye = at - GetFrontDirection() * r;
}
aimPos = eye;
aimDir = VMath::normalizeApprox(at - eye);
}
void BaseCharacter::ComputeThirdPersonCameraArgs(RcVector3 offset, RPoint3 eye, RPoint3 at)
{
VERUS_QREF_SM;
const float r = 0.1f;
Point3 point;
Vector3 norm;
const Point3 pos = _smoothPosition;
const float startAt = _cc.GetRadius() + _cc.GetHeight() * 0.5f; // Inside capsule.
const Point3 origin = pos + Vector3(0, startAt, 0);
at = pos + GetYawMatrix() * offset;
if (sm.RayCastingTest(origin, at, nullptr, &point, &norm, &r))
at = point + norm * r;
eye = at - GetFrontDirection() * _cameraRadius.GetValue();
}
float BaseCharacter::ComputeThirdPersonCamera(Scene::RCamera camera, Anim::RcOrbit orbit, RcVector3 offset)
{
VERUS_QREF_SM;
const float r = 0.1f;
Point3 point;
Vector3 norm;
Point3 eye, at;
ComputeThirdPersonCameraArgs(offset, eye, at);
Vector3 toEye = eye - at;
// Consider orientation:
Matrix3 matFromRaySpace;
matFromRaySpace.AimZ(toEye);
Matrix3 matToRaySpace = VMath::transpose(matFromRaySpace);
toEye = (matFromRaySpace * orbit.GetMatrix() * matToRaySpace) * toEye;
eye = at + Vector3(toEye);
float ret = 0;
if (sm.RayCastingTest(at, eye, nullptr, &point, &norm, &r)) // Hitting the wall?
{
eye = point + norm * r;
const float maxCameraRadius = VMath::dist(at, eye) + r;
_cameraRadius.SetLimits(_minCameraRadius, maxCameraRadius);
ret = 1 - maxCameraRadius / _maxCameraRadius;
}
else // No collision?
{
_cameraRadius.SetLimits(_minCameraRadius, _maxCameraRadius);
}
if (VMath::distSqr(at, eye) < r * r) // Extremely close?
{
_cameraRadius.SetLimits(_minCameraRadius, r);
eye = at - GetFrontDirection() * r;
ret = 1;
}
camera.MoveEyeTo(eye);
camera.MoveAtTo(at);
return ret;
}
void BaseCharacter::SetMaxCameraRadius(float r)
{
_maxCameraRadius = r;
_cameraRadius.SetLimits(_minCameraRadius, r);
_cameraRadius.UpdateClamped(0);
}

View File

@ -0,0 +1,85 @@
#pragma once
namespace verus
{
namespace Game
{
class BaseCharacter : public Spirit
{
Vector3 _extraForce = Vector3(0);
Physics::CharacterController _cc;
float _idleRadius = 1;
float _idleHeight = 1;
float _stepHeight = 1;
float _airborneControl = 0.1f;
float _jumpSpeed = 6;
float _minCameraRadius = 0.1f;
float _maxCameraRadius = 7.5f;
Anim::Elastic<float> _smoothSpeedOnGround;
Anim::Elastic<float> _fallSpeed;
Linear<float> _cameraRadius;
Cooldown _jumpCooldown = 0.25f; // To filter BaseCharacter_OnJump().
Cooldown _wallHitCooldown = 2;
Cooldown _unstuckCooldown = 0.25f;
bool _airborne = false;
bool _ragdoll = false;
public:
BaseCharacter();
virtual ~BaseCharacter();
virtual void HandleInput() override;
virtual void Update() override;
//! Creates the underlying controller (Physics::CharacterController).
//! EndRagdoll() calls this method automatically.
void InitController();
void DoneController();
Physics::RCharacterController GetController() { return _cc; }
virtual void MoveTo(RcPoint3 pos) override;
// Dimensions:
float GetIdleRadius() const { return _idleRadius; }
void SetIdleRadius(float r) { _idleRadius = r; }
float GetIdleHeight() const { return _idleHeight; }
void SetIdleHeight(float h) { _idleHeight = h; }
void SetStepHeight(float sh) { _stepHeight = sh; }
// Jumps:
bool IsOnGround() const;
bool TryJump(bool whileAirborne = false);
void Jump();
void SetJumpSpeed(float v = 6);
float GetFallSpeed() const { return _fallSpeed; }
virtual void BaseCharacter_OnFallImpact(float speed) {}
virtual void BaseCharacter_OnWallImpact(float speed) {}
virtual void BaseCharacter_OnJump() {}
void AddExtraForce(RcVector3 v) { _extraForce += v; }
// For AI:
//! Check if the speed is less than expected.
bool IsStuck();
//! Is typically called when AI gets a new task.
void StartUnstuckCooldown() { _unstuckCooldown.Start(); }
// Ragdoll:
bool IsRagdoll() const { return _ragdoll; }
void ToggleRagdoll();
void BeginRagdoll();
void EndRagdoll();
virtual void BaseCharacter_OnInitRagdoll(RcTransform3 matW) {}
virtual void BaseCharacter_OnDoneRagdoll() {}
void ComputeThirdPersonAim(RPoint3 aimPos, RVector3 aimDir, RcVector3 offset = Vector3(0));
virtual void ComputeThirdPersonCameraArgs(RcVector3 offset, RPoint3 eye, RPoint3 at);
float ComputeThirdPersonCamera(Scene::RCamera camera, Anim::RcOrbit orbit, RcVector3 offset = Vector3(0));
void SetMaxCameraRadius(float r);
float GetCameraRadius() const { return _cameraRadius.GetValue(); }
};
VERUS_TYPEDEFS(BaseCharacter);
}
}

View File

@ -68,7 +68,6 @@ BaseGame::~BaseGame()
Free_D();
Utils::FreeEx(&_alloc);
SDL_Quit();
//CGL::CRender::DoneWin32();
}
void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc desc)
@ -93,7 +92,7 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc desc)
{
HRESULT hr = 0;
if (FAILED(hr = SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)))
throw VERUS_RUNTIME_ERROR << "Reset(), hr=" << VERUS_HR(hr);
throw VERUS_RUNTIME_ERROR << "SetProcessDpiAwareness(), hr=" << VERUS_HR(hr);
settings.UpdateHighDpiScale();
}
@ -143,9 +142,6 @@ void BaseGame::Run(bool relativeMouseMode)
do // The Game Loop.
{
if (_p->_escapeKeyExitGame && km.IsKeyDownEvent(SDL_SCANCODE_ESCAPE))
Exit();
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL2_ProcessEvent(&event);
@ -227,12 +223,12 @@ void BaseGame::Run(bool relativeMouseMode)
}
}
if (_p->_escapeKeyExitGame && km.IsKeyDownEvent(SDL_SCANCODE_ESCAPE))
Exit();
if (_p->_minimized)
continue;
if (quit)
break;
//
// UPDATE
//
@ -264,12 +260,12 @@ void BaseGame::Run(bool relativeMouseMode)
_p->_cameraSpirit.HandleInput();
_p->_cameraSpirit.Update();
_p->_camera.MoveEyeTo(_p->_cameraSpirit.GetPosition());
_p->_camera.MoveAtTo(_p->_cameraSpirit.GetPosition() + _p->_cameraSpirit.GetDirectionFront());
//if (Scene::CWater::IsValidSingleton())
_p->_camera.MoveAtTo(_p->_cameraSpirit.GetPosition() + _p->_cameraSpirit.GetFrontDirection());
if (Scene::Water::IsValidSingleton())
{
// VERUS_QREF_WATER;
// if (water.IsInitialized())
// _p->_camera.ExcludeWaterLine();
VERUS_QREF_WATER;
if (water.IsInitialized())
_p->_camera.ExcludeWaterLine();
}
_p->_camera.Update();
sm.SetCamera(&_p->_camera);

View File

@ -20,7 +20,7 @@ namespace verus
void Run(bool relativeMouseMode = true);
void Exit();
virtual void BaseGame_UpdateSettings() {};
virtual void BaseGame_UpdateSettings() {}
virtual void BaseGame_LoadContent() = 0;
virtual void BaseGame_UnloadContent() = 0;
virtual void BaseGame_HandleInput() = 0;
@ -55,9 +55,9 @@ namespace verus
RSpirit GetCameraSpirit();
// Configuration:
void EnableDefaultCameraMovement(bool b);
void EnableEscapeKeyExitGame(bool b);
void EnableRawInputEvents(bool b);
void EnableDefaultCameraMovement(bool b = true);
void EnableEscapeKeyExitGame(bool b = true);
void EnableRawInputEvents(bool b = true);
void ShowFPS(bool b);
void BulletDebugDraw();

View File

@ -3,4 +3,5 @@
#include "State.h"
#include "StateMachine.h"
#include "Spirit.h"
#include "BaseCharacter.h"
#include "BaseGame.h"

View File

@ -17,41 +17,41 @@ Spirit::~Spirit()
{
}
void Spirit::ComputeDerivedVars()
void Spirit::ComputeDerivedVars(float smoothSpeed)
{
_dv._matPitch = Matrix3::rotationX(_pitch);
_dv._matYaw = Matrix3::rotationY(_yaw);
_dv._matLeanYaw = _dv._matYaw * Matrix3::rotationZ(-_yaw.GetDelta() * smoothSpeed * _turnLeanStrength);
_dv._matRot = _dv._matYaw * _dv._matPitch;
_dv._dirFront = _dv._matRot * Vector3(0, 0, 1);
_dv._dirFront2D = _dv._matYaw * Vector3(0, 0, 1);
_dv._dirSide = VMath::normalizeApprox(VMath::cross(_dv._dirFront, Vector3(0, 1, 0)));
_dv._dirSide2D = VMath::normalizeApprox(VMath::cross(_dv._dirFront2D, Vector3(0, 1, 0)));
_dv._frontDir = _dv._matRot * Vector3(0, 0, 1);
_dv._frontDir2D = _dv._matYaw * Vector3(0, 0, 1);
_dv._sideDir = VMath::normalizeApprox(VMath::cross(_dv._frontDir, Vector3(0, 1, 0)));
_dv._sideDir2D = VMath::normalizeApprox(VMath::cross(_dv._frontDir2D, Vector3(0, 1, 0)));
}
void Spirit::MoveFront(float x)
{
_move += _dv._dirFront * x;
_move += _dv._frontDir * x;
}
void Spirit::MoveSide(float x)
{
_move += _dv._dirSide * x;
_move += _dv._sideDir * x;
}
void Spirit::MoveFront2D(float x)
{
_move += _dv._dirFront2D * x;
_move += _dv._frontDir2D * x;
}
void Spirit::MoveSide2D(float x)
{
_move += _dv._dirSide2D * x;
_move += _dv._sideDir2D * x;
}
void Spirit::TurnPitch(float rad)
{
_pitch = _pitch.GetTarget() + rad;
_pitch = Math::Clamp<float>(_pitch.GetTarget(), -_maxPitch, _maxPitch);
_pitch = Math::Clamp<float>(_pitch.GetTarget() + rad, -_maxPitch, _maxPitch);
}
void Spirit::TurnYaw(float rad)
@ -61,7 +61,7 @@ void Spirit::TurnYaw(float rad)
void Spirit::SetPitch(float rad)
{
_pitch = rad;
_pitch = Math::Clamp<float>(rad, -_maxPitch, _maxPitch);
}
void Spirit::SetYaw(float rad)
@ -73,9 +73,28 @@ void Spirit::HandleInput()
{
VERUS_QREF_TIMER;
// Update velocity:
if (_accel)
{
// Normalize move vector:
_moveLen = VMath::length(_move);
if (_moveLen >= VERUS_FLOAT_THRESHOLD)
_move /= _moveLen;
_velocity += _move * (dt * _accel);
const float speed = VMath::length(_velocity);
if (speed > _maxSpeed) // Too fast?
{
_velocity /= speed;
_velocity *= _maxSpeed;
}
else if (speed < VERUS_FLOAT_THRESHOLD) // Too slow slowpoke.jpg?
{
_velocity = Vector3(0);
}
_move = _velocity;
}
else // No accel:
{
@ -92,34 +111,33 @@ void Spirit::Update()
_pitch.Update();
_yaw.Update();
ComputeDerivedVars();
// Update position:
_positionPrev = _position;
_smoothPositionPrev = _smoothPosition;
{
_position += _velocity * dt;
}
// <Position>
_prevPosition = _position;
_smoothPrevPosition = _smoothPosition;
_position += _velocity * dt;
_smoothPosition = _position;
_smoothPosition.Update();
// </Position>
_speed = VMath::dist(_smoothPosition, _smoothPositionPrev) * timer.GetDeltaTimeInv();
_speed = VMath::dist(_smoothPosition, _smoothPrevPosition) * timer.GetDeltaTimeInv();
_smoothSpeed = _speed;
_smoothSpeed.Update();
// Friction:
// <Friction>
if (_decel && _moveLen < VERUS_FLOAT_THRESHOLD)
{
float speed = VMath::length(_velocity);
if (speed >= VERUS_FLOAT_THRESHOLD)
{
float speed = VMath::length(_velocity);
if (speed >= VERUS_FLOAT_THRESHOLD)
{
const Vector3 dir = _velocity / speed;
//speed = Math::Reduce(speed, _decel*dt);
_velocity = dir * speed;
}
const Vector3 dir = _velocity / speed;
speed = Math::Reduce(speed, _decel * dt);
_velocity = dir * speed;
}
}
// </Friction>
_move = Vector3(0);
ComputeDerivedVars();
}
void Spirit::SetAcceleration(float accel, float decel)
@ -133,34 +151,34 @@ Point3 Spirit::GetPosition(bool smooth)
return smooth ? static_cast<Point3>(_smoothPosition) : _position;
}
void Spirit::MoveTo(RcPoint3 pos, float onTerrain)
void Spirit::MoveTo(RcPoint3 pos)
{
_position = pos;
_positionPrev = _position;
_prevPosition = _position;
_smoothPosition.ForceTarget(_position);
_smoothPositionPrev = _position;
_smoothPrevPosition = _position;
}
void Spirit::SetRemotePosition(RcPoint3 pos)
{
_positionRemote = pos;
_remotePosition = pos;
}
bool Spirit::FitRemotePosition()
{
VERUS_QREF_TIMER;
const Point3 pos = _position;
const float d = Math::Max(9.f, VMath::distSqr(_positionRemote, pos) * 4);
const float d = Math::Max(9.f, VMath::distSqr(_remotePosition, pos) * 4);
const float ratio = 1 / exp(dt * d);
const bool warp = d >= 4 * 4;
_position = warp ? _positionRemote : VMath::lerp(ratio, _positionRemote, pos);
_position = warp ? _remotePosition : VMath::lerp(ratio, _remotePosition, pos);
if (warp)
{
_positionPrev = _position;
_prevPosition = _position;
_smoothPosition.ForceTarget(_position);
_smoothPositionPrev = _position;
_smoothPrevPosition = _position;
}
_positionRemote += _velocity * dt; // Predict.
_remotePosition += _velocity * dt; // Predict.
return warp;
}
@ -221,3 +239,14 @@ Transform3 Spirit::GetUprightMatrix() const
{
return Transform3(_dv._matYaw, Vector3(_smoothPosition));
}
Transform3 Spirit::GetUprightWithLeanMatrix() const
{
return Transform3(_dv._matLeanYaw, Vector3(_smoothPosition));
}
float Spirit::GetMotionBlur() const
{
VERUS_QREF_SM;
return sm.GetMainCamera()->ComputeMotionBlur(_smoothPosition, _smoothPrevPosition);
}

View File

@ -6,41 +6,45 @@ namespace verus
{
class Spirit : public AllocatorAware
{
protected:
static const float s_defaultMaxPitch;
struct DerivedVars
{
Matrix3 _matPitch;
Matrix3 _matYaw;
Matrix3 _matLeanYaw;
Matrix3 _matRot;
Vector3 _dirFront = Vector3(0);
Vector3 _dirFront2D = Vector3(0);
Vector3 _dirSide = Vector3(0);
Vector3 _dirSide2D = Vector3(0);
Vector3 _frontDir = Vector3(0);
Vector3 _frontDir2D = Vector3(0);
Vector3 _sideDir = Vector3(0);
Vector3 _sideDir2D = Vector3(0);
};
DerivedVars _dv;
Point3 _position = Point3(0);
Point3 _positionPrev = Point3(0);
Point3 _positionRemote = Point3(0);
Point3 _prevPosition = Point3(0);
Point3 _remotePosition = Point3(0);
Vector3 _velocity = Vector3(0);
Vector3 _move = Vector3(0);
Point3 _smoothPositionPrev = Point3(0);
Anim::Damping<Point3> _smoothPosition;
Anim::Damping<float, true> _pitch;
Anim::Damping<float, true> _yaw;
Point3 _smoothPrevPosition = Point3(0);
Anim::Elastic<Point3> _smoothPosition;
Anim::Elastic<float, true> _pitch;
Anim::Elastic<float, true> _yaw;
Anim::Elastic<float> _smoothSpeed;
float _speed = 0;
float _maxSpeed = 10;
float _moveLen = 0;
float _maxPitch = s_defaultMaxPitch;
float _accel = 0;
float _decel = 0;
float _speed = 0;
float _maxSpeed = 10;
float _turnLeanStrength = 0;
public:
Spirit();
virtual ~Spirit();
VERUS_P(void ComputeDerivedVars());
void ComputeDerivedVars(float smoothSpeed = 0);
// Move:
void MoveFront(float x);
@ -60,19 +64,21 @@ namespace verus
virtual void Update();
void SetAcceleration(float accel = 5, float decel = 5);
float GetSpeed() const { return _speed; }
float GetSmoothSpeed() const { return _smoothSpeed; }
float GetMaxSpeed() const { return _maxSpeed; }
void SetMaxSpeed(float v = 10) { _maxSpeed = v; }
Point3 GetPosition(bool smooth = true);
void MoveTo(RcPoint3 pos, float onTerrain = -1);
void SetRemotePosition(RcPoint3 pos);
bool FitRemotePosition();
Point3 GetPosition(bool smooth = true);
virtual void MoveTo(RcPoint3 pos);
void SetRemotePosition(RcPoint3 pos);
bool FitRemotePosition();
RcVector3 GetVelocity() const { return _velocity; }
void SetVelocity(RcVector3 v) { _velocity = v; }
RcVector3 GetDirectionFront() const { return _dv._dirFront; }
RcVector3 GetDirectionSide() const { return _dv._dirSide; }
RcVector3 GetFrontDirection() const { return _dv._frontDir; }
RcVector3 GetSideDirection() const { return _dv._sideDir; }
//! Rotates smoothly across multiple frames.
void Rotate(RcVector3 front, float speed);
@ -84,6 +90,11 @@ namespace verus
RcMatrix3 GetRotationMatrix() const;
Transform3 GetMatrix() const;
Transform3 GetUprightMatrix() const;
Transform3 GetUprightWithLeanMatrix() const;
float GetMotionBlur() const;
void SetTurnLeanStrength(float x) { _turnLeanStrength = x; }
};
VERUS_TYPEDEFS(Spirit);
}

View File

@ -11,6 +11,7 @@ namespace verus
StateMachine* _pStateMachine = nullptr;
public:
StateMachine* GetStateMachine() const { return _pStateMachine; }
StateMachine* SetStateMachine(StateMachine* p) { return Utils::Swap(_pStateMachine, p); }
virtual bool IsValidNextState(State* p);

View File

@ -98,6 +98,18 @@ float Convert::LinearToSRGB(float color)
return color < 0.0031308f ? 12.92f * color : 1.055f * pow(color, 1 / 2.4f) - 0.055f;
}
void Convert::SRGBToLinear(float color[])
{
VERUS_FOR(i, 3)
color[i] = SRGBToLinear(color[i]);
}
void Convert::LinearToSRGB(float color[])
{
VERUS_FOR(i, 3)
color[i] = LinearToSRGB(color[i]);
}
UINT32 Convert::Color16To32(UINT16 in)
{
const int b = ((in >> 0) & 0x1F) << 3;

View File

@ -48,6 +48,8 @@ namespace verus
// Colors:
static float SRGBToLinear(float color);
static float LinearToSRGB(float color);
static void SRGBToLinear(float color[]);
static void LinearToSRGB(float color[]);
static UINT32 Color16To32(UINT16 in);
static void ColorInt32ToFloat(UINT32 in, float* out, bool sRGB = true);
static UINT32 ColorFloatToInt32(const float* in, bool sRGB = true);

View File

@ -0,0 +1,34 @@
#include "verus.h"
using namespace verus;
Cooldown::Cooldown(float interval) :
_baseInterval(interval)
{
}
bool Cooldown::IsFinished(float after) const
{
VERUS_QREF_TIMER;
return _deadline <= timer.GetTime() + after;
}
bool Cooldown::IsInProgress(float partComplete) const
{
VERUS_QREF_TIMER;
const float t = timer.GetTime();
const float startTime = _deadline - _actualInterval;
if (t >= startTime && t < _deadline)
{
const float part = (t - startTime) / _actualInterval;
return part >= partComplete;
}
return false;
}
void Cooldown::Start(float interval)
{
VERUS_QREF_TIMER;
_actualInterval = (interval >= 0) ? interval : _baseInterval;
_deadline = timer.GetTime() + _actualInterval;
}

View File

@ -0,0 +1,21 @@
#pragma once
namespace verus
{
class Cooldown
{
float _baseInterval = 0;
float _actualInterval = 0;
float _deadline = 0;
public:
Cooldown(float interval);
bool IsFinished(float after = 0) const;
bool IsInProgress(float partComplete = 1) const;
void Start(float interval = -1);
void Reset() { _deadline = 0; }
void SetBaseInterval(float x) { _baseInterval = x; }
};
VERUS_TYPEDEFS(Cooldown);
}

View File

@ -17,6 +17,7 @@
#include "Linear.h"
#include "Convert.h"
#include "Timer.h"
#include "Cooldown.h"
#include "EngineInit.h"
#include "GlobalVarsClipboard.h"

View File

@ -7,6 +7,11 @@ Object::Object()
_flags = 0;
}
Object::Object(const Object& that) :
_flags(that._flags.load())
{
}
Object::~Object()
{
VERUS_RT_ASSERT(!IsInitialized());

View File

@ -31,6 +31,7 @@ namespace verus
protected:
Object();
Object(const Object& that);
virtual ~Object();
void Init();

View File

@ -154,10 +154,10 @@ namespace verus
}
};
template<typename T, int NUM>
template<typename T, int COUNT>
class Pwns
{
T _t[NUM];
T _t[COUNT];
public:
Pwns()
@ -171,18 +171,18 @@ namespace verus
void Done()
{
VERUS_FOR(i, NUM)
VERUS_FOR(i, COUNT)
_t[i].Done();
}
const T& operator[](int i) const
{
VERUS_RT_ASSERT(i >= 0 && i < NUM);
VERUS_RT_ASSERT(i >= 0 && i < COUNT);
return _t[i];
}
T& operator[](int i)
{
VERUS_RT_ASSERT(i >= 0 && i < NUM);
VERUS_RT_ASSERT(i >= 0 && i < COUNT);
return _t[i];
}
};

View File

@ -560,7 +560,7 @@ void Image::Init(CSZ url)
FileSystem::LoadResourceFromFile(url, _vData);
ilGenImages(1, &_name);
ilBindImage(_name);
ilLoadL(IL_TYPE_UNKNOWN, _vData.data(), _vData.size());
ilLoadL(IL_TYPE_UNKNOWN, _vData.data(), Utils::Cast32(_vData.size()));
_width = ilGetInteger(IL_IMAGE_WIDTH);
_height = ilGetInteger(IL_IMAGE_HEIGHT);
_bytesPerPixel = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);

View File

@ -28,6 +28,19 @@ int Math::HighestBit(int x)
return bit;
}
int Math::LowestBit(int x)
{
if (!x)
return -1;
int bit = 0;
while (!(x & 1))
{
x >>= 1;
++bit;
}
return bit;
}
bool Math::IsNaN(float x)
{
// 'isnan' : is not a member of 'std' :(
@ -61,21 +74,6 @@ float Math::SmoothStep(float a, float b, float t)
return x * x * (3 - (x + x));
}
float Math::LinearToSin(float t)
{
return sin(t * VERUS_PI);
}
float Math::LinearToCos(float t)
{
return cos(t * VERUS_PI) * -0.5f + 0.5f; // [1 to -1] -> [0 to 1].
}
float Math::EaseInOutSine(float x)
{
return -(cos(VERUS_PI * x) - 1) * 0.5f;
}
Vector3 Math::TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c)
{
return VMath::normalize(VMath::cross(a - b, a - c));
@ -261,6 +259,14 @@ Transform3 Math::ToUVMatrix(float zOffset, RcVector4 texSize, PcVector4 pTileSiz
return m;
}
float Math::Reduce(float val, float reduction)
{
if (abs(val) < abs(reduction))
return 0;
else
return val - glm::sign(val) * reduction;
}
void Math::Test()
{
const float e = 1e-6f;

View File

@ -50,6 +50,7 @@ namespace verus
bool IsPowerOfTwo(int x);
UINT32 NextPowerOfTwo(UINT32 x);
int HighestBit(int x);
int LowestBit(int x);
bool IsNaN(float x);
// Angles:
@ -60,9 +61,6 @@ namespace verus
// Interpolation, splines:
float Lerp(float a, float b, float t);
float SmoothStep(float a, float b, float t);
float LinearToSin(float t);
float LinearToCos(float t);
float EaseInOutSine(float x);
// Shapes:
Vector3 TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c);
@ -82,10 +80,12 @@ namespace verus
int ComputeMipLevels(int w, int h, int d = 1);
void Test();
// Matrices:
Transform3 QuadMatrix(float x = 0, float y = 0, float w = 1, float h = 1);
Transform3 ToUVMatrix(float zOffset = 0, RcVector4 texSize = Vector4(0), PcVector4 pTileSize = nullptr);
float Reduce(float val, float reduction);
void Test();
};
}

View File

@ -161,23 +161,8 @@ void QuadtreeIntegral::TraverseVisible(int currentNode)
_testCount++;
{
Bounds bounds = _vNodes[currentNode].GetBounds();
Sphere sphere = _vNodes[currentNode].GetSphere();
#if 0
if (Scene::CWater::I().IsReflectionMode())
{
Point3 c = sphere.GetCenter();
c.setY(-c.getY());
sphere.SetCenter(c);
bounds.MirrorY();
}
#endif
if (Relation::outside == Scene::SceneManager::I().GetCamera()->GetFrustum().ContainsAabb(bounds))
return;
}
if (Relation::outside == Scene::SceneManager::I().GetCamera()->GetFrustum().ContainsAabb(_vNodes[currentNode].GetBounds()))
return;
// Yes, it is visible:
if (Node::HasChildren(currentNode, _nodeCount)) // Node has children -> update them:

View File

@ -18,9 +18,9 @@ void CharacterController::Init(RcPoint3 pos, RcDesc desc)
VERUS_QREF_BULLET;
if (desc._radius >= 1e-4f)
if (desc._radius >= VERUS_FLOAT_THRESHOLD)
_radius = desc._radius;
if (desc._height >= 1e-4f)
if (desc._height >= VERUS_FLOAT_THRESHOLD)
_height = desc._height;
float stepHeight = _radius;
if (desc._stepHeight >= 0)

View File

@ -44,6 +44,27 @@ void Atmosphere::Init()
renderer.GetDS().InitByAtmosphere(_shadowMap.GetTexture());
CreateCelestialBodyMesh();
{
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Sun", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_SUN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Moon", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_MOON].Init(pipeDesc);
}
_texSky.LoadDDS("[Textures]:Sky/Sky.dds");
_tex[TEX_SKY].Init("[Textures]:Sky/Sky.dds");
@ -58,14 +79,20 @@ void Atmosphere::Init()
_clouds._phaseB.setX(utils.GetRandom().NextFloat());
_clouds._phaseB.setY(utils.GetRandom().NextFloat());
_sun._matTilt = Matrix3::rotationX(-VERUS_PI / 10);
_sun._dirToMidnight = _sun._matTilt * Vector3(0, -1, 0);
_sun._dirTo = VMath::mulPerElem(_sun._dirToMidnight, Vector3(1, -1, 1));
_fog._density[0] = _fog._density[1] = 0.0006f;
_sun._matTilt = Matrix3::rotationX(_sun._latitude);
UpdateSun(_time);
}
void Atmosphere::Done()
{
_shader->FreeDescriptorSet(_cshSkyFS);
if (_shader)
{
_shader->FreeDescriptorSet(_cshMoonFS);
_shader->FreeDescriptorSet(_cshSunFS);
_shader->FreeDescriptorSet(_cshSkyFS);
}
VERUS_DONE(Atmosphere);
}
@ -73,25 +100,25 @@ void Atmosphere::UpdateSun(float time)
{
// Update time and sun's color before calling this method.
_sun._dirTo = Matrix3::rotationZ(time * VERUS_2PI) * _sun._dirToMidnight;
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(time * VERUS_2PI) * Vector3(0, -1, 0);
_night = false;
if (_sun._dirTo.getY() < 0) // Moon light:
{
_night = true;
_sun._dirTo = Matrix3::rotationZ(time * VERUS_2PI + VERUS_PI) * _sun._dirToMidnight;
_sun._color = VMath::mulPerElem(_sun._color, Vector3(0.19f, 0.21f, 0.45f));
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(time * VERUS_2PI) * Vector3(0, 1, 0);
_sun._color = glm::saturation(0.1f, _sun._color.GLM()) * 0.5f;
}
// Reduce light's intensity when near horizon:
const float intensity = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1);
_sun._color *= intensity;
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 5, 0, 1);
_sun._color *= _sun._alpha;
}
void Atmosphere::Update()
{
VERUS_QREF_RENDERER;
VERUS_QREF_TIMER;
VERUS_QREF_WATER;
if (!_async_loaded)
{
@ -106,23 +133,33 @@ void Atmosphere::Update()
_async_loaded = true;
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_SKY].Init(pipeDesc);
pipeDesc._renderPassHandle = water.GetRenderPassHandle();
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
_pipe[PIPE_SKY_REFLECTION].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
_pipe[PIPE_CLOUDS].Init(pipeDesc);
pipeDesc._renderPassHandle = water.GetRenderPassHandle();
pipeDesc._rasterizationState._cullMode = CGI::CullMode::front;
_pipe[PIPE_CLOUDS_REFLECTION].Init(pipeDesc);
}
_shader->FreeDescriptorSet(_cshSkyFS);
_cshSkyFS = _shader->BindDescriptorSetTextures(1, { _tex[TEX_SKY], _tex[TEX_STARS], _tex[TEX_CLOUDS], _tex[TEX_CLOUDS_NM] });
_shader->FreeDescriptorSet(_cshSunFS);
_cshSunFS = _shader->BindDescriptorSetTextures(1, { _tex[TEX_SKY], _tex[TEX_STARS], _tex[TEX_SUN], _tex[TEX_CLOUDS_NM] });
_shader->FreeDescriptorSet(_cshMoonFS);
_cshMoonFS = _shader->BindDescriptorSetTextures(1, { _tex[TEX_SKY], _tex[TEX_STARS], _tex[TEX_MOON], _tex[TEX_CLOUDS_NM] });
}
}
if (!_async_loaded)
@ -132,28 +169,46 @@ 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(64, color, 1.5f); _fog._color = Vector3::MakeFromPointer(color) * _hdrScale;
GetColor(208, color, 0.3f); _ambientColor = Vector3::MakeFromPointer(color) * _hdrScale;
GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * _hdrScale;
GetColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(68000, 45000, 10) * cloudScaleAmb);
GetColor(110, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(75000, 8000, 1) * cloudScaleFog);
GetColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(85000, 30000, 1) * cloudScaleSun);
glm::vec3 ambientColor = _ambientColor.GLM();
glm::vec3 fogColor = _fog._color.GLM();
_ambientColor = glm::saturation(0.75f, ambientColor);
const float clearSky = Math::Min(1.f, 1.5f - _clouds._cloudiness);
_fog._color = glm::saturation(clearSky * 0.75f, fogColor);
_fog._colorInit = _fog._color;
_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);
#ifdef _DEBUG
if (abs(_time - 0.5f) < 0.01f && glm::epsilonEqual(static_cast<float>(_clouds._cloudiness), 0.25f, 0.05f))
{
const glm::vec3 grayAmbient = glm::saturation(0.f, _ambientColor.GLM());
const glm::vec3 grayFog = glm::saturation(0.f, _fog._color.GLM());
const glm::vec3 graySun = glm::saturation(0.f, _sun._color.GLM());
VERUS_RT_ASSERT(glm::epsilonEqual(grayAmbient.x, 6400.f, 640.f));
VERUS_RT_ASSERT(glm::epsilonEqual(graySun.x, 32000.f, 3200.f));
}
#endif
UpdateSun(_time);
}
void Atmosphere::DrawSky()
void Atmosphere::DrawSky(bool reflection)
{
if (!_async_loaded)
return;
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_WATER;
if (water.IsUnderwater())
reflection = false;
auto cb = renderer.GetCommandBuffer();
@ -161,24 +216,25 @@ void Atmosphere::DrawSky()
Matrix3 matS = Matrix3::scale(Vector3(4, 1, 4)); // Stretch sky dome.
const Matrix4 matSkyDome = cam.GetMatrixVP() * Transform3(matS, Vector3(cam.GetEyePosition()));
s_ubPerFrame._time_cloudiness_expo.x = _time;
s_ubPerFrame._time_cloudiness_expo.y = _clouds._cloudiness;
s_ubPerFrame._time_cloudiness_expo.z = 0;
s_ubPerFrame._time_cloudiness.x = _time;
s_ubPerFrame._time_cloudiness.y = _clouds._cloudiness;
s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), 0);
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), 0);
s_ubPerFrame._dirToSun = float4(_sun._dirTo.GLM(), 0);
s_ubPerFrame._sunColor = float4(_sun._color.GLM(), _sun._alpha);
s_ubPerFrame._phaseAB = float4(
_clouds._phaseA.getX(),
_clouds._phaseA.getY(),
_clouds._phaseB.getX(),
_clouds._phaseB.getY());
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), 0);
_skyDome.CopyPosDeqScale(&s_ubPerMeshVS._posDeqScale.x);
_skyDome.CopyPosDeqBias(&s_ubPerMeshVS._posDeqBias.x);
s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat();
_skyDome.BindGeo(cb);
// <Sky>
cb->BindPipeline(_pipe[PIPE_SKY]);
s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat();
_skyDome.BindGeo(cb);
cb->BindPipeline(_pipe[reflection ? PIPE_SKY_REFLECTION : PIPE_SKY]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
@ -190,8 +246,55 @@ void Atmosphere::DrawSky()
cb->DrawIndexed(_skyDome.GetIndexCount());
// </Sky>
const float celestialBodyScale = 0.02f + 0.02f * (1 - abs(_sun._dirTo.getY()));
matS = Matrix3::scale(Vector3(celestialBodyScale, 1, celestialBodyScale));
// <Sun>
{
const Matrix3 matR = Matrix3::rotationZ(_time * VERUS_2PI);
const Transform3 matW = Transform3(_sun._matTilt * matR * matS, Vector3(cam.GetEyePosition()));
s_ubPerObject._matW = matW.UniformBufferFormat();
s_ubPerObject._matWVP = Matrix4(cam.GetMatrixVP() * matW).UniformBufferFormat();
cb->BindVertexBuffers(_geo);
cb->BindPipeline(_pipe[PIPE_SUN]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _cshSunFS);
cb->BindDescriptors(_shader, 2);
cb->BindDescriptors(_shader, 3);
_shader->EndBindDescriptors();
cb->Draw(4, 1);
}
// </Sun>
// <Moon>
{
const Matrix3 matR = Matrix3::rotationZ(_time * VERUS_2PI + VERUS_PI);
const Transform3 matW = Transform3(_sun._matTilt * matR * matS, Vector3(cam.GetEyePosition()));
s_ubPerObject._matW = matW.UniformBufferFormat();
s_ubPerObject._matWVP = Matrix4(cam.GetMatrixVP() * matW).UniformBufferFormat();
cb->BindVertexBuffers(_geo);
cb->BindPipeline(_pipe[PIPE_MOON]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _cshMoonFS);
cb->BindDescriptors(_shader, 2);
cb->BindDescriptors(_shader, 3);
_shader->EndBindDescriptors();
cb->Draw(4, 1);
}
// </Moon>
// <Clouds>
cb->BindPipeline(_pipe[PIPE_CLOUDS]);
s_ubPerObject._matWVP = matSkyDome.UniformBufferFormat();
_skyDome.BindGeo(cb);
cb->BindPipeline(_pipe[reflection ? PIPE_CLOUDS_REFLECTION : PIPE_CLOUDS]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
@ -230,6 +333,15 @@ 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
{
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));
}
RcVector3 Atmosphere::GetDirToSun() const
{
return _sun._dirTo;
@ -240,6 +352,11 @@ RcVector3 Atmosphere::GetSunColor() const
return _sun._color;
}
float Atmosphere::GetSunAlpha() const
{
return _sun._alpha;
}
void Atmosphere::BeginShadow(int split)
{
_shadowMap.Begin(_sun._dirTo, 1, 0, split);
@ -266,3 +383,27 @@ RcPoint3 Atmosphere::GetEyePosition(PVector3 pDirFront)
return sm.GetCamera()->GetEyePosition();
}
}
void Atmosphere::CreateCelestialBodyMesh()
{
CGI::GeometryDesc geoDesc;
const CGI::VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(Vertex, _pos), CGI::IeType::floats, 3, CGI::IeUsage::position, 0},
{0, offsetof(Vertex, _tc), CGI::IeType::shorts, 2, CGI::IeUsage::texCoord, 0},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(Vertex), 0 };
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
const Vertex skyBody[] =
{
{-1, -1, -1, 1, 0},
{-1, -1, +1, 0, 0},
{+1, -1, -1, 1, 1},
{+1, -1, +1, 0, 1},
};
_geo->CreateVertexBuffer(4, 0);
_geo->UpdateVertexBuffer(skyBody, 0);
}

View File

@ -12,7 +12,11 @@ namespace verus
enum PIPE
{
PIPE_SKY,
PIPE_SKY_REFLECTION,
PIPE_CLOUDS,
PIPE_CLOUDS_REFLECTION,
PIPE_SUN,
PIPE_MOON,
PIPE_COUNT
};
@ -27,6 +31,12 @@ namespace verus
TEX_COUNT
};
struct Vertex
{
float _pos[3];
short _tc[2];
};
private:
struct Clouds
{
@ -34,26 +44,22 @@ namespace verus
Vector4 _phaseB = Vector4(0);
float _speedPhaseA = 0.017f;
float _speedPhaseB = 0.003f;
Anim::Damping<float> _cloudiness = 0.25f;
Anim::Elastic<float> _cloudiness = 0.25f;
};
struct Fog
{
Vector3 _color = Vector3(0);
Vector3 _colorInit = Vector3(0);
float _start = 10000;
float _end = 100000;
float _startEx = 0;
float _endEx = 0;
float _density = 0.0002f;
float _density[2] = {}; // Actual and base.
};
struct Sun
{
Matrix3 _matTilt;
Vector3 _dirToMidnight = Vector3(0, -1, 0);
Vector3 _dirTo = Vector3(0, 1, 0);
Vector3 _color = Vector3(0);
float _alpha = 1;
float _latitude = 0.7f;
};
static UB_PerFrame s_ubPerFrame;
@ -61,6 +67,7 @@ namespace verus
static UB_PerMeshVS s_ubPerMeshVS;
static UB_PerObject s_ubPerObject;
CGI::GeometryPwn _geo;
CGI::ShaderPwn _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
@ -73,8 +80,9 @@ namespace verus
CGI::TextureRAM _texSky;
float _time = 0.5f;
float _timeSpeed = 1 / 300.f;
float _hdrScale = 1000;
CGI::CSHandle _cshSkyFS;
CGI::CSHandle _cshSunFS;
CGI::CSHandle _cshMoonFS;
bool _night = false;
bool _async_loaded = false;
@ -87,29 +95,33 @@ namespace verus
void UpdateSun(float time);
void Update();
void DrawSky();
void DrawSky(bool reflection = false);
void GetColor(int level, float* pOut, float scale);
float GetMagnitude(float noon, float dusk, float midnight) const;
// Time:
float GetTime() const { return _time; }
void SetTime(float x) { _time = x; }
float GetTimeSpeed() const { return _timeSpeed; }
void SetTimeSpeed(float x) { _timeSpeed = x; }
RcVector3 GetAmbientColor() const { return _ambientColor; }
// Clouds:
Anim::Damping<float>& GetCloudiness() { return _clouds._cloudiness; }
Anim::Elastic<float>& GetCloudiness() { return _clouds._cloudiness; }
void SetCloudiness(float x) { _clouds._cloudiness = x; _clouds._cloudiness.ForceTarget(); }
// Fog:
RcVector3 GetFogColor() const { return _fog._color; }
float GetFogDensity() const { return _fog._density; }
void SetFogDensity(float d) { _fog._density = d; }
float GetFogDensity() const { return _fog._density[0]; }
float GetBaseFogDensity() const { return _fog._density[1]; }
void SetBaseFogDensity(float d) { _fog._density[1] = d; }
// Sun:
RcVector3 GetDirToSun() const;
RcVector3 GetSunColor() const;
float GetSunAlpha() const;
// Shadow:
void BeginShadow(int split);
@ -117,6 +129,8 @@ namespace verus
RCascadedShadowMap GetShadowMap() { return _shadowMap; }
RcPoint3 GetEyePosition(PVector3 pDirFront = nullptr);
void CreateCelestialBodyMesh();
};
VERUS_TYPEDEFS(Atmosphere);
}

View File

@ -13,9 +13,14 @@ void Camera::UpdateInternal()
if (_update & Update::p)
{
if (0 == _fovY)
{
_matP = Matrix4::MakeOrtho(_w, _h, _zNear, _zFar);
}
else
{
_matP = Matrix4::MakePerspective(_fovY, _aspectRatio, _zNear, _zFar);
_fovScale = 0.5f / tan(_fovY * 0.5f);
}
}
}
@ -48,6 +53,22 @@ void Camera::UpdateVP()
_frustum.FromMatrix(_matVP);
}
void Camera::EnableReflectionMode()
{
const Transform3 matV = _matV;
_eyePos.setY(-_eyePos.getY());
_atPos.setY(-_atPos.getY());
UpdateView();
UpdateVP();
const Transform3 tr = Transform3::scale(Vector3(1, -1, 1));
_matV = matV * tr;
_matVi = VMath::orthoInverse(_matV);
_matVP = _matP * _matV;
}
Vector4 Camera::GetZNearFarEx() const
{
return Vector4(_zNear, _zFar, _zFar / (_zFar - _zNear), _zFar * _zNear / (_zNear - _zFar));
@ -63,9 +84,9 @@ void Camera::SetFrustumFar(float zFar)
_frustum.SetFarPlane(_eyePos, _frontDir, zFar);
}
void Camera::SetFOVH(float x)
void Camera::SetFovX(float x)
{
SetFOV(2 * atan(tan(x * 0.5f) / _aspectRatio));
SetFovY(2 * atan(tan(x * 0.5f) / _aspectRatio));
}
void Camera::GetClippingSpacePlane(RVector4 plane) const

View File

@ -25,6 +25,7 @@ namespace verus
VERUS_PD(Point3 _atPos = Point3(0, 0, -1));
VERUS_PD(Vector3 _upDir = Vector3(0, 1, 0));
VERUS_PD(Vector3 _frontDir = Vector3(0, 0, -1));
float _fovScale = 1;
float _fovY = VERUS_PI / 4; // Zero FOV means ortho.
float _aspectRatio = 1;
float _zNear = 0.1f; // 10 cm.
@ -39,6 +40,8 @@ namespace verus
void UpdateView();
void UpdateVP();
void EnableReflectionMode();
Vector4 GetZNearFarEx() const;
// Frustum:
@ -64,12 +67,13 @@ namespace verus
RcMatrix4 GetMatrixVP() const { return _matVP; }
// Perspective:
float GetFOV() const { return _fovY; }
float GetFovScale() const { return _fovScale; } // For converting offsets in meters to offsets in texture coords.
float GetFovY() const { return _fovY; }
float GetAspectRatio() const { return _aspectRatio; }
float GetZNear() const { return _zNear; }
float GetZFar() const { return _zFar; }
void SetFOVH(float x);
void SetFOV(float x) { _update |= Update::p; _fovY = x; }
void SetFovX(float x);
void SetFovY(float x) { _update |= Update::p; _fovY = x; }
void SetAspectRatio(float x) { _update |= Update::p; _aspectRatio = x; }
void SetZNear(float x) { _update |= Update::p; _zNear = x; }
void SetZFar(float x) { _update |= Update::p; _zFar = x; }

View File

@ -3,6 +3,17 @@
using namespace verus;
using namespace verus::Scene;
CameraOrbit::CameraOrbit() :
_pitch(0, 18),
_yaw(0, 18),
_radius(10, 8)
{
}
CameraOrbit::~CameraOrbit()
{
}
void CameraOrbit::Update()
{
const Vector3 toEye = Matrix3::rotationZYX(Vector3(_pitch, _yaw, 0)) * Vector3(0, 0, _radius);
@ -10,6 +21,15 @@ void CameraOrbit::Update()
MainCamera::Update();
}
void CameraOrbit::UpdateElastic()
{
if (!_elastic)
return;
_pitch.Update();
_yaw.Update();
_radius.Update();
}
void CameraOrbit::DragController_GetParams(float& x, float& y)
{
x = _yaw;
@ -18,8 +38,13 @@ void CameraOrbit::DragController_GetParams(float& x, float& y)
void CameraOrbit::DragController_SetParams(float x, float y)
{
_yaw = fmod(x, VERUS_2PI);
_yaw = Math::WrapAngle(x);
_pitch = Math::Clamp(y, -VERUS_PI * 0.49f, VERUS_PI * 0.49f);
if (!_elastic)
{
_pitch.ForceTarget();
_yaw.ForceTarget();
}
Update();
}
@ -31,40 +56,8 @@ void CameraOrbit::DragController_GetRatio(float& x, float& y)
void CameraOrbit::MulRadiusBy(float a)
{
_radius *= a;
_radius = _radius.GetTarget() * a;
if (!_elastic)
_radius.ForceTarget();
Update();
}
void CameraOrbit::SaveState(int slot)
{
StringStream ss;
ss << _C(Utils::I().GetWritablePath()) << "/CameraState.xml";
IO::Xml xml;
xml.SetFilename(_C(ss.str()));
xml.Load();
char txt[16];
sprintf_s(txt, "slot%d", slot);
char params[40];
sprintf_s(params, "|%f %f %f", _pitch, _yaw, _radius);
xml.Set(txt, _C(_atPos.ToString() + params));
}
void CameraOrbit::LoadState(int slot)
{
StringStream ss;
ss << _C(Utils::I().GetWritablePath()) << "/CameraState.xml";
IO::Xml xml;
xml.SetFilename(_C(ss.str()));
xml.Load();
char txt[16];
sprintf_s(txt, "slot%d", slot);
CSZ v = xml.GetS(txt);
if (v)
{
CSZ p = strchr(v, '|');
_atPos.FromString(v);
sscanf(p + 1, "%f %f %f", &_pitch, &_yaw, &_radius);
_update |= Update::v;
Update();
}
}

View File

@ -6,28 +6,32 @@ namespace verus
{
class CameraOrbit : public MainCamera, public Input::DragControllerDelegate
{
float _pitch = 0;
float _yaw = 0;
float _radius = 10;
Anim::Elastic<float, true> _pitch;
Anim::Elastic<float, true> _yaw;
Anim::Elastic<float> _radius;
bool _elastic = false;
public:
CameraOrbit();
virtual ~CameraOrbit();
virtual void Update() override;
void UpdateElastic();
virtual void DragController_GetParams(float& x, float& y) override;
virtual void DragController_SetParams(float x, float y) override;
virtual void DragController_GetRatio(float& x, float& y) override;
float GetRadius() const { return _radius; }
void SetRadius(float r) { _radius = r; }
void SetRadius(float r) { _radius = r; _radius.ForceTarget(); }
void MulRadiusBy(float a);
float GetPitch() const { return _pitch; }
float GetYaw() const { return _yaw; }
void SetPitch(float a) { _pitch = a; }
void SetYaw(float a) { _yaw = a; }
void SetPitch(float a) { _pitch = Math::WrapAngle(a); _pitch.ForceTarget(); }
void SetYaw(float a) { _yaw = Math::WrapAngle(a); _yaw.ForceTarget(); }
virtual void SaveState(int slot) override;
virtual void LoadState(int slot) override;
void EnableElastic(bool b = true) { _elastic = b; }
};
VERUS_TYPEDEFS(CameraOrbit);
}

View File

@ -95,9 +95,9 @@ void Grass::Init(RTerrain terrain)
const int strides[] = { sizeof(Vertex), sizeof(PerInstanceData), 0 };
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
_geo->CreateVertexBuffer(_vPatchMeshVB.size(), 0);
_geo->CreateVertexBuffer(Utils::Cast32(_vPatchMeshVB.size()), 0);
_geo->CreateVertexBuffer(maxInstances, 1);
_geo->CreateIndexBuffer(_vPatchMeshIB.size());
_geo->CreateIndexBuffer(Utils::Cast32(_vPatchMeshIB.size()));
_geo->UpdateVertexBuffer(_vPatchMeshVB.data(), 0);
_geo->UpdateIndexBuffer(_vPatchMeshIB.data());
@ -258,7 +258,7 @@ void Grass::Draw()
meshInstCount++;
}
}
cb->DrawIndexed(_vPatchMeshIB.size(), meshInstCount, 0, 0, _instanceCount);
cb->DrawIndexed(Utils::Cast32(_vPatchMeshIB.size()), meshInstCount, 0, 0, _instanceCount);
_instanceCount += meshInstCount;
s_shader->EndBindDescriptors();
@ -283,7 +283,7 @@ void Grass::QuadtreeIntegral_ProcessVisibleNode(const short* ij, RcPoint3 center
Patch patch;
patch.i = ij[0];
patch.j = ij[1];
patch.h = center.getY() * 100;
patch.h = Terrain::ConvertHeight(center.getY());
patch.type = 0;
if (distSq <= 64 * 64.f)
patch.type |= 0x1;
@ -393,7 +393,7 @@ void Grass::CreateBuffers()
vertex._pos[0] = static_cast<short>(bush._vertPos[i].getX() * 1000);
vertex._pos[1] = static_cast<short>(bush._vertPos[i].getY() * 1000);
vertex._pos[2] = static_cast<short>(bush._vertPos[i].getZ() * 1000);
vertex._pos[3] = bush._phaseShift * 99;
vertex._pos[3] = static_cast<short>(bush._phaseShift * 99);
vertex._tc[0] = _bushTexCoords[0][i][0];
vertex._tc[1] = _bushTexCoords[0][i][1];
vertex._tc[2] = static_cast<short>(bush._x * 1000);
@ -453,8 +453,7 @@ void Grass::OnTextureLoaded(int layer)
int Grass::BeginMagnet(RcPoint3 pos, float radius)
{
const int count = _vMagnets.size();
VERUS_FOR(i, count)
VERUS_FOR(i, _vMagnets.size())
{
if (!_vMagnets[i]._active)
{

View File

@ -117,7 +117,7 @@ void Material::Pick::SetColor(float r, float g, float b)
z = b;
}
void Material::Pick::SetAmount(float x)
void Material::Pick::SetAlpha(float x)
{
w = x;
}
@ -162,7 +162,7 @@ void Material::PickRound::SetRadius(float r)
z = r;
}
void Material::PickRound::SetAmount(float x)
void Material::PickRound::SetAlpha(float x)
{
w = x;
}
@ -241,6 +241,7 @@ bool Material::Done()
_refCount--;
if (_refCount <= 0)
{
Mesh::GetShader()->FreeDescriptorSet(_csh);
_texAlbedo.Done();
_texNormal.Done();
VERUS_DONE(Material);
@ -290,8 +291,8 @@ void Material::LoadTextures(bool streamParts)
_texNormal.Done();
_texAlbedo.Init(_dict.Find("texAlbedo"), streamParts);
_texNormal.Init(_dict.Find("texNormal"), streamParts);
_texAlbedoEnable.w = 1;
_texNormalEnable.w = 1;
_texEnableAlbedo.w = 1;
_texEnableNormal.w = 1;
}
String Material::ToString()
@ -305,29 +306,25 @@ String Material::ToString()
_dict.Insert("alphaSwitch", /**/_C(Str::ToString(_alphaSwitch)));
_dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir)));
_dict.Insert("bushEffect", /**/_C(Str::ToString(_bushEffect)));
_dict.Insert("detail", /**/_C(Str::ToString(_detail)));
_dict.Insert("emitPick", /**/_C(_emitPick.ToString()));
_dict.Insert("emitXPick", /**/_C(_emitXPick.ToString()));
_dict.Insert("emission", /**/_C(Str::ToString(_emission)));
_dict.Insert("emissionPick", /**/_C(_emissionPick.ToString()));
_dict.Insert("eyePick", /**/_C(Str::ToString(_eyePick.ToPixels())));
_dict.Insert("gloss", /**/_C(Str::ToString(_gloss)));
_dict.Insert("glossX", /**/_C(Str::ToString(_glossX)));
_dict.Insert("glossXPick", /**/_C(_glossXPick.ToString()));
_dict.Insert("glossPick", /**/_C(_glossPick.ToString()));
_dict.Insert("glossScaleBias", /**/_C(Str::ToString(_glossScaleBias)));
_dict.Insert("hairDesat", /**/_C(Str::ToString(_hairDesat)));
_dict.Insert("hairPick", /**/_C(_hairPick.ToString()));
_dict.Insert("lamBias", /**/_C(Str::ToString(_lamBias)));
_dict.Insert("lamScale", /**/_C(Str::ToString(_lamScale)));
_dict.Insert("lamScaleBias", /**/_C(Str::ToString(_lamScaleBias)));
_dict.Insert("lightPass", /**/_C(Str::ToString(_lightPass)));
_dict.Insert("metalPick", /**/_C(_metalPick.ToString()));
_dict.Insert("parallaxDepth", /**/_C(Str::ToString(_parallaxDepth)));
_dict.Insert("skinPick", /**/_C(_skinPick.ToString()));
_dict.Insert("specBias", /**/_C(Str::ToString(_specBias)));
_dict.Insert("specScale", /**/_C(Str::ToString(_specScale)));
_dict.Insert("specScaleBias", /**/_C(Str::ToString(_specScaleBias)));
_dict.Insert("tc0ScaleBias", /**/_C(Str::ToString(_tc0ScaleBias)));
_dict.Insert("texAlbedo", /**/pTexAlbedo ? _C(pTexAlbedo->GetName()) : empty);
_dict.Insert("texAlbedoEnable", /**/_C(Str::ToColorString(_texAlbedoEnable)));
_dict.Insert("texEnableAlbedo", /**/_C(Str::ToColorString(_texEnableAlbedo)));
_dict.Insert("texNormal", /**/pTexNormal ? _C(pTexNormal->GetName()) : empty);
_dict.Insert("texNormalEnable", /**/_C(Str::ToColorString(_texNormalEnable, false)));
_dict.Insert("texEnableNormal", /**/_C(Str::ToColorString(_texEnableNormal, false)));
_dict.Insert("userColor", /**/_C(Str::ToColorString(_userColor)));
_dict.Insert("userPick", /**/_C(_userPick.ToString()));
@ -340,27 +337,23 @@ void Material::FromString(CSZ txt)
_alphaSwitch = Str::FromStringVec2(_dict.Find("alphaSwitch", "1 1"));
_anisoSpecDir = Str::FromStringVec2(_dict.Find("anisoSpecDir", "0 1"));
_bushEffect = Str::FromStringVec4(_dict.Find("bushEffect", "0 0 0 0"));
_detail = _dict.FindFloat("detail", 0);
_emitPick.FromString(_dict.Find("emitPick", "00000000"));
_emitXPick.FromString(_dict.Find("emitXPick", "00000000"));
_emission = _dict.FindFloat("emission", 0);
_emissionPick.FromString(_dict.Find("emissionPick", "00000000"));
_eyePick = Str::FromStringVec4(_dict.Find("eyePick", "0 0 0 0"));
_gloss = _dict.FindFloat("gloss", 10);
_glossX = _dict.FindFloat("glossX", 10);
_glossXPick.FromString(_dict.Find("glossXPick", "00000000"));
_glossPick.FromString(_dict.Find("glossPick", "00000000"));
_glossScaleBias = Str::FromStringVec2(_dict.Find("glossScaleBias", "1 0"));
_hairDesat = _dict.FindFloat("hairDesat", 0);
_hairPick.FromString(_dict.Find("hairPick", "00000000"));
_lamBias = _dict.FindFloat("lamBias", 0);
_lamScale = _dict.FindFloat("lamScale", 1);
_lamScaleBias = Str::FromStringVec2(_dict.Find("lamScaleBias", "1 0"));
_lightPass = _dict.FindFloat("lightPass", 1);
_metalPick.FromString(_dict.Find("metalPick", "00000000"));
_parallaxDepth = _dict.FindFloat("parallaxDepth", 0);
_skinPick.FromString(_dict.Find("skinPick", "00000000"));
_specBias = _dict.FindFloat("specBias", 0);
_specScale = _dict.FindFloat("specScale", 1);
_specScaleBias = Str::FromStringVec2(_dict.Find("specScaleBias", "1 0"));
_tc0ScaleBias = Str::FromStringVec4(_dict.Find("tc0ScaleBias", "1 1 0 0"));
_texAlbedoEnable = Str::FromColorString(_dict.Find("texAlbedoEnable", "80808000"));
_texNormalEnable = Str::FromColorString(_dict.Find("texNormalEnable", "8080FF00"), false);
_texEnableAlbedo = Str::FromColorString(_dict.Find("texEnableAlbedo", "80808000"));
_texEnableNormal = Str::FromColorString(_dict.Find("texEnableNormal", "8080FF00"), false);
_userColor = Str::FromColorString(_dict.Find("userColor", "00000000"));
_userPick.FromString(_dict.Find("userPick", "0 0 0 0"));
@ -372,7 +365,7 @@ void Material::BindDescriptorSetTextures()
VERUS_RT_ASSERT(!_csh.IsSet());
VERUS_RT_ASSERT(IsLoaded());
VERUS_QREF_MM;
_csh = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
_csh = Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
}
bool Material::UpdateMeshUniformBuffer(float motionBlur)
@ -381,29 +374,33 @@ bool Material::UpdateMeshUniformBuffer(float motionBlur)
Mesh::UB_PerMaterialFS ubPrev;
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
ub._texEnableAlbedo = _texAlbedoEnable;
ub._texEnableNormal = _texNormalEnable;
ub._skinPick = _skinPick;
ub._hairPick = _hairPick;
ub._emitPick = _emitPick;
ub._emitXPick = _emitXPick;
ub._metalPick = _metalPick;
ub._glossXPick = _glossXPick;
ub._alphaSwitch_anisoSpecDir = float4(_alphaSwitch, _anisoSpecDir);
ub._detail_emission_gloss_hairDesat.x = _detail;
ub._detail_emission_gloss_hairDesat.y = _emission;
ub._detail_emission_gloss_hairDesat.z = _gloss;
ub._detail_emission_gloss_hairDesat.w = _hairDesat;
ub._detailScale_strassScale = float4(1, 1, 1, 1);
ub._emissionPick = _emissionPick;
ub._eyePick = _eyePick;
ub._hairParams = glm::vec4(_anisoSpecDir, 0, _hairDesat);
ub._lsb_gloss_lp = glm::vec4(_lamScale, _lamBias, _gloss, _lightPass);
ub._ssb_as = glm::vec4(_specScale, _specBias, _alphaSwitch.x, _alphaSwitch.y);
ub._glossPick = _glossPick;
ub._glossScaleBias_specScaleBias = float4(_glossScaleBias, _specScaleBias);
ub._hairPick = _hairPick;
ub._lamScaleBias_lightPass_motionBlur = float4(_lamScaleBias, _lightPass, motionBlur);
ub._metalPick = _metalPick;
ub._skinPick = _skinPick;
ub._tc0ScaleBias = _tc0ScaleBias;
ub._texEnableAlbedo = _texEnableAlbedo;
ub._texEnableNormal = _texEnableNormal;
ub._userColor = _userColor;
ub._userPick = _userPick;
ub._ds_scale = glm::vec4(_detail, 1, 1, 1);
if (_texAlbedo)
{
ub._ds_scale = glm::vec4(_detail, 1,
ub._detailScale_strassScale = float4(
_texAlbedo->GetTex()->GetSize().getX() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4);
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getX() / 256 * 8,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 8);
}
ub._motionBlur_glossX.x = motionBlur;
ub._motionBlur_glossX.y = _glossX;
ub._bushEffect = _bushEffect;
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
}
@ -461,7 +458,7 @@ void MaterialManager::InitCmd()
_texDetail.Init("[Textures]:Detail.FX.dds", false, true);
_texStrass.Init("[Textures]:Strass.dds", false, true, &strassSamplerDesc);
_cshDefault = Scene::Mesh::GetShader()->BindDescriptorSetTextures(1,
_cshDefault = Mesh::GetShader()->BindDescriptorSetTextures(1,
{
_texDefaultAlbedo->GetTex(),
_texDefaultNormal->GetTex(),
@ -472,6 +469,7 @@ void MaterialManager::InitCmd()
void MaterialManager::Done()
{
Mesh::GetShader()->FreeDescriptorSet(_cshDefault);
_texStrass.Done();
_texDetail.Done();
_texDefaultNormal.Done();

View File

@ -66,21 +66,13 @@ namespace verus
colorFilter
};
struct Stats
{
int _shaderChangeCount = 0;
int _textureChangeCount = 0;
int _stateChangeCount = 0;
};
VERUS_TYPEDEFS(Stats);
class Pick : public glm::vec4
{
public:
Pick();
Pick(const glm::vec4& v);
void SetColor(float r, float g, float b);
void SetAmount(float x);
void SetAlpha(float x);
void FromString(CSZ sz);
String ToString();
};
@ -92,7 +84,7 @@ namespace verus
PickRound(const glm::vec4& v);
void SetUV(float u, float v);
void SetRadius(float r);
void SetAmount(float x);
void SetAlpha(float x);
glm::vec4 ToPixels() const;
void FromPixels(const glm::vec4& pix);
};
@ -101,29 +93,25 @@ namespace verus
IO::Dictionary _dict;
glm::vec2 _alphaSwitch = glm::vec2(1, 1);
glm::vec2 _anisoSpecDir = glm::vec2(0, 1);
glm::vec4 _bushEffect = glm::vec4(0);
float _detail = 0;
Pick _emitPick;
Pick _emitXPick;
float _emission = 0;
Pick _emissionPick;
PickRound _eyePick;
float _gloss = 10;
float _glossX = 10;
Pick _glossXPick;
Pick _glossPick;
glm::vec2 _glossScaleBias = glm::vec2(1, 0);
float _hairDesat = 0;
Pick _hairPick;
float _lamBias = 0;
float _lamScale = 1;
glm::vec2 _lamScaleBias = glm::vec2(1, 0);
float _lightPass = 1;
Pick _metalPick;
float _parallaxDepth = 0;
Pick _skinPick;
float _specBias = 0;
float _specScale = 1;
glm::vec2 _specScaleBias = glm::vec2(1, 0);
glm::vec4 _tc0ScaleBias = glm::vec4(1, 1, 0, 0);
TexturePwn _texAlbedo;
glm::vec4 _texAlbedoEnable = glm::vec4(0.5f, 0.5f, 0.5f, 1);
glm::vec4 _texEnableAlbedo = glm::vec4(0.5f, 0.5f, 0.5f, 1);
TexturePwn _texNormal;
glm::vec4 _texNormalEnable = glm::vec4(0.5f, 0.5f, 1.0f, 1);
glm::vec4 _texEnableNormal = glm::vec4(0.5f, 0.5f, 1.0f, 1);
glm::vec4 _userColor = glm::vec4(0, 0, 0, 0);
Pick _userPick;
Blending _blending = Blending::opaque;

View File

@ -68,6 +68,25 @@ void Mesh::Done()
VERUS_DONE(Mesh);
}
void Mesh::Draw(RcDrawDesc dd, CGI::CommandBufferPtr cb)
{
BindGeo(cb);
BindPipeline(cb, dd._allowTess);
UpdateUniformBufferPerFrame();
cb->BindDescriptors(Scene::Mesh::GetShader(), 0);
UpdateUniformBufferPerMaterialFS();
cb->BindDescriptors(Scene::Mesh::GetShader(), 1, dd._cshMaterial);
UpdateUniformBufferPerMeshVS();
cb->BindDescriptors(Scene::Mesh::GetShader(), 2);
UpdateUniformBufferSkeletonVS();
cb->BindDescriptors(Scene::Mesh::GetShader(), 3);
UpdateUniformBufferPerObject(dd._matW);
cb->BindDescriptors(Scene::Mesh::GetShader(), 4);
cb->DrawIndexed(GetIndexCount());
}
void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
{
VERUS_QREF_RENDERER;

View File

@ -66,6 +66,14 @@ namespace verus
};
VERUS_TYPEDEFS(Desc);
struct DrawDesc
{
Transform3 _matW = Transform3::identity();
CGI::CSHandle _cshMaterial;
bool _allowTess = true;
};
VERUS_TYPEDEFS(DrawDesc);
Mesh();
virtual ~Mesh();
@ -75,6 +83,8 @@ namespace verus
void Init(RcDesc desc = Desc());
void Done();
void Draw(RcDrawDesc dd, CGI::CommandBufferPtr cb);
void BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb);
void BindPipeline(CGI::CommandBufferPtr cb, bool allowTess = true);
void BindGeo(CGI::CommandBufferPtr cb);

View File

@ -22,6 +22,10 @@ void SceneManager::Done()
VERUS_DONE(SceneManager);
}
void SceneManager::UpdateParts()
{
}
bool SceneManager::IsDrawingDepth(DrawDepth dd)
{
if (DrawDepth::automatic == dd)
@ -32,3 +36,82 @@ bool SceneManager::IsDrawingDepth(DrawDepth dd)
else
return DrawDepth::yes == dd;
}
bool SceneManager::RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock,
PPoint3 pPoint, PVector3 pNormal, const float* pRadius, Physics::Group mask)
{
//VERUS_RT_ASSERT(!pBlock || *pBlock);
VERUS_QREF_BULLET;
btVector3 from(pointA.Bullet()), to(pointB.Bullet());
if (pPoint || pNormal)
{
if (pRadius)
{
btSphereShape sphere(*pRadius);
btTransform trA, trB;
trA.setIdentity();
trB.setIdentity();
trA.setOrigin(pointA.Bullet());
trB.setOrigin(pointB.Bullet());
btCollisionWorld::ClosestConvexResultCallback ccrc(from, to);
ccrc.m_collisionFilterMask = +mask;
bullet.GetWorld()->convexSweepTest(&sphere, trA, trB, ccrc);
if (ccrc.hasHit())
{
Physics::PUserPtr p = static_cast<Physics::PUserPtr>(ccrc.m_hitCollisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
if (pPoint)
*pPoint = ccrc.m_hitPointWorld;
if (pNormal)
*pNormal = ccrc.m_hitNormalWorld;
return true;
}
else
return false;
}
else
{
btCollisionWorld::ClosestRayResultCallback crrc(from, to);
crrc.m_collisionFilterMask = +mask;
bullet.GetWorld()->rayTest(from, to, crrc);
if (crrc.hasHit())
{
Physics::PUserPtr p = static_cast<Physics::PUserPtr>(crrc.m_collisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
if (pPoint)
*pPoint = crrc.m_hitPointWorld;
if (pNormal)
*pNormal = crrc.m_hitNormalWorld;
return true;
}
else
return false;
}
}
else // Point/normal not required?
{
struct AnyRayResultCallback : public btCollisionWorld::RayResultCallback
{
btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
{
m_closestHitFraction = 0;
m_collisionObject = rayResult.m_collisionObject;
return 0;
}
} arrc;
arrc.m_collisionFilterMask = +mask;
bullet.GetWorld()->rayTest(from, to, arrc);
if (arrc.hasHit())
{
Physics::PUserPtr p = static_cast<Physics::PUserPtr>(arrc.m_collisionObject->getUserPointer());
//if (pBlock && p->UserPtr_GetType() == +NodeType::block)
// pBlock->Attach(static_cast<PBlock>(p));
return true;
}
else
return false;
}
return false;
}

View File

@ -24,6 +24,8 @@ namespace verus
void Init();
void Done();
void UpdateParts();
// Camera:
PCamera GetCamera() const { return _pCamera; }
PCamera SetCamera(PCamera p) { return Utils::Swap(_pCamera, p); }
@ -31,6 +33,10 @@ namespace verus
PMainCamera SetCamera(PMainCamera p) { _pCamera = p; return Utils::Swap(_pMainCamera, p); }
static bool IsDrawingDepth(DrawDepth dd);
bool RayCastingTest(RcPoint3 pointA, RcPoint3 pointB, void* pBlock = nullptr,
PPoint3 pPoint = nullptr, PVector3 pNormal = nullptr, const float* pRadius = nullptr,
Physics::Group mask = Physics::Group::immovable | Physics::Group::terrain);
};
VERUS_TYPEDEFS(SceneManager);
}

View File

@ -76,7 +76,7 @@ void ShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar)
_camera.SetUpDirection(up);
_camera.MoveAtTo(at);
_camera.MoveEyeTo(eye);
_camera.SetFOV(0);
_camera.SetFovY(0);
_camera.SetZNear(zNear);
_camera.SetZFar(zFar);
_camera.SetWidth(size);
@ -245,7 +245,7 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
float zNearFrustum, zFarFrustum;
const float closerToLight = 1500;
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
const float maxRange = (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra) ? 850 : 350;
const float maxRange = (settings._sceneShadowQuality >= App::Settings::ShadowQuality::ultra) ? 850.f : 350.f;
const float range = Math::Min<float>(maxRange, cam.GetZFar() - cam.GetZNear()); // Clip terrain, etc.
_camera = cam;
@ -269,14 +269,14 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
sideW = static_cast<int>(frustumBounds.getZ() - frustumBounds.getX() + 2.5f);
sideH = static_cast<int>(frustumBounds.getW() - frustumBounds.getY() + 2.5f);
sizeW = sideW;
sizeH = sideH;
sizeW = static_cast<float>(sideW);
sizeH = static_cast<float>(sideH);
// Setup CSM light space camera for full range (used for terrain layout, etc.):
_cameraCSM.SetUpDirection(up);
_cameraCSM.MoveAtTo(at);
_cameraCSM.MoveEyeTo(eye);
_cameraCSM.SetFOV(0);
_cameraCSM.SetFovY(0);
_cameraCSM.SetZNear(zNear);
_cameraCSM.SetZFar(zFar);
_cameraCSM.SetWidth(sizeW);
@ -325,13 +325,13 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
{
side = (sideW < sideH) ? sideH : sideW;
side = Math::NextPowerOfTwo(side);
sizeW = side;
sizeH = side;
sizeW = static_cast<float>(side);
sizeH = static_cast<float>(side);
}
else
{
sizeW = sideW;
sizeH = sideH;
sizeW = static_cast<float>(sideW);
sizeH = static_cast<float>(sideH);
}
if (_snapToTexels)
@ -353,7 +353,7 @@ void CascadedShadowMap::Begin(RcVector3 dirToSun, float zNear, float zFar, int s
_camera.SetUpDirection(up);
_camera.MoveAtTo(at);
_camera.MoveEyeTo(eye);
_camera.SetFOV(0);
_camera.SetFovY(0);
_camera.SetZNear(zNear);
_camera.SetZFar(zFar);
_camera.SetWidth(sizeW);

View File

@ -407,6 +407,7 @@ void Terrain::InitStatic()
CGI::Sampler::linearMipN, // Normal
CGI::Sampler::linearMipN, // Blend
CGI::Sampler::linearMipN, // Layers
CGI::Sampler::shadow
}, CGI::ShaderStageFlags::fs);
s_shader[SHADER_SIMPLE]->CreatePipelineLayout();
}
@ -482,7 +483,7 @@ void Terrain::Init(RcDesc desc)
VERUS_FOR(lod, 5)
{
VERUS_P_FOR(i, _vPatches.size())
VERUS_P_FOR(i, Utils::Cast32(_vPatches.size()))
{
_vPatches[i].UpdateNormals(this, lod);
});
@ -602,8 +603,11 @@ void Terrain::Init(RcDesc desc)
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshVS);
_cshVS = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(0, { _tex[TEX_HEIGHTMAP], _tex[TEX_NORMALS] });
s_shader[SHADER_SIMPLE]->FreeDescriptorSet(_cshSimpleVS);
_cshSimpleVS = s_shader[SHADER_SIMPLE]->BindDescriptorSetTextures(0, { _tex[TEX_HEIGHTMAP], _tex[TEX_NORMALS] });
_vBlendBuffer.resize(_mapSide * _mapSide);
VERUS_P_FOR(i, _vBlendBuffer.size())
VERUS_P_FOR(i, Utils::Cast32(_vBlendBuffer.size()))
{
_vBlendBuffer[i] = VERUS_COLOR_RGBA(255, 0, 0, 255);
});
@ -616,8 +620,33 @@ void Terrain::Init(RcDesc desc)
_vLayerUrls.reserve(s_maxLayers);
}
void Terrain::InitByWater()
{
VERUS_QREF_WATER;
{
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);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._primitiveRestartEnable = true;
_pipe[PIPE_REFLECTION_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);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc._primitiveRestartEnable = true;
_pipe[PIPE_UNDERWATER_STRIP].Init(pipeDesc);
}
}
void Terrain::Done()
{
s_shader[SHADER_SIMPLE]->FreeDescriptorSet(_cshSimpleVS);
s_shader[SHADER_SIMPLE]->FreeDescriptorSet(_cshSimpleFS);
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshVS);
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshFS);
@ -640,7 +669,6 @@ void Terrain::Layout()
std::for_each(_vPatches.begin(), _vPatches.end(), [](RTerrainPatch patch) {patch._quadtreeLOD = -1; });
PCamera pPrevCamera = nullptr;
Camera cam;
// For CSM we need to create geometry beyond the view frustum (1st slice):
if (settings._sceneShadowQuality >= App::Settings::ShadowQuality::cascaded && atmo.GetShadowMap().IsRendering())
{
@ -775,6 +803,100 @@ void Terrain::Draw(RcDrawDesc dd)
void Terrain::DrawReflection()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_WATER;
if (!_visiblePatchCount)
return;
auto cb = renderer.GetCommandBuffer();
const Transform3 matW = Transform3::identity();
s_ubSimpleTerrainVS._matW = matW.UniformBufferFormat();
s_ubSimpleTerrainVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubSimpleTerrainVS._eyePos = float4(atmo.GetEyePosition().GLM(), 0);
s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.x = 1.f / _mapSide;
s_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.y = static_cast<float>(water.IsUnderwater() ? USHRT_MAX : 0);
VERUS_FOR(i, VERUS_COUNT_OF(_layerData))
s_ubSimpleTerrainFS._vSpecStrength[i >> 2][i & 0x3] = _layerData[i]._specStrength;
s_ubSimpleTerrainFS._lamScaleBias.x = _lamScale;
s_ubSimpleTerrainFS._lamScaleBias.y = _lamBias;
s_ubSimpleTerrainFS._ambientColor = float4(atmo.GetAmbientColor().GLM(), 0);
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();
memcpy(&s_ubSimpleTerrainFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubSimpleTerrainFS._shadowConfig));
s_ubSimpleTerrainFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);
bool bindStrip = true;
const int half = _mapSide >> 1;
int firstInstance = 0;
int edge = _visiblePatchCount - 1;
int lod = _vPatches[_vSortedPatchIndices.front()]._quadtreeLOD;
s_shader[SHADER_SIMPLE]->BeginBindDescriptors();
VERUS_FOR(i, _visiblePatchCount)
{
RcTerrainPatch patch = _vPatches[_vSortedPatchIndices[i]];
if (patch._quadtreeLOD != lod || i == edge)
{
if (i == edge)
i++; // Drawing patches [firstInstance, i).
if (!lod)
{
if (water.IsUnderwater())
cb->BindPipeline(_pipe[PIPE_UNDERWATER_LIST]);
else
cb->BindPipeline(_pipe[PIPE_REFLECTION_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]);
else
cb->BindPipeline(_pipe[PIPE_REFLECTION_STRIP]);
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 0, _cshSimpleVS);
cb->BindDescriptors(s_shader[SHADER_SIMPLE], 1, _cshSimpleFS);
}
const int instanceCount = i - firstInstance; // Drawing patches [firstInstance, i).
for (int inst = firstInstance; inst < i; ++inst)
{
const int at = _instanceCount + inst;
RcTerrainPatch patchToDraw = _vPatches[_vSortedPatchIndices[inst]];
_vInstanceBuffer[at]._posPatch[0] = patchToDraw._ijCoord[1] - half;
_vInstanceBuffer[at]._posPatch[1] = patchToDraw._patchHeight;
_vInstanceBuffer[at]._posPatch[2] = patchToDraw._ijCoord[0] - half;
_vInstanceBuffer[at]._posPatch[3] = 0;
VERUS_ZERO_MEM(_vInstanceBuffer[at]._layers);
VERUS_FOR(ch, 4)
_vInstanceBuffer[at]._layers[ch] = patchToDraw._layerForChannel[ch];
}
cb->DrawIndexed(_lods[lod]._indexCount, instanceCount, _lods[lod]._firstIndex, 0, _instanceCount + firstInstance);
lod = patch._quadtreeLOD;
firstInstance = i;
}
}
s_shader[SHADER_SIMPLE]->EndBindDescriptors();
_instanceCount += _visiblePatchCount;
_geo->UpdateVertexBuffer(_vInstanceBuffer.data(), 1);
}
void Terrain::ResetInstanceCount()
@ -1022,6 +1144,7 @@ void Terrain::LoadLayerTextures()
VERUS_QREF_MM;
VERUS_QREF_RENDERER;
VERUS_QREF_ATMO;
renderer->WaitIdle();
@ -1058,6 +1181,8 @@ void Terrain::LoadLayerTextures()
s_shader[SHADER_MAIN]->FreeDescriptorSet(_cshFS);
_cshFS = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(1, { _tex[TEX_NORMALS], _tex[TEX_BLEND], _tex[TEX_LAYERS], _tex[TEX_LAYERS_NM], mm.GetDetailTexture() });
s_shader[SHADER_SIMPLE]->FreeDescriptorSet(_cshSimpleFS);
_cshSimpleFS = s_shader[SHADER_SIMPLE]->BindDescriptorSetTextures(1, { _tex[TEX_NORMALS], _tex[TEX_BLEND], _tex[TEX_LAYERS], atmo.GetShadowMap().GetTexture() });
}
int Terrain::GetMainLayerAt(const int ij[2]) const
@ -1124,8 +1249,9 @@ void Terrain::UpdateHeightmapTexture()
VERUS_FOR(j, side)
{
const int ij[] = { i * step, j * step };
const float bestPrecision = 50;
_vHeightmapSubresData[offset + j] = glm::packHalf1x16(GetHeightAt(ij, 0) - bestPrecision);
short h;
GetHeightAt(ij, 0, &h);
_vHeightmapSubresData[offset + j] = glm::packHalf1x16(h);
}
});
_tex[TEX_HEIGHTMAP]->UpdateSubresource(_vHeightmapSubresData.data(), lod);
@ -1151,10 +1277,10 @@ void Terrain::UpdateNormalsTexture()
memcpy(tan, GetNormalAt(ij, 0, TerrainTBN::tangent), 3);
BYTE rgba[4] =
{
nrm[0] + 127,
nrm[2] + 127,
tan[1] + 127,
tan[2] + 127
static_cast<BYTE>(nrm[0] + 127),
static_cast<BYTE>(nrm[2] + 127),
static_cast<BYTE>(tan[1] + 127),
static_cast<BYTE>(tan[2] + 127)
};
memcpy(&_vNormalsSubresData[(i << _mapShift) + j], rgba, sizeof(UINT32));
}
@ -1236,7 +1362,7 @@ void Terrain::Serialize(IO::RSeekableStream stream)
}
// Texture names:
BYTE layerCount = _vLayerUrls.size();
BYTE layerCount = Utils::Cast32(_vLayerUrls.size());
stream << layerCount;
VERUS_FOR(i, layerCount)
{

View File

@ -98,6 +98,10 @@ namespace verus
PIPE_WIREFRAME_LIST,
PIPE_WIREFRAME_STRIP,
PIPE_TESS,
PIPE_REFLECTION_LIST,
PIPE_REFLECTION_STRIP,
PIPE_UNDERWATER_LIST,
PIPE_UNDERWATER_STRIP,
PIPE_COUNT
};
@ -155,6 +159,8 @@ namespace verus
int _visiblePatchCount = 0;
CGI::CSHandle _cshVS;
CGI::CSHandle _cshFS;
CGI::CSHandle _cshSimpleVS;
CGI::CSHandle _cshSimpleFS;
TerrainLOD _lods[5]; // Level of detail data for (16x16, 8x8, 4x4, 2x2, 1x1).
LayerData _layerData[s_maxLayers];
TerrainPhysics _physics;
@ -194,6 +200,7 @@ namespace verus
static void DoneStatic();
void Init(RcDesc desc = Desc());
void InitByWater();
void Done();
void Layout();

View File

@ -47,14 +47,19 @@ void Water::Init(RTerrain terrain)
_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubWaterVS, sizeof(s_ubWaterVS), 100,
{
CGI::Sampler::linearClampMipL,
CGI::Sampler::linearMipL
CGI::Sampler::linearMipL,
CGI::Sampler::linearMipN
}, CGI::ShaderStageFlags::vs);
_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubWaterFS, sizeof(s_ubWaterFS), 100,
{
CGI::Sampler::linearClampMipL,
CGI::Sampler::linearMipL,
CGI::Sampler::custom,
CGI::Sampler::aniso
CGI::Sampler::linearClampMipL, // TerrainHeightmap
CGI::Sampler::linearMipL, // GenHeightmap
CGI::Sampler::custom, // GenNormals
CGI::Sampler::aniso, // Foam
CGI::Sampler::linearClampMipL, // Reflection
CGI::Sampler::linearClampMipN, // Refraction
CGI::Sampler::shadow,
CGI::Sampler::nearestMipN
}, CGI::ShaderStageFlags::fs);
_shader[SHADER_MAIN]->CreatePipelineLayout();
@ -66,7 +71,7 @@ void Water::Init(RTerrain terrain)
Vector<UINT16> vIndices;
Math::CreateStripGrid(_gridWidth - 1, _gridHeight - 1, vIndices);
_indexCount = vIndices.size();
_indexCount = Utils::Cast32(vIndices.size());
CGI::GeometryDesc geoDesc;
const CGI::VertexInputAttrDesc viaDesc[] =
@ -79,15 +84,16 @@ void Water::Init(RTerrain terrain)
geoDesc._pStrides = strides;
_geo.Init(geoDesc);
_geo->CreateVertexBuffer(_gridWidth * _gridHeight, 0);
_geo->CreateIndexBuffer(vIndices.size());
_geo->CreateIndexBuffer(Utils::Cast32(vIndices.size()));
_geo->UpdateIndexBuffer(vIndices.data());
CreateWaterPlane();
{
CGI::PipelineDesc pipeDesc(_geo, _shader[SHADER_MAIN], "#0", renderer.GetDS().GetRenderPassHandle_Compose(), renderer.GetDS().GetSubpass_Compose());
CGI::PipelineDesc pipeDesc(_geo, _shader[SHADER_MAIN], "#0", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
//pipeDesc._rasterizationState._polygonMode = CGI::PolygonMode::line;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
_pipe[PIPE_MAIN].Init(pipeDesc);
}
@ -106,13 +112,15 @@ void Water::Init(RTerrain terrain)
CGI::TextureDesc texDesc;
texDesc._url = "[Textures]:Water/Foam.dds";
texDesc._flags = CGI::TextureDesc::Flags::anyShaderResource;
_tex[TEX_FOAM].Init(texDesc);
texDesc.Reset();
texDesc._url = "[Textures]:Water/Heightmap.FX.dds";
_tex[TEX_SOURCE_HEIGHTMAP].Init(texDesc);
CGI::SamplerDesc normalsSamplerDesc;
normalsSamplerDesc.SetFilter("a");
normalsSamplerDesc.SetFilter("ll");
normalsSamplerDesc.SetAddressMode("rr");
normalsSamplerDesc._mipLodBias = 0.5f;
normalsSamplerDesc._minLod = 1;
@ -131,17 +139,19 @@ void Water::Init(RTerrain terrain)
_fbhGenHeightmap = renderer->CreateFramebuffer(_rphGenHeightmap, { _tex[TEX_GEN_HEIGHTMAP] }, _genSide, _genSide);
_fbhGenNormals = renderer->CreateFramebuffer(_rphGenNormals, { _tex[TEX_GEN_NORMALS] }, _genSide, _genSide);
_cshWaterVS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(0, { _pTerrain->GetHeightmapTexture(), _tex[TEX_GEN_HEIGHTMAP] });
_shader[SHADER_GEN]->FreeDescriptorSet(_cshGenNormals);
_cshGenNormals = _shader[SHADER_GEN]->BindDescriptorSetTextures(2, { _tex[TEX_GEN_HEIGHTMAP] });
texDesc.Reset();
texDesc._format = CGI::Format::floatR11G11B10;
texDesc._width = settings._screenSizeWidth;
texDesc._height = settings._screenSizeHeight;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
texDesc._width = 1024;
texDesc._height = 512;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips;
_tex[TEX_REFLECTION].Init(texDesc);
texDesc._clearValue = Vector4(1);
texDesc._format = CGI::Format::unormD24uintS8;
texDesc._mipLevels = 1;
texDesc._flags = CGI::TextureDesc::Flags::none;
_tex[TEX_REFLECTION_DEPTH].Init(texDesc);
@ -153,32 +163,24 @@ void Water::Init(RTerrain terrain)
texDesc._width,
texDesc._height);
// Texture for rendering reflection onto:
/*
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::simpleReflection)
{
texDesc.Reset();
texDesc._format = CGI::Format::unormR8G8B8A8;
texDesc._width = 512;
texDesc._height = 512;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::generateMips;
_tex[TEX_REFLECT].Init(texDesc);
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction)
_tex[TEX_REFRACT].Init(texDesc);
texDesc._format = CGI::Format::unormD16;
_tex[TEX_REFLECT_DEPTH].Init(texDesc);
}
*/
VERUS_FOR(i, s_maxHarmonics)
_amplitudes[i] = PhillipsSpectrum(0.5f + i / 2.f);
_pTerrain->InitByWater();
}
void Water::Done()
{
if (_shader[SHADER_GEN])
{
_shader[SHADER_GEN]->FreeDescriptorSet(_cshGenNormals);
_shader[SHADER_GEN]->FreeDescriptorSet(_cshGenHeightmap);
}
if (_shader[SHADER_MAIN])
{
_shader[SHADER_MAIN]->FreeDescriptorSet(_cshWaterFS);
_shader[SHADER_MAIN]->FreeDescriptorSet(_cshWaterVS);
}
VERUS_DONE(Water);
}
@ -187,36 +189,27 @@ void Water::Update()
VERUS_UPDATE_ONCE_CHECK;
VERUS_QREF_TIMER;
_phase = fmod(_phase + dt * (1 / 29.f), 1.f);
_phaseWave = fmod(_phaseWave + dt * (1 / 61.f), 1.f);
_phase = fmod(_phase + dt * (1 / 23.f), 1.f);
_wavePhase = fmod(_wavePhase + dt * (1 / 29.f), 1.f);
}
void Water::Draw()
{
VERUS_UPDATE_ONCE_CHECK_DRAW;
if (!_cshWaterFS.IsSet())
{
if (_tex[TEX_FOAM]->IsLoaded())
{
_cshWaterFS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(1,
{
_pTerrain->GetHeightmapTexture(),
_tex[TEX_GEN_HEIGHTMAP],
_tex[TEX_GEN_NORMALS],
_tex[TEX_FOAM]
});
}
else
return;
}
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_TIMER;
VERUS_QREF_ATMO;
if (!_cshWaterFS.IsSet())
{
OnSwapChainResized();
if (!_cshWaterFS.IsSet())
return;
}
auto cb = renderer.GetCommandBuffer();
RCamera cam = *sm.GetCamera();
@ -235,19 +228,41 @@ void Water::Draw()
const Matrix3 matR = Matrix3::rotationY(angle);
matW = Transform3(matR, Vector3(eyePosAtGroundLevel - flatDir * 5 * abs(cam.GetFrontDirection().getY())));
const Transform3 matShift = Transform3::translation(Vector3(0, -0.01f, 0)); // Sky-waterline bleeding fix.
const Matrix4 matWVP = cam.GetMatrixVP() * matW;
const Matrix4 matScreen = Matrix4(Math::ToUVMatrix()) * matShift * cam.GetMatrixVP();
s_ubWaterVS._matW = matW.UniformBufferFormat();
s_ubWaterVS._matVP = cam.GetMatrixVP().UniformBufferFormat();
s_ubWaterVS._eyePos = float4(cam.GetEyePosition().GLM(), 0);
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.x = 1 / _patchSide;
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.y = Math::ComputeDistToMipScale(_genSide << 6, renderer.GetSwapChainHeight(), _patchSide, cam.GetFOV());
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.z = 1.f / _pTerrain->GetMapSide();
s_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.w = Math::ComputeDistToMipScale(_pTerrain->GetMapSide(), renderer.GetSwapChainHeight(), _pTerrain->GetMapSide(), cam.GetFOV());
s_ubWaterVS._matScreen = matScreen.UniformBufferFormat();
s_ubWaterVS._eyePos_mapSideInv = float4(cam.GetEyePosition().GLM(), 1.f / _pTerrain->GetMapSide());
s_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.x = 1 / _patchSide;
s_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.y =
Math::ComputeDistToMipScale(static_cast<float>(_genSide << 6), static_cast<float>(renderer.GetSwapChainHeight()), _patchSide, cam.GetFovY());
s_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.z =
Math::ComputeDistToMipScale(static_cast<float>(_pTerrain->GetMapSide()), static_cast<float>(renderer.GetSwapChainHeight()), static_cast<float>(_pTerrain->GetMapSide()), cam.GetFovY());
s_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.w = _wavePhase;
s_ubWaterFS._phase.x = _phase;
s_ubWaterFS._matV = cam.GetMatrixV().UniformBufferFormat();
s_ubWaterFS._phase_wavePhase_camScale.x = _phase;
s_ubWaterFS._phase_wavePhase_camScale.y = _wavePhase;
s_ubWaterFS._phase_wavePhase_camScale.z = cam.GetFovScale() / cam.GetAspectRatio();
s_ubWaterFS._phase_wavePhase_camScale.w = -cam.GetFovScale();
s_ubWaterFS._diffuseColorShallow = float4(_diffuseColorShallow.GLM(), 0);
s_ubWaterFS._diffuseColorDeep = float4(_diffuseColorDeep.GLM(), 0);
s_ubWaterFS._ambientColor = float4(atmo.GetAmbientColor().GLM(), 0);
if (IsUnderwater())
s_ubWaterFS._fogColor = Vector4(VMath::mulPerElem(_diffuseColorShallow, atmo.GetAmbientColor()) * 0.1f, _fogDensity).GLM();
else
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();
memcpy(&s_ubWaterFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubWaterFS._shadowConfig));
s_ubWaterFS._splitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);
@ -258,115 +273,44 @@ void Water::Draw()
cb->BindDescriptors(_shader[SHADER_MAIN], 1, _cshWaterFS);
cb->DrawIndexed(_indexCount);
_shader[SHADER_MAIN]->EndBindDescriptors();
}
//ms_cbPerObject.matWVP = matWVP.ConstBufferFormat();
//ms_cbPerObject.matW = matW.ConstBufferFormat();
//ms_cbPerObject.matV = cam.GetMatrixV().ConstBufferFormat();
void Water::OnSwapChainResized()
{
if (!_tex[TEX_FOAM]->IsLoaded())
return;
if (false)
{
//_sb[SB_DEPTH]->Apply(sbad);
VERUS_QREF_RENDERER;
VERUS_QREF_ATMO;
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
_shader[SHADER_MAIN]->FreeDescriptorSet(_cshWaterFS);
_shader[SHADER_MAIN]->FreeDescriptorSet(_cshWaterVS);
_cshWaterVS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(0, { _pTerrain->GetHeightmapTexture(), _tex[TEX_GEN_HEIGHTMAP], _tex[TEX_FOAM] });
_cshWaterFS = _shader[SHADER_MAIN]->BindDescriptorSetTextures(1,
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP] }, 0 + VERUS_ST_VS_OFFSET);
//renderer->SetTextures({ _texLand }, 5 + VERUS_ST_VS_OFFSET);
}
//_s->Bind("TDepth");
//_s->UpdateBuffer(0);
//_geo->BeginDraw(0x1);
//renderer->DrawIndexedPrimitive(CGI::PT_TRIANGLESTRIP, 0, _indexCount);
//_geo->EndDraw(0x1);
}
else
{
VERUS_QREF_ATMO;
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction) // True refraction:
{
//renderer->StretchRect(m_tex[TEX_REFRACT], renderer.GetOffscreenColorTexture());
//_tex[TEX_REFRACT]->GenerateMipmaps();
}
//renderer->SetRenderTargets({ renderer.GetOffscreenColorTexture(), renderer.GetDS().GetGBuffer(1) }, renderer.GetOffscreenDepthTexture());
//_sb[SB_MASTER]->Apply(sbad);
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP] }, 0 + VERUS_ST_VS_OFFSET);
//renderer->SetTextures({ _texLand }, 5 + VERUS_ST_VS_OFFSET);
}
Matrix4 matTexSpace = Matrix4::identity();
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::solidColor)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP_BASE] });
//renderer->SetTextures({ _tex[TEX_FOAM] }, 2);
//renderer->SetTextures({ _texLand }, 5);
//renderer->SetTextures({ atmo.GetSunShadowTexture() }, 6);
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::simpleReflection)
{
//renderer->SetTextures({ _tex[TEX_REFLECT] }, 3);
const Transform3 matShift = Transform3::translation(Vector3(0, -0.01f, 0)); // Sky-waterline bleeding fix.
//matTexSpace = Matrix4(Math::ToUVMatrix(0, Math::TOUV_RENDER_TARGET_VFLIP | Math::TOUV_MAP_TEXELS_TO_PIXELS, _tex[TEX_REFLECT]->GetSize()) * matShift) * matWVP;
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesReflection)
{
//renderer->SetTextures({ _tex[TEX_HEIGHTMAP], _tex[TEX_NORMALMAP] });
}
if (settings._sceneWaterQuality >= App::Settings::WaterQuality::trueWavesRefraction)
{
//renderer->SetTextures({ _tex[TEX_REFRACT] }, 4);
}
//ms_cbPerFrame.matReflect = matTexSpace.ConstBufferFormat();
//ms_cbPerFrame.shadowTexSize = atmo.GetSunShadowTexture() ? atmo.GetSunShadowTexture()->GetSize() : CVector4(0);
//ms_cbPerFrame.matSunShadow = atmo.GetSunShadowMatrix(0).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM1 = atmo.GetSunShadowMatrix(1).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM2 = atmo.GetSunShadowMatrix(2).ConstBufferFormat();
//ms_cbPerFrame.matSunShadowCSM3 = atmo.GetSunShadowMatrix(3).ConstBufferFormat();
//ms_cbPerFrame.csmParams = atmo.GetParamsCSM();
//ms_cbPerFrame.phases_mapSideInv.x = _phase;
//ms_cbPerFrame.phases_mapSideInv.y = _phaseWave;
//ms_cbPerFrame.phases_mapSideInv.z = 1.f / _mapSide;
//ms_cbPerFrame.eyePos = cam.GetPositionEye();
//ms_cbPerFrame.colorAmbient = atmo.GetAmbientColor();
//ms_cbPerFrame.dirToSun = atmo.GetDirToSun();
//ms_cbPerFrame.colorSun = atmo.GetSunColor();
//ms_cbPerFrame.colorSunSpec = atmo.GetSunColor();
//ms_cbPerFrame.fogColor = atmo.GetFogColor();
//char tech[8];
//sprintf_s(tech, "T_%d", settings._sceneWaterQuality);
//_s->Bind(tech);
//_s->UpdateBuffer(0);
//_s->UpdateBuffer(1);
//_geo->BeginDraw(0x1);
//renderer->DrawIndexedPrimitive(CGI::PT_TRIANGLESTRIP, 0, _indexCount);
//_geo->EndDraw(0x1);
}
///renderer->SetTextures({ nullptr }, 0 + VERUS_ST_VS_OFFSET);
//renderer.DrawQuad(m_tex[HTEX_HEIGHTMAP]);
_pTerrain->GetHeightmapTexture(),
_tex[TEX_GEN_HEIGHTMAP],
_tex[TEX_GEN_NORMALS],
_tex[TEX_FOAM],
_tex[TEX_REFLECTION],
renderer.GetDS().GetComposedTextureB(),
atmo.GetShadowMap().GetTexture(),
atmo.GetShadowMap().GetTexture(),
});
}
void Water::BeginReflection(CGI::PBaseCommandBuffer pCB)
{
VERUS_QREF_SM;
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
_reflectionMode = sm.GetCamera()->GetEyePosition().getY() >= 0;
_renderToTexture = true;
_camera = *sm.GetCamera();
if (!IsUnderwater(_camera.GetEyePosition()))
_camera.EnableReflectionMode();
_pSceneCamera = sm.SetCamera(&_camera);
pCB->BeginRenderPass(_rphReflection, _fbhReflection,
{
@ -378,14 +322,16 @@ void Water::BeginReflection(CGI::PBaseCommandBuffer pCB)
void Water::EndReflection(CGI::PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
if (!pCB)
pCB = &(*renderer.GetCommandBuffer());
pCB->EndRenderPass();
_reflectionMode = false;
_renderToTexture = false;
sm.SetCamera(_pSceneCamera);
_tex[TEX_REFLECTION]->GenerateMips();
}
void Water::GenerateTextures()
@ -393,7 +339,10 @@ void Water::GenerateTextures()
if (!_cshGenHeightmap.IsSet())
{
if (_tex[TEX_SOURCE_HEIGHTMAP]->IsLoaded())
{
_shader[SHADER_GEN]->FreeDescriptorSet(_cshGenHeightmap);
_cshGenHeightmap = _shader[SHADER_GEN]->BindDescriptorSetTextures(1, { _tex[TEX_SOURCE_HEIGHTMAP] });
}
else
return;
}
@ -426,7 +375,7 @@ void Water::GenerateHeightmapTexture()
cb->EndRenderPass();
_tex[TEX_GEN_HEIGHTMAP]->GenerateMips();
_tex[TEX_GEN_HEIGHTMAP]->GenerateMips(&(*cb));
}
void Water::GenerateNormalsTexture()
@ -453,7 +402,7 @@ void Water::GenerateNormalsTexture()
cb->EndRenderPass();
_tex[TEX_GEN_NORMALS]->GenerateMips();
_tex[TEX_GEN_NORMALS]->GenerateMips(&(*cb));
}
CGI::TexturePtr Water::GetCausticsTexture() const
@ -479,15 +428,16 @@ void Water::CreateWaterPlane()
Vector<glm::vec4> vVB;
vVB.resize(_gridWidth * _gridHeight);
const float maxAngle = atan(maxRadius / 10); // Assume best height is 10 meters.
const float fudgeFactor = 100;
const float maxAngle = atan(maxRadius / fudgeFactor);
VERUS_FOR(i, _gridHeight)
{
const float radius = tan(zPolar * maxAngle) * 10;
const float radius = tan(zPolar * maxAngle) * fudgeFactor;
VERUS_FOR(j, _gridWidth)
{
float xSqueeze = xPolar;
VERUS_FOR(k, 6)
xSqueeze = Math::EaseInOutSine(xSqueeze);
xSqueeze = glm::sineEaseInOut(xSqueeze);
xSqueeze = Math::Lerp(xSqueeze, xPolar, 0.2f);
const float xCartesian = radius * sin(xSqueeze * VERUS_2PI);
@ -511,3 +461,15 @@ float Water::PhillipsSpectrum(float k)
const float k2 = k * k;
return exp(-1 / (kl * kl)) / (k2 * k2);
}
bool Water::IsUnderwater() const
{
return _pSceneCamera ?
IsUnderwater(_pSceneCamera->GetEyePosition()) :
IsUnderwater(SceneManager::I().GetCamera()->GetEyePosition());
}
bool Water::IsUnderwater(RcPoint3 eyePos) const
{
return eyePos.getY() < 0;
}

View File

@ -54,13 +54,13 @@ namespace verus
static UB_GenHeightmapFS s_ubGenHeightmapFS;
static UB_GenNormalsFS s_ubGenNormalsFS;
Vector3 _diffuseColorShallow = Vector3(0.02f, 0.42f, 0.52f);
Vector3 _diffuseColorDeep = Vector3(0.01f, 0.01f, 0.06f);
PTerrain _pTerrain = nullptr;
Vector<Vertex> _vSwapBuffer;
CGI::GeometryPwn _geo;
CGI::ShaderPwns<SHADER_COUNT> _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::TexturePtr _texLand;
CGI::CSHandle _cshWaterVS;
CGI::CSHandle _cshWaterFS;
CGI::RPHandle _rphGenHeightmap;
@ -71,18 +71,17 @@ namespace verus
CGI::CSHandle _cshGenNormals;
CGI::RPHandle _rphReflection;
CGI::FBHandle _fbhReflection;
Camera _camera;
PCamera _pSceneCamera = nullptr;
const int _genSide = 1024;
const int _sideReflect = 256;
int _gridWidth = 128;
int _gridHeight = 512;
int _indexCount = 0;
const float _patchSide = 64;
const float _fogDensity = 0.02f;
float _phase = 0;
float _phaseWave = 0;
float _wavePhase = 0;
float _amplitudes[s_maxHarmonics];
bool _reflectionMode = false;
bool _renderToTexture = false;
bool _geoReady = false;
public:
Water();
@ -94,6 +93,9 @@ namespace verus
void Update();
void Draw();
void OnSwapChainResized();
CGI::RPHandle GetRenderPassHandle() const { return _rphReflection; }
void BeginReflection(CGI::PBaseCommandBuffer pCB = nullptr);
void EndReflection(CGI::PBaseCommandBuffer pCB = nullptr);
@ -104,15 +106,18 @@ namespace verus
// Caustics are highlights on ocean floor.
CGI::TexturePtr GetCausticsTexture() const;
// Render reflection when above or normal view when below water level.
bool IsReflectionMode() const { return _reflectionMode; }
// Is rendering done to water's renderer target?
bool IsRenderToTexture() const { return _renderToTexture; }
PCamera GetSceneCamera() { return _pSceneCamera; }
VERUS_P(void CreateWaterPlane());
static float PhillipsSpectrum(float k);
bool IsUnderwater() const;
bool IsUnderwater(RcPoint3 eyePos) const;
RcVector3 GetDiffuseColorShallow() const { return _diffuseColorShallow; }
RcVector3 GetDiffuseColorDeep() const { return _diffuseColorDeep; }
float GetFogDensity() const { return _fogDensity; }
};
VERUS_TYPEDEFS(Water);
}

View File

@ -231,8 +231,7 @@ DS_ACC_FSO mainFS(VSO si)
float4 config = g_ubShadowFS._shadowConfig;
const float lamBiasMask = saturate(lamScaleBiasWithHair.y * config.y);
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
const float scale = -posWV.z - 5.0;
const float3 posForShadow = posWV + normalWV * 0.012 * max(1.0, scale * 0.2) + dirToLightWV * max(0.0, scale * 0.002);
const float3 posForShadow = AdjustPosForShadow(posWV, normalWV, dirToLightWV, -posWV.z);
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubShadowFS._matSunShadow, -posForShadow.z);
shadowMask = ShadowMapCSM(
g_texShadowCmp,

View File

@ -39,6 +39,12 @@ struct FSO
float4 color : SV_Target0;
};
struct FSO2
{
float4 target0 : SV_Target0;
float4 target1 : SV_Target1;
};
#ifdef _VS
VSO mainVS(VSI si)
{
@ -54,65 +60,111 @@ VSO mainVS(VSI si)
#endif
#ifdef _FS
FSO mainFS(VSO si)
{
FSO so;
#ifdef DEF_COMPOSE
const float3 colorAmbient = g_ubComposeFS._colorAmbient.rgb;
FSO2 mainFS(VSO si)
{
FSO2 so;
const float3 ambientColor = g_ubComposeFS._ambientColor_exposure.rgb;
const float2 ndcPos = si.clipSpacePos.xy;
const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0);
const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0);
const float4 rawGBuffer2 = g_texGBuffer2.Sample(g_samGBuffer2, si.tc0);
const float1 rawDepth = g_texDepth.Sample(g_samDepth, si.tc0).r;
const float3 normalWV = DS_GetNormal(rawGBuffer1);
const float2 emission = DS_GetEmission(rawGBuffer1);
const float4 rawAccDiff = g_texAccDiff.Sample(g_samAccDiff, si.tc0);
const float4 rawAccSpec = g_texAccSpec.Sample(g_samAccSpec, si.tc0);
const float4 accDiff = rawAccDiff;
const float4 accSpec = rawAccSpec;
// White color means 50% albedo, black is not really black:
const float3 albedo = max(rawGBuffer0.rgb * 0.5, 0.0001);
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 = 1.0;
const float ssaoSpec = 1.0;
const float ssaoAmb = 1.0;
const float3 albedo = max(rawGBuffer0.rgb * g_ubComposeFS._toneMappingConfig.z, 0.0001);
const float depth = ToLinearDepth(rawDepth, g_ubComposeFS._zNearFarEx);
const float3 posW = DS_GetPosition(rawDepth, g_ubComposeFS._matInvVP, ndcPos);
const float fog = ComputeFog(depth, g_ubComposeFS._fogColor.a, posW.y);
const float3 normalW = mul(normalWV, (float3x3)g_ubComposeFS._matInvV);
const float grayAmbient = Grayscale(colorAmbient);
const float3 colorGround = lerp(colorAmbient, float3(1, 0.88, 0.47) * grayAmbient, saturate(grayAmbient * 14.0));
const float3 colorAmbientFinal = lerp(colorGround, colorAmbient, saturate(normalW.y * 2.0 + 0.5));
const float grayAmbient = Grayscale(ambientColor);
const float3 finalAmbientColor = lerp(grayAmbient * 0.5, ambientColor, normalW.y * 0.5 + 0.5);
const float3 color =
albedo * (accDiff.rgb * ssaoDiff + colorAmbientFinal * ssaoAmb) +
albedo * (accDiff.rgb * ssaoDiff + finalAmbientColor * ssaoAmb) +
accSpec.rgb * ssaoSpec +
albedo * emission.x;
const float3 colorWithFog = lerp(color, g_ubComposeFS._fogColor.rgb, fog);
// <Fog>
float3 colorWithFog;
{
const float fog = ComputeFog(depth, g_ubComposeFS._fogColor.a, posW.y);
colorWithFog = lerp(color, g_ubComposeFS._fogColor.rgb, fog);
}
// </Fog>
so.color.rgb = colorWithFog;
so.color.rgb = lerp(so.color.rgb, g_ubComposeFS._colorBackground.rgb, floor(rawDepth) * g_ubComposeFS._colorBackground.a);
so.color.a = 1.0;
#endif
// <Underwater>
float3 underwaterColor;
{
const float diffuseMask = ToWaterDiffuseMask(posW.y);
const float refractMask = saturate((diffuseMask - 0.5) * 2.0);
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 float3 planktonColor = lerp(
waterDiffColorDeepAmbient * deepAmbientColor,
waterDiffColorShallowAmbient,
diffuseMask);
const float3 color = lerp(albedo * planktonColor * 10.0, colorWithFog, refractMask);
const float fog = ComputeFog(depth, g_ubComposeFS._waterDiffColorShallow.a);
underwaterColor = lerp(color, planktonColor * 0.1, fog * saturate(1.0 - refractMask + g_ubComposeFS._waterDiffColorDeep.a));
}
// </Underwater>
#ifdef DEF_TONE_MAPPING
const float4 rawComposed = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0);
so.target0.rgb = underwaterColor;
so.target0.a = 1.0;
so.color.rgb = VerusToneMapping(rawComposed.rgb * g_ubComposeFS._toneMappingConfig.x, g_ubComposeFS._toneMappingConfig.y);
so.color.a = 1.0;
#endif
so.target1 = so.target0;
return so;
}
#endif
#ifdef DEF_TONE_MAPPING
FSO mainFS(VSO si)
{
FSO so;
const float4 rawGBuffer0 = g_texGBuffer0.Sample(g_samGBuffer0, si.tc0);
const float4 rawGBuffer1 = g_texGBuffer1.Sample(g_samGBuffer1, si.tc0);
const float4 rawComposed = g_texDepth.Sample(g_samDepth, si.tc0);
const float3 exposedComposed = rawComposed.rgb * g_ubComposeFS._ambientColor_exposure.a;
so.color.rgb = VerusToneMapping(exposedComposed, 0.5);
so.color.a = 1.0;
// SolidColor (using special value 1.0 for emission):
so.color.rgb = lerp(so.color.rgb, rawGBuffer0.rgb, floor(rawGBuffer1.b));
// <BackgroundColor>
const float2 normalWasSet = ceil(rawGBuffer1.rg);
const float bg = 1.0 - saturate(normalWasSet.r + normalWasSet.g);
so.color.rgb = lerp(so.color.rgb, g_ubComposeFS._backgroundColor.rgb, bg * g_ubComposeFS._backgroundColor.a);
// </BackgroundColor>
if (false)
{
const float gray = Grayscale(rawComposed.rgb);
so.color.r = saturate((gray - 25.0) * 0.001);
so.color.gb *= 0.5;
}
return so;
}
#endif
#endif
//@main:#Compose COMPOSE
//@main:#ToneMapping TONE_MAPPING

View File

@ -10,9 +10,10 @@ VERUS_UBUFFER UB_ComposeFS
{
mataff _matInvV;
matrix _matInvVP;
float4 _colorAmbient;
float4 _colorBackground;
float4 _ambientColor_exposure;
float4 _backgroundColor;
float4 _fogColor;
float4 _zNearFarEx;
float4 _toneMappingConfig;
float4 _waterDiffColorShallow;
float4 _waterDiffColorDeep;
};

View File

@ -4,7 +4,6 @@
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibSurface.hlsl"
#include "LibVertex.hlsl"
#include "DS_Grass.inc.hlsl"
ConstantBuffer<UB_GrassVS> g_ubGrassVS : register(b0, space0);
@ -72,14 +71,13 @@ VSO mainVS(VSI si)
pos = float3(center.x, 0.45 * pointSpriteScale.y, center.y);
#endif
const float bestPrecision = 50.0;
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 mipTexelCenter = texelCenter * exp2(geomipsLod);
const float2 tcMap = pos.xz * mapSideInv + 0.5;
const float2 tcUniform = center * mapSideInv + 0.5;
groundHeight = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + mipTexelCenter, geomipsLod).r + bestPrecision;
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);

View File

@ -172,7 +172,7 @@ PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
}
[domain("tri")]
//[maxtessfactor(7.0)]
[maxtessfactor(7.0)]
[outputcontrolpoints(3)]
[outputtopology("triangle_cw")]
[partitioning(_PARTITION_METHOD)]
@ -244,32 +244,60 @@ DS_FSO mainFS(VSO si)
si.matTBN2.xyz);
const float3 rand = Rand(si.pos.xy);
// <Material>
const float2 mm_alphaSwitch = g_ubPerMaterialFS._alphaSwitch_anisoSpecDir.xy;
const float2 mm_anisoSpecDir = g_ubPerMaterialFS._alphaSwitch_anisoSpecDir.zw;
const float mm_detail = g_ubPerMaterialFS._detail_emission_gloss_hairDesat.x;
const float2 mm_detailScale = g_ubPerMaterialFS._detailScale_strassScale.xy;
const float mm_emission = g_ubPerMaterialFS._detail_emission_gloss_hairDesat.y;
const float4 mm_emissionPick = g_ubPerMaterialFS._emissionPick;
const float4 mm_eyePick = g_ubPerMaterialFS._eyePick;
const float mm_gloss = g_ubPerMaterialFS._detail_emission_gloss_hairDesat.z;
const float4 mm_glossPick = g_ubPerMaterialFS._glossPick;
const float2 mm_glossScaleBias = g_ubPerMaterialFS._glossScaleBias_specScaleBias.xy;
const float mm_hairDesat = g_ubPerMaterialFS._detail_emission_gloss_hairDesat.w;
const float4 mm_hairPick = g_ubPerMaterialFS._hairPick;
const float2 mm_lamScaleBias = g_ubPerMaterialFS._lamScaleBias_lightPass_motionBlur.xy;
const float mm_lightPass = g_ubPerMaterialFS._lamScaleBias_lightPass_motionBlur.z;
const float4 mm_metalPick = g_ubPerMaterialFS._metalPick;
const float4 mm_skinPick = g_ubPerMaterialFS._skinPick;
const float2 mm_specScaleBias = g_ubPerMaterialFS._glossScaleBias_specScaleBias.zw;
const float2 mm_strassScale = g_ubPerMaterialFS._detailScale_strassScale.zw;
const float4 mm_tc0ScaleBias = g_ubPerMaterialFS._tc0ScaleBias;
const float4 mm_texEnableAlbedo = g_ubPerMaterialFS._texEnableAlbedo;
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;
// </Material>
const float2 tc0 = si.tc0 * mm_tc0ScaleBias.xy + mm_tc0ScaleBias.zw;
// <Albedo>
float4 rawAlbedo;
{
const float texAlbedoEnable = ceil(g_ubPerMaterialFS._texEnableAlbedo.a);
rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, si.tc0 * texAlbedoEnable);
rawAlbedo.rgb = lerp(g_ubPerMaterialFS._texEnableAlbedo.rgb, rawAlbedo.rgb, g_ubPerMaterialFS._texEnableAlbedo.a);
const float texEnableAlbedoAlpha = ceil(mm_texEnableAlbedo.a);
rawAlbedo = g_texAlbedo.Sample(g_samAlbedo, tc0 * texEnableAlbedoAlpha);
rawAlbedo.rgb = lerp(mm_texEnableAlbedo.rgb, rawAlbedo.rgb, mm_texEnableAlbedo.a);
}
const float gray = Grayscale(rawAlbedo.rgb);
// </Albedo>
const float2 alpha_spec = AlphaSwitch(rawAlbedo, si.tc0, g_ubPerMaterialFS._ssb_as.zw);
const float emitAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._emitPick, 16.0);
const float emitXAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._emitXPick, 16.0);
const float eyeAlpha = PickAlphaRound(g_ubPerMaterialFS._eyePick, si.tc0);
const float glossXAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._glossXPick, 32.0);
const float hairAlpha = round(PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._hairPick, 16.0));
const float metalAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._metalPick, 16.0);
const float skinAlpha = PickAlpha(rawAlbedo.rgb, g_ubPerMaterialFS._skinPick, 16.0);
const float userAlpha = PickAlphaHue(rawAlbedo.rgb, g_ubPerMaterialFS._userPick, 32.0);
const float2 alpha_spec = AlphaSwitch(rawAlbedo, tc0, mm_alphaSwitch);
const float emitAlpha = PickAlpha(rawAlbedo.rgb, mm_emissionPick, 16.0);
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 = PickAlphaHue(rawAlbedo.rgb, mm_userPick, 32.0);
rawAlbedo.rgb = lerp(rawAlbedo.rgb, Overlay(gray, si.color0.rgb), userAlpha * si.color0.a);
const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * g_ubPerMaterialFS._hairParams.w));
const float3 hairAlbedo = Overlay(alpha_spec.y, Desaturate(rawAlbedo.rgb, hairAlpha * mm_hairDesat));
// <Gloss>
//float gloss = lerp(g_ubPerMaterialFS._lsb_gloss_lp.z, g_ubPerMaterialFS._motionBlur_glossX.y, glossXAlpha);
float gloss = lerp(4.4, 16.0, alpha_spec.y);
float gloss = lerp(4.0, 16.0, alpha_spec.y) * mm_glossScaleBias.x + mm_glossScaleBias.y;
gloss = lerp(gloss, mm_gloss, glossAlpha);
gloss = lerp(gloss, 4.0 + alpha_spec.y, skinAlpha);
gloss = lerp(gloss, 0.0, eyeAlpha);
// </Gloss>
@ -280,35 +308,35 @@ DS_FSO mainFS(VSO si)
float lightPassStrength;
float3 anisoWV;
{
const float texNormalEnable = ceil(g_ubPerMaterialFS._texEnableNormal.a);
float4 rawNormal = g_texNormal.Sample(g_samNormal, si.tc0 * texNormalEnable);
rawNormal = lerp(g_ubPerMaterialFS._texEnableNormal.rgbr, rawNormal, g_ubPerMaterialFS._texEnableNormal.a);
const float texEnableNormalAlpha = ceil(mm_texEnableNormal.a);
float4 rawNormal = g_texNormal.Sample(g_samNormal, tc0 * texEnableNormalAlpha);
rawNormal = lerp(mm_texEnableNormal.rgbr, rawNormal, mm_texEnableNormal.a);
const float4 normalAA = NormalMapAA(rawNormal);
const float3 normalTBN = normalAA.xyz;
normalWV = normalize(mul(normalTBN, matFromTBN));
toksvigFactor = ComputeToksvigFactor(normalAA.a, gloss);
lightPassStrength = rawNormal.r;
anisoWV = normalize(mul(cross(normalTBN, cross(g_ubPerMaterialFS._hairParams.xyz, normalTBN)), matFromTBN));
anisoWV = normalize(mul(cross(normalTBN, cross(float3(mm_anisoSpecDir, 0), normalTBN)), matFromTBN));
}
// </Normal>
// <Detail>
{
const float3 rawDetail = g_texDetail.Sample(g_samDetail, si.tc0 * g_ubPerMaterialFS._ds_scale.zw).rgb;
rawAlbedo.rgb = rawAlbedo.rgb * lerp(0.5, rawDetail, g_ubPerMaterialFS._ds_scale.x) * 2.0;
const float3 rawDetail = g_texDetail.Sample(g_samDetail, tc0 * mm_detailScale).rgb;
rawAlbedo.rgb = rawAlbedo.rgb * lerp(0.5, rawDetail, mm_detail) * 2.0;
}
// </Detail>
// <Strass>
float strass;
{
const float rawStrass = g_texStrass.Sample(g_samStrass, si.tc0 * g_ubPerMaterialFS._ds_scale.zw * 2.0).r;
strass = saturate(rawStrass * (0.3 + 0.7 * alpha_spec.y) * 4.0) * g_ubPerMaterialFS._ds_scale.y;
const float rawStrass = g_texStrass.Sample(g_samStrass, tc0 * mm_strassScale).r;
strass = saturate(rawStrass * (0.3 + 0.7 * alpha_spec.y) * 4.0);
}
// </Strass>
// <LambertianScaleBias>
float2 lamScaleBias = g_ubPerMaterialFS._lsb_gloss_lp.xy + float2(0, lightPassStrength * 8.0 * g_ubPerMaterialFS._lsb_gloss_lp.w);
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);
// </LambertianScaleBias>
@ -326,10 +354,11 @@ DS_FSO mainFS(VSO si)
DS_SetAlbedo(so, lerp(rawAlbedo.rgb, hairAlbedo, hairAlpha));
DS_SetSpec(so, max(eyeAlpha, max(strass,
alpha_spec.y * (1.0 + hairAlpha * 0.75) * g_ubPerMaterialFS._ssb_as.x + g_ubPerMaterialFS._ssb_as.y)));
alpha_spec.y * (1.0 + hairAlpha * 0.75) * mm_specScaleBias.x + mm_specScaleBias.y)));
DS_SetNormal(so, normalWV + NormalDither(rand));
DS_SetEmission(so, max(emitAlpha, emitXAlpha) * alpha_spec.y, skinAlpha);
DS_SetEmission(so, emitAlpha * mm_emission, skinAlpha);
DS_SetMotionBlur(so, motionBlur);
DS_SetLamScaleBias(so, lamScaleBias, float4(anisoWV, hairAlpha));
DS_SetMetallicity(so, metalAlpha, hairAlpha);

View File

@ -10,22 +10,22 @@ VERUS_UBUFFER UB_PerFrame
VERUS_UBUFFER UB_PerMaterialFS
{
float4 _alphaSwitch_anisoSpecDir;
float4 _detail_emission_gloss_hairDesat;
float4 _detailScale_strassScale;
float4 _emissionPick;
float4 _eyePick;
float4 _glossPick;
float4 _glossScaleBias_specScaleBias;
float4 _hairPick;
float4 _lamScaleBias_lightPass_motionBlur;
float4 _metalPick;
float4 _skinPick;
float4 _tc0ScaleBias;
float4 _texEnableAlbedo;
float4 _texEnableNormal;
float4 _skinPick;
float4 _hairPick;
float4 _emitPick;
float4 _emitXPick;
float4 _metalPick;
float4 _glossXPick;
float4 _eyePick;
float4 _hairParams;
float4 _lsb_gloss_lp;
float4 _ssb_as;
float4 _userColor;
float4 _userPick;
float4 _ds_scale;
float4 _motionBlur_glossX;
float4 _bushEffect;
};
VERUS_UBUFFER UB_PerMeshVS

View File

@ -48,7 +48,6 @@ struct VSO
#endif
};
static const float g_bestPrecision = 50.0;
static const float g_layerScale = 1.0 / 8.0;
#ifdef _VS
@ -68,7 +67,7 @@ VSO mainVS(VSI si)
// <HeightAndNormal>
float3 intactNrm;
{
const float approxHeight = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r + g_bestPrecision;
const float approxHeight = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r);
pos.y = approxHeight;
const float distToEye = distance(pos, eyePos);
@ -77,8 +76,8 @@ VSO mainVS(VSI si)
const float geomipsLodBase = floor(geomipsLod);
const float geomipsLodNext = geomipsLodBase + 1.0;
const float2 texelCenterAB = (0.5 * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
const float yA = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.xx, geomipsLodBase).r + g_bestPrecision;
const float yB = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.yy, geomipsLodNext).r + g_bestPrecision;
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);
@ -114,7 +113,7 @@ PCFO PatchConstFunc(const OutputPatch<HSO, 3> outputPatch)
}
[domain("tri")]
//[maxtessfactor(7.0)]
[maxtessfactor(7.0)]
[outputcontrolpoints(3)]
[outputtopology("triangle_cw")]
[partitioning(_PARTITION_METHOD)]
@ -248,15 +247,15 @@ DS_FSO mainFS(VSO si)
// </Albedo>
// <Water>
float waterGlossBoost = 0.0;
float waterGlossBoost;
{
const float dryMask = saturate(si.tcBlend.z);
const float dryMask3 = dryMask * dryMask * dryMask;
const float wetMask = 1.0 - dryMask;
const float wetMask3 = wetMask * wetMask * wetMask;
albedo.rgb *= dryMask3 * 0.5 + 0.5;
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3);
waterGlossBoost = min(32.0, dryMask * wetMask3 * 128.0);
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3 * 0.1);
waterGlossBoost = min(32.0, dryMask * wetMask3 * 100.0);
}
// </Water>

View File

@ -62,19 +62,20 @@ float4 PackColor(float4 x)
void mainCS(CSI si)
{
float4 srcColor1 = 0.0;
float2 tc = 0.0;
switch (g_ub._srcDimensionCase)
{
case DIM_CASE_WE_HE:
{
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + 0.5);
tc = g_ub._texelSize * (si.dispatchThreadID.xy + 0.5);
srcColor1 = g_texSrcMip.SampleLevel(g_samSrcMip, tc, g_ub._srcMipLevel);
}
break;
case DIM_CASE_WO_HE:
{
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.5));
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.5));
const float2 offset = g_ub._texelSize * float2(0.5, 0.0);
srcColor1 = lerp(
@ -85,7 +86,7 @@ void mainCS(CSI si)
break;
case DIM_CASE_WE_HO:
{
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.5, 0.25));
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.5, 0.25));
const float2 offset = g_ub._texelSize * float2(0.0, 0.5);
srcColor1 = lerp(
@ -96,7 +97,7 @@ void mainCS(CSI si)
break;
case DIM_CASE_WO_HO:
{
const float2 tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.25));
tc = g_ub._texelSize * (si.dispatchThreadID.xy + float2(0.25, 0.25));
const float2 offset = g_ub._texelSize * 0.5;
srcColor1 = lerp(
@ -112,6 +113,20 @@ void mainCS(CSI si)
break;
}
#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 float gray = Grayscale(srcColor1.rgb);
const float2 mask = saturate((float2(-1, 1) * gray + float2(0.1, -0.99)) * 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;
}
#endif
g_uavOutMip1[si.dispatchThreadID.xy] = PackColor(srcColor1);
if (1 == g_ub._mipLevelCount)
@ -166,3 +181,4 @@ void mainCS(CSI si)
#endif
//@main:# (C)
//@main:#Exposure EXPOSURE (C)

View File

@ -76,6 +76,12 @@ matrix ToFloat4x4(mataff m)
float4(m[3], 1));
}
// Asymmetric abs():
float2 AsymAbs(float2 x, float negScale = -1.0, float posScale = 1.0)
{
return x * lerp(posScale, negScale, step(x, 0.0));
}
float3 Rand(float2 uv)
{
return frac(sin(dot(uv, float2(12.9898, 78.233)) * float3(1, 2, 3)) * 43758.5453);
@ -102,3 +108,24 @@ static const float2 _POINT_SPRITE_TEX_COORDS[4] =
float2(1, 0),
float2(1, 1)
};
float UnpackTerrainHeight(float height)
{
return height * 0.01;
}
float ToLandMask(float height)
{
return saturate(height * 0.2 + 1.0); // [-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]
return mask * mask * mask;
}
float3 ReflectionDimming(float3 hdr, float scale)
{
return lerp(hdr * scale, hdr, saturate(hdr * (1.0 / 65536.0)));
}

View File

@ -71,15 +71,6 @@ float4 ColorToSRGB(float4 x)
return float4(rgb, x.a);
}
float4 HDRColorToLinear(float4 x)
{
return float4(x.rgb * x.rgb * 12.0, x.a);
}
float4 HDRColorToSRGB(float4 x)
{
return float4(sqrt(saturate(x.rgb * (1.0 / 12.0))), x.a);
}
// See: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
float3 ToneMappingACES(float3 x)
{
@ -93,6 +84,9 @@ float3 ToneMappingACES(float3 x)
float3 VerusToneMapping(float3 hdr, float filmicLook = 1.0)
{
const float maxValue = max(max(hdr.r, hdr.g), hdr.b);
const float desatMask = saturate(maxValue * 0.1);
hdr = lerp(hdr, maxValue, desatMask * desatMask);
const float3 ldr = lerp(1.0 - exp(-hdr), ToneMappingACES(hdr), filmicLook);
return saturate(ldr);
}

View File

@ -73,15 +73,21 @@ 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));
return float2(HDRColorToLinear(em_skin.x).r, em_skin.y);
const float em = exp2(em_skin.x * 15.0) - 1.0;
return float2(em, em_skin.y);
}
void DS_SetEmission(inout DS_FSO so, float emission, float skin)
{
const float em = HDRColorToSRGB(emission).r;
const float em = saturate(log2(1.0 + emission) * (1.0 / 15.0));
so.target1.b = (3.0 * em - skin) * 0.25 + 0.25;
}
void DS_SetMotionBlur(inout DS_FSO so, float mb)
{
so.target1.a = mb;
}
float2 DS_GetLamScaleBias(float4 gbuffer)
{
return gbuffer.rg * float2(8, 4) - float2(0, 2); // {0 to 8, -2 to 2}.

View File

@ -16,10 +16,17 @@ float4 ToLinearDepth(float4 d, float4 zNearFarEx)
float ComputeFog(float depth, float density, float height = 0.0)
{
const float strength = 1.0 - saturate(height * 0.003);
const float fog = 1.0 / exp(depth * lerp(0.0, density, strength * strength));
const float power = depth * lerp(0.0, density, strength * strength);
const float fog = 1.0 / exp(power * power);
return 1.0 - saturate(fog);
}
float3 AdjustPosForShadow(float3 pos, float3 normal, float3 dirToLight, float depth)
{
const float scale = depth - 5.0;
return pos + normal * 0.012 * max(1.0, scale * 0.2) + dirToLight * max(0.0, scale * 0.002);
}
float4 ShadowCoords(float4 pos, matrix mat, float depth)
{
// For CSM transformation is done in PS.
@ -90,6 +97,14 @@ float PCF(
#endif
}
float SimplePCF(
Texture2D texCmp,
SamplerComparisonState samCmp,
float3 tc)
{
return texCmp.SampleCmpLevelZero(samCmp, tc.xy, tc.z).r;
}
float ShadowMap(
Texture2D texCmp,
SamplerComparisonState samCmp,
@ -158,3 +173,53 @@ float ShadowMapCSM(
return ShadowMap(texCmp, samCmp, tex, sam, pos, config);
#endif
}
float SimpleShadowMapCSM(
Texture2D texCmp,
SamplerComparisonState samCmp,
float4 pos,
float4 config,
float4 ranges,
matrix mat0,
matrix mat1,
matrix mat2,
matrix mat3)
{
#if _SHADOW_QUALITY >= 4
float ret = 1.0;
const float4 p = float4(pos.xyz, 1);
float contrast = 1.0;
const float contrastScale = config.w;
if (pos.w > ranges.x)
{
const float fadeStart = (ranges.x + ranges.w) * 0.5;
const float fade = saturate((pos.w - fadeStart) / (ranges.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);
}
else
{
const float3 tc = mul(p, mat3).xyz;
ret = SimplePCF(texCmp, samCmp, tc);
}
return saturate((ret - 0.5) * contrast + 0.5);
#else
return SimplePCF(texCmp, samCmp, pos.xyz);
#endif
}

View File

@ -13,7 +13,7 @@ float FresnelSchlick(float minRef, float maxAdd, float power)
float EnergyNorm(float gloss)
{
return (gloss + 2.0) * (1.0 / 8.0);
return min(100.0, (gloss + 2.0) * (1.0 / 8.0));
}
float4 VerusLit(float3 dirToLight, float3 normal, float3 dirToEye, float gloss,

View File

@ -3,7 +3,7 @@
#define _PARTITION_METHOD "fractional_even"
// Hull shader's output, also domain shader's input.
// Includes vertex position in world-view space and 2 control points in same space.
// Includes vertex position in world-view space and 2 bezier control points in same space.
// If all points are not visible, then clipped will be 1:
#define _HSO_STRUCT struct HSO { \
float3 posWV[3] : POSITIONS; \
@ -16,7 +16,7 @@ struct PCFO
{
float tessFactors[3] : SV_TessFactor;
float insideTessFactor : SV_InsideTessFactor;
float3 viewB111 : VIEWB111;
float3 b111 : B111; // Bezier control point in the middle of a patch.
};
#define _HS_COPY(a) so.vso.a = inputPatch[id].a
@ -31,8 +31,8 @@ struct PCFO
const uint thisID = id; \
const uint nextID = (thisID < 2) ? thisID + 1 : 0; \
so.posWV[0] = inputPatch[thisID].pos.xyz; \
so.posWV[1] = ComputeControlPoint(inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, inputPatch[thisID].nrmWV.xyz); \
so.posWV[2] = ComputeControlPoint(inputPatch[nextID].pos.xyz, inputPatch[thisID].pos.xyz, inputPatch[nextID].nrmWV.xyz); \
so.posWV[1] = ComputeBezierPoint(inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, inputPatch[thisID].nrmWV.xyz); \
so.posWV[2] = ComputeBezierPoint(inputPatch[nextID].pos.xyz, inputPatch[thisID].pos.xyz, inputPatch[nextID].nrmWV.xyz); \
so.clipped = ComputeClipping(matP, so.posWV[0], so.posWV[1], so.posWV[2]); \
so.oppositeEdgeTessFactor = ComputeEdgeTessFactor(matP, inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, viewportSize.xy); \
const float3 normal = (inputPatch[thisID].nrmWV.xyz + inputPatch[nextID].nrmWV.xyz) * 0.5; \
@ -49,18 +49,18 @@ struct PCFO
const float ratio = kB / sum; \
float3 myCP, exCP; \
so.posWV[0] = inputPatch[thisID].pos.xyz; \
myCP = ComputeControlPoint(inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, inputPatch[thisID].nrmWV.xyz); \
exCP = ComputeControlPoint(inputPatch[thisEX].pos.xyz, inputPatch[nextEX].pos.xyz, inputPatch[thisEX].nrmWV.xyz); \
myCP = ComputeBezierPoint(inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, inputPatch[thisID].nrmWV.xyz); \
exCP = ComputeBezierPoint(inputPatch[thisEX].pos.xyz, inputPatch[nextEX].pos.xyz, inputPatch[thisEX].nrmWV.xyz); \
so.posWV[1] = lerp(myCP, exCP, ratio); \
myCP = ComputeControlPoint(inputPatch[nextID].pos.xyz, inputPatch[thisID].pos.xyz, inputPatch[nextID].nrmWV.xyz); \
exCP = ComputeControlPoint(inputPatch[nextEX].pos.xyz, inputPatch[thisEX].pos.xyz, inputPatch[nextEX].nrmWV.xyz); \
myCP = ComputeBezierPoint(inputPatch[nextID].pos.xyz, inputPatch[thisID].pos.xyz, inputPatch[nextID].nrmWV.xyz); \
exCP = ComputeBezierPoint(inputPatch[nextEX].pos.xyz, inputPatch[thisEX].pos.xyz, inputPatch[nextEX].nrmWV.xyz); \
so.posWV[2] = lerp(myCP, exCP, ratio); \
so.clipped = ComputeClipping(matP, so.posWV[0], so.posWV[1], so.posWV[2]); \
so.oppositeEdgeTessFactor = ComputeEdgeTessFactor(matP, inputPatch[thisID].pos.xyz, inputPatch[nextID].pos.xyz, viewportSize.xy); \
const float3 normal = (inputPatch[thisID].nrmWV.xyz + inputPatch[thisEX].nrmWV.xyz + inputPatch[nextID].nrmWV.xyz + inputPatch[nextEX].nrmWV.xyz) * 0.25; \
so.oppositeEdgeTessFactor = (normal.z < -0.75) ? 0.0 : max(1.0, so.oppositeEdgeTessFactor * (1.0 - abs(normal.z * 0.75)));
// Patch Constant Function, here central control point is calculated:
// Patch Constant Function, here central bezier control point is calculated:
#define _HS_PCF_BODY(matP) \
so.tessFactors[0] = outputPatch[1].oppositeEdgeTessFactor; \
so.tessFactors[1] = outputPatch[2].oppositeEdgeTessFactor; \
@ -77,8 +77,8 @@ struct PCFO
const float3 b201 = outputPatch[2].posWV[2]; \
const float3 e = (b210 + b120 + b021 + b012 + b102 + b201) * (1.0 / 6.0); \
const float3 v = (b003 + b030 + b300) * (1.0 / 3.0); \
so.viewB111 = e + (e - v) * 0.5; \
const float b111Clipped = IsClipped(ApplyProjection(so.viewB111, matP)); \
so.b111 = e + (e - v) * 0.5; \
const float b111Clipped = IsClipped(ApplyProjection(so.b111, matP)); \
if (outputPatch[0].clipped && outputPatch[1].clipped && outputPatch[2].clipped && b111Clipped) { so.tessFactors[0] = 0.0; }
#define _DS_INIT_FLAT_POS \
@ -101,11 +101,13 @@ struct PCFO
outputPatch[1].posWV[2] * uvwSq3.z * uvw.y + \
outputPatch[2].posWV[1] * uvwSq3.z * uvw.x + \
outputPatch[2].posWV[2] * uvwSq3.x * uvw.z + \
si.viewB111 * uvw.x * uvw.y * uvw.z * 6.0
si.b111 * uvw.x * uvw.y * uvw.z * 6.0
float3 ComputeControlPoint(float3 posA, float3 posB, float3 nrmA)
float3 ComputeBezierPoint(float3 posA, float3 posB, float3 nrmA)
{
return (2.0 * posA + posB - dot(posB - posA, nrmA) * nrmA) * (1.0 / 3.0);
// Project a 1/3 midpoint on the plane, which is defined by the nearest vertex and it's normal.
const float extrudeLen = dot(posB - posA, nrmA);
return (2.0 * posA + posB - extrudeLen * nrmA) * (1.0 / 3.0);
}
// Optimized version of the projection transform:

View File

@ -43,7 +43,7 @@ FSO mainFS(VSO si)
{
FSO so;
so.color = g_tex.Sample(g_sam, si.tc0);
so.color = g_tex.SampleLevel(g_sam, si.tc0, 0.0);
return so;
}

View File

@ -1,27 +1,27 @@
// Copyright (C) 2020, Dmitry Maluev (dmaluev@gmail.com)
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibDepth.hlsl"
#include "LibLighting.hlsl"
#include "LibSurface.hlsl"
#include "LibTessellation.hlsl"
#include "SimpleTerrain.inc.hlsl"
ConstantBuffer<UB_SimpleTerrainVS> g_ubSimpleTerrainVS : register(b0, space0);
ConstantBuffer<UB_SimpleTerrainFS> g_ubSimpleTerrainFS : register(b0, space1);
Texture2D g_texHeightVS : register(t1, space0);
SamplerState g_samHeightVS : register(s1, space0);
Texture2D g_texNormalVS : register(t2, space0);
SamplerState g_samNormalVS : register(s2, space0);
Texture2D g_texHeightVS : register(t1, space0);
SamplerState g_samHeightVS : register(s1, space0);
Texture2D g_texNormalVS : register(t2, space0);
SamplerState g_samNormalVS : register(s2, space0);
Texture2D g_texNormal : register(t1, space1);
SamplerState g_samNormal : register(s1, space1);
Texture2D g_texBlend : register(t2, space1);
SamplerState g_samBlend : register(s2, space1);
Texture2DArray g_texLayers : register(t3, space1);
SamplerState g_samLayers : register(s3, space1);
Texture2D g_texNormal : register(t1, space1);
SamplerState g_samNormal : register(s1, space1);
Texture2D g_texBlend : register(t2, space1);
SamplerState g_samBlend : register(s2, space1);
Texture2DArray g_texLayers : register(t3, space1);
SamplerState g_samLayers : register(s3, space1);
Texture2D g_texShadowCmp : register(t4, space1);
SamplerComparisonState g_samShadowCmp : register(s4, space1);
struct VSI
{
@ -33,11 +33,13 @@ struct VSI
struct VSO
{
float4 pos : SV_Position;
float3 nrmW : TEXCOORD0;
float4 layerForChannel : TEXCOORD1;
float3 tcBlend : TEXCOORD2;
float4 tcLayer_tcMap : TEXCOORD3;
float3 dirToEye : TEXCOORD4;
float4 posW_depth : TEXCOORD0;
float3 nrmW : TEXCOORD1;
float4 layerForChannel : TEXCOORD2;
float2 tcBlend : TEXCOORD3;
float4 tcLayer_tcMap : TEXCOORD4;
float3 dirToEye : TEXCOORD5;
float clipDistance : SV_ClipDistance;
};
struct FSO
@ -45,7 +47,6 @@ struct FSO
float4 color : SV_Target0;
};
static const float g_bestPrecision = 50.0;
static const float g_layerScale = 1.0 / 8.0;
#ifdef _VS
@ -53,8 +54,9 @@ VSO mainVS(VSI si)
{
VSO so;
const float3 eyePos = g_ubSimpleTerrainVS._eyePos_mapSideInv.xyz;
const float mapSideInv = g_ubSimpleTerrainVS._eyePos_mapSideInv.w;
const float3 eyePos = g_ubSimpleTerrainVS._eyePos.xyz;
const float mapSideInv = g_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.x;
const float clipDistanceOffset = g_ubSimpleTerrainVS._mapSideInv_clipDistanceOffset.y;
const float2 edgeCorrection = si.pos.yw;
si.pos.yw = 0.0;
@ -65,7 +67,7 @@ VSO mainVS(VSI si)
// <HeightAndNormal>
float3 intactNrm;
{
const float approxHeight = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r + g_bestPrecision;
const float approxHeight = UnpackTerrainHeight(g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + (0.5 * mapSideInv) * 16.0, 4.0).r);
pos.y = approxHeight;
const float distToEye = distance(pos, eyePos);
@ -74,8 +76,8 @@ VSO mainVS(VSI si)
const float geomipsLodBase = floor(geomipsLod);
const float geomipsLodNext = geomipsLodBase + 1.0;
const float2 texelCenterAB = (0.5 * mapSideInv) * exp2(float2(geomipsLodBase, geomipsLodNext));
const float yA = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.xx, geomipsLodBase).r + g_bestPrecision;
const float yB = g_texHeightVS.SampleLevel(g_samHeightVS, tcMap + texelCenterAB.yy, geomipsLodNext).r + g_bestPrecision;
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);
@ -85,13 +87,14 @@ VSO mainVS(VSI si)
// </HeightAndNormal>
so.pos = mul(float4(pos, 1), g_ubSimpleTerrainVS._matVP);
so.posW_depth = float4(pos, so.pos.z);
so.nrmW = mul(intactNrm, (float3x3)g_ubSimpleTerrainVS._matW);
so.layerForChannel = si.layerForChannel;
so.tcBlend.xy = posBlend * mapSideInv + 0.5;
so.tcBlend.z = pos.y;
so.tcBlend = posBlend * mapSideInv + 0.5;
so.tcLayer_tcMap.xy = pos.xz * g_layerScale;
so.tcLayer_tcMap.zw = (pos.xz + 0.5) * mapSideInv + 0.5; // Texel's center.
so.dirToEye = eyePos - pos;
so.clipDistance = pos.y + clipDistanceOffset;
return so;
}
@ -106,7 +109,7 @@ FSO mainFS(VSO si)
const float2 tcLayer = si.tcLayer_tcMap.xy;
const float2 tcMap = si.tcLayer_tcMap.zw;
const float4 rawBlend = g_texBlend.Sample(g_samBlend, si.tcBlend.xy);
const float4 rawBlend = g_texBlend.Sample(g_samBlend, si.tcBlend);
float4 weights = float4(rawBlend.rgb, 1.0 - dot(rawBlend.rgb, float3(1, 1, 1)));
// <Albedo>
@ -138,34 +141,59 @@ FSO mainFS(VSO si)
// </Albedo>
// <Water>
float waterGlossBoost = 0.0;
float waterGlossBoost;
{
const float dryMask = saturate(si.tcBlend.z);
const float dryMask = saturate(si.posW_depth.y);
const float dryMask3 = dryMask * dryMask * dryMask;
const float wetMask = 1.0 - dryMask;
const float wetMask3 = wetMask * wetMask * wetMask;
albedo.rgb *= dryMask3 * 0.5 + 0.5;
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3);
waterGlossBoost = min(32.0, dryMask * wetMask3 * 128.0);
specStrength = dryMask * saturate(specStrength + wetMask3 * wetMask3 * 0.1);
waterGlossBoost = min(32.0, dryMask * wetMask3 * 100.0);
}
// </Water>
const float gloss = lerp(3.3, 15.0, specStrength) + waterGlossBoost;
const float3 normal = normalize(si.nrmW);
const float3 dirToEye = normalize(si.dirToEye);
const float3 dirToEye = normalize(si.dirToEye.xyz);
const float depth = si.posW_depth.w;
// <Shadow>
float shadowMask;
{
float4 config = g_ubSimpleTerrainFS._shadowConfig;
const float lamBiasMask = saturate(g_ubSimpleTerrainFS._lamScaleBias.y * config.y);
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
const float3 posForShadow = AdjustPosForShadow(si.posW_depth.xyz, normal, g_ubSimpleTerrainFS._dirToSun.xyz, depth);
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubSimpleTerrainFS._matSunShadow, depth);
shadowMask = SimpleShadowMapCSM(
g_texShadowCmp,
g_samShadowCmp,
tcShadow,
config,
g_ubSimpleTerrainFS._splitRanges,
g_ubSimpleTerrainFS._matSunShadow,
g_ubSimpleTerrainFS._matSunShadowCSM1,
g_ubSimpleTerrainFS._matSunShadowCSM2,
g_ubSimpleTerrainFS._matSunShadowCSM3);
}
// </Shadow>
const float4 litRet = VerusLit(g_ubSimpleTerrainFS._dirToSun.xyz, normal, dirToEye,
gloss,
g_ubSimpleTerrainFS._lamScaleBias.xy,
float4(0, 0, 1, 0));
const float3 diffColor = litRet.y * g_ubSimpleTerrainFS._sunColor.rgb * albedo.rgb;
const float3 specColor = litRet.z * g_ubSimpleTerrainFS._sunColor.rgb * specStrength;
const float3 diffColor = litRet.y * g_ubSimpleTerrainFS._sunColor.rgb * shadowMask + g_ubSimpleTerrainFS._ambientColor.rgb;
const float3 specColor = litRet.z * g_ubSimpleTerrainFS._sunColor.rgb * shadowMask * specStrength;
so.color.rgb = diffColor + specColor;
so.color.rgb = albedo.rgb * 0.5 * diffColor + specColor;
so.color.a = 1.0;
const float fog = ComputeFog(depth, g_ubSimpleTerrainFS._fogColor.a, si.posW_depth.y);
so.color.rgb = lerp(so.color.rgb, g_ubSimpleTerrainFS._fogColor.rgb, fog);
return so;
}
#endif

View File

@ -4,13 +4,22 @@ VERUS_UBUFFER UB_SimpleTerrainVS
{
mataff _matW;
matrix _matVP;
float4 _eyePos_mapSideInv;
float4 _eyePos;
float4 _mapSideInv_clipDistanceOffset;
};
VERUS_UBUFFER UB_SimpleTerrainFS
{
float4 _vSpecStrength[8];
float4 _lamScaleBias;
float4 _ambientColor;
float4 _fogColor;
float4 _dirToSun;
float4 _sunColor;
matrix _matSunShadow;
matrix _matSunShadowCSM1;
matrix _matSunShadowCSM2;
matrix _matSunShadowCSM3;
float4 _shadowConfig;
float4 _splitRanges;
};

View File

@ -2,7 +2,6 @@
#include "Lib.hlsl"
#include "LibColor.hlsl"
#include "LibDeferredShading.hlsl"
#include "LibSurface.hlsl"
#include "LibVertex.hlsl"
#include "Sky.inc.hlsl"
@ -28,6 +27,12 @@ struct VSI
VK_LOCATION(8) int4 tc0 : TEXCOORD0;
};
struct VSI_SKY_BODY
{
VK_LOCATION_POSITION float4 pos : POSITION;
VK_LOCATION(8) int4 tc0 : TEXCOORD0;
};
struct VSO
{
float4 pos : SV_Position;
@ -40,6 +45,13 @@ struct VSO
#endif
};
struct VSO_SKY_BODY
{
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
float height : TEXCOORD1;
};
struct FSO
{
float4 color : SV_Target0;
@ -50,13 +62,11 @@ VSO mainVS(VSI si)
{
VSO so;
const float time = g_ubPerFrame._time_cloudiness_expo.x;
const float3 intactPos = DequantizeUsingDeq3D(si.pos.xyz, g_ubPerMeshVS._posDeqScale.xyz, g_ubPerMeshVS._posDeqBias.xyz);
so.pos = mul(float4(intactPos, 1), g_ubPerObject._matWVP).xyww; // Peg the depth. (c) ATI
so.color0 = pow(saturate(dot(normalize(intactPos), g_ubPerFrame._dirToSun.xyz)), 3.0);
so.tc0 = float2(time, 0.5 - intactPos.y);
so.color0 = pow(saturate(dot(normalize(intactPos * float3(1, 0.25, 1)), g_ubPerFrame._dirToSun.xyz)), 4.0);
so.tc0 = float2(g_ubPerFrame._time_cloudiness.x, 0.5 - intactPos.y);
so.tcStars = intactPos.xz * 16.0; // Stars.
#ifdef DEF_CLOUDS
so.tcPhaseA = intactPos.xz * (4.0 - 4.0 * intactPos.y) + g_ubPerFrame._phaseAB.xy;
@ -65,6 +75,17 @@ VSO mainVS(VSI si)
return so;
}
VSO_SKY_BODY mainSkyBodyVS(VSI_SKY_BODY si)
{
VSO_SKY_BODY so;
so.pos = mul(si.pos, g_ubPerObject._matWVP).xyww;
so.tc0 = si.tc0.xy;
so.height = mul(si.pos.xyz, (float3x3)g_ubPerObject._matW).y;
return so;
}
#endif
#ifdef _FS
@ -74,10 +95,12 @@ FSO mainFS(VSO si)
const float3 rand = Rand(si.pos.xy);
const float time = g_ubPerFrame._time_cloudiness_expo.x;
const float cloudiness = g_ubPerFrame._time_cloudiness_expo.y;
const float time = g_ubPerFrame._time_cloudiness.x;
const float cloudiness = g_ubPerFrame._time_cloudiness.y;
const float dayRatio = (1.0 - abs(0.5 - time) * 1.9);
const float sunAlpha = g_ubPerFrame._sunColor.a;
const float sunBoost = si.color0.r * sunAlpha;
#ifdef DEF_CLOUDS
const float3 rawSky = g_texSky.Sample(g_samSky, float2(time, 0.3)).rgb;
@ -99,30 +122,57 @@ FSO mainFS(VSO si)
const float clearSky = 1.0 - cloudiness;
const float clearSkySoft = 0.1 + 0.9 * clearSky;
const float alpha = saturate((avgColor - clearSky) * 4.0);
const float alpha = saturate((avgColor - clearSky) * 3.5);
const float sunBoost = si.color0.r * dayRatio;
const float directGlow = saturate(dot(normal, g_ubPerFrame._dirToSun.xyz));
const float edgeGlow = saturate((0.75 - alpha) * 1.5);
const float directGlow = saturate(dot(normal, g_ubPerFrame._dirToSun.xyz)) * sunAlpha;
const float edgeGlow = saturate((0.85 - alpha) * 1.2);
const float ambientGlow = edgeGlow * 0.5 + noonHalf * 0.25 + sunBoost * dayRatio;
const float glow = saturate(lerp(directGlow * 0.25, edgeGlow, noonHalf) + ambientGlow);
const float diff = saturate((avgColor + directGlow + sunBoost * 0.25) * dayRatio * clearSkySoft);
const float3 finalColor = saturate(diff * cloudColor + glow * rimColor * clearSkySoft);
const float hdrScale = dayRatio * dayRatio * 1000.0;
const float hdrScale = Grayscale(g_ubPerFrame._ambientColor.xyz) * (8.0 - 2.0 * cloudiness);
so.color.rgb = finalColor * hdrScale;
so.color.a = alpha;
// <Fog>
{
const float cloudScale = cloudiness * cloudiness;
const float fogBias = 0.01 + 0.49 * cloudScale;
const float fogContrast = 1.0 + 2.0 * cloudScale;
const float fog = saturate((si.tc0.y - 0.5 + fogBias) * (fogContrast / fogBias));
so.color.rgb = lerp(so.color.rgb, g_ubPerFrame._fogColor.rgb, lerp(1.0, fog, alpha));
so.color.a = max(so.color.a, fog);
}
// </Fog>
#else
const float4 rawSky = g_texSky.Sample(g_samSky, si.tc0);
const float3 skyColor = rawSky.rgb + rand * lerp(0.001, 0.01, rawSky.rgb);
const float3 skyColor = rawSky.rgb + rand * lerp(0.001, 0.01, rawSky.rgb); // Dithering.
const float4 rawStars = g_texStars.Sample(g_samStars, si.tcStars);
const float night = abs(0.5 - time) * 2.0;
const float3 colorWithStars = skyColor + si.color0 * 0.1 + rawStars.rgb * night * night;
const float hdrScale = Grayscale(g_ubPerFrame._ambientColor.xyz) * (10.0 + 5.0 * sunBoost);
so.color = float4(skyColor.rgb * hdrScale + rawStars.rgb * 5.0, 1);
#endif
const float hdrScale = dayRatio * dayRatio * 1000.0;
so.color = float4(colorWithStars.rgb * hdrScale, 1);
return so;
}
FSO mainSkyBodyFS(VSO_SKY_BODY si)
{
FSO so;
so.color = g_texClouds.Sample(g_samClouds, si.tc0);
const float mask = abs(si.height);
#ifdef DEF_SUN
so.color.rgb *= lerp(float3(1.0, 0.2, 0.001), 1.0, mask);
so.color.rgb *= (60.0 * 1000.0) + (100.0 * 1000.0) * mask;
#endif
#ifdef DEF_MOON
const float hdrScale = Grayscale(g_ubPerFrame._ambientColor.xyz) * 12.0;
so.color.rgb *= lerp(float3(1.0, 0.9, 0.8), 1.0, mask);
so.color.rgb *= max(100.0, hdrScale);
so.color.a *= mask;
#endif
return so;
@ -131,3 +181,5 @@ FSO mainFS(VSO si)
//@main:#Sky SKY
//@main:#Clouds CLOUDS
//@mainSkyBody:#Sun SUN
//@mainSkyBody:#Moon MOON

View File

@ -2,11 +2,12 @@
VERUS_UBUFFER UB_PerFrame
{
float4 _color;
float4 _time_cloudiness_expo;
float4 _dirToSun;
float4 _phaseAB;
float4 _time_cloudiness;
float4 _ambientColor;
float4 _fogColor;
float4 _dirToSun;
float4 _sunColor;
float4 _phaseAB;
};
VERUS_UBUFFER UB_PerMaterialFS
@ -24,5 +25,4 @@ VERUS_UBUFFER UB_PerObject
{
mataff _matW;
matrix _matWVP;
float4 _add;
};

View File

@ -3,25 +3,34 @@
#include "Lib.hlsl"
#include "LibDepth.hlsl"
#include "LibLighting.hlsl"
#include "LibSurface.hlsl"
#include "Water.inc.hlsl"
ConstantBuffer<UB_WaterVS> g_ubWaterVS : register(b0, space0);
ConstantBuffer<UB_WaterFS> g_ubWaterFS : register(b0, space1);
Texture2D g_texTerrainHeightmapVS : register(t1, space0);
SamplerState g_samTerrainHeightmapVS : register(s1, space0);
Texture2D g_texGenHeightmapVS : register(t2, space0);
SamplerState g_samGenHeightmapVS : register(s2, space0);
Texture2D g_texTerrainHeightmapVS : register(t1, space0);
SamplerState g_samTerrainHeightmapVS : register(s1, space0);
Texture2D g_texGenHeightmapVS : register(t2, space0);
SamplerState g_samGenHeightmapVS : register(s2, space0);
Texture2D g_texFoamVS : register(t3, space0);
SamplerState g_samFoamVS : register(s3, space0);
Texture2D g_texTerrainHeightmap : register(t1, space1);
SamplerState g_samTerrainHeightmap : register(s1, space1);
Texture2D g_texGenHeightmap : register(t2, space1);
SamplerState g_samGenHeightmap : register(s2, space1);
Texture2D g_texGenNormals : register(t3, space1);
SamplerState g_samGenNormals : register(s3, space1);
Texture2D g_texFoam : register(t4, space1);
SamplerState g_samFoam : register(s4, space1);
Texture2D g_texTerrainHeightmap : register(t1, space1);
SamplerState g_samTerrainHeightmap : register(s1, space1);
Texture2D g_texGenHeightmap : register(t2, space1);
SamplerState g_samGenHeightmap : register(s2, space1);
Texture2D g_texGenNormals : register(t3, space1);
SamplerState g_samGenNormals : register(s3, space1);
Texture2D g_texFoam : register(t4, space1);
SamplerState g_samFoam : register(s4, space1);
Texture2D g_texReflection : register(t5, space1);
SamplerState g_samReflection : register(s5, space1);
Texture2D g_texRefraction : register(t6, space1);
SamplerState g_samRefraction : register(s6, space1);
Texture2D g_texShadowCmp : register(t7, space1);
SamplerComparisonState g_samShadowCmp : register(s7, space1);
Texture2D g_texShadow : register(t8, space1);
SamplerState g_samShadow : register(s8, space1);
struct VSI
{
@ -30,10 +39,12 @@ struct VSI
struct VSO
{
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
float2 tcLand : TEXCOORD1;
float4 dirToEye : TEXCOORD2;
float4 pos : SV_Position;
float2 tc0 : TEXCOORD0;
float3 tcLand_height : TEXCOORD1;
float4 tcScreen : TEXCOORD2;
float4 dirToEye_depth : TEXCOORD3;
float3 posW : TEXCOORD4;
};
struct FSO
@ -41,25 +52,18 @@ struct FSO
float4 color : SV_Target0;
};
static const float g_bestPrecision = 50.0;
static const float g_waterPatchTexelCenter = 0.5 / 1024.0;
static const float g_beachTexelCenter = 0.5 / 16.0;
static const float g_beachMip = 6.0;
static const float g_beachHeightScale = 2.0;
static const float g_adjustHeightBy = 1.0;
static const float g_beachHeightScale = 3.0;
static const float g_adjustHeightBy = 0.7;
static const float g_foamScale = 8.0;
static const float g_shadeScale = 1.0 / 32.0;
static const float g_wavesZoneMaskCenter = -10.0;
static const float g_wavesZoneMaskContrast = 0.12;
static const float g_wavesMaskScaleBias = 20.0;
float ToLandMask(float height)
{
return saturate(height * 0.2 + 1.0); // [-5 to 0] -> [0 to 1]
}
float ToPlanktonMask(float height)
{
return saturate(height * 0.02 + 1.0);
}
float GetWaterHeightAt(
float2 GetWaterHeightAt(
Texture2D texTerrainHeightmap, SamplerState samTerrainHeightmap,
Texture2D texGenHeightmap, SamplerState samGenHeightmap,
float2 pos, float waterScale, float mapSideInv,
@ -68,15 +72,15 @@ float GetWaterHeightAt(
const float2 tc = pos * waterScale;
const float2 tcLand = pos * mapSideInv + 0.5;
float landHeight = 0.0;
float landHeight;
{
const float mip = log2(max(1.0, distToEye * landDistToMipScale));
const float texelCenter = 0.5 * mapSideInv * exp2(mip);
landHeight = texTerrainHeightmap.SampleLevel(samTerrainHeightmap, tcLand + texelCenter, mip).r + g_bestPrecision;
landHeight = UnpackTerrainHeight(texTerrainHeightmap.SampleLevel(samTerrainHeightmap, tcLand + texelCenter, mip).r);
}
const float landMask = ToLandMask(landHeight);
float seaWaterHeight = 0.0;
float seaWaterHeight;
{
const float mip = log2(max(1.0, distToEye * distToMipScale));
const float texelCenter = g_waterPatchTexelCenter * exp2(mip);
@ -89,7 +93,7 @@ float GetWaterHeightAt(
const float scale = saturate(distToEye); // Too close -> wave can get clipped.
return (height + g_adjustHeightBy) * scale * scale;
return float2((height + g_adjustHeightBy) * scale * scale, landHeight);
}
#ifdef _VS
@ -97,29 +101,48 @@ VSO mainVS(VSI si)
{
VSO so;
const float3 eyePos = g_ubWaterVS._eyePos.xyz;
const float waterScale = g_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.x;
const float distToMipScale = g_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.y;
const float mapSideInv = g_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.z;
const float landDistToMipScale = g_ubWaterVS._waterScale_distToMipScale_mapSideInv_landDistToMipScale.w;
const float3 eyePos = g_ubWaterVS._eyePos_mapSideInv.xyz;
const float mapSideInv = g_ubWaterVS._eyePos_mapSideInv.w;
const float waterScale = g_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.x;
const float distToMipScale = g_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.y;
const float landDistToMipScale = g_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.z;
const float wavePhase = g_ubWaterVS._waterScale_distToMipScale_landDistToMipScale_wavePhase.w;
float3 posW = mul(float4(si.pos.xyz, 1), g_ubWaterVS._matW).xyz;
const float3 dirToEye = eyePos - posW;
const float distToEye = length(dirToEye);
const float height = GetWaterHeightAt(
const float2 height_landHeight = GetWaterHeightAt(
g_texTerrainHeightmapVS, g_samTerrainHeightmapVS,
g_texGenHeightmapVS, g_samGenHeightmapVS,
posW.xz, waterScale, mapSideInv,
distToEye, distToMipScale, landDistToMipScale);
posW.y = height;
const float2 tc0 = posW.xz * waterScale;
// <Waves>
float wave;
{
const float phaseShift = saturate(g_texFoamVS.SampleLevel(g_samFoamVS, tc0 * g_shadeScale, 4.0).r * 2.0);
const float wavesZoneMask = saturate(1.0 - g_wavesZoneMaskContrast * abs(height_landHeight.y - g_wavesZoneMaskCenter));
const float2 wavesMaskCenter = frac(wavePhase + phaseShift + float2(0.0, 0.5)) * g_wavesMaskScaleBias - g_wavesMaskScaleBias;
const float2 absDeltaAsym = AsymAbs(height_landHeight.y - wavesMaskCenter, -1.0, 3.0);
const float wavesMask = smoothstep(0.0, 1.0, saturate(1.0 - 0.15 * min(absDeltaAsym.x, absDeltaAsym.y)));
wave = wavesMask * wavesZoneMask;
}
// </Waves>
posW.y = height_landHeight.x + wave * 2.0 * saturate(1.0 / (distToEye * 0.01));
so.pos = mul(float4(posW, 1), g_ubWaterVS._matVP);
so.tc0 = posW.xz * waterScale;
so.tcLand = (posW.xz + 0.5) * mapSideInv + 0.5;
so.dirToEye.xyz = dirToEye;
so.dirToEye.w = distToEye;
so.tc0 = tc0;
so.tcLand_height.xy = (posW.xz + 0.5) * mapSideInv + 0.5;
so.tcLand_height.z = height_landHeight.x;
so.tcScreen = mul(float4(posW, 1), g_ubWaterVS._matScreen);
so.dirToEye_depth.xyz = dirToEye;
so.dirToEye_depth.w = so.pos.z;
so.posW = posW;
return so;
}
@ -130,73 +153,176 @@ FSO mainFS(VSO si)
{
FSO so;
const float3 dirToEye = normalize(si.dirToEye.xyz);
const float phase = g_ubWaterFS._phase_wavePhase_camScale.x;
const float wavePhase = g_ubWaterFS._phase_wavePhase_camScale.y;
const float2 camScale = g_ubWaterFS._phase_wavePhase_camScale.zw;
const float height = si.tcLand_height.z;
const float3 dirToEye = normalize(si.dirToEye_depth.xyz);
const float depth = si.dirToEye_depth.w;
const float4 tcScreenInv = 1.0 / si.tcScreen;
const float perspectScale = tcScreenInv.z;
const float2 tcScreen = si.tcScreen.xy * tcScreenInv.w;
// <Land>
float beachWaterHeight = 0.0;
float landHeight = 0.0;
float landMask = 0.0;
float landMaskStatic = 0.0;
float beachWaterHeight;
float landHeight;
float landMask;
float landMaskStatic;
{
beachWaterHeight = g_texGenHeightmap.SampleLevel(g_samGenHeightmap, si.tc0 + g_beachTexelCenter, g_beachMip).r * g_beachHeightScale + g_adjustHeightBy;
landHeight = g_texTerrainHeightmap.Sample(g_samTerrainHeightmap, si.tcLand).r + g_bestPrecision;
landHeight = UnpackTerrainHeight(g_texTerrainHeightmap.Sample(g_samTerrainHeightmap, si.tcLand_height.xy).r);
landMask = ToLandMask(landHeight - beachWaterHeight);
landMaskStatic = lerp(saturate((ToLandMask(landHeight) - 0.8) * 5.0), landMask, 0.1);
}
const float alpha = saturate((1.0 - landMask) * 20.0);
// </Land>
// <Foam>
float4 foamColor = 0.0;
// <Waves>
float wave;
float fresnelDimmer; // A trick to make waves look more 3D.
{
const float2 tcFoam = si.tc0 * g_foamScale;
const float2 tcFoamA = tcFoam + g_ubWaterFS._phase.x + float2(0.5, 0.0);
const float2 tcFoamB = tcFoam - g_ubWaterFS._phase.x;
const float3 foamColorA = g_texFoam.Sample(g_samFoam, tcFoamA).rgb;
const float3 foamColorB = g_texFoam.Sample(g_samFoam, tcFoamB).rgb;
foamColor.rgb = lerp(foamColorA, foamColorB, 0.5) * 2.0;
foamColor.a = saturate(foamColor.b * 2.0);
const float phaseShift = saturate(g_texFoam.SampleLevel(g_samFoam, si.tc0 * g_shadeScale, 4.0).r * 2.0);
const float wavesZoneMask = saturate(1.0 - g_wavesZoneMaskContrast * abs(landHeight - g_wavesZoneMaskCenter));
const float2 wavesMaskCenter = frac(wavePhase + phaseShift + float2(0.0, 0.5)) * g_wavesMaskScaleBias - g_wavesMaskScaleBias;
const float2 delta = landHeight - wavesMaskCenter;
const float2 absDelta = abs(delta);
const float2 absDeltaAsym = AsymAbs(delta, -1.0, 3.5);
const float wavesMask = saturate(1.0 - 0.5 * min(absDeltaAsym.x, absDeltaAsym.y));
wave = wavesMask * wavesZoneMask;
const float biggerWavesMask = saturate(1.0 - 0.5 * min(absDelta.x, absDelta.y));
fresnelDimmer = saturate(1.0 - biggerWavesMask * wavesZoneMask * 1.5);
}
const float foamAlpha = 0.01 + 0.99 * landMaskStatic * foamColor.a;
// </Foam>
// <Plankton>
float3 planktonColor = 0.0;
{
const float3 planktonColorShallow = float3(0.02, 0.42, 0.52);
const float3 planktonColorDeep = float3(0.01, 0.011, 0.06);
planktonColor = lerp(planktonColorDeep, planktonColorShallow, ToPlanktonMask(landHeight));
planktonColor *= 0.5;
}
// </Plankton>
// </Waves>
// <Normal>
float3 normal = 0.0;
float3 normal;
{
const float3 rawNormal = g_texGenNormals.Sample(g_samGenNormals, si.tc0).rgb;
const float3 normalWithLand = lerp(rawNormal, float3(0.5, 0.5, 1), landMask * 0.8);
const float3 normalWithLand = lerp(rawNormal, float3(0.5, 0.5, 1), saturate(landMask * 0.8 + wave));
normal = normalize(normalWithLand.xzy * float3(-2, 2, -2) + float3(1, -1, 1));
}
// </Normal>
const float spec = lerp(1.0, 0.1, foamAlpha);
const float gloss = lerp(1024.0, 4.0, foamAlpha);
// <Reflection>
float3 reflectColor;
{
const float fudgeFactor = 32.0;
const float3 flatReflect = reflect(-dirToEye, float3(0, 1, 0));
const float3 bumpReflect = reflect(-dirToEye, normal);
const float3 delta = bumpReflect - flatReflect;
const float2 viewSpaceOffsetPerMeter = mul(float4(delta, 0), g_ubWaterFS._matV).xy;
const float2 offset = viewSpaceOffsetPerMeter * saturate(perspectScale) * camScale * fudgeFactor;
reflectColor = g_texReflection.Sample(g_samReflection, tcScreen + max(offset, float2(-1, 0))).rgb;
reflectColor = ReflectionDimming(reflectColor, 0.8);
}
// </Reflection>
const float3 waterColor = lerp(planktonColor, foamColor.rgb, foamAlpha);
const float3 skyColor = float3(0.1, 0.26, 0.67) * 750.0;
// <Refraction>
float3 refractColor;
{
const float fudgeFactor = (0.1 + 0.9 * abs(dirToEye.y) * abs(dirToEye.y)) * 2.5;
const float waterDepth = -landHeight;
const float2 tcScreen2 = tcScreen * 2.0 - 1.0;
const float mask = saturate(dot(tcScreen2, tcScreen2));
const float3 bumpRefract = refract(-dirToEye, normal, 1.0 / 1.33);
const float3 delta = bumpRefract + dirToEye;
const float2 viewSpaceOffsetPerMeter = mul(float4(delta, 0), g_ubWaterFS._matV).xy * (1.0 - mask);
const float2 offset = viewSpaceOffsetPerMeter * waterDepth * saturate(perspectScale) * camScale * fudgeFactor;
const float2 tcRefractR = tcScreen + offset * 0.9;
const float2 tcRefractG = tcScreen + offset * 1.0;
const float2 tcRefractB = tcScreen + offset * 1.1;
refractColor = float3(
g_texRefraction.SampleLevel(g_samRefraction, tcRefractR, 0.0).r,
g_texRefraction.SampleLevel(g_samRefraction, tcRefractG, 0.0).g,
g_texRefraction.SampleLevel(g_samRefraction, tcRefractB, 0.0).b);
}
// </Refraction>
const float shade = g_texFoam.Sample(g_samFoam, si.tc0 * g_shadeScale).r;
// <Foam>
float4 foamColor;
float foamHeightAlpha;
{
const float2 tcFoam = si.tc0 * g_foamScale;
const float2 tcFoamA = tcFoam + phase + float2(0.5, 0.0);
const float2 tcFoamB = tcFoam - phase;
const float3 foamColorA = g_texFoam.Sample(g_samFoam, tcFoamA).rgb;
const float3 foamColorB = g_texFoam.Sample(g_samFoam, tcFoamB).rgb;
foamColor.rgb = lerp(foamColorA, foamColorB, 0.5);
foamColor.a = saturate(foamColor.b * 2.0);
const float a = saturate(height - 0.1);
const float a2 = a * a;
const float a4 = a2 * a2;
foamHeightAlpha = saturate(a4 * a4 + wave * 0.75);
const float complement = 1.0 - shade;
const float mask = saturate((landMask - 0.9) * 10.0 * (1.0 - shade * 3.0)) * complement * complement;
const float superfoam = saturate(mask * (1.0 - mask) * 3.0);
foamColor = lerp(foamColor, 1.0, max(superfoam * superfoam, saturate(wave * 0.75)));
}
const float foamAlpha = 0.002 + 0.998 * saturate(landMaskStatic + foamHeightAlpha) * foamColor.a;
// </Foam>
// <Plankton>
float3 planktonColor;
float refractMask;
{
const float diffuseMask = ToWaterDiffuseMask(landHeight);
planktonColor = lerp(g_ubWaterFS._diffuseColorDeep.rgb, g_ubWaterFS._diffuseColorShallow.rgb, diffuseMask);
planktonColor *= 0.3 + 0.2 * saturate(shade - wave);
refractMask = saturate((diffuseMask - 0.5) * 2.0);
}
// </Plankton>
const float spec = lerp(1.0, 0.1, foamAlpha);
const float gloss = lerp(1200.0, 4.0, foamAlpha);
const float2 lamScaleBias = float2(1, 0.2);
// <Shadow>
float shadowMask;
{
float4 config = g_ubWaterFS._shadowConfig;
const float lamBiasMask = saturate(lamScaleBias.y * config.y);
config.y = 1.0 - lamBiasMask; // Keep penumbra blurry.
const float3 posForShadow = AdjustPosForShadow(si.posW, normal, g_ubWaterFS._dirToSun.xyz, depth);
const float4 tcShadow = ShadowCoords(float4(posForShadow, 1), g_ubWaterFS._matSunShadow, depth);
shadowMask = ShadowMapCSM(
g_texShadowCmp,
g_samShadowCmp,
g_texShadow,
g_samShadow,
tcShadow,
config,
g_ubWaterFS._splitRanges,
g_ubWaterFS._matSunShadow,
g_ubWaterFS._matSunShadowCSM1,
g_ubWaterFS._matSunShadowCSM2,
g_ubWaterFS._matSunShadowCSM3);
}
// </Shadow>
const float4 litRet = VerusLit(g_ubWaterFS._dirToSun.xyz, normal, dirToEye,
gloss,
float2(1, 0.3),
lamScaleBias,
float4(0, 0, 1, 0),
1.0);
const float fresnelTerm = FresnelSchlick(0.02, 0.97, litRet.w);
const float fresnelTerm = FresnelSchlick(0.03, 0.6 * fresnelDimmer, litRet.w);
const float3 diffColor = litRet.y * g_ubWaterFS._sunColor.rgb * waterColor;
const float3 specColor = litRet.z * g_ubWaterFS._sunColor.rgb * spec + skyColor * fresnelTerm;
const float3 diff = litRet.y * g_ubWaterFS._sunColor.rgb * shadowMask + g_ubWaterFS._ambientColor.rgb;
const float3 diffColorFoam = foamColor.rgb * diff;
const float3 diffColorOpaque = planktonColor * diff;
const float3 diffColor = lerp(lerp(diffColorOpaque, refractColor, refractMask), diffColorFoam, foamAlpha);
const float3 specColor = max(litRet.z * g_ubWaterFS._sunColor.rgb * shadowMask * spec, reflectColor) * fresnelTerm;
so.color.rgb = diffColor + specColor;
const float fog = ComputeFog(depth, g_ubWaterFS._fogColor.a);
so.color.rgb = lerp(diffColor * (1.0 - fresnelTerm) + specColor, g_ubWaterFS._fogColor.rgb, fog);
so.color.a = alpha;
clip(so.color.a - 0.01);

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