diff --git a/Sources/Rendering/Core/ImageResliceMapper/index.d.ts b/Sources/Rendering/Core/ImageResliceMapper/index.d.ts index 9eaa73da5eb..b5a888f4b4c 100755 --- a/Sources/Rendering/Core/ImageResliceMapper/index.d.ts +++ b/Sources/Rendering/Core/ImageResliceMapper/index.d.ts @@ -1,10 +1,9 @@ import vtkAbstractImageMapper, { IAbstractImageMapperInitialValues, } from '../AbstractImageMapper'; -import vtkImageData from '../../../Common/DataModel/ImageData'; import vtkPlane from '../../../Common/DataModel/Plane'; import vtkPolyData from '../../../Common/DataModel/PolyData'; -import { Bounds, Nullable, Vector3 } from '../../../types'; +import { Bounds, Extent } from '../../../types'; import { SlabTypes } from './Constants'; interface ICoincidentTopology { @@ -234,6 +233,25 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper { * @param {vtkPolyData} slicePolyData The polydata to slice the volume with. Default: null */ setSlicePolyData(slicePolyData: vtkPolyData): boolean; + + /** + * Tells the mapper to only update the specified extents. + * + * If there are zero extents, the mapper updates the entire volume texture. + * Otherwise, the mapper will only update the texture by the specified extents + * during the next render call. + * + * This array is cleared after a successful render. + * @param extents + */ + setUpdatedExtents(extents: Extent[]): boolean; + + /** + * Retrieves the updated extents. + * + * This array is cleared after every successful render. + */ + getUpdatedExtents(): Extent[]; } /** diff --git a/Sources/Rendering/Core/ImageResliceMapper/index.js b/Sources/Rendering/Core/ImageResliceMapper/index.js index 66136a4c85a..953818b3add 100644 --- a/Sources/Rendering/Core/ImageResliceMapper/index.js +++ b/Sources/Rendering/Core/ImageResliceMapper/index.js @@ -39,18 +39,20 @@ function vtkImageResliceMapper(publicAPI, model) { // Object factory // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { +const defaultValues = (initialValues) => ({ slabThickness: 0.0, slabTrapezoidIntegration: 0, slabType: SlabTypes.MEAN, slicePlane: null, slicePolyData: null, -}; + updatedExtents: [], + ...initialValues, +}); // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); + Object.assign(model, defaultValues(initialValues)); // Build VTK API vtkAbstractImageMapper.extend(publicAPI, model, initialValues); @@ -61,6 +63,7 @@ export function extend(publicAPI, model, initialValues = {}) { 'slabType', 'slicePlane', 'slicePolyData', + 'updatedExtents', ]); CoincidentTopologyHelper.implementCoincidentTopologyMethods(publicAPI, model); diff --git a/Sources/Rendering/Core/VolumeMapper/index.d.ts b/Sources/Rendering/Core/VolumeMapper/index.d.ts index 3c9b53be6ef..b8dfb534a18 100755 --- a/Sources/Rendering/Core/VolumeMapper/index.d.ts +++ b/Sources/Rendering/Core/VolumeMapper/index.d.ts @@ -1,7 +1,9 @@ -import vtkPiecewiseFunction from "../../../Common/DataModel/PiecewiseFunction"; -import { Bounds, Range, Extent } from "../../../types"; -import vtkAbstractMapper3D, { IAbstractMapper3DInitialValues } from "../AbstractMapper3D"; -import { BlendMode, FilterMode } from "./Constants"; +import vtkPiecewiseFunction from '../../../Common/DataModel/PiecewiseFunction'; +import { Bounds, Range, Extent } from '../../../types'; +import vtkAbstractMapper3D, { + IAbstractMapper3DInitialValues, +} from '../AbstractMapper3D'; +import { BlendMode, FilterMode } from './Constants'; /** * @@ -279,19 +281,19 @@ export interface vtkVolumeMapper extends vtkAbstractMapper3D { */ setLAOKernelRadius(LAOKernelRadius: number): void; - /** - * Set kernel size for local ambient occlusion. It specifies the number of rays that are randomly sampled in the hemisphere. - * Value is clipped between 1 and 32. - * @param LAOKernelSize - */ - setLAOKernelSize(LAOKernelSize: number): void; + /** + * Set kernel size for local ambient occlusion. It specifies the number of rays that are randomly sampled in the hemisphere. + * Value is clipped between 1 and 32. + * @param LAOKernelSize + */ + setLAOKernelSize(LAOKernelSize: number): void; - /** - * Set kernel radius for local ambient occlusion. It specifies the number of samples that are considered on each random ray. - * Value must be greater than or equal to 1. - * @param LAOKernelRadius - */ - setLAOKernelRadius(LAOKernelRadius: number): void; + /** + * Set kernel radius for local ambient occlusion. It specifies the number of samples that are considered on each random ray. + * Value must be greater than or equal to 1. + * @param LAOKernelRadius + */ + setLAOKernelRadius(LAOKernelRadius: number): void; /** * Tells the mapper to only update the specified extents. @@ -312,10 +314,10 @@ export interface vtkVolumeMapper extends vtkAbstractMapper3D { */ getUpdatedExtents(): Extent[]; - /** - * - */ - update(): void; + /** + * + */ + update(): void; } /** diff --git a/Sources/Rendering/OpenGL/ImageResliceMapper/index.js b/Sources/Rendering/OpenGL/ImageResliceMapper/index.js index 3319e32094c..3048ba046f1 100644 --- a/Sources/Rendering/OpenGL/ImageResliceMapper/index.js +++ b/Sources/Rendering/OpenGL/ImageResliceMapper/index.js @@ -215,24 +215,39 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) { const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars); const reBuildTex = !tex?.vtkObj || tex?.hash !== toString; - if (reBuildTex) { + const hasUpdatedExtents = !!model.renderable.getUpdatedExtents().length; + + // reset the scalars texture if there are no updated extents + if (reBuildTex && !hasUpdatedExtents) { + // Use norm16 for scalar texture if the extension is available + model.scalarTexture.setOglNorm16Ext( + model.context.getExtension('EXT_texture_norm16') + ); + + model.scalarTexture.releaseGraphicsResources(model._openGLRenderWindow); + model.scalarTexture.resetFormatAndType(); + } + + if (reBuildTex || hasUpdatedExtents) { if (!model.openGLTexture) { model.openGLTexture = vtkOpenGLTexture.newInstance(); model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow); } + + // If hasUpdatedExtents, then the texture is partially updated + const updatedExtents = [...model.renderable.getUpdatedExtents()]; + // clear the array to acknowledge the update. + model.renderable.setUpdatedExtents([]); + // Build the image scalar texture const dims = image.getDimensions(); - // Use norm16 for the 3D texture if the extension is available - model.openGLTexture.setOglNorm16Ext( - model.context.getExtension('EXT_texture_norm16') - ); - model.openGLTexture.releaseGraphicsResources(model._openGLRenderWindow); - model.openGLTexture.resetFormatAndType(); model.openGLTexture.create3DFilterableFromDataArray( dims[0], dims[1], dims[2], - scalars + scalars, + false, + updatedExtents ); if (scalars) { model._openGLRenderWindow.setGraphicsResourceForObject( diff --git a/Sources/Rendering/OpenGL/Texture/index.d.ts b/Sources/Rendering/OpenGL/Texture/index.d.ts index 122f62ef21e..b8c9544eac1 100644 --- a/Sources/Rendering/OpenGL/Texture/index.d.ts +++ b/Sources/Rendering/OpenGL/Texture/index.d.ts @@ -1,7 +1,7 @@ import { Wrap, Filter } from './Constants'; import vtkOpenGLRenderWindow from '../RenderWindow'; import { Extent, Nullable } from '../../../types'; -import { VtkDataTypes } from "../../../Common/Core/DataArray"; +import { VtkDataTypes } from '../../../Common/Core/DataArray'; import { vtkViewNode } from '../../../Rendering/SceneGraph/ViewNode'; import { vtkObject } from '../../../interfaces'; @@ -268,7 +268,15 @@ export interface vtkOpenGLTexture extends vtkViewNode { * @param updatedExtents Only update the specified extents (default: []) * @returns {boolean} True if the texture was successfully created, false otherwise. */ - create3DFromRaw(width: number, height: number, depth: number, numComps: number, dataType: VtkDataTypes, data: any, updatedExtents?: Extent[]): boolean; + create3DFromRaw( + width: number, + height: number, + depth: number, + numComps: number, + dataType: VtkDataTypes, + data: any, + updatedExtents?: Extent[] + ): boolean; /** * Creates a 3D filterable texture from raw data, with a preference for size over accuracy if necessary. @@ -285,7 +293,16 @@ export interface vtkOpenGLTexture extends vtkViewNode { * @param updatedExtents Only update the specified extents (default: []) * @returns {boolean} True if the texture was successfully created, false otherwise. */ - create3DFilterableFromRaw(width: number, height: number, depth: number, numComps: number, dataType: VtkDataTypes, values: any, preferSizeOverAccuracy: boolean, updatedExtents?: Extent[]): boolean; + create3DFilterableFromRaw( + width: number, + height: number, + depth: number, + numComps: number, + dataType: VtkDataTypes, + values: any, + preferSizeOverAccuracy: boolean, + updatedExtents?: Extent[] + ): boolean; /** * Creates a 3D filterable texture from a data array, with a preference for size over accuracy if necessary. @@ -300,7 +317,14 @@ export interface vtkOpenGLTexture extends vtkViewNode { * @param updatedExtents Only update the specified extents (default: []) * @returns {boolean} True if the texture was successfully created, false otherwise. */ - create3DFilterableFromDataArray(width: number, height: number, depth: number, dataArray: any, preferSizeOverAccuracy: boolean, updatedExtents?: Extent[]): boolean; + create3DFilterableFromDataArray( + width: number, + height: number, + depth: number, + dataArray: any, + preferSizeOverAccuracy: boolean, + updatedExtents?: Extent[] + ): boolean; /** * Sets the OpenGL render window in which the texture will be used.