diff --git a/examples/volrover_live_sdf_deform.py b/examples/volrover_live_sdf_deform.py deleted file mode 100644 index d2d6b4b..0000000 --- a/examples/volrover_live_sdf_deform.py +++ /dev/null @@ -1,84 +0,0 @@ -# examples/volrover_live_sdf_deform.py — a LIVE, fast SDF deformation demo. -# -# Generates a signed-distance field (SDF) volume from the built-in Stanford bunny -# (or any cvc::geometry), adds it to the running volrover3 scene as a volume, then -# each time slice mutates the voxel values IN PLACE from Python — via the zero-copy -# numpy view over the volume's buffer (volume.grid()) — and re-uploads, so the -# surface visibly deforms/decays in real time. -# -# HOW IT WORKS -# * pycvc.sdf(app, geom, dim) -> cvc::volume (the SDF field). -# * vol.grid() is a NUMPY VIEW of the volume's voxel buffer (no copy) — writing -# to it writes the C++ voxels directly. -# * node.setVolume(vol) re-copies the (now-modified) voxels into the VTK volume -# mapper and re-renders. For a modest field this per-frame refresh is sub-ms — -# "live and fast". (The zero-copy CUDA<->GL path that removes even this refresh -# copy is the roadmap §C GPU-geometry / interop item.) -# -# RUN: volrover3 Jobs tab -> Load Script -> Run as Job (needs numpy). - -import math - -import numpy as np - -try: - import pycvc - import vrhost -except ImportError as exc: # pragma: no cover - only meaningful inside volrover3 - raise RuntimeError( - "volrover_live_sdf_deform: run INSIDE volrover3 (Jobs tab -> Load Script)." - ) from exc - -_app = vrhost.app() -_sg = vrhost.scene() - -# ── build the source geometry: the built-in bunny (a procedural .bunny mesh) ── -_bunny = pycvc.geometry(_app) -_bunny.load("bunny.bunny") # the .bunny handler is procedural (CVC_GEOMETRY_ENABLE_BUNNY) -print("live-sdf: bunny has %d verts / %d tris — computing SDF..." % - (_bunny.num_vertices(), _bunny.num_triangles())) - -# ── compute the SDF volume from the mesh ───────────────────────────────────── -# pycvc flattens cvc::sdf's `dimension` arg to (nx, ny, nz); bbox/algorithm use -# their defaults (the mesh extents). -_N = 64 -_vol = pycvc.sdf(_app, _bunny, _N, _N, _N) # SDF over the mesh's extents -print("live-sdf: SDF volume %dx%dx%d built." % (_N, _N, _N)) - -# ── add it to the live scene as a volume, with a surface-highlighting TF ────── -_sg.addGraphics("sdf", _vol) -_node = _sg.getGraphics("sdf") -# A transfer function peaked around the zero level-set makes the SDF's *surface* -# (distance ~ 0) opaque and the interior/exterior fade out — so deforming the -# field reads as the surface moving. (colorTable rows: scalar, r, g, b; opacity -# rows: scalar, alpha — normalized 0..1 over the value range; see VolumeNode.) -_node.setDefaultTransferFunction() - -# ── the zero-copy voxel view we mutate every frame ─────────────────────────── -_grid = _vol.grid() # numpy view of the voxel buffer (no copy) -_grid_flat = _grid.reshape(-1) -_n = _grid_flat.size -# precompute a per-voxel spatial phase so we can add a travelling ripple cheaply -_zz, _yy, _xx = np.meshgrid( - np.linspace(0, 1, _N), np.linspace(0, 1, _N), np.linspace(0, 1, _N), indexing="ij" -) -_phase = (2.0 * math.pi * (_xx + _yy + _zz)).reshape(-1).astype(_grid_flat.dtype) -_base = _grid_flat.copy() # the pristine SDF to modulate around - -print("live-sdf: driving live deformation — the bunny SDF surface ripples + erodes. Jobs tab -> Stop.") - -_t = 0.0 - - -def step(dt): - global _t - _t += dt - # Deform: a travelling sinusoidal ripple on the distance field + a slow erosion - # (adding a growing positive bias pushes the zero-crossing inward = decay). - ripple = 2.0 * np.sin(_phase - 3.0 * _t) - erode = 0.6 * _t - _grid_flat[:] = _base + ripple + erode # in-place write into the voxel buffer - _node.setVolume(_vol) # re-upload the modified voxels + re-render - _sg.processEvents() - if _t > 8.0: # loop the decay so the demo runs indefinitely - _t = 0.0 diff --git a/examples/volrover_live_texture.py b/examples/volrover_live_texture.py deleted file mode 100644 index b63831d..0000000 --- a/examples/volrover_live_texture.py +++ /dev/null @@ -1,82 +0,0 @@ -# examples/volrover_live_texture.py — LIVE, zero-copy texture editing on a mesh. -# -# Maps a texture (a cvc::image) onto a UV'd mesh in the running volrover3 scene, -# then edits the texture's PIXELS in place from Python each frame — via the -# zero-copy numpy view over the image buffer — and the mesh's surface texture -# updates live, with NO per-frame copies. -# -# This is the acceptance test for PHASE 5 (pycvc image + texture bindings) built on -# PHASE 2/4 (geometry UVs -> SetTCoords; GeometryNode::setTexture). It needs these -# binding additions, which are NOT in the shipped pycvc/pycvc_gl yet: -# * pycvc.image — the cvc::image value type (Phase 1) wrapped, with -# img.numpy() returning a zero-copy (H,W,C) view. -# * geometry.set_uvs(...) / uvs()— per-vertex UVs (Phase 2) on the pycvc geometry. -# * node.set_texture(img) — pycvc_gl binding of GeometryNode::setTexture, -# ideally the ZERO-COPY variant that wraps the -# image buffer (vtkUnsignedCharArray::SetArray) so -# the vtkTexture aliases img's storage. -# * node.texture_modified() — signal the vtkTexture changed (no re-copy), so -# an in-place pixel edit shows next render. -# Until then this script imports cleanly but raises a clear message at run time. -# (The fully zero-copy CUDA<->GL path is roadmap §C.) -# -# RUN: volrover3 Jobs tab -> Load Script -> Run as Job (needs numpy + Phase 5). - -import numpy as np - -try: - import pycvc - import pycvc_gl # noqa: F401 - import vrhost -except ImportError as exc: # pragma: no cover - raise RuntimeError( - "volrover_live_texture: run INSIDE volrover3 (Jobs tab -> Load Script)." - ) from exc - -_app = vrhost.app() -_sg = vrhost.scene() - -if not hasattr(pycvc, "image"): - raise RuntimeError( - "volrover_live_texture needs the Phase-5 pycvc.image + node.set_texture " - "bindings (not in this build yet). See the script header." - ) - -# ── a UV'd quad to paint on ────────────────────────────────────────────────── -_g = pycvc.geometry(_app) -_g.add_vertices([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]) -_g.add_triangles([0, 1, 2, 0, 2, 3]) -_g.set_uvs([0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]) # Phase-2 UVs -> SetTCoords -_sg.addGraphics("quad", _g) -_node = _sg.getGraphics("quad") - -# ── the texture: an RGBA8 cvc::image; set it once, then edit pixels in place ── -_W = _H = 256 -_tex = pycvc.image(_W, _H, pycvc.image.RGBA, pycvc.image.u8) -_node.set_texture(_tex) # Phase-4 setTexture, bound in Phase 5 (zero-copy variant) - -# zero-copy view of the SAME buffer the vtkTexture aliases — writes are live. -_pix = _tex.numpy() # (H, W, 4) uint8 - -# precompute coordinate grids for a cheap animated pattern -_yy, _xx = np.mgrid[0:_H, 0:_W].astype(np.float32) -_cx, _cy = _W / 2.0, _H / 2.0 - -print("live-texture: painting the quad's texture in place each frame (zero-copy). Jobs tab -> Stop.") - -_t = 0.0 - - -def step(dt): - global _t - _t += dt - # A travelling radial ripple painted straight into the texture's pixels. - r = np.hypot(_xx - _cx, _yy - _cy) - wave = 0.5 + 0.5 * np.sin(0.15 * r - 4.0 * _t) - ang = np.arctan2(_yy - _cy, _xx - _cx) - _pix[..., 0] = (255 * wave).astype(np.uint8) # R - _pix[..., 1] = (127 * (1.0 + np.sin(ang + _t))).astype(np.uint8) # G - _pix[..., 2] = (255 * (1.0 - wave)).astype(np.uint8) # B - _pix[..., 3] = 255 # A - _node.texture_modified() # mark the aliased vtkTexture dirty — no re-copy - _sg.processEvents()