Skip to content

Commit c3b8275

Browse files
committed
feat: Split 2D and 3D resolution sliders effect
1 parent 343e5e1 commit c3b8275

8 files changed

Lines changed: 198 additions & 60 deletions

File tree

src/datasource/catmaid/backend.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ export class CatmaidSpatiallyIndexedSkeletonSourceBackend extends WithParameters
5555
max: { x: localMax[0], y: localMax[1], z: localMax[2] },
5656
};
5757

58-
// Use currentLod from the source backend
59-
const lodValue = this.currentLod;
58+
// Use LOD stored on the chunk to support per-view LODs on shared sources.
59+
const lodValue = chunk.lod ?? this.currentLod;
6060
// Get cache provider from parameters (passed from frontend)
6161
const cacheProvider = this.parameters.catmaidParameters.cacheProvider;
6262
const nodes = await this.client.fetchNodes(bbox, lodValue, cacheProvider);

src/datasource/catmaid/frontend.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,20 @@ export class CatmaidMultiscaleSpatiallyIndexedSkeletonSource extends MultiscaleS
111111
}
112112

113113
getPerspectiveSources(): SliceViewSingleResolutionSource<SpatiallyIndexedSkeletonSource>[] {
114-
const sources = this.getSources({ view: "3d" } as any);
114+
const sources = this.getSources({} as any);
115115
return sources.length > 0 ? sources[0] : [];
116116
}
117117

118118
getSliceViewPanelSources(): SliceViewSingleResolutionSource<SpatiallyIndexedSkeletonSource>[] {
119-
const sources = this.getSources({ view: "2d" } as any);
119+
const sources = this.getSources({} as any);
120120
return sources.length > 0 ? sources[0] : [];
121121
}
122122

