From 4d2f91afc7debd30666da575886ef1ec22d38352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Tue, 3 Mar 2026 08:49:35 +0100 Subject: [PATCH] gaussian splat improvements --- .../shaders/ShaderInterop_GaussianSplat.h | 1 + WickedEngine/shaders/gaussian_splatVS.hlsl | 13 ++++++------- WickedEngine/wiGaussianSplatModel.cpp | 19 +++++++++++++------ WickedEngine/wiGaussianSplatModel.h | 13 +++++++++---- WickedEngine/wiRenderer.cpp | 9 +-------- WickedEngine/wiScene.cpp | 13 +++++++++++++ WickedEngine/wiVersion.cpp | 2 +- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/WickedEngine/shaders/ShaderInterop_GaussianSplat.h b/WickedEngine/shaders/ShaderInterop_GaussianSplat.h index 6944e7a86..dc27e8097 100644 --- a/WickedEngine/shaders/ShaderInterop_GaussianSplat.h +++ b/WickedEngine/shaders/ShaderInterop_GaussianSplat.h @@ -15,6 +15,7 @@ struct GaussianSplatCB { ShaderTransform transform; ShaderTransform transform_inverse; + float4x4 modelViewMatrix; int sphericalHarmonicsDegree; int splatStride; int padding0; diff --git a/WickedEngine/shaders/gaussian_splatVS.hlsl b/WickedEngine/shaders/gaussian_splatVS.hlsl index 2cb38b93b..741a73f7b 100644 --- a/WickedEngine/shaders/gaussian_splatVS.hlsl +++ b/WickedEngine/shaders/gaussian_splatVS.hlsl @@ -228,19 +228,18 @@ half3 fetchViewDependentRadiance(in uint splatIndex, in float3 worldViewDir) void main(in uint vertexID : SV_VertexID, in uint instanceID : SV_InstanceID, out float4 pos : SV_Position, out half4 color : COLOR, out half2 localPos : LOCALPOS) { const uint splatIndex = sortedIndexBuffer[instanceID]; + ShaderCamera camera = GetCamera(); const float3 splatCenter = float4(splats[splatIndex].position, 1).xyz; color = unpack_half4(splats[splatIndex].color); - float3 viewDir = normalize(mul(cb.transform_inverse.GetMatrix(), float4(GetCamera().position, 1)).xyz - splatCenter); + float3 viewDir = normalize(mul(cb.transform_inverse.GetMatrix(), float4(camera.position, 1)).xyz - splatCenter); color.rgb += fetchViewDependentRadiance(splatIndex, viewDir); color.rgb = RemoveSRGBCurve_Fast(color.rgb); // Checked against SuperSplat Editor, result is more similar with gamma remove - float4x4 modelViewMatrix = mul(GetCamera().view, cb.transform.GetMatrix()); - - const float4 viewCenter = mul(modelViewMatrix, float4(splatCenter, 1.0)); - const float4 clipCenter = mul(GetCamera().projection, viewCenter); + const float4 viewCenter = mul(cb.modelViewMatrix, float4(splatCenter, 1.0)); + const float4 clipCenter = mul(camera.projection, viewCenter); const float3x3 cov3Dm = fetchCovariance(splatIndex); - const float3 cov2Dv = threedgsCovarianceProjection(cov3Dm, viewCenter, GetCamera().focal, modelViewMatrix); // computes the basis vectors of the extent of the projected covariance + const float3 cov2Dv = threedgsCovarianceProjection(cov3Dm, viewCenter, camera.focal, cb.modelViewMatrix); // computes the basis vectors of the extent of the projected covariance const float2 fragPos = BILLBOARD[vertexID].xy; // We use sqrt(8) standard deviations instead of 3 to eliminate more of the splat with a very low opacity. @@ -253,7 +252,7 @@ void main(in uint vertexID : SV_VertexID, in uint instanceID : SV_InstanceID, ou else { const float3 ndcCenter = clipCenter.xyz / clipCenter.w; - const float2 ndcOffset = float2(fragPos.x * basisVector1 + fragPos.y * basisVector2) * /*frameInfo.basisViewport*/GetCamera().internal_resolution_rcp * 2.0 * /*frameInfo.inverseFocalAdjustment*/1.0; + const float2 ndcOffset = float2(fragPos.x * basisVector1 + fragPos.y * basisVector2) * /*frameInfo.basisViewport*/camera.internal_resolution_rcp * 2.0 * /*frameInfo.inverseFocalAdjustment*/1.0; const float4 quadPos = float4(ndcCenter.xy + ndcOffset, ndcCenter.z, 1.0); pos = quadPos; } diff --git a/WickedEngine/wiGaussianSplatModel.cpp b/WickedEngine/wiGaussianSplatModel.cpp index 4304b5a7d..3fb8a7e58 100644 --- a/WickedEngine/wiGaussianSplatModel.cpp +++ b/WickedEngine/wiGaussianSplatModel.cpp @@ -5,6 +5,7 @@ #include "wiTimer.h" #include "wiEventHandler.h" #include "wiGPUSortLib.h" +#include "wiScene_Components.h" using namespace wi::math; using namespace wi::graphics; @@ -24,13 +25,13 @@ namespace wi { GraphicsDevice* device = GetDevice(); - aabb = AABB(); + aabb_rest = AABB(); auto fill_gpu = [&](void* dest) { GaussianSplat* splat_dest = (GaussianSplat*)dest; for (size_t splatIdx = 0; splatIdx < positions.size(); ++splatIdx) { - aabb.AddPoint(positions[splatIdx]); + aabb_rest.AddPoint(positions[splatIdx]); GaussianSplat splat = {}; splat.position = positions[splatIdx]; @@ -177,14 +178,19 @@ namespace wi device->SetName(&constantBuffer, "GaussianSplatModel::constantBuffer"); } - void GaussianSplatModel::Update(const XMFLOAT4X4& transform, wi::graphics::CommandList cmd) + void GaussianSplatModel::Update(const XMFLOAT4X4& matrix) + { + transform = matrix; + XMFLOAT4X4 transform_inverse; + XMStoreFloat4x4(&transform_inverse, XMMatrixInverse(nullptr, XMLoadFloat4x4(&matrix))); + aabb = aabb_rest.transform(matrix); + } + + void GaussianSplatModel::UpdateGPU(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) { GraphicsDevice* device = GetDevice(); device->EventBegin("Gaussian Splat Update", cmd); - XMFLOAT4X4 transform_inverse; - XMStoreFloat4x4(&transform_inverse, XMMatrixInverse(nullptr, XMLoadFloat4x4(&transform))); - const uint32_t totalSphericalHarmonicsComponentCount = uint32_t(f_rest.size() / positions.size()); const uint32_t sphericalHarmonicsCoefficientsPerChannel = totalSphericalHarmonicsComponentCount / 3; int sphericalHarmonicsDegree = 0; @@ -208,6 +214,7 @@ namespace wi GaussianSplatCB cb = {}; cb.transform.Create(transform); cb.transform_inverse.Create(transform_inverse); + XMStoreFloat4x4(&cb.modelViewMatrix, XMMatrixMultiply(XMLoadFloat4x4(&transform), camera.GetView())); cb.sphericalHarmonicsDegree = sphericalHarmonicsDegree; cb.splatStride = splatStride; device->UpdateBuffer(&constantBuffer, &cb, cmd); diff --git a/WickedEngine/wiGaussianSplatModel.h b/WickedEngine/wiGaussianSplatModel.h index c32ec33ff..98939bd49 100644 --- a/WickedEngine/wiGaussianSplatModel.h +++ b/WickedEngine/wiGaussianSplatModel.h @@ -5,6 +5,7 @@ #include "wiVector.h" #include "wiMath.h" #include "wiECS.h" +#include "wiScene_Decl.h" namespace wi { @@ -18,10 +19,13 @@ namespace wi wi::vector scales; wi::vector opacities; wi::vector f_dc; - wi::vector f_rest; // 45 floats per splat (15 * rgb coefficient SH3) + wi::vector f_rest; // number of floats depends on SH degree // Below this are non-serialized attributes: - wi::primitive::AABB aabb; + wi::primitive::AABB aabb_rest; // aabb without trasformation + wi::primitive::AABB aabb; // aabb with trasformation + XMFLOAT4X4 transform = wi::math::IDENTITY_MATRIX; + XMFLOAT4X4 transform_inverse = wi::math::IDENTITY_MATRIX; wi::graphics::GPUBuffer splatBuffer; wi::graphics::GPUBuffer shBuffer; wi::graphics::GPUBuffer indirectBuffer; @@ -36,8 +40,9 @@ namespace wi void CreateRenderData(); - void Update(const XMFLOAT4X4& transform, wi::graphics::CommandList cmd); - void Draw(wi::graphics::CommandList cmd); + void Update(const XMFLOAT4X4& matrix); + void UpdateGPU(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd); // culling and sorting + void Draw(wi::graphics::CommandList cmd); // will be drawn with culling and sorting based on previous call to UpdateGPU void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 6529edeb1..78bffdb84 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -5644,18 +5644,11 @@ void UpdateRenderDataAsync( const wi::GaussianSplatModel& splat = vis.scene->gaussian_splats[i]; if (!vis.camera->frustum.CheckBoxFast(splat.aabb)) continue; - XMFLOAT4X4 matrix = wi::math::IDENTITY_MATRIX; - Entity entity = vis.scene->gaussian_splats.GetEntity(i); - const TransformComponent* transform = vis.scene->transforms.GetComponent(entity); - if (transform != nullptr) - { - matrix = transform->world; - } if (prof_splats == 0) { prof_splats = wi::profiler::BeginRangeGPU("Gaussian Splat Culling and Sorting", cmd); } - vis.scene->gaussian_splats[i].Update(matrix, cmd); + vis.scene->gaussian_splats[i].UpdateGPU(*vis.camera, cmd); } if (prof_splats != 0) { diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 3cf899a78..71d6ac5ca 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5263,6 +5263,19 @@ namespace wi::scene } }); + + for (size_t i = 0; i < gaussian_splats.GetCount(); ++i) + { + const wi::GaussianSplatModel& splat = gaussian_splats[i]; + XMFLOAT4X4 matrix = wi::math::IDENTITY_MATRIX; + Entity entity = gaussian_splats.GetEntity(i); + const TransformComponent* transform = transforms.GetComponent(entity); + if (transform != nullptr) + { + matrix = transform->world; + } + gaussian_splats[i].Update(matrix); + } } void Scene::RunWeatherUpdateSystem(wi::jobsystem::context& ctx) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index e723f7030..9134014dc 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 72; // minor bug fixes, alterations, refactors, updates - const int revision = 48; + const int revision = 49; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);