Specification — Field System (GRIN Evaluation)¶
Charter section: §7 Field and Metric System
Status: Implemented
Key source files: RendererCore/Fields/FieldSystem.cs, RendererCore/Fields/FieldCurves.cs, RendererCore/Fields/FieldModels.cs
1) Purpose¶
The Field System evaluates the aggregate acceleration vector at any world-space point, given a SceneSnapshot. This acceleration drives curved-ray integration in Pass-1.
2) Public API (Implemented)¶
public static Vector3 AccelAt(Vector3 pWorld, in SceneSnapshot snapshot)
Returns the summed acceleration contribution from all influencing fields at
pWorld. Called by RayBeamRenderer during Pass-1 integration and by
FieldProbe3D for diagnostics.
3) Evaluation Pipeline (Implemented)¶
For each candidate field entity:
-
Broadphase: Query
FieldTLAS.QueryPoint(pWorld)for candidate indices. Falls back to brute-force linear scan if no TLAS. -
Bounds check:
worldBounds[i].Contains(pWorld)— skip if outside. -
Local transform:
pLocal = Vector3.Transform(pWorld, localFromWorld[i]) -
Shape distance:
SphereRadial:r = pLocal.Length()-
BoxVolume:r = pLocal.Length()(TODO: real box distance model) -
Parameter unpack: Read
rInner, rOuter, amp, a, b, cfromPackedParamBufferatparamOffset[i]. -
Range check: Skip if
rOuter <= 0orr > rOuter. -
Normalised coordinate:
u = Saturate((r - rInner) / max(ε, rOuter - rInner)) -
Curve evaluation:
f = FieldCurves.Eval(curveType, u, a, b, c, clamp01: true) -
Direction + metric model:
dirLocal = pLocal / r(radial outward)-
If
MetricModel.GordonMetric: negate direction (inward/attractive) -
Contribution:
contributionLocal = dirLocal * (amp * f) -
World transform:
contributionWorld = Vector3.TransformNormal(contributionLocal, worldFromLocal[i]) -
Accumulate:
total += contributionWorld
Guard: r < ε → skip (avoid division by zero at field origin).
4) Curve Laws (Implemented)¶
public static float Eval(FieldCurveType type, float u, float a, float b, float c, bool clamp01)
Input u is clamped to [0,1] before evaluation.
| CurveType | Formula | Notes |
|---|---|---|
| Linear | 1 - u |
Default falloff |
| Power | (1 - u)^a |
Adjustable rolloff |
| Polynomial | a + b*u + c*u² |
General quadratic |
| Exponential | exp(-a * u) |
Smooth decay |
Output optionally clamped to [0,1] when clamp01 = true (always true in
current AccelAt path).
Source: RendererCore/Fields/FieldCurves.cs
5) Metric Model Enum (Implemented)¶
public enum MetricModel { GRIN = 0, GordonMetric = 1 }
public enum FieldShapeType { SphereRadial = 0, BoxVolume = 1 }
public enum FieldCurveType { Linear = 0, Power = 1, Polynomial = 2, Exponential = 3 }
Source: RendererCore/Fields/FieldModels.cs
6) Known Limitations¶
BoxVolumeshape falls back to radial distance (TODO in code)Flagsfield is present in SOA but not consumed byAccelAt(TODO: 1/r² mode, invert, etc.)- TLAS candidate buffer is
stackalloc int[256]— max 256 candidate fields per query point - No tensor/anisotropic IOR support (Tier 0 only)
7) Determinism¶
- Candidate order is determined by TLAS traversal (stable given stable build)
- Accumulation is sequential float addition (order-dependent but deterministic)
- No randomisation in field evaluation
8) Performance¶
- Zero heap allocation in hot path (
stackallocfor candidates) - Single pass over candidates with early-exit on bounds/range
ref readonlynode access in TLAS traversalSaturateandClamp01are branchless-friendly