PyVista backend (lfd)¶
quiltwright.lfd
¶
Looking Glass Quilt Renderer¶
Renders any PyVista scene into a quilt -- the tiled multi-view image format used by Looking Glass holographic light-field displays.
A quilt packs N renders of the same scene, captured from camera positions
swept horizontally across a viewing cone, into a single image. Views are
tiled left-to-right, bottom-to-top: view 0 (leftmost camera) sits at the
bottom-left tile and view N-1 (rightmost camera) at the top-right. Looking
Glass software (Bridge, Studio) detects quilt settings from the filename
suffix _qs<cols>x<rows>a<aspect>.png, so files saved through
:func:save_quilt are recognised automatically.
Each view uses an off-axis (asymmetric-frustum) projection rather than a "toe-in" rotation: the camera translates along its horizontal axis while the frustum is sheared back toward the focal plane. This keeps the focal plane identical across views -- the geometric requirement for the display's lenticular optics to fuse the views into a stable hologram. Content at the focal plane appears at the physical screen surface; content nearer/farther floats in front of / behind the glass.
Quilt geometry (:class:QuiltSpec, :data:QUILT_PRESETS,
:func:assemble_quilt, :func:save_quilt) lives in :mod:quiltwright.quilt.
Bridge control (:func:cast_quilt) lives in :mod:quiltwright.bridge. Both
are re-exported from here so existing from quiltwright.lfd import ...
callers keep working.
Optional dependencies -- install the viz extras group::
poetry install --with viz # pyvista, pillow, scipy, ...
Typical usage::
import pyvista as pv
from quiltwright.lfd import QUILT_PRESETS, render_quilt, save_quilt
p = pv.Plotter(off_screen=True)
p.add_mesh(pv.ParametricTorus())
spec = QUILT_PRESETS["portrait"]
quilt = render_quilt(p, spec)
save_quilt(quilt, "torus", spec) # -> torus_qs8x6a0.75.png
p.close()
The saved quilt can be displayed on the device by dragging it into Looking
Glass Studio, or cast directly from Python via :func:cast_quilt if Looking
Glass Bridge is running on the machine driving the display.
Part of Quiltwright -- https://github.com/Flux-Frontiers/quiltwright Author: Eric G. Suchanek, PhD
QuiltSpec(columns, rows, quilt_width, quilt_height, aspect, view_cone=35.0)
dataclass
¶
Geometry of a quilt: tiling grid, total pixel size, and view cone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
columns
|
int
|
Number of view tiles per quilt row. |
required |
rows
|
int
|
Number of view tiles per quilt column. |
required |
quilt_width
|
int
|
Total quilt width in pixels. |
required |
quilt_height
|
int
|
Total quilt height in pixels. |
required |
aspect
|
float
|
Aspect ratio (width / height) of a single view, which matches the target display's aspect. Embedded in the quilt filename so Looking Glass software can configure playback correctly. |
required |
view_cone
|
float
|
Total horizontal sweep of the camera in degrees. Looking Glass documents 35° as the standard rendering cone (the physical display cone is wider, ~40-58° depending on model; rendering slightly narrower adds apparent depth). |
35.0
|
n_views
property
¶
Total number of views in the quilt.
tile_height
property
¶
Height of a single view tile in pixels.
tile_width
property
¶
Width of a single view tile in pixels.
filename(stem, ext='png')
¶
Quilt filename with the metadata suffix Looking Glass software parses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stem
|
str
|
Base name without extension (e.g. |
required |
ext
|
str
|
File extension without the dot. |
'png'
|
Returns:
| Type | Description |
|---|---|
str
|
e.g. |
Source code in src/quiltwright/quilt.py
95 96 97 98 99 100 101 102 | |
scaled(factor)
¶
Same view grid at a fraction of the pixel size.
Casting at full preset size is rarely what you want: rendering costs about a second, but the wait is Bridge loading the resulting PNG, and that scales with its area. Halving the linear size quarters it.
The scaled dimensions are rounded down to a multiple of the tile grid, which is the part that is easy to get wrong: scale naively and the quilt no longer divides evenly into tiles, so every view lands on a fractional pixel boundary and the whole light field smears.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factor
|
float
|
Linear scale factor, e.g. |
required |
Returns:
| Type | Description |
|---|---|
QuiltSpec
|
A new :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If factor is not positive, or scales the quilt below one pixel per tile. |
Source code in src/quiltwright/quilt.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
still(height=1100)
¶
The same view, once, as a flat image at this device's aspect.
A one-tile "quilt" is the cheapest way to check framing, lighting and
materials before paying for the whole sweep, and it is what the
gallery images are: :func:view_offsets returns a single zero offset
at n_views == 1, so the render is the centre view and nothing
else. The width follows :attr:aspect rather than being fixed, so
the still is framed like the panel it is standing in for -- a still
of a landscape device is a landscape image.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
height
|
int
|
Image height in pixels. |
1100
|
Returns:
| Type | Description |
|---|---|
QuiltSpec
|
A new 1x1 :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If height is not positive. |
Source code in src/quiltwright/quilt.py
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
tile_origin(view_index)
¶
Pixel (x, y) of a view's top-left corner within the quilt image.
Quilt convention: view 0 at the bottom-left, advancing
left-to-right then bottom-to-top. The returned y is measured
from the image top (numpy/PIL row order).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
view_index
|
int
|
View number in |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
|
Source code in src/quiltwright/quilt.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
with_grid(columns, rows)
¶
Same quilt at a different view-grid density.
Total quilt pixels stay fixed, so more views means fewer pixels per view: the device's lenticular optics interpolate between views, so extra views give smoother look-around at the cost of per-view sharpness. The official presets are the factory-calibrated balance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
columns
|
int
|
New number of tile columns. |
required |
rows
|
int
|
New number of tile rows. |
required |
Returns:
| Type | Description |
|---|---|
QuiltSpec
|
A new :class: |
Source code in src/quiltwright/quilt.py
104 105 106 107 108 109 110 111 112 113 114 115 116 | |
assemble_quilt(views, spec)
¶
Tile per-view images into a single quilt image.
This is the renderer-agnostic half of quilt production: it takes views
that some backend already rendered -- VTK via :func:render_quilt, a
ray-tracer via :mod:quiltwright.povray -- and lays them out in quilt
order. Views are consumed lazily, so a backend can stream them without
holding all n_views frames in memory at once.
Views whose pixel size differs from the tile size are resampled, which is what makes anamorphic quilts (tile pixel aspect != view aspect, e.g. the 27" presets) come out correctly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
views
|
Iterable[ndarray]
|
Iterable of |
required |
spec
|
QuiltSpec
|
Quilt specification (grid, size, aspect). |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the number of views does not match |
Source code in src/quiltwright/quilt.py
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | |
camera_frame(camera)
¶
Decompose a vtkCamera into position, focal point, right/up basis, distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
A |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray, ndarray, ndarray, float]
|
|
Source code in src/quiltwright/lfd.py
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | |
cast_quilt(quilt_path, spec, *, bridge_url=BRIDGE_URL, playlist='quiltwright', timeout=10.0, head_index=-1)
¶
Show a saved quilt on the connected Looking Glass via Bridge.
Requires Looking Glass Bridge <https://lookingglassfactory.com/software/looking-glass-bridge>_
(>= 2.2) running on the machine the display is plugged into. Follows
Bridge's orchestration sequence: enter orchestration, show the display
window, create a playlist holding the quilt, and play it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quilt_path
|
str | Path
|
Path to a quilt PNG on the Bridge host's filesystem. |
required |
spec
|
QuiltSpec
|
Quilt specification (tiling + aspect sent to Bridge). |
required |
bridge_url
|
str
|
Base URL of the Bridge HTTP API. |
BRIDGE_URL
|
playlist
|
str
|
Name of the Bridge playlist to (re)create. |
'quiltwright'
|
timeout
|
float
|
HTTP timeout in seconds per request. |
10.0
|
head_index
|
int
|
Which Bridge output device to play on. |
-1
|
Returns:
| Type | Description |
|---|---|
dict
|
Decoded JSON response of the final |
Source code in src/quiltwright/bridge.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
depth_report(plotter, spec, *, fov=14.0, zoom=None, labels=DEPTH_LABELS, extra_depths=None, soft_px=5.5)
¶
Depth budget for a PyVista scene, as a report to print before rendering.
The PyVista counterpart to
:func:~quiltwright.povray.format_depth_budget. Pass the same fov
and zoom you will pass to :func:render_quilt, so the numbers
describe the render you are about to make.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
Plotter with the scene composed and the camera framed. |
required | |
spec
|
QuiltSpec
|
Quilt specification. |
required |
fov
|
float | None
|
FOV that will be used for the render; see :func: |
14.0
|
zoom
|
float | None
|
Zoom that will be used for the render. |
None
|
labels
|
tuple[str, str, str]
|
Names for the near, focal and far depths. |
DEPTH_LABELS
|
extra_depths
|
Mapping[str, float] | None
|
Further labelled depths to include, e.g.
|
None
|
soft_px
|
float
|
Disparity above which a row is flagged as soft. |
5.5
|
Returns:
| Type | Description |
|---|---|
str
|
Multi-line report. |
Source code in src/quiltwright/lfd.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | |
find_ffmpeg()
¶
Locate an ffmpeg binary: system PATH first, then imageio-ffmpeg's.
Returns:
| Type | Description |
|---|---|
str
|
Path to an ffmpeg executable. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no ffmpeg can be found. |
Source code in src/quiltwright/runtime.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
focal_distance_for_range(near, far)
¶
Focal distance that balances disparity between the nearest and farthest content -- their harmonic mean.
Disparity grows with |1 - Z/depth|, which is asymmetric in depth:
placing the focal plane at the arithmetic midpoint leaves the near
content far worse off than the far content. Equalising the two,
Z/near - 1 = 1 - Z/far, gives Z = 2/(1/near + 1/far).
With far at infinity this reduces to 2 * near.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
near
|
float
|
Distance to the nearest content, in scene units. |
required |
far
|
float
|
Distance to the farthest content; may be |
required |
Returns:
| Type | Description |
|---|---|
float
|
Focal distance to aim the camera at. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If near is not positive or exceeds far. |
Source code in src/quiltwright/quilt.py
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | |
frame_and_focus(plotter, *, fov=14.0, margin=1.15)
¶
Frame a PyVista scene tightly at its final view, and focus it.
The PyVista counterpart to
:func:~quiltwright.cycles.frame_camera, and the thing to call once the
camera is pointing where you want it. reset_camera() fits the
un-tilted bounds, so once the view is tilted -- by an orbit, or an
explicit camera_position -- that framing is too loose and the subject
reads as small with a lot of empty margin: ask for a mountain hologram
and get a speck.
This re-fits from scratch at the final view direction. The eight
bounding-box corners are projected onto the camera's own right/up/forward
axes, which accounts for foreshortening -- a flat, elongated terrain
viewed obliquely needs far less distance than its bounding sphere would
suggest -- giving the tightest distance that still keeps every corner in
frame at the target FOV and window aspect. The focal plane then goes at
the harmonic mean of the resulting near and far depths, the same balance
:func:focal_distance_for_range gives the POV-Ray path, measured from
exact geometry rather than a rendered plane sweep.
The camera is modified, unlike :func:scene_depths, which measures
copies: position, view angle and focal point are all overwritten. Only
the view direction survives. Having locked the camera here, pass
fov=None to :func:render_quilt so it does not frame the scene a
second time from scratch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
A |
required | |
fov
|
float
|
Vertical field of view to lock the camera to, in degrees. Must match what the render actually uses, or the depth budget describes a different camera than the one that renders. |
14.0
|
margin
|
float
|
Headroom beyond the tight corner-projected fit, as a
fraction -- |
1.15
|
Returns:
| Type | Description |
|---|---|
tuple[float, float, float]
|
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If PyVista is not installed. |
Source code in src/quiltwright/lfd.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
pause_quilt(*, bridge_url=BRIDGE_URL, timeout=10.0)
¶
Pause playback on the connected Looking Glass.
Freezes the current frame; the playlist and its position are retained,
so :func:resume_quilt continues from where it left off. This is
Bridge's transport control group -- there is no stop_playlist or
pause_playlist endpoint (a guessed endpoint name doesn't 404: Bridge
answers with 200 OK and an empty body, indistinguishable from a slow
success unless you check that the response has no status field).
Confirmed against the endpoint list in the official
bridge.js <https://github.com/Looking-Glass/bridge.js>_ SDK source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bridge_url
|
str
|
Base URL of the Bridge HTTP API. |
BRIDGE_URL
|
timeout
|
float
|
HTTP timeout in seconds. |
10.0
|
Returns:
| Type | Description |
|---|---|
dict
|
Decoded JSON response of the |
Source code in src/quiltwright/bridge.py
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
render_quilt(plotter, spec, *, view_cone=None, fov=14.0, zoom=None)
¶
Render the plotter's scene into a quilt image.
The plotter's current camera defines the centre view; its focal point
becomes the holographic focal plane (the physical surface of the
display). Position the camera before calling -- e.g. via
plotter.camera_position or plotter.reset_camera() -- exactly as
you would for a normal screenshot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
An off-screen |
required | |
spec
|
QuiltSpec
|
Quilt specification (grid, size, aspect, cone). |
required |
view_cone
|
float | None
|
Override the spec's view cone in degrees. |
None
|
fov
|
float | None
|
Vertical field of view in degrees for the quilt cameras.
Looking Glass recommends ~14° (matches real-world parallax at
typical viewing distance); the camera is dollied back so the scene
stays the same size in frame. Pass |
14.0
|
zoom
|
float | None
|
Optional camera zoom factor applied after framing, before the view sweep. Values > 1 make the subject fill more of each tile, which is what drives perceived depth -- parallax is proportional to on-screen size, so a subject occupying a third of the frame yields a third of the available look-around. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
Source code in src/quiltwright/lfd.py
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | |
render_quilt_video(plotter, spec, out_stem, *, n_frames=180, fps=24, orbit_degrees=360.0, view_cone=None, fov=14.0, zoom=None, crf=18, on_frame=None, progress=True)
¶
Render an animated quilt video (default: a full turntable orbit).
Renders one quilt per frame, rotating the camera about the focal point
between frames, then encodes the sequence to MP4 per the Looking Glass
quilt-video spec (yuv420p; H.264, or HEVC for 8K quilts). The
filename carries the _qs<cols>x<rows>a<aspect> suffix so Studio /
Bridge auto-detect playback settings.
Note the cost: a Portrait video renders n_frames x 48 views.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
An off-screen |
required | |
spec
|
QuiltSpec
|
Quilt specification (grid, size, aspect, cone). |
required |
out_stem
|
str | Path
|
Output path; quilt suffix + |
required |
n_frames
|
int
|
Number of video frames (with fps sets loop duration). |
180
|
orbit_degrees
|
float
|
Total camera orbit over the clip; 360 loops seamlessly. Pass 0 to disable the turntable (use on_frame). |
360.0
|
view_cone
|
float | None
|
Override the spec's view cone in degrees. |
None
|
fov
|
float | None
|
Per-view vertical FOV; see :func: |
14.0
|
zoom
|
float | None
|
Camera dolly factor; see :func: |
None
|
crf
|
int
|
x264/x265 quality (lower = better; 15-20 sensible). |
18
|
on_frame
|
Optional |
None
|
|
progress
|
bool
|
Print a progress line while rendering. |
True
|
Returns:
| Type | Description |
|---|---|
Path
|
Path of the quilt MP4 written. |
Source code in src/quiltwright/lfd.py
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | |
resume_quilt(*, bridge_url=BRIDGE_URL, timeout=10.0)
¶
Resume playback after :func:pause_quilt.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bridge_url
|
str
|
Base URL of the Bridge HTTP API. |
BRIDGE_URL
|
timeout
|
float
|
HTTP timeout in seconds. |
10.0
|
Returns:
| Type | Description |
|---|---|
dict
|
Decoded JSON response of the |
Source code in src/quiltwright/bridge.py
207 208 209 210 211 212 213 214 215 | |
save_and_cast_quilt(quilt, stem, spec, *, cast=True, bridge_url=BRIDGE_URL, timeout=10.0)
¶
Write a quilt to disk, then hand Bridge the path to it.
The two calls this composes take different argument types, and the mistake
is invisible until a panel is connected: :func:save_quilt takes the
array, :func:cast_quilt takes a path. Passing the array to the caster
raises argument should be a str or an os.PathLike object ... not
'ndarray' -- after the render, which for a ray-traced quilt is minutes
later and the worst possible moment to find out.
The file is confirmed on disk before Bridge is contacted, and a failed cast is returned rather than raised, so losing the display never costs the render.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quilt
|
ndarray
|
RGB array from :func: |
required |
stem
|
str | Path
|
Output path without the quilt suffix or extension. |
required |
spec
|
QuiltSpec
|
Quilt specification, used for both the filename and Bridge. |
required |
cast
|
bool
|
Whether to push the written file to the Looking Glass.
|
True
|
bridge_url
|
str
|
Base URL of the Bridge HTTP API. |
BRIDGE_URL
|
timeout
|
float
|
HTTP timeout in seconds per Bridge request. |
10.0
|
Returns:
| Type | Description |
|---|---|
tuple[Path, str | None]
|
|
Source code in src/quiltwright/bridge.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |
save_quilt(quilt, stem, spec)
¶
Write a quilt to PNG using the Looking Glass filename convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quilt
|
ndarray
|
RGB array from :func: |
required |
stem
|
str | Path
|
Output path without the quilt suffix or extension.
Any |
required |
spec
|
QuiltSpec
|
Quilt specification (encodes the suffix metadata). |
required |
Returns:
| Type | Description |
|---|---|
Path
|
The path written, e.g. |
Source code in src/quiltwright/quilt.py
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | |
scene_depths(plotter, *, fov=14.0, zoom=None, labels=DEPTH_LABELS)
¶
Near, focal and far distances for the scene, as :func:render_quilt will see them.
Measures the plotter's bounding box along the view axis, then applies the
same framing :func:render_quilt applies before sweeping -- narrowing the
FOV and dollying back, then the optional zoom dolly. Reading the camera
as-is instead is the tempting shortcut and it is wrong: the render's FOV
and focal distance are both different by then, so the disparity computed
from them describes a picture nobody is going to make. Nothing is
mutated; the arithmetic is done on copies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
A |
required | |
fov
|
float | None
|
The vertical FOV that will be passed to :func: |
14.0
|
zoom
|
float | None
|
The zoom that will be passed to :func: |
None
|
labels
|
tuple[str, str, str]
|
Names for the near, focal and far entries, in that order. |
DEPTH_LABELS
|
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Labelled distances from the render camera, in scene units,
ready to hand to :func: |
Source code in src/quiltwright/lfd.py
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | |
stop_quilt(*, bridge_url=BRIDGE_URL, timeout=10.0)
¶
Stop playback: pause the current frame and hide the display window.
Bridge's own bridge.js <https://github.com/Looking-Glass/bridge.js>_
SDK documents delete_playlist as the way to stop a playlist, and
an earlier version of this function called it. In testing it reliably
left Bridge unresponsive to every further HTTP call -- reproduced twice,
once mid-video and once on a single still image, so it isn't a
large-file decode race. This function deliberately avoids
delete_playlist and reaches the same end state (nothing visible,
playback halted) through calls already proven safe: the playlist from
:func:cast_quilt is left instantiated but paused and hidden, rather
than deleted, so :func:cast_quilt can safely replace it later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bridge_url
|
str
|
Base URL of the Bridge HTTP API. |
BRIDGE_URL
|
timeout
|
float
|
HTTP timeout in seconds. |
10.0
|
Returns:
| Type | Description |
|---|---|
dict
|
Decoded JSON response of the final |
Source code in src/quiltwright/bridge.py
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | |
sweep_spec(n_views, view_cone, tile_width, tile_height)
¶
Geometry for a plain ordered view sweep rather than a tiled quilt.
A quilt's view count is columns * rows, so a rectangular grid cannot
express a prime count. A single row can express any count at all, which
is what consumers that want the views as separate frames -- hologram
printers, lenticular interlacers -- actually ask for. The camera sweep is
identical either way; only the packing differs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_views
|
int
|
Number of views in the sweep. |
required |
view_cone
|
float
|
Total horizontal camera sweep in degrees. |
required |
tile_width
|
int
|
Pixel width of one view. |
required |
tile_height
|
int
|
Pixel height of one view. |
required |
Returns:
| Type | Description |
|---|---|
QuiltSpec
|
A single-row :class: |
Source code in src/quiltwright/quilt.py
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | |
view_disparity(spec, fov, focal_distance, depth)
¶
Pixel shift of a feature between adjacent quilt views.
This is the number that decides whether a hologram fuses. A lenticular display blends neighbouring views optically, so content that moves only a pixel or two between them reads as solid depth, while larger shifts read as ghosting or a visible stack of copies. Rendered scenes that "look fine" flat routinely blow this budget.
Derived from the off-axis projection: a point at depth along the view
axis lands at image coordinate (D/aspect)(x/depth + s(1/Z - 1/depth))
for eye offset s, so the shift across the whole cone is
[tan(cone/2)/tan(fov/2)] * (1 - Z/depth) * tile_height pixels, which
divided between n_views - 1 gaps gives this. The aspect ratio
cancels. Verified against ray-traced renders to within 0.5%.
Two consequences worth internalising: content at the focal plane has zero disparity, and a narrower FOV increases disparity, because it magnifies the scene and the parallax along with it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
QuiltSpec
|
Quilt specification (view count + cone angle + tile size). |
required |
fov
|
float
|
Vertical field of view in degrees. |
required |
focal_distance
|
float
|
Camera-to-focal-plane distance, in scene units. |
required |
depth
|
float
|
Distance of the content of interest from the camera, in
scene units. Use |
required |
Returns:
| Type | Description |
|---|---|
float
|
Adjacent-view shift in pixels. Roughly 4-5 px is the practical ceiling; beyond ~8 px expect visible ghosting on hard edges. |
Source code in src/quiltwright/quilt.py
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | |
view_offsets(spec, distance)
¶
Horizontal camera offsets (world units) for every view in the quilt.
Cameras sweep a total angle of spec.view_cone centred on the base
camera position, at constant distance from the focal plane. Offsets are
ordered to match quilt view order: view 0 is the leftmost camera.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
QuiltSpec
|
Quilt specification (view count + cone angle). |
required |
distance
|
float
|
Distance from camera to the focal plane. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Array of shape |
Source code in src/quiltwright/quilt.py
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | |