Curved-Ray Renderer Architecture Master Outline¶
1) Executive Summary¶
This document is the code-grounded master outline for the curved-ray renderer in this repository.
- Current state: the runtime path is a Godot-driven renderer where curved rays
are generated as bounded segment chains (
RayBeamRenderer.RaySeg) and consumed by a two-pass film pipeline (GrinFilmCamera.RenderStep). - Current state: field and geometry broadphase data are snapshotted into
RendererCore.SceneSnapshot.SceneSnapshotand shared viaRendererCore.Common.FrameSnapshotBus. - Current state: pass-2 collision/narrowphase still uses Godot physics
(
IntersectRay,IntersectShape,CastMotion) with optionalGeometryTLAScandidate pruning. - Planned / TODO: internal triangle-level intersection (BLAS + internal narrowphase) is not wired yet.
What this engine is:
- A curved-ray film renderer embedded in Godot.
- A hybrid architecture where
RendererCoreowns snapshot/field/TLAS data structures while final collision is still delegated to Godot physics.
What this engine is not (today):
- Not yet a fully internal intersection stack.
- Not yet an end-to-end task-graph scheduler in
RendererCore/Scheduler. - Not yet a production "Core" backend that replaces the legacy film path.
What "curved rays are first-class" means in implementation terms:
- Rays are explicitly represented as segment sequences (
RaySeg) with:A,B,TraveledB, andRadiusBound. RadiusBoundis consumed by pass-2 envelope broadphase (Aabb3.FromSegment(...).Expand(...)).- Pass-1 integration can be physically-driven (
UseIntegratedField) with adaptive step sizing, not just straight-line + post bend.
Source anchors:
GrinFilmCamera.csRayBeamRenderer.csRendererCore/SceneSnapshot/SceneSnapshot.csRendererCore/Common/FrameSnapshotBus.cs
2) Current Architecture at a Glance¶
Godot scene tree
-> GodotAdapter.SnapshotBuilder.BuildFromGodotScene(...)
-> SceneSnapshot { Fields, FieldParams, FieldTLAS, Geometry, GeometryTLAS }
-> CurvatureBoundGrid (added by GrinFilmCamera.RenderFrameBackend)
-> FrameSnapshotBus.Set(snapshot, frameId)
GrinFilmCamera backend dispatch (per _Process when UpdateEveryFrame=true)
-> BackendMode.Legacy:
LegacyBackend.RenderFrame(snapshot)
-> GrinFilmCamera.RenderStep()
Pass 1 (Parallel.For): segment integration + optional pass1 hit probes
Pass 2 (Main thread): broadphase + Godot physics + shading + writeback
Upload Image -> ImageTexture -> TextureRect/FilmOverlay2D
-> BackendMode.Core:
CoreBackend.RenderFrame(snapshot) // snapshot summary print
LegacyBackend.RenderFrame(snapshot) // still renders output
-> BackendMode.Compare:
LegacyBackend.RenderFrame(snapshot) // TODO compare mode
Current state:
- Main entry is
GrinFilmCamera._Process -> RenderFrameBackend. - Snapshot is rebuilt every frame from the live Godot scene.
- Legacy film pipeline is still the output-producing path.
Source anchors:
GrinFilmCamera.csGodotAdapter/SnapshotBuilder.csRenderBackends/LegacyBackend.csRenderBackends/CoreBackend.cs
3) Core Design Principles (As Implemented)¶
Snapshot Immutability¶
- Current state:
SceneSnapshotproperties areinit-set and rebuilt each frame (SnapshotBuilder.BuildFromGodotScene). - Current state: consumers read snapshot arrays as immutable for the frame.
- Current state: immutability is by discipline/convention; arrays are not deep read-only wrappers.
Data-Oriented Layout¶
- Current state: field/geometry snapshot data are SOA arrays and packed buffers
(
FieldEntitySOA,GeometryEntitySOA,PackedParamBuffer). - Current state: TLAS node arrays are contiguous (
FieldTLAS.Nodes,GeometryTLAS.Nodes) for stack-based traversal.
Determinism and Threading¶
- Current state: snapshot extraction order is stabilized by sorting node paths
(
string.CompareOrdinal). - Current state: pass-1 is parallel per pixel; pass-2 remains main-thread due Godot physics API calls.
- Current state:
RenderStephas a re-entry guard (Interlocked). - Current state: optional SoftGate random probing uses
_rng.Randf(), so deterministic replay is not guaranteed when randomness is enabled.
Source anchors:
GodotAdapter/SnapshotBuilder.csRendererCore/SceneSnapshot/*.csRendererCore/Fields/FieldTLAS.csRendererCore/Geometry/GeometryTLAS.csGrinFilmCamera.cs
4) Module Map (Folders and Responsibilities)¶
RendererCore/*¶
SceneSnapshot/*: snapshot container and SOA/pod types.Fields/*: field enums, field evaluation, field TLAS, curvature bound grid.Geometry/*: geometry TLAS over world AABBs.Integrators/*: currently onlyStepPolicy(dt helper).Common/*: snapshot bus + debug overlay/log toggles.Accel/: currently empty.Scheduler/: currently empty.
Source anchors:
RendererCore/SceneSnapshot/SceneSnapshot.csRendererCore/Fields/FieldSystem.csRendererCore/Geometry/GeometryTLAS.csRendererCore/Integrators/StepPolicy.csRendererCore/Common/FrameSnapshotBus.cs
RenderBackends/*¶
- Backend interface and mode enum.
LegacyBackend: drivesGrinFilmCamera.RenderStep().CoreBackend: currently logs snapshot summary.BackendSelector: exists but is not the active dispatch path.
Source anchors:
RenderBackends/IRenderBackend.csRenderBackends/LegacyBackend.csRenderBackends/CoreBackend.csRenderBackends/BackendSelector.cs
GodotAdapter/*¶
- Godot scene extraction into
SceneSnapshot. - Field collection, parameter packing, TLAS builds.
- Geometry collection as world AABBs + Godot instance IDs.
Source anchors:
GodotAdapter/SnapshotBuilder.cs
Root-level Orchestrators / Runtime Nodes¶
GrinFilmCamera: backend dispatch, frame snapshot publish, film render loop, pass-1/pass-2 pipeline, budgets/watchdogs, telemetry.RayBeamRenderer: curved segment integration primitives and collision helper APIs used by film pass.FieldSource3D: authoring/runtime field node definition.FieldGrid3D: pass-1 acceleration cache (vector field grid).FieldProbe3D: runtime probe of snapshot field system + debug overlay output.FilmOverlay2D: 2D overlay renderer for debug rays/hit normals/bus items.PerfScope/PerfStats: timing/counter aggregation and log output.
Source anchors:
GrinFilmCamera.csRayBeamRenderer.csFieldSource3D.csFieldGrid3D.csFieldProbe3D.csFilmOverlay2D.csPerfScope.csPerfStats.cs
5) Data Model and Memory Layout¶
SceneSnapshot Shape¶
Current state (RendererCore.SceneSnapshot.SceneSnapshot):
InstanceSOA InstancesFieldEntitySOA FieldsPackedParamBuffer FieldParamsFieldTLAS FieldTLASGeometryEntitySOA GeometryGeometryTLAS GeometryTLASCurvatureBoundGrid CurvatureGrid
SOA Containers¶
Current state:
InstanceSOA: mesh/material IDs, object/world transforms, world bounds.GeometryEntitySOA: world bounds +GodotInstanceIds.FieldEntitySOA: metric/shape/curve enums, transforms, bounds, param offsets/lengths, flags.
Packed Parameters¶
Current state:
PackedParamBuffer.AppendBlock8(...)stores field params in blocks of 8:rInner, rOuter, amp, a, b, c, r0, r1.
TLAS Layers¶
Current state:
FieldTLASbuilt fromFieldEntitySOA.WorldBounds.GeometryTLASbuilt fromGeometryEntitySOA.WorldBounds.
Frame Rebuild vs Reuse¶
Current state:
- Rebuilt per frame: snapshot, field TLAS, geometry TLAS, curvature grid.
- Reused across frames: camera-owned pass buffers (
_segBuf, hit arrays, quick-ray caches, perf windows, optional field grid cache with cadence).
Important present limitation:
SnapshotBuildercurrently setsInstances = InstanceSOA.Empty(); instance transform SOA is defined but not populated in this path.
Source anchors:
RendererCore/SceneSnapshot/SceneSnapshot.csRendererCore/SceneSnapshot/InstanceSOA.csRendererCore/SceneSnapshot/GeometryEntitySOA.csRendererCore/SceneSnapshot/FieldEntitySOA.csRendererCore/SceneSnapshot/PackedParamBuffer.csGodotAdapter/SnapshotBuilder.cs
6) Coordinate Spaces and Transforms¶
Current state:
- Field evaluation is world-query driven:
FieldSystem.AccelAt(Vector3 pWorld, SceneSnapshot snapshot). - Field transforms are explicit per entity:
WorldFromLocal[]andLocalFromWorld[]. - Field radius/shape tests are evaluated in field-local space and converted back to world contribution.
- Geometry in snapshot is currently represented in world AABBs.
- Camera convention follows Godot: forward is
-Basis.Z.
Current state for instance transforms:
InstanceSOA.WorldFromObjectandObjectFromWorldare part of model but not currently populated bySnapshotBuilder.
Source anchors:
RendererCore/Fields/FieldSystem.csRendererCore/SceneSnapshot/FieldEntitySOA.csRendererCore/SceneSnapshot/InstanceSOA.csGodotAdapter/SnapshotBuilder.csRayBeamRenderer.cs
7) Fields and Metrics System¶
Field Entity Representation¶
Current state:
- Authored by
FieldSource3Dwith exported:MetricModel,FieldShapeType,FieldCurveType, radii, amplitude, flags, and curve coefficients. - Extracted by
SnapshotBuilderinto SOA arrays andPackedParamBuffer.
Metric Models¶
Current state (RendererCore.Fields.MetricModel):
GRIN = 0GordonMetric = 1
Current behavior:
FieldSystemflips local direction sign forGordonMetricvsGRIN.
Shapes and Curves¶
Current state:
- Shapes:
SphereRadial,BoxVolume. - Curves:
Linear,Power,Polynomial,Exponential. FieldCurves.Eval(...)handles curve law evaluation.
Current limitations / TODO already in code:
FieldSystem:BoxVolumecurrently falls back to radial distance model.FieldSystem: flags behavior includes TODO for1/r^2mode details.
Curvature Bounds and Grids¶
Current state:
CurvatureBoundGrid.BuildAroundCamera(...)computes per-cellKmaxusing candidate fields viaFieldTLAS.QueryAabb.RayBeamRenderer.BuildRaySegmentsCamera_Pass1converts localKmaxinto segment envelope radius bound (RaySeg.RadiusBound).StepPolicy.ComputeDtexists and is used byFieldProbe3Dfor probe readouts.
Field Cache (FieldGrid3D)¶
Current state:
- Optional pass-1 vector field cache (
UseFieldGrid) rebuilt on cadence or field cache refresh; sampled before source fallback.
Source anchors:
FieldSource3D.csRendererCore/Fields/FieldModels.csRendererCore/Fields/FieldCurves.csRendererCore/Fields/FieldSystem.csRendererCore/Fields/CurvatureBoundGrid.csFieldGrid3D.csFieldProbe3D.cs
8) Curved Ray Representation and Integration¶
Ray State in Code¶
Current state:
- Segment struct:
RayBeamRenderer.RaySeg(A,B,TraveledB,RadiusBound). - Hit payload:
RayBeamRenderer.HitPayload. - Pass-1 hit metadata:
RayBeamRenderer.Pass1HitInfo.
Integration Method¶
Current state:
- Main pass-1 builder:
RayBeamRenderer.BuildRaySegmentsCamera_Pass1(...). - Uses explicit stepping over
StepsPerRaywith two paths: - Integrated path (
UseIntegratedField=true): update velocity by field acceleration and step adaptively. - Analytic bend path: parametric bend by
beta * t^gamma * bendScale. - Adaptive step controls:
StepLength,MinStepLength,MaxStepLength,StepAdaptGain, low-curvature boost controls.
Segment Cadence and Envelopes¶
Current state:
- Segment emission cadence uses base
CollisionEveryNStepsand optional screen-space cadence adaptation. - Envelope radius is computed from curvature grid when available.
Chunking and envelope status:
- Current state: envelope-carrying segments are implemented (
RadiusBound). - Planned / TODO: dedicated chunk system from
Docs/spec_curved_ray_chunks.mdis not yet materialized as separate runtime chunk types.
Source anchors:
RayBeamRenderer.csGrinFilmCamera.csDocs/spec_curved_ray_chunks.md
9) Acceleration Structures and Intersection¶
TLAS in Runtime¶
Current state:
FieldTLAS: BVH over field AABBs, used for field candidate queries.GeometryTLAS: BVH over geometry AABBs, used as pass-2 candidate pruning.
BVH/BLAS Type Inventory¶
Current state:
RendererCore.Fields.BVHNodeinFieldTLAS.RendererCore.Geometry.GeometryBVHNodeinGeometryTLAS.- No BLAS triangle BVH implementation in
RendererCore/Accelyet.
Intersection API Boundary¶
Current state:
- Pass-1 generates segments and optional probe hits.
- Pass-2 performs broadphase + narrowphase using Godot physics:
IntersectRay,IntersectShape,CastMotion, and helper wrappers (SubdividedRayHit,SweepSegmentHit). - When geometry TLAS pruning is enabled, narrowphase hits are accepted only if collider ID is in TLAS-derived candidate instance IDs.
Validation vs production status:
- Current state: Godot physics is still production narrowphase.
- Planned / TODO: internal triangle-level intersection path to replace this.
Source anchors:
RendererCore/Fields/FieldTLAS.csRendererCore/Geometry/GeometryTLAS.csGrinFilmCamera.csRayBeamRenderer.csRendererCore/SceneSnapshot/GeometryEntitySOA.cs
10) Scheduling and Concurrency¶
Current state work partition:
- Frame is processed in row bands (
RowsPerFrameand adaptive row sizing). - Pass-1:
Parallel.Foracross pixels in current band. - Pass-2: sequential on main thread.
Current thread-safety strategy:
- Snapshot is read-only during
RenderStep. - Pass-1 writes per-pixel buffers (disjoint indices) and merges counters via
Interlocked. - Re-entry guard prevents overlapping
RenderStepinvocations.
Current watchdogs and budgets:
UpdateEveryFrameBudgetMs,UpdateEveryFrameMaxRowsPerStep.RenderStepMaxMs,RenderStepMaxPixelsPerFrame,RenderStepMaxSegmentsPerFrame.- Multiple guard exits for stuck/no-progress/no-hit/no-candidate bands.
- SoftGate budgets and watchdog (
Pass2SoftGate*config set).
Planned / TODO:
RendererCore/Scheduleris currently empty; task-graph scheduler doc exists but is not the runtime backbone yet.
Source anchors:
GrinFilmCamera.csRenderBackends/LegacyBackend.csRendererCore/Scheduler/Docs/spec_scheduler_task_graph.md
11) Rendering Backends and Output¶
Current backend reality:
LegacyBackendis the rendering backend that produces film output.CoreBackendcurrently prints snapshot summary only.BackendMode.Corecurrently executes both core summary and legacy render.BackendMode.Comparecurrently falls back to legacy path.
Current output chain:
- Film buffer (
Image) updated toImageTextureeach render step. - Output to configured
TextureRect(FilmViewPath) or auto-created overlay. - Optional
FilmOverlay2Ddraws world ray/hit overlays + film gradient normals. DebugOverlayBusitems (for example fromFieldProbe3D) are consumed byFilmOverlay2D.
Postprocess/shader note:
- Shader files exist in repo, but this C# pipeline does not currently show a dedicated postprocess stage wiring them in runtime code.
Source anchors:
RenderBackends/LegacyBackend.csRenderBackends/CoreBackend.csRenderBackends/BackendMode.csGrinFilmCamera.csFilmOverlay2D.csRendererCore/Common/DebugOverlayBus.cs
12) Telemetry, Debugging, and Validation¶
Current telemetry:
XPrimeRay.Perf.FramePerf+PerfScopestage timing/counters.PerfStatsrolling-window frame summaries and invariant checks.- Frame/band render-health logging in
GrinFilmCamera.
Current debugging and validation helpers:
FieldProbe3DevaluatesFieldSystem.AccelAtagainst current snapshot bus state and draws overlay diagnostics.- Geometry prune audit and reject sampling instrumentation in pass-2.
FieldSource3Din-game debug shape rendering.RayBeamRendererdebug overlay +GetDebugRayBundlehandoff.RayVizandCurvedCameraare auxiliary debug/visual tools.
Source anchors:
PerfScope.csPerfStats.csGrinFilmCamera.csFieldProbe3D.csFieldSource3D.csRayBeamRenderer.csRayViz.csCurvedCamera.cs
13) Roadmap (Reconciled to Current Code)¶
Charter Reality Check¶
- Previous charter said: renderer owns all production intersection.
- Code shows: pass-2 still uses Godot physics; internal TLAS is currently pruning/filtering, not full internal narrowphase.
-
Update needed: add internal triangle acceleration + intersection path before claiming full ownership.
-
Previous charter said: full end-to-end multithreading.
- Code shows: pass-1 is parallel, pass-2 is main-thread.
-
Update needed: move pass-2 off Godot physics dependency.
-
Previous charter said: scheduler/task graph subsystem.
- Code shows: scheduler folder is empty; scheduling logic is embedded in
GrinFilmCamera. - Update needed: migrate runtime scheduling to
RendererCore/Scheduler.
Implemented¶
- Scene snapshot extraction (
SnapshotBuilder) with field/geometry SOA. - Field and geometry TLAS builds and queries.
- Curvature bound grid creation around camera.
- Pass-1 curved segment integration with adaptive stepping and optional probes.
- Pass-2 broadphase policies + TLAS-gated Godot narrowphase.
- Budget/watchdog/telemetry framework in the film renderer.
In Progress¶
- Core backend migration (
CoreBackendexists but is summary-only). - Geometry TLAS pruning quality instrumentation (audit/fn/fp/reject samples).
- SoftGate policy tuning for quick-ray-miss recovery.
Planned Next¶
- Internal BLAS/triangle intersection path and removal of Godot as production narrowphase.
RendererCore/Schedulertask graph implementation.- Real compare mode in backend dispatch.
- Explicit runtime chunk system if needed beyond
RaySegenvelope usage.
Related specialized docs:
Docs/architecture_overview.mdDocs/spec_scene_snapshot_data_layout.mdDocs/spec_bvh_acceleration.mdDocs/spec_metric_models_grin_vs_gordon.mdDocs/spec_curved_ray_chunks.mdDocs/spec_scheduler_task_graph.md
14) Glossary¶
SceneSnapshot: immutable-for-frame container passed into rendering stages.SOA: struct-of-arrays data layout (FieldEntitySOA,GeometryEntitySOA).PackedParamBuffer: contiguous float buffer for field parameter blocks.TLAS: top-level AABB hierarchy over entities (FieldTLAS,GeometryTLAS).BLAS: lower-level triangle hierarchy; planned, not implemented in code.GRIN: metric model (MetricModel.GRIN) for optical gradient-index behavior.GordonMetric: metric model variant currently implemented as direction-sign inversion in field contribution logic.RaySeg: bounded curved segment used for pass-2 tests and envelopes.RadiusBound: conservative segment envelope radius used for geometry pruning.Pass-1: parallel segment integration stage.Pass-2: main-thread collision + shading stage.SoftGate: gated policy for extra subdivided checks on uncertain misses.FieldGrid3D: optional cached vector field for pass-1 acceleration sampling.CurvatureBoundGrid: camera-centered grid ofKmaxupper bounds.RenderHealth: rolling diagnostics for stalls, hit-rate, prune behavior.
14) Relativistic Optics, Metrics, and Wormholes¶
Goal: make the engine academically credible for gravitational optics by defining a metric-first path for null geodesics, while retaining the existing GRIN/field pipeline as a practical/artist-friendly control layer.
14.1 Key Principle: “Euclidean scene, non‑Euclidean light”¶
- Geometry/colliders can remain standard Euclidean meshes (for gameplay + authoring).
- The light transport is governed by an effective spacetime / optical metric that bends rays (null curves) through the same Euclidean world positions.
- This matches how most production GR lensing renderers work: they integrate geodesics in a chosen coordinate chart and sample scene content along the ray.
14.2 Physics alignment levels (Research Mode tiers)¶
Tier 0 (Current, “GRIN-Field”): - Rays bend under a configurable field rule (beta/gamma, integrated acceleration, step adapt). Good for art, intuition, and controllable DOEs.
Tier 1 (Optical Metric / Gordon Metric): - Interpret curvature field as a spatially varying refractive index and/or moving medium (Gordon metric). - Required: a canonical conversion contract: (field params) → (n(x), v(x)) → effective metric g_eff(x).
Tier 2 (Full GR Metric): - Integrate null geodesics from explicit g_{μν}(x) (Schwarzschild, Kerr, weak-field PN, custom numerically defined metrics). - Required: Christoffel symbols Γ^μ_{αβ}(x) and a null-constraint enforcement strategy.
Tier 3 (Exotic / Wormhole Metrics): - Implement a small library of wormhole metrics (e.g., Morris–Thorne-style spherically symmetric static wormhole) as coordinate charts. - Rendering does not require non-Euclidean meshes; it requires: - a coordinate mapping / chart definition, - geodesic integration through that chart, - and sampling content from one or more “regions” (mouth A / mouth B) via mapping.
14.3 Integrators: “PHD level” method inventory (engine should expose them)¶
Engine should provide a unified integrator interface with these options: - Fixed-step explicit integrators: Euler (debug), Midpoint, RK2, RK4. - Adaptive embedded Runge–Kutta: RKF45 / Dormand–Prince RK45 (error estimate + dt control). - Symplectic / geometric integrators (where applicable): Verlet / Stormer–Verlet, implicit midpoint (energy behavior). - Geodesic-specific forms: - Hamiltonian formulation for null geodesics (canonical momenta p_μ; integrate Hamilton’s equations). - First integrals for common metrics (Schwarzschild/Kerr constants of motion) to reduce drift. - Constraint handling: - null constraint g_{μν} u^μ u^ν = 0 enforced via projection, renormalization, or constrained integrator step.
Deliverable target: - A single “RayIntegrator” contract with: State, Step(dt), ErrorEstimate(dt), and optional ConstraintProject(). - Current “StepPolicy” becomes one implementation; GR integrators become additional implementations.
14.4 Wormhole modeling (what we need to add)¶
You do not need “non-Cartesian scene meshes.” You need non-trivial coordinate mapping and metric definitions: - Metric: pick a wormhole line element (static spherically symmetric is easiest). - Charts/Regions: define mouth A and mouth B as separate coordinate patches (or a single patch with mapping). - Ray transport: integrate geodesics through the metric; when the ray crosses the throat, map its coordinates to the other region. - Sampling: query fields/geometry in the appropriate region’s scene snapshot or via portal mapping.
Proposed engine abstraction:
- IMetricField (returns g_{μν} and optionally Γ or ∂g).
- IChartMap (maps between Euclidean world (x,y,z,t) and chart coordinates; supports portal crossings).
- IRaySampler (samples scene content along a ray, including “which region” rules).
14.5 Twistor/spinor note (position in the roadmap)¶
- Twistors/spinors can be treated as an alternative representation of rays and null directions (especially useful for Kerr and conformal structures).
- They are not strictly required to render GR lensing, but they can improve stability/efficiency and connect to conformal compactifications (Penrose-style).
- Roadmap: add a “representation layer” where a ray may be stored as (x^μ, p_μ) Hamiltonian state or a spinor/twistor state, while preserving the same integrator/sampler interfaces above.
15) Research Mode Toggle (spec)¶
Purpose: allow switching between production/gameplay constraints and research/validation constraints without touching gameplay-facing defaults.
Required components:
- ResearchModeConfig (authoritative toggle + policy)
- Enabled
- Preset (e.g., Off / Validate / PaperMatch / StressTest)
- LoggingVerbosity
- DeterminismMode (seeded RNG, disable random probes, fixed dt, etc.)
- ResearchModeOverrides (override values for EffectiveConfig)
- strong typing, explicit “OverrideX” bool flags
- override groups: Film, Broadphase, RayMarch, SoftGate, Budgets, Debug
Integration point (code):
- GrinFilmCamera.ResolveEffectiveConfig(out EffectiveConfig cfg) must call:
- ResearchModeOverrides.Apply(ref cfg, ResearchModeConfig cfgResearch, sourceContext: "GrinFilmCamera")
- Must log a one-line “ResearchMode active” banner when enabled, with a stable hash of the override set.
Validation behaviors to include: - Option to disable all stochastic choices (SoftGate randomness) for repeatable runs. - Option to run a “truth pass” (full overlap + no pruning) on a sampled subset for FP/FN estimates. - Option to dump ray states for a small set of pixels for offline comparison.