Skip to content

fmri_surface_data.surface: space-matched default view, render perf fix, docs#89

Merged
torwager merged 4 commits into
masterfrom
surface-space-default-view
Jul 14, 2026
Merged

fmri_surface_data.surface: space-matched default view, render perf fix, docs#89
torwager merged 4 commits into
masterfrom
surface-space-default-view

Conversation

@torwager

Copy link
Copy Markdown
Contributor

Follow-up to #86 (the fmri_surface_data object). Three commits, cherry-picked onto current master so they apply cleanly on top of the squash-merge.

1. Space-matched default four-surface view

surface(obj) with no explicit surface argument now picks a four-surface view (L/R lateral + medial) matched to the object's surface_space, so data renders at native (or near-native) fidelity by default:

surface_space verts/hemi default view how it paints
fsLR_32k 32,492 foursurfaces_hcp native (direct)
fsaverage_164k 163,842 foursurfaces_freesurfer native (direct)
fsaverage6/5/4 40,962 / 10,242 / 2,562 foursurfaces_freesurfer resampled up to 164k (nearest, cached)
onavg_41k/10k 40,962 / 10,242 foursurfaces_hcp resampled to fs_LR (nearest, cached)

No new mesh assets needed: nested fsaverage spaces are subsets of fsaverage-164k and onavg is fs_LR-aligned via the vendored onavg spheres, so each renders on its parent/aligned display space through the fast, cached nearest resample already in render_layer_surfaces (prints a one-line message when it resamples). Previously every non-fs_LR/-164k space fell back to foursurfaces_hcp, forcing an unnecessary cross-family resample.

Also fixes a parser bug in @fmri_surface_data/surface.m: a bare surface keyword (surface(obj,'foursurfaces_hcp'), surface(obj,'hcp inflated left')) fell into the colour-option branch and indexed past the end of varargin. Non-mode tokens are now split into colour options vs surface directives; directives override the space-matched default view.

2. Render performance regression fix

Cortex-only fs_LR data on foursurfaces_hcp had regressed to ~48 s because incidental subcortical anatomy meshes triggered a needless volume projection. Now arbitrary (non-standard) meshes are deferred per view and projected only when no native/resampled cortical patch painted in that view — addblobs is back to ~0.2 s. to_display_volume also uses nearest (not barycentric) for its display-only cortex resample (~250× faster: 0.2 s vs 48 s; the barycentric weight-build was the entire bottleneck). Arbitrary-mesh renders (hires left, cutaway) drop from ~48 s to ~0.8 s.

3. Docs

Per-space default-view table added to both the comprehensive reference (CanlabCore/docs/) and the readthedocs functional index (docs/); refreshed the Surface-spaces section (all 7 spaces; resample_surface is implemented) and corrected the surface() space-mismatch text.

Tests

New test_default_view_matches_space in canlab_test_surface_render.m. Surface render + fmridisplay suites pass locally (24/24) on R2026a + SPM25.

🤖 Generated with Claude Code

torwager and others added 4 commits July 14, 2026 15:36
…est for display volume

surface()/addblobs() for cortex-only fs_LR data on a mixed patch layout
(e.g. foursurfaces_hcp) became very slow: incidental subcortical anatomy
meshes triggered a full barycentric resample + surf2vol projection even
though the cortex painted natively on its own 32492 mesh.

render_layer_surfaces (paint_surface_native_layer):
 - Per view, defer arbitrary (non-standard) meshes and project to a volume
   ONLY when no native/resampled cortical patch was painted in that view.
   Cortex-only data on foursurfaces_hcp now paints natively with no
   projection (addblobs ~0.2s vs ~48s before).
 - Print a one-time message when resampling onto a standard mesh or
   projecting to a volume, so the workspace shows when work is happening.

to_display_volume: resample cortex to fsaverage-164k by nearest neighbour
instead of barycentric. This volume is display-only (sampled at mesh
vertices to colour a patch); at 164k density the result is visually
identical but ~250x faster (0.2s vs ~48s -- the barycentric weight build
dominated). Arbitrary-mesh render (hires left / cutaway) now ~0.8s.

Surface render + fmridisplay suites: 23/23 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ct's space

surface(obj) with no explicit surface argument now picks a four-surface view
that matches the object's surface-space family, so the data renders at native
(or near-native) fidelity by default:
 - fsLR_32k        -> foursurfaces_hcp        (native, 32492/hemi)
 - fsaverage_164k  -> foursurfaces_freesurfer (native, 163842/hemi)
 - fsaverage6/5/4  -> foursurfaces_freesurfer (nested; resampled up to 164k)
 - onavg_41k/10k   -> foursurfaces_hcp        (fs_LR-aligned; resampled to fs_LR)

No new mesh assets are needed: fsaverage6/5/4 are nested subsets of
fsaverage-164k and onavg is fs_LR-aligned via the vendored onavg spheres, so
each renders on its parent/aligned display space through the fast, cached
nearest-neighbour resample already in render_layer_surfaces (a one-line message
prints when a resample happens). Previously every non-fs_LR/-164k space fell
back to foursurfaces_hcp, forcing an unnecessary cross-family resample.

@fmridisplay/surface: surface_default_keyword now keys off a coarse space
family (local_space_family) rather than two exact strings.

@fmri_surface_data/surface:
 - Fix parser bug: a bare surface keyword (e.g. surface(obj,'foursurfaces_hcp')
   or surface(obj,'hcp inflated left')) fell into the colour-option branch and
   indexed past the end of varargin. Non-mode tokens are now split into colour
   options (value pairs) vs surface directives (bare token / direction-
   orientation-axes pairs); directives are forwarded to the native managed path
   and override the space-matched default view.
 - Expanded help: a Surface-spaces table (space, verts/hemi, default view, mesh
   files) and runnable examples rendering one object per space plus the
   existing/mni-surface modes.

New test test_default_view_matches_space (canlab_test_surface_render): verifies
fs_LR/fsaverage6/onavg pick the right view and paint, and that an explicit
keyword overrides without erroring. Surface render + fmridisplay suites: 24/24 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ata surface reference

Documents which four-surface view surface(obj) picks for each surface_space
(fsLR_32k/fsaverage_164k render natively; nested fsaverage6/5/4 -> fsaverage-164k;
onavg -> fs_LR, both via a fast cached nearest resample). Added the table to both
the comprehensive reference (CanlabCore/docs) and the readthedocs functional index
(docs). Also refreshed the comprehensive doc's Surface-spaces section (all 7 spaces;
resample_surface is implemented, not a 'planned enhancement') and corrected the
surface() space-mismatch text (standard meshes auto-resample; only truly arbitrary
meshes project via a volume).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@torwager
torwager merged commit 82c7085 into master Jul 14, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant