2020.6
This commit is contained in:
parent
ee5afaab96
commit
043c4c9e65
|
@ -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();
|
||||
|
|
|
@ -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=";
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, ®ion);
|
||||
}
|
||||
|
||||
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, ®ion);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@ namespace verus
|
|||
input,
|
||||
shadow,
|
||||
aniso, // Most common sampler for 3D.
|
||||
anisoClamp,
|
||||
linearMipL,
|
||||
nearestMipL,
|
||||
linearMipN,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
#include "State.h"
|
||||
#include "StateMachine.h"
|
||||
#include "Spirit.h"
|
||||
#include "BaseCharacter.h"
|
||||
#include "BaseGame.h"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#include "Linear.h"
|
||||
#include "Convert.h"
|
||||
#include "Timer.h"
|
||||
#include "Cooldown.h"
|
||||
#include "EngineInit.h"
|
||||
#include "GlobalVarsClipboard.h"
|
||||
|
||||
|
|
|
@ -7,6 +7,11 @@ Object::Object()
|
|||
_flags = 0;
|
||||
}
|
||||
|
||||
Object::Object(const Object& that) :
|
||||
_flags(that._flags.load())
|
||||
{
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
VERUS_RT_ASSERT(!IsInitialized());
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace verus
|
|||
|
||||
protected:
|
||||
Object();
|
||||
Object(const Object& that);
|
||||
virtual ~Object();
|
||||
|
||||
void Init();
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue