Fix Global SDF update when changing Draw Modes of the model

Refactor `DrawModes` field in `StaticModel` and `FoliageType` into property with getter/setter

#3949
This commit is contained in:
Wojtek Figat
2026-03-11 16:01:56 +01:00
parent 479c5f896c
commit 96bbae8e28
7 changed files with 79 additions and 27 deletions

View File

@@ -22,7 +22,7 @@
#include "Engine/Serialization/Serialization.h"
#include "Engine/Utilities/Encryption.h"
#define FOLIAGE_GET_DRAW_MODES(renderContext, type) (type.DrawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(type.ShadowsMode))
#define FOLIAGE_GET_DRAW_MODES(renderContext, type) (type._drawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(type.ShadowsMode))
#define FOLIAGE_CAN_DRAW(renderContext, type) (type.IsReady() && FOLIAGE_GET_DRAW_MODES(renderContext, type) != DrawPass::None && type.Model->CanBeRendered())
Foliage::Foliage(const SpawnParams& params)
@@ -360,7 +360,7 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D
draw.DrawState = &instance.DrawState;
draw.Bounds = sphere;
draw.PerInstanceRandom = instance.Random;
draw.DrawModes = type.DrawModes;
draw.DrawModes = type._drawModes;
draw.SetStencilValue(_layer);
type.Model->Draw(context.RenderContext, draw);
@@ -597,14 +597,22 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Me
void Foliage::InitType(const RenderView& view, FoliageType& type)
{
const DrawPass drawModes = type.DrawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
const DrawPass drawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
type._canDraw = type.IsReady() && drawModes != DrawPass::None && type.Model && type.Model->CanBeRendered();
bool drawModesDirty = false;
for (int32 j = 0; j < type.Entries.Count(); j++)
{
auto& e = type.Entries[j];
e.ReceiveDecals = type.ReceiveDecals != 0;
e.ShadowsMode = type.ShadowsMode;
if (type._drawModesDirty)
{
type._drawModesDirty = 0;
drawModesDirty = true;
}
}
if (drawModesDirty)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::DrawModes);
}
int32 Foliage::GetInstancesCount() const
@@ -1250,7 +1258,7 @@ void Foliage::Draw(RenderContext& renderContext)
draw.Deformation = nullptr;
draw.Bounds = instance.Bounds;
draw.PerInstanceRandom = instance.Random;
draw.DrawModes = type.DrawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
draw.DrawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
draw.SetStencilValue(_layer);
type.Model->Draw(renderContext, draw);
return;

View File

@@ -13,6 +13,7 @@ FoliageType::FoliageType()
, Index(-1)
{
_isReady = 0;
_drawModesDirty = 0;
ReceiveDecals = true;
UseDensityScaling = false;
@@ -32,7 +33,7 @@ FoliageType& FoliageType::operator=(const FoliageType& other)
CullDistance = other.CullDistance;
CullDistanceRandomRange = other.CullDistanceRandomRange;
ScaleInLightmap = other.ScaleInLightmap;
DrawModes = other.DrawModes;
SetDrawModes(other._drawModes);
ShadowsMode = other.ShadowsMode;
PaintDensity = other.PaintDensity;
PaintRadius = other.PaintRadius;
@@ -69,6 +70,19 @@ void FoliageType::SetMaterials(const Array<MaterialBase*>& value)
Entries[i].Material = value[i];
}
DrawPass FoliageType::GetDrawModes() const
{
return _drawModes;
}
void FoliageType::SetDrawModes(DrawPass value)
{
if (_drawModes == value)
return;
_drawModes = value;
_drawModesDirty = 1;
}
Float3 FoliageType::GetRandomScale() const
{
Float3 result;
@@ -150,7 +164,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE(CullDistance);
SERIALIZE(CullDistanceRandomRange);
SERIALIZE(ScaleInLightmap);
SERIALIZE(DrawModes);
SERIALIZE_MEMBER(DrawModes, _drawModes);
SERIALIZE(ShadowsMode);
SERIALIZE_BIT(ReceiveDecals);
SERIALIZE_BIT(UseDensityScaling);
@@ -191,7 +205,7 @@ void FoliageType::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
DESERIALIZE(CullDistance);
DESERIALIZE(CullDistanceRandomRange);
DESERIALIZE(ScaleInLightmap);
DESERIALIZE(DrawModes);
DESERIALIZE_MEMBER(DrawModes, _drawModes);
DESERIALIZE(ShadowsMode);
DESERIALIZE_BIT(ReceiveDecals);
DESERIALIZE_BIT(UseDensityScaling);

View File

@@ -48,6 +48,8 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API FoliageType : public ScriptingOb
private:
uint8 _isReady : 1;
uint8 _canDraw : 1;
uint8 _drawModesDirty : 1;
DrawPass _drawModes = DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward;
public:
/// <summary>
@@ -124,9 +126,15 @@ public:
API_FIELD() float ScaleInLightmap = 1.0f;
/// <summary>
/// The draw passes to use for rendering this foliage type.
/// Gets the draw passes to use for rendering this foliage type.
/// </summary>
API_FIELD() DrawPass DrawModes = DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward;
API_PROPERTY(Attributes="DefaultValue(DrawPass.Depth | DrawPass.GBuffer | DrawPass.Forward)")
DrawPass GetDrawModes() const;
/// <summary>
/// Sets the draw passes to use for rendering this foliage type.
/// </summary>
API_PROPERTY() void SetDrawModes(DrawPass value);
/// <summary>
/// The shadows casting mode.
@@ -184,7 +192,7 @@ public:
API_FIELD() float PlacementRandomRollAngle = 0.0f;
/// <summary>
/// The density scaling scale applied to the global scale for the foliage instances of this type. Can be used to boost or reduce density scaling effect on this foliage type. Default is 1.
/// The density scale factor applied to the global scale for the foliage instances of this type. Can be used to boost or reduce density scaling effect on this foliage type. Default is 1. Lower to reduce density scaling effect when downscaling foliage via global quality/scalability.
/// </summary>
API_FIELD() float DensityScalingScale = 1.0f;

View File

@@ -66,6 +66,20 @@ void StaticModel::SetBoundsScale(float value)
UpdateBounds();
}
DrawPass StaticModel::GetDrawModes() const
{
return _drawModes;
}
void StaticModel::SetDrawModes(DrawPass value)
{
if (_drawModes == value)
return;
_drawModes = value;
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::DrawModes);
}
int32 StaticModel::GetLODBias() const
{
return _lodBias;
@@ -330,13 +344,13 @@ void StaticModel::Draw(RenderContext& renderContext)
return;
if (renderContext.View.Pass == DrawPass::GlobalSDF)
{
if (EnumHasAnyFlags(DrawModes, DrawPass::GlobalSDF) && Model->SDF.Texture)
if (EnumHasAnyFlags(_drawModes, DrawPass::GlobalSDF) && Model->SDF.Texture)
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _transform, _box);
return;
}
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
{
if (EnumHasAnyFlags(DrawModes, DrawPass::GlobalSurfaceAtlas) && Model->SDF.Texture)
if (EnumHasAnyFlags(_drawModes, DrawPass::GlobalSurfaceAtlas) && Model->SDF.Texture)
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
return;
}
@@ -353,7 +367,7 @@ void StaticModel::Draw(RenderContext& renderContext)
draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
draw.LightmapUVs = &Lightmap.UVsArea;
draw.Flags = _staticFlags;
draw.DrawModes = DrawModes;
draw.DrawModes = _drawModes;
draw.Bounds = _sphere;
draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
@@ -390,7 +404,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
draw.LightmapUVs = &Lightmap.UVsArea;
draw.Flags = _staticFlags;
draw.DrawModes = DrawModes;
draw.DrawModes = _drawModes;
draw.Bounds = _sphere;
draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
@@ -435,7 +449,7 @@ void StaticModel::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE_MEMBER(LODBias, _lodBias);
SERIALIZE_MEMBER(ForcedLOD, _forcedLod);
SERIALIZE_MEMBER(SortOrder, _sortOrder);
SERIALIZE(DrawModes);
SERIALIZE_MEMBER(DrawModes, _drawModes);
if (HasLightmap()
#if USE_EDITOR
@@ -487,7 +501,7 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
DESERIALIZE_MEMBER(LODBias, _lodBias);
DESERIALIZE_MEMBER(ForcedLOD, _forcedLod);
DESERIALIZE_MEMBER(SortOrder, _sortOrder);
DESERIALIZE(DrawModes);
DESERIALIZE_MEMBER(DrawModes, _drawModes);
DESERIALIZE_MEMBER(LightmapIndex, Lightmap.TextureIndex);
DESERIALIZE_MEMBER(LightmapArea, Lightmap.UVsArea);
@@ -537,27 +551,27 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
if (member != stream.MemberEnd() && member->value.IsBool() && member->value.GetBool())
{
MARK_CONTENT_DEPRECATED();
DrawModes = DrawPass::Depth;
_drawModes = DrawPass::Depth;
}
}
// [Deprecated on 07.02.2022, expires on 07.02.2024]
if (modifier->EngineBuild <= 6330)
{
MARK_CONTENT_DEPRECATED();
DrawModes |= DrawPass::GlobalSDF;
_drawModes |= DrawPass::GlobalSDF;
}
// [Deprecated on 27.04.2022, expires on 27.04.2024]
if (modifier->EngineBuild <= 6331)
{
MARK_CONTENT_DEPRECATED();
DrawModes |= DrawPass::GlobalSurfaceAtlas;
_drawModes |= DrawPass::GlobalSurfaceAtlas;
}
{
const auto member = stream.FindMember("RenderPasses");
if (member != stream.MemberEnd() && member->value.IsInt())
{
DrawModes = (DrawPass)member->value.GetInt();
_drawModes = (DrawPass)member->value.GetInt();
}
}
}

