Vixen
dd8b0a81
csharp
public sealed class GrassResidency

Which cells are close enough to hold a scattered buffer, and which slot each of them is in.

Read the guide page for this →

Remarks

[docs/plan/31 § T6]'s ring, and the reason grass costs a fixed amount of memory. A cell entering range is given one of a fixed number of pooled allocations and scattered into it; a cell leaving hands its slot back. Nothing about it is persisted, so eviction is free and re-entry is a re-scatter that produces the identical blades — Hash is what makes that true.

⚠ Eviction happens further out than creation, and the gap is not decoration. A camera standing on the boundary of a cell that is created and evicted at the same distance re-scatters it every frame, which is the whole cost of the feature paid for nothing. The hysteresis makes the two ranges different, so standing still is stable.

⚠ Distance is measured to the nearest point of the cell, not to its centre. A 32 m cell whose near edge is under the camera has its centre 22 m away, so a centre test with a 20 m range would leave the ground the camera is standing on bare.

⚠ A ring too small for its range drops the far cells. The wanted set is filled nearest first, so what a capacity that ran out loses is the horizon rather than a hole under the camera — and Refused says it happened, because the alternative is a level that quietly stops having grass at a distance nobody chose.

⚠ Not Vixen.Rendering's PageResidency, and what separates them is the policy rather than the storage. That service is an LRU under a byte budget: a request that needs room evicts whatever was used longest ago, and it always finds room, because only a pinned page refuses. This is a distance ring, where a cell further out than everything resident has to lose — Reclaim takes a slot only from a cell further away than the candidate, and Refused is what happens when there is none. Touching cells in distance order does not recover that: nine slots under a range that wants forty-one cells re-place every slot every frame while nobody moves, in either request order, because each of the thirty-two that does not fit still evicts one that did. ARingThatRanOutStandsStill is that property held down. The layering says the same thing more cheaply — this assembly references no device and that one is the render system — but the policy is why they are two services and not one.

Fields and properties (6)

  • public FoliageCellGrid Grid

    The grid its cells are of.

  • public int Capacity

    How many cells may be resident at once.

  • public int Count

    How many are.

  • public float Hysteresis

    How far past the creation range a cell survives before it is evicted, as a fraction.

  • public int Refused

    How many cells the last update wanted and had no slot for.

  • public IEnumerable<GrassSlot> Resident

    Every resident cell and its slot.

Methods (5)

  • public GrassResidency(FoliageCellGrid grid, int capacity)

    Creates an empty ring.

  • public bool TryGetSlot(FoliageCellKey cell, out int slot)

    Which slot a cell is in, if it is resident.

  • public GrassResidencyChange Update(Vector3 viewPosition, float range)

    Brings the ring up to date with where the view is.

  • public void Clear()

    Drops every cell, returning every slot.

  • public float DistanceTo(FoliageCellKey cell, Vector2 position)

    How far a cell's nearest point is from a horizontal position.

Used by (7)

  • GrassFieldVixen.Rendering.Terrain
  • GrassRendererVixen.Rendering.Terrain
  • GrassRendererTestsVixen.Rendering.Terrain.Tests
  • GrassResidencyTestsVixen.Foliage.Tests
  • TerrainSceneRendererVixen.Rendering.Terrain
  • GrassFieldVixen.Editor.App
  • VegetationPresenterVixen.Editor.App