Files
sbox-public/engine/Sandbox.Engine/Scene/Components/Clutter/ClutterBatchSceneObject.cs
Antoine Pilote 01c5fc2b2c Clutter LODs for instanced models (#4786)
* add LOD switching for clutter model instances

* DrawModelInstamce with correct LOD level

* removed some useless comments. move stuff around

https://files.facepunch.com/antopilo/1b0711b1/sbox-dev_AcVXDWDDah.mp4

* use biggest scale axis to determine screen coverage for clutter lod level

* clamp LOD in managed

* clamp lod in native

* rename lod Count to maxLodCount
2026-05-19 10:04:55 -07:00

86 lines
1.9 KiB
C#

using System.Runtime.InteropServices;
using Sandbox.Rendering;
namespace Sandbox.Clutter;
/// <summary>
/// Custom scene object for rendering batched clutter models.
/// Groups instances by model type for efficient GPU instanced rendering.
/// </summary>
internal class ClutterBatchSceneObject : SceneCustomObject
{
private readonly Dictionary<Model, ClutterModelBatch> _batches = [];
private readonly CommandList _commandList = new( "ClutterBatch" );
private readonly int _lodLevel;
public ClutterBatchSceneObject( SceneWorld world, int lodLevel ) : base( world )
{
_lodLevel = lodLevel;
Flags.IsOpaque = true;
Flags.IsTranslucent = false;
Flags.CastShadows = true;
Flags.WantsPrePass = true;
}
/// <summary>
/// Adds a clutter instance to the appropriate batch.
/// </summary>
public void AddInstance( ClutterInstance instance )
{
if ( instance.Entry?.Model == null )
return;
var model = instance.Entry.Model;
if ( !_batches.TryGetValue( model, out var batch ) )
{
batch = new ClutterModelBatch( model );
_batches[model] = batch;
}
batch.AddInstance( instance.Transform );
}
/// <summary>
/// Builds the command list from current batches. Must be called on the main thread
/// after all instances have been added.
/// </summary>
public void BuildCommandList()
{
_commandList.Reset();
foreach ( var (model, batch) in _batches )
{
if ( batch.Transforms.Count == 0 || model == null )
continue;
_commandList.DrawModelInstanced( model, CollectionsMarshal.AsSpan( batch.Transforms ), _lodLevel );
}
}
/// <summary>
/// Clears all batches.
/// </summary>
public void Clear()
{
foreach ( var batch in _batches.Values )
batch.Clear();
_batches.Clear();
_commandList.Reset();
}
public new void Delete()
{
Clear();
base.Delete();
}
public override void RenderSceneObject()
{
_commandList.ExecuteOnRenderThread();
}
}