This commit is contained in:
Dmitry 2023-04-01 19:21:00 +03:00
parent b8941ef04e
commit 8eb4422cd3
123 changed files with 2141 additions and 825 deletions

View File

@ -486,7 +486,7 @@ void TextureD3D11::ClearCshGenerateMips()
if (!_vCshGenerateMips.empty())
{
VERUS_QREF_RENDERER;
auto shader = renderer.GetShaderGenerateMips();
auto shader = (_desc._flags & TextureDesc::Flags::cubeMap) ? renderer.GetShaderGenerateCubeMapMips() : renderer.GetShaderGenerateMips();
for (auto& csh : _vCshGenerateMips)
shader->FreeDescriptorSet(csh);
_vCshGenerateMips.clear();

View File

@ -3,6 +3,7 @@
#define SDL_VIDEO_DRIVER_WINRT 1
#define VERUS_INCLUDE_D3D11
#define VERUS_INCLUDE_PIX
#define XR_USE_GRAPHICS_API_D3D11
#include <verus.h>

View File

@ -315,6 +315,27 @@ void CommandBufferD3D12::TraceRays(int width, int height, int depth)
//GetD3DGraphicsCommandList()->DispatchRays(&desc);
}
void CommandBufferD3D12::ProfilerBeginEvent(UINT32 color, CSZ text)
{
#if defined(VERUS_INCLUDE_PIX) && defined(VERUS_PROFILER_CALLS)
PIXBeginEvent(GetD3DGraphicsCommandList(), VERUS_COLOR_TO_D3D(color), text);
#endif
}
void CommandBufferD3D12::ProfilerEndEvent()
{
#if defined(VERUS_INCLUDE_PIX) && defined(VERUS_PROFILER_CALLS)
PIXEndEvent(GetD3DGraphicsCommandList());
#endif
}
void CommandBufferD3D12::ProfilerSetMarker(UINT32 color, CSZ text)
{
#if defined(VERUS_INCLUDE_PIX) && defined(VERUS_PROFILER_CALLS)
PIXSetMarker(GetD3DGraphicsCommandList(), VERUS_COLOR_TO_D3D(color), text);
#endif
}
ID3D12GraphicsCommandList3* CommandBufferD3D12::GetD3DGraphicsCommandList() const
{
VERUS_QREF_RENDERER;

View File

@ -53,6 +53,10 @@ namespace verus
virtual void DispatchMesh(int groupCountX, int groupCountY, int groupCountZ) override;
virtual void TraceRays(int width, int height, int depth) override;
virtual void ProfilerBeginEvent(UINT32 color, CSZ text) override;
virtual void ProfilerEndEvent() override;
virtual void ProfilerSetMarker(UINT32 color, CSZ text) override;
//
// D3D12
//

View File

@ -620,7 +620,7 @@ void TextureD3D12::ClearCshGenerateMips()
if (!_vCshGenerateMips.empty())
{
VERUS_QREF_RENDERER;
auto shader = renderer.GetShaderGenerateMips();
auto shader = (_desc._flags & TextureDesc::Flags::cubeMap) ? renderer.GetShaderGenerateCubeMapMips() : renderer.GetShaderGenerateMips();
for (auto& csh : _vCshGenerateMips)
shader->FreeDescriptorSet(csh);
_vCshGenerateMips.clear();

View File

@ -3,6 +3,7 @@
#define SDL_VIDEO_DRIVER_WINRT 1
#define VERUS_INCLUDE_D3D12
#define VERUS_INCLUDE_PIX
#define XR_USE_GRAPHICS_API_D3D12
#include <verus.h>

View File

@ -235,6 +235,7 @@ Vector<CSZ> RendererVulkan::GetRequiredExtensions()
void RendererVulkan::CreateInstance()
{
VERUS_QREF_CONST_SETTINGS;
VkResult res = VK_SUCCESS;
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
@ -244,20 +245,16 @@ void RendererVulkan::CreateInstance()
const auto vExtensions = GetRequiredExtensions();
const int major = (VERUS_SDK_VERSION >> 24) & 0xFF;
const int minor = (VERUS_SDK_VERSION >> 16) & 0xFF;
const int patch = (VERUS_SDK_VERSION) & 0xFFFF;
VkValidationFeatureEnableEXT enabledValidationFeatures[] = { VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT };
VkValidationFeaturesEXT vkvf = { VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT };
vkvf.enabledValidationFeatureCount = VERUS_COUNT_OF(enabledValidationFeatures);
vkvf.pEnabledValidationFeatures = enabledValidationFeatures;
VkApplicationInfo vkai = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
vkai.pApplicationName = "Game";
vkai.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
vkai.pEngineName = "Verus";
vkai.engineVersion = VK_MAKE_VERSION(major, minor, patch);
vkai.pApplicationName = settings._info._appName;
vkai.applicationVersion = settings._info._appVersion;
vkai.pEngineName = settings._info._engineName;
vkai.engineVersion = settings._info._engineVersion;
vkai.apiVersion = s_apiVersion;
VkInstanceCreateInfo vkici = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };

View File

@ -536,7 +536,7 @@ Continue TextureVulkan::Scheduled_Update()
if (!_vCshGenerateMips.empty())
{
VERUS_QREF_RENDERER;
auto shader = renderer.GetShaderGenerateMips();
auto shader = (_desc._flags & TextureDesc::Flags::cubeMap) ? renderer.GetShaderGenerateCubeMapMips() : renderer.GetShaderGenerateMips();
for (auto& csh : _vCshGenerateMips)
shader->FreeDescriptorSet(csh);
_vCshGenerateMips.clear();

View File

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Compressonator_4.3.206\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.5\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.22.0-bin\include;C:\Home\Middleware\OpenXR-SDK-release-1.0.25\include;C:\Home\Middleware\SDL2-2.0.22\include;C:\VulkanSDK\1.3.239.0\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_4.3.206\lib\VS2019\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.5\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.22.0-bin\libs\Win64;C:\Home\Middleware\OpenXR-SDK-release-1.0.25\lib;C:\Home\Middleware\SDL2-2.0.22\lib\x64;C:\VulkanSDK\1.3.239.0\Lib;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Compressonator_4.3.206\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.5\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.22.0-bin\include;C:\Home\Middleware\OpenXR-SDK-release-1.0.27\include;C:\Home\Middleware\SDL2-2.0.22\include;C:\Home\Middleware\WinPixEventRuntime\include;C:\VulkanSDK\1.3.239.0\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_4.3.206\lib\VS2019\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.5\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.22.0-bin\libs\Win64;C:\Home\Middleware\OpenXR-SDK-release-1.0.27\lib;C:\Home\Middleware\SDL2-2.0.22\lib\x64;C:\Home\Middleware\WinPixEventRuntime\lib;C:\VulkanSDK\1.3.239.0\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View File

@ -304,6 +304,7 @@
<ClInclude Include="src\World\WorldManager.h" />
<ClInclude Include="src\World\MaterialManager.h" />
<ClInclude Include="src\World\Mesh.h" />
<ClInclude Include="src\World\WorldNodes\BlockChainNode.h" />
<ClInclude Include="src\World\WorldNodes\BlockNode.h" />
<ClInclude Include="src\World\WorldNodes\ControlPointNode.h" />
<ClInclude Include="src\World\WorldNodes\EmitterNode.h" />
@ -636,6 +637,7 @@
<ClCompile Include="src\World\WorldManager.cpp" />
<ClCompile Include="src\World\MaterialManager.cpp" />
<ClCompile Include="src\World\Mesh.cpp" />
<ClCompile Include="src\World\WorldNodes\BlockChainNode.cpp" />
<ClCompile Include="src\World\WorldNodes\BlockNode.cpp" />
<ClCompile Include="src\World\WorldNodes\ControlPointNode.cpp" />
<ClCompile Include="src\World\WorldNodes\EmitterNode.cpp" />

View File

@ -810,6 +810,9 @@
<ClInclude Include="src\World\WorldNodes\PathNode.h">
<Filter>src\World\WorldNodes</Filter>
</ClInclude>
<ClInclude Include="src\World\WorldNodes\BlockChainNode.h">
<Filter>src\World\WorldNodes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -1397,6 +1400,9 @@
<ClCompile Include="src\World\WorldNodes\PathNode.cpp">
<Filter>src\World\WorldNodes</Filter>
</ClCompile>
<ClCompile Include="src\World\WorldNodes\BlockChainNode.cpp">
<Filter>src\World\WorldNodes</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Lib.hlsl">

View File

@ -32,7 +32,7 @@ void Collection::Async_WhenLoaded(CSZ url, RcBlob blob)
md._motion.ComputePlaybackSpeed(md._duration);
}
void Collection::AddMotion(CSZ name, bool loop, float duration)
void Collection::AddMotion(CSZ name, bool looping, float duration, bool fast)
{
CSZ shortName = name;
if (_useShortNames)
@ -42,7 +42,8 @@ void Collection::AddMotion(CSZ name, bool loop, float duration)
}
RMotionData md = *TStoreMotions::Insert(shortName);
md._duration = duration;
md._loop = loop;
md._looping = looping;
md._fast = fast;
IO::Async::I().Load(name, this);
}
@ -107,8 +108,8 @@ void Animation::Update(int layerCount, PLayer pLayers)
md._motion.ProcessTriggers(_time, this, GetTriggerStatesArray());
if (_time >= duration)
{
_playing = md._loop; // Continue?
_time = md._loop ? fmod(_time, duration) : duration;
_playing = md._looping; // Continue?
_time = md._looping ? fmod(_time, duration) : duration;
md._motion.ResetTriggers(GetTriggerStatesArray()); // New loop, reset triggers.
if (_pDelegate)
_pDelegate->Animation_OnEnd(_C(_currentMotion)); // This can call TransitionTo and change everything.
@ -178,11 +179,17 @@ void Animation::Pause()
void Animation::TransitionTo(CSZ name, Interval duration, int randTime, PMotion pFromMotion)
{
bool prevMotionFast = false;
PMotion pMotion = pFromMotion;
if (!_currentMotion.empty() || pFromMotion) // Deal with previous motion?
{
PMotionData pMotionData = nullptr;
if (!pFromMotion)
pMotion = &_pCollection->Find(_C(_currentMotion))->_motion;
{
pMotionData = _pCollection->Find(_C(_currentMotion));
pMotion = &pMotionData->_motion;
prevMotionFast = pMotionData->_fast;
}
if (_transition) // Already in transition?
pMotion->BindBlendMotion(&_transitionMotion, Math::ApplyEasing(_easing, _transitionTime / _transitionDuration));
pMotion->BakeMotionAt(_time, _transitionMotion); // Capture current pose.
@ -209,8 +216,17 @@ void Animation::TransitionTo(CSZ name, Interval duration, int randTime, PMotion
pMotion->ResetTriggers(GetTriggerStatesArray());
if (name)
{
pMotion = &_pCollection->Find(name)->_motion;
PMotionData pMotionData = _pCollection->Find(name);
pMotion = &pMotionData->_motion;
pMotion->ResetTriggers(GetTriggerStatesArray());
if (prevMotionFast)
_easing = pMotionData->_fast ? Easing::quadInOut : Easing::cubicOut;
else
_easing = pMotionData->_fast ? Easing::cubicIn : Easing::quadInOut;
}
else
{
_easing = prevMotionFast ? Easing::cubicOut : Easing::quadInOut;
}
// Reset time:

View File

@ -17,7 +17,8 @@ namespace verus
{
Motion _motion;
float _duration = 0;
bool _loop = true;
bool _looping = true;
bool _fast = false; // For auto easing.
};
VERUS_TYPEDEFS(MotionData);
@ -33,7 +34,7 @@ namespace verus
virtual void Async_WhenLoaded(CSZ url, RcBlob blob) override;
void AddMotion(CSZ name, bool loop = true, float duration = 0);
void AddMotion(CSZ name, bool looping = true, float duration = 0, bool fast = false);
void DeleteAll();
PMotionData Find(CSZ name);
int GetMaxBones();
@ -68,7 +69,7 @@ namespace verus
String _currentMotion;
String _prevMotion;
Vector<int> _vTriggerStates;
Easing _easing = Easing::quadInOut;
Easing _easing = Easing::none;
float _time = 0;
float _transitionDuration = 0;
float _transitionTime = 0;
@ -99,8 +100,6 @@ namespace verus
Interval duration = 0.5f, int randTime = -1, PMotion pFromMotion = nullptr);
bool IsInTransition() const { return _transition; }
void SetEasing(Easing easing) { _easing = easing; }
virtual void Motion_OnTrigger(CSZ name, int state) override;
PMotion GetMotion();

View File

@ -162,6 +162,8 @@ void Settings::ParseCommandLineArgs(int argc, char* argv[])
_commandLine._borderlessWindowed = true;
if (IsArg(i, "--restarted"))
_commandLine._restarted = true;
if (IsArg(i, "--xr-height") && i + 1 < argc)
_commandLine._xrHeight = static_cast<float>(atof(argv[i + 1]));
}
SetFilename("Settings.json");
@ -233,6 +235,8 @@ void Settings::Load()
_sceneShadowQuality = static_cast<Quality>(GetI("sceneShadowQuality", +_sceneShadowQuality));
_sceneWaterQuality = static_cast<WaterQuality>(GetI("sceneWaterQuality", +_sceneWaterQuality));
_uiLang = GetS("uiLang", _C(_uiLang));
_xrFOV = GetF("xrFOV", _xrFOV);
_xrHeight = GetF("xrHeight", _xrHeight);
}
void Settings::HandleHighDpi()
@ -276,10 +280,22 @@ void Settings::HandleCommandLineArgs()
_displayMode = DisplayMode::borderlessWindowed;
MatchScreen();
}
if (_commandLine._xrHeight != -FLT_MAX)
_xrHeight = _commandLine._xrHeight;
}
void Settings::Validate()
{
if (!_info._appName)
_info._appName = "Unnamed";
if (!_info._appVersion)
_info._appVersion = VERUS_MAKE_VERSION(0, 1, 0);
if (!_info._engineName)
_info._engineName = VERUS_ENGINE_NAME;
if (!_info._engineVersion)
_info._engineVersion = VERUS_SDK_VERSION;
_displayFOV = Math::Clamp<float>(_displayFOV, 60, 90);
_displayOffscreenScale = Math::Clamp(_displayOffscreenScale, 0.25f, 4.f);
_displaySizeWidth = Math::Clamp(_displaySizeWidth, 480, 0x2000);
@ -291,6 +307,8 @@ void Settings::Validate()
_sceneGrassDensity = Math::Clamp(_sceneGrassDensity, 100, 1000);
_sceneShadowQuality = Math::Clamp(_sceneShadowQuality, Quality::low, Quality::ultra);
_sceneWaterQuality = Math::Clamp(_sceneWaterQuality, WaterQuality::solidColor, WaterQuality::trueWavesRefraction);
_xrFOV = Math::Clamp<float>(_xrFOV, 45, 135);
_xrHeight = Math::Clamp<float>(_xrHeight, -3, 3);
if (_uiLang != "RU" && _uiLang != "EN")
_uiLang = "EN";
@ -329,6 +347,8 @@ void Settings::Save()
Set("sceneShadowQuality", +_sceneShadowQuality);
Set("sceneWaterQuality", +_sceneWaterQuality);
Set("uiLang", _C(_uiLang));
Set("xrFOV", _xrFOV);
Set("xrHeight", _xrHeight);
Json::Save();
}

View File

@ -12,6 +12,16 @@ namespace verus
borderlessWindowed
};
class Info
{
public:
CSZ _appName = nullptr;
UINT32 _appVersion = 0;
CSZ _engineName = nullptr;
UINT32 _engineVersion = 0;
};
VERUS_TYPEDEFS(Info);
class QualitySettings
{
public:
@ -115,12 +125,13 @@ namespace verus
public:
struct CommandLine
{
int _gapi = -1;
int _openXR = -1;
bool _exclusiveFullscreen = false;
bool _windowed = false;
bool _borderlessWindowed = false;
bool _restarted = false;
int _gapi = -1;
int _openXR = -1;
float _xrHeight = -FLT_MAX;
bool _exclusiveFullscreen = false;
bool _windowed = false;
bool _borderlessWindowed = false;
bool _restarted = false;
};
enum Platform : int
@ -140,9 +151,12 @@ namespace verus
bool _openXR = false;
bool _physicsSupportDebugDraw = false;
String _uiLang = "EN";
float _xrFOV = 110;
float _xrHeight = 0;
CommandLine _commandLine;
Limits _limits;
String _imguiFont;
Info _info;
float _highDpiScale = 1;
Platform _platform = Platform::classic;

View File

@ -77,6 +77,12 @@ namespace verus
virtual void TraceRays(int width, int height, int depth) {} // WIP.
// </Draw>
// <Profiler>
virtual void ProfilerBeginEvent(UINT32 color, CSZ text) {}
virtual void ProfilerEndEvent() {}
virtual void ProfilerSetMarker(UINT32 color, CSZ text) {}
// </Profiler>
RcVector4 GetViewportSize() const { return _viewportSize; }
RcVector4 GetViewScaleBias() const { return _viewScaleBias; }
};

View File

@ -92,9 +92,13 @@ bool BaseExtReality::CheckRequiredExtensions() const
void BaseExtReality::CreateInstance()
{
VERUS_QREF_CONST_SETTINGS;
XrResult res = XR_SUCCESS;
XrInstanceCreateInfo xrici = { XR_TYPE_INSTANCE_CREATE_INFO };
strcpy_s(xrici.applicationInfo.applicationName, "TestApp");
strcpy_s(xrici.applicationInfo.applicationName, settings._info._appName);
xrici.applicationInfo.applicationVersion = settings._info._appVersion;
strcpy_s(xrici.applicationInfo.engineName, settings._info._engineName);
xrici.applicationInfo.engineVersion = settings._info._engineVersion;
xrici.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
xrici.enabledExtensionCount = Utils::Cast32(_vRequiredExtensions.size());
xrici.enabledExtensionNames = _vRequiredExtensions.data();

View File

@ -564,7 +564,11 @@ void DeferredShading::BeginGeometryPass()
_activeGeometryPass = true;
_frame = renderer.GetFrameCount();
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(0, 128, 128, 255), "DeferredShading/GeometryPass...");
cb->BeginRenderPass(_rph, _fbh,
{
_tex[TEX_GBUFFER_0]->GetClearValue(),
_tex[TEX_GBUFFER_1]->GetClearValue(),
@ -583,6 +587,9 @@ void DeferredShading::EndGeometryPass()
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeGeometryPass = false;
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_END_EVENT(cb);
}
bool DeferredShading::BeginLightingPass(bool ambient, bool terrainOcclusion)
@ -594,6 +601,8 @@ bool DeferredShading::BeginLightingPass(bool ambient, bool terrainOcclusion)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 255, 96, 255), "...DeferredShading/LightingPass");
cb->NextSubpass();
if (ambient)
@ -683,8 +692,12 @@ void DeferredShading::EndLightingPass()
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass && !_activeForwardRendering);
_activeLightingPass = false;
auto cb = renderer.GetCommandBuffer();
_shader[SHADER_LIGHT]->EndBindDescriptors();
renderer.GetCommandBuffer()->EndRenderPass();
cb->EndRenderPass();
VERUS_PROFILER_END_EVENT(cb);
}
void DeferredShading::BeginComposeAndForwardRendering(bool underwaterMask)
@ -699,6 +712,8 @@ void DeferredShading::BeginComposeAndForwardRendering(bool underwaterMask)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 255, 255, 255), "DeferredShading/ComposeAndForwardRendering");
// Compose buffers, that is perform "final color = albedo * diffuse + specular" computation. Result is still HDR:
cb->BeginRenderPass(_rphCompose, _fbhCompose,
{
@ -745,7 +760,11 @@ void DeferredShading::EndComposeAndForwardRendering()
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && _activeForwardRendering);
_activeForwardRendering = false;
renderer.GetCommandBuffer()->EndRenderPass();
auto cb = renderer.GetCommandBuffer();
cb->EndRenderPass();
VERUS_PROFILER_END_EVENT(cb);
}
void DeferredShading::DrawReflection()
@ -755,20 +774,25 @@ void DeferredShading::DrawReflection()
auto cb = renderer.GetCommandBuffer();
cb->BeginRenderPass(_rphReflection, _fbhReflection, { _tex[TEX_COMPOSED_A]->GetClearValue() });
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 128, 96, 255), "DeferredShading/DrawReflection");
{
s_ubReflectionVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubReflectionVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubReflectionVS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
cb->BeginRenderPass(_rphReflection, _fbhReflection, { _tex[TEX_COMPOSED_A]->GetClearValue() });
cb->BindPipeline(ssr.IsCubeMapDebugMode() ? _pipe[PIPE_REFLECTION_DEBUG] : _pipe[PIPE_REFLECTION]);
_shader[SHADER_REFLECTION]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_REFLECTION], 0);
cb->BindDescriptors(_shader[SHADER_REFLECTION], 1, _cshReflection);
_shader[SHADER_REFLECTION]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
s_ubReflectionVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubReflectionVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubReflectionVS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
cb->EndRenderPass();
cb->BindPipeline(ssr.IsCubeMapDebugMode() ? _pipe[PIPE_REFLECTION_DEBUG] : _pipe[PIPE_REFLECTION]);
_shader[SHADER_REFLECTION]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_REFLECTION], 0);
cb->BindDescriptors(_shader[SHADER_REFLECTION], 1, _cshReflection);
_shader[SHADER_REFLECTION]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
VERUS_PROFILER_END_EVENT(cb);
}
void DeferredShading::ToneMapping()
@ -777,18 +801,22 @@ void DeferredShading::ToneMapping()
auto cb = renderer.GetCommandBuffer();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeVS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 160, 255, 255), "DeferredShading/ToneMapping");
{
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeVS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
// Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve:
cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_COMPOSE], 0);
cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
// Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve:
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(cb.Get());
}
VERUS_PROFILER_END_EVENT(cb);
}
bool DeferredShading::IsLightUrl(CSZ url)
@ -839,7 +867,7 @@ void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool w
s_ubShadowFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrixDS(2).UniformBufferFormat();
s_ubShadowFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrixDS(3).UniformBufferFormat();
s_ubShadowFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixP().UniformBufferFormat();
s_ubShadowFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubShadowFS._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubShadowFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubShadowFS._shadowConfig));
cb->BindDescriptors(_shader[SHADER_LIGHT], 3);
}

View File

@ -296,7 +296,12 @@ void Renderer::Update()
void Renderer::Draw()
{
if (_pRendererDelegate)
if (!_pRendererDelegate)
return;
auto cb = GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(165, 13, 35, 255), "Renderer/Draw");
{
_currentViewType = ViewType::none;
_currentViewIndex = 0;
@ -305,45 +310,50 @@ void Renderer::Draw()
_currentViewX = 0;
_currentViewY = 0;
_pRendererDelegate->Renderer_OnDraw();
}
VERUS_PROFILER_END_EVENT(cb);
{
ViewDesc viewDesc;
viewDesc._type = ViewType::screen;
_currentViewType = viewDesc._type;
_currentViewIndex = 0;
_currentViewWidth = _screenSwapChainWidth;
_currentViewHeight = _screenSwapChainHeight;
_currentViewX = 0;
_currentViewY = 0;
_pRendererDelegate->Renderer_OnDrawView(viewDesc);
}
auto pExtReality = _pBaseRenderer->GetExtReality();
if (pExtReality->IsInitialized())
{
const int viewCount = pExtReality->LocateViews();
VERUS_FOR(i, viewCount)
{
ViewDesc viewDesc;
pExtReality->BeginView(i, viewDesc);
_currentViewType = viewDesc._type;
_currentViewIndex = viewDesc._index;
_currentViewWidth = viewDesc._vpWidth;
_currentViewHeight = viewDesc._vpHeight;
_currentViewX = viewDesc._vpX;
_currentViewY = viewDesc._vpY;
_pRendererDelegate->Renderer_OnDrawView(viewDesc);
pExtReality->EndView(i);
}
}
_currentViewType = ViewType::none;
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(128, 187, 1, 255), "Renderer/DrawView");
{
ViewDesc viewDesc;
viewDesc._type = ViewType::screen;
_currentViewType = viewDesc._type;
_currentViewIndex = 0;
_currentViewWidth = 0;
_currentViewHeight = 0;
_currentViewWidth = _screenSwapChainWidth;
_currentViewHeight = _screenSwapChainHeight;
_currentViewX = 0;
_currentViewY = 0;
_pRendererDelegate->Renderer_OnDrawView(viewDesc);
}
VERUS_PROFILER_END_EVENT(cb);
auto pExtReality = _pBaseRenderer->GetExtReality();
if (pExtReality->IsInitialized())
{
const int viewCount = pExtReality->LocateViews();
VERUS_FOR(i, viewCount)
{
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(116, 43, 144, 255), "Renderer/DrawView(XR)");
ViewDesc viewDesc;
pExtReality->BeginView(i, viewDesc);
_currentViewType = viewDesc._type;
_currentViewIndex = viewDesc._index;
_currentViewWidth = viewDesc._vpWidth;
_currentViewHeight = viewDesc._vpHeight;
_currentViewX = viewDesc._vpX;
_currentViewY = viewDesc._vpY;
_pRendererDelegate->Renderer_OnDrawView(viewDesc);
pExtReality->EndView(i);
VERUS_PROFILER_END_EVENT(cb);
}
}
_currentViewType = ViewType::none;
_currentViewIndex = 0;
_currentViewWidth = 0;
_currentViewHeight = 0;
_currentViewX = 0;
_currentViewY = 0;
}
void Renderer::BeginFrame()
@ -353,10 +363,18 @@ void Renderer::BeginFrame()
pExtReality->BeginFrame();
_pBaseRenderer->BeginFrame();
auto cb = GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_WHITE, "Renderer/Frame");
}
void Renderer::AcquireSwapChainImage()
{
auto cb = GetCommandBuffer();
VERUS_PROFILER_SET_MARKER(cb, VERUS_COLOR_WHITE, "Renderer/AcquireSwapChainImage");
switch (_currentViewType)
{
case ViewType::screen:
@ -376,6 +394,10 @@ void Renderer::AcquireSwapChainImage()
void Renderer::EndFrame()
{
auto cb = GetCommandBuffer();
VERUS_PROFILER_END_EVENT(cb);
_pBaseRenderer->EndFrame();
auto pExtReality = _pBaseRenderer->GetExtReality();
@ -537,7 +559,11 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass)
case ViewType::screen:
{
if (!pExtReality->IsInitialized())
{
VERUS_PROFILER_BEGIN_EVENT(pCB, VERUS_COLOR_BLACK, "Renderer/DrawOffscreenColor/GenerateMips");
_tex[TEX_OFFSCREEN_COLOR]->GenerateMips();
VERUS_PROFILER_END_EVENT(pCB);
}
pCB->BeginRenderPass(_rphScreenSwapChain, _fbhScreenSwapChain[_pBaseRenderer->GetSwapChainBufferIndex()], { Vector4(0) },
ViewportScissorFlags::setScissorForFramebuffer);
@ -554,7 +580,11 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass)
{
VERUS_RT_ASSERT(pExtReality->IsInitialized());
if (!_currentViewIndex)
{
VERUS_PROFILER_BEGIN_EVENT(pCB, VERUS_COLOR_BLACK, "Renderer/DrawOffscreenColor/GenerateMips");
_tex[TEX_OFFSCREEN_COLOR]->GenerateMips();
VERUS_PROFILER_END_EVENT(pCB);
}
pCB->BeginRenderPass(pExtReality->GetRenderPassHandle(), pExtReality->GetFramebufferHandle(), { Vector4(0) },
ViewportScissorFlags::setScissorForFramebuffer);

View File

@ -78,10 +78,13 @@ void Bloom::InitByAtmosphere(CGI::TexturePtr texShadow)
void Bloom::Done()
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rphLightShafts);
renderer->DeleteRenderPass(_rph);
if (CGI::Renderer::IsLoaded())
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rphLightShafts);
renderer->DeleteRenderPass(_rph);
}
VERUS_DONE(Bloom);
}
@ -148,6 +151,8 @@ void Bloom::Generate()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 96, 255, 255), "Bloom/Generate");
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_PING]->GetClearValue() },
CGI::ViewportScissorFlags::setAllForCurrentViewScaled | CGI::ViewportScissorFlags::applyHalfScale);
@ -189,7 +194,7 @@ void Bloom::Generate()
s_ubBloomLightShaftsFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrix(2).UniformBufferFormat();
s_ubBloomLightShaftsFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrix(3).UniformBufferFormat();
s_ubBloomLightShaftsFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixVP().UniformBufferFormat();
s_ubBloomLightShaftsFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubBloomLightShaftsFS._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubBloomLightShaftsFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubBloomLightShaftsFS._shadowConfig));
cb->BindPipeline(_pipe[PIPE_LIGHT_SHAFTS]);
@ -206,6 +211,8 @@ void Bloom::Generate()
if (_blurLightShafts)
Blur::I().GenerateForBloom(true);
}
VERUS_PROFILER_END_EVENT(cb);
}
CGI::TexturePtr Bloom::GetTexture() const

View File

@ -170,26 +170,28 @@ void Blur::Init()
void Blur::Done()
{
VERUS_QREF_RENDERER;
if (CGI::Renderer::IsLoaded())
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbhMotionBlur);
renderer->DeleteRenderPass(_rphMotionBlur);
renderer->DeleteFramebuffer(_fbhMotionBlur);
renderer->DeleteRenderPass(_rphMotionBlur);
renderer->DeleteFramebuffer(_fbhAntiAliasing);
renderer->DeleteRenderPass(_rphAntiAliasing);
renderer->DeleteFramebuffer(_fbhAntiAliasing);
renderer->DeleteRenderPass(_rphAntiAliasing);
_bloomHandles.DeleteFramebuffers();
_bloomHandles.DeleteRenderPasses();
_bloomHandles.DeleteFramebuffers();
_bloomHandles.DeleteRenderPasses();
_dofHandles.DeleteFramebuffers();
_dofHandles.DeleteRenderPasses();
_dofHandles.DeleteFramebuffers();
_dofHandles.DeleteRenderPasses();
_rdsHandles.DeleteFramebuffers();
_rdsHandles.DeleteRenderPasses();
renderer->DeleteFramebuffer(_fbhSsao);
renderer->DeleteRenderPass(_rphSsao);
_rdsHandles.DeleteFramebuffers();
_rdsHandles.DeleteRenderPasses();
renderer->DeleteFramebuffer(_fbhSsao);
renderer->DeleteRenderPass(_rphSsao);
}
VERUS_DONE(Blur);
}
@ -287,6 +289,8 @@ void Blur::GenerateForSsao()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForSsao");
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_rphSsao, _fbhSsao, { renderer.GetDS().GetGBuffer(2)->GetClearValue() });
@ -304,6 +308,8 @@ void Blur::GenerateForSsao()
cb->EndRenderPass();
}
_shader->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::GenerateForResolveDitheringAndSharpen()
@ -312,6 +318,8 @@ void Blur::GenerateForResolveDitheringAndSharpen()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForResolveDitheringAndSharpen");
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_rdsHandles._rphU, _rdsHandles._fbhU, { renderer.GetDS().GetComposedTextureB()->GetClearValue() });
@ -340,6 +348,8 @@ void Blur::GenerateForResolveDitheringAndSharpen()
cb->EndRenderPass();
}
_shader->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::GenerateForDepthOfField()
@ -351,7 +361,6 @@ void Blur::GenerateForDepthOfField()
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
const float radius = 0.02f;
const Matrix3 matR = Matrix3::rotationZ(Math::ToRadians(45));
const Vector3 dirs[] =
{
@ -384,6 +393,8 @@ void Blur::GenerateForDepthOfField()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForDepthOfField");
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
_shader->BeginBindDescriptors();
{
@ -393,11 +404,10 @@ void Blur::GenerateForDepthOfField()
s_ubBlurVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubBlurVS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
s_ubBlurFS._tcViewScaleBias = cb->GetViewScaleBias().GLM();
UpdateUniformBuffer(radius, 0, renderer.GetCurrentViewWidth(), samplesPerPixel, maxSamples);
UpdateUniformBuffer(_dofRadius, 0, renderer.GetCurrentViewWidth(), samplesPerPixel, maxSamples);
s_ubExtraBlurFS._zNearFarEx = wm.GetPassCamera()->GetZNearFarEx().GLM();
s_ubExtraBlurFS._textureSize = cb->GetViewportSize().GLM();
s_ubExtraBlurFS._focusDist_blurStrength.x = _dofFocusDist;
s_ubExtraBlurFS._focusDist_blurStrength.y = _dofBlurStrength;
s_ubExtraBlurFS._focusDist.x = _dofFocusDist;
s_ubExtraBlurFS._blurDir = float4(
dirs[0].getX(), dirs[0].getY() * renderer.GetCurrentViewAspectRatio(),
dirs[1].getX(), dirs[1].getY() * renderer.GetCurrentViewAspectRatio());
@ -413,7 +423,7 @@ void Blur::GenerateForDepthOfField()
{
cb->BeginRenderPass(_dofHandles._rphV, _dofHandles._fbhV, { renderer.GetDS().GetComposedTextureA()->GetClearValue() });
UpdateUniformBuffer(radius * 0.5f, 0, renderer.GetCurrentViewHeight(), samplesPerPixel, maxSamples);
UpdateUniformBuffer(_dofRadius * 0.5f, 0, renderer.GetCurrentViewHeight(), samplesPerPixel, maxSamples);
s_ubExtraBlurFS._blurDir = float4(dirs[2].getX(), dirs[2].getY() * renderer.GetCurrentViewAspectRatio(), 0, 0);
cb->BindPipeline(_pipe[PIPE_DOF_V]);
@ -426,6 +436,8 @@ void Blur::GenerateForDepthOfField()
}
_shader->EndBindDescriptors();
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::GenerateForBloom(bool forLightShafts)
@ -467,6 +479,8 @@ void Blur::GenerateForBloom(bool forLightShafts)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForBloom");
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() },
@ -499,6 +513,8 @@ void Blur::GenerateForBloom(bool forLightShafts)
cb->EndRenderPass();
}
_shader->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::GenerateForAntiAliasing()
@ -509,6 +525,8 @@ void Blur::GenerateForAntiAliasing()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForAntiAliasing");
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
cb->BeginRenderPass(_rphAntiAliasing, _fbhAntiAliasing, { renderer.GetDS().GetComposedTextureB()->GetClearValue() });
@ -529,6 +547,8 @@ void Blur::GenerateForAntiAliasing()
cb->EndRenderPass();
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::GenerateForMotionBlur()
@ -539,6 +559,8 @@ void Blur::GenerateForMotionBlur()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 0, 64, 255), "Blur/GenerateForMotionBlur");
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
cb->BeginRenderPass(_rphMotionBlur, _fbhMotionBlur, { renderer.GetDS().GetComposedTextureA()->GetClearValue() });
@ -560,6 +582,8 @@ void Blur::GenerateForMotionBlur()
cb->EndRenderPass();
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
VERUS_PROFILER_END_EVENT(cb);
}
void Blur::UpdateUniformBuffer(float radius, int sampleCount, int texSize, float samplesPerPixel, int maxSamples)

View File

@ -79,7 +79,7 @@ namespace verus
CGI::CSHandle _cshMotionBlurExtra;
float _dofFocusDist = 10;
float _dofBlurStrength = 0.2f;
float _dofRadius = 0.005f;
float _bloomRadius = 0.02f;
float _bloomLightShaftsRadius = 0.002f;
bool _enableDepthOfField = false;
@ -106,8 +106,8 @@ namespace verus
void EnableDepthOfField(bool b) { _enableDepthOfField = b; }
float GetDofFocusDistance() const { return _dofFocusDist; }
void SetDofFocusDistance(float dist) { _dofFocusDist = dist; }
float GetDofBlurStrength() const { return _dofBlurStrength; }
void SetDofBlurStrength(float strength) { _dofBlurStrength = strength; }
float GetDofRadius() const { return _dofRadius; }
void SetDofRadius(float radius) { _dofRadius = radius; }
};
VERUS_TYPEDEFS(Blur);
}

View File

@ -85,6 +85,8 @@ void Cinema::Draw()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(200, 180, 150, 255), "Cinema/Draw");
s_ubCinemaVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubCinemaVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubCinemaVS._matP = Math::ToUVMatrix(0, renderer.GetDS().GetGBuffer(0)->GetSize(), &_texFilmGrain->GetSize(), _uOffset, _vOffset).UniformBufferFormat();
@ -97,4 +99,6 @@ void Cinema::Draw()
cb->BindDescriptors(_shader, 1, _csh);
_shader->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
VERUS_PROFILER_END_EVENT(cb);
}

View File

@ -649,7 +649,7 @@ bool Particles::TimeCorrectedVerletIntegration(RParticle particle, RPoint3 point
else
{
VERUS_QREF_WM;
if (wm.RayTestEx(particle._prevPosition, particle._position, nullptr, &point, &normal, nullptr, Physics::Bullet::I().GetMainMask()))
if (wm.RayTestEx(particle._prevPosition, particle._position, nullptr, &point, &normal, nullptr, Physics::Bullet::I().GetStaticMask()))
{
hit = true;
particle._inContact = normal.getY() > 0.7071f;

View File

@ -70,9 +70,12 @@ void Ssao::InitCmd()
void Ssao::Done()
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rph);
if (CGI::Renderer::IsLoaded())
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rph);
}
VERUS_DONE(Ssao);
}
@ -125,6 +128,8 @@ void Ssao::Generate()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 64, 255, 255), "Ssao/Generate");
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetGBuffer(3)->GetClearValue() });
World::RCamera passCamera = *wm.GetPassCamera();
@ -153,6 +158,8 @@ void Ssao::Generate()
if (_blur)
Blur::I().GenerateForSsao();
VERUS_PROFILER_END_EVENT(cb);
}
void Ssao::UpdateRandNormalsTexture()

View File

@ -59,9 +59,12 @@ void Ssr::Init()
void Ssr::Done()
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rph);
if (CGI::Renderer::IsLoaded())
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbh);
renderer->DeleteRenderPass(_rph);
}
VERUS_DONE(Ssr);
}
@ -134,6 +137,8 @@ void Ssr::Generate()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 32, 255, 255), "Ssr/Generate");
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetLightAccSpecularTexture()->GetClearValue() });
@ -164,4 +169,6 @@ void Ssr::Generate()
cb->EndRenderPass();
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
VERUS_PROFILER_END_EVENT(cb);
}

View File

@ -259,10 +259,9 @@ void BaseCharacter::ComputeThirdPersonCameraArgs(RcVector3 offset, RPoint3 eye,
const RcVector3 offsetW = GetYawMatrix() * offset;
const Point3 pos = _smoothPosition;
const float startAt = _cc.GetRadius() + _cc.GetHeight() * 0.5f; // Inside capsule.
const Point3 origin = pos + Vector3(0, startAt, 0);
const Point3 origin = pos + Vector3(0, GetThirdPersonCameraBaseHeight(), 0);
at = pos + offsetW;
if (wm.RayTestEx(origin, at, nullptr, &point, &norm, &r, Physics::Bullet::I().GetMainMask()))
if (wm.RayTestEx(origin, at, nullptr, &point, &norm, &r, Physics::Bullet::I().GetStaticMask()))
at = point + norm * r;
eye = at - GetFrontDirection() * _cameraRadius.GetValue() + offsetW * 0.05f;
}
@ -288,7 +287,7 @@ float BaseCharacter::ComputeThirdPersonCamera(World::RCamera camera, Anim::RcOrb
eye = at + Vector3(toEye);
float ret = 0;
if (wm.RayTestEx(at, eye, nullptr, &point, &norm, &r, Physics::Bullet::I().GetMainMask())) // Hitting the wall?
if (wm.RayTestEx(at, eye, nullptr, &point, &norm, &r, Physics::Bullet::I().GetStaticMask())) // Hitting the wall?
{
eye = point + norm * r;
const float maxCameraRadius = VMath::dist(at, eye) + r;
@ -324,7 +323,7 @@ void BaseCharacter::ComputeThirdPersonAim(RPoint3 aimPos, RVector3 aimDir, RcVec
Point3 eye, at;
ComputeThirdPersonCameraArgs(offset, eye, at);
if (wm.RayTestEx(at, eye, nullptr, &point, &norm, &r, Physics::Bullet::I().GetMainMask())) // Hitting the wall?
if (wm.RayTestEx(at, eye, nullptr, &point, &norm, &r, Physics::Bullet::I().GetStaticMask())) // Hitting the wall?
{
eye = point + norm * r;
}
@ -340,6 +339,11 @@ void BaseCharacter::ComputeThirdPersonAim(RPoint3 aimPos, RVector3 aimDir, RcVec
aimDir = VMath::normalizeApprox(at - eye);
}
float BaseCharacter::GetThirdPersonCameraBaseHeight() const
{
return _cc.GetRadius() + _cc.GetHeight() * 0.5f; // Inside capsule.
}
void BaseCharacter::SetMaxCameraRadius(float r)
{
_maxCameraRadius = r;

View File

@ -79,6 +79,7 @@ namespace verus
virtual void ComputeThirdPersonCameraArgs(RcVector3 offset, RPoint3 eye, RPoint3 at);
float ComputeThirdPersonCamera(World::RCamera camera, Anim::RcOrbit orbit, RcVector3 offset = Vector3(0));
void ComputeThirdPersonAim(RPoint3 aimPos, RVector3 aimDir, RcVector3 offset = Vector3(0));
float GetThirdPersonCameraBaseHeight() const;
void SetMaxCameraRadius(float r);
float GetCameraRadius() const { return _cameraRadius.GetValue(); }
};

View File

@ -64,7 +64,7 @@ BaseGame::~BaseGame()
RestartApp();
}
void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc windowDesc)
void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::RcInfo appInfo, App::Window::RcDesc windowDesc)
{
const int ret = SDL_Init(SDL_INIT_EVERYTHING);
if (ret)
@ -74,6 +74,7 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc windowDes
App::Settings::Make();
VERUS_QREF_SETTINGS;
settings._info = appInfo;
settings.ParseCommandLineArgs(argc, argv);
settings.Load();
settings.HandleHighDpi();
@ -155,38 +156,47 @@ void BaseGame::Loop(bool relativeMouseMode)
// <RawInput>
bool keyboardShortcut = false;
if (_p->_rawInputEvents && !ImGui::GetIO().WantCaptureMouse)
if (_p->_rawInputEvents)
{
switch (event.type)
if (!ImGui::GetIO().WantCaptureMouse)
{
case SDL_KEYDOWN:
{
keyboardShortcut = BaseGame_SDL_OnKeyboardShortcut(event.key.keysym.sym, event.key.keysym.mod);
switch (event.type)
{
case SDL_MOUSEMOTION:
{
BaseGame_SDL_OnMouseMotion(event.motion.xrel, event.motion.yrel);
}
break;
case SDL_MOUSEBUTTONDOWN:
{
if (2 == event.button.clicks)
BaseGame_SDL_OnMouseDoubleClick(event.button.button);
else
BaseGame_SDL_OnMouseButtonDown(event.button.button);
}
break;
case SDL_MOUSEBUTTONUP:
{
BaseGame_SDL_OnMouseButtonUp(event.button.button);
}
break;
case SDL_MOUSEWHEEL:
{
BaseGame_SDL_OnMouseWheel(event.wheel.y);
}
break;
}
}
break;
case SDL_MOUSEMOTION:
if (!ImGui::GetIO().WantCaptureKeyboard)
{
BaseGame_SDL_OnMouseMotion(event.motion.xrel, event.motion.yrel);
}
break;
case SDL_MOUSEBUTTONDOWN:
{
if (2 == event.button.clicks)
BaseGame_SDL_OnMouseDoubleClick(event.button.button);
else
BaseGame_SDL_OnMouseButtonDown(event.button.button);
}
break;
case SDL_MOUSEBUTTONUP:
{
BaseGame_SDL_OnMouseButtonUp(event.button.button);
}
break;
case SDL_MOUSEWHEEL:
{
BaseGame_SDL_OnMouseWheel(event.wheel.y);
}
break;
switch (event.type)
{
case SDL_KEYDOWN:
{
keyboardShortcut = BaseGame_SDL_OnKeyboardShortcut(event.key.keysym.sym, event.key.keysym.mod);
}
break;
}
}
}
// </RawInput>
@ -266,59 +276,77 @@ void BaseGame::Loop(bool relativeMouseMode)
renderer.BeginFrame();
async.Update();
auto cb = renderer.GetCommandBuffer();
timer.Update();
BaseGame_EnterRequestedState();
if (_p->_defaultCameraMovement) // Handle input:
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(0, 113, 197, 255), "BaseGame/Update");
{
const float speed = im.IsKeyPressed(SDL_SCANCODE_SPACE) ? 20.f : 2.f;
if (im.IsKeyPressed(SDL_SCANCODE_W))
_p->_cameraSpirit.MoveFront(speed);
if (im.IsKeyPressed(SDL_SCANCODE_S))
_p->_cameraSpirit.MoveFront(-speed);
if (im.IsKeyPressed(SDL_SCANCODE_A))
_p->_cameraSpirit.MoveSide(-speed);
if (im.IsKeyPressed(SDL_SCANCODE_D))
_p->_cameraSpirit.MoveSide(speed);
}
im.HandleInput();
if (_restartApp)
continue;
VERUS_PROFILER_SET_MARKER(cb, VERUS_COLOR_WHITE, "BaseGame/Update/Async");
async.Update();
if (Physics::Bullet::IsValidSingleton())
Physics::Bullet::I().Simulate();
VERUS_PROFILER_SET_MARKER(cb, VERUS_COLOR_WHITE, "BaseGame/Update/Timer");
timer.Update();
if (_p->_defaultCameraMovement)
{
_p->_cameraSpirit.HandleActions();
_p->_cameraSpirit.Update();
_p->_camera.MoveEyeTo(_p->_cameraSpirit.GetPosition());
_p->_camera.MoveAtTo(_p->_cameraSpirit.GetPosition() + _p->_cameraSpirit.GetFrontDirection());
if (World::Water::IsValidSingleton())
BaseGame_EnterRequestedState();
if (_p->_defaultCameraMovement) // Handle input:
{
VERUS_QREF_WATER;
if (water.IsInitialized())
_p->_camera.ExcludeWaterLine();
const float speed = im.IsKeyPressed(SDL_SCANCODE_SPACE) ? 20.f : 2.f;
if (im.IsKeyPressed(SDL_SCANCODE_W))
_p->_cameraSpirit.MoveFront(speed);
if (im.IsKeyPressed(SDL_SCANCODE_S))
_p->_cameraSpirit.MoveFront(-speed);
if (im.IsKeyPressed(SDL_SCANCODE_A))
_p->_cameraSpirit.MoveSide(-speed);
if (im.IsKeyPressed(SDL_SCANCODE_D))
_p->_cameraSpirit.MoveSide(speed);
}
_p->_camera.Update();
if (World::WorldManager::IsValidSingleton())
World::WorldManager::I().SetAllCameras(&_p->_camera);
}
else
{
if (World::WorldManager::IsValidSingleton())
World::WorldManager::I().SetAllCameras(nullptr);
}
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(38, 125, 11, 255), "BaseGame/Update/Input");
im.HandleInput();
VERUS_PROFILER_END_EVENT(cb);
if (_restartApp)
continue;
BaseGame_Update(); // Between physics and audio update.
if (_restartApp)
continue;
if (Physics::Bullet::IsValidSingleton())
{
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(246, 154, 0, 255), "BaseGame/Update/Physics");
Physics::Bullet::I().Simulate();
VERUS_PROFILER_END_EVENT(cb);
}
if (Audio::AudioSystem::IsValidSingleton())
Audio::AudioSystem::I().Update();
if (_p->_defaultCameraMovement)
{
_p->_cameraSpirit.HandleActions();
_p->_cameraSpirit.Update();
_p->_camera.MoveEyeTo(_p->_cameraSpirit.GetPosition());
_p->_camera.MoveAtTo(_p->_cameraSpirit.GetPosition() + _p->_cameraSpirit.GetFrontDirection());
if (World::Water::IsValidSingleton())
{
VERUS_QREF_WATER;
if (water.IsInitialized())
_p->_camera.ExcludeWaterLine();
}
_p->_camera.Update();
if (World::WorldManager::IsValidSingleton())
World::WorldManager::I().SetAllCameras(&_p->_camera);
}
else
{
if (World::WorldManager::IsValidSingleton())
World::WorldManager::I().SetAllCameras(nullptr);
}
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(0, 167, 116, 255), "BaseGame/Update/Game");
BaseGame_Update(); // Between physics and audio update.
VERUS_PROFILER_END_EVENT(cb);
if (_restartApp)
continue;
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(128, 0, 0, 255), "BaseGame/Update/Audio");
if (Audio::AudioSystem::IsValidSingleton())
Audio::AudioSystem::I().Update();
VERUS_PROFILER_END_EVENT(cb);
}
VERUS_PROFILER_END_EVENT(cb);
// Draw current frame:
renderer.Draw();

View File

@ -18,7 +18,9 @@ namespace verus
BaseGame();
~BaseGame();
void Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc windowDesc = App::Window::Desc());
void Initialize(VERUS_MAIN_DEFAULT_ARGS,
App::RcInfo appInfo = App::Info(),
App::Window::RcDesc windowDesc = App::Window::Desc());
void Loop(bool relativeMouseMode = true);
void Exit();

View File

@ -28,7 +28,7 @@ void Spirit::ComputeDerivedVars(float smoothSpeed)
_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)));
if (VMath::distSqr(_position, _dv._jerkyPosition) > 5 * 5.f)
if (VMath::distSqr(_position, _dv._jerkyPosition) > _jerkyPositionDelta * _jerkyPositionDelta)
_dv._jerkyPosition = _position;
}

View File

@ -42,6 +42,7 @@ namespace verus
float _accel = 0;
float _decel = 0;
float _turnLeanStrength = 0;
float _jerkyPositionDelta = 10;
public:
Spirit();

View File

@ -11,6 +11,12 @@ namespace verus
int _pong = 1;
public:
void Reserve(int capacity)
{
_v[0].reserve(capacity);
_v[1].reserve(capacity);
}
void PushBack(const T& x)
{
_v[_ping].push_back(x);
@ -19,6 +25,7 @@ namespace verus
template<typename TFnInsert, typename TFnDelete>
void HandleDifference(const TFnInsert& fnInsert, const TFnDelete& fnDelete)
{
// Sort and remove duplicates:
std::sort(_v[_ping].begin(), _v[_ping].end(), [](const T& a, const T& b)
{
return a.GetID() < b.GetID();
@ -31,34 +38,43 @@ namespace verus
typename Vector<T>::iterator itPong = _v[_pong].begin(), itPongEnd = _v[_pong].end();
while (itPing != itPingEnd)
{
if (itPong == itPongEnd) // No more items in pong?
if (itPong == itPongEnd) // Ran out of pong elements?
{
while (itPing != itPingEnd) // All remaining.
while (itPing != itPingEnd) // Ping leftovers.
fnInsert(*itPing++);
break;
}
if (itPing->GetID() < itPong->GetID()) // New item in ping, insert it:
if (itPing->GetID() < itPong->GetID()) // Found new element in ping?
{
fnInsert(*itPing++);
}
else if (itPong->GetID() < itPing->GetID()) // Old item in pong, delete it.
else if (itPong->GetID() < itPing->GetID()) // Found outdated element in pong?
{
fnDelete(*itPong++);
}
else // Same:
{
*itPing = *itPong; // No need to insert or delete, just copy payload.
*itPing = *itPong; // Copy existing payload from pong to ping.
itPing++;
itPong++;
}
}
while (itPong != itPongEnd) // Handle leftovers.
// Ran out of ping elements?
while (itPong != itPongEnd) // Pong leftovers.
fnDelete(*itPong++);
// Swap:
_pong = _ping;
_ping = (_ping + 1) & 0x1;
_v[_ping].clear();
}
template<typename TFn>
void ForEach(const TFn& fn)
{
for (auto& x : _v[_pong])
fn(x);
}
};
}

View File

@ -26,6 +26,9 @@
#define _C(x) ((x).c_str())
#define VERUS_MAKE_VERSION(major, minor, patch) (((major)<<24)|((minor)<<12)|(patch))
#define VERUS_VERSION_MAJOR(version) ((version >> 24) & 0xFF)
#define VERUS_VERSION_MINOR(version) ((version >> 12) & 0xFFF)
#define VERUS_VERSION_PATCH(version) ((version) & 0xFFF)
#define VERUS_P_FOR(i, to) Parallel::For(0, to, [&](int i)
#define VERUS_U_FOR(i, to) for(UINT32 i = 0; i < to; ++i)
@ -93,3 +96,14 @@
#define VERUS_COLOR_BLEND_TINTED_GLASS "s*(sc)+d*(1-sc)"
#define VERUS_COLOR_BLEND_MIN "min(s, d)"
#define VERUS_COLOR_BLEND_MAX "max(s, d)"
#ifdef VERUS_PROFILER_CALLS
# pragma message("VERUS_PROFILER_CALLS is defined")
# define VERUS_PROFILER_BEGIN_EVENT(cb, color, text) cb->ProfilerBeginEvent(color, text)
# define VERUS_PROFILER_END_EVENT(cb) cb->ProfilerEndEvent()
# define VERUS_PROFILER_SET_MARKER(cb, color, text) cb->ProfilerSetMarker(color, text)
#else
# define VERUS_PROFILER_BEGIN_EVENT(cb, color, text)
# define VERUS_PROFILER_END_EVENT(cb)
# define VERUS_PROFILER_SET_MARKER(cb, color, text)
#endif

View File

@ -9,24 +9,31 @@ namespace verus
Vector<T> _v;
int _next = 0;
void IncrementNext()
{
_next = (_next + 1) % _v.size();
}
public:
void Resize(int size)
{
_v.resize(size);
_next = Math::Min(_next, static_cast<int>(_v.size()));
_next = Math::Min(_next, static_cast<int>(_v.size()) - 1);
}
int Reserve()
{
_next = Math::Min(_next, static_cast<int>(_v.size()));
_next = Math::Min(_next, static_cast<int>(_v.size()) - 1);
VERUS_FOR(i, _v.size())
{
if (!_v[_next].IsReserved())
{
_v[_next].Reserve();
return _next++;
const int ret = _next;
IncrementNext();
return ret;
}
_next = (_next + 1) % _v.size();
IncrementNext();
}
return -1;
}

View File

@ -32,3 +32,8 @@ Range::Iterator Range::end() const
{
return _end;
}
bool Range::Includes(int value) const
{
return value >= _begin && value < _end;
}

View File

@ -31,5 +31,7 @@ namespace verus
Iterator begin() const;
Iterator end() const;
bool Includes(int value) const;
};
}

View File

@ -305,7 +305,7 @@ void Transform3::InstFormat(VMath::Vector4* p) const
memcpy(p, &m, 3 * sizeof(Vector4));
}
float4 Transform3::ToSpriteMat() const
float4 Transform3::ToSpriteRollMatrix() const
{
const Vector3 up = getUpper3x3() * Vector3(0, 1);
const glm::vec2 upNorm(glm::normalize(up.GLM2()));

View File

@ -86,7 +86,7 @@ namespace verus
mataff UniformBufferFormat() const;
static mataff UniformBufferFormatIdentity();
void InstFormat(VMath::Vector4* p) const;
float4 ToSpriteMat() const;
float4 ToSpriteRollMatrix() const;
const float* ToPointer() const { return reinterpret_cast<const float*>(this); }

View File

@ -206,6 +206,7 @@ Continue Octree::TraverseVisible(RcFrustum frustum, PResult pResult, int current
if (_vNodes.empty())
return Continue::no;
// <Init>
if (!currentNode)
{
_defaultResult = Result();
@ -215,53 +216,91 @@ Continue Octree::TraverseVisible(RcFrustum frustum, PResult pResult, int current
pResult->_passedTestCount = 0;
pResult->_pLastFoundToken = nullptr;
pResult->_depth = World::WorldManager::IsDrawingDepth(World::DrawDepth::automatic);
_skipTestNode = -1;
}
// </Init>
pResult->_testCount++;
const float onePixel = Math::ComputeOnePixelDistance(
_vNodes[currentNode].GetSphere().GetRadius());
const bool notTooSmall = pResult->_depth || VMath::distSqr(
frustum.GetZNearPosition(), _vNodes[currentNode].GetSphere().GetCenter()) < onePixel * onePixel;
if (notTooSmall &&
Relation::outside != frustum.ContainsSphere(_vNodes[currentNode].GetSphere()) &&
Relation::outside != frustum.ContainsAabb(_vNodes[currentNode].GetBounds()))
// <TestNode>
if (-1 == _skipTestNode)
{
pResult->_testCount++;
const float onePixel = Math::ComputeOnePixelDistance(
_vNodes[currentNode].GetSphere().GetRadius());
const bool notTooSmall = pResult->_depth || VMath::distSqr(
frustum.GetZNearPosition(), _vNodes[currentNode].GetSphere().GetCenter()) < onePixel * onePixel;
Relation relation = Relation::outside;
if (notTooSmall)
{
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
{
RcElement element = node.GetElementAt(i);
pResult->_testCount++;
const float onePixel = Math::ComputeOnePixelDistance(
element._sphere.GetRadius());
const bool notTooSmall = pResult->_depth || VMath::distSqr(
frustum.GetZNearPosition(), element._sphere.GetCenter()) < onePixel * onePixel;
if (notTooSmall &&
Relation::outside != frustum.ContainsSphere(element._sphere) &&
Relation::outside != frustum.ContainsAabb(element._bounds))
{
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Octree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
}
relation = frustum.ContainsSphere(_vNodes[currentNode].GetSphere());
if (Relation::outside != relation)
relation = frustum.ContainsAabb(_vNodes[currentNode].GetBounds());
}
if (Node::HasChildren(currentNode, Utils::Cast32(_vNodes.size())))
switch (relation)
{
VERUS_FOR(i, 8)
{
const int childIndex = Node::GetChildIndex(currentNode, i);
if (Continue::no == TraverseVisible(frustum, pResult, childIndex, pUser))
return Continue::no;
}
case Relation::outside: return Continue::yes; // Early return.
case Relation::inside: _skipTestNode = currentNode;
}
}
// </TestNode>
// <ProcessNodeElements>
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
{
RcElement element = node.GetElementAt(i);
// <TestElement>
pResult->_testCount++;
const float onePixel = Math::ComputeOnePixelDistance(
element._sphere.GetRadius());
const bool notTooSmall = pResult->_depth || VMath::distSqr(
frustum.GetZNearPosition(), element._sphere.GetCenter()) < onePixel * onePixel;
Relation relation = Relation::outside;
if (notTooSmall)
{
if (-1 == _skipTestNode)
{
relation = frustum.ContainsSphere(element._sphere);
if (Relation::outside != relation)
relation = frustum.ContainsAabb(element._bounds);
}
else
{
relation = Relation::inside;
}
}
// </TestElement>
if (Relation::outside != relation)
{
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Octree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
}
// </ProcessNodeElements>
// <TraverseChildren>
if (Node::HasChildren(currentNode, Utils::Cast32(_vNodes.size())))
{
VERUS_FOR(i, 8)
{
const int childIndex = Node::GetChildIndex(currentNode, i);
if (Continue::no == TraverseVisible(frustum, pResult, childIndex, pUser))
return Continue::no;
}
}
// </TraverseChildren>
if (_skipTestNode == currentNode)
_skipTestNode = -1;
return Continue::yes;
}
@ -270,6 +309,7 @@ Continue Octree::TraverseVisible(RcPoint3 point, PResult pResult, int currentNod
if (_vNodes.empty())
return Continue::no;
// <Init>
if (!currentNode)
{
_defaultResult = Result();
@ -279,27 +319,29 @@ Continue Octree::TraverseVisible(RcPoint3 point, PResult pResult, int currentNod
pResult->_passedTestCount = 0;
pResult->_pLastFoundToken = nullptr;
}
// </Init>
pResult->_testCount++;
if (_vNodes[currentNode].GetBounds().IsInside(point))
{
// <ProcessNodeElements>
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
{
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
RcElement element = node.GetElementAt(i);
pResult->_testCount++;
if (element._bounds.IsInside(point))
{
RcElement element = node.GetElementAt(i);
pResult->_testCount++;
if (element._bounds.IsInside(point))
{
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Octree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Octree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
}
// </ProcessNodeElements>
// <TraverseChildren>
if (Node::HasChildren(currentNode, Utils::Cast32(_vNodes.size())))
{
BYTE remapped[8];
@ -311,6 +353,7 @@ Continue Octree::TraverseVisible(RcPoint3 point, PResult pResult, int currentNod
return Continue::no;
}
}
// </TraverseChildren>
}
return Continue::yes;
}

View File

@ -73,6 +73,7 @@ namespace verus
Vector<Node> _vNodes;
POctreeDelegate _pDelegate = nullptr;
Result _defaultResult;
int _skipTestNode = -1;
public:
Octree();

View File

@ -196,6 +196,7 @@ Continue Quadtree::TraverseVisible(RcPoint3 point, PResult pResult, int currentN
if (_vNodes.empty())
return Continue::no;
// <Init>
if (!currentNode)
{
_defaultResult = Result();
@ -205,27 +206,29 @@ Continue Quadtree::TraverseVisible(RcPoint3 point, PResult pResult, int currentN
pResult->_passedTestCount = 0;
pResult->_pLastFoundToken = nullptr;
}
// </Init>
pResult->_testCount++;
if (_vNodes[currentNode].GetBounds().IsInside2D(point))
{
// <ProcessNodeElements>
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
{
RcNode node = _vNodes[currentNode];
const int count = node.GetElementCount();
VERUS_FOR(i, count)
RcElement element = node.GetElementAt(i);
pResult->_testCount++;
if (element._bounds.IsInside2D(point))
{
RcElement element = node.GetElementAt(i);
pResult->_testCount++;
if (element._bounds.IsInside2D(point))
{
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Quadtree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
pResult->_passedTestCount++;
pResult->_pLastFoundToken = element._pToken;
if (Continue::no == _pDelegate->Quadtree_ProcessNode(element._pToken, pUser))
return Continue::no;
}
}
// </ProcessNodeElements>
// <TraverseChildren>
if (Node::HasChildren(currentNode, Utils::Cast32(_vNodes.size())))
{
BYTE remapped[4];
@ -237,6 +240,7 @@ Continue Quadtree::TraverseVisible(RcPoint3 point, PResult pResult, int currentN
return Continue::no;
}
}
// </TraverseChildren>
}
return Continue::yes;
}

View File

@ -155,13 +155,14 @@ void QuadtreeIntegral::TraverseVisible(int currentNode, int depth)
{
VERUS_QREF_WM;
// <Init>
if (!currentNode)
{
_testCount = 0;
_passedTestCount = 0;
_skipTestNode = -1;
}
_testCount++;
// </Init>
bool testFrustum = true;
if (_distCoarseMode && depth + 2 >= _maxDepth)
@ -177,9 +178,18 @@ void QuadtreeIntegral::TraverseVisible(int currentNode, int depth)
testFrustum = false;
}
RFrustum frustum = wm.GetPassCamera()->GetFrustum();
if (testFrustum && Relation::outside == frustum.ContainsAabb(_vNodes[currentNode].GetBounds()))
return;
// <TestNode>
if (testFrustum && -1 == _skipTestNode)
{
_testCount++;
RFrustum frustum = wm.GetPassCamera()->GetFrustum();
switch (frustum.ContainsAabb(_vNodes[currentNode].GetBounds()))
{
case Relation::outside: return; // Early return.
case Relation::inside: _skipTestNode = currentNode;
}
}
// </TestNode>
// Yes, it is visible:
if (Node::HasChildren(currentNode, _nodeCount)) // Node has children -> update them:
@ -197,4 +207,7 @@ void QuadtreeIntegral::TraverseVisible(int currentNode, int depth)
_vNodes[currentNode].GetOffsetIJ(),
_vNodes[currentNode].GetSphere().GetCenter());
}
if (_skipTestNode == currentNode)
_skipTestNode = -1;
}

View File

@ -52,6 +52,7 @@ namespace verus
int _nodeCount = 0;
int _testCount = 0;
int _passedTestCount = 0;
int _skipTestNode = -1;
int _mapSide = 0;
int _limit = 0;
int _maxDepth = 0;

View File

@ -18,9 +18,12 @@ void Bullet::Init()
VERUS_INIT();
VERUS_QREF_CONST_SETTINGS;
const btVector3 worldAabbMin(-2048, -1024, -2048);
const btVector3 worldAabbMax(+2048, +1024, +2048);
_pCollisionConfiguration = new(_pCollisionConfiguration.GetData()) btDefaultCollisionConfiguration();
_pDispatcher = new(_pDispatcher.GetData()) btCollisionDispatcher(_pCollisionConfiguration.Get());
_pBroadphaseInterface = new(_pBroadphaseInterface.GetData()) btDbvtBroadphase();
_pBroadphaseInterface = new(_pBroadphaseInterface.GetData()) btAxisSweep3(worldAabbMin, worldAabbMax);
_pConstraintSolver = new(_pConstraintSolver.GetData()) btSequentialImpulseConstraintSolver();
_pBroadphaseInterface->getOverlappingPairCache()->setInternalGhostPairCallback(&_ghostPairCallback);
@ -252,6 +255,7 @@ CSZ Bullet::GroupToString(int index)
"Gizmo",
"Particle",
"Terrain",
"Forest",
"Transport",
"Wall"
};

View File

@ -72,14 +72,14 @@ namespace verus
LocalPtr<btDefaultCollisionConfiguration> _pCollisionConfiguration;
LocalPtr<btCollisionDispatcher> _pDispatcher;
LocalPtr<btDbvtBroadphase> _pBroadphaseInterface;
LocalPtr<btAxisSweep3> _pBroadphaseInterface;
LocalPtr<btSequentialImpulseConstraintSolver> _pConstraintSolver;
LocalPtr<btDiscreteDynamicsWorld> _pDiscreteDynamicsWorld;
LocalPtr<btStaticPlaneShape> _pStaticPlaneShape;
LocalRigidBody _pStaticPlaneRigidBody;
btGhostPairCallback _ghostPairCallback;
BulletDebugDraw _debugDraw;
Group _mainMask = Group::immovable | Group::terrain;
Group _staticMask = Group::immovable | Group::terrain | Group::forest;
bool _pauseSimulation = false;
public:
@ -89,6 +89,10 @@ namespace verus
void Init();
void Done();
btDefaultCollisionConfiguration* GetCollisionConfiguration() { return _pCollisionConfiguration.Get(); }
btCollisionDispatcher* GetDispatcher() { return _pDispatcher.Get(); }
btAxisSweep3* GetBroadphaseInterface() { return _pBroadphaseInterface.Get(); }
btSequentialImpulseConstraintSolver* GetConstraintSolver() { return _pConstraintSolver.Get(); }
btDiscreteDynamicsWorld* GetWorld() { return _pDiscreteDynamicsWorld.Get(); }
btRigidBody* AddNewRigidBody(
@ -124,8 +128,9 @@ namespace verus
static CSZ GroupToString(int index);
Group GetMainMask() const { return _mainMask; }
void SetMainMask(Group mask) { _mainMask = mask; }
Group GetStaticMask() const { return _staticMask; }
Group GetNonStaticMask() const { return ~_staticMask; }
void SetStaticMask(Group mask) { _staticMask = mask; }
};
VERUS_TYPEDEFS(Bullet);
}

View File

@ -41,7 +41,7 @@ void CharacterController::Init(RcPoint3 pos, RcDesc desc)
_pKCC = new(_pKCC.GetData()) KinematicCharacterController(_pGhostObject.Get(), _pCapsule.Get(), stepHeight);
_pKCC->setGravity(-bullet.GetWorld()->getGravity().getY());
_pKCC->setMaxSlope(btRadians(48));
bullet.GetWorld()->addCollisionObject(_pGhostObject.Get(), +Group::character, -1);
bullet.GetWorld()->addCollisionObject(_pGhostObject.Get(), +Group::character, +Group::all);
bullet.GetWorld()->addAction(_pKCC.Get());
UpdateScaling();
}

View File

@ -21,8 +21,9 @@ namespace verus
gizmo = (1 << 10), // Editor::PGizmoTool
particle = (1 << 11),
terrain = (1 << 12),
transport = (1 << 13),
wall = (1 << 14),
forest = (1 << 13),
transport = (1 << 14),
wall = (1 << 15),
all = UINT32_MAX
};
}

View File

@ -56,11 +56,11 @@ void Vehicle::Init(RcDesc desc)
const float k = forcePerWheel / desc._suspensionRestLength; // Hooke's law (F = k * x).
_vehicleTuning.m_suspensionStiffness = k / desc._mass; // Per 1 kg.
_vehicleTuning.m_suspensionCompression = _vehicleTuning.m_suspensionStiffness * 0.15f;
_vehicleTuning.m_suspensionDamping = _vehicleTuning.m_suspensionStiffness * 0.2f;
_vehicleTuning.m_suspensionCompression = _vehicleTuning.m_suspensionStiffness * 0.09f; // Compression damping (absorb bumps).
_vehicleTuning.m_suspensionDamping = _vehicleTuning.m_suspensionStiffness * 0.11f; // Relaxation damping (track the downslope of the bump).
_vehicleTuning.m_maxSuspensionTravelCm = 100 * 2 * desc._suspensionRestLength;
_vehicleTuning.m_frictionSlip = 1.5f;
_vehicleTuning.m_maxSuspensionForce = forcePerWheel * 3;
_vehicleTuning.m_frictionSlip = 2;
_vehicleTuning.m_maxSuspensionForce = forcePerWheel * 10;
averageWheelPos -= centerOfMassOffset;
averageWheelPos.setY(0);
@ -88,8 +88,8 @@ void Vehicle::Init(RcDesc desc)
_pChassis = bullet.AddNewRigidBody(_pChassis, desc._mass, desc._tr.Bullet(), _pCompoundShape.Get(),
+Group::transport, +Group::all, &trCoM);
_pChassis->setFriction(Bullet::GetFriction(Material::metal));
_pChassis->setRestitution(Bullet::GetRestitution(Material::metal) * 0.25f); // Energy-absorbing deformation.
_pChassis->setFriction(0);
_pChassis->setRestitution(0);
_pChassis->setUserPointer(this);
_pChassis->setActivationState(DISABLE_DEACTIVATION);
_pVehicleRaycaster = new(_pVehicleRaycaster.GetData()) btDefaultVehicleRaycaster(bullet.GetWorld());

View File

@ -100,7 +100,7 @@ FSO mainFS(VSO si)
g_ubBloomLightShaftsFS._matShadowCSM2,
g_ubBloomLightShaftsFS._matShadowCSM3,
g_ubBloomLightShaftsFS._matScreenCSM,
g_ubBloomLightShaftsFS._csmSplitRanges,
g_ubBloomLightShaftsFS._csmSliceBounds,
g_ubBloomLightShaftsFS._shadowConfig,
false);
acc += shadowMask * step(pickingRayLen, distToEye);

View File

@ -25,6 +25,6 @@ VERUS_UBUFFER UB_BloomLightShaftsFS
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -305,7 +305,7 @@ FSO mainSharpenFS(VSO si)
float DepthToCircleOfConfusion(float depth, float focusDist)
{
return abs((depth - focusDist * 2.0) / depth + 1.0);
return abs((depth - focusDist) / depth);
}
#ifdef _VS
@ -327,16 +327,15 @@ FSO mainDofFS(VSO si)
{
FSO so;
const float focusDist = g_ubExtraBlurFS._focusDist_blurStrength.x;
const float blurStrength = g_ubExtraBlurFS._focusDist_blurStrength.y;
const float focusDist = g_ubExtraBlurFS._focusDist.x;
const float originDepthSam = g_texDepth.SampleLevel(g_samDepth, si.tc0.zw, 0.0).r;
const float originDepth = ToLinearDepth(originDepthSam, g_ubExtraBlurFS._zNearFarEx);
const float scale = DepthToCircleOfConfusion(originDepth, focusDist) * blurStrength;
const float scale = DepthToCircleOfConfusion(originDepth, focusDist);
const int sampleCount = clamp(g_ubBlurFS._sampleCount * scale, 3, 31);
const float radius = g_ubBlurFS._radius_invRadius_stride.x * scale;
const float invRadius = 1.0 / radius;
const float invRadius = 1.0 / (radius + _SINGULARITY_FIX);
const float2 blurDir = g_ubExtraBlurFS._blurDir.xy;
const float2 blurDir2 = g_ubExtraBlurFS._blurDir.zw * radius;
@ -355,9 +354,9 @@ FSO mainDofFS(VSO si)
const float kernelDepthSam = g_texDepth.SampleLevel(g_samDepth, tcView, 0.0).r;
const float kernelDepth = ToLinearDepth(kernelDepthSam, g_ubExtraBlurFS._zNearFarEx);
const float kernelDeeper = kernelDepth - originDepth;
const float kernelScale = DepthToCircleOfConfusion(kernelDepth, focusDist) * blurStrength;
const float kernelScale = DepthToCircleOfConfusion(kernelDepth, focusDist);
// Blurry area should not sample sharp area unless it is closer to the camera.
float weight = min(scale, min(2.0, max(kernelScale, kernelDeeper)));
float weight = _SINGULARITY_FIX + min(scale, max(kernelScale, kernelDeeper));
#ifdef DEF_U // 1st pass - make a rhombus:
weight *= 1.0 - 0.5 * origin;
@ -502,7 +501,7 @@ FSO mainMotionFS(VSO si)
#else
const float3 rand = Rand(si.pos.xy);
const float2 ndcPos = ToNdcPos(si.tc0.xy);
const float offsetScale = 0.6 + 0.1 * rand.x; // Blur 60% - 70% of frame time.
const float offsetScale = 0.6 + 0.1 * rand.x; // Blur 60% - 70% of frame time (shutter time).
#if _SHADER_QUALITY <= _Q_LOW
const int sampleCount = 6;
@ -543,7 +542,7 @@ FSO mainMotionFS(VSO si)
const float kernelDepth = ToLinearDepth(kernelDepthSam, g_ubExtraBlurFS._zNearFarEx);
const float kernelDeeper = kernelDepth - originDepth;
const float allowed = saturate(1.0 + kernelDeeper * equalize) * gBuffer1Sam.a; // Closer points require extra care.
const float weight = 1.0 + saturate(kernelDeeper); // To fix the seam between foreground and background.
const float weight = 1.0 + 2.0 * saturate(kernelDeeper); // To fix the seam between foreground and background.
const float3 kernelColorSam = g_tex.SampleLevel(g_sam, kernelCoords, 0.0).rgb;
acc += lerp(0.0, float4(kernelColorSam * weight, weight), allowed);

View File

@ -21,5 +21,5 @@ VERUS_UBUFFER UB_ExtraBlurFS
float4 _zNearFarEx;
float4 _textureSize;
float4 _blurDir;
float4 _focusDist_blurStrength;
float4 _focusDist;
};

View File

@ -35,16 +35,16 @@ struct VSI
struct VSO
{
float4 pos : SV_Position;
float4 clipSpacePos : TEXCOORD0;
float4 pos : SV_Position;
float4 clipSpacePos : TEXCOORD0;
#if defined(DEF_DIR) || defined(DEF_SPOT) // Direction and cone shape for spot.
float4 lightDirWV_invConeDelta : TEXCOORD1;
float4 lightDirWV_invConeDelta : TEXCOORD1;
#endif
#if defined(DEF_OMNI) || defined(DEF_SPOT) // Omni and spot have position and radius.
float3 lightPosWV : TEXCOORD2;
float3 radius_radiusSq_invRadiusSq : TEXCOORD3;
float4 lightPosWV_lampRadius : TEXCOORD2;
float4 radius_radiusSq_invRadiusSq_invLampRadius : TEXCOORD3;
#endif
float4 color_coneOut : TEXCOORD4;
float4 color_coneOut : TEXCOORD4;
};
#ifdef _VS
@ -100,10 +100,14 @@ VSO mainVS(VSI si)
#endif
#if defined(DEF_OMNI) || defined(DEF_SPOT)
{
so.lightPosWV = mul(float4(0, 0, 0, 1), matWV).xyz;
so.radius_radiusSq_invRadiusSq.y = dot(scaledFrontDir, scaledFrontDir);
so.radius_radiusSq_invRadiusSq.x = sqrt(so.radius_radiusSq_invRadiusSq.y);
so.radius_radiusSq_invRadiusSq.z = 1.0 / so.radius_radiusSq_invRadiusSq.y;
so.lightPosWV_lampRadius.xyz = mul(float4(0, 0, 0, 1), matWV).xyz;
so.radius_radiusSq_invRadiusSq_invLampRadius.y = dot(scaledFrontDir, scaledFrontDir);
so.radius_radiusSq_invRadiusSq_invLampRadius.x = sqrt(so.radius_radiusSq_invRadiusSq_invLampRadius.y);
so.radius_radiusSq_invRadiusSq_invLampRadius.z = 1.0 / so.radius_radiusSq_invRadiusSq_invLampRadius.y;
const float lampRadius = ComputeLampRadius(so.radius_radiusSq_invRadiusSq_invLampRadius.x, color);
so.lightPosWV_lampRadius.w = lampRadius;
so.radius_radiusSq_invRadiusSq_invLampRadius.w = 1.0 / lampRadius;
}
#endif
// </MoreLightParams>
@ -113,6 +117,7 @@ VSO mainVS(VSI si)
#endif
#ifdef _FS
[earlydepthstencil]
DS_ACC_FSO mainFS(VSO si)
{
DS_ACC_FSO so;
@ -135,12 +140,14 @@ DS_ACC_FSO mainFS(VSO si)
const float coneOut = si.color_coneOut.a;
#endif
// Omni and spot have position and radius:
// Omni and spot have position, radius and size:
#if defined(DEF_OMNI) || defined(DEF_SPOT)
const float3 lightPosWV = si.lightPosWV;
const float radius = si.radius_radiusSq_invRadiusSq.x;
const float radiusSq = si.radius_radiusSq_invRadiusSq.y;
const float invRadiusSq = si.radius_radiusSq_invRadiusSq.z;
const float3 lightPosWV = si.lightPosWV_lampRadius.xyz;
const float radius = si.radius_radiusSq_invRadiusSq_invLampRadius.x;
const float radiusSq = si.radius_radiusSq_invRadiusSq_invLampRadius.y;
const float invRadiusSq = si.radius_radiusSq_invRadiusSq_invLampRadius.z;
const float lampRadius = si.lightPosWV_lampRadius.w;
const float invLampRadius = si.radius_radiusSq_invRadiusSq_invLampRadius.w;
#endif
// Depth:
@ -179,17 +186,20 @@ DS_ACC_FSO mainFS(VSO si)
const float lightFalloff = 1.0; // No falloff.
#else
const float3 toLightWV = lightPosWV - posWV;
const float3 dirToLightWV = normalize(toLightWV);
const float distToLightSq = dot(toLightWV, toLightWV);
const float distToLight = length(toLightWV);
const float distToLightSq = distToLight * distToLight;
const float3 dirToLightWV = toLightWV / distToLight;
const float lightFalloff = ComputePointLightIntensity(distToLightSq, radiusSq, invRadiusSq);
#endif
#ifdef DEF_SPOT // Extra step for spot light:
const float coneIntensity = ComputeSpotLightConeIntensity(dirToLightWV, lightDirWV, coneOut, invConeDelta);
const float coneIntensity = ComputeSpotLightConeIntensity(dirToLightWV, lightDirWV, coneOut, invConeDelta) *
saturate(distToLight * invLampRadius * 10.0 - 10.0);
#else
const float coneIntensity = 1.0; // No cone.
#endif
const float lightFalloffWithCone = lightFalloff * coneIntensity;
const float3 dirToEyeWV = normalize(-posWV);
const float distToEye = length(posWV);
const float3 dirToEyeWV = -posWV / distToEye;
const float3 lightColor = si.color_coneOut.rgb;
// </LightData>
@ -212,14 +222,20 @@ DS_ACC_FSO mainFS(VSO si)
g_ubShadowFS._matShadowCSM2,
g_ubShadowFS._matShadowCSM3,
g_ubShadowFS._matScreenCSM,
g_ubShadowFS._csmSplitRanges,
g_ubShadowFS._csmSliceBounds,
shadowConfig);
#endif
}
// </Shadow>
const float lightMinRoughness = 0.015;
const float lightRoughness = lightMinRoughness + roughness * (1.0 / (1.0 - lightMinRoughness));
#ifdef DEF_DIR
const float lightMinRoughness = 0.015; // The sun.
#else
const float distToReflected = distToLight + distToEye;
const float lampRadiusFactor = lampRadius / (1.0 + distToReflected * distToReflected);
const float lightMinRoughness = clamp(lampRadiusFactor * 64.0, 0.01, 0.6);
#endif
const float lightRoughness = lightMinRoughness + (1.0 - lightMinRoughness) * roughness;
float3 punctualDiff, punctualSpec;
VerusLit(normalWV, dirToLightWV, dirToEyeWV, tangentWV,

View File

@ -28,7 +28,7 @@ VERUS_UBUFFER UB_ShadowFS
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -42,8 +42,8 @@ VSO mainVS(VSI si)
const float3 toEye = g_ubForestVS._eyePos.xyz - si.pos.xyz;
const float distToHead = distance(g_ubForestVS._headPos.xyz, si.pos.xyz);
const float nearAlpha = ComputeFade(distToHead, 60.0, 90.0);
const float farAlpha = 1.0 - ComputeFade(distToHead, 900.0, 1000.0);
const float nearAlpha = QuadOutEasing(ComputeFade(distToHead, 50.0, 100.0));
const float farAlpha = 1.0 - ComputeFade(distToHead, 750.0, 1000.0);
so.pos = mul(si.pos, g_ubForestVS._matWVP);
so.tc0 = 0.0;
@ -77,8 +77,8 @@ void mainGS(point VSO si[1], inout TriangleStream<VSO> stream)
{
const float2 posOffset = _POINT_SPRITE_POS_OFFSETS[i] * so.psize;
const float2 offset = float2(
dot(posOffset, g_ubForestVS._spriteMat.xy),
dot(posOffset, g_ubForestVS._spriteMat.zw));
dot(posOffset, g_ubForestVS._matRoll.xy),
dot(posOffset, g_ubForestVS._matRoll.zw));
so.pos.xy = center + offset;
so.tc0 = _POINT_SPRITE_TEX_COORDS[i];
stream.Append(so);
@ -105,7 +105,7 @@ float ComputeMask(float2 tc, float alpha)
{
const float2 tcCenter = tc - 0.5;
const float grad = 1.0 - saturate(dot(tcCenter, tcCenter) * 4.0);
return saturate(grad + (alpha * 2.0 - 1.0));
return saturate(grad + (alpha * 2.0 - 1.0)); // 0 to grad to 1.
}
#ifdef _FS
@ -159,7 +159,7 @@ DS_FSO mainFS(VSO si)
so.target1.a = 1.0;
so.target3.a = max(so.target3.a, AlphaToResolveDitheringMask(alpha));
const float fudgeFactor = 1.5;
const float fudgeFactor = 1.2;
clip(saturate(alpha * fudgeFactor) * mask - (dither + (1.0 / 8.0)));
return so;

View File

@ -7,7 +7,7 @@ VERUS_UBUFFER UB_ForestVS
float4 _viewportSize;
float4 _eyePos;
float4 _headPos;
float4 _spriteMat;
float4 _matRoll;
};
VERUS_UBUFFER UB_ForestFS

View File

@ -184,8 +184,8 @@ void mainGS(point VSO si[1], inout TriangleStream<VSO> stream)
{
const float2 posOffset = _POINT_SPRITE_POS_OFFSETS[i] * so.psize;
const float2 offset = float2(
dot(posOffset, g_ubGrassVS._spriteMat.xy),
dot(posOffset, g_ubGrassVS._spriteMat.zw));
dot(posOffset, g_ubGrassVS._matRoll.xy),
dot(posOffset, g_ubGrassVS._matRoll.zw));
so.pos.xy = center + offset;
so.tc0 = _POINT_SPRITE_TEX_COORDS[i];
stream.Append(so);

View File

@ -10,7 +10,7 @@ VERUS_UBUFFER UB_GrassVS
float4 _headPos;
float4 _viewportSize;
float4 _warp_turb;
float4 _spriteMat;
float4 _matRoll;
};
VERUS_UBUFFER UB_GrassFS

View File

@ -88,7 +88,6 @@ VSO mainVS(VSI si)
const float4 userColor = g_ubPerObject._userColor;
#endif
float addLamBias = 0.0;
#if defined(DEF_SKINNED) || defined(DEF_ROBOTIC)
const float4 warpMask = float4(
1,
@ -124,9 +123,6 @@ VSO mainVS(VSI si)
lerp(matW33[1], matNewW33[1], userColor.a),
lerp(matW33[2], matNewW33[2], userColor.a),
matW[3]);
const float weight = 1.0 - saturate(dot(offsetXYZ, offsetXYZ));
addLamBias = (-(weight * weight * weight)) * saturate(userColor.a);
}
const float3 pos = inPos;
#else
@ -196,7 +192,7 @@ VSO mainVS(VSI si)
so.color0 = userColor;
#ifdef DEF_PLANT
so.color0.rgb = RandomColor(userColor.xz, 0.25, 0.15);
so.color0.a = 1.0 - ComputeFade(max(-so.pos.z, so.pos.w), 70.0, 100.0);
so.color0.a = QuadOutEasing(1.0 - ComputeFade(max(-so.pos.z, so.pos.w), 50.0, 100.0));
#endif
#if !defined(DEF_DEPTH) && !defined(DEF_SOLID_COLOR)
so.matTBN0 = float4(tanWV, posW.x);
@ -415,7 +411,7 @@ DS_FSO mainFS(VSO si)
// <Strass>
{
const float strass = g_texStrass.Sample(g_samStrass, tc0 * mm_strassScale).r;
roughness *= 1.0 - clamp(strass * mm_roughDiffuse * 4.0, 0.0, 0.99);
roughness *= 1.0 - strass * mm_roughDiffuse;
}
// </Strass>

View File

@ -173,6 +173,7 @@ VSO mainDS(_IN_DS)
#endif
#ifdef _FS
[earlydepthstencil]
DS_FSO mainFS(VSO si)
{
DS_FSO so;
@ -184,16 +185,36 @@ DS_FSO mainFS(VSO si)
// Fix interpolation errors by rounding:
si.layerForChannel = round(si.layerForChannel);
const float2 tcLayer = si.tcLayer_tcMap.xy;
const float2 tcLayer2 = si.tcLayer_tcMap.xy * 0.25;
const float2 tcMap = si.tcLayer_tcMap.zw;
const float4 blendSam = g_texBlend.Sample(g_samBlend, si.tcBlend.xy);
const float4 weights = float4(blendSam.rgb, 1.0 - dot(blendSam.rgb, 1.0));
float4 weights;
{
const float4 blendSam = g_texBlend.Sample(g_samBlend, si.tcBlend.xy);
weights = float4(blendSam.rgb, 1.0 - dot(blendSam.rgb, 1.0));
#if _SHADER_QUALITY >= _Q_HIGH
const float2 tc = tcLayer * 0.125;
const float4 blendNoise = float4(
g_texDetail.Sample(g_samDetail, tc + si.layerForChannel.rr * (1.0 / 16.0)).r,
g_texDetail.Sample(g_samDetail, tc + si.layerForChannel.gg * (1.0 / 16.0)).r,
g_texDetail.Sample(g_samDetail, tc + si.layerForChannel.bb * (1.0 / 16.0)).r,
g_texDetail.Sample(g_samDetail, tc + si.layerForChannel.aa * (1.0 / 16.0)).r);
const float4 noiseMask = saturate(weights * (1.0 - weights) * 3.0);
weights = lerp(weights, saturate((blendNoise - 0.5) * 6.0 + 0.5), noiseMask);
weights /= dot(weights, 1.0);
#endif
}
const float4 texEnabled = ceil(weights);
const float3 tcLayerR = float3(tcLayer * texEnabled.r, si.layerForChannel.r);
const float3 tcLayerG = float3(tcLayer * texEnabled.g, si.layerForChannel.g);
const float3 tcLayerB = float3(tcLayer * texEnabled.b, si.layerForChannel.b);
const float3 tcLayerA = float3(tcLayer * texEnabled.a, si.layerForChannel.a);
const float3 tcLayerR2 = float3(tcLayer2 * texEnabled.r, si.layerForChannel.r);
const float3 tcLayerG2 = float3(tcLayer2 * texEnabled.g, si.layerForChannel.g);
const float3 tcLayerB2 = float3(tcLayer2 * texEnabled.b, si.layerForChannel.b);
const float3 tcLayerA2 = float3(tcLayer2 * texEnabled.a, si.layerForChannel.a);
// <Basis>
float3 basisTan, basisBin, basisNrm;
@ -217,11 +238,20 @@ DS_FSO mainFS(VSO si)
float detailStrength;
float roughStrength;
{
const float ratio = 0.4;
float3 accAlbedo = 0.0;
accAlbedo += g_texLayers.Sample(g_samLayers, tcLayerR).rgb * weights.r;
accAlbedo += g_texLayers.Sample(g_samLayers, tcLayerG).rgb * weights.g;
accAlbedo += g_texLayers.Sample(g_samLayers, tcLayerB).rgb * weights.b;
accAlbedo += g_texLayers.Sample(g_samLayers, tcLayerA).rgb * weights.a;
accAlbedo += lerp(
g_texLayers.Sample(g_samLayers, tcLayerR).rgb,
g_texLayers.Sample(g_samLayers, tcLayerR2).rgb, ratio) * weights.r;
accAlbedo += lerp(
g_texLayers.Sample(g_samLayers, tcLayerG).rgb,
g_texLayers.Sample(g_samLayers, tcLayerG2).rgb, ratio) * weights.g;
accAlbedo += lerp(
g_texLayers.Sample(g_samLayers, tcLayerB).rgb,
g_texLayers.Sample(g_samLayers, tcLayerB2).rgb, ratio) * weights.b;
accAlbedo += lerp(
g_texLayers.Sample(g_samLayers, tcLayerA).rgb,
g_texLayers.Sample(g_samLayers, tcLayerA2).rgb, ratio) * weights.a;
albedo = accAlbedo;
static float vDetailStrength[_MAX_TERRAIN_LAYERS] = (float[_MAX_TERRAIN_LAYERS])g_ubTerrainFS._vDetailStrength;
@ -269,11 +299,20 @@ DS_FSO mainFS(VSO si)
float3 normalWV;
float3 tangentWV;
{
const float ratio = 0.4;
float4 accNormal = 0.0;
accNormal += g_texLayersN.Sample(g_samLayersN, tcLayerR) * weights.r;
accNormal += g_texLayersN.Sample(g_samLayersN, tcLayerG) * weights.g;
accNormal += g_texLayersN.Sample(g_samLayersN, tcLayerB) * weights.b;
accNormal += g_texLayersN.Sample(g_samLayersN, tcLayerA) * weights.a;
accNormal += lerp(
g_texLayersN.Sample(g_samLayersN, tcLayerR),
g_texLayersN.Sample(g_samLayersN, tcLayerR2), ratio) * weights.r;
accNormal += lerp(
g_texLayersN.Sample(g_samLayersN, tcLayerG),
g_texLayersN.Sample(g_samLayersN, tcLayerG2), ratio) * weights.g;
accNormal += lerp(
g_texLayersN.Sample(g_samLayersN, tcLayerB),
g_texLayersN.Sample(g_samLayersN, tcLayerB2), ratio) * weights.b;
accNormal += lerp(
g_texLayersN.Sample(g_samLayersN, tcLayerA),
g_texLayersN.Sample(g_samLayersN, tcLayerA2), ratio) * weights.a;
accNormal.rg = saturate(accNormal.rg * lerp(0.5, detailNSam.rg, detailStrength) * 2.0);
@ -319,7 +358,7 @@ DS_FSO mainFS(VSO si)
// <Strass>
{
const float strass = g_texStrass.Sample(g_samStrass, tcLayer * g_strassScale).r;
roughness *= 1.0 - clamp(strass * roughStrength * 4.0, 0.0, 0.99);
roughness *= 1.0 - strass * roughStrength;
}
// </Strass>
@ -341,6 +380,20 @@ DS_FSO mainFS(VSO si)
DS_SetTangent(so, tangentWV);
DS_SetAnisoSpec(so, anisoSpec);
DS_SetRoughDiffuse(so, roughStrength);
#if 0
DS_SetAlbedo(so, 1.0);
DS_SetNormal(so, matFromTBN[2]);
DS_SetEmission(so, 0.0);
DS_SetOcclusion(so, 1.0);
DS_SetRoughness(so, 0.0);
DS_SetMetallic(so, 1.0);
DS_SetWrapDiffuse(so, 0.0);
DS_SetRoughDiffuse(so, 0.0);
#endif
}
#endif

View File

@ -208,6 +208,12 @@ float SinAcos(float x) // sin(acos(x))
{
return sqrt(saturate(1.0 - x * x));
}
float QuadOutEasing(float x)
{
const float a = 1.0 - x;
return 1.0 - a * a;
}
// </Math>
// <PhysicallyBasedRendering>

View File

@ -75,7 +75,7 @@ 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);
const float desatMask = saturate(maxValue * 0.05);
hdr = lerp(hdr, maxValue, desatMask * desatMask); // Color crosstalk.
const float3 ldr = lerp(1.0 - exp(-hdr), ToneMappingACES(hdr), filmicLook);
return saturate(ldr);

View File

@ -201,7 +201,7 @@ float ShadowMapCSM(
matrix mat2,
matrix mat3,
matrix matScreen,
float4 csmSplitRanges,
float4 csmSliceBounds,
float4 config)
{
#if _SHADOW_QUALITY >= _Q_HIGH
@ -213,22 +213,22 @@ float ShadowMapCSM(
if (IsClippedCSM(clipSpacePos))
{
if (depth >= csmSplitRanges.x)
if (depth >= csmSliceBounds.x)
{
const float fadeStart = (csmSplitRanges.x + csmSplitRanges.w) * 0.5;
const float fade = saturate((depth - fadeStart) / (csmSplitRanges.w - fadeStart));
const float fadeStart = (csmSliceBounds.x + csmSliceBounds.w) * 0.5;
const float fade = saturate((depth - fadeStart) / (csmSliceBounds.w - fadeStart));
contrast = contrastScale * contrastScale * contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat0).xyz;
ret = max(PCF(texCmp, samCmp, tex, sam, tc, config), fade);
}
else if (depth >= csmSplitRanges.y)
else if (depth >= csmSliceBounds.y)
{
contrast = contrastScale * contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat1).xyz;
ret = PCF(texCmp, samCmp, tex, sam, tc, config);
}
else if (depth >= csmSplitRanges.z)
else if (depth >= csmSliceBounds.z)
{
contrast = contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat2).xyz;
@ -263,7 +263,7 @@ float SimpleShadowMapCSM(
matrix mat2,
matrix mat3,
matrix matScreen,
float4 csmSplitRanges,
float4 csmSliceBounds,
float4 config,
bool clipping = true)
{
@ -276,22 +276,22 @@ float SimpleShadowMapCSM(
if (!clipping || IsClippedCSM(clipSpacePos))
{
if (depth >= csmSplitRanges.x)
if (depth >= csmSliceBounds.x)
{
const float fadeStart = (csmSplitRanges.x + csmSplitRanges.w) * 0.5;
const float fade = saturate((depth - fadeStart) / (csmSplitRanges.w - fadeStart));
const float fadeStart = (csmSliceBounds.x + csmSliceBounds.w) * 0.5;
const float fade = saturate((depth - fadeStart) / (csmSliceBounds.w - fadeStart));
contrast = contrastScale * contrastScale * contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat0).xyz;
ret = max(SimplePCF(texCmp, samCmp, tc), fade);
}
else if (depth >= csmSplitRanges.y)
else if (depth >= csmSliceBounds.y)
{
contrast = contrastScale * contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat1).xyz;
ret = SimplePCF(texCmp, samCmp, tc);
}
else if (depth >= csmSplitRanges.z)
else if (depth >= csmSliceBounds.z)
{
contrast = contrastScale;
const float3 tc = mul(float4(biasedPos, 1.0), mat2).xyz;

View File

@ -163,3 +163,8 @@ float ComputeSpotLightConeIntensity(float3 dirToLight, float3 lightDir, float co
const float dp = dot(-dirToLight, lightDir);
return saturate((dp - coneOut) * invConeDelta);
}
float ComputeLampRadius(float radius, float3 color)
{
return radius * 10.0 / dot(color, 1.0 / 3.0);
}

View File

@ -5,7 +5,7 @@ float ComputeNormalZ(float2 v)
return sqrt(saturate(1.0 - dot(v.xy, v.xy)));
}
float3 NormalMapFromBC5(float4 normalSam, float contrast = -1.0)
float3 NormalMapFromBC5(float4 normalSam, float contrast = -2.0)
{
float3 normal = (normalSam.rgb - 0.5) * contrast;
normal.z = ComputeNormalZ(normal.xy);

View File

@ -57,8 +57,8 @@ VSO mainVS(VSI si)
const float3 toEye = eyePos - si.pos.xyz;
const float distToMainCamera = distance(mainCameraEyePos, si.pos.xyz);
const float nearAlpha = ComputeFade(distToMainCamera, 6.0, 9.0);
const float farAlpha = 1.0 - ComputeFade(distToMainCamera, 900.0, 1000.0);
const float nearAlpha = ComputeFade(distToMainCamera, 5.0, 10.0);
const float farAlpha = 1.0 - ComputeFade(distToMainCamera, 750.0, 1000.0);
so.pos = mul(si.pos, g_ubSimpleForestVS._matWVP);
so.tc0 = 0.0;
@ -119,7 +119,7 @@ float ComputeMask(float2 tc, float alpha)
{
const float2 tcCenter = tc - 0.5;
const float grad = 1.0 - saturate(dot(tcCenter, tcCenter) * 4.0);
return saturate(grad + (alpha * 2.0 - 1.0));
return saturate(grad + (alpha * 2.0 - 1.0)); // 0 to grad to 1.
}
#ifdef _FS
@ -171,7 +171,7 @@ FSO mainFS(VSO si)
g_ubSimpleForestFS._matShadowCSM2,
g_ubSimpleForestFS._matShadowCSM3,
g_ubSimpleForestFS._matScreenCSM,
g_ubSimpleForestFS._csmSplitRanges,
g_ubSimpleForestFS._csmSliceBounds,
g_ubSimpleForestFS._shadowConfig);
}
// </Shadow>

View File

@ -24,6 +24,6 @@ VERUS_UBUFFER UB_SimpleForestFS
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -245,7 +245,7 @@ FSO mainFS(VSO si)
g_ubSimplePerFrame._matShadowCSM2,
g_ubSimplePerFrame._matShadowCSM3,
g_ubSimplePerFrame._matScreenCSM,
g_ubSimplePerFrame._csmSplitRanges,
g_ubSimplePerFrame._csmSliceBounds,
g_ubSimplePerFrame._shadowConfig);
}
// </Shadow>

View File

@ -14,7 +14,7 @@ VERUS_UBUFFER UB_SimplePerFrame
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -180,7 +180,7 @@ FSO mainFS(VSO si)
g_ubSimpleTerrainFS._matShadowCSM2,
g_ubSimpleTerrainFS._matShadowCSM3,
g_ubSimpleTerrainFS._matScreenCSM,
g_ubSimpleTerrainFS._csmSplitRanges,
g_ubSimpleTerrainFS._csmSliceBounds,
g_ubSimpleTerrainFS._shadowConfig);
}
// </Shadow>

View File

@ -21,6 +21,6 @@ VERUS_UBUFFER UB_SimpleTerrainFS
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -304,7 +304,7 @@ FSO mainFS(VSO si)
g_ubWaterFS._matShadowCSM2,
g_ubWaterFS._matShadowCSM3,
g_ubWaterFS._matScreenCSM,
g_ubWaterFS._csmSplitRanges,
g_ubWaterFS._csmSliceBounds,
shadowConfig);
}
// </Shadow>

View File

@ -26,6 +26,6 @@ VERUS_UBUFFER UB_WaterFS
matrix _matShadowCSM2;
matrix _matShadowCSM3;
matrix _matScreenCSM;
float4 _csmSplitRanges;
float4 _csmSliceBounds;
float4 _shadowConfig;
};

View File

@ -472,15 +472,15 @@ float Atmosphere::GetWindSpeed() const
return _wind._speed;
}
void Atmosphere::BeginShadow(int split)
void Atmosphere::BeginShadow(int slice)
{
const Vector3 up = _sun._matTilt * Vector3(0, 0, 1);
_shadowMapBaker.Begin(_sun._dirTo, split, up);
_shadowMapBaker.Begin(_sun._dirTo, slice, up);
}
void Atmosphere::EndShadow(int split)
void Atmosphere::EndShadow(int slice)
{
_shadowMapBaker.End(split);
_shadowMapBaker.End(slice);
}
void Atmosphere::CreateCelestialBodyMesh()

View File

@ -167,8 +167,8 @@ namespace verus
RCubeMapBaker GetCubeMapBaker() { return _cubeMapBaker; }
// ShadowMap:
void BeginShadow(int split);
void EndShadow(int split);
void BeginShadow(int slice);
void EndShadow(int slice);
RCascadedShadowMapBaker GetShadowMapBaker() { return _shadowMapBaker; }
void CreateCelestialBodyMesh();

View File

