@kitware/vtk.js 32.6.2 → 33.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/BREAKING_CHANGES.md +3 -0
  2. package/IO/Image.js +1 -3
  3. package/Interaction/Manipulators/KeyboardCameraManipulator.d.ts +113 -0
  4. package/Rendering/Core/Actor.d.ts +5 -20
  5. package/Rendering/Core/Actor.js +5 -68
  6. package/Rendering/Core/ImageProperty.d.ts +0 -22
  7. package/Rendering/Core/ImageSlice.d.ts +7 -23
  8. package/Rendering/Core/ImageSlice.js +9 -68
  9. package/Rendering/Core/PointPicker.js +1 -4
  10. package/Rendering/Core/Prop3D.d.ts +39 -2
  11. package/Rendering/Core/Prop3D.js +81 -2
  12. package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
  13. package/Rendering/Core/Volume.d.ts +5 -20
  14. package/Rendering/Core/Volume.js +2 -70
  15. package/Rendering/Core/VolumeMapper/Constants.d.ts +0 -7
  16. package/Rendering/Core/VolumeMapper/Constants.js +2 -8
  17. package/Rendering/Core/VolumeMapper.d.ts +16 -140
  18. package/Rendering/Core/VolumeMapper.js +17 -52
  19. package/Rendering/Core/VolumeProperty/Constants.d.ts +12 -3
  20. package/Rendering/Core/VolumeProperty/Constants.js +11 -4
  21. package/Rendering/Core/VolumeProperty.d.ts +120 -4
  22. package/Rendering/Core/VolumeProperty.js +49 -4
  23. package/Rendering/OpenGL/ImageCPRMapper.js +27 -19
  24. package/Rendering/OpenGL/ImageMapper.js +34 -41
  25. package/Rendering/OpenGL/ImageResliceMapper.js +261 -172
  26. package/Rendering/OpenGL/PolyDataMapper.js +1 -8
  27. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +3 -3
  28. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +8 -5
  29. package/Rendering/OpenGL/VolumeMapper.js +710 -772
  30. package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
  31. package/Rendering/WebGPU/VolumePassFSQ.js +2 -2
  32. package/index.d.ts +1 -1
  33. package/macros2.js +1 -1
  34. package/package.json +1 -1
  35. package/IO/Image/TGAReader/Constants.js +0 -28
  36. package/IO/Image/TGAReader.d.ts +0 -121
  37. package/IO/Image/TGAReader.js +0 -418
@@ -13,6 +13,7 @@ export interface IVolumePropertyInitialValues {
13
13
  specularPower?: number;
14
14
  useLabelOutline?: boolean;
15
15
  labelOutlineThickness?: number | number[];
16
+ colorMixPreset?: ColorMixPreset;
16
17
  }
17
18
 
