From e760e5cc9739d8037fdf96647e2f1ba4162773e3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Mar 2025 13:23:08 +0100 Subject: [PATCH 1/7] Fix particle sim shader compilation warning on Vulkan #https://github.com/KhronosGroup/glslang/issues/2066 --- Content/Editor/MaterialTemplates/GPUParticles.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content/Editor/MaterialTemplates/GPUParticles.shader b/Content/Editor/MaterialTemplates/GPUParticles.shader index 678eef099..5900743e3 100644 --- a/Content/Editor/MaterialTemplates/GPUParticles.shader +++ b/Content/Editor/MaterialTemplates/GPUParticles.shader @@ -140,7 +140,7 @@ void SetParticleVec4(uint particleIndex, int offset, float4 value) bool AddParticle(out uint dstIndex) { // Acquire the particle index in the destination buffer - DstParticlesData.InterlockedAdd(ParticleCounterOffset, 1, dstIndex); + DstParticlesData.InterlockedAdd(ParticleCounterOffset, 1u, dstIndex); // Prevent overflow return dstIndex >= PARTICLE_CAPACITY; From 679d56d7a396b800164fb16463697bafccfad457 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Mar 2025 13:31:01 +0100 Subject: [PATCH 2/7] Fix regression error on duplicated scene objects in registry --- Source/Engine/Content/Content.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp index 98cb1a737..e7c4f399c 100644 --- a/Source/Engine/Content/Content.cpp +++ b/Source/Engine/Content/Content.cpp @@ -1042,7 +1042,8 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type) LOAD_FAILED(); } #endif - result->RegisterObject(); + if (!result->IsInternalType()) + result->RegisterObject(); // Register asset AssetsLocker.Lock(); From fef967d4a0b9cc064f0cb78c0970f5d89edfba8d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Mar 2025 14:28:47 +0100 Subject: [PATCH 3/7] Fix crash on Vulkan when binding dummy buffer as missing uniform buffer #3000 --- .../GraphicsDevice/Vulkan/GPUContextVulkan.cpp | 11 +++-------- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 14 ++++++++++---- .../Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h | 6 ++++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index c363bed45..ff7eeb148 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -557,14 +557,9 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des VkBuffer buffer = VK_NULL_HANDLE; VkDeviceSize offset = 0, range = 0; uint32 dynamicOffset = 0; - if (handle) - handle->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset); - else - { - const auto dummy = _device->HelperResources.GetDummyBuffer(); - buffer = dummy->GetHandle(); - range = dummy->GetSize(); - } + if (!handle) + handle = (GPUConstantBufferVulkan*)_device->HelperResources.GetDummyConstantBuffer(); + handle->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset); needsWrite |= dsWriter.WriteDynamicUniformBuffer(descriptorIndex, buffer, offset, range, dynamicOffset, index); break; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 9b6d4ba2c..35c5ec519 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -749,8 +749,6 @@ bool BufferedQueryPoolVulkan::HasRoom() const HelperResourcesVulkan::HelperResourcesVulkan(GPUDeviceVulkan* device) : _device(device) - , _dummyBuffer(nullptr) - , _dummyVB(nullptr) { Platform::MemoryClear(_dummyTextures, sizeof(_dummyTextures)); Platform::MemoryClear(_staticSamplers, sizeof(_staticSamplers)); @@ -883,7 +881,6 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyBuffer() _dummyBuffer = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyBuffer")); _dummyBuffer->Init(GPUBufferDescription::Buffer(sizeof(int32) * 256, GPUBufferFlags::ShaderResource | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_SInt)); } - return _dummyBuffer; } @@ -894,15 +891,24 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyVertexBuffer() _dummyVB = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyVertexBuffer")); _dummyVB->Init(GPUBufferDescription::Vertex(sizeof(Color32), 1, &Color32::Transparent)); } - return _dummyVB; } +GPUConstantBuffer* HelperResourcesVulkan::GetDummyConstantBuffer() +{ + if (!_dummyCB) + { + _dummyCB = _device->CreateConstantBuffer(256, TEXT("DummyConstantBuffer")); + } + return _dummyCB; +} + void HelperResourcesVulkan::Dispose() { SAFE_DELETE_GPU_RESOURCES(_dummyTextures); SAFE_DELETE_GPU_RESOURCE(_dummyBuffer); SAFE_DELETE_GPU_RESOURCE(_dummyVB); + SAFE_DELETE_GPU_RESOURCE(_dummyCB); for (int32 i = 0; i < ARRAY_COUNT(_staticSamplers); i++) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index e24bf449c..3dd04014b 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -308,8 +308,9 @@ class HelperResourcesVulkan private: GPUDeviceVulkan* _device; GPUTextureVulkan* _dummyTextures[6]; - GPUBufferVulkan* _dummyBuffer; - GPUBufferVulkan* _dummyVB; + GPUBufferVulkan* _dummyBuffer = nullptr; + GPUBufferVulkan* _dummyVB = nullptr; + GPUConstantBuffer* _dummyCB = nullptr; VkSampler _staticSamplers[GPU_STATIC_SAMPLERS_COUNT]; public: @@ -320,6 +321,7 @@ public: GPUTextureVulkan* GetDummyTexture(SpirvShaderResourceType type); GPUBufferVulkan* GetDummyBuffer(); GPUBufferVulkan* GetDummyVertexBuffer(); + GPUConstantBuffer* GetDummyConstantBuffer(); void Dispose(); }; From 7d79dbac409724ed4afd3cc0b867b61d846b4b72 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Mar 2025 14:29:17 +0100 Subject: [PATCH 4/7] Fix shadows sampling error in shader due to incorrect sampler used #3000 --- Source/Shaders/ShadowsSampling.hlsl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index 393234fc4..c2b67301e 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -11,11 +11,13 @@ #endif #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 -#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) shadowMap.SampleCmpLevelZero(ShadowSamplerLinear, shadowUV, sceneDepth) -#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) shadowMap.SampleCmpLevelZero(ShadowSamplerLinear, shadowUV, sceneDepth, texelOffset) +#define SAMPLE_SHADOW_SAMPLER ShadowSamplerLinear +#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) shadowMap.SampleCmpLevelZero(SAMPLE_SHADOW_SAMPLER, shadowUV, sceneDepth) +#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) shadowMap.SampleCmpLevelZero(SAMPLE_SHADOW_SAMPLER, shadowUV, sceneDepth, texelOffset) #else -#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SamplerLinearClamp, shadowUV, 0).r) -#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SamplerLinearClamp, shadowUV, 0, texelOffset).r) +#define SAMPLE_SHADOW_SAMPLER SamplerLinearClamp +#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowUV, 0).r) +#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowUV, 0, texelOffset).r) #endif float4 GetShadowMask(ShadowSample shadow) @@ -276,7 +278,7 @@ ShadowSample SampleDirectionalLightShadow(LightData light, Buffer shadow { float opacity = gBuffer.CustomData.a; shadowMapUV = GetLightShadowAtlasUV(shadow, shadowTile, gBuffer.WorldPos, shadowPosition); - float shadowMapDepth = shadowMap.SampleLevel(SamplerLinearClamp, shadowMapUV, 0).r; + float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowMapUV, 0).r; result.TransmissionShadow = CalculateSubsurfaceOcclusion(opacity, shadowPosition.z, shadowMapDepth); result.TransmissionShadow = PostProcessShadow(shadow, result.TransmissionShadow); } @@ -337,7 +339,7 @@ ShadowSample SampleLocalLightShadow(LightData light, Buffer shadowsBuffe { float opacity = gBuffer.CustomData.a; shadowMapUV = GetLightShadowAtlasUV(shadow, shadowTile, gBuffer.WorldPos, shadowPosition); - float shadowMapDepth = shadowMap.SampleLevel(SamplerLinearClamp, shadowMapUV, 0).r; + float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowMapUV, 0).r; result.TransmissionShadow = CalculateSubsurfaceOcclusion(opacity, shadowPosition.z, shadowMapDepth); result.TransmissionShadow = PostProcessShadow(shadow, result.TransmissionShadow); } From 8a52fa257b53e3cf58ba5ea44e525d7e1cc9458a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 8 Mar 2025 14:29:36 +0100 Subject: [PATCH 5/7] Add logging draw event into in Vulkan error --- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 35c5ec519..0e3103a0f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -231,6 +231,19 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever LOG(Info, "[Vulkan] {0} {1}:{2}({3}) {4}", type, severity, callbackData->messageIdNumber, String(callbackData->pMessageIdName), message); else LOG(Info, "[Vulkan] {0} {1}:{2} {3}", type, severity, callbackData->messageIdNumber, message); + +#if BUILD_DEBUG + if (auto* context = (GPUContextVulkan*)GPUDevice::Instance->GetMainContext()) + { + if (auto* state = (GPUPipelineStateVulkan*)context->GetState()) + { + const StringAnsi vsName = state->DebugDesc.VS ? state->DebugDesc.VS->GetName() : StringAnsi::Empty; + const StringAnsi psName = state->DebugDesc.PS ? state->DebugDesc.PS->GetName() : StringAnsi::Empty; + LOG(Warning, "[Vulkan] Error during rendering with VS={}, PS={}", String(vsName), String(psName)); + } + } +#endif + return VK_FALSE; } From 34dcbc0445269a6fb8377842714b9ed9fd09ecf7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 29 Oct 2024 23:55:42 +0100 Subject: [PATCH 6/7] Add `Vector3.SignedAngle` utility method Merge 072f7c7e45757f011ebd6936e4b2e01d9833abfe and c1bd42ff7eb71824683bb8ba63f0c9173281bb4d --- Source/Engine/Core/Math/Vector3.cpp | 32 +++++++++++++++++++++++++---- Source/Engine/Core/Math/Vector3.cs | 17 ++++++++++++++- Source/Engine/Core/Math/Vector3.h | 13 ++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp index 5a26f2309..d11df8f6d 100644 --- a/Source/Engine/Core/Math/Vector3.cpp +++ b/Source/Engine/Core/Math/Vector3.cpp @@ -320,8 +320,17 @@ float Float3::Angle(const Float3& from, const Float3& to) { const float dot = Math::Clamp(Dot(Normalize(from), Normalize(to)), -1.0f, 1.0f); if (Math::Abs(dot) > 1.0f - ZeroTolerance) - return dot > 0.0f ? 0.0f : PI; - return Math::Acos(dot); + return dot > 0.0f ? 0.0f : 180.0f; + return Math::Acos(dot) * RadiansToDegrees; +} + +template<> +float Float3::SignedAngle(const Float3& from, const Float3& to, const Float3& axis) +{ + const float angle = Angle(from, to); + const Float3 cross = Cross(from, to); + const float sign = Math::Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; } template<> @@ -648,8 +657,17 @@ double Double3::Angle(const Double3& from, const Double3& to) { const double dot = Math::Clamp(Dot(Normalize(from), Normalize(to)), -1.0, 1.0); if (Math::Abs(dot) > 1.0 - ZeroTolerance) - return dot > 0.0 ? 0.0 : PI; - return Math::Acos(dot); + return dot > 0.0 ? 0.0 : 180.0; + return Math::Acos(dot) * RadiansToDegrees; +} + +template<> +double Double3::SignedAngle(const Double3& from, const Double3& to, const Double3& axis) +{ + const double angle = Angle(from, to); + const Double3 cross = Cross(from, to); + const double sign = Math::Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; } template<> @@ -881,6 +899,12 @@ int32 Int3::Angle(const Int3& from, const Int3& to) return 0; } +template<> +int32 Int3::SignedAngle(const Int3& from, const Int3& to, const Int3& axis) +{ + return 0; +} + template<> Int3 Int3::SnapToGrid(const Int3& pos, const Int3& gridSize) { diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs index 61d0e51f0..360057f5d 100644 --- a/Source/Engine/Core/Math/Vector3.cs +++ b/Source/Engine/Core/Math/Vector3.cs @@ -1345,7 +1345,7 @@ namespace FlaxEngine } /// - /// Calculates the angle (in degrees) between and . This is always the smallest value. + /// Calculates the angle (in degrees) between and vectors. This is always the smallest value. /// /// The first vector. /// The second vector. @@ -1358,6 +1358,21 @@ namespace FlaxEngine return (Real)Math.Acos(dot) * Mathr.RadiansToDegrees; } + /// + /// Calculates the signed angle (in degrees) between and vectors. This is always the smallest value. The sign of the result depends on: the order of input vectors, and the direction of the vector. + /// + /// The first vector. + /// The second vector. + /// The axis around which the vectors are rotated. + /// The angle (in degrees). + public static Real SignedAngle(Vector3 from, Vector3 to, Vector3 axis) + { + Real angle = Angle(from, to); + Vector3 cross = Cross(from, to); + Real sign = Mathr.Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; + } + /// /// Projects a 3D vector from object space into screen space. /// diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h index 67f8e7d44..10271dece 100644 --- a/Source/Engine/Core/Math/Vector3.h +++ b/Source/Engine/Core/Math/Vector3.h @@ -812,13 +812,22 @@ public: static FLAXENGINE_API T TriangleArea(const Vector3Base& v0, const Vector3Base& v1, const Vector3Base& v2); /// - /// Calculates the angle (in radians) between from and to. This is always the smallest value. + /// Calculates the angle (in degrees) between from and to. This is always the smallest value. /// /// The first vector. /// The second vector. - /// The angle (in radians). + /// The angle (in degrees). static FLAXENGINE_API T Angle(const Vector3Base& from, const Vector3Base& to); + /// + /// Calculates the signed angle (in degrees) between from and to vectors. This is always the smallest value. The sign of the result depends on: the order of input vectors, and the direction of the axis vector. + /// + /// The first vector. + /// The second vector. + /// The axis around which the vectors are rotated. + /// The angle (in degrees). + static FLAXENGINE_API T SignedAngle(const Vector3Base& from, const Vector3Base& to, const Vector3Base& axis); + /// /// Snaps the input position onto the grid. /// From a93085d6d659c215e611eb2ec43261df94db8875 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 9 Mar 2025 09:15:49 +0100 Subject: [PATCH 7/7] Redo 7d79dbac409724ed4afd3cc0b867b61d846b4b72 --- Source/Shaders/ShadowsSampling.hlsl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index c2b67301e..598a22748 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -11,13 +11,16 @@ #endif #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 -#define SAMPLE_SHADOW_SAMPLER ShadowSamplerLinear -#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) shadowMap.SampleCmpLevelZero(SAMPLE_SHADOW_SAMPLER, shadowUV, sceneDepth) -#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) shadowMap.SampleCmpLevelZero(SAMPLE_SHADOW_SAMPLER, shadowUV, sceneDepth, texelOffset) +#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) shadowMap.SampleCmpLevelZero(ShadowSamplerLinear, shadowUV, sceneDepth) +#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) shadowMap.SampleCmpLevelZero(ShadowSamplerLinear, shadowUV, sceneDepth, texelOffset) #else -#define SAMPLE_SHADOW_SAMPLER SamplerLinearClamp -#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowUV, 0).r) -#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowUV, 0, texelOffset).r) +#define SAMPLE_SHADOW_MAP(shadowMap, shadowUV, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SamplerLinearClamp, shadowUV, 0).r) +#define SAMPLE_SHADOW_MAP_OFFSET(shadowMap, shadowUV, texelOffset, sceneDepth) (sceneDepth < shadowMap.SampleLevel(SamplerLinearClamp, shadowUV, 0, texelOffset).r) +#endif +#if VULKAN || FEATURE_LEVEL < FEATURE_LEVEL_SM5 +#define SAMPLE_SHADOW_MAP_SAMPLER SamplerPointClamp +#else +#define SAMPLE_SHADOW_MAP_SAMPLER SamplerLinearClamp #endif float4 GetShadowMask(ShadowSample shadow) @@ -278,7 +281,7 @@ ShadowSample SampleDirectionalLightShadow(LightData light, Buffer shadow { float opacity = gBuffer.CustomData.a; shadowMapUV = GetLightShadowAtlasUV(shadow, shadowTile, gBuffer.WorldPos, shadowPosition); - float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowMapUV, 0).r; + float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_MAP_SAMPLER, shadowMapUV, 0).r; result.TransmissionShadow = CalculateSubsurfaceOcclusion(opacity, shadowPosition.z, shadowMapDepth); result.TransmissionShadow = PostProcessShadow(shadow, result.TransmissionShadow); } @@ -339,7 +342,7 @@ ShadowSample SampleLocalLightShadow(LightData light, Buffer shadowsBuffe { float opacity = gBuffer.CustomData.a; shadowMapUV = GetLightShadowAtlasUV(shadow, shadowTile, gBuffer.WorldPos, shadowPosition); - float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_SAMPLER, shadowMapUV, 0).r; + float shadowMapDepth = shadowMap.SampleLevel(SAMPLE_SHADOW_MAP_SAMPLER, shadowMapUV, 0).r; result.TransmissionShadow = CalculateSubsurfaceOcclusion(opacity, shadowPosition.z, shadowMapDepth); result.TransmissionShadow = PostProcessShadow(shadow, result.TransmissionShadow); }