diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 6e863260f..8879eafd8 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -14,6 +14,7 @@ #endif #include "Engine/Level/SceneQuery.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Renderer/GlobalSignDistanceFieldPass.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Utilities/Encryption.h" @@ -318,6 +319,41 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, #endif +#if !FOLIAGE_USE_SINGLE_QUAD_TREE + +void Foliage::DrawClusterGlobalSDF(class GlobalSignDistanceFieldPass* globalSDF, const BoundingBox& globalSDFBounds, FoliageCluster* cluster, FoliageType& type) +{ + if (cluster->Children[0]) + { + // Draw children recursive +#define DRAW_CLUSTER(idx) \ + if (globalSDFBounds.Intersects(cluster->Children[idx]->TotalBounds)) \ + DrawClusterGlobalSDF(globalSDF, globalSDFBounds, cluster->Children[idx], type) + DRAW_CLUSTER(0); + DRAW_CLUSTER(1); + DRAW_CLUSTER(2); + DRAW_CLUSTER(3); +#undef DRAW_CLUSTER + } + else + { + // Draw visible instances + for (int32 i = 0; i < cluster->Instances.Count(); i++) + { + auto& instance = *cluster->Instances[i]; + if (CollisionsHelper::BoxIntersectsSphere(globalSDFBounds, instance.Bounds)) + { + const Transform transform = _transform.LocalToWorld(instance.Transform); + BoundingBox bounds; + BoundingBox::FromSphere(instance.Bounds, bounds); + globalSDF->RasterizeModelSDF(this, type.Model->SDF, transform, bounds); + } + } + } +} + +#endif + int32 Foliage::GetInstancesCount() const { return Instances.Count(); @@ -856,15 +892,10 @@ bool Foliage::Intersects(const Ray& ray, Real& distance, Vector3& normal, int32& void Foliage::Draw(RenderContext& renderContext) { - if (renderContext.View.Pass == DrawPass::GlobalSDF) - return; // TODO: Foliage rendering to Global SDF - if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas) - return; // Not supported if (Instances.IsEmpty()) return; - auto& view = renderContext.View; - PROFILE_CPU(); + auto& view = renderContext.View; // Cache data per foliage instance type for (auto& type : FoliageTypes) @@ -883,6 +914,37 @@ void Foliage::Draw(RenderContext& renderContext) } } + if (renderContext.View.Pass == DrawPass::GlobalSDF) + { + auto globalSDF = GlobalSignDistanceFieldPass::Instance(); + BoundingBox globalSDFBounds; + globalSDF->GetCullingBounds(globalSDFBounds); + // +#if FOLIAGE_USE_SINGLE_QUAD_TREE + for (auto i = Instances.Begin(); i.IsNotEnd(); ++i) + { + auto& instance = *i; + auto& type = FoliageTypes[instance.Type]; + if (type._canDraw && CollisionsHelper::BoxIntersectsSphere(globalSDFBounds, instance.Bounds)) + { + const Transform transform = _transform.LocalToWorld(instance.Transform); + BoundingBox bounds; + BoundingBox::FromSphere(instance.Bounds, bounds); + globalSDF->RasterizeModelSDF(this, type.Model->SDF, transform, bounds); + } + } +#else + for (auto& type : FoliageTypes) + { + if (type._canDraw && type.Root) + DrawClusterGlobalSDF(globalSDF, globalSDFBounds, type.Root, type); + } +#endif + return; + } + if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas) + return; // Not supported + // Draw visible clusters #if FOLIAGE_USE_SINGLE_QUAD_TREE || !FOLIAGE_USE_DRAW_CALLS_BATCHING Mesh::DrawInfo draw; diff --git a/Source/Engine/Foliage/Foliage.h b/Source/Engine/Foliage/Foliage.h index 100e25338..bfcb6ff4c 100644 --- a/Source/Engine/Foliage/Foliage.h +++ b/Source/Engine/Foliage/Foliage.h @@ -175,6 +175,9 @@ private: #else void DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, Mesh::DrawInfo& draw); #endif +#if !FOLIAGE_USE_SINGLE_QUAD_TREE + void DrawClusterGlobalSDF(class GlobalSignDistanceFieldPass* globalSDF, const BoundingBox& globalSDFBounds, FoliageCluster* cluster, FoliageType& type); +#endif public: /// diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 994b961b1..28227d259 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -537,9 +537,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex _sdfData = &sdfData; { PROFILE_CPU_NAMED("Draw"); - BoundingBox cascadeBoundsWorld = cascadeBounds; - cascadeBoundsWorld.Minimum += sdfData.Origin; - cascadeBoundsWorld.Maximum += sdfData.Origin; + BoundingBox cascadeBoundsWorld = cascadeBounds.MakeOffsetted(sdfData.Origin); + _cascadeCullingBounds = cascadeBoundsWorld; for (SceneRendering* scene : renderContext.List->Scenes) { for (const auto& e : scene->Actors) diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.h b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.h index 4c45e2acc..926cee7ca 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.h +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.h @@ -47,6 +47,7 @@ private: int32 _cascadeIndex; float _voxelSize; BoundingBox _cascadeBounds; + BoundingBox _cascadeCullingBounds; class GlobalSignDistanceFieldCustomBuffer* _sdfData; public: @@ -75,6 +76,11 @@ public: /// The output buffer. void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output); + void GetCullingBounds(BoundingBox& bounds) const + { + bounds = _cascadeCullingBounds; + } + // Rasterize Model SDF into the Global SDF. Call it from actor Draw() method during DrawPass::GlobalSDF. void RasterizeModelSDF(Actor* actor, const ModelBase::SDFData& sdf, const Transform& localToWorld, const BoundingBox& objectBounds);