Code/PerformantTerrainScatterer/PerformantTerrainScattererManager.Data.cs

Data and helper types for a terrain scatterer component. Defines enums, property-backed structs for materials and model entries, and internal structs/classes for chunk, batch and instance render data used to place and render scattered objects on terrain.

Native Interop
using System.Collections.Generic;
using Sandbox;

public sealed partial class PerformantTerrainScatterer
{
	public enum ScattererNoiseType
	{
		None,
		Perlin,
		Simplex
	}

	public struct MaterialWeight
	{
		public MaterialWeight() { }
		[Property] public TerrainMaterial Material { get; set; } = null;
		[Property, Range( 0f, 100f )] public float Weight { get; set; } = 1f;
	}

	public struct MaterialInstanceOverride
	{
		public MaterialInstanceOverride() { }
		[Property] public TerrainMaterial Material { get; set; } = null;
		[Property] public int MaxInstances { get; set; } = 500;
	}

	public struct ScattererModelEntry
	{
		public ScattererModelEntry() { }
		[Property, Category( "Base" )] public Model Model { get; set; } = null;
		[Property, Category( "Base" )] public float ZOffset { get; set; } = 0f;

		[Property, Category( "Noise Scattering" )]
		public ScattererNoiseType NoiseType { get; set; } = ScattererNoiseType.None;

		[Property, Category( "Noise Scattering" )]
		public float NoiseScale { get; set; } = 0.002f;

		[Property, Category( "Noise Scattering" ), Range( 0f, 1f )]
		public float NoiseThreshold { get; set; } = 0.4f;

		[Property, Category( "Performance" )] public float RenderDistance { get; set; } = 2500f;
		[Property, Category( "Terrain" )] public List<MaterialWeight> MaterialWeights { get; set; } = new();

		[Property, Category( "Randomization" )]
		public bool RandomizeScale { get; set; } = false;

		[Property, Category( "Randomization" ), ShowIf( nameof(RandomizeScale), true )]
		public float MinScale { get; set; } = 0.8f;

		[Property, Category( "Randomization" ), ShowIf( nameof(RandomizeScale), true )]
		public float MaxScale { get; set; } = 1.2f;

		[Property, Category( "LOD" ), Range( 0.1f, 4f )]
		public float LodBias { get; set; } = 1.0f;
	}

	private struct ChunkRenderData
	{
		public Vector3 Center;
		public ModelRenderBatch[] Batches;
	}

	private struct ModelRenderBatch
	{
		public Model Model;
		public Transform[] Transforms;
		public float RenderDistSq;
		public float[] LodDistancesSq;
		public int MaxLod;
	}

	private struct InstanceData
	{
		public Vector3 Position;
		public Rotation Rotation;
		public float Scale;
		public int ModelIndex;
	}

	private class ClutterChunk
	{
		public Vector3 Center;
		public readonly Dictionary<int, Transform[]> TransformsByModel = new();
	}
}