123123
getSources(
124-
options: SliceViewSourceOptions,
124+
_options: SliceViewSourceOptions,
125125
): SliceViewSingleResolutionSource<SpatiallyIndexedSkeletonSource>[][] {
126+
void _options;
126127
const sources: SliceViewSingleResolutionSource<SpatiallyIndexedSkeletonSource>[] = [];
127-
const view = (options as { view?: string } | undefined)?.view ?? "2d";
128128

129129
// Sorted by minimum dimension (Descending: Large/Coarse -> Small/Fine)
130130
const sortedGridSizes = this.sortedGridCellSizes;
@@ -181,7 +181,6 @@ export class CatmaidMultiscaleSpatiallyIndexedSkeletonSource extends MultiscaleS
181181
parameters.catmaidParameters.projectId = this.projectId;
182182
parameters.catmaidParameters.cacheProvider = this.cacheProvider;
183183
parameters.gridIndex = gridIndex;
184-
parameters.view = view;
185184
parameters.metadata = {
186185
transform: mat4.create(),
187186
vertexAttributes: new Map([

src/skeleton/backend.ts

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ export class SpatiallyIndexedSkeletonChunk extends SliceViewChunk implements Ske
219219
vertexPositions: Float32Array | null = null;
220220
vertexAttributes: TypedNumberArray[] | null = null;
221221
indices: Uint32Array | null = null;
222+
lod: number = 0;
222223
missingConnections: Array<{ nodeId: number; parentId: number; vertexIndex: number; skeletonId: number }> = [];
223224
nodeMap: Map<number, number> = new Map(); // Maps node ID to vertex index
224225

@@ -242,6 +243,19 @@ export class SpatiallyIndexedSkeletonChunk extends SliceViewChunk implements Ske
242243
export class SpatiallyIndexedSkeletonSourceBackend extends SliceViewChunkSourceBackend<SpatiallyIndexedSkeletonChunkSpecification, SpatiallyIndexedSkeletonChunk> {
243244
chunkConstructor = SpatiallyIndexedSkeletonChunk;
244245
currentLod: number = 0;
246+
247+
getChunk(chunkGridPosition: Float32Array) {
248+
const lodValue = this.currentLod;
249+
const key = `${chunkGridPosition.join()}:${lodValue}`;
250+
let chunk = this.chunks.get(key);
251+
if (chunk === undefined) {
252+
chunk = this.getNewChunk_(this.chunkConstructor) as SpatiallyIndexedSkeletonChunk;
253+
chunk.initializeVolumeChunk(key, chunkGridPosition);
254+
chunk.lod = lodValue;
255+
this.addChunk(chunk);
256+
}
257+
return chunk;
258+
}
245259
}
246260

247261
interface SpatiallyIndexedSkeletonRenderLayerAttachmentState {
@@ -278,39 +292,12 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager
278292

279293
// Debounce LOD changes to avoid making requests for every slider value
280294
const debouncedLodUpdate = debounce(() => {
281-
const lodValue = this.skeletonLod.value;
282-
// Update LOD value in all sources and invalidate all chunks when LOD changes
283-
for (const attachment of this.attachments.values()) {
284-
const attachmentState =
285-
attachment.state! as SpatiallyIndexedSkeletonRenderLayerAttachmentState;
286-
const { transformedSources } = attachmentState;
287-
for (const scales of transformedSources) {
288-
for (const tsource of scales) {
289-
const source = tsource.source as SpatiallyIndexedSkeletonSourceBackend;
290-
source.currentLod = lodValue;
291-
this.chunkManager.queueManager.invalidateSourceCache(source);
292-
}
293-
}
294-
}
295295
scheduleUpdateChunkPriorities();
296296
}, 300);
297297

298298
this.registerDisposer(
299299
this.skeletonLod.changed.add(() => {
300-
// Update currentLod immediately so it's ready when debounce completes
301-
const lodValue = this.skeletonLod.value;
302-
for (const attachment of this.attachments.values()) {
303-
const attachmentState =
304-
attachment.state! as SpatiallyIndexedSkeletonRenderLayerAttachmentState;
305-
const { transformedSources } = attachmentState;
306-
for (const scales of transformedSources) {
307-
for (const tsource of scales) {
308-
const source = tsource.source as SpatiallyIndexedSkeletonSourceBackend;
309-
source.currentLod = lodValue;
310-
}
311-
}
312-
}
313-
// Debounce the invalidation and chunk request
300+
// Trigger a reschedule; LOD-specific chunks are keyed by LOD.
314301
debouncedLodUpdate();
315302
}),
316303
);
@@ -367,7 +354,7 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager
367354
const priorityTier = getPriorityTier(visibility);
368355
const basePriority = getBasePriority(visibility);
369356

370-
const projectionParameters = view.projectionParameters.value;
357+
const projectionParameters = view.projectionParameters.value;
371358
const { chunkManager } = this;
372359
const sliceProjectionParameters =
373360
projectionParameters as SliceViewProjectionParameters;
@@ -515,6 +502,7 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager
515502
return selected;
516503
};
517504

505+
const lodValue = this.skeletonLod.value;
518506
for (const scales of transformedSources) {
519507
const selectedScales = selectScales(scales);
520508
if (DEBUG_SPATIALLY_INDEXED_SKELETON_SCALES) {
@@ -529,14 +517,15 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager
529517
});
530518
}
531519
for (const { tsource, scaleIndex } of selectedScales) {
520+
const source =
521+
tsource.source as SpatiallyIndexedSkeletonSourceBackend;
522+
source.currentLod = lodValue;
532523
forEachVisibleVolumetricChunk(
533524
projectionParameters,
534525
this.localPosition.value,
535526
tsource,
536527
() => {
537-
const chunk = (
538-
tsource.source as SpatiallyIndexedSkeletonSourceBackend
539-
).getChunk(tsource.curPositionInChunks);
528+
const chunk = source.getChunk(tsource.curPositionInChunks);
540529
++this.numVisibleChunksNeeded;
541530
if (chunk.state === ChunkState.GPU_MEMORY) {
542531
++this.numVisibleChunksAvailable;
@@ -559,7 +548,6 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager
559548
export class SpatiallyIndexedSkeletonSliceViewRenderLayerBackend extends SliceViewRenderLayerBackend {
560549
skeletonGridLevel: SharedWatchableValue<number>;
561550
skeletonLod: SharedWatchableValue<number>;
562-
private lastSources: SpatiallyIndexedSkeletonSourceBackend[] = [];
563551

564552
constructor(rpc: RPC, options: any) {
565553
super(rpc, options);
@@ -573,28 +561,24 @@ export class SpatiallyIndexedSkeletonSliceViewRenderLayerBackend extends SliceVi
573561
);
574562
this.registerDisposer(
575563
this.skeletonLod.changed.add(() => {
576-
const lodValue = this.skeletonLod.value;
577-
for (const source of this.lastSources) {
578-
source.currentLod = lodValue;
579-
chunkManager.queueManager.invalidateSourceCache(source);
580-
}
581564
scheduleUpdateChunkPriorities();
582565
}),
583566
);
584567
}
585568

569+
prepareChunkSourceForRequest(source: SpatiallyIndexedSkeletonSourceBackend) {
570+
source.currentLod = this.skeletonLod.value;
571+
}
572+
586573
filterVisibleSources(
587574
sliceView: SliceViewBase,
588575
sources: readonly TransformedSource[],
589576
): Iterable<TransformedSource> {
590577
const lodValue = this.skeletonLod.value;
591-
const uniqueSources = new Set<SpatiallyIndexedSkeletonSourceBackend>();
592578
for (const tsource of sources) {
593579
const source = tsource.source as SpatiallyIndexedSkeletonSourceBackend;
594580
source.currentLod = lodValue;
595-
uniqueSources.add(source);
596581
}
597-
this.lastSources = Array.from(uniqueSources);
598582

599583
const gridIndexedSources = sources
600584
.map((tsource, scaleIndex) => ({

0 commit comments

Comments
 (0)