Any 3D object file → a hologram¶
Command: quiltwright mesh
Module: quiltwright.cycles (mesh_bounds, frame_camera, autoframe_camera)
If you have a mesh file, you have a hologram — the only missing piece is where to put the camera, and that can be measured.
Quiltwright's Cycles backend already imports every mesh format
Blender can read — glTF/GLB, OBJ, STL, PLY, USD, FBX, Alembic — and renders the
textures and PBR materials the file carries. What it does not get from an
imported mesh is a camera: a .blend can carry its own, but an OBJ or a GLB
off a modeling tool, a photogrammetry scan, an asset library, or an AI
generator such as Meshy cannot. Its scale, origin and
up-axis after import are all unknown, so a hand-written CyclesCamera is
guesswork — and the wrong guess renders an empty frame or a subject jammed
against the edge.
This is the piece that closes that gap. It measures the imported bounds and frames them, so an arbitrary object file becomes a quilt in one command.
The one command¶
quiltwright mesh model.glb
That probes the mesh's bounds, places a front-on camera at the distance that fills the view, path-traces the sweep, and writes a quilt. Common variations:
# Fast single-view still while you dial in lighting and view
quiltwright mesh scan.fbx --still --lighting sky
# A finished portrait quilt cast straight to the display
quiltwright mesh asset.obj --device 27-portrait --samples 256 --cast
# A three-quarter view instead of dead-on, wider lens
quiltwright mesh statue.ply --view-direction 0.5 -1 0.3 --fov 20
| Flag | What it does |
|---|---|
--device |
Target display preset (portrait default; 27-portrait, go, …) |
--lighting |
studio (default), soft, sky, or a path to an .hdr/.exr — an imported mesh has no lights, and a path tracer renders an unlit scene black |
--fov |
Vertical field of view; the framing distance follows from it |
--view-direction |
Direction from the object center to the eye (default 0 -1 0, front-on) |
--margin |
Framing headroom beyond a tight fit (1.2 default; 1.0 is exactly tight) |
--samples |
Cycles samples per pixel (128 default; 64 previews, 256 for finals) |
--compute |
Cycles compute device: auto (default, GPU first), gpu, cpu |
--view-transform |
OCIO view transform (Standard default; see cycles.md) |
--still |
One center view as a flat image at the device's aspect, instead of a full quilt — the fast way to check framing |
--preview |
Quarter-size quilt, for iterating |
--cast |
Send the finished quilt to Looking Glass Bridge |
How the framing works¶
The mesh is imported once to measure its world-space bounding box, through the same importer the render uses — so the box is exactly what the render will see, with the file's transforms and axis conversion already applied. The camera is then placed so the box's enclosing sphere (half the diagonal, so the whole object stays framed from any viewing direction) fills the field of view, using the exact spherical relation
sin(fov / 2) = radius / distance
rather than the small-angle tangent, since object-centric FOVs (~14–30°) are
not small angles. The eye sits along --view-direction from the bounds center,
aimed back at that center — which becomes the holographic focal plane.
Geometry nearer the camera floats out of the display; geometry beyond it
recedes.
In Python¶
The script is thin over three public functions, useful on their own when you want the pieces:
from quiltwright.cycles import mesh_bounds, frame_camera, render_cycles_quilt
from quiltwright.quilt import QUILT_PRESETS, save_quilt
lo, hi = mesh_bounds("dragon.glb") # world-space (min, max) corners
camera = frame_camera(lo, hi, fov=14.0) # a CyclesCamera aimed at the center
quilt = render_cycles_quilt("dragon.glb", QUILT_PRESETS["portrait"], camera,
samples=192, lighting="studio")
save_quilt(quilt, "dragon", QUILT_PRESETS["portrait"])
autoframe_camera("dragon.glb", fov=14.0) composes the first two into one call.
Because the result is an ordinary CyclesCamera, the POV-Ray backend's
depth budget applies unchanged — run format_depth_budget() on it
before committing to a 48-view render, exactly as for any hand-placed camera.
frame_camera is pure arithmetic (no Blender), so the framing is unit-tested
directly; mesh_bounds and the end-to-end path are covered against a real
import in tests/test_cycles.py.
Notes from real assets¶
- Prefer GLB when your tool offers it. It embeds geometry, textures and PBR materials in one binary file — nothing to unzip, no external texture folder to keep beside the mesh. An FBX or OBJ from the same tool usually references its textures as sibling files, and loses them if that folder goes missing.
- A baked ground plane frames badly. Some generators (Meshy among them) export the object sitting on a small base or disc. It reads as a ragged shelf under the subject and enlarges the bounds; delete that ground mesh in the source tool before export for a clean float.
- Lighting is the biggest lever.
studiofloats the object in near-black for a hero-object look;softis an even, neutral clay reading good for seeing the model;skydrops it into daylight with a horizon; an HDRI gives glossy and glazed surfaces something real to reflect. See cycles.md for the rigs in detail.
What this is not¶
For a scene composed in Python — a PyVista plotter, or geometry built from
analytic primitives — you do not need this: render_cycles_quilt_from_plotter()
frames a plotter directly (see cycles.md), and the POV-Ray
generators frame their own scenes. This path is specifically for a finished
object file that arrived from elsewhere with no camera and no lights.