@@ -18,6 +18,8 @@ import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
1818import vtkOutlineFilter from 'vtk.js/Sources/Filters/General/OutlineFilter' ;
1919import vtkOrientationMarkerWidget from 'vtk.js/Sources/Interaction/Widgets/OrientationMarkerWidget' ;
2020import 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' ;
2123import vtkWidgetManager from 'vtk.js/Sources/Widgets/Core/WidgetManager' ;
2224
2325import vtkSphereSource from 'vtk.js/Sources/Filters/Sources/SphereSource' ;
@@ -31,6 +33,7 @@ import controlPanel from './controlPanel.html';
3133
3234// Force the loading of HttpDataAccessHelper to support gzip decompression
3335import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper' ;
36+ import { BlendMode } from '../../../../Rendering/Core/VolumeMapper/Constants' ;
3437
3538// ----------------------------------------------------------------------------
3639// Define main attributes
@@ -53,6 +56,8 @@ widgetState.setSphereRadius(10 * window.devicePixelRatio);
5356widgetState . setLineThickness ( 5 ) ;
5457
5558const showDebugActors = true ;
59+ const debugPlanes = false ;
60+ let renderWithGPU = true ;
5661
5762// ----------------------------------------------------------------------------
5863// Define html structure
@@ -142,7 +147,11 @@ for (let i = 0; i < 4; i++) {
142147 obj . interactor . bindEvents ( element ) ;
143148 obj . widgetManager . setRenderer ( obj . renderer ) ;
144149 if ( i < 3 ) {
145- obj . interactor . setInteractorStyle ( vtkInteractorStyleImage . newInstance ( ) ) ;
150+ obj . interactor . setInteractorStyle (
151+ debugPlanes
152+ ? vtkInteractorStyleTrackballCamera . newInstance ( )
153+ : vtkInteractorStyleImage . newInstance ( )
154+ ) ;
146155 obj . widgetInstance = obj . widgetManager . addWidget ( widget , xyzToViewType [ i ] ) ;
147156 obj . widgetInstance . setScaleInPixels ( true ) ;
148157 obj . widgetInstance . setRotationHandlePosition ( 0.75 ) ;
@@ -155,6 +164,7 @@ for (let i = 0; i < 4; i++) {
155164 ) ;
156165 }
157166
167+ // CPU reslice
158168 obj . reslice = vtkImageReslice . newInstance ( ) ;
159169 obj . reslice . setSlabMode ( SlabMode . MEAN ) ;
160170 obj . reslice . setSlabNumberOfSlices ( 1 ) ;
@@ -165,6 +175,18 @@ for (let i = 0; i < 4; i++) {
165175 obj . resliceMapper . setInputConnection ( obj . reslice . getOutputPort ( ) ) ;
166176 obj . resliceActor = vtkImageSlice . newInstance ( ) ;
167177 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+
168190 obj . sphereActors = [ ] ;
169191 obj . sphereSources = [ ] ;
170192
@@ -253,6 +275,7 @@ function updateReslice(
253275 viewType : '' ,
254276 reslice : null ,
255277 actor : null ,
278+ sliceHelper : null ,
256279 renderer : null ,
257280 resetFocalPoint : false , // Reset the focal point to the center of the display image
258281 keepFocalPointPosition : false , // Defines if the focal point position is kepts (same display distance from reslice cursor center)
@@ -267,9 +290,20 @@ function updateReslice(
267290 ) ;
268291 if ( obj . modified ) {
269292 // Get returned modified from setter to know if we have to render
293+ // CPU
270294 interactionContext . actor . setUserMatrix (
271295 interactionContext . reslice . getResliceAxes ( )
272296 ) ;
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+
273307 interactionContext . sphereSources [ 0 ] . setCenter ( ...obj . origin ) ;
274308 interactionContext . sphereSources [ 1 ] . setCenter ( ...obj . point1 ) ;
275309 interactionContext . sphereSources [ 2 ] . setCenter ( ...obj . point2 ) ;
@@ -301,8 +335,17 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
301335 view3D . renderer . addActor ( outlineActor ) ;
302336
303337 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+
306349 view3D . renderer . addActor ( obj . resliceActor ) ;
307350 obj . sphereActors . forEach ( ( actor ) => {
308351 obj . renderer . addActor ( actor ) ;
@@ -333,7 +376,8 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
333376 updateReslice ( {
334377 viewType,
335378 reslice,
336- actor : obj . resliceActor ,
379+ actor : obj . resliceActor , // CPU
380+ sliceHelper : obj . sliceHelper , // GPU
337381 renderer : obj . renderer ,
338382 resetFocalPoint : false ,
339383 keepFocalPointPosition,
@@ -347,7 +391,8 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {
347391 updateReslice ( {
348392 viewType,
349393 reslice,
350- actor : obj . resliceActor ,
394+ actor : obj . resliceActor , // CPU
395+ sliceHelper : obj . sliceHelper , // GPU
351396 renderer : obj . renderer ,
352397 resetFocalPoint : true , // At first initilization, center the focal point to the image center
353398 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() {
375420 viewType : xyzToViewType [ i ] ,
376421 reslice : obj . reslice ,
377422 actor : obj . resliceActor ,
423+ sliceHelper : obj . sliceHelper ,
378424 renderer : obj . renderer ,
379425 resetFocalPoint : true ,
380426 keepFocalPointPosition : false ,
@@ -411,6 +457,20 @@ checkboxScaleInPixels.addEventListener('change', (ev) => {
411457 } ) ;
412458} ) ;
413459
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+
414474const optionSlabModeMin = document . getElementById ( 'slabModeMin' ) ;
415475optionSlabModeMin . value = SlabMode . MIN ;
416476const optionSlabModeMax = document . getElementById ( 'slabModeMax' ) ;
@@ -419,10 +479,16 @@ const optionSlabModeMean = document.getElementById('slabModeMean');
419479optionSlabModeMean . value = SlabMode . MEAN ;
420480const optionSlabModeSum = document . getElementById ( 'slabModeSum' ) ;
421481optionSlabModeSum . 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 ) => {
424489 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
426492 } ) ;
427493 updateViews ( ) ;
428494} ) ;
@@ -432,7 +498,8 @@ sliderSlabNumberofSlices.addEventListener('change', (ev) => {
432498 const trSlabNumberValue = document . getElementById ( 'slabNumberValue' ) ;
433499 trSlabNumberValue . innerHTML = ev . target . value ;
434500 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
436503 } ) ;
437504 updateViews ( ) ;
438505} ) ;
@@ -447,7 +514,10 @@ buttonReset.addEventListener('click', () => {
447514const selectInterpolationMode = document . getElementById ( 'selectInterpolation' ) ;
448515selectInterpolationMode . addEventListener ( 'change' , ( ev ) => {
449516 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
451521 } ) ;
452522 updateViews ( ) ;
453523} ) ;
0 commit comments