18
19
  export interface vtkVolumeProperty extends vtkObject {
@@ -71,7 +72,7 @@ export interface vtkVolumeProperty extends vtkObject {
71
72
  /**
72
73
  *
73
74
  */
74
- getColorMixPreset(): Nullable<ColorMixPreset>;
75
+ getColorMixPreset(): ColorMixPreset;
75
76
 
76
77
  /**
77
78
  *
@@ -194,7 +195,7 @@ export interface vtkVolumeProperty extends vtkObject {
194
195
 
195
196
  /**
196
197
  * Set the color mix code to a preset value
197
- * Set to null to use no preset
198
+ * Defaults to ColorMixPreset.DEFAULT
198
199
  * See the test `testColorMix` for an example on how to use this preset.
199
200
  *
200
201
  * If set to `CUSTOM`, a tag `//VTK::CustomColorMix` is made available to the
@@ -202,9 +203,9 @@ export interface vtkVolumeProperty extends vtkObject {
202
203
  * will be used to mix the colors from each component.
203
204
  * Each component is available as a rgba vec4: `comp0`, `comp1`...
204
205
  * There are other useful functions or variable available. To find them,
205
- * see `//VTK::CustomComponentsColorMix::Impl` tag in `vtkVolumeFS.glsl`.
206
+ * see `//VTK::CustomColorMix` tag in `vtkVolumeFS.glsl`.
206
207
  */
207
- setColorMixPreset(preset: Nullable<ColorMixPreset>): boolean;
208
+ setColorMixPreset(preset: ColorMixPreset): boolean;
208
209
 
209
210
  /**
210
211
  * Does the data have independent components, or do some define color only?
@@ -370,6 +371,121 @@ export interface vtkVolumeProperty extends vtkObject {
370
371
  * Get the interpolation type for sampling a volume as a string.
371
372
  */
372
373
  getInterpolationTypeAsString(): string;
374
+
375
+ /**
376
+ *
377
+ */
378
+ getAverageIPScalarRange(): Range;
379
+
380
+ /**
381
+ *
382
+ */
383
+ getAverageIPScalarRangeByReference(): Range;
384
+
385
+ /**
386
+ * Get the blending coefficient that interpolates between surface and volume rendering
387
+ * @default 0.0
388
+ */
389
+ getVolumetricScatteringBlending(): number;
390
+
391
+ /**
392
+ * Get the global illumination reach of volume shadow
393
+ * @default 0.0
394
+ */
395
+ getGlobalIlluminationReach(): number;
396
+
397
+ /**
398
+ * Get anisotropy of volume shadow scatter
399
+ * @default 0.0
400
+ */
401
+ getAnisotropy(): number;
402
+
403
+ /**
404
+ * Get local ambient occlusion flag
405
+ * @default false
406
+ */
407
+ getLocalAmbientOcclusion(): boolean;
408
+
409
+ /**
410
+ * Get kernel size for local ambient occlusion
411
+ * @default 15
412
+ */
413
+ getLAOKernelSize(): number;
414
+
415
+ /**
416
+ * Get kernel radius for local ambient occlusion
417
+ * @default 7
418
+ */
419
+ getLAOKernelRadius(): number;
420
+
421
+ /**
422
+ *
423
+ * @param x
424
+ * @param y
425
+ */
426
+ setAverageIPScalarRange(x: number, y: number): boolean;
427
+
428
+ /**
429
+ *
430
+ * @param {Range} averageIPScalarRange
431
+ */
432
+ setAverageIPScalarRangeFrom(averageIPScalarRange: Range): boolean;
433
+
434
+ /**
435
+ * Set the normal computation to be dependent on the transfer function.
436
+ * By default, the mapper relies on the scalar gradient for computing normals at sample locations
437
+ * for lighting calculations. This is an approximation and can lead to inaccurate results.
438
+ * When enabled, this property makes the mapper compute normals based on the accumulated opacity
439
+ * at sample locations. This can generate a more accurate representation of edge structures in the
440
+ * data but adds an overhead and drops frame rate.
441
+ * @param computeNormalFromOpacity
442
+ */
443
+ setComputeNormalFromOpacity(computeNormalFromOpacity: boolean): boolean;
444
+
445
+ /**
446
+ * Set the blending coefficient that determines the interpolation between surface and volume rendering.
447
+ * Default value of 0.0 means shadow effect is computed with phong model.
448
+ * Value of 1.0 means shadow is created by volume occlusion.
449
+ * @param volumeScatterBlendCoef
450
+ */
451
+ setVolumetricScatteringBlending(volumeScatterBlendCoef: number): void;
452
+
453
+ /**
454
+ * Set the global illumination reach of volume shadow. This function is only effective when volumeScatterBlendCoef is greater than 0.
455
+ * Default value of 0.0 means only the neighboring voxel is considered when creating global shadow.
456
+ * Value of 1.0 means the shadow ray traverses through the entire volume.
457
+ * @param globalIlluminationReach
458
+ */
459
+ setGlobalIlluminationReach(globalIlluminationReach: number): void;
460
+
461
+ /**
462
+ * Set anisotropy of volume shadow scatter. This function is only effective when volumeScatterBlendCoef is greater than 0.
463
+ * Default value of 0.0 means light scatters uniformly in all directions.
464
+ * Value of -1.0 means light scatters backward, value of 1.0 means light scatters forward.
465
+ * @param anisotropy
466
+ */
467
+ setAnisotropy(anisotropy: number): void;
468
+
469
+ /**
470
+ * Set whether to turn on local ambient occlusion (LAO). LAO is only effective if shading is on and volumeScatterBlendCoef is set to 0.
471
+ * LAO effect is added to ambient lighting, so the ambient component of the actor needs to be great than 0.
472
+ * @param localAmbientOcclusion
473
+ */
474
+ setLocalAmbientOcclusion(localAmbientOcclusion: boolean): void;
475
+
476
+ /**
477
+ * Set kernel size for local ambient occlusion. It specifies the number of rays that are randomly sampled in the hemisphere.
478
+ * Value is clipped between 1 and 32.
479
+ * @param LAOKernelSize
480
+ */
481
+ setLAOKernelSize(LAOKernelSize: number): void;
482
+
483
+ /**
484
+ * Set kernel radius for local ambient occlusion. It specifies the number of samples that are considered on each random ray.
485
+ * Value must be greater than or equal to 1.
486
+ * @param LAOKernelRadius
487
+ */
488
+ setLAOKernelRadius(LAOKernelRadius: number): void;
373
489
  }
374
490
 
375
491
  /**
@@ -1,11 +1,14 @@
1
1
  import { m as macro } from '../../macros2.js';
2
+ import { E as clampValue, K as floor } from '../../Common/Core/Math/index.js';
2
3
  import vtkColorTransferFunction from './ColorTransferFunction.js';
3
4
  import vtkPiecewiseFunction from '../../Common/DataModel/PiecewiseFunction.js';
4
5
  import Constants from './VolumeProperty/Constants.js';
5
6
 
6
7
  const {
7
8
  InterpolationType,
8
- OpacityMode
9
+ OpacityMode,
10
+ FilterMode,
11
+ ColorMixPreset
9
12
  } = Constants;
10
13
  const {
11
14
  vtkErrorMacro
@@ -19,6 +22,9 @@ const VTK_MAX_VRCOMP = 4;
19
22
  function vtkVolumeProperty(publicAPI, model) {
20
23
  // Set our className
21
24
  model.classHierarchy.push('vtkVolumeProperty');
25
+ const superClass = {
26
+ ...publicAPI
27
+ };
22
28
  publicAPI.getMTime = () => {
23
29
  let mTime = model.mtime;
24
30
  let time;
@@ -197,6 +203,25 @@ function vtkVolumeProperty(publicAPI, model) {
197
203
  const cap = macro.capitalize(val);
198
204
  publicAPI[`get${cap}`] = index => model.componentData[index][`${val}`];
199
205
  });
206
+ publicAPI.setAverageIPScalarRange = (min, max) => {
207
+ console.warn('setAverageIPScalarRange is deprecated use setIpScalarRange');
208
+ publicAPI.setIpScalarRange(min, max);
209
+ };
210
+ publicAPI.getFilterModeAsString = () => macro.enumToString(FilterMode, model.filterMode);
211
+ publicAPI.setFilterModeToOff = () => {
212
+ publicAPI.setFilterMode(FilterMode.OFF);
213
+ };
214
+ publicAPI.setFilterModeToNormalized = () => {
215
+ publicAPI.setFilterMode(FilterMode.NORMALIZED);
216
+ };
217
+ publicAPI.setFilterModeToRaw = () => {
218
+ publicAPI.setFilterMode(FilterMode.RAW);
219
+ };
220
+ publicAPI.setGlobalIlluminationReach = gl => superClass.setGlobalIlluminationReach(clampValue(gl, 0.0, 1.0));
221
+ publicAPI.setVolumetricScatteringBlending = vsb => superClass.setVolumetricScatteringBlending(clampValue(vsb, 0.0, 1.0));
222
+ publicAPI.setAnisotropy = at => superClass.setAnisotropy(clampValue(at, -0.99, 0.99));
223
+ publicAPI.setLAOKernelSize = ks => superClass.setLAOKernelSize(floor(clampValue(ks, 1, 32)));
224
+ publicAPI.setLAOKernelRadius = kr => superClass.setLAOKernelRadius(kr >= 1 ? kr : 1);
200
225
  }
201
226
 
202
227
  // ----------------------------------------------------------------------------
@@ -204,7 +229,7 @@ function vtkVolumeProperty(publicAPI, model) {
204
229
  // ----------------------------------------------------------------------------
205
230
 
206
231
  const DEFAULT_VALUES = {
207
- colorMixPreset: null,
232
+ colorMixPreset: ColorMixPreset.DEFAULT,
208
233
  independentComponents: true,
209
234
  interpolationType: InterpolationType.FAST_LINEAR,
210
235
  shade: false,
@@ -214,7 +239,22 @@ const DEFAULT_VALUES = {
214
239
  specularPower: 10.0,
215
240
  useLabelOutline: false,
216
241
  labelOutlineThickness: [1],
217
- labelOutlineOpacity: 1.0
242
+ labelOutlineOpacity: 1.0,
243
+ // Properties moved from volume mapper
244
+ ipScalarRange: [-1000000.0, 1000000.0],
245
+ filterMode: FilterMode.OFF,
246
+ // ignored by WebGL so no behavior change
247
+ preferSizeOverAccuracy: false,
248
+ // Whether to use halfFloat representation of float, when it is inaccurate
249
+ computeNormalFromOpacity: false,
250
+ // volume shadow parameters
251
+ volumetricScatteringBlending: 0.0,
252
+ globalIlluminationReach: 0.0,
253
+ anisotropy: 0.0,
254
+ // local ambient occlusion
255
+ localAmbientOcclusion: false,
256
+ LAOKernelSize: 15,
257
+ LAOKernelRadius: 7
218
258
  };
219
259
 
220
260
  // ----------------------------------------------------------------------------
@@ -245,7 +285,12 @@ function extend(publicAPI, model) {
245
285
  });
246
286
  }
247
287
  }
248
- macro.setGet(publicAPI, model, ['colorMixPreset', 'independentComponents', 'interpolationType', 'shade', 'ambient', 'diffuse', 'specular', 'specularPower', 'useLabelOutline', 'labelOutlineOpacity']);
288
+ macro.setGet(publicAPI, model, ['colorMixPreset', 'independentComponents', 'interpolationType', 'shade', 'ambient', 'diffuse', 'specular', 'specularPower', 'useLabelOutline', 'labelOutlineOpacity',
289
+ // Properties moved from volume mapper
290
+ 'filterMode', 'preferSizeOverAccuracy', 'computeNormalFromOpacity', 'volumetricScatteringBlending', 'globalIlluminationReach', 'anisotropy', 'localAmbientOcclusion', 'LAOKernelSize', 'LAOKernelRadius']);
291
+
292
+ // Property moved from volume mapper
293
+ macro.setGetArray(publicAPI, model, ['ipScalarRange'], 2);
249
294
  macro.setGetArray(publicAPI, model, ['labelOutlineThickness']);
250
295
 
251
296
  // Object methods
@@ -11,7 +11,7 @@ import vtkOpenGLTexture from './Texture.js';
11
11
  import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
12
12
  import vtkShaderProgram from './ShaderProgram.js';
13
13
  import vtkViewNode from '../SceneGraph/ViewNode.js';
14
- import { getImageDataHash, getTransferFunctionHash } from './RenderWindow/resourceSharingHelper.js';
14
+ import { getImageDataHash, getTransferFunctionsHash } from './RenderWindow/resourceSharingHelper.js';
15
15
  import { v as vtkPolyDataVS } from './glsl/vtkPolyDataVS.glsl.js';
16
16
  import { v as vtkPolyDataFS } from './glsl/vtkPolyDataFS.glsl.js';
17
17
  import { registerOverride } from './ViewNodeFactory.js';
@@ -181,9 +181,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
181
181
  const iComps = ppty.getIndependentComponents();
182
182
  const numIComps = iComps ? numComp : 1;
183
183
  const textureHeight = iComps ? 2 * numIComps : 1;
184
- const colorTransferFunc = ppty.getRGBTransferFunction();
185
- const colorTextureHash = getTransferFunctionHash(colorTransferFunc, iComps, numIComps);
186
- const cachedColorEntry = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
184
+ const colorTransferFunctions = [];
185
+ for (let component = 0; component < numIComps; ++component) {
186
+ colorTransferFunctions.push(ppty.getRGBTransferFunction(component));
187
+ }
188
+ const colorTextureHash = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
189
+ const firstColorTransferFunc = ppty.getRGBTransferFunction();
190
+ const cachedColorEntry = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
187
191
  const reBuildColorTexture = !cachedColorEntry?.oglObject?.getHandle() || cachedColorEntry?.hash !== colorTextureHash;
188
192
  if (reBuildColorTexture) {
189
193
  const cWidth = 1024;
@@ -191,7 +195,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
191
195
  const cTable = new Uint8ClampedArray(cSize);
192
196
  model.colorTexture = vtkOpenGLTexture.newInstance();
193
197
  model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
194
- if (colorTransferFunc) {
198
+ if (firstColorTransferFunc) {
195
199
  const tmpTable = new Float32Array(cWidth * 3);
196
200
  for (let c = 0; c < numIComps; c++) {
197
201
  const cfun = ppty.getRGBTransferFunction(c);
@@ -219,13 +223,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
219
223
  model.colorTexture.resetFormatAndType();
220
224
  model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
221
225
  }
222
- if (colorTransferFunc) {
223
- model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, colorTextureHash);
224
- if (colorTransferFunc !== model._colorTransferFunc) {
225
- model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
226
+ if (firstColorTransferFunc) {
227
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, model.colorTexture, colorTextureHash);
228
+ if (firstColorTransferFunc !== model._colorTransferFunc) {
229
+ model._openGLRenderWindow.registerGraphicsResourceUser(firstColorTransferFunc, publicAPI);
226
230
  model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
227
231
  }
228
- model._colorTransferFunc = colorTransferFunc;
232
+ model._colorTransferFunc = firstColorTransferFunc;
229
233
  }
230
234
  } else {
231
235
  model.colorTexture = cachedColorEntry.oglObject;
@@ -234,9 +238,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
234
238
  // Build piecewise function buffer. This buffer is used either
235
239
  // for component weighting or opacity, depending on whether we're
236
240
  // rendering components independently or not.
237
- const pwFunc = ppty.getPiecewiseFunction();
238
- const pwfTextureHash = getTransferFunctionHash(pwFunc, iComps, numIComps);
239
- const cachedPwfEntry = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
241
+ const opacityFunctions = [];
242
+ for (let component = 0; component < numIComps; ++component) {
243
+ opacityFunctions.push(ppty.getPiecewiseFunction(component));
244
+ }
245
+ const pwfTextureHash = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
246
+ const firstPwFunc = ppty.getPiecewiseFunction();
247
+ const cachedPwfEntry = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
240
248
  const reBuildPwf = !cachedPwfEntry?.oglObject?.getHandle() || cachedPwfEntry?.hash !== pwfTextureHash;
241
249
  if (reBuildPwf) {
242
250
  const pwfWidth = 1024;
@@ -244,7 +252,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
244
252
  const pwfTable = new Uint8ClampedArray(pwfSize);
245
253
  model.pwfTexture = vtkOpenGLTexture.newInstance();
246
254
  model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
247
- if (pwFunc) {
255
+ if (firstPwFunc) {
248
256
  const pwfFloatTable = new Float32Array(pwfSize);
249
257
  const tmpTable = new Float32Array(pwfWidth);
250
258
  for (let c = 0; c < numIComps; ++c) {
@@ -276,13 +284,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
276
284
  model.pwfTexture.resetFormatAndType();
277
285
  model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
278
286
  }
279
- if (pwFunc) {
280
- model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, pwfTextureHash);
281
- if (pwFunc !== model._pwFunc) {
282
- model._openGLRenderWindow.registerGraphicsResourceUser(pwFunc, publicAPI);
287
+ if (firstPwFunc) {
288
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, model.pwfTexture, pwfTextureHash);
289
+ if (firstPwFunc !== model._pwFunc) {
290
+ model._openGLRenderWindow.registerGraphicsResourceUser(firstPwFunc, publicAPI);
283
291
  model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
284
292
  }
285
- model._pwFunc = pwFunc;
293
+ model._pwFunc = firstPwFunc;
286
294
  }
287
295
  } else {
288
296
  model.pwfTexture = cachedPwfEntry.oglObject;
@@ -4,14 +4,13 @@ import { n as newInstance$1, e as setGet, o as obj, r as vtkErrorMacro$1, h as c
4
4
  import vtkDataArray from '../../Common/Core/DataArray.js';
5
5
  import { VtkDataTypes } from '../../Common/Core/DataArray/Constants.js';
6
6
  import vtkHelper from './Helper.js';
7
- import { u as uninitializeBounds } from '../../Common/Core/Math/index.js';
8
7
  import vtkOpenGLTexture from './Texture.js';
9
8
  import vtkShaderProgram from './ShaderProgram.js';
10
9
  import vtkViewNode from '../SceneGraph/ViewNode.js';
11
10
  import { Representation } from '../Core/Property/Constants.js';
12
11
  import { Filter, Wrap } from './Texture/Constants.js';
13
12
  import { InterpolationType } from '../Core/ImageProperty/Constants.js';
14
- import { getTransferFunctionHash } from './RenderWindow/resourceSharingHelper.js';
13
+ import { getTransferFunctionsHash } from './RenderWindow/resourceSharingHelper.js';
15
14
  import { v as vtkPolyDataVS } from './glsl/vtkPolyDataVS.glsl.js';
16
15
  import { v as vtkPolyDataFS } from './glsl/vtkPolyDataFS.glsl.js';
17
16
  import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
@@ -168,9 +167,9 @@ function vtkOpenGLImageMapper(publicAPI, model) {
168
167
  // check for the outline thickness and opacity
169
168
  const vtkImageLabelOutline = actor.getProperty().getUseLabelOutline();
170
169
  if (vtkImageLabelOutline === true) {
171
- FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutline::Dec', ['uniform int outlineThickness;', 'uniform float vpWidth;', 'uniform float vpHeight;', 'uniform float vpOffsetX;', 'uniform float vpOffsetY;', 'uniform mat4 PCWCMatrix;', 'uniform mat4 vWCtoIDX;', 'uniform ivec3 imageDimensions;', 'uniform int sliceAxis;']).result;
170
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutline::Dec', ['uniform int outlineThickness;', 'uniform float vpWidth;', 'uniform float vpHeight;', 'uniform float vpOffsetX;', 'uniform float vpOffsetY;', 'uniform mat4 PCWCMatrix;', 'uniform mat4 vWCtoIDX;', 'uniform ivec3 imageDimensions;']).result;
172
171
  FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ImageLabelOutlineOn', '#define vtkImageLabelOutlineOn').result;
173
- FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutlineHelperFunction', ['#ifdef vtkImageLabelOutlineOn', 'vec3 fragCoordToIndexSpace(vec4 fragCoord) {', ' vec4 pcPos = vec4(', ' (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,', ' (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,', ' (fragCoord.z - 0.5) * 2.0,', ' 1.0);', '', ' vec4 worldCoord = PCWCMatrix * pcPos;', ' vec4 vertex = (worldCoord/worldCoord.w);', '', ' vec3 index = (vWCtoIDX * vertex).xyz;', '', ' // half voxel fix for labelmapOutline', ' return (index + vec3(0.5)) / vec3(imageDimensions);', '}', 'vec2 getSliceCoords(vec3 coord, int axis) {', ' if (axis == 0) return coord.yz;', ' if (axis == 1) return coord.xz;', ' if (axis == 2) return coord.xy;', '}', '#endif']).result;
172
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutlineHelperFunction', ['#ifdef vtkImageLabelOutlineOn', 'vec3 fragCoordToIndexSpace(vec4 fragCoord) {', ' vec4 pcPos = vec4(', ' (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,', ' (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,', ' (fragCoord.z - 0.5) * 2.0,', ' 1.0);', '', ' vec4 worldCoord = PCWCMatrix * pcPos;', ' vec4 vertex = (worldCoord/worldCoord.w);', '', ' vec3 index = (vWCtoIDX * vertex).xyz;', '', ' // half voxel fix for labelmapOutline', ' return (index + vec3(0.5)) / vec3(imageDimensions);', '}', '#endif']).result;
174
173
  }
175
174
  if (iComps) {
176
175
  const rgba = ['r', 'g', 'b', 'a'];
@@ -202,7 +201,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
202
201
  FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [...splitStringOnEnter(`
203
202
  #ifdef vtkImageLabelOutlineOn
204
203
  vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord);
205
- float centerValue = texture2D(texture1, getSliceCoords(centerPosIS, sliceAxis)).r;
204
+ float centerValue = texture2D(texture1, centerPosIS.xy).r;
206
205
  bool pixelOnBorder = false;
207
206
  vec3 tColor = texture2D(colorTexture1, vec2(centerValue * cscale0 + cshift0, 0.5)).rgb;
208
207
  float scalarOpacity = texture2D(pwfTexture1, vec2(centerValue * pwfscale0 + pwfshift0, 0.5)).r;
@@ -213,7 +212,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
213
212
  int actualThickness = int(textureValue * 255.0);
214
213
 
215
214
  if (segmentIndex == 0){
216
- gl_FragData[0] = vec4(0.0, 0.0, 0.0, 0.0);
215
+ gl_FragData[0] = vec4(0.0, 1.0, 1.0, 0.0);
217
216
  return;
218
217
  }
219
218
 
@@ -226,7 +225,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
226
225
  gl_FragCoord.y + float(j),
227
226
  gl_FragCoord.z, gl_FragCoord.w);
228
227
  vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);
229
- float value = texture2D(texture1, getSliceCoords(neighborPosIS, sliceAxis)).r;
228
+ float value = texture2D(texture1, neighborPosIS.xy).r;
230
229
  if (value != centerValue) {
231
230
  pixelOnBorder = true;
232
231
  break;
@@ -475,14 +474,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
475
474
  if (vtkImageLabelOutline === true) {
476
475
  const worldToIndex = image.getWorldToIndex();
477
476
  const imageDimensions = image.getDimensions();
478
- let sliceAxis = model.renderable.getClosestIJKAxis().ijkMode;
479
-
480
- // SlicingMode.NONE equates to SlicingMode.K
481
- if (sliceAxis === SlicingMode.NONE) {
482
- sliceAxis = SlicingMode.K;
483
- }
484
- program.setUniform3i('imageDimensions', imageDimensions[0], imageDimensions[1], imageDimensions[2]);
485
- program.setUniformi('sliceAxis', sliceAxis);
477
+ program.setUniform3i('imageDimensions', imageDimensions[0], imageDimensions[1], 1);
486
478
  program.setUniformMatrix('vWCtoIDX', worldToIndex);
487
479
  const labelOutlineKeyMats = model.openGLCamera.getKeyMatrices(ren);
488
480
 
@@ -555,13 +547,6 @@ function vtkOpenGLImageMapper(publicAPI, model) {
555
547
  publicAPI.renderPieceDraw(ren, actor);
556
548
  publicAPI.renderPieceFinish(ren, actor);
557
549
  };
558
- publicAPI.computeBounds = (ren, actor) => {
559
- if (!publicAPI.getInput()) {
560
- uninitializeBounds(model.bounds);
561
- return;
562
- }
563
- model.bounds = publicAPI.getInput().getBounds();
564
- };
565
550
  publicAPI.updateBufferObjects = (ren, actor) => {
566
551
  // Rebuild buffers if needed
567
552
  if (publicAPI.getNeedToRebuildBufferObjects(ren, actor)) {
@@ -585,9 +570,13 @@ function vtkOpenGLImageMapper(publicAPI, model) {
585
570
  const iComps = actorProperty.getIndependentComponents();
586
571
  const numIComps = iComps ? numComp : 1;
587
572
  const textureHeight = iComps ? 2 * numIComps : 1;
588
- const colorTransferFunc = actorProperty.getRGBTransferFunction();
589
- const cfunToString = getTransferFunctionHash(colorTransferFunc, iComps, numIComps);
590
- const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
573
+ const colorTransferFunctions = [];
574
+ for (let component = 0; component < numIComps; ++component) {
575
+ colorTransferFunctions.push(actorProperty.getRGBTransferFunction(component));
576
+ }
577
+ const cfunToString = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
578
+ const firstColorTransferFunc = actorProperty.getRGBTransferFunction();
579
+ const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
591
580
  const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== cfunToString;
592
581
  if (reBuildC) {
593
582
  model.colorTexture = vtkOpenGLTexture.newInstance({
@@ -605,7 +594,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
605
594
  model.colorTexture.setMinificationFilter(Filter.LINEAR);
606
595
  model.colorTexture.setMagnificationFilter(Filter.LINEAR);
607
596
  }
608
- if (colorTransferFunc) {
597
+ if (firstColorTransferFunc) {
609
598
  const tmpTable = new Float32Array(cWidth * 3);
610
599
  for (let c = 0; c < numIComps; c++) {
611
600
  const cfun = actorProperty.getRGBTransferFunction(c);
@@ -632,13 +621,13 @@ function vtkOpenGLImageMapper(publicAPI, model) {
632
621
  }
633
622
  model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
634
623
  }
635
- if (colorTransferFunc) {
636
- model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, cfunToString);
637
- if (colorTransferFunc !== model._colorTransferFunc) {
638
- model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
624
+ if (firstColorTransferFunc) {
625
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, model.colorTexture, cfunToString);
626
+ if (firstColorTransferFunc !== model._colorTransferFunc) {
627
+ model._openGLRenderWindow.registerGraphicsResourceUser(firstColorTransferFunc, publicAPI);
639
628
  model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
640
629
  }
641
- model._colorTransferFunc = colorTransferFunc;
630
+ model._colorTransferFunc = firstColorTransferFunc;
642
631
  }
643
632
  } else {
644
633
  model.colorTexture = cTex.oglObject;
@@ -647,9 +636,13 @@ function vtkOpenGLImageMapper(publicAPI, model) {
647
636
  // Build piecewise function buffer. This buffer is used either
648
637
  // for component weighting or opacity, depending on whether we're
649
638
  // rendering components independently or not.
650
- const pwFunc = actorProperty.getPiecewiseFunction();
651
- const pwfunToString = getTransferFunctionHash(pwFunc, iComps, numIComps);
652
- const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
639
+ const opacityFunctions = [];
640
+ for (let component = 0; component < numIComps; ++component) {
641
+ opacityFunctions.push(actorProperty.getPiecewiseFunction(component));
642
+ }
643
+ const pwfunToString = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
644
+ const firstPwFunc = actorProperty.getPiecewiseFunction();
645
+ const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
653
646
  // rebuild opacity tfun?
654
647
  const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== pwfunToString;
655
648
  if (reBuildPwf) {
@@ -668,7 +661,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
668
661
  model.pwfTexture.setMinificationFilter(Filter.LINEAR);
669
662
  model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
670
663
  }
671
- if (pwFunc) {
664
+ if (firstPwFunc) {
672
665
  const pwfFloatTable = new Float32Array(pwfSize);
673
666
  const tmpTable = new Float32Array(pwfWidth);
674
667
  for (let c = 0; c < numIComps; ++c) {
@@ -699,13 +692,13 @@ function vtkOpenGLImageMapper(publicAPI, model) {
699
692
  pwfTable.fill(255.0);
700
693
  model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
701
694
  }
702
- if (pwFunc) {
703
- model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, pwfunToString);
704
- if (pwFunc !== model._pwFunc) {
705
- model._openGLRenderWindow.registerGraphicsResourceUser(pwFunc, publicAPI);
695
+ if (firstPwFunc) {
696
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, model.pwfTexture, pwfunToString);
697
+ if (firstPwFunc !== model._pwFunc) {
698
+ model._openGLRenderWindow.registerGraphicsResourceUser(firstPwFunc, publicAPI);
706
699
  model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
707
700
  }
708
- model._pwFunc = pwFunc;
701
+ model._pwFunc = firstPwFunc;
709
702
  }
710
703
  } else {
711
704
  model.pwfTexture = pwfTex.oglObject;
@@ -903,7 +896,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
903
896
  }
904
897
  };
905
898
  publicAPI.updatelabelOutlineThicknessTexture = image => {
906
- const labelOutlineThicknessArray = image.getProperty().getLabelOutlineThicknessByReference();
899
+ const labelOutlineThicknessArray = image.getProperty().getLabelOutlineThickness();
907
900
  const lTex = model._openGLRenderWindow.getGraphicsResourceForObject(labelOutlineThicknessArray);
908
901
 
909
902
  // compute the join of the labelOutlineThicknessArray so that