Arena 3D Renderer
The RODENT arena renderer converts the experiment arena definition into a live 3D Godot scene. The renderer is data-driven: arena regions, walls, doors, structures, stimuli, materials, and camera behaviour are created from the current experiment snapshot rather than being hard-coded into a single arena layout.
Renderer Architecture
The arena is displayed through a Godot SubViewport embedded inside the arena panel.
ArenaPanel
│
▼
SubViewportContainer
│
▼
SubViewport
│
▼
Arena3D
│
├── Floor regions
├── Floor labels
├── Outer walls
├── Inner walls
├── Doors
├── Structures
├── Stimuli
├── Treatment chamber
└── Camera
The SubViewportContainer is responsible for displaying the viewport, while Arena3D contains the generated 3D scene.
The relevant implementation files are:
src/app/panels/arena_panel.tscn
src/app/panels/arena_panel.gd
src/app/arena_3d.gd
Snapshot-Driven Rendering
The renderer is rebuilt using:
setup_from_snapshot(snapshot)
The snapshot contains the current arena configuration and simulation state.
When the snapshot is applied, the renderer rebuilds the relevant scene objects:
- Floor regions
- Region labels
- Outer walls
- Inner walls
- Doors
- DCR roof
- Structures
- Stimuli
- Treatment chamber
- Camera state
Previously generated arena objects are removed before rebuilding. Generated nodes use prefixes such as:
region_
outer_wall_
corner_post_
inner_wall_
jpost_
collision_
door_
ring_
dcr_roof_
bridge_
structure_
label_
stim_
light_source_
treatment_chamber
This prevents stale geometry from remaining after an experiment configuration changes.
Coordinate Mapping
Preset coordinates use a two-dimensional arena coordinate system.
JSON Godot
x ───────────────────► X
y ───────────────────► Z
elevation ► Y
The renderer uses:
_scale := 0.1
Therefore:
Godot X = JSON x × 0.1
Godot Z = JSON y × 0.1
Godot Y = elevation × 0.1
For example, a JSON position of:
[50, 25]
is rendered at approximately:
Godot X = 5.0
Godot Z = 2.5
This allows the JSON arena coordinates to remain independent of the physical scale used by the Godot scene.
Floor Regions
Arena regions are created from their rect definition.
A rectangular region uses:
"rect": [x, y, width, height]
The renderer calculates the centre of the region and creates a mesh using its dimensions.
Regions can also specify a circular shape.
For rectangular regions:
rect
├── x
├── y
├── width
└── height
For circular regions, the renderer uses the configured radius.
Region elevation is supported, allowing regions to represent raised sections of an arena.
The renderer also supports region rotation through:
"rotation_y": 90
Region Materials
Each region can reference a material through:
"material_id": "solid_floor"
The renderer resolves the material against the material definitions in:
arena.materials
The legacy surface value can also be used as a fallback when resolving a region material.
Outer Walls
Outer walls are controlled by:
"use_outer_walls": true
The wall height is configured using:
"outer_wall_height": 28
The material is selected using:
"outer_wall_material_id": "clear_acrylic"
Four outer walls are generated:
North
South
West
East
Four corner posts are also generated.
Outer walls use collision geometry so that they act as boundaries for the arena.
Inner Walls
Inner walls are defined using a rectangular geometry, height, material and enabled state.
Example:
{
"id": "divider",
"rect": [48, 20, 4, 60],
"height": 20,
"material_id": "painted_steel",
"enabled": true
}
The renderer determines whether the wall is primarily horizontal or vertical from its dimensions.
Walls may also specify:
"rotation_y": 45
The visual mesh and collision body use the same rotation.
This ensures that rotated walls remain physically aligned with their visible geometry.
Door Rendering
Doors reference an existing inner wall:
"wall": "divider"
The renderer uses this relationship to determine where the opening must be placed.
When a wall contains one or more doors, the wall is segmented around the door openings rather than rendering a solid wall through the doorway.
Door orientation is also rotation-aware.
Doors can have the following states:
open
closed
locked
transitioning
Open
An open door:
- disables its collision shape
- sets collision layer and mask to zero
- displays a translucent visual
- rotates the visual door panel open
Closed
A closed door:
- keeps collision enabled
- displays the closed door material
Locked
A locked door:
- keeps collision enabled
- displays a red-emission visual state
Transitioning
A transitioning door:
- keeps collision enabled
- displays an amber-emission visual state
- partially rotates the visual panel
The renderer therefore keeps the visual representation and collision state synchronized.
Collision Geometry
The renderer creates collision geometry using Godot physics nodes.
Box-based arena objects use:
StaticBody3D
│
└── CollisionShape3D
│
└── BoxShape3D
Walls and doors therefore have physical collision geometry in addition to their visible meshes.
Collision geometry copies the position and rotation of the associated visual object.
Rotated Wall Collision
Rotated walls require special handling because a door opening must remain aligned with the wall's local coordinate system.
The renderer transforms door positions into wall-local coordinates before calculating the required gap.
Conceptually:
World position
│
▼
Wall-local coordinate system
│
▼
Door gap calculation
│
▼
Segmented wall
This prevents a rotated wall from producing incorrectly positioned door openings.
Structures
The renderer supports additional arena structures, including:
bridge
ramp
Bridge
A bridge can reference:
region_id
entry_region_id
exit_region_id
elevation
The bridge renderer creates:
- an elevated bridge base
- an entry ramp
- an exit ramp
The bridge can therefore represent a raised section connecting different regions.
The current bridge implementation focuses on rendering the elevated structure and its ramps. The bridge base and ramps are not treated as generic wall collision geometry by the renderer.
Ramp
Ramps are created as thin box meshes rotated according to the required slope.
This allows elevated and sloped regions to be visually represented without requiring a separate terrain system.
DCR Roof
Regions marked:
"covered": true
can receive a DCR roof.
The renderer creates the roof at approximately the configured wall height and darkens the corresponding floor material.
This provides visual separation between covered and uncovered regions.
Stimuli
Stimuli are represented visually using:
- a sphere marker
- a radius indicator
- a label
Light stimuli additionally create a Godot light source.
The renderer therefore provides both a visible stimulus location and an indication of the stimulus's effective radius.
Treatment Chamber
An optional treatment chamber can be rendered from the arena configuration.
The chamber can specify:
id
label
position
size
rotation_y
material_id
enabled
collidable
This allows treatment-related arena geometry to be represented directly in the 3D scene.
Material System
Materials are resolved using the material definitions maintained by the experiment system.
The renderer uses the material's visual properties, including:
albedo colour
roughness
metallic
transparency
The supported default material IDs are:
| Material | Purpose |
|---|---|
solid_floor | Standard arena floor |
rubber | Rubber-like surface |
wire_mesh | Transparent mesh-like surface |
wood_chip | Natural bedding surface |
painted_steel | Metal wall and structure surface |
clear_acrylic | Transparent enclosure surface |
Unknown material IDs use the renderer's fallback appearance instead of causing the entire arena render to fail.
Transparency Handling
Transparent materials require explicit Godot transparency configuration.
The material renderer checks whether the configured transparency is greater than zero.
For transparent materials it enables:
BaseMaterial3D.TRANSPARENCY_ALPHA
and calculates the displayed alpha from the configured transparency value.
Conceptually:
transparency = 0.55
alpha = 1.0 - 0.55
= 0.45
This ensures materials such as clear_acrylic and wire_mesh are rendered as transparent rather than appearing as opaque surfaces.
Camera System
The arena supports three camera modes.
Orbit View
The orbit camera provides a conventional inspection view around the arena.
Controls:
Left drag → rotate
Right drag → pan
Wheel → zoom
The orbit pitch is constrained to prevent the camera from flipping.
The orbit distance is constrained between a minimum and maximum range.
Zooming towards the mouse position also adjusts the orbit target so that the view remains focused on the area being inspected.
Free Fly
Free-fly mode provides first-person style arena navigation.
Controls:
W/A/S/D → movement
Q/E → vertical movement
Shift → faster movement
Left drag → look around
The free camera uses configurable mouse sensitivity and horizontal/vertical inversion.
Follow Rat
Follow Rat mode keeps the camera positioned relative to the simulated rat.
The camera follows the rat using smoothing rather than snapping directly to every position update.
The follow camera supports:
Left drag → look around the rat
Wheel → change follow distance
The follow distance and pitch are constrained to sensible ranges.
Camera Collision
The camera performs a raycast from its target towards its desired position.
If an obstacle is detected, the camera is moved towards the collision point and offset slightly along the collision normal.
Conceptually:
Target
│
│ desired camera path
▼
Obstacle
│
▼
Collision point
│
▼
Camera moved before entering obstacle
This prevents the camera from passing directly through arena geometry.
Camera Reset
Resetting the camera restores the default orbit configuration.
The default orbit configuration includes:
Distance: 8.8
Pitch: -55°
Yaw: 0°
The target is reset to the centre of the arena.
Renderer Responsibilities
The renderer is responsible for:
- converting arena data into 3D geometry
- creating floor regions
- rendering labels
- generating outer walls
- generating inner walls
- creating door openings
- updating door visuals
- enabling and disabling door collision
- rendering structures
- rendering stimuli
- rendering treatment chambers
- applying material properties
- rendering transparent materials
- providing camera controls
- preventing camera geometry penetration
- rebuilding the scene when the experiment snapshot changes
The renderer does not own the experiment configuration itself. It visualizes the configuration supplied by the application.
Related Files
src/app/arena_3d.gd
src/app/arena_view.gd
src/app/panels/arena_panel.gd
src/app/panels/arena_panel.tscn
src/app/services/experiment_migrator.gd
The arena renderer therefore acts as the visual and interactive 3D layer between the experiment data model and the user interface.