Add Global Surface Atlas rendering for Foliage
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "Engine/Level/SceneQuery.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Renderer/GlobalSignDistanceFieldPass.h"
|
||||
#include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
|
||||
@@ -352,6 +353,35 @@ void Foliage::DrawClusterGlobalSDF(class GlobalSignDistanceFieldPass* globalSDF,
|
||||
}
|
||||
}
|
||||
|
||||
void Foliage::DrawClusterGlobalSA(GlobalSurfaceAtlasPass* globalSA, const Vector4& cullingPosDistance, FoliageCluster* cluster, FoliageType& type, const BoundingBox& localBounds)
|
||||
{
|
||||
if (cluster->Children[0])
|
||||
{
|
||||
// Draw children recursive
|
||||
#define DRAW_CLUSTER(idx) \
|
||||
if (CollisionsHelper::DistanceBoxPoint(cluster->Children[idx]->TotalBounds, Vector3(cullingPosDistance)) < cullingPosDistance.W) \
|
||||
DrawClusterGlobalSA(globalSA, cullingPosDistance, cluster->Children[idx], type, localBounds)
|
||||
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::DistanceSpherePoint(instance.Bounds, Vector3(cullingPosDistance)) < cullingPosDistance.W)
|
||||
{
|
||||
const Transform transform = _transform.LocalToWorld(instance.Transform);
|
||||
globalSA->RasterizeActor(this, &instance, instance.Bounds, transform, localBounds, MAX_uint32, true, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int32 Foliage::GetInstancesCount() const
|
||||
@@ -918,8 +948,7 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
{
|
||||
auto globalSDF = GlobalSignDistanceFieldPass::Instance();
|
||||
BoundingBox globalSDFBounds;
|
||||
globalSDF->GetCullingBounds(globalSDFBounds);
|
||||
//
|
||||
globalSDF->GetCullingData(globalSDFBounds);
|
||||
#if FOLIAGE_USE_SINGLE_QUAD_TREE
|
||||
for (auto i = Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
@@ -942,8 +971,67 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
||||
return; // Not supported
|
||||
{
|
||||
// Draw foliage instances into Global Surface Atlas
|
||||
auto globalSA = GlobalSurfaceAtlasPass::Instance();
|
||||
Vector4 cullingPosDistance;
|
||||
globalSA->GetCullingData(cullingPosDistance);
|
||||
#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::DistanceSpherePoint(instance.Bounds, Vector3(cullingPosDistance)) < cullingPosDistance.W)
|
||||
{
|
||||
const Transform transform = _transform.LocalToWorld(instance.Transform);
|
||||
BoundingBox localBounds = type.Model->LODs.Last().GetBox();
|
||||
globalSA->RasterizeActor(this, &instance, instance.Bounds, transform, localBounds, MAX_uint32, true, 0.5f);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (auto& type : FoliageTypes)
|
||||
{
|
||||
if (type._canDraw && type.Root)
|
||||
{
|
||||
BoundingBox localBounds = type.Model->LODs.Last().GetBox();
|
||||
DrawClusterGlobalSA(globalSA, cullingPosDistance, type.Root, type, localBounds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (renderContext.View.Pass & DrawPass::GlobalSurfaceAtlas)
|
||||
{
|
||||
// Draw single foliage instance projection into Global Surface Atlas
|
||||
auto& instance = *(FoliageInstance*)GlobalSurfaceAtlasPass::Instance()->GetCurrentActorObject();
|
||||
auto& type = FoliageTypes[instance.Type];
|
||||
for (int32 i = 0; i < type.Entries.Count(); i++)
|
||||
{
|
||||
auto& e = type.Entries[i];
|
||||
e.ReceiveDecals = type.ReceiveDecals != 0;
|
||||
e.ShadowsMode = type.ShadowsMode;
|
||||
}
|
||||
Matrix world;
|
||||
const Transform transform = _transform.LocalToWorld(instance.Transform);
|
||||
renderContext.View.GetWorldMatrix(transform, world);
|
||||
Mesh::DrawInfo draw;
|
||||
draw.Flags = GetStaticFlags();
|
||||
draw.LODBias = 0;
|
||||
draw.ForcedLOD = -1;
|
||||
draw.VertexColors = nullptr;
|
||||
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(instance.Lightmap.TextureIndex);
|
||||
draw.LightmapUVs = &instance.Lightmap.UVsArea;
|
||||
draw.Buffer = &type.Entries;
|
||||
draw.World = &world;
|
||||
draw.DrawState = &instance.DrawState;
|
||||
draw.Bounds = instance.Bounds;
|
||||
draw.PerInstanceRandom = instance.Random;
|
||||
draw.DrawModes = static_cast<DrawPass>(type.DrawModes & view.Pass & (int32)view.GetShadowsDrawPassMask(type.ShadowsMode));
|
||||
type.Model->Draw(renderContext, draw);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw visible clusters
|
||||
#if FOLIAGE_USE_SINGLE_QUAD_TREE || !FOLIAGE_USE_DRAW_CALLS_BATCHING
|
||||
|
||||
@@ -177,6 +177,7 @@ private:
|
||||
#endif
|
||||
#if !FOLIAGE_USE_SINGLE_QUAD_TREE
|
||||
void DrawClusterGlobalSDF(class GlobalSignDistanceFieldPass* globalSDF, const BoundingBox& globalSDFBounds, FoliageCluster* cluster, FoliageType& type);
|
||||
void DrawClusterGlobalSA(class GlobalSurfaceAtlasPass* globalSA, const Vector4& cullingPosDistance, FoliageCluster* cluster, FoliageType& type, const BoundingBox& localBounds);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -480,6 +480,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
const uint32 viewMask = renderContext.View.RenderLayersMask;
|
||||
const Float3 viewPosition = renderContext.View.Position;
|
||||
const float minObjectRadius = 20.0f; // Skip too small objects
|
||||
_cullingPosDistance = Vector4(viewPosition, distance);
|
||||
for (auto* scene : renderContext.List->Scenes)
|
||||
{
|
||||
for (auto& e : scene->Actors)
|
||||
@@ -582,8 +583,9 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
|
||||
// Fake projection matrix to disable Screen Size culling based on RenderTools::ComputeBoundsScreenRadiusSquared
|
||||
renderContextTiles.View.Projection.Values[0][0] = 10000.0f;
|
||||
|
||||
|
||||
// Collect draw calls for the object
|
||||
_currentActorObject = actorObject;
|
||||
object.Actor->Draw(renderContextTiles);
|
||||
|
||||
// Render all tiles into the atlas
|
||||
@@ -1154,12 +1156,12 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Transform& localToWorld, const BoundingBox& localBounds, uint32 tilesMask, bool useVisibility)
|
||||
void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Transform& localToWorld, const BoundingBox& localBounds, uint32 tilesMask, bool useVisibility, float qualityScale)
|
||||
{
|
||||
GlobalSurfaceAtlasCustomBuffer& surfaceAtlasData = *_surfaceAtlasData;
|
||||
Float3 boundsSize = localBounds.GetSize() * actor->GetScale();
|
||||
const float distanceScale = Math::Lerp(1.0f, surfaceAtlasData.DistanceScaling, Math::InverseLerp(surfaceAtlasData.DistanceScalingStart, surfaceAtlasData.DistanceScalingEnd, (float)CollisionsHelper::DistanceSpherePoint(actorObjectBounds, surfaceAtlasData.ViewPosition)));
|
||||
const float tilesScale = surfaceAtlasData.TileTexelsPerWorldUnit * distanceScale;
|
||||
const float tilesScale = surfaceAtlasData.TileTexelsPerWorldUnit * distanceScale * qualityScale;
|
||||
GlobalSurfaceAtlasObject* object = surfaceAtlasData.Objects.TryGet(actorObject);
|
||||
bool anyTile = false, dirty = false;
|
||||
for (int32 tileIndex = 0; tileIndex < 6; tileIndex++)
|
||||
|
||||
@@ -61,6 +61,8 @@ private:
|
||||
class GlobalSurfaceAtlasCustomBuffer* _surfaceAtlasData;
|
||||
Array<void*> _dirtyObjectsBuffer;
|
||||
uint64 _culledObjectsSizeFrames[8];
|
||||
Vector4 _cullingPosDistance;
|
||||
void* _currentActorObject;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -80,8 +82,20 @@ public:
|
||||
/// <param name="output">The output buffer.</param>
|
||||
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
|
||||
|
||||
// Gets the culling view position (xyz) and view distance (w)
|
||||
void GetCullingData(Vector4& cullingPosDistance) const
|
||||
{
|
||||
cullingPosDistance = _cullingPosDistance;
|
||||
}
|
||||
|
||||
// Gets the current object of the actor that is drawn into atlas.
|
||||
void* GetCurrentActorObject() const
|
||||
{
|
||||
return _currentActorObject;
|
||||
}
|
||||
|
||||
// Rasterize actor into the Global Surface Atlas. Call it from actor Draw() method during DrawPass::GlobalSurfaceAtlas.
|
||||
void RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Transform& localToWorld, const BoundingBox& localBounds, uint32 tilesMask = MAX_uint32, bool useVisibility = true);
|
||||
void RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Transform& localToWorld, const BoundingBox& localBounds, uint32 tilesMask = MAX_uint32, bool useVisibility = true, float qualityScale = 1.0f);
|
||||
|
||||
private:
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
/// <param name="output">The output buffer.</param>
|
||||
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
|
||||
|
||||
void GetCullingBounds(BoundingBox& bounds) const
|
||||
void GetCullingData(BoundingBox& bounds) const
|
||||
{
|
||||
bounds = _cascadeCullingBounds;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user