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.