simvx.graphics.renderer.reflection_probe_pack

ReflectionProbe3D std430 box-record packing: backend-agnostic, numpy only.

The per-probe box record (Probe in cube_textured.frag / the ProbeBuffer SSBO) is shared by the desktop Vulkan reflection_probe_pass (which uploads it to a GPU buffer indexed by capture slot) and the web export’s scene3d_serializer (which streams it to the browser WebGPU runtime). Keeping the packing here, free of any vulkan import, lets the web export bundle it into Pyodide without dragging in the desktop graphics stack. Both backends march the identical 48-byte std430 record so the same scene reflects identically.

Slot ownership differs by backend. Desktop assigns the cube-array slot inside the capture pass and writes each record at off = 16 + slot*48 with centre_slice.w = slot*6. On web the capture pass (reflection_probe_pass.js) owns slotting, so the wire records are emitted in probe order, each prefixed with a stable probe id (a u32). The JS runtime resolves id -> slot against the live capture pass and patches centre_slice.w = slot*6 before upload, so the shader still sees the desktop centre_slice.w / 6.0 array layer.

Module Contents

Functions

build_probe_records

Pack ReflectionProbe3D nodes into the web wire byte array.

Data

API

simvx.graphics.renderer.reflection_probe_pack.__all__

[‘MAX_PROBES’, ‘PROBE_RECORD_STRIDE’, ‘PROBE_WIRE_STRIDE’, ‘SCHED_EVERY_FRAME’, ‘SCHED_MODE_ALWAYS’,…

simvx.graphics.renderer.reflection_probe_pack.MAX_PROBES

8

simvx.graphics.renderer.reflection_probe_pack.PROBE_RECORD_STRIDE

48

simvx.graphics.renderer.reflection_probe_pack.PROBE_WIRE_STRIDE

None

simvx.graphics.renderer.reflection_probe_pack.SCHED_MODE_ALWAYS

1

simvx.graphics.renderer.reflection_probe_pack.SCHED_EVERY_FRAME

2

simvx.graphics.renderer.reflection_probe_pack.SCHED_UPDATE_REQUESTED

4

simvx.graphics.renderer.reflection_probe_pack.build_probe_records(probes: list[Any]) tuple[numpy.ndarray, int][source]

Pack ReflectionProbe3D nodes into the web wire byte array.

Returns (bytes_array, count) where count is clamped to MAX_PROBES. Each PROBE_WIRE_STRIDE-byte record is::

u32  probe id            (stable per-node id; JS resolves id -> slot)
vec4 centre_slice        (xyz = capture_position, w = 0.0 placeholder*)
vec4 half_extent_intensity (xyz = size, w = intensity)
vec4 flags               (x = box_projection, y = blend_distance,
                          z = scheduling bitfield, w = 0)

* centre_slice.w is a placeholder on the wire; the JS runtime overwrites it with slot * 6 once the capture pass has assigned the cube-array slot, so the shader’s centre_slice.w / 6.0 array layer matches the desktop. The xyz/intensity/box_projection/blend_distance fields are byte-identical to the desktop _upload_boxes pack (reflection_probe_pass.py). flags.z is a reserved std430 field the shader ignores; it carries the capture-pass scheduling bits (SCHED_*) so the wire record fully describes the probe.