Optimize foliage drawing by caching per-instance world matrix
This commit is contained in:
@@ -154,13 +154,16 @@ void Foliage::DrawInstance(DrawContext& context, FoliageInstance& instance, int3
|
||||
|
||||
// Add instance to the draw batch
|
||||
auto& instanceData = e->Instances.AddOne();
|
||||
Matrix world;
|
||||
Transform transform;
|
||||
_transform.LocalToWorld(instance.Transform, transform);
|
||||
const Float3 translation = transform.Translation - context.ViewOrigin;
|
||||
Matrix::Transformation(transform.Scale, transform.Orientation, translation, world);
|
||||
constexpr float worldDeterminantSign = 1.0f;
|
||||
instanceData.Store(world, world, instance.LightmapUVsArea, drawCall.Surface.GeometrySize, instance.Random, worldDeterminantSign, lodDitherFactor);
|
||||
if (!instance.CachedDrawWorldValid)
|
||||
{
|
||||
Transform transform;
|
||||
_transform.LocalToWorld(instance.Transform, transform);
|
||||
const Float3 translation = transform.Translation - context.ViewOrigin;
|
||||
Matrix::Transformation(transform.Scale, transform.Orientation, translation, instance.CachedDrawWorld);
|
||||
instance.CachedDrawWorldValid = true;
|
||||
}
|
||||
instanceData.Store(instance.CachedDrawWorld, instance.CachedDrawWorld, instance.LightmapUVsArea, drawCall.Surface.GeometrySize, instance.Random, worldDeterminantSign, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +495,7 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Me
|
||||
type.Model->GetLODsCount() - 1,
|
||||
renderContext.View.CullingFrustum,
|
||||
};
|
||||
_cachedDrawWorldOrigin = renderContext.View.Origin;
|
||||
if (context.RenderContext.View.Pass != DrawPass::Depth)
|
||||
context.MinObjectPixelSizeSq = 0.0f; // Don't use it in main view
|
||||
#if FOLIAGE_USE_DRAW_CALLS_BATCHING
|
||||
@@ -605,6 +609,21 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Me
|
||||
#endif
|
||||
}
|
||||
|
||||
void Foliage::PreDraw(const RenderView& view)
|
||||
{
|
||||
// When origin changes, then update all instance matrices
|
||||
if (_cachedDrawWorldOrigin != view.Origin)
|
||||
{
|
||||
_cachedDrawWorldOrigin = view.Origin;
|
||||
for (auto i = Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
i->CachedDrawWorldValid = false;
|
||||
}
|
||||
|
||||
// Cache data per foliage instance type
|
||||
for (FoliageType& type : FoliageTypes)
|
||||
InitType(view, type);
|
||||
}
|
||||
|
||||
void Foliage::InitType(const RenderView& view, FoliageType& type)
|
||||
{
|
||||
const DrawPass drawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
|
||||
@@ -775,6 +794,7 @@ void Foliage::AddInstance(const FoliageInstance& instance)
|
||||
data->Bounds = BoundingSphere::Empty;
|
||||
data->Random = Random::Rand();
|
||||
data->CullDistance = type->CullDistance + type->CullDistanceRandomRange * data->Random;
|
||||
data->CachedDrawWorldValid = false;
|
||||
|
||||
// Validate foliage type model
|
||||
if (!type->IsReady())
|
||||
@@ -813,6 +833,7 @@ void Foliage::SetInstanceTransform(int32 index, const Transform& value)
|
||||
|
||||
// Change transform
|
||||
instance.Transform = value;
|
||||
instance.CachedDrawWorldValid = false;
|
||||
|
||||
// Update bounds
|
||||
if (type.IsReady())
|
||||
@@ -1200,12 +1221,7 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
const RenderView& view = renderContext.View;
|
||||
|
||||
// Cache data per foliage instance type
|
||||
for (auto& type : FoliageTypes)
|
||||
{
|
||||
InitType(renderContext.View, type);
|
||||
}
|
||||
PreDraw(view);
|
||||
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
||||
{
|
||||
@@ -1305,8 +1321,6 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
draw.ForcedLOD = -1;
|
||||
draw.VertexColors = nullptr;
|
||||
draw.Deformation = nullptr;
|
||||
#else
|
||||
DrawCallsList draw[MODEL_MAX_LODS];
|
||||
#endif
|
||||
#if FOLIAGE_USE_SINGLE_QUAD_TREE
|
||||
if (Root)
|
||||
@@ -1314,6 +1328,9 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
#else
|
||||
for (auto& type : FoliageTypes)
|
||||
{
|
||||
#if !FOLIAGE_USE_SINGLE_QUAD_TREE && FOLIAGE_USE_DRAW_CALLS_BATCHING
|
||||
DrawCallsList draw[MODEL_MAX_LODS];
|
||||
#endif
|
||||
DrawType(renderContext, type, draw);
|
||||
}
|
||||
#endif
|
||||
@@ -1329,9 +1346,7 @@ void Foliage::Draw(RenderContextBatch& renderContextBatch)
|
||||
const RenderView& view = renderContextBatch.GetMainContext().View;
|
||||
if (EnumHasAnyFlags(view.Pass, DrawPass::GBuffer) && !(view.Pass & (DrawPass::GlobalSDF | DrawPass::GlobalSurfaceAtlas)) && renderContextBatch.EnableAsync)
|
||||
{
|
||||
// Cache data per foliage instance type
|
||||
for (FoliageType& type : FoliageTypes)
|
||||
InitType(view, type);
|
||||
PreDraw(view);
|
||||
|
||||
// Run async job for each foliage type
|
||||
_renderContextBatch = &renderContextBatch;
|
||||
@@ -1760,6 +1775,13 @@ void Foliage::OnTransformChanged()
|
||||
|
||||
PROFILE_CPU();
|
||||
|
||||
if (IsDuringPlay())
|
||||
{
|
||||
// Invalidate cached world matrix
|
||||
for (auto i = Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
i->CachedDrawWorldValid = false;
|
||||
}
|
||||
|
||||
UpdateBounds();
|
||||
RebuildClusters();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ API_CLASS() class FLAXENGINE_API Foliage final : public Actor
|
||||
private:
|
||||
bool _disableFoliageTypeEvents;
|
||||
int32 _sceneRenderingKey = -1;
|
||||
Vector3 _cachedDrawWorldOrigin = Vector3::Zero;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -215,6 +216,7 @@ private:
|
||||
RenderContextBatch* _renderContextBatch;
|
||||
#endif
|
||||
|
||||
void PreDraw(const RenderView& view);
|
||||
void InitType(const RenderView& view, FoliageType& type);
|
||||
void UpdateBounds();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Core/Math/BoundingSphere.h"
|
||||
#include "Engine/Core/Math/Half.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
|
||||
/// <summary>
|
||||
/// Foliage instanced mesh instance. Packed data with very little of logic. Managed by the foliage chunks and foliage actor itself.
|
||||
@@ -48,6 +49,11 @@ API_STRUCT(NoPod, NoDefault) struct FLAXENGINE_API FoliageInstance
|
||||
/// </summary>
|
||||
byte DrawStateLODTransition = 255;
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to indicate whether CachedDrawWorld contains valid data.
|
||||
/// </summary>
|
||||
byte CachedDrawWorldValid = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The per-instance random value from range [0;1].
|
||||
/// </summary>
|
||||
@@ -63,6 +69,11 @@ API_STRUCT(NoPod, NoDefault) struct FLAXENGINE_API FoliageInstance
|
||||
/// </summary>
|
||||
Half4 LightmapUVsArea;
|
||||
|
||||
/// <summary>
|
||||
/// Cached local-to-world transformation matrix for the instance used during rendering. Relative to the last rendering context origin. Valid only if CachedDrawWorldValid flag is set.
|
||||
/// </summary>
|
||||
Matrix CachedDrawWorld;
|
||||
|
||||
public:
|
||||
bool operator==(const FoliageInstance& v) const
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user