@@ -18,6 +18,8 @@ import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
18
18
import vtkOutlineFilter from 'vtk.js/Sources/Filters/General/OutlineFilter' ;
19
19
import vtkOrientationMarkerWidget from 'vtk.js/Sources/Interaction/Widgets/OrientationMarkerWidget' ;
20
20
import vtkResliceCursorWidget from 'vtk.js/Sources/Widgets/Widgets3D/ResliceCursorWidget' ;
21
+ import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume' ;
22
+ import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper' ;
21
23
import vtkWidgetManager from 'vtk.js/Sources/Widgets/Core/WidgetManager' ;
22
24
23
25
import vtkSphereSource from 'vtk.js/Sources/Filters/Sources/SphereSource' ;
@@ -31,6 +33,7 @@ import controlPanel from './controlPanel.html';
31
33
32
34
// Force the loading of HttpDataAccessHelper to support gzip decompression
33
35
import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper' ;
36
+ import { BlendMode } from '../../../../Rendering/Core/VolumeMapper/Constants' ;
34
37
35
38
// ----------------------------------------------------------------------------
36
39
// Define main attributes
@@ -53,6 +56,8 @@ widgetState.setSphereRadius(10 * window.devicePixelRatio);
53
56
widgetState . setLineThickness ( 5 ) ;
54
57
55
58
const showDebugActors = true ;
59
+ const debugPlanes = false ;
60
+ let renderWithGPU = true ;
56
61
57
62
// ----------------------------------------------------------------------------
58
63
// Define html structure
@@ -142,7 +147,11 @@ for (let i = 0; i < 4; i++) {
142
147
obj . interactor . bindEvents ( element ) ;
143
148
obj . widgetManager . setRenderer ( obj . renderer ) ;
144
149
if ( i < 3 ) {
145
- obj . interactor . setInteractorStyle ( vtkInteractorStyleImage . newInstance ( ) ) ;
150
+ obj . interactor . setInteractorStyle (
151
+ debugPlanes
152
+ ? vtkInteractorStyleTrackballCamera . newInstance ( )
153
+ : vtkInteractorStyleImage . newInstance ( )
154
+ ) ;
146
155
obj . widgetInstance = obj . widgetManager . addWidget ( widget , xyzToViewType [ i ] ) ;
147
156
obj . widgetInstance . setScaleInPixels ( true ) ;
148
157
obj . widgetInstance . setRotationHandlePosition ( 0.75 ) ;
@@ -155,6 +164,7 @@ for (let i = 0; i < 4; i++) {
155
164
) ;
156
165
}
157
166
167
+ // CPU reslice
158
168
obj . reslice = vtkImageReslice . newInstance ( ) ;
159
169
obj . reslice . setSlabMode ( SlabMode . MEAN ) ;
160
170
obj . reslice . setSlabNumberOfSlices ( 1 ) ;
@@ -165,6 +175,18 @@ for (let i = 0; i < 4; i++) {
165
175
obj . resliceMapper . setInputConnection ( obj . reslice . getOutputPort ( ) ) ;
166
176
obj . resliceActor = vtkImageSlice . newInstance ( ) ;
167
177
obj . resliceActor . setMapper ( obj . resliceMapper ) ;
178
+
179
+ // GPU reslice
180
+ obj . volume = vtkVolume . newInstance ( ) ;
181
+ obj . volumeMapper = vtkVolumeMapper . newInstance ( ) ;
182
+ // obj.volumeMapper.setMaximumSamplesPerRay(1);
183
+ obj . volume . setMapper ( obj . volumeMapper ) ;
184
+
185
+ obj . sliceHelper = vtkVolumeMapper . vtkSliceHelper . newInstance ( {
186
+ thickness : 1 ,
187
+ } ) ;
188
+ obj . sliceHelper . registerClipPlanesToMapper ( obj . volumeMapper ) ;
189
+
168
190
obj . sphereActors = [ ] ;
169
191
obj . sphereSources = [ ] ;
170
192
@@ -253,6 +275,7 @@ function updateReslice(
253
275
viewType : '' ,
254
276
reslice : null ,
255
277
actor : null ,
278
+ sliceHelper : null ,
256
279
renderer : null ,
257
280
resetFocalPoint : false , // Reset the focal point to the center of the display image
258
281
keepFocalPointPosition : false , // Defines if the focal point position is kepts (same display distance from reslice cursor center)
@@ -267,9 +290,20 @@ function updateReslice(
267
290
) ;
268
291
if ( obj . modified ) {
269
292
// Get returned modified from setter to know if we have to render
293
+ // CPU
270
294
interactionContext . actor . setUserMatrix (
271
295
interactionContext . reslice . getResliceAxes ( )
272
296
) ;
297
+ // GPU
298
+ interactionContext . sliceHelper . setNormal (
299
+ interactionContext . reslice . getResliceAxes ( ) [ 8 ] ,
300
+ interactionContext . reslice . getResliceAxes ( ) [ 9 ] ,
301
+ interactionContext . reslice . getResliceAxes ( ) [ 10 ]
302
+ ) ;
303
+ interactionContext . sliceHelper . setOrigin (
304
+ widget . getWidgetState ( ) . getCenter ( )
305
+ ) ;
306
+
273
307
interactionContext . sphereSources [ 0 ] . setCenter ( ...obj . origin ) ;
274
308
interactionContext . sphereSources [ 1 ] . setCenter ( ...obj . point1 ) ;
275
309
interactionContext . sphereSources [ 2 ] . setCenter ( ...obj . point2 ) ;
@@ -301,8 +335,17 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
301
335
view3D . renderer . addActor ( outlineActor ) ;
302
336
303
337
viewAttributes . forEach ( ( obj , i ) => {
304
- obj . reslice . setInputData ( image ) ;
305
- obj . renderer . addActor ( obj . resliceActor ) ;
338
+ obj . reslice . setInputData ( image ) ; // CPU
339
+ obj . volumeMapper . setInputData ( image ) ; // GPU
340
+
341
+ obj . renderer . addActor ( obj . resliceActor ) ; // CPU
342
+ obj . renderer . addVolume ( obj . volume ) ; // GPU
343
+
344
+ obj . volume
345
+ . getProperty ( )
346
+ . getRGBTransferFunction ( 0 )
347
+ . setRange ( ...image . getPointData ( ) . getScalars ( ) . getRange ( ) ) ;
348
+
306
349
view3D . renderer . addActor ( obj . resliceActor ) ;
307
350
obj . sphereActors . forEach ( ( actor ) => {
308
351
obj . renderer . addActor ( actor ) ;
@@ -333,7 +376,8 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
333
376
updateReslice ( {
334
377
viewType,
335
378
reslice,
336
- actor : obj . resliceActor ,
379
+ actor : obj . resliceActor , // CPU
380
+ sliceHelper : obj . sliceHelper , // GPU
337
381
renderer : obj . renderer ,
338
382
resetFocalPoint : false ,
339
383
keepFocalPointPosition,
@@ -347,7 +391,8 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
347
391
updateReslice ( {
348
392
viewType,
349
393
reslice,
350
- actor : obj . resliceActor ,
394
+ actor : obj . resliceActor , // CPU
395
+ sliceHelper : obj . sliceHelper , // GPU
351
396
renderer : obj . renderer ,
352
397
resetFocalPoint : true , // At first initilization, center the focal point to the image center
353
398
keepFocalPointPosition : false , // Don't update the focal point as we already set it to the center of the image
@@ -375,6 +420,7 @@ function updateViews() {
375
420
viewType : xyzToViewType [ i ] ,
376
421
reslice : obj . reslice ,
377
422
actor : obj . resliceActor ,
423
+ sliceHelper : obj . sliceHelper ,
378
424
renderer : obj . renderer ,
379
425
resetFocalPoint : true ,
380
426
keepFocalPointPosition : false ,
@@ -411,6 +457,20 @@ checkboxScaleInPixels.addEventListener('change', (ev) => {
411
457
} ) ;
412
458
} ) ;
413
459
460
+ document . getElementById ( 'renderWithGPU' ) . addEventListener ( 'change' , ( ev ) => {
461
+ renderWithGPU = ev . target . checked ;
462
+ viewAttributes . forEach ( ( obj , i ) => {
463
+ obj . resliceActor . setVisibility ( ! renderWithGPU ) ;
464
+ obj . volume . setVisibility ( renderWithGPU ) ;
465
+ obj . interactor . render ( ) ;
466
+ } ) ;
467
+ } ) ;
468
+ viewAttributes . forEach ( ( obj , i ) => {
469
+ obj . resliceActor . setVisibility ( ! renderWithGPU ) ;
470
+ obj . volume . setVisibility ( renderWithGPU ) ;
471
+ obj . interactor . render ( ) ;
472
+ } ) ;
473
+
414
474
const optionSlabModeMin = document . getElementById ( 'slabModeMin' ) ;
415
475
optionSlabModeMin . value = SlabMode . MIN ;
416
476
const optionSlabModeMax = document . getElementById ( 'slabModeMax' ) ;
@@ -419,10 +479,16 @@ const optionSlabModeMean = document.getElementById('slabModeMean');
419
479
optionSlabModeMean . value = SlabMode . MEAN ;
420
480
const optionSlabModeSum = document . getElementById ( 'slabModeSum' ) ;
421
481
optionSlabModeSum . value = SlabMode . SUM ;
422
- const selectSlabMode = document . getElementById ( 'slabMode' ) ;
423
- selectSlabMode . addEventListener ( 'change' , ( ev ) => {
482
+ const slabModeToBlendMode = {
483
+ [ SlabMode . MIN ] : BlendMode . MINIMUM_INTENSITY_BLEND ,
484
+ [ SlabMode . MAX ] : BlendMode . MAXIMUM_INTENSITY_BLEND ,
485
+ [ SlabMode . MEAN ] : BlendMode . AVERAGE_INTENSITY_BLEND ,
486
+ [ SlabMode . SUM ] : BlendMode . ADDITIVE_INTENSITY_BLEND ,
487
+ } ;
488
+ document . getElementById ( 'slabMode' ) . addEventListener ( 'change' , ( ev ) => {
424
489
viewAttributes . forEach ( ( obj ) => {
425
- obj . reslice . setSlabMode ( Number ( ev . target . value ) ) ;
490
+ obj . reslice . setSlabMode ( Number ( ev . target . value ) ) ; // CPU
491
+ obj . volumeMapper . setBlendMode ( slabModeToBlendMode [ ev . target . value ] ) ; // GPU
426
492
} ) ;
427
493
updateViews ( ) ;
428
494
} ) ;
@@ -432,7 +498,8 @@ sliderSlabNumberofSlices.addEventListener('change', (ev) => {
432
498
const trSlabNumberValue = document . getElementById ( 'slabNumberValue' ) ;
433
499
trSlabNumberValue . innerHTML = ev . target . value ;
434
500
viewAttributes . forEach ( ( obj ) => {
435
- obj . reslice . setSlabNumberOfSlices ( ev . target . value ) ;
501
+ obj . reslice . setSlabNumberOfSlices ( ev . target . value ) ; // CPU
502
+ obj . sliceHelper . setThickness ( Number ( ev . target . value ) ) ; // GPU
436
503
} ) ;
437
504
updateViews ( ) ;
438
505
} ) ;
@@ -447,7 +514,10 @@ buttonReset.addEventListener('click', () => {
447
514
const selectInterpolationMode = document . getElementById ( 'selectInterpolation' ) ;
448
515
selectInterpolationMode . addEventListener ( 'change' , ( ev ) => {
449
516
viewAttributes . forEach ( ( obj ) => {
450
- obj . reslice . setInterpolationMode ( Number ( ev . target . selectedIndex ) ) ;
517
+ obj . reslice . setInterpolationMode ( Number ( ev . target . selectedIndex ) ) ; // CPU
518
+ obj . volume
519
+ . getProperty ( )
520
+ . setInterpolationType ( Number ( ev . target . selectedIndex ) ) ; // GPU
451
521
} ) ;
452
522
updateViews ( ) ;
453
523
} ) ;
0 commit comments