View File

@@ -23,6 +23,7 @@ private:
bool _vertexColorsDirty;
byte _vertexColorsCount;
int8 _sortOrder;
DrawPass _drawModes = DrawPass::Default;
Array<Color32> _vertexColorsData[MODEL_MAX_LODS];
GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS];
Model* _residencyChangedModel = nullptr;
@@ -40,12 +41,6 @@ public:
API_FIELD(Attributes="EditorOrder(20), DefaultValue(null), EditorDisplay(\"Model\")")
AssetReference<Model> Model;
/// <summary>
/// The draw passes to use for rendering this object.
/// </summary>
API_FIELD(Attributes="EditorOrder(15), DefaultValue(DrawPass.Default), EditorDisplay(\"Model\")")
DrawPass DrawModes = DrawPass::Default;
/// <summary>
/// The baked lightmap entry.
/// </summary>
@@ -74,6 +69,17 @@ public:
/// </summary>
API_PROPERTY() void SetBoundsScale(float value);
/// <summary>
/// Gets the draw passes to use for rendering this object.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(15), DefaultValue(DrawPass.Default), EditorDisplay(\"Model\")")
DrawPass GetDrawModes() const;
/// <summary>
/// Sets the draw passes to use for rendering this object.
/// </summary>
API_PROPERTY() void SetDrawModes(DrawPass value);
/// <summary>
/// Gets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality.
/// </summary>

View File

@@ -56,6 +56,7 @@ public:
Layer = 4,
StaticFlags = 8,
AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked
DrawModes = 32,
Auto = Visual | Bounds | Layer,
};

View File

@@ -408,7 +408,8 @@ public:
if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle()))
{
ScopeWriteLock lock(Locker);
OnSceneRenderingDirty(BoundingBox::FromSphere(prevBounds));
if (flags != DrawModes && flags != Layer && flags != StaticFlags)
OnSceneRenderingDirty(BoundingBox::FromSphere(prevBounds));
OnSceneRenderingDirty(a->GetBox());
}
}