From 460678402e590ce70f0f2889e1abf7a905d0904d Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Mon, 16 Dec 2024 14:08:56 +0100 Subject: [PATCH] allow selective segment visibility regardless of proofreading tool --- .../materials/plane_material_factory.ts | 14 +++++ .../oxalis/shaders/main_data_shaders.glsl.ts | 29 ++++----- .../oxalis/shaders/segmentation.glsl.ts | 41 +++++++++++++ frontend/javascripts/oxalis/store.ts | 1 + .../left-border-tabs/layer_settings_tab.tsx | 59 ++++++++++--------- .../dataset_view_configuration.schema.ts | 1 + 6 files changed, 99 insertions(+), 46 deletions(-) diff --git a/frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts b/frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts index 87c5a6220c7..aabec1e2429 100644 --- a/frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts +++ b/frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts @@ -146,6 +146,9 @@ class PlaneMaterialFactory { selectiveVisibilityInProofreading: { value: true, }, + selectiveSegmentVisibility: { + value: false, + }, is3DViewBeingRendered: { value: true, }, @@ -562,6 +565,17 @@ class PlaneMaterialFactory { true, ), ); + + this.storePropertyUnsubscribers.push( + listenToStoreProperty( + (storeState) => storeState.datasetConfiguration.selectiveSegmentVisibility, + (selectiveSegmentVisibility) => { + this.uniforms.selectiveSegmentVisibility.value = selectiveSegmentVisibility; + }, + true, + ), + ); + this.storePropertyUnsubscribers.push( listenToStoreProperty( (storeState) => getMagInfoByLayer(storeState.dataset), diff --git a/frontend/javascripts/oxalis/shaders/main_data_shaders.glsl.ts b/frontend/javascripts/oxalis/shaders/main_data_shaders.glsl.ts index 4501f3bce64..68444fa1fdd 100644 --- a/frontend/javascripts/oxalis/shaders/main_data_shaders.glsl.ts +++ b/frontend/javascripts/oxalis/shaders/main_data_shaders.glsl.ts @@ -6,6 +6,7 @@ import { convertCellIdToRGB, getBrushOverlay, getCrossHairOverlay, + getSegmentationAlphaIncrement, getSegmentId, } from "./segmentation.glsl"; import { getMaybeFilteredColorOrFallback } from "./filtering.glsl"; @@ -110,6 +111,7 @@ uniform highp uint LOOKUP_CUCKOO_TWIDTH; uniform float sphericalCapRadius; uniform bool selectiveVisibilityInProofreading; +uniform bool selectiveSegmentVisibility; uniform float viewMode; uniform float alpha; uniform bool renderBucketIndices; @@ -178,6 +180,7 @@ ${compileShader( hasSegmentation ? getBrushOverlay : null, hasSegmentation ? getSegmentId : null, hasSegmentation ? getCrossHairOverlay : null, + hasSegmentation ? getSegmentationAlphaIncrement : null, almostEq, )} @@ -291,25 +294,13 @@ void main() { && hoveredUnmappedSegmentIdHigh == <%= segmentationName %>_unmapped_id_high; bool isActiveCell = activeCellIdLow == <%= segmentationName %>_id_low && activeCellIdHigh == <%= segmentationName %>_id_high; - // Highlight cell only if it's hovered or active during proofreading - // and if segmentation opacity is not zero - float alphaIncrement = isProofreading - ? (isActiveCell - ? (isHoveredUnmappedSegment - ? 0.4 // Highlight the hovered super-voxel of the active segment - : (isHoveredSegment - ? 0.15 // Highlight the not-hovered super-voxels of the hovered segment - : 0.0 - ) - ) - : (isHoveredSegment - ? 0.2 - // We are in proofreading mode, but the current voxel neither belongs - // to the active segment nor is it hovered. When selective visibility - // is enabled, lower the opacity. - : (selectiveVisibilityInProofreading ? -<%= segmentationName %>_alpha : 0.0) - ) - ) : (isHoveredSegment ? 0.2 : 0.0); + float alphaIncrement = getSegmentationAlphaIncrement( + <%= segmentationName %>_alpha, + isHoveredSegment, + isHoveredUnmappedSegment, + isActiveCell + ); + gl_FragColor = vec4(mix( data_color.rgb, convertCellIdToRGB(<%= segmentationName %>_id_high, <%= segmentationName %>_id_low), diff --git a/frontend/javascripts/oxalis/shaders/segmentation.glsl.ts b/frontend/javascripts/oxalis/shaders/segmentation.glsl.ts index 6076008ba5f..f86e4bc6a49 100644 --- a/frontend/javascripts/oxalis/shaders/segmentation.glsl.ts +++ b/frontend/javascripts/oxalis/shaders/segmentation.glsl.ts @@ -351,3 +351,44 @@ export const getSegmentId: ShaderModule = { <% }) %> `, }; + +export const getSegmentationAlphaIncrement: ShaderModule = { + requirements: [], + code: ` + float getSegmentationAlphaIncrement(float alpha, bool isHoveredSegment, bool isHoveredUnmappedSegment, bool isActiveCell) { + // Highlight segment only if + // - it's hovered or + // - active during proofreading + // Also, make segments invisible if selective visibility is turned on (unless the segment + // is active or hovered). + + if (isProofreading) { + if (isActiveCell) { + return (isHoveredUnmappedSegment + ? 0.4 // Highlight the hovered super-voxel of the active segment + : (isHoveredSegment + ? 0.15 // Highlight the not-hovered super-voxels of the hovered segment + : 0.0 + ) + ); + } else { + return (isHoveredSegment + ? 0.2 + // We are in proofreading mode, but the current voxel neither belongs + // to the active segment nor is it hovered. When selective visibility + // is enabled, lower the opacity. + : (selectiveVisibilityInProofreading ? -alpha : 0.0) + ); + } + } + + if (isHoveredSegment) { + return 0.2; + } else if (selectiveSegmentVisibility) { + return isActiveCell ? 0.15 : -alpha; + } else { + return 0.; + } + } + `, +}; diff --git a/frontend/javascripts/oxalis/store.ts b/frontend/javascripts/oxalis/store.ts index 61762134fd8..617bb52e212 100644 --- a/frontend/javascripts/oxalis/store.ts +++ b/frontend/javascripts/oxalis/store.ts @@ -330,6 +330,7 @@ export type DatasetConfiguration = { readonly renderMissingDataBlack: boolean; readonly loadingStrategy: LoadingStrategy; readonly segmentationPatternOpacity: number; + readonly selectiveSegmentVisibility: boolean; readonly blendMode: BLEND_MODES; // If nativelyRenderedLayerName is not-null, the layer with // that name (or id) should be rendered without any transforms. diff --git a/frontend/javascripts/oxalis/view/left-border-tabs/layer_settings_tab.tsx b/frontend/javascripts/oxalis/view/left-border-tabs/layer_settings_tab.tsx index 29fb787852b..8efb15a097d 100644 --- a/frontend/javascripts/oxalis/view/left-border-tabs/layer_settings_tab.tsx +++ b/frontend/javascripts/oxalis/view/left-border-tabs/layer_settings_tab.tsx @@ -132,33 +132,8 @@ import { } from "types/schemas/dataset_view_configuration.schema"; import defaultState from "oxalis/default_state"; -type DatasetSettingsProps = { - userConfiguration: UserConfiguration; - datasetConfiguration: DatasetConfiguration; - dataset: APIDataset; - onChange: (propertyName: keyof DatasetConfiguration, value: any) => void; - onChangeLayer: ( - layerName: string, - propertyName: keyof DatasetLayerConfiguration, - value: any, - ) => void; - onClipHistogram: (layerName: string, shouldAdjustClipRange: boolean) => Promise; - histogramData: HistogramDataForAllLayers; - onChangeRadius: (value: number) => void; - onChangeShowSkeletons: (arg0: boolean) => void; - onSetPosition: (arg0: Vector3) => void; - onZoomToMag: (layerName: string, arg0: Vector3) => number; - onChangeUser: (key: keyof UserConfiguration, value: any) => void; - reloadHistogram: (layerName: string) => void; - tracing: Tracing; - task: Task | null | undefined; - onEditAnnotationLayer: (tracingId: string, layerProperties: EditableLayerProperties) => void; - controlMode: ControlMode; - isArbitraryMode: boolean; - isAdminOrDatasetManager: boolean; - isAdminOrManager: boolean; - isSuperUser: boolean; -}; +type DatasetSettingsProps = ReturnType & + ReturnType; type State = { // If this is set to not-null, the downsampling modal @@ -927,9 +902,37 @@ class DatasetSettings extends React.PureComponent { defaultValue={defaultDatasetViewConfigurationWithoutNull.segmentationPatternOpacity} /> ); + + const isProofreadingMode = this.props.activeTool === "PROOFREAD"; + const isSelectiveVisibilityDisabled = isProofreadingMode; + + const selectiveVisibilitySwitch = ( + +
+ +
+
+ ); + return (
{segmentationOpacitySetting} + {selectiveVisibilitySwitch}
); @@ -1338,6 +1341,7 @@ class DatasetSettings extends React.PureComponent { "loadingStrategy", "segmentationPatternOpacity", "blendMode", + "selectiveSegmentVisibility", ] as Array ).map((key) => ({ name: settings[key] as string, @@ -1585,6 +1589,7 @@ const mapStateToProps = (state: OxalisState) => ({ state.activeUser != null ? Utils.isUserAdminOrDatasetManager(state.activeUser) : false, isAdminOrManager: state.activeUser != null ? Utils.isUserAdminOrManager(state.activeUser) : false, isSuperUser: state.activeUser?.isSuperUser || false, + activeTool: state.uiInformation.activeTool, }); const mapDispatchToProps = (dispatch: Dispatch) => ({ diff --git a/frontend/javascripts/types/schemas/dataset_view_configuration.schema.ts b/frontend/javascripts/types/schemas/dataset_view_configuration.schema.ts index 46d09bc45a7..672acab0ad2 100644 --- a/frontend/javascripts/types/schemas/dataset_view_configuration.schema.ts +++ b/frontend/javascripts/types/schemas/dataset_view_configuration.schema.ts @@ -89,6 +89,7 @@ export const defaultDatasetViewConfigurationWithoutNull: DatasetConfiguration = blendMode: BLEND_MODES.Additive, colorLayerOrder: [], nativelyRenderedLayerName: null, + selectiveSegmentVisibility: false, }; export const defaultDatasetViewConfiguration = { ...defaultDatasetViewConfigurationWithoutNull,