Vixen
02b45cc4
csharp
public sealed class GrassRenderer

A field of grass: cells scattered as they come into range, culled per blade every frame.

Read the guide page for this →

Remarks

[docs/plan/31 § T6] and [§ D8]. Nothing here is loaded and nothing here is saved. A cell entering range is scattered into one of a fixed number of pooled buffers; a cell leaving hands its buffer back; a cell coming back is re-scattered to the identical blades, because Hash depends on the cell coordinate and the slot and on nothing else.

⚠ The scatter happens on entry and the cull happens every frame, and keeping those apart is the whole shape of the feature. Scattering per frame would probe the surface for every blade of every cell every frame — which is the cost the ring exists to pay once — and culling on entry would draw the far half of every cell for as long as it stayed resident.

⚠ Residency is per cell and scatter is per cell per field. One ring, because the cell is the unit of everything foliage does and a ring per field would probe the same ground several times; but a field with a 20 m cull distance does not scatter into a cell held resident by a field with an 80 m one, or the short field would pay for the long field's range.

⚠ This is the CPU half. GrassScatter.rvn is the dispatch that mirrors it, and GrassScatterParityTests is what holds the two together — the same arrangement FoliageRenderer and InstanceCuller have, for the same reason: a scatter fails silently in both directions.

Fields and properties (13)

  • public GrassResidency Residency

    Which cells hold blades and which slot each of them is in.

  • public int FieldCapacity

    How many grass types the ring has room for.

  • public IReadOnlyList<GrassBatch> Batches

    What each resident cell drew, in the order they were gathered.

  • public ReadOnlySpan<Matrix4x4> Transforms

    Every surviving blade's transform, compacted across every cell and field.

  • public ReadOnlySpan<InstanceParameters> Parameters

    And their parameters, at the same indices.

  • public int BladesResident

    How many blades the ring is holding.

  • public int BladesScattered

    How many blades the last scatter produced.

  • public int BladesDropped

    How many it dropped.

  • public int CellsConsidered

    How many cell-and-field pairs the last cull tested.

  • public int CellsDrawn

    How many survived the first stage.

  • public int BladesConsidered

    How many blades those cells held.

  • public int BladesDrawn

    And how many survived the second.

  • public int Draws

    How many indirect draws the frame issues, empty ones included.

Methods (5)

  • public GrassRenderer(FoliageCellGrid grid, int capacity = 256, int fields = 4)

    Creates a renderer with a ring of a fixed size.

  • public int Scatter(IReadOnlyList<GrassDraw> fields, IFoliageSurface surface, Vector3 viewPosition, float densityScale = 1)

    Brings the ring up to date and scatters whatever entered range.

  • public int Cull(IReadOnlyList<GrassDraw> fields, in BoundingFrustum frustum, Vector3 viewPosition, float densityScale = 1)

    Culls what the ring holds against a view and builds its indirect draws.

  • public void Reset()

    Drops every blade and returns every slot.

  • public void Grow(int fields)

    Makes room for more grass types per cell.

Used by (1)

  • GrassRendererTestsVixen.Rendering.Terrain.Tests