@ -22,11 +22,92 @@ BaseMesh::~BaseMesh()
void BaseMesh::Init(CSZ url)
{
VERUS_INIT();
_url = url;
if (Str::StartsWith(url, "[_GEN]:"))
return;
VERUS_INIT();
IO::Async::I().Load(url, this);
}
void BaseMesh::Init(RcSourceBuffers sourceBuffers)
{
VERUS_INIT();
VERUS_RT_ASSERT(!_vertCount);
_vertCount = Utils::Cast32(sourceBuffers._vPos.size());
_indexCount = Utils::Cast32(sourceBuffers._vIndices.size());
_faceCount = _indexCount ? _indexCount / 3 : _vertCount / 3;
if (_indexCount)
_vIndices.assign(sourceBuffers._vIndices.begin(), sourceBuffers._vIndices.end());
_vBinding0.resize(_vertCount);
if (!sourceBuffers._vPos.empty())
{
Math::Bounds bounds;
VERUS_FOR(i, _vertCount)
bounds.Include(sourceBuffers._vPos[i]);
const glm::vec3 extents = bounds.GetExtents().GLM();
glm::vec3 scale, bias;
ComputeDeq(scale, bias, extents, bounds.GetMin().GLM());
memcpy(_posDeq + 0, glm::value_ptr(scale), sizeof(float) * 3);
memcpy(_posDeq + 3, glm::value_ptr(bias), sizeof(float) * 3);
VERUS_FOR(i, _vertCount)
{
glm::vec3 v(sourceBuffers._vPos[i]);
QuantizeV(v, extents, bounds.GetMin().GLM());
_vBinding0[i]._pos[0] = short(v.x);
_vBinding0[i]._pos[1] = short(v.y);
_vBinding0[i]._pos[2] = short(v.z);
}
}
if (!sourceBuffers._vTc0.empty())
{
Math::Bounds bounds;
VERUS_FOR(i, _vertCount)
bounds.Include(sourceBuffers._vTc0[i]);
const glm::vec3 extents = bounds.GetExtents().GLM();
glm::vec3 scale, bias;
ComputeDeq(scale, bias, extents, bounds.GetMin().GLM());
memcpy(_tc0Deq + 0, glm::value_ptr(scale), sizeof(float) * 2);
memcpy(_tc0Deq + 2, glm::value_ptr(bias), sizeof(float) * 2);
VERUS_FOR(i, _vertCount)
{
glm::vec3 v(sourceBuffers._vTc0[i], 0);
QuantizeV(v, extents, bounds.GetMin().GLM());
_vBinding0[i]._tc0[0] = short(v.x);
_vBinding0[i]._tc0[1] = short(v.y);
}
}
if (!sourceBuffers._vNrm.empty())
{
VERUS_FOR(i, _vertCount)
Convert::SnormToSint8(glm::value_ptr(sourceBuffers._vNrm[i]), _vBinding0[i]._nrm, 3);
}
if (sourceBuffers._recalculateTangentSpace)
{
_vBinding2.resize(_vertCount);
Vector<glm::vec3> vTan, vBin;
Math::TangentSpaceTools::RecalculateTangentSpace(
sourceBuffers._vIndices,
sourceBuffers._vPos,
sourceBuffers._vNrm,
sourceBuffers._vTc0,
vTan, vBin);
VERUS_FOR(i, _vertCount)
{
Convert::SnormToSint16(glm::value_ptr(vTan[i]), _vBinding2[i]._tan, 3);
Convert::SnormToSint16(glm::value_ptr(vBin[i]), _vBinding2[i]._bin, 3);
}
}
if (_initShape)
InitShape(Transform3::identity());
CreateDeviceBuffers();
}
void BaseMesh::Done()
{
IO::Async::Cancel(this);
@ -466,15 +547,15 @@ void BaseMesh::RecalculateTangentSpace()
Math::TangentSpaceTools::RecalculateNormals(_vIndices, vV, vN, 1);
VERUS_FOR(i, _vertCount)
Convert::SnormToSint8(&vN[i].x, _vBinding0[i]._nrm, 3);
Convert::SnormToSint8(glm::value_ptr(vN[i]), _vBinding0[i]._nrm, 3);
if (!_vBinding2.empty())
{
Math::TangentSpaceTools::RecalculateTangentSpace(_vIndices, vV, vN, vTex, vTan, vBin);
VERUS_FOR(i, _vertCount)
{
Convert::SnormToSint16(&vTan[i].x, _vBinding2[i]._tan, 3);
Convert::SnormToSint16(&vBin[i].x, _vBinding2[i]._bin, 3);
Convert::SnormToSint16(glm::value_ptr(vTan[i]), _vBinding2[i]._tan, 3);
Convert::SnormToSint16(glm::value_ptr(vBin[i]), _vBinding2[i]._bin, 3);
}
}
}
@ -493,11 +574,11 @@ btBvhTriangleMeshShape* BaseMesh::InitShape(RcTransform3 tr, CSZ url)
DoneShape();
String finalUrl = url ? url : _url;
String finalURL = url ? url : _url;
String cacheFilename;
if (!finalUrl.empty())
if (!finalURL.empty() && !Str::StartsWith(_C(finalURL), "[_GEN]:"))
{
String filename = Str::ToPakFriendlyUrl(_C(finalUrl));
String filename = Str::ToPakFriendlyUrl(_C(finalURL));
if (url)
filename += ".INST";
filename = "[Models]:PhyCache/" + filename + ".bullet";

View File

@ -60,10 +60,21 @@ namespace verus
bool _initShape = false;
public:
struct SourceBuffers
{
Vector<UINT16> _vIndices;
Vector<glm::vec3> _vPos;
Vector<glm::vec2> _vTc0;
Vector<glm::vec3> _vNrm;
bool _recalculateTangentSpace = true;
};
VERUS_TYPEDEFS(SourceBuffers);
BaseMesh();
virtual ~BaseMesh();
void Init(CSZ url);
void Init(RcSourceBuffers sourceBuffers);
void Done();
Str GetURL() const { return _C(_url); }

View File

@ -74,6 +74,18 @@ void CubeMapBaker::BeginEnvMap(CGI::CubeMapFace cubeMapFace, RcPoint3 center)
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
auto cb = renderer.GetCommandBuffer();
switch (cubeMapFace)
{
case CGI::CubeMapFace::posX: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 240, 240, 255), "CubeMapBaker/posX"); break;
case CGI::CubeMapFace::negX: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(255, 224, 224, 255), "CubeMapBaker/negX"); break;
case CGI::CubeMapFace::posY: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(240, 255, 240, 255), "CubeMapBaker/posY"); break;
case CGI::CubeMapFace::negY: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(224, 255, 224, 255), "CubeMapBaker/negY"); break;
case CGI::CubeMapFace::posZ: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(240, 240, 255, 255), "CubeMapBaker/posZ"); break;
case CGI::CubeMapFace::negZ: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(224, 224, 255, 255), "CubeMapBaker/negZ"); break;
}
_center = center;
Vector3 facePos = Vector3(0);
@ -99,7 +111,7 @@ void CubeMapBaker::BeginEnvMap(CGI::CubeMapFace cubeMapFace, RcPoint3 center)
_pPrevPassCamera = wm.SetPassCamera(&_passCamera);
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh[+cubeMapFace],
cb->BeginRenderPass(_rph, _fbh[+cubeMapFace],
{
_tex[TEX_COLOR]->GetClearValue(),
_tex[TEX_DEPTH]->GetClearValue()
@ -112,7 +124,11 @@ void CubeMapBaker::EndEnvMap()
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
renderer.GetCommandBuffer()->EndRenderPass();
auto cb = renderer.GetCommandBuffer();
cb->EndRenderPass();
VERUS_PROFILER_END_EVENT(cb);
wm.SetPassCamera(_pPrevPassCamera);
}

View File

@ -577,6 +577,10 @@ void EditorTerrain::ApplyBrushSplat(const float xz[2], int layer, int radius, fl
falloff = Convert::Sint8ToSnorm(GetNormalAt(ij)[1]);
falloff = pow(falloff, 10.f);
break;
case TerrainSplatMode::inversedNormal:
falloff = Convert::Sint8ToSnorm(GetNormalAt(ij)[1]);
falloff = 1 - pow(falloff, 10.f);
break;
}
SplatTileAtEx(ij, layer, strength * maskValue * falloff);
}

View File

@ -10,6 +10,7 @@ namespace verus
solid,
grad,
normal,
inversedNormal,
rand
};

View File

@ -80,13 +80,14 @@ void Forest::Init(PTerrain pTerrain, CSZ url)
};
_scatter.Init(s_scatterSide, SCATTER_TYPE_COUNT, id, 19201);
_scatter.SetDelegate(this);
_scatter.SetMaxDist(_maxDist * 1.25f);
_scatter.SetMaxDist(_maxDistForModels * 1.25f);
_vPlants.reserve(16);
_vLayerData.reserve(16);
_vDrawPlants.resize(_capacity);
_vCollisionPool.Resize(1000);
_vCollisionPlants.Reserve(400);
_vCollisionPool.Resize(400);
if (url)
{
@ -127,6 +128,7 @@ void Forest::Init(PTerrain pTerrain, CSZ url)
typeNode.attribute("minScale").as_float(0.5f),
typeNode.attribute("maxScale").as_float(1.5f),
typeNode.attribute("windBending").as_float(1),
typeNode.attribute("hullSplitU").as_float(-1),
typeNode.attribute("allowedNormal").as_int(116));
}
@ -143,11 +145,15 @@ void Forest::Done()
bullet.GetWorld()->removeRigidBody(block.GetRigidBody());
block.GetDefaultMotionState()->~btDefaultMotionState();
block.GetRigidBody()->~btRigidBody();
block.GetScaledBvhTriangleMeshShape()->~btScaledBvhTriangleMeshShape();
block.GetUniformScalingShapeForBranches()->~btUniformScalingShape();
block.GetUniformScalingShapeForTrunk()->~btUniformScalingShape();
block.GetCompoundShape()->~btCompoundShape();
block.Free();
});
for (auto& plant : _vPlants)
{
plant._pConvexHullShapeForBranches.Delete();
plant._pConvexHullShapeForTrunk.Delete();
s_shader[SHADER_SIMPLE]->FreeDescriptorSet(plant._cshSimple);
s_shader[SHADER_MAIN]->FreeDescriptorSet(plant._csh);
}
@ -178,7 +184,6 @@ void Forest::Update()
Mesh::Desc meshDesc;
meshDesc._url = _C(plant._url);
meshDesc._instanceCapacity = _capacity;
meshDesc._initShape = true;
plant._mesh.Init(meshDesc);
Material::Desc matDesc;
@ -203,6 +208,22 @@ void Forest::Update()
_maxSizeAll = plant._maxSize;
_pTerrain->FattenQuadtreeNodesBy(_maxSizeAll);
}
// Time to create convex hulls:
plant._pConvexHullShapeForTrunk = new(plant._pConvexHullShapeForTrunk.GetData()) btConvexHullShape();
plant._pConvexHullShapeForBranches = new(plant._pConvexHullShapeForBranches.GetData()) btConvexHullShape();
plant._mesh.ForEachVertex([&plant](int index, RcPoint3 pos, RcVector3 nrm, RcPoint3 tc)
{
if (tc.getX() >= plant._hullSplitU)
plant._pConvexHullShapeForBranches->addPoint(pos.Bullet(), false);
else
plant._pConvexHullShapeForTrunk->addPoint(pos.Bullet(), false);
return Continue::yes;
});
plant._pConvexHullShapeForTrunk->recalcLocalAabb();
plant._pConvexHullShapeForBranches->recalcLocalAabb();
plant._pConvexHullShapeForTrunk->optimizeConvexHull();
plant._pConvexHullShapeForBranches->optimizeConvexHull();
}
if (!plant._tex[0] && plant._mesh.IsLoaded() && plant._material->IsLoaded())
@ -333,36 +354,31 @@ void Forest::Layout(bool reflection)
{
if (!IsInitialized())
return;
_visibleCount = 0;
VERUS_QREF_ATMO;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_WM;
_visibleCount = 0;
for (auto& plant : _vPlants)
{
for (auto& bc : plant._vBakedChunks)
bc._visible = false;
{
const float zFarWas = wm.GetHeadCamera()->GetZFar();
if (!reflection)
{
wm.GetHeadCamera()->SetFrustumFar(_maxDist);
Math::RQuadtreeIntegral qt = _pTerrain->GetQuadtree();
qt.SetDelegate(&_scatter);
qt.TraverseVisible();
qt.SetDelegate(_pTerrain);
}
wm.GetHeadCamera()->SetFrustumFar(1000);
_octree.TraverseVisible(wm.GetHeadCamera()->GetFrustum());
wm.GetHeadCamera()->SetFrustumFar(zFarWas);
if (reflection)
return;
}
_octree.TraverseVisible(wm.GetPassCamera()->GetFrustum());
if (!reflection)
{
Math::RQuadtreeIntegral quadtree = _pTerrain->GetQuadtree();
quadtree.SetDelegate(&_scatter);
quadtree.TraverseVisible();
quadtree.SetDelegate(_pTerrain);
SortVisible();
}
}
void Forest::SortVisible()
{
const float tessDistSq = _tessDist * _tessDist;
std::sort(_vDrawPlants.begin(), _vDrawPlants.begin() + _visibleCount, [tessDistSq](RDrawPlant plantA, RDrawPlant plantB)
{
@ -406,6 +422,8 @@ void Forest::DrawModels(bool allowTess)
auto cb = renderer.GetCommandBuffer();
auto shader = Mesh::GetShader();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 255, 160, 255), "Forest/DrawModels");
auto DrawMesh = [cb](PMesh pMesh)
{
if (pMesh && !pMesh->IsInstanceBufferEmpty(true))
@ -480,6 +498,8 @@ void Forest::DrawModels(bool allowTess)
}
}
shader->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Forest::DrawSprites()
@ -494,12 +514,14 @@ void Forest::DrawSprites()
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 255, 160, 255), "Forest/DrawSprites");
s_ubForestVS._matP = wm.GetPassCamera()->GetMatrixP().UniformBufferFormat();
s_ubForestVS._matWVP = wm.GetPassCamera()->GetMatrixVP().UniformBufferFormat();
s_ubForestVS._viewportSize = cb->GetViewportSize().GLM();
s_ubForestVS._eyePos = float4(wm.GetPassCamera()->GetEyePosition().GLM(), 0);
s_ubForestVS._headPos = float4(wm.GetHeadCamera()->GetEyePosition().GLM(), 0);
s_ubForestVS._spriteMat = wm.GetPassCamera()->GetMatrixV().ToSpriteMat();
s_ubForestVS._matRoll = wm.GetPassCamera()->GetMatrixV().ToSpriteRollMatrix();
cb->BindPipeline(_pipe[drawingDepth ? PIPE_DEPTH : PIPE_MAIN]);
cb->BindVertexBuffers(_geo);
@ -517,6 +539,8 @@ void Forest::DrawSprites()
}
}
s_shader[SHADER_MAIN]->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
@ -568,6 +592,8 @@ void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(32, 255, 160, 255), "Forest/DrawSimple");
s_ubSimpleForestVS._matP = wm.GetPassCamera()->GetMatrixP().UniformBufferFormat();
s_ubSimpleForestVS._matWVP = wm.GetPassCamera()->GetMatrixVP().UniformBufferFormat();
s_ubSimpleForestVS._viewportSize = cb->GetViewportSize().GLM();
@ -585,7 +611,7 @@ void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
s_ubSimpleForestFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrix(2).UniformBufferFormat();
s_ubSimpleForestFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrix(3).UniformBufferFormat();
s_ubSimpleForestFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixVP().UniformBufferFormat();
s_ubSimpleForestFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubSimpleForestFS._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubSimpleForestFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubSimpleForestFS._shadowConfig));
switch (mode)
@ -608,6 +634,8 @@ void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
}
}
s_shader[SHADER_SIMPLE]->EndBindDescriptors();
VERUS_PROFILER_END_EVENT(cb);
}
void Forest::UpdateCollision(const Vector<Vector4>& vZones)
@ -624,8 +652,8 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
};
const int r = static_cast<int>(zone.getW() + 0.5f);
const int r2 = r * r;
const int iRange[2] = { Math::Clamp(centerIJ[0] - r, 0, mapSide), Math::Clamp(centerIJ[0] + r, 0, mapSide) };
const int jRange[2] = { Math::Clamp(centerIJ[1] - r, 0, mapSide), Math::Clamp(centerIJ[1] + r, 0, mapSide) };
const int iRange[2] = { Math::Clamp(centerIJ[0] - r, 0, mapSide), Math::Clamp(centerIJ[0] + r + 1, 0, mapSide) };
const int jRange[2] = { Math::Clamp(centerIJ[1] - r, 0, mapSide), Math::Clamp(centerIJ[1] + r + 1, 0, mapSide) };
for (int i = iRange[0]; i < iRange[1]; ++i)
{
const int offsetI = centerIJ[0] - i;
@ -697,22 +725,36 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
const float t = (plant._alignToNormal - 0.1f) / 0.8f;
const Matrix3 matBasis = Matrix3::Lerp(Matrix3::identity(), _pTerrain->GetBasisAt(ij), t);
const Transform3 matW = Transform3(matBasis * Matrix3::rotationY(instance._angle), Vector3(pos));
btScaledBvhTriangleMeshShape* pShape = new(block.GetScaledBvhTriangleMeshShape())
btScaledBvhTriangleMeshShape(plant._mesh.GetShape(), btVector3(scale, scale, scale));
btRigidBody* pRigidBody = bullet.AddNewRigidBody(0, matW.Bullet(), pShape, +Physics::Group::immovable, +Physics::Group::all, nullptr,
btCompoundShape* pCompoundShape = new(block.GetCompoundShape()) btCompoundShape();
btUniformScalingShape* pUniformScalingShapeForTrunk = new(block.GetUniformScalingShapeForTrunk())
btUniformScalingShape(plant._pConvexHullShapeForTrunk.Get(), scale);
btUniformScalingShape* pUniformScalingShapeForBranches = new(block.GetUniformScalingShapeForBranches())
btUniformScalingShape(plant._pConvexHullShapeForBranches.Get(), scale);
// DebugDraw will not show UniformScalingShape, add ConvexHullShape instead.
btTransform tr;
tr.setIdentity();
if (plant._pConvexHullShapeForTrunk->getNumPoints())
pCompoundShape->addChildShape(tr, pUniformScalingShapeForTrunk);
if (plant._pConvexHullShapeForBranches->getNumPoints())
pCompoundShape->addChildShape(tr, pUniformScalingShapeForBranches);
btRigidBody* pRigidBody = bullet.AddNewRigidBody(0, matW.Bullet(), pCompoundShape, +Physics::Group::forest, +bullet.GetNonStaticMask(), nullptr,
block.GetDefaultMotionState(),
block.GetRigidBody());
pRigidBody->setFriction(Physics::Bullet::GetFriction(Physics::Material::stone));
pRigidBody->setRestitution(Physics::Bullet::GetRestitution(Physics::Material::stone));
pRigidBody->setFriction(Physics::Bullet::GetFriction(Physics::Material::wood));
pRigidBody->setRestitution(Physics::Bullet::GetRestitution(Physics::Material::wood));
},
[this](RCollisionPlant cp)
{
if (cp._poolBlockIndex < 0)
return;
VERUS_QREF_BULLET;
RCollisionPoolBlock block = _vCollisionPool.GetBlockAt(cp._poolBlockIndex);
bullet.GetWorld()->removeRigidBody(block.GetRigidBody());
block.GetDefaultMotionState()->~btDefaultMotionState();
block.GetRigidBody()->~btRigidBody();
block.GetScaledBvhTriangleMeshShape()->~btScaledBvhTriangleMeshShape();
block.GetUniformScalingShapeForBranches()->~btUniformScalingShape();
block.GetUniformScalingShapeForTrunk()->~btUniformScalingShape();
block.GetCompoundShape()->~btCompoundShape();
block.Free();
});
}
@ -776,6 +818,7 @@ void Forest::SetLayer(int layer, RcLayerDesc desc)
plant._alignToNormal = plantDesc._alignToNormal;
plant._maxScale = plantDesc._maxScale;
plant._windBending = plantDesc._windBending;
plant._hullSplitU = plantDesc._hullSplitU;
plant._allowedNormal = plantDesc._allowedNormal;
const float ds = plantDesc._maxScale - plantDesc._minScale;
const int count = 64;
@ -783,10 +826,6 @@ void Forest::SetLayer(int layer, RcLayerDesc desc)
VERUS_FOR(i, count)
plant._vScales[i] = plantDesc._minScale + ds * (i * i * i) / (count * count * count);
std::shuffle(plant._vScales.begin(), plant._vScales.end(), random.GetGenerator());
//plant._vShapePool.resize(2000 * sizeof(btScaledBvhTriangleMeshShape));
//plant._vMotionStatePool.resize(2000 * sizeof(btDefaultMotionState));
//plant._vRigidBodyPool.resize(2000 * sizeof(btRigidBody));
}
}
}
@ -1185,7 +1224,7 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl
Point3 pos(x, h, z);
RcPoint3 headPos = wm.GetHeadCamera()->GetEyePosition();
const float distSq = VMath::distSqr(headPos, pos);
const float maxDistSq = _maxDist * _maxDist;
const float maxDistSq = _maxDistForModels * _maxDistForModels;
if (distSq >= maxDistSq)
return;
@ -1231,7 +1270,7 @@ Continue Forest::Octree_ProcessNode(void* pToken, void* pUser)
{
VERUS_QREF_WM;
PBakedChunk pBakedChunk = static_cast<PBakedChunk>(pToken);
pBakedChunk->_visible = wm.GetPassCamera()->GetFrustum().ContainsAabb(pBakedChunk->_bounds) != Relation::outside;
pBakedChunk->_visible = true;
return Continue::yes;
}

View File

@ -74,24 +74,32 @@ namespace verus
class alignas(VERUS_MEMORY_ALIGNMENT) CollisionPoolBlock
{
public:
BYTE _data[sizeof(btScaledBvhTriangleMeshShape) + sizeof(btDefaultMotionState) + sizeof(btRigidBody)];
bool _reserved = 0;
BYTE _data[sizeof(btCompoundShape) + 2 * sizeof(btUniformScalingShape) + sizeof(btDefaultMotionState) + sizeof(btRigidBody)];
bool _reserved = false;
bool IsReserved() const { return _reserved; }
void Reserve() { _reserved = true; }
void Free() { _reserved = false; }
btScaledBvhTriangleMeshShape* GetScaledBvhTriangleMeshShape()
btCompoundShape* GetCompoundShape()
{
return reinterpret_cast<btScaledBvhTriangleMeshShape*>(&_data[0]);
return reinterpret_cast<btCompoundShape*>(&_data[0]);
}
btUniformScalingShape* GetUniformScalingShapeForTrunk()
{
return reinterpret_cast<btUniformScalingShape*>(&_data[sizeof(btCompoundShape)]);
}
btUniformScalingShape* GetUniformScalingShapeForBranches()
{
return reinterpret_cast<btUniformScalingShape*>(&_data[sizeof(btCompoundShape) + sizeof(btUniformScalingShape)]);
}
btDefaultMotionState* GetDefaultMotionState()
{
return reinterpret_cast<btDefaultMotionState*>(&_data[sizeof(btScaledBvhTriangleMeshShape)]);
return reinterpret_cast<btDefaultMotionState*>(&_data[sizeof(btCompoundShape) + 2 * sizeof(btUniformScalingShape)]);
}
btRigidBody* GetRigidBody()
{
return reinterpret_cast<btRigidBody*>(&_data[sizeof(btScaledBvhTriangleMeshShape) + sizeof(btDefaultMotionState)]);
return reinterpret_cast<btRigidBody*>(&_data[sizeof(btCompoundShape) + 2 * sizeof(btUniformScalingShape) + sizeof(btDefaultMotionState)]);
}
};
VERUS_TYPEDEFS(CollisionPoolBlock);
@ -114,12 +122,15 @@ namespace verus
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::CSHandle _csh;
CGI::CSHandle _cshSimple;
LocalPtr<btConvexHullShape> _pConvexHullShapeForTrunk;
LocalPtr<btConvexHullShape> _pConvexHullShapeForBranches;
Vector<BakedChunk> _vBakedChunks;
Vector<float> _vScales;
float _alignToNormal = 1;
float _maxScale = 0;
float _maxSize = 0;
float _windBending = 1;
float _hullSplitU = -1;
char _allowedNormal = 116;
float GetSize() const;
@ -171,7 +182,8 @@ namespace verus
DifferenceVector<CollisionPlant> _vCollisionPlants;
Pool<CollisionPoolBlock> _vCollisionPool;
const float _margin = 1.1f;
float _maxDist = 100;
float _maxDistForModels = 100;
float _maxDistForChunks = 1000;
float _tessDist = 50;
float _maxSizeAll = 0;
float _phaseY = 0;
@ -190,15 +202,24 @@ namespace verus
float _minScale = 0.8f;
float _maxScale = 1.25f;
float _windBending = 1;
float _hullSplitU = -1;
char _allowedNormal = 116;
void Set(CSZ url, float alignToNormal = 1, float minScale = 0.8f, float maxScale = 1.25f, float windBending = 1, char allowedNormal = 116)
void Set(
CSZ url,
float alignToNormal = 1,
float minScale = 0.8f,
float maxScale = 1.25f,
float windBending = 1,
float hullSplitU = -1,
char allowedNormal = 116)
{
_url = url;
_alignToNormal = alignToNormal;
_minScale = minScale;
_maxScale = maxScale;
_windBending = windBending;
_hullSplitU = hullSplitU;
_allowedNormal = allowedNormal;
}
};
@ -225,6 +246,7 @@ namespace verus
void ResetInstanceCount();
void Update();
void Layout(bool reflection = false);
void SortVisible();
void Draw(bool allowTess = true);
VERUS_P(void DrawModels(bool allowTess));
VERUS_P(void DrawSprites());

View File

@ -207,21 +207,19 @@ void Grass::Layout()
{
VERUS_QREF_WM;
// <Traverse>
_visiblePatchCount = 0;
const float zFar = wm.GetPassCamera()->GetZFar();
wm.GetPassCamera()->SetZFar(128);
wm.GetPassCamera()->UpdateZNearFar();
// Reuse terrain's quadtree:
Math::RQuadtreeIntegral quadtree = _pTerrain->GetQuadtree();
_visiblePatchCount = 0;
quadtree.SetDelegate(this);
quadtree.TraverseVisible();
quadtree.SetDelegate(_pTerrain);
wm.GetPassCamera()->SetZFar(zFar);
wm.GetPassCamera()->UpdateZNearFar();
// </Traverse>
}
void Grass::Draw()
@ -251,7 +249,7 @@ void Grass::Draw()
s_ubGrassVS._headPos = float4(wm.GetHeadCamera()->GetEyePosition().GLM(), 0);
s_ubGrassVS._viewportSize = cb->GetViewportSize().GLM();
s_ubGrassVS._warp_turb = Vector4(_warpSpring.GetOffset(), _turbulence).GLM();
s_ubGrassVS._spriteMat = wm.GetPassCamera()->GetMatrixV().ToSpriteMat();
s_ubGrassVS._matRoll = wm.GetPassCamera()->GetMatrixV().ToSpriteRollMatrix();
cb->BindVertexBuffers(_geo);
cb->BindIndexBuffer(_geo);

View File

@ -167,7 +167,7 @@ void LightMapBaker::Init(RcDesc desc)
{
tex->GetClearValue(),
_tex[TEX_DEPTH]->GetClearValue()
});
}, CGI::ViewportScissorFlags::setAllForFramebuffer);
renderer.GetCommandBuffer()->EndRenderPass();
tex->GenerateMips();
}
@ -179,19 +179,22 @@ void LightMapBaker::Init(RcDesc desc)
void LightMapBaker::Done()
{
VERUS_QREF_RENDERER;
if (renderer.GetShaderQuad())
if (CGI::Renderer::IsLoaded())
{
VERUS_QREF_RENDERER;
if (renderer.GetShaderQuad())
{
VERUS_FOR(ringBufferIndex, CGI::BaseRenderer::s_ringBufferSize)
renderer.GetShaderQuad()->FreeDescriptorSet(_cshQuad[ringBufferIndex]);
renderer.GetShaderQuad()->FreeDescriptorSet(_cshHemicubeMask);
}
VERUS_FOR(ringBufferIndex, CGI::BaseRenderer::s_ringBufferSize)
renderer.GetShaderQuad()->FreeDescriptorSet(_cshQuad[ringBufferIndex]);
renderer.GetShaderQuad()->FreeDescriptorSet(_cshHemicubeMask);
{
VERUS_FOR(batchIndex, s_batchSize)
renderer->DeleteFramebuffer(_fbh[ringBufferIndex][batchIndex]);
}
renderer->DeleteRenderPass(_rph);
}
VERUS_FOR(ringBufferIndex, CGI::BaseRenderer::s_ringBufferSize)
{
VERUS_FOR(batchIndex, s_batchSize)
renderer->DeleteFramebuffer(_fbh[ringBufferIndex][batchIndex]);
}
renderer->DeleteRenderPass(_rph);
VERUS_DONE(LightMapBaker);
}
@ -358,7 +361,7 @@ void LightMapBaker::DrawEmpty()
{
tex->GetClearValue(),
_tex[TEX_DEPTH]->GetClearValue()
});
}, CGI::ViewportScissorFlags::setAllForFramebuffer);
DrawHemicubeMask();
@ -404,7 +407,7 @@ void LightMapBaker::DrawLumel(RcPoint3 pos, RcVector3 nrm, int batchIndex)
{
tex->GetClearValue(),
_tex[TEX_DEPTH]->GetClearValue()
});
}, CGI::ViewportScissorFlags::setAllForFramebuffer);
if (_pDelegate)
{
const glm::vec2 randVec = glm::circularRand(1.f);
@ -420,7 +423,7 @@ void LightMapBaker::DrawLumel(RcPoint3 pos, RcVector3 nrm, int batchIndex)
{
const CGI::CubeMapFace cubeMapFace = static_cast<CGI::CubeMapFace>(i);
Camera cam;
MainCamera cam;
cam.MoveEyeTo(drawLumelDesc._eyePos);
switch (cubeMapFace)
{
@ -450,12 +453,14 @@ void LightMapBaker::DrawLumel(RcPoint3 pos, RcVector3 nrm, int batchIndex)
cam.SetZNear(0.00001f);
cam.SetZFar(_desc._distance);
cam.Update();
PCamera pPrevCamera = wm.SetPassCamera(&cam);
auto pPrevPassCamera = wm.SetPassCamera(&cam);
auto pPrevHeadCamera = wm.SetHeadCamera(&cam);
drawLumelDesc._frontDir = cam.GetFrontDirection();
_pDelegate->LightMapBaker_Draw(cubeMapFace, drawLumelDesc);
wm.SetPassCamera(pPrevCamera);
wm.SetPassCamera(pPrevPassCamera);
wm.SetHeadCamera(pPrevHeadCamera);
}
_pDelegate->LightMapBaker_Draw(CGI::CubeMapFace::negZ, drawLumelDesc);

View File

@ -80,11 +80,21 @@ void Mesh::Init(RcDesc desc)
}
_instanceCapacity = desc._instanceCapacity;
_instanceBufferFormat = desc._instanceBufferFormat;
_initShape = desc._initShape;
BaseMesh::Init(desc._url);
}
void Mesh::Init(RcSourceBuffers sourceBuffers, RcDesc desc)
{
_instanceCapacity = desc._instanceCapacity;
_instanceBufferFormat = desc._instanceBufferFormat;
_initShape = desc._initShape;
BaseMesh::Init(sourceBuffers);
}
void Mesh::Done()
{
VERUS_DONE(Mesh);
@ -505,7 +515,7 @@ void Mesh::UpdateUniformBufferSimplePerFrame(DrawSimpleMode mode)
s_ubSimplePerFrame._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrix(2).UniformBufferFormat();
s_ubSimplePerFrame._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrix(3).UniformBufferFormat();
s_ubSimplePerFrame._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixVP().UniformBufferFormat();
s_ubSimplePerFrame._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubSimplePerFrame._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubSimplePerFrame._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubSimplePerFrame._shadowConfig));
}
@ -520,26 +530,29 @@ void Mesh::CreateDeviceBuffers()
CGI::GeometryDesc geoDesc;
geoDesc._name = _C(_url);
const CGI::VertexInputAttrDesc viaDesc[] =
Vector<CGI::VertexInputAttrDesc> vViaDesc;
{
{0, offsetof(VertexInputBinding0, _pos), CGI::ViaType::shorts, 4, CGI::ViaUsage::position, 0},
{0, offsetof(VertexInputBinding0, _tc0), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 0},
{0, offsetof(VertexInputBinding0, _nrm), CGI::ViaType::ubytes, 4, CGI::ViaUsage::normal, 0},
{1, offsetof(VertexInputBinding1, _bw), CGI::ViaType::shorts, 4, CGI::ViaUsage::blendWeights, 0},
{1, offsetof(VertexInputBinding1, _bi), CGI::ViaType::shorts, 4, CGI::ViaUsage::blendIndices, 0},
{2, offsetof(VertexInputBinding2, _tan), CGI::ViaType::shorts, 4, CGI::ViaUsage::tangent, 0},
{2, offsetof(VertexInputBinding2, _bin), CGI::ViaType::shorts, 4, CGI::ViaUsage::binormal, 0},
{3, offsetof(VertexInputBinding3, _tc1), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 1},
{3, offsetof(VertexInputBinding3, _clr), CGI::ViaType::ubytes, 4, CGI::ViaUsage::color, 0},
{-4, offsetof(PerInstanceData, _matPart0), CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 0},
{-4, offsetof(PerInstanceData, _matPart1), CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 1},
{-4, offsetof(PerInstanceData, _matPart2), CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 2},
{-4, offsetof(PerInstanceData, _instData), CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 3},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
const int strides[] = { sizeof(VertexInputBinding0), sizeof(VertexInputBinding1), sizeof(VertexInputBinding2), sizeof(VertexInputBinding3), sizeof(PerInstanceData), 0 };
vViaDesc.reserve(16);
vViaDesc.push_back({ 0, offsetof(VertexInputBinding0, _pos), CGI::ViaType::shorts, 4, CGI::ViaUsage::position, 0 });
vViaDesc.push_back({ 0, offsetof(VertexInputBinding0, _tc0), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 0 });
vViaDesc.push_back({ 0, offsetof(VertexInputBinding0, _nrm), CGI::ViaType::ubytes, 4, CGI::ViaUsage::normal, 0 });
vViaDesc.push_back({ 1, offsetof(VertexInputBinding1, _bw), CGI::ViaType::shorts, 4, CGI::ViaUsage::blendWeights, 0 });
vViaDesc.push_back({ 1, offsetof(VertexInputBinding1, _bi), CGI::ViaType::shorts, 4, CGI::ViaUsage::blendIndices, 0 });
vViaDesc.push_back({ 2, offsetof(VertexInputBinding2, _tan), CGI::ViaType::shorts, 4, CGI::ViaUsage::tangent, 0 });
vViaDesc.push_back({ 2, offsetof(VertexInputBinding2, _bin), CGI::ViaType::shorts, 4, CGI::ViaUsage::binormal, 0 });
vViaDesc.push_back({ 3, offsetof(VertexInputBinding3, _tc1), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 1 });
vViaDesc.push_back({ 3, offsetof(VertexInputBinding3, _clr), CGI::ViaType::ubytes, 4, CGI::ViaUsage::color, 0 });
vViaDesc.push_back({ 3, offsetof(VertexInputBinding3, _clr), CGI::ViaType::ubytes, 4, CGI::ViaUsage::color, 0 });
vViaDesc.push_back({ -4, 0, CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 0 });
vViaDesc.push_back({ -4, 16, CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 1 });
vViaDesc.push_back({ -4, 32, CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 2 });
vViaDesc.push_back({ -4, 48, CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 3 });
if (InstanceBufferFormat::mataff_2float4 == _instanceBufferFormat)
vViaDesc.push_back({ -4, 64, CGI::ViaType::floats, 4, CGI::ViaUsage::instData, 4 });
vViaDesc.push_back(CGI::VertexInputAttrDesc::End());
}
geoDesc._pVertexInputAttrDesc = vViaDesc.data();
const int strides[] = { sizeof(VertexInputBinding0), sizeof(VertexInputBinding1), sizeof(VertexInputBinding2), sizeof(VertexInputBinding3), GetInstanceSize(), 0 };
geoDesc._pStrides = strides;
geoDesc._32BitIndices = _vIndices.empty();
_geo.Init(geoDesc);
@ -588,9 +601,9 @@ void Mesh::CreateDeviceBuffers()
// Instance buffer:
if (_instanceCapacity > 0)
{
_vInstanceBuffer.resize(_instanceCapacity);
_vInstanceBuffer.resize(_instanceCapacity * GetInstanceSize());
_bindingsMask |= (1 << 4);
_geo->CreateVertexBuffer(Utils::Cast32(_vInstanceBuffer.size()), 4);
_geo->CreateVertexBuffer(_instanceCapacity, 4);
}
}
@ -605,15 +618,30 @@ void Mesh::ResetInstanceCount()
_firstInstance = 0;
}
void Mesh::PushInstance(RcTransform3 matW, RcVector4 instData)
void Mesh::PushInstance(RcTransform3 matW, RcVector4 instData, PcVector4 pInstData1)
{
VERUS_RT_ASSERT(!_vInstanceBuffer.empty());
if (!_vertCount)
return;
if (IsInstanceBufferFull())
return;
matW.InstFormat(&_vInstanceBuffer[_instanceCount]._matPart0);
_vInstanceBuffer[_instanceCount]._instData = instData;
const int offset = _instanceCount * GetInstanceSize();
switch (_instanceBufferFormat)
{
case InstanceBufferFormat::mataff_float4:
{
matW.InstFormat(reinterpret_cast<PVector4>(&_vInstanceBuffer[offset]));
*reinterpret_cast<PVector4>(&_vInstanceBuffer[offset] + 48) = instData;
}
break;
case InstanceBufferFormat::mataff_2float4:
{
matW.InstFormat(reinterpret_cast<PVector4>(&_vInstanceBuffer[offset]));
*reinterpret_cast<PVector4>(&_vInstanceBuffer[offset] + 48) = instData;
*reinterpret_cast<PVector4>(&_vInstanceBuffer[offset] + 64) = *pInstData1;
}
break;
}
_instanceCount++;
}
@ -633,8 +661,19 @@ bool Mesh::IsInstanceBufferEmpty(bool fromFirstInstance)
return GetInstanceCount(fromFirstInstance) <= 0;
}
int Mesh::GetInstanceSize() const
{
switch (_instanceBufferFormat)
{
case InstanceBufferFormat::mataff_float4: return 64;
case InstanceBufferFormat::mataff_2float4: return 80;
}
return 0;
}
void Mesh::UpdateInstanceBuffer()
{
VERUS_RT_ASSERT(!_vInstanceBuffer.empty());
_geo->UpdateVertexBuffer(&_vInstanceBuffer[_firstInstance], 4, nullptr, GetInstanceCount(true), _firstInstance);
const int offset = _firstInstance * GetInstanceSize();
_geo->UpdateVertexBuffer(&_vInstanceBuffer[offset], 4, nullptr, GetInstanceCount(true), _firstInstance);
}

View File

@ -69,12 +69,10 @@ namespace verus
PIPE_COUNT
};
struct PerInstanceData
enum class InstanceBufferFormat : int
{
Vector4 _matPart0 = Vector4(0);
Vector4 _matPart1 = Vector4(0);
Vector4 _matPart2 = Vector4(0);
Vector4 _instData = Vector4(0);
mataff_float4,
mataff_2float4
};
private:
@ -91,20 +89,22 @@ namespace verus
static UB_SimpleSkeletonVS s_ubSimpleSkeletonVS;
static UB_SimplePerObject s_ubSimplePerObject;
CGI::GeometryPwn _geo;
Vector<PerInstanceData> _vInstanceBuffer;
int _instanceCapacity = 0;
int _instanceCount = 0;
int _firstInstance = 0;
UINT32 _bindingsMask = 0;
CGI::GeometryPwn _geo;
Vector<BYTE> _vInstanceBuffer;
int _instanceCapacity = 0;
int _instanceCount = 0;
int _firstInstance = 0;
InstanceBufferFormat _instanceBufferFormat = InstanceBufferFormat::mataff_float4;
UINT32 _bindingsMask = 0;
public:
struct Desc
{
CSZ _url = nullptr;
CSZ _warpURL = nullptr;
int _instanceCapacity = 0;
bool _initShape = false;
CSZ _url = nullptr;
CSZ _warpURL = nullptr;
int _instanceCapacity = 0;
InstanceBufferFormat _instanceBufferFormat = InstanceBufferFormat::mataff_float4;
bool _initShape = false;
Desc(CSZ url = nullptr) : _url(url) {}
};
@ -131,6 +131,7 @@ namespace verus
static void DoneStatic();
void Init(RcDesc desc = Desc());
void Init(RcSourceBuffers sourceBuffers, RcDesc desc = Desc());
void Done();
void Draw(RcDrawDesc drawDesc, CGI::CommandBufferPtr cb);
@ -160,9 +161,10 @@ namespace verus
// Instancing:
void ResetInstanceCount();
void MarkFirstInstance() { _firstInstance = _instanceCount; }
void PushInstance(RcTransform3 matW, RcVector4 instData);
void PushInstance(RcTransform3 matW, RcVector4 instData, PcVector4 pInstData1 = nullptr);
bool IsInstanceBufferFull();
bool IsInstanceBufferEmpty(bool fromFirstInstance = false);
int GetInstanceSize() const;
void UpdateInstanceBuffer();
int GetInstanceCount(bool fromFirstInstance = false) const { return fromFirstInstance ? _instanceCount - _firstInstance : _instanceCount; }

View File

@ -57,6 +57,10 @@ void ShadowMapBaker::Begin(RcVector3 dirToSun, RcVector3 up)
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 96, 96, 255), "ShadowMapBaker");
Point3 eye, at;
const float texSizeInMeters = 100;
const float depth = texSizeInMeters * 10;
@ -75,7 +79,6 @@ void ShadowMapBaker::Begin(RcVector3 dirToSun, RcVector3 up)
at = (matFromLightSpace * snappedPos).getXYZ();
}
// Setup light space camera and use it (used for terrain draw, etc.):
eye = at + dirToSun * (depth * (2 / 3.f));
const float zNear = 1;
const float zFar = zNear + depth;
@ -92,7 +95,7 @@ void ShadowMapBaker::Begin(RcVector3 dirToSun, RcVector3 up)
_config._unormDepthScale = depth;
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh, { _tex->GetClearValue() },
cb->BeginRenderPass(_rph, _fbh, { _tex->GetClearValue() },
CGI::ViewportScissorFlags::setAllForFramebuffer);
VERUS_RT_ASSERT(!_baking);
@ -104,7 +107,11 @@ void ShadowMapBaker::End()
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
renderer.GetCommandBuffer()->EndRenderPass();
auto cb = renderer.GetCommandBuffer();
cb->EndRenderPass();
VERUS_PROFILER_END_EVENT(cb);
const Matrix4 m = Math::ToUVMatrix();
_matShadow = m * _passCamera.GetMatrixVP();
@ -161,8 +168,12 @@ void CascadedShadowMapBaker::Init(int side)
VERUS_QREF_RENDERER;
_side = side;
_headCameraPreferredRange = 300;
if (settings._sceneShadowQuality >= App::Settings::Quality::ultra)
{
_side *= 2;
_headCameraPreferredRange = 1000;
}
_rph = renderer->CreateShadowRenderPass(CGI::Format::unormD24uintS8);
@ -205,7 +216,7 @@ void CascadedShadowMapBaker::UpdateMatrixForCurrentView()
_matShadowCSM_DS[i] = _matShadowCSM[i] * wm.GetViewCamera()->GetMatrixInvV();
}
void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int slice, RcVector3 up)
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneShadowQuality < App::Settings::Quality::high)
@ -214,14 +225,29 @@ void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
_currentSplit = split;
_currentSlice = slice;
auto cb = renderer.GetCommandBuffer();
switch (_currentSlice)
{
case 0: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(48, 48, 48, 255), "CascadedShadowMapBaker/0"); break;
case 1: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(64, 64, 64, 255), "CascadedShadowMapBaker/1"); break;
case 2: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(80, 80, 80, 255), "CascadedShadowMapBaker/2"); break;
case 3: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 96, 96, 255), "CascadedShadowMapBaker/3"); break;
default: VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 96, 96, 255), "CascadedShadowMapBaker"); break;
}
RcCamera headCamera = *wm.GetHeadCamera();
_passCamera = headCamera;
Point3 eye, at;
float texWidthInMeters, texHeightInMeters, texSizeInMeters;
float zNear, zFar;
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
const float headCameraRange = Math::Min<float>(_headCameraPreferredRange, headCamera.GetZFar() - headCamera.GetZNear());
auto ComputeTextureSize = [&texWidthInMeters, &texHeightInMeters, &texSizeInMeters](Math::RcBounds bounds)
{
// Stabilize size:
@ -231,50 +257,26 @@ void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
texSizeInMeters = Math::Max(texWidthInMeters, texHeightInMeters);
};
const Matrix4 matToLightSpace = Matrix4::lookAt(Point3(0), Point3(-dirToSun), up);
const float headCameraMaxRange = (settings._sceneShadowQuality >= App::Settings::Quality::ultra) ? 1000.f : 300.f;
const float headCameraRange = Math::Min<float>(headCameraMaxRange, headCamera.GetZFar() - headCamera.GetZNear()); // Clip terrain, etc.
_passCamera = headCamera;
auto PrepareCameraArguments = [this, &eye, &at, &zNear, &zFar, &dirToSun, &matToLightSpace](RcPoint3 centerPosLS)
auto PrepareCameraArguments = [this, &eye, &at, &zNear, &zFar, &dirToSun, &matToLightSpace](RcPoint3 centerPosLS, float atOffset)
{
at = (VMath::orthoInverse(matToLightSpace) * centerPosLS).getXYZ();
eye = at + dirToSun * (_depth * (2 / 3.f));
at = (VMath::orthoInverse(matToLightSpace) * centerPosLS).getXYZ() + dirToSun * atOffset;
eye = at + dirToSun * _depth;
zNear = 1;
zFar = zNear + _depth;
};
if (0 == _currentSplit)
if (0 == _currentSlice)
{
_matScreenVP = _passCamera.GetMatrixVP();
_matScreenP = _passCamera.GetMatrixP();
_depth = Math::Min(headCameraRange * 10, 10000.f); // 10 times larger than side.
_passCamera.SetZFar(_passCamera.GetZNear() + headCameraRange);
_passCamera.Update(); // Prepare frustum for measurements.
Point3 focusedCenterPos; // With stable Z.
const Math::Bounds frustumBoundsLS = _passCamera.GetFrustum().GetBounds(matToLightSpace, &focusedCenterPos);
ComputeTextureSize(frustumBoundsLS);
// Setup CSM light space camera for full range (used for terrain layout, etc.):
PrepareCameraArguments(focusedCenterPos);
_passCameraCSM.MoveEyeTo(eye);
_passCameraCSM.MoveAtTo(at);
_passCameraCSM.SetUpDirection(up);
_passCameraCSM.SetYFov(0);
_passCameraCSM.SetZNear(zNear);
_passCameraCSM.SetZFar(zFar);
_passCameraCSM.SetXMag(texSizeInMeters);
_passCameraCSM.SetYMag(texSizeInMeters);
_passCameraCSM.Update();
_depth = Math::Min(headCameraRange * 2, 2000.f);
}
if (settings._sceneShadowQuality >= App::Settings::Quality::ultra) // Adjusted for 7x7 PCF.
{
// Compute split ranges (weights are 2, 4.5, 12, 39):
_splitRanges = Vector4(
// Compute slice bounds (weights are 2, 4.5, 12, 39):
_sliceBounds = Vector4(
headCamera.GetZNear() + headCameraRange * (18.5f / 57.5f),
headCamera.GetZNear() + headCameraRange * (6.5f / 57.5f),
headCamera.GetZNear() + headCameraRange * (2 / 57.5f),
@ -282,40 +284,41 @@ void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
}
else // Adjusted for 5x5 PCF.
{
// Compute split ranges (weights are 2, 3, 6, 15):
_splitRanges = Vector4(
// Compute slice bounds (weights are 2, 3, 6, 15):
_sliceBounds = Vector4(
headCamera.GetZNear() + headCameraRange * (10 / 26.f),
headCamera.GetZNear() + headCameraRange * (5 / 26.f),
headCamera.GetZNear() + headCameraRange * (2 / 26.f),
headCamera.GetZNear());
}
// Default scene camera with the current split range:
switch (_currentSplit)
// Default world camera with current slice bounds:
switch (_currentSlice)
{
case 0:
_passCamera.SetZNear(_splitRanges.getX());
_passCamera.SetZNear(_sliceBounds.getX());
_passCamera.SetZFar(headCamera.GetZNear() + headCameraRange);
break;
case 1:
_passCamera.SetZNear(_splitRanges.getY());
_passCamera.SetZFar(_splitRanges.getX());
_passCamera.SetZNear(_sliceBounds.getY());
_passCamera.SetZFar(_sliceBounds.getX());
break;
case 2:
_passCamera.SetZNear(_splitRanges.getZ());
_passCamera.SetZFar(_splitRanges.getY());
_passCamera.SetZNear(_sliceBounds.getZ());
_passCamera.SetZFar(_sliceBounds.getY());
break;
case 3:
_passCamera.SetZNear(_splitRanges.getW());
_passCamera.SetZFar(_splitRanges.getZ());
_passCamera.SetZNear(_sliceBounds.getW());
_passCamera.SetZFar(_sliceBounds.getZ());
break;
}
_splitRanges.setW(headCamera.GetZNear() + headCameraRange);
_sliceBounds.setW(headCamera.GetZNear() + headCameraRange);
_passCamera.Update(); // Prepare frustum for measurements.
Point3 focusedCenterPos; // With stable Z.
const Math::Bounds frustumBoundsLS = _passCamera.GetFrustum().GetBounds(matToLightSpace, &focusedCenterPos);
ComputeTextureSize(frustumBoundsLS);
const float atOffset = frustumBoundsLS.GetMin().getZ() - focusedCenterPos.getZ();
if (_snapToTexels)
{
@ -328,8 +331,7 @@ void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
focusedCenterPos.setY(focusedCenterPos.getY() - fmod(snappedPos.getY() + texelSizeInMeters * 0.5f, texelSizeInMeters));
}
// Setup light space camera and use it (used for terrain draw, etc.):
PrepareCameraArguments(focusedCenterPos);
PrepareCameraArguments(focusedCenterPos, atOffset);
_passCamera.MoveEyeTo(eye);
_passCamera.MoveAtTo(at);
_passCamera.SetUpDirection(up);
@ -343,26 +345,26 @@ void CascadedShadowMapBaker::Begin(RcVector3 dirToSun, int split, RcVector3 up)
_config._unormDepthScale = zFar - zNear;
if (0 == _currentSplit)
if (0 == _currentSlice)
{
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh, { _tex->GetClearValue() },
cb->BeginRenderPass(_rph, _fbh, { _tex->GetClearValue() },
CGI::ViewportScissorFlags::setAllForFramebuffer);
}
const float s = static_cast<float>(_side / 2);
switch (_currentSplit)
switch (_currentSlice)
{
case 0: renderer.GetCommandBuffer()->SetViewport({ Vector4(0, 0, s, s) }); break;
case 1: renderer.GetCommandBuffer()->SetViewport({ Vector4(s, 0, s, s) }); break;
case 2: renderer.GetCommandBuffer()->SetViewport({ Vector4(0, s, s, s) }); break;
case 3: renderer.GetCommandBuffer()->SetViewport({ Vector4(s, s, s, s) }); break;
case 0: cb->SetViewport({ Vector4(0, 0, s, s) }); break;
case 1: cb->SetViewport({ Vector4(s, 0, s, s) }); break;
case 2: cb->SetViewport({ Vector4(0, s, s, s) }); break;
case 3: cb->SetViewport({ Vector4(s, s, s, s) }); break;
}
VERUS_RT_ASSERT(!_baking);
_baking = true;
}
void CascadedShadowMapBaker::End(int split)
void CascadedShadowMapBaker::End(int slice)
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneShadowQuality < App::Settings::Quality::high)
@ -370,44 +372,40 @@ void CascadedShadowMapBaker::End(int split)
VERUS_QREF_RENDERER;
VERUS_QREF_WM;
VERUS_RT_ASSERT(_currentSplit == split);
VERUS_RT_ASSERT(_currentSlice == slice);
if (3 == _currentSplit)
renderer.GetCommandBuffer()->EndRenderPass();
auto cb = renderer.GetCommandBuffer();
if (3 == _currentSlice)
cb->EndRenderPass();
VERUS_PROFILER_END_EVENT(cb);
const Matrix4 m = Math::ToUVMatrix();
_matShadowCSM[_currentSplit] = _matOffset[_currentSplit] * m * _passCamera.GetMatrixVP();
_matShadowCSM[_currentSlice] = _matOffset[_currentSlice] * m * _passCamera.GetMatrixVP();
_pPrevPassCamera = wm.SetPassCamera(_pPrevPassCamera);
VERUS_RT_ASSERT(&_passCamera == _pPrevPassCamera); // Check camera's integrity.
_pPrevPassCamera = nullptr;
_currentSplit = -1;
_currentSlice = -1;
VERUS_RT_ASSERT(_baking);
_baking = false;
}
RcMatrix4 CascadedShadowMapBaker::GetShadowMatrix(int split) const
RcMatrix4 CascadedShadowMapBaker::GetShadowMatrix(int slice) const
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneShadowQuality < App::Settings::Quality::high)
return ShadowMapBaker::GetShadowMatrix();
return _matShadowCSM[split];
return _matShadowCSM[slice];
}
RcMatrix4 CascadedShadowMapBaker::GetShadowMatrixDS(int split) const
RcMatrix4 CascadedShadowMapBaker::GetShadowMatrixDS(int slice) const
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneShadowQuality < App::Settings::Quality::high)
return ShadowMapBaker::GetShadowMatrixDS();
return _matShadowCSM_DS[split];
}
PCamera CascadedShadowMapBaker::GetPassCameraCSM()
{
VERUS_QREF_CONST_SETTINGS;
if (settings._sceneShadowQuality < App::Settings::Quality::high)
return nullptr;
return &_passCameraCSM;
return _matShadowCSM_DS[slice];
}

View File

@ -63,10 +63,10 @@ namespace verus
Matrix4 _matOffset[4];
Matrix4 _matScreenVP = Matrix4::identity();
Matrix4 _matScreenP = Matrix4::identity();
Vector4 _splitRanges = Vector4(0);
Camera _passCameraCSM;
int _currentSplit = -1;
Vector4 _sliceBounds = Vector4(0);
int _currentSlice = -1;
float _depth = 0;
float _headCameraPreferredRange = 0;
public:
CascadedShadowMapBaker();
@ -77,19 +77,17 @@ namespace verus
void UpdateMatrixForCurrentView();
void Begin(RcVector3 dirToSun, int split, RcVector3 up = Vector3(0, 1, 0));
void End(int split);
void Begin(RcVector3 dirToSun, int slice, RcVector3 up = Vector3(0, 1, 0));
void End(int slice);
RcMatrix4 GetShadowMatrix(int split = 0) const;
RcMatrix4 GetShadowMatrixDS(int split = 0) const;
RcMatrix4 GetShadowMatrix(int slice = 0) const;
RcMatrix4 GetShadowMatrixDS(int slice = 0) const;
RcMatrix4 GetScreenMatrixVP() const { return _matScreenVP; }
RcMatrix4 GetScreenMatrixP() const { return _matScreenP; }
int GetCurrentSplit() const { return _currentSplit; }
RcVector4 GetSplitRanges() const { return _splitRanges; }
PCamera GetPassCameraCSM();
int GetCurrentSlice() const { return _currentSlice; }
RcVector4 GetSliceBounds() const { return _sliceBounds; }
};
VERUS_TYPEDEFS(CascadedShadowMapBaker);
}

View File

@ -41,9 +41,9 @@ void TerrainPhysics::Init(Physics::PUserPtr p, int w, int h, const void* pData,
btTransform tr;
tr.setIdentity();
tr.setOrigin(btVector3(-0.5f, 0, -0.5f));
_pRigidBody = bullet.AddNewRigidBody(_pRigidBody, 0, tr, _pShape.Get(), +Physics::Group::terrain);
_pRigidBody->setFriction(Physics::Bullet::GetFriction(Physics::Material::wood));
_pRigidBody->setRestitution(Physics::Bullet::GetRestitution(Physics::Material::wood));
_pRigidBody = bullet.AddNewRigidBody(_pRigidBody, 0, tr, _pShape.Get(), +Physics::Group::terrain, +bullet.GetNonStaticMask());
_pRigidBody->setFriction(Physics::Bullet::GetFriction(Physics::Material::stone));
_pRigidBody->setRestitution(Physics::Bullet::GetRestitution(Physics::Material::stone));
_pRigidBody->setUserPointer(p);
EnableDebugDraw(false);
@ -740,26 +740,30 @@ void Terrain::Layout()
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_WM;
// <Traverse>
PCamera pPrevPassCamera = nullptr;
// For CSM we need to create geometry beyond the view frustum (1st slice):
if (settings._sceneShadowQuality >= App::Settings::Quality::high && atmo.GetShadowMapBaker().IsBaking())
{
PCamera pPassCameraCSM = atmo.GetShadowMapBaker().GetPassCameraCSM();
if (pPassCameraCSM)
pPrevPassCamera = wm.SetPassCamera(pPassCameraCSM);
}
_visiblePatchCount = 0;
_visibleSortedPatchCount = 0;
_visibleRandomPatchCount = 0;
_quadtree.TraverseVisible();
SortVisiblePatches();
// Back to original camera:
if (pPrevPassCamera)
wm.SetPassCamera(pPrevPassCamera);
// </Traverse>
_quadtree.TraverseVisible();
SortVisible();
}
void Terrain::SortVisible()
{
_visiblePatchCount = _visibleSortedPatchCount + _visibleRandomPatchCount;
std::sort(_vSortedPatchIndices.begin(), _vSortedPatchIndices.begin() + _visibleSortedPatchCount, [this](int a, int b)
{
RcTerrainPatch patchA = GetPatch(a);
RcTerrainPatch patchB = GetPatch(b);
if (patchA._quadtreeLOD != patchB._quadtreeLOD)
return patchA._quadtreeLOD < patchB._quadtreeLOD;
return patchA._distToHeadSq < patchB._distToHeadSq;
});
if (_visibleRandomPatchCount)
memcpy(&_vSortedPatchIndices[_visibleSortedPatchCount], _vRandomPatchIndices.data(), _visibleRandomPatchCount * sizeof(UINT16));
}
void Terrain::Draw(RcDrawDesc dd)
@ -777,6 +781,8 @@ void Terrain::Draw(RcDrawDesc dd)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(160, 255, 96, 255), "Terrain/Draw");
s_ubTerrainVS._matW = matW.UniformBufferFormat();
s_ubTerrainVS._matWV = Transform3(wm.GetPassCamera()->GetMatrixV() * matW).UniformBufferFormat();
s_ubTerrainVS._matV = wm.GetPassCamera()->GetMatrixV().UniformBufferFormat();
@ -873,6 +879,8 @@ void Terrain::Draw(RcDrawDesc dd)
_geo->UpdateVertexBuffer(&_vInstanceBuffer[_instanceCount], 1, cb.Get(), _visiblePatchCount, _instanceCount);
_instanceCount += _visiblePatchCount;
VERUS_PROFILER_END_EVENT(cb);
}
void Terrain::DrawSimple(DrawSimpleMode mode)
@ -890,6 +898,8 @@ void Terrain::DrawSimple(DrawSimpleMode mode)
auto cb = renderer.GetCommandBuffer();
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(160, 255, 64, 255), "Terrain/DrawSimple");
s_ubSimpleTerrainVS._matW = matW.UniformBufferFormat();
s_ubSimpleTerrainVS._matVP = wm.GetPassCamera()->GetMatrixVP().UniformBufferFormat();
s_ubSimpleTerrainVS._headPos = float4(wm.GetHeadCamera()->GetEyePosition().GLM(), 0);
@ -905,7 +915,7 @@ void Terrain::DrawSimple(DrawSimpleMode mode)
s_ubSimpleTerrainFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrix(2).UniformBufferFormat();
s_ubSimpleTerrainFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrix(3).UniformBufferFormat();
s_ubSimpleTerrainFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixVP().UniformBufferFormat();
s_ubSimpleTerrainFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubSimpleTerrainFS._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubSimpleTerrainFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubSimpleTerrainFS._shadowConfig));
cb->BindVertexBuffers(_geo);
@ -973,23 +983,8 @@ void Terrain::DrawSimple(DrawSimpleMode mode)
_geo->UpdateVertexBuffer(&_vInstanceBuffer[_instanceCount], 1, cb.Get(), _visiblePatchCount, _instanceCount);
_instanceCount += _visiblePatchCount;
}
void Terrain::SortVisiblePatches()
{
_visiblePatchCount = _visibleSortedPatchCount + _visibleRandomPatchCount;
std::sort(_vSortedPatchIndices.begin(), _vSortedPatchIndices.begin() + _visibleSortedPatchCount, [this](int a, int b)
{
RcTerrainPatch patchA = GetPatch(a);
RcTerrainPatch patchB = GetPatch(b);
if (patchA._quadtreeLOD != patchB._quadtreeLOD)
return patchA._quadtreeLOD < patchB._quadtreeLOD;
return patchA._distToHeadSq < patchB._distToHeadSq;
});
if (_visibleRandomPatchCount)
memcpy(&_vSortedPatchIndices[_visibleSortedPatchCount], _vRandomPatchIndices.data(), _visibleRandomPatchCount * sizeof(UINT16));
VERUS_PROFILER_END_EVENT(cb);
}
int Terrain::UserPtr_GetType()

View File

@ -219,11 +219,10 @@ namespace verus
void ResetInstanceCount();
void Layout();
void SortVisible();
void Draw(RcDrawDesc dd = DrawDesc());
void DrawSimple(DrawSimpleMode mode);
void SortVisiblePatches();
virtual int UserPtr_GetType() override;
int GetMapSide() const { return _mapSide; }

View File

@ -265,7 +265,7 @@ void Water::Draw()
s_ubWaterFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrix(2).UniformBufferFormat();
s_ubWaterFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrix(3).UniformBufferFormat();
s_ubWaterFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixVP().UniformBufferFormat();
s_ubWaterFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
s_ubWaterFS._csmSliceBounds = atmo.GetShadowMapBaker().GetSliceBounds().GLM();
memcpy(&s_ubWaterFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubWaterFS._shadowConfig));
cb->BindPipeline(_pipe[PIPE_MAIN]);
@ -341,7 +341,9 @@ void Water::EndPlanarReflection(CGI::PBaseCommandBuffer pCB)
wm.SetPassCamera(_pPrevPassCamera);
wm.SetHeadCamera(_pPrevHeadCamera);
VERUS_PROFILER_BEGIN_EVENT(pCB, VERUS_COLOR_BLACK, "Water/PlanarReflection/GenerateMips");
_tex[TEX_REFLECTION]->GenerateMips();
VERUS_PROFILER_END_EVENT(pCB);
}
void Water::GenerateTextures()
@ -367,24 +369,30 @@ void Water::GenerateHeightmapTexture()
auto cb = renderer.GetCommandBuffer();
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenHeightmapFS._phase.x = _phase;
memcpy(&s_ubGenHeightmapFS._amplitudes, _amplitudes, sizeof(_amplitudes));
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(96, 96, 160, 255), "Water/GenerateHeightmapTexture");
{
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenHeightmapFS._phase.x = _phase;
memcpy(&s_ubGenHeightmapFS._amplitudes, _amplitudes, sizeof(_amplitudes));
cb->BeginRenderPass(_rphGenHeightmap, _fbhGenHeightmap, { _tex[TEX_GEN_HEIGHTMAP]->GetClearValue(), },
CGI::ViewportScissorFlags::setAllForFramebuffer);
cb->BeginRenderPass(_rphGenHeightmap, _fbhGenHeightmap, { _tex[TEX_GEN_HEIGHTMAP]->GetClearValue(), },
CGI::ViewportScissorFlags::setAllForFramebuffer);
cb->BindPipeline(_pipe[PIPE_GEN_HEIGHTMAP]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 1, _cshGenHeightmap);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->BindPipeline(_pipe[PIPE_GEN_HEIGHTMAP]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 1, _cshGenHeightmap);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
cb->EndRenderPass();
_tex[TEX_GEN_HEIGHTMAP]->GenerateMips(cb.Get());
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_BLACK, "Water/GenerateHeightmapTexture/GenerateMips");
_tex[TEX_GEN_HEIGHTMAP]->GenerateMips(cb.Get());
VERUS_PROFILER_END_EVENT(cb);
}
VERUS_PROFILER_END_EVENT(cb);
}
void Water::GenerateNormalsTexture()
@ -393,24 +401,30 @@ void Water::GenerateNormalsTexture()
auto cb = renderer.GetCommandBuffer();
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenNormalsFS._textureSize = _tex[TEX_GEN_HEIGHTMAP]->GetSize().GLM();
s_ubGenNormalsFS._waterScale.x = 1 / _patchSide;
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_RGBA(128, 128, 255, 255), "Water/GenerateNormalsTexture");
{
s_ubGen._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubGen._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubGenNormalsFS._textureSize = _tex[TEX_GEN_HEIGHTMAP]->GetSize().GLM();
s_ubGenNormalsFS._waterScale.x = 1 / _patchSide;
cb->BeginRenderPass(_rphGenNormals, _fbhGenNormals, { _tex[TEX_GEN_NORMALS]->GetClearValue(), },
CGI::ViewportScissorFlags::setAllForFramebuffer);
cb->BeginRenderPass(_rphGenNormals, _fbhGenNormals, { _tex[TEX_GEN_NORMALS]->GetClearValue(), },
CGI::ViewportScissorFlags::setAllForFramebuffer);
cb->BindPipeline(_pipe[PIPE_GEN_NORMALS]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 2, _cshGenNormals);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->BindPipeline(_pipe[PIPE_GEN_NORMALS]);
_shader[SHADER_GEN]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_GEN], 0);
cb->BindDescriptors(_shader[SHADER_GEN], 2, _cshGenNormals);
_shader[SHADER_GEN]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
cb->EndRenderPass();
_tex[TEX_GEN_NORMALS]->GenerateMips(cb.Get());
VERUS_PROFILER_BEGIN_EVENT(cb, VERUS_COLOR_BLACK, "Water/GenerateNormalsTexture/GenerateMips");
_tex[TEX_GEN_NORMALS]->GenerateMips(cb.Get());
VERUS_PROFILER_END_EVENT(cb);
}
VERUS_PROFILER_END_EVENT(cb);
}
CGI::TexturePtr Water::GetCausticsTexture() const

View File

@ -61,8 +61,8 @@ void WorldManager::Update()
{
VERUS_UPDATE_ONCE_CHECK;
for (auto pNode : _vNodes)
pNode->Update();
VERUS_FOR(i, _vNodes.size()) // Must check size every loop iteration.
_vNodes[i]->Update(); // Can add/remove child nodes.
}
void WorldManager::UpdateParts()
@ -88,21 +88,16 @@ void WorldManager::Layout()
_visibleCount = 0;
VERUS_ZERO_MEM(_visibleCountPerType);
// <Traverse>
PCamera pPrevPassCamera = nullptr;
// For CSM we need to create geometry beyond the view frustum (1st slice):
if (settings._sceneShadowQuality >= App::Settings::Quality::high && atmo.GetShadowMapBaker().IsBaking())
{
PCamera pPassCameraCSM = atmo.GetShadowMapBaker().GetPassCameraCSM();
if (pPassCameraCSM)
pPrevPassCamera = SetPassCamera(pPassCameraCSM);
}
_octree.TraverseVisible(_pPassCamera->GetFrustum());
// Back to original camera:
if (pPrevPassCamera)
SetPassCamera(pPrevPassCamera);
// </Traverse>
SortVisible();
for (auto& x : TStoreTerrainNodes::_list)
x.Layout();
}
void WorldManager::SortVisible()
{
VERUS_RT_ASSERT(!_visibleCountPerType[+NodeType::unknown]);
std::sort(_vVisibleNodes.begin(), _vVisibleNodes.begin() + _visibleCount, [](PBaseNode pA, PBaseNode pB)
{
@ -157,9 +152,6 @@ void WorldManager::Layout()
// Draw same node types front-to-back:
return pA->GetDistToHeadSq() < pB->GetDistToHeadSq();
});
for (auto& x : TStoreTerrainNodes::_list)
x.Layout();
}
void WorldManager::Draw()
@ -448,6 +440,8 @@ Continue WorldManager::Octree_ProcessNode(void* pToken, void* pUser)
PBaseNode pNode = static_cast<PBaseNode>(pToken);
if (pNode->IsDisabled())
return Continue::yes;
if (IsDrawingDepth(DrawDepth::automatic) && !pNode->IsShadowCaster())
return Continue::yes;
_vVisibleNodes[_visibleCount++] = pNode;
_visibleCountPerType[+pNode->GetType()]++;
return Continue::yes;
@ -792,6 +786,7 @@ void WorldManager::DeleteNode(NodeType type, CSZ name, bool hierarchy)
case NodeType::model: deleted = TStoreModelNodes::Delete(_C(static_cast<RModelNode>(node).GetURL())); break;
case NodeType::particles: deleted = TStoreParticlesNodes::Delete(_C(static_cast<RParticlesNode>(node).GetURL())); break;
case NodeType::block: TStoreBlockNodes::Delete(static_cast<PBlockNode>(&node)); break;
case NodeType::blockChain: TStoreBlockChainNodes::Delete(static_cast<PBlockChainNode>(&node)); break;
case NodeType::controlPoint: TStoreControlPointNodes::Delete(static_cast<PControlPointNode>(&node)); break;
case NodeType::emitter: TStoreEmitterNodes::Delete(static_cast<PEmitterNode>(&node)); break;
case NodeType::instance: TStoreInstanceNodes::Delete(static_cast<PInstanceNode>(&node)); break;
@ -841,17 +836,18 @@ PBaseNode WorldManager::DuplicateNode(PBaseNode pTargetNode, HierarchyDuplicatio
BroadcastOnNodeDuplicated(pTargetNode, false, pNewNode, hierarchyDuplication);
switch (pTargetNode->GetType())
{
case NodeType::base: {BaseNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::block: {BlockNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::controlPoint: {ControlPointNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::emitter: {EmitterNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::instance: {InstanceNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::light: {LightNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::path: {PathNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::physics: {PhysicsNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::prefab: {PrefabNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::shaker: {ShakerNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::sound: {SoundNodePtr node; node.Duplicate(*pTargetNode); pNewNode = node.Get(); break; }
case NodeType::base: {BaseNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::block: {BlockNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::blockChain: {BlockChainNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::controlPoint: {ControlPointNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::emitter: {EmitterNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::instance: {InstanceNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::light: {LightNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::path: {PathNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::physics: {PhysicsNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::prefab: {PrefabNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::shaker: {ShakerNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
case NodeType::sound: {SoundNodePtr node; node.Duplicate(*pTargetNode, hierarchyDuplication); pNewNode = node.Get(); break; }
}
BroadcastOnNodeDuplicated(pTargetNode, true, pNewNode, hierarchyDuplication);
@ -935,14 +931,11 @@ int WorldManager::GetSelectedCount()
void WorldManager::SelectAllChildNodes(PBaseNode pTargetNode)
{
const int nodeIndex = GetIndexOf(pTargetNode);
const int nodeDepth = pTargetNode->GetDepth();
const int nodeCount = GetNodeCount();
for (int i = nodeIndex + 1; i < nodeCount; ++i)
for (int i = GetIndexOf(pTargetNode) + 1; i < nodeCount; ++i)
{
PBaseNode pNode = _vNodes[i];
if (pNode->GetDepth() <= nodeDepth)
if (pNode->GetDepth() <= pTargetNode->GetDepth())
break;
pNode->Select();
}
@ -959,6 +952,165 @@ void WorldManager::ResetRigidBodyTransforms()
});
}
void WorldManager::GenerateBlockChainNodes(PBlockChainNode pBlockChainNode)
{
if (!pBlockChainNode->GetSourceModelCount())
return;
VERUS_RT_ASSERT(NodeType::path == pBlockChainNode->GetParent()->GetType());
char buffer[IO::Stream::s_bufferSize] = {};
PPathNode pPathNode = static_cast<PPathNode>(pBlockChainNode->GetParent());
PControlPointNode pHeadNode = nullptr;
float fullLength = 0;
ForEachControlPointOf(pPathNode, false, [&fullLength, &pHeadNode](World::PControlPointNode pControlPointNode)
{
if (!pHeadNode && pControlPointNode->IsHeadControlPoint())
pHeadNode = pControlPointNode;
fullLength += pControlPointNode->GetSegmentLength();
return Continue::yes;
});
pBlockChainNode->ParseArguments();
float length = 0;
int slot = 0;
while (true)
{
const float slotLength = pBlockChainNode->GetLengthForSlot(slot++);
if (slotLength < VERUS_FLOAT_THRESHOLD)
break;
length += slotLength;
if (length >= fullLength)
break;
}
// Delete previously generated nodes:
CGI::Renderer::I()->WaitIdle();
bool nodeDeleted = false;
do
{
nodeDeleted = false;
for (auto pNode : _vNodes)
{
if (pNode->GetParent() == pBlockChainNode && (pNode->GetType() == NodeType::model || pNode->GetType() == NodeType::block))
{
DeleteNode(pNode);
nodeDeleted = true;
break;
}
}
} while (nodeDeleted);
_recursionDepth = 1; // Disable sorting.
const int slotCount = slot;
slot = 0;
const float scale = fullLength / length;
const float bankedTurn = pPathNode->GetDictionary().FindFloat("_BankedTurn");
float distOffset = 0;
while (slot < slotCount)
{
const float slotLength = pBlockChainNode->GetLengthForSlot(slot) * scale;
const float pivotOffset = distOffset + slotLength * 0.5f;
Point3 pivotPos;
pHeadNode->ComputePositionAt(pivotOffset, pivotPos);
ModelNodePtr modelNode = pBlockChainNode->GetModelNodeForSlot(slot);
if (modelNode)
{
RMesh mesh = modelNode->GetMesh();
BaseMesh::SourceBuffers sourceBuffers;
sourceBuffers._vIndices.resize(mesh.GetIndexCount());
sourceBuffers._vPos.resize(mesh.GetVertCount());
sourceBuffers._vTc0.resize(mesh.GetVertCount());
sourceBuffers._vNrm.resize(mesh.GetVertCount());
memcpy(sourceBuffers._vIndices.data(), mesh.GetIndices(), sourceBuffers._vIndices.size() * sizeof(UINT16));
mesh.ForEachVertex([&sourceBuffers, pHeadNode, fullLength, scale, pivotOffset, &pivotPos, bankedTurn](int index, RcPoint3 pos, RcVector3 nrm, RcPoint3 tc)
{
const float offsetFromPivot = pos.getZ() * scale;
Point3 posOnPath;
Vector3 pathDir;
pHeadNode->ComputePositionAt(pivotOffset + offsetFromPivot, posOnPath, &pathDir, true);
const Vector3 zAxis = pathDir;
Vector3 yAxis(0, 1, 0);
Vector3 xAxis = VMath::cross(yAxis, zAxis);
yAxis = VMath::cross(zAxis, xAxis);
if (bankedTurn > 0)
{
Point3 posOnPath2;
pHeadNode->ComputePositionAt(pivotOffset + offsetFromPivot + 5, posOnPath2, nullptr, true);
const Vector3 delta = VMath::normalize(posOnPath2 - posOnPath) - pathDir;
yAxis = VMath::normalize(yAxis + delta * bankedTurn);
xAxis = VMath::cross(yAxis, zAxis);
yAxis = VMath::cross(zAxis, xAxis);
}
const Matrix3 mat(xAxis, yAxis, zAxis);
const Point3 newPos = (posOnPath - pivotPos) + xAxis * pos.getX() + yAxis * pos.getY();
const Vector3 newNrm = mat * nrm;
sourceBuffers._vPos[index] = newPos.GLM();
sourceBuffers._vTc0[index] = tc.GLM2();
sourceBuffers._vNrm[index] = newNrm.GLM();
return Continue::yes;
});
BlockChainNode::PcSourceModel pSourceModel = pBlockChainNode->GetSourceModelForSlot(slot);
String url("[_GEN]:");
url += _C(pBlockChainNode->GetName());
url += "/";
url += std::to_string(slot);
ModelNode::Desc modelNodeDesc;
modelNodeDesc._url = _C(url);
modelNodeDesc._materialURL = _C(modelNode->GetMaterial()->_name);
ModelNodePtr genModelNode;
genModelNode.Init(modelNodeDesc);
genModelNode->SetGeneratedFlag();
genModelNode->SetParent(pBlockChainNode);
Mesh::Desc meshDesc;
meshDesc._instanceCapacity = 1000;
meshDesc._initShape = true;
genModelNode->GetMesh().Init(sourceBuffers, meshDesc);
BlockNode::Desc blockNodeDesc;
blockNodeDesc._modelURL = _C(url);
BlockNodePtr genBlockNode;
genBlockNode.Init(blockNodeDesc);
genBlockNode->SetGeneratedFlag();
genBlockNode->SetParent(pBlockChainNode);
genBlockNode->MoveTo(pivotPos + Vector3(pBlockChainNode->GetPosition(true)));
if (pSourceModel && pSourceModel->_noShadowCaster)
genBlockNode->SetShadowCasterFlag(false);
if (pSourceModel && !pSourceModel->_noPhysicsNode)
{
PhysicsNodePtr genPhysicsNode;
genPhysicsNode.Init(_C(genBlockNode->GetName()));
genPhysicsNode->SetGeneratedFlag();
genPhysicsNode->SetParent(genBlockNode.Get(), true);
}
sprintf_s(buffer, "%d", slot);
genBlockNode->GetDictionary().Insert("_BlockChainSlot", buffer);
}
slot++;
distOffset += slotLength;
}
_recursionDepth = 0; // Enable sorting.
SortNodes();
}
bool WorldManager::Connect2ControlPoints(PControlPointNode pNodeA, PControlPointNode pNodeB)
{
if (!pNodeA || !pNodeB)
@ -1000,6 +1152,7 @@ void WorldManager::UpdatePrefabInstances(PPrefabNode pPrefabNode, bool sortNodes
});
// Delete all nodes which are children of these instances:
CGI::Renderer::I()->WaitIdle();
bool nodeDeleted = false;
do
{
@ -1080,6 +1233,7 @@ void WorldManager::ReplaceSimilarWithInstances(PPrefabNode pPrefabNode)
}
const bool multiMode = (childCount >= 2);
CGI::Renderer::I()->WaitIdle();
bool nodeDeleted = false;
do
{
@ -1204,6 +1358,13 @@ PBlockNode WorldManager::InsertBlockNode()
return p;
}
PBlockChainNode WorldManager::InsertBlockChainNode()
{
auto p = TStoreBlockChainNodes::Insert();
_vNodes.push_back(p);
return p;
}
PControlPointNode WorldManager::InsertControlPointNode()
{
auto p = TStoreControlPointNodes::Insert();
@ -1385,6 +1546,7 @@ void WorldManager::Deserialize(IO::RStream stream)
case NodeType::model: InsertModelNode(_C(url))->Deserialize(stream); break;
case NodeType::particles: InsertParticlesNode(_C(url))->Deserialize(stream); break;
case NodeType::block: InsertBlockNode()->Deserialize(stream); break;
case NodeType::blockChain: InsertBlockChainNode()->Deserialize(stream); break;
case NodeType::controlPoint: InsertControlPointNode()->Deserialize(stream); break;
case NodeType::emitter: InsertEmitterNode()->Deserialize(stream); break;
case NodeType::instance: InsertInstanceNode()->Deserialize(stream); break;
@ -1403,7 +1565,6 @@ void WorldManager::Deserialize(IO::RStream stream)
for (auto pNode : _vNodes)
pNode->OnAllNodesDeserialized();
for (auto& prefabNode : TStorePrefabNodes::_list)
UpdatePrefabInstances(&prefabNode, false);
SortNodes();
@ -1486,6 +1647,7 @@ UINT32 WorldManager::NodeTypeToHash(NodeType type)
case NodeType::model: return 'EDOM';
case NodeType::particles: return 'TRAP';
case NodeType::block: return 'COLB';
case NodeType::blockChain: return 'HCLB';
case NodeType::controlPoint: return 'TNOC';
case NodeType::emitter: return 'TIME';
case NodeType::instance: return 'TSNI';
@ -1509,6 +1671,7 @@ NodeType WorldManager::HashToNodeType(UINT32 hash)
case 'EDOM': return NodeType::model;
case 'TRAP': return NodeType::particles;
case 'COLB': return NodeType::block;
case 'HCLB': return NodeType::blockChain;
case 'TNOC': return NodeType::controlPoint;
case 'TIME': return NodeType::emitter;
case 'TSNI': return NodeType::instance;
@ -1546,9 +1709,9 @@ UINT32 WorldManager::NodeTypeToColor(NodeType type, int alpha)
VERUS_COLOR_RGBA(255, 128, 255, alpha), // 11, prefab
VERUS_COLOR_RGBA(255, 255, 128, alpha), // 12, terrain
VERUS_COLOR_RGBA(255, 128, 000, alpha), // 13, sound
VERUS_COLOR_RGBA(000, 255, 128, alpha), // 14, shaker
VERUS_COLOR_RGBA(128, 000, 255, alpha), // 15
VERUS_COLOR_RGBA(255, 171, 85, alpha), // 13, sound
VERUS_COLOR_RGBA(85, 255, 171, alpha), // 14, shaker
VERUS_COLOR_RGBA(171, 85, 255, alpha), // 15, blockChain
};
switch (type)
@ -1557,6 +1720,7 @@ UINT32 WorldManager::NodeTypeToColor(NodeType type, int alpha)
case NodeType::model: return colors[8];
case NodeType::particles: return colors[7];
case NodeType::block: return colors[2];
case NodeType::blockChain: return colors[15];
case NodeType::controlPoint: return colors[4];
case NodeType::emitter: return colors[1];
case NodeType::instance: return colors[5];

View File

@ -14,6 +14,7 @@ namespace verus
typedef StoreUnique<String, ParticlesNode> TStoreParticlesNodes;
typedef Store<BaseNode> TStoreBaseNodes;
typedef Store<BlockNode> TStoreBlockNodes;
typedef Store<BlockChainNode> TStoreBlockChainNodes;
typedef Store<ControlPointNode> TStoreControlPointNodes;
typedef Store<EmitterNode> TStoreEmitterNodes;
typedef Store<InstanceNode> TStoreInstanceNodes;
@ -26,10 +27,11 @@ namespace verus
typedef Store<TerrainNode> TStoreTerrainNodes;
class WorldManager : public Singleton<WorldManager>, public Object, public Math::OctreeDelegate,
private TStoreModelNodes, private TStoreParticlesNodes,
private TStoreBaseNodes, private TStoreBlockNodes, private TStoreControlPointNodes,
private TStoreEmitterNodes, private TStoreInstanceNodes, private TStoreLightNodes,
private TStorePathNodes, private TStorePhysicsNodes, private TStorePrefabNodes,
private TStoreShakerNodes, private TStoreSoundNodes, private TStoreTerrainNodes
private TStoreBaseNodes, private TStoreBlockNodes, private TStoreBlockChainNodes,
private TStoreControlPointNodes, private TStoreEmitterNodes, private TStoreInstanceNodes,
private TStoreLightNodes, private TStorePathNodes, private TStorePhysicsNodes,
private TStorePrefabNodes, private TStoreShakerNodes, private TStoreSoundNodes,
private TStoreTerrainNodes
{
Math::Octree _octree;
LocalPtr<btBoxShape> _pPickingShape;
@ -79,6 +81,7 @@ namespace verus
void Update();
void UpdateParts();
void Layout();
void SortVisible();
void Draw();
void DrawSimple(DrawSimpleMode mode);
void DrawTerrainNodes(Terrain::RcDrawDesc dd);
@ -209,6 +212,20 @@ namespace verus
}
}
if (NodeType::unknown == query._type || NodeType::blockChain == query._type)
{
VERUS_FOREACH_X(TStoreBlockChainNodes::TList, TStoreBlockChainNodes::_list, it)
{
auto& blockChain = *it++;
if (
MatchName(blockChain) &&
MatchSelected(blockChain) &&
MatchParent(blockChain))
if (Continue::no == fn(blockChain))
return;
}
}
if (NodeType::unknown == query._type || NodeType::controlPoint == query._type)
{
VERUS_FOREACH_X(TStoreControlPointNodes::TList, TStoreControlPointNodes::_list, it)
@ -354,20 +371,20 @@ namespace verus
template<typename T>
void ForEachControlPointOf(PPathNode pPathNode, bool onlyHeads, const T& fn)
{
const int nodeIndex = GetIndexOf(pPathNode);
const int nodeDepth = pPathNode->GetDepth();
const int nodeCount = GetNodeCount();
for (int i = nodeIndex + 1; i < nodeCount; ++i)
for (int i = GetIndexOf(pPathNode) + 1; i < nodeCount; ++i)
{
PBaseNode pNode = _vNodes[i];
if (pNode->GetDepth() <= nodeDepth)
if (pNode->GetDepth() <= pPathNode->GetDepth())
break;
PControlPointNode pControlPointNode = static_cast<PControlPointNode>(pNode);
if (!onlyHeads || pControlPointNode->IsHeadControlPoint())
if (NodeType::controlPoint == pNode->GetType())
{
if (Continue::no == fn(pControlPointNode))
return;
PControlPointNode pControlPointNode = static_cast<PControlPointNode>(pNode);
if (!onlyHeads || pControlPointNode->IsHeadControlPoint())
{
if (Continue::no == fn(pControlPointNode))
return;
}
}
}
}
@ -405,8 +422,8 @@ namespace verus
void ResetRigidBodyTransforms();
void GenerateBlockChainNodes(PBlockChainNode pBlockChainNode);
static bool Connect2ControlPoints(PControlPointNode pNodeA, PControlPointNode pNodeB);
void UpdatePrefabInstances(PPrefabNode pPrefabNode, bool sortNodes = true);
void ReplaceSimilarWithInstances(PPrefabNode pPrefabNode);
// </NodeOperations>
@ -421,6 +438,8 @@ namespace verus
PBlockNode InsertBlockNode();
PBlockChainNode InsertBlockChainNode();
PControlPointNode InsertControlPointNode();
PEmitterNode InsertEmitterNode();

View File

@ -31,6 +31,8 @@ void BaseNode::Init(RcDesc desc)
OnLocalTransformUpdated();
UpdateGlobalTransform();
AddDefaultPickingBody(); // Can be overridden by nodes that don't need this rigid body.
_flags &= ~Flags::readOnlyFlags;
}
void BaseNode::Done()
@ -41,7 +43,7 @@ void BaseNode::Done()
VERUS_DONE(BaseNode);
}
void BaseNode::Duplicate(RBaseNode node)
void BaseNode::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
_trLocal = node._trLocal;
_trGlobal = node._trGlobal;
@ -52,7 +54,7 @@ void BaseNode::Duplicate(RBaseNode node)
_pParent = node._pParent;
_name = node._name;
_type = node._type;
_flags = node._flags;
_flags = node._flags | Flags::readOnlyFlags;
_groups = node._groups;
_depth = node._depth;
@ -109,6 +111,7 @@ void BaseNode::GetEditorCommands(Vector<EditorCommand>& v)
v.push_back(EditorCommand(nullptr, EditorCommandCode::node_resetLocalTransform));
v.push_back(EditorCommand(nullptr, EditorCommandCode::node_resetLocalTransformKeepGlobal));
v.push_back(EditorCommand(nullptr, EditorCommandCode::node_pointAt));
v.push_back(EditorCommand(nullptr, EditorCommandCode::node_moveTo));
}
void BaseNode::ExecuteEditorCommand(RcEditorCommand command)
@ -140,6 +143,11 @@ void BaseNode::ExecuteEditorCommand(RcEditorCommand command)
}
}
bool BaseNode::CanAutoSelectParentNode() const
{
return _pParent && NodeType::instance == _pParent->GetType();
}
void BaseNode::Rename(CSZ name)
{
if (_name == name)
@ -275,6 +283,19 @@ void BaseNode::Select(bool select)
VERUS_BITMASK_UNSET(_flags, Flags::selected);
}
bool BaseNode::IsShadowCaster() const
{
return !!(_flags & Flags::shadowCaster);
}
void BaseNode::SetShadowCasterFlag(bool shadowCaster)
{
if (shadowCaster)
VERUS_BITMASK_SET(_flags, Flags::shadowCaster);
else
VERUS_BITMASK_UNSET(_flags, Flags::shadowCaster);
}
bool BaseNode::IsInGroup(int index) const
{
return !!((_groups >> index) & 0x1);
@ -573,7 +594,7 @@ void BaseNode::Serialize(IO::RSeekableStream stream)
_dict.Serialize(stream);
stream << wm.GetIndexOf(_pParent, true);
stream.WriteString(_C(_name));
stream << (_flags & ~Flags::selected);
stream << (_flags & Flags::serializedMask);
stream << _groups;
}
@ -600,6 +621,7 @@ void BaseNode::Deserialize(IO::RStream stream)
_uiScale = uiScale;
_pParent = wm.GetNodeByIndex(parentIndex);
_name = name;
_flags |= Flags::readOnlyFlags;
UpdateDepth();
@ -699,7 +721,7 @@ void BaseNode::SerializeXML(pugi::xml_node node)
node.append_attribute("uiS") = _C(_uiScale.ToString(true));
node.append_attribute("parent") = wm.GetIndexOf(_pParent, true);
node.append_attribute("name") = _C(_name);
node.append_attribute("flags") = (_flags & ~Flags::selected);
node.append_attribute("flags") = (_flags & Flags::serializedMask);
node.append_attribute("groups") = _groups;
}
@ -749,12 +771,12 @@ void BaseNodePtr::Init(BaseNode::RcDesc desc)
_p->Init(desc);
}
void BaseNodePtr::Duplicate(RBaseNode node)
void BaseNodePtr::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
VERUS_QREF_WM;
VERUS_RT_ASSERT(!_p);
_p = wm.InsertBaseNode();
_p->Duplicate(node);
_p->Duplicate(node, hierarchyDuplication);
}
void BaseNodePwn::Done()

View File

@ -22,7 +22,11 @@ namespace verus
dynamic = (1 << 2), // Will be bound to the root of octree.
generated = (1 << 3), // Created by some other node.
disabled = (1 << 4), // Draw method will not be called.
selected = (1 << 5)
selected = (1 << 5),
shadowCaster = (1 << 6),
readOnlyFlags = (1u << 31),
serializedMask = ~(octreeBindOnce | generated | selected)
};
Transform3 _trLocal = Transform3::identity();
@ -56,7 +60,7 @@ namespace verus
void Init(RcDesc desc);
void Done();
virtual void Duplicate(BaseNode& node);
virtual void Duplicate(BaseNode& node, HierarchyDuplication hierarchyDuplication);
virtual void Update() {}
virtual void Layout() {}
@ -68,7 +72,7 @@ namespace verus
// <Editor>
virtual void GetEditorCommands(Vector<EditorCommand>& v);
virtual void ExecuteEditorCommand(RcEditorCommand command);
virtual bool CanAutoSelectParentNode() const { return false; }
virtual bool CanAutoSelectParentNode() const;
// </Editor>
// <Identity>
@ -104,6 +108,9 @@ namespace verus
bool IsSelected() const;
void Select(bool select = true);
bool IsShadowCaster() const;
void SetShadowCasterFlag(bool shadowCaster = true);
// </Flags>
// <Groups>
@ -174,7 +181,7 @@ namespace verus
{
public:
void Init(BaseNode::RcDesc desc);
void Duplicate(RBaseNode node);
void Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication);
};
VERUS_TYPEDEFS(BaseNodePtr);

View File

@ -0,0 +1,286 @@
// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "verus.h"
using namespace verus;
using namespace verus::World;
// BlockChainNode::SourceModel:
bool BlockChainNode::SourceModel::IsAssignedToSlot(int slot) const
{
for (const auto& x : _vSlots)
{
if (x.Includes(slot))
return true;
}
return false;
}
// BlockChainNode:
BlockChainNode::BlockChainNode()
{
_type = NodeType::blockChain;
}
BlockChainNode::~BlockChainNode()
{
Done();
}
void BlockChainNode::Init(RcDesc desc)
{
_pParent = desc._pPathNode;
UpdateDepth();
String name;
if (!desc._name)
name = String("Bc") + _C(desc._pPathNode->GetName());
BaseNode::Init(desc._name ? desc._name : _C(name));
_vSourceModels.reserve(8);
}
void BlockChainNode::Done()
{
VERUS_DONE(BlockChainNode);
}
void BlockChainNode::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
BaseNode::Duplicate(node, hierarchyDuplication);
RBlockChainNode blockChainNode = static_cast<RBlockChainNode>(node);
if (NodeType::block == _type)
{
Desc desc;
desc._name = _C(_name);
Init(desc);
}
}
void BlockChainNode::Update()
{
if (!_async_generatedNodes)
{
bool allLoaded = true;
for (const auto& x : _vSourceModels)
{
if (x._modelNode && !x._modelNode->GetMesh().IsLoaded())
{
allLoaded = false;
break;
}
}
if (allLoaded)
{
VERUS_QREF_WM;
wm.GenerateBlockChainNodes(this);
_async_generatedNodes = true;
}
}
}
void BlockChainNode::GetEditorCommands(Vector<EditorCommand>& v)
{
BaseNode::GetEditorCommands(v);
v.push_back(EditorCommand(nullptr, EditorCommandCode::separator));
v.push_back(EditorCommand(nullptr, EditorCommandCode::blockChain_generateNodes));
}
void BlockChainNode::ExecuteEditorCommand(RcEditorCommand command)
{
BaseNode::ExecuteEditorCommand(command);
switch (command._code)
{
case EditorCommandCode::blockChain_generateNodes:
{
_async_generatedNodes = false;
}
break;
}
}
bool BlockChainNode::CanSetParent(PBaseNode pNode) const
{
return false;
}
void BlockChainNode::OnNodeDeleted(PBaseNode pNode, bool afterEvent, bool hierarchy)
{
BaseNode::OnNodeDeleted(pNode, afterEvent, hierarchy);
if (!afterEvent && pNode->GetType() == NodeType::model)
UnbindSourceModel(static_cast<PModelNode>(pNode));
}
void BlockChainNode::Serialize(IO::RSeekableStream stream)
{
BaseNode::Serialize(stream);
VERUS_QREF_WM;
stream << GetSourceModelCount();
for (const auto& x : _vSourceModels)
{
stream << wm.GetIndexOf(x._modelNode.Get(), true);
stream << x._length;
stream.WriteString(_C(x._arguments));
}
}
void BlockChainNode::Deserialize(IO::RStream stream)
{
BaseNode::Deserialize(stream);
VERUS_QREF_WM;
int sourceModelCount;
stream >> sourceModelCount;
VERUS_FOR(i, sourceModelCount)
{
SourceModel sourceModel;
int modelIndex = -1;
stream >> modelIndex;
sourceModel._modelNode.Attach(static_cast<PModelNode>(wm.GetNodeByIndex(modelIndex)));
stream >> sourceModel._length;
char arguments[IO::Stream::s_bufferSize] = {};
stream.ReadString(arguments);
sourceModel._arguments = arguments;
_vSourceModels.push_back(std::move(sourceModel));
}
if (NodeType::blockChain == _type)
{
Desc desc;
desc._name = _C(_name);
desc._pPathNode = GetParent();
Init(desc);
}
}
bool BlockChainNode::BindSourceModel(PModelNode pModelNode)
{
for (const auto& x : _vSourceModels)
{
if (x._modelNode == pModelNode)
return false;
}
SourceModel sourceModel;
sourceModel._modelNode.Attach(pModelNode);
sourceModel._length = pModelNode ? pModelNode->GetMesh().GetBounds().GetDimensions().getZ() : 1.f;
_vSourceModels.push_back(std::move(sourceModel));
return true;
}
bool BlockChainNode::UnbindSourceModel(PModelNode pModelNode)
{
return _vSourceModels.end() != _vSourceModels.erase(std::remove_if(_vSourceModels.begin(), _vSourceModels.end(),
[pModelNode](RSourceModel sourceModel)
{
return sourceModel._modelNode == pModelNode;
}), _vSourceModels.end());
}
int BlockChainNode::GetSourceModelCount() const
{
return Utils::Cast32(_vSourceModels.size());
}
BlockChainNode::PcSourceModel BlockChainNode::GetSourceModelForSlot(int slot) const
{
if (_vSourceModels.empty())
return nullptr;
for (int i = 1; i < _vSourceModels.size(); ++i)
{
if (_vSourceModels[i].IsAssignedToSlot(slot))
return &_vSourceModels[i];
}
return &_vSourceModels[0];
}
ModelNodePtr BlockChainNode::GetModelNodeForSlot(int slot) const
{
if (_vSourceModels.empty())
return ModelNodePtr();
for (int i = 1; i < _vSourceModels.size(); ++i)
{
if (_vSourceModels[i].IsAssignedToSlot(slot))
return _vSourceModels[i]._modelNode;
}
return _vSourceModels[0]._modelNode;
}
float BlockChainNode::GetLengthForSlot(int slot) const
{
if (_vSourceModels.empty())
return 0;
for (int i = 1; i < _vSourceModels.size(); ++i)
{
if (_vSourceModels[i].IsAssignedToSlot(slot))
return _vSourceModels[i]._length;
}
return _vSourceModels[0]._length;
}
void BlockChainNode::ParseArguments()
{
for (auto& x : _vSourceModels)
{
x._vSlots.clear();
x._noPhysicsNode = false;
x._noShadowCaster = false;
Vector<String> vArgs;
Str::Explode(_C(x._arguments), ",", vArgs);
for (const auto& arg : vArgs)
{
if (isdigit(arg[0]))
{
const size_t dash = arg.find('-');
if (dash != String::npos)
x._vSlots.push_back(Range(atoi(_C(arg)), atoi(_C(arg) + dash + 1) + 1));
else
x._vSlots.push_back(Range(atoi(_C(arg))));
}
else if (arg == "-nophy")
{
x._noPhysicsNode = true;
}
else if (arg == "-nosc")
{
x._noShadowCaster = true;
}
}
}
}
// BlockChainNodePtr:
void BlockChainNodePtr::Init(BlockChainNode::RcDesc desc)
{
VERUS_QREF_WM;
VERUS_RT_ASSERT(!_p);
_p = wm.InsertBlockChainNode();
_p->Init(desc);
}
void BlockChainNodePtr::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
VERUS_QREF_WM;
VERUS_RT_ASSERT(!_p);
_p = wm.InsertBlockChainNode();
_p->Duplicate(node, hierarchyDuplication);
}
void BlockChainNodePwn::Done()
{
if (_p)
{
WorldManager::I().DeleteNode(_p);
_p = nullptr;
}
}

View File

@ -0,0 +1,92 @@
// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#pragma once
namespace verus
{
namespace World
{
class BlockChainNode : public BaseNode
{
public:
struct SourceModel
{
Vector<Range> _vSlots;
ModelNodePtr _modelNode;
String _arguments;
float _length = 0;
bool _noPhysicsNode = false;
bool _noShadowCaster = false;
bool IsAssignedToSlot(int slot) const;
};
VERUS_TYPEDEFS(SourceModel);
private:
Vector<SourceModel> _vSourceModels;
bool _async_generatedNodes = false;
public:
struct Desc : BaseNode::Desc
{
PBaseNode _pPathNode = nullptr;
Desc(PBaseNode pPathNode = nullptr) : _pPathNode(pPathNode) {}
};
VERUS_TYPEDEFS(Desc);
BlockChainNode();
virtual ~BlockChainNode();
void Init(RcDesc desc);
void Done();
virtual void Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication) override;
virtual void Update() override;
virtual void GetEditorCommands(Vector<EditorCommand>& v) override;
virtual void ExecuteEditorCommand(RcEditorCommand command) override;
virtual bool CanSetParent(PBaseNode pNode) const override;
virtual void OnNodeDeleted(PBaseNode pNode, bool afterEvent, bool hierarchy) override;
virtual void Serialize(IO::RSeekableStream stream) override;
virtual void Deserialize(IO::RStream stream) override;
bool BindSourceModel(PModelNode pModelNode);
bool UnbindSourceModel(PModelNode pModelNode);
int GetSourceModelCount() const;
PcSourceModel GetSourceModelForSlot(int slot) const;
ModelNodePtr GetModelNodeForSlot(int slot) const;
template<typename T>
void ForEachSourceModel(const T& fn)
{
for (auto& x : _vSourceModels)
fn(x);
}
float GetLengthForSlot(int slot) const;
void ParseArguments();
};
VERUS_TYPEDEFS(BlockChainNode);
class BlockChainNodePtr : public Ptr<BlockChainNode>
{
public:
void Init(BlockChainNode::RcDesc desc);
void Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication);
};
VERUS_TYPEDEFS(BlockChainNodePtr);
class BlockChainNodePwn : public BlockChainNodePtr
{
public:
~BlockChainNodePwn() { Done(); }
void Done();
};
VERUS_TYPEDEFS(BlockChainNodePwn);
}
}

View File

@ -18,8 +18,13 @@ BlockNode::~BlockNode()
void BlockNode::Init(RcDesc desc)
{
SetOctreeElementFlag();
if (!(_flags & Flags::readOnlyFlags))
{
SetOctreeElementFlag();
SetShadowCasterFlag();
}
BaseNode::Init(desc._name ? desc._name : desc._modelURL);
SetShadowCasterFlag();
ModelNode::Desc modelDesc;
modelDesc._url = desc._modelURL;
@ -38,9 +43,9 @@ void BlockNode::Done()
VERUS_DONE(BlockNode);
}
void BlockNode::Duplicate(RBaseNode node)
void BlockNode::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
BaseNode::Duplicate(node);
BaseNode::Duplicate(node, hierarchyDuplication);
RBlockNode blockNode = static_cast<RBlockNode>(node);
@ -219,12 +224,12 @@ void BlockNodePtr::Init(BlockNode::RcDesc desc)
_p->Init(desc);
}
void BlockNodePtr::Duplicate(RBaseNode node)
void BlockNodePtr::Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication)
{
VERUS_QREF_WM;
VERUS_RT_ASSERT(!_p);
_p = wm.InsertBlockNode();
_p->Duplicate(node);
_p->Duplicate(node, hierarchyDuplication);
}
void BlockNodePwn::Done()

View File

@ -32,7 +32,7 @@ namespace verus
void Init(RcDesc desc);
void Done();
virtual void Duplicate(RBaseNode node) override;
virtual void Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication) override;
virtual void Update() override;
@ -64,7 +64,7 @@ namespace verus
{
public:
void Init(BlockNode::RcDesc desc);
void Duplicate(RBaseNode node);
void Duplicate(RBaseNode node, HierarchyDuplication hierarchyDuplication);
};
VERUS_TYPEDEFS(BlockNodePtr);

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