@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.
- package/BREAKING_CHANGES.md +3 -0
- package/IO/Image.js +1 -3
- package/Interaction/Manipulators/KeyboardCameraManipulator.d.ts +113 -0
- package/Rendering/Core/Actor.d.ts +5 -20
- package/Rendering/Core/Actor.js +5 -68
- package/Rendering/Core/ImageProperty.d.ts +0 -22
- package/Rendering/Core/ImageSlice.d.ts +7 -23
- package/Rendering/Core/ImageSlice.js +9 -68
- package/Rendering/Core/PointPicker.js +1 -4
- package/Rendering/Core/Prop3D.d.ts +39 -2
- package/Rendering/Core/Prop3D.js +81 -2
- package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
- package/Rendering/Core/Volume.d.ts +5 -20
- package/Rendering/Core/Volume.js +2 -70
- package/Rendering/Core/VolumeMapper/Constants.d.ts +0 -7
- package/Rendering/Core/VolumeMapper/Constants.js +2 -8
- package/Rendering/Core/VolumeMapper.d.ts +16 -140
- package/Rendering/Core/VolumeMapper.js +17 -52
- package/Rendering/Core/VolumeProperty/Constants.d.ts +12 -3
- package/Rendering/Core/VolumeProperty/Constants.js +11 -4
- package/Rendering/Core/VolumeProperty.d.ts +120 -4
- package/Rendering/Core/VolumeProperty.js +49 -4
- package/Rendering/OpenGL/ImageCPRMapper.js +27 -19
- package/Rendering/OpenGL/ImageMapper.js +34 -41
- package/Rendering/OpenGL/ImageResliceMapper.js +261 -172
- package/Rendering/OpenGL/PolyDataMapper.js +1 -8
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +3 -3
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +8 -5
- package/Rendering/OpenGL/VolumeMapper.js +710 -772
- package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
- package/Rendering/WebGPU/VolumePassFSQ.js +2 -2
- package/index.d.ts +1 -1
- package/macros2.js +1 -1
- package/package.json +1 -1
- package/IO/Image/TGAReader/Constants.js +0 -28
- package/IO/Image/TGAReader.d.ts +0 -121
- package/IO/Image/TGAReader.js +0 -418
|
@@ -13,7 +13,7 @@ import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
|
|
|
13
13
|
import vtkShaderProgram from './ShaderProgram.js';
|
|
14
14
|
import vtkTransform from '../../Common/Transform/Transform.js';
|
|
15
15
|
import vtkViewNode from '../SceneGraph/ViewNode.js';
|
|
16
|
-
import { getImageDataHash,
|
|
16
|
+
import { getImageDataHash, getTransferFunctionsHash } from './RenderWindow/resourceSharingHelper.js';
|
|
17
17
|
import { v as vtkImageResliceMapperVS } from './glsl/vtkImageResliceMapperVS.glsl.js';
|
|
18
18
|
import { v as vtkImageResliceMapperFS } from './glsl/vtkImageResliceMapperFS.glsl.js';
|
|
19
19
|
import { Filter } from './Texture/Constants.js';
|
|
@@ -49,8 +49,43 @@ function safeMatrixMultiply(matrixArray, matrixType, tmpMat) {
|
|
|
49
49
|
function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
50
50
|
// Set our className
|
|
51
51
|
model.classHierarchy.push('vtkOpenGLImageResliceMapper');
|
|
52
|
+
|
|
53
|
+
// Associate a reference counter to each graphics resource
|
|
54
|
+
const graphicsResourceReferenceCount = new Map();
|
|
55
|
+
function decreaseGraphicsResourceCount(openGLRenderWindow, coreObject) {
|
|
56
|
+
if (!coreObject) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const oldCount = graphicsResourceReferenceCount.get(coreObject) ?? 0;
|
|
60
|
+
const newCount = oldCount - 1;
|
|
61
|
+
if (newCount <= 0) {
|
|
62
|
+
openGLRenderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI);
|
|
63
|
+
graphicsResourceReferenceCount.delete(coreObject);
|
|
64
|
+
} else {
|
|
65
|
+
graphicsResourceReferenceCount.set(coreObject, newCount);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function increaseGraphicsResourceCount(openGLRenderWindow, coreObject) {
|
|
69
|
+
if (!coreObject) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const oldCount = graphicsResourceReferenceCount.get(coreObject) ?? 0;
|
|
73
|
+
const newCount = oldCount + 1;
|
|
74
|
+
graphicsResourceReferenceCount.set(coreObject, newCount);
|
|
75
|
+
if (oldCount <= 0) {
|
|
76
|
+
openGLRenderWindow.registerGraphicsResourceUser(coreObject, publicAPI);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function replaceGraphicsResource(openGLRenderWindow, oldResourceCoreObject, newResourceCoreObject) {
|
|
80
|
+
if (oldResourceCoreObject === newResourceCoreObject) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
decreaseGraphicsResourceCount(openGLRenderWindow, oldResourceCoreObject);
|
|
84
|
+
increaseGraphicsResourceCount(openGLRenderWindow, newResourceCoreObject);
|
|
85
|
+
}
|
|
52
86
|
function unregisterGraphicsResources(renderWindow) {
|
|
53
|
-
|
|
87
|
+
// Convert to an array using the spread operator as Firefox doesn't support Iterator.forEach()
|
|
88
|
+
[...graphicsResourceReferenceCount.keys()].forEach(coreObject => renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI));
|
|
54
89
|
}
|
|
55
90
|
publicAPI.buildPass = prepass => {
|
|
56
91
|
if (prepass) {
|
|
@@ -110,11 +145,28 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
110
145
|
type: 'StartEvent'
|
|
111
146
|
});
|
|
112
147
|
model.renderable.update();
|
|
113
|
-
|
|
114
|
-
|
|
148
|
+
const numberOfInputs = model.renderable.getNumberOfInputPorts();
|
|
149
|
+
model.currentValidInputs = [];
|
|
150
|
+
for (let inputIndex = 0; inputIndex < numberOfInputs; ++inputIndex) {
|
|
151
|
+
const imageData = model.renderable.getInputData(inputIndex);
|
|
152
|
+
if (imageData && !imageData.isDeleted()) {
|
|
153
|
+
model.currentValidInputs.push({
|
|
154
|
+
imageData,
|
|
155
|
+
inputIndex
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const numberOfValidInputs = model.currentValidInputs.length;
|
|
160
|
+
if (numberOfValidInputs <= 0) {
|
|
115
161
|
vtkErrorMacro('No input!');
|
|
116
162
|
return;
|
|
117
163
|
}
|
|
164
|
+
|
|
165
|
+
// Number of components
|
|
166
|
+
const firstImageData = model.currentValidInputs[0].imageData;
|
|
167
|
+
const firstScalars = firstImageData.getPointData().getScalars();
|
|
168
|
+
model.multiTexturePerVolumeEnabled = numberOfValidInputs > 1;
|
|
169
|
+
model.numberOfComponents = model.multiTexturePerVolumeEnabled ? numberOfValidInputs : firstScalars.getNumberOfComponents();
|
|
118
170
|
publicAPI.updateResliceGeometry();
|
|
119
171
|
publicAPI.renderPieceStart(ren, actor);
|
|
120
172
|
publicAPI.renderPieceDraw(ren, actor);
|
|
@@ -126,17 +178,35 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
126
178
|
publicAPI.renderPieceStart = (ren, actor) => {
|
|
127
179
|
// make sure the BOs are up to date
|
|
128
180
|
publicAPI.updateBufferObjects(ren, actor);
|
|
129
|
-
|
|
181
|
+
|
|
182
|
+
// Update filters for scalar textures
|
|
183
|
+
const actorProperties = actor.getProperties();
|
|
184
|
+
model.currentValidInputs.forEach(_ref => {
|
|
185
|
+
let {
|
|
186
|
+
inputIndex
|
|
187
|
+
} = _ref;
|
|
188
|
+
const actorProperty = actorProperties[inputIndex];
|
|
189
|
+
const interpolationType = actorProperty.getInterpolationType();
|
|
190
|
+
const scalarTexture = model.scalarTextures[inputIndex];
|
|
191
|
+
if (interpolationType === InterpolationType.NEAREST) {
|
|
192
|
+
scalarTexture.setMinificationFilter(Filter.NEAREST);
|
|
193
|
+
scalarTexture.setMagnificationFilter(Filter.NEAREST);
|
|
194
|
+
} else {
|
|
195
|
+
scalarTexture.setMinificationFilter(Filter.LINEAR);
|
|
196
|
+
scalarTexture.setMagnificationFilter(Filter.LINEAR);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Update color and opacity texture filters
|
|
201
|
+
const firstValidInput = model.currentValidInputs[0];
|
|
202
|
+
const firstProperty = actorProperties[firstValidInput.inputIndex];
|
|
203
|
+
const iType = firstProperty.getInterpolationType();
|
|
130
204
|
if (iType === InterpolationType.NEAREST) {
|
|
131
|
-
model.openGLTexture.setMinificationFilter(Filter.NEAREST);
|
|
132
|
-
model.openGLTexture.setMagnificationFilter(Filter.NEAREST);
|
|
133
205
|
model.colorTexture.setMinificationFilter(Filter.NEAREST);
|
|
134
206
|
model.colorTexture.setMagnificationFilter(Filter.NEAREST);
|
|
135
207
|
model.pwfTexture.setMinificationFilter(Filter.NEAREST);
|
|
136
208
|
model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
|
|
137
209
|
} else {
|
|
138
|
-
model.openGLTexture.setMinificationFilter(Filter.LINEAR);
|
|
139
|
-
model.openGLTexture.setMagnificationFilter(Filter.LINEAR);
|
|
140
210
|
model.colorTexture.setMinificationFilter(Filter.LINEAR);
|
|
141
211
|
model.colorTexture.setMagnificationFilter(Filter.LINEAR);
|
|
142
212
|
model.pwfTexture.setMinificationFilter(Filter.LINEAR);
|
|
@@ -150,9 +220,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
150
220
|
const gl = model.context;
|
|
151
221
|
|
|
152
222
|
// render the texture
|
|
153
|
-
model.
|
|
154
|
-
|
|
155
|
-
model.pwfTexture.activate();
|
|
223
|
+
const allTextures = [...model.scalarTextures, model.colorTexture, model.pwfTexture];
|
|
224
|
+
allTextures.forEach(texture => texture.activate());
|
|
156
225
|
|
|
157
226
|
// update shaders if required
|
|
158
227
|
publicAPI.updateShaders(model.tris, ren, actor);
|
|
@@ -160,9 +229,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
160
229
|
// Finally draw
|
|
161
230
|
gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
|
|
162
231
|
model.tris.getVAO().release();
|
|
163
|
-
|
|
164
|
-
model.colorTexture.deactivate();
|
|
165
|
-
model.pwfTexture.deactivate();
|
|
232
|
+
allTextures.forEach(texture => texture.deactivate());
|
|
166
233
|
};
|
|
167
234
|
publicAPI.renderPieceFinish = (ren, actor) => {};
|
|
168
235
|
publicAPI.updateBufferObjects = (ren, actor) => {
|
|
@@ -171,56 +238,63 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
171
238
|
publicAPI.buildBufferObjects(ren, actor);
|
|
172
239
|
}
|
|
173
240
|
};
|
|
174
|
-
publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => model.VBOBuildTime.getMTime() < publicAPI.getMTime() || model.VBOBuildTime.getMTime() < actor.getMTime() || model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < actor.getProperty(
|
|
241
|
+
publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => model.VBOBuildTime.getMTime() < publicAPI.getMTime() || model.VBOBuildTime.getMTime() < actor.getMTime() || model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < actor.getProperty(model.currentValidInputs[0].inputIndex)?.getMTime() || model.currentValidInputs.some(_ref2 => {
|
|
242
|
+
let {
|
|
243
|
+
imageData
|
|
244
|
+
} = _ref2;
|
|
245
|
+
return model.VBOBuildTime.getMTime() < imageData.getMTime();
|
|
246
|
+
}) || model.VBOBuildTime.getMTime() < model.resliceGeom.getMTime() || model.scalarTextures.length !== model.currentValidInputs.length || !model.scalarTextures.every(texture => !!texture?.getHandle()) || !model.colorTexture?.getHandle() || !model.pwfTexture?.getHandle();
|
|
175
247
|
publicAPI.buildBufferObjects = (ren, actor) => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
const iComps = ppty.getIndependentComponents();
|
|
208
|
-
const numIComps = iComps ? numComp : 1;
|
|
248
|
+
model.currentValidInputs.forEach((_ref3, component) => {
|
|
249
|
+
let {
|
|
250
|
+
imageData
|
|
251
|
+
} = _ref3;
|
|
252
|
+
// rebuild the scalarTexture if the data has changed
|
|
253
|
+
const scalars = imageData.getPointData().getScalars();
|
|
254
|
+
const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
|
|
255
|
+
const scalarsHash = getImageDataHash(imageData, scalars);
|
|
256
|
+
const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
|
|
257
|
+
if (reBuildTex) {
|
|
258
|
+
const newScalarTexture = vtkOpenGLTexture.newInstance();
|
|
259
|
+
newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
260
|
+
// Build the textures
|
|
261
|
+
const dims = imageData.getDimensions();
|
|
262
|
+
// Use norm16 for scalar texture if the extension is available
|
|
263
|
+
newScalarTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
|
|
264
|
+
newScalarTexture.resetFormatAndType();
|
|
265
|
+
newScalarTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
|
|
266
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(scalars, newScalarTexture, scalarsHash);
|
|
267
|
+
model.scalarTextures[component] = newScalarTexture;
|
|
268
|
+
} else {
|
|
269
|
+
model.scalarTextures[component] = tex.oglObject;
|
|
270
|
+
}
|
|
271
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
|
|
272
|
+
model._scalarTexturesCore[component] = scalars;
|
|
273
|
+
});
|
|
274
|
+
const firstValidInput = model.currentValidInputs[0];
|
|
275
|
+
const actorProperties = actor.getProperties();
|
|
276
|
+
const firstActorProperty = actorProperties[firstValidInput.inputIndex];
|
|
277
|
+
const iComps = firstActorProperty.getIndependentComponents();
|
|
278
|
+
const numIComps = iComps ? model.numberOfComponents : 1;
|
|
209
279
|
const textureHeight = iComps ? 2 * numIComps : 1;
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
280
|
+
const colorTransferFunctions = [];
|
|
281
|
+
for (let component = 0; component < numIComps; ++component) {
|
|
282
|
+
colorTransferFunctions.push(firstActorProperty.getRGBTransferFunction(component));
|
|
283
|
+
}
|
|
284
|
+
const colorFuncHash = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
|
|
285
|
+
const firstColorTransferFunc = firstActorProperty.getRGBTransferFunction();
|
|
286
|
+
const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
|
|
287
|
+
const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== colorFuncHash;
|
|
214
288
|
if (reBuildC) {
|
|
215
289
|
const cWidth = 1024;
|
|
216
290
|
const cSize = cWidth * textureHeight * 3;
|
|
217
291
|
const cTable = new Uint8ClampedArray(cSize);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (
|
|
292
|
+
const newColorTexture = vtkOpenGLTexture.newInstance();
|
|
293
|
+
newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
294
|
+
if (firstColorTransferFunc) {
|
|
221
295
|
const tmpTable = new Float32Array(cWidth * 3);
|
|
222
296
|
for (let c = 0; c < numIComps; c++) {
|
|
223
|
-
const cfun =
|
|
297
|
+
const cfun = firstActorProperty.getRGBTransferFunction(c);
|
|
224
298
|
const cRange = cfun.getRange();
|
|
225
299
|
cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
|
|
226
300
|
if (iComps) {
|
|
@@ -230,52 +304,57 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
230
304
|
}
|
|
231
305
|
} else {
|
|
232
306
|
for (let i = 0; i < cWidth * 3; i++) {
|
|
233
|
-
cTable[c * cWidth *
|
|
307
|
+
cTable[c * cWidth * 3 + i] = 255.0 * tmpTable[i];
|
|
234
308
|
}
|
|
235
309
|
}
|
|
236
310
|
}
|
|
237
|
-
|
|
238
|
-
|
|
311
|
+
newColorTexture.resetFormatAndType();
|
|
312
|
+
newColorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
|
|
239
313
|
} else {
|
|
240
|
-
for (let
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (colorTransferFunc) {
|
|
249
|
-
model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, toString);
|
|
250
|
-
if (colorTransferFunc !== model._colorTransferFunc) {
|
|
251
|
-
model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
|
|
252
|
-
model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
|
|
314
|
+
for (let column = 0; column < cWidth * 3; ++column) {
|
|
315
|
+
const opacity = 255.0 * column / ((cWidth - 1) * 3);
|
|
316
|
+
for (let row = 0; row < textureHeight; ++row) {
|
|
317
|
+
// R, G, B
|
|
318
|
+
cTable[row * cWidth * 3 + column + 0] = opacity;
|
|
319
|
+
cTable[row * cWidth * 3 + column + 1] = opacity;
|
|
320
|
+
cTable[row * cWidth * 3 + column + 2] = opacity;
|
|
321
|
+
}
|
|
253
322
|
}
|
|
254
|
-
|
|
323
|
+
newColorTexture.resetFormatAndType();
|
|
324
|
+
newColorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
|
|
325
|
+
}
|
|
326
|
+
if (firstColorTransferFunc) {
|
|
327
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, newColorTexture, colorFuncHash);
|
|
255
328
|
}
|
|
329
|
+
model.colorTexture = newColorTexture;
|
|
256
330
|
} else {
|
|
257
331
|
model.colorTexture = cTex.oglObject;
|
|
258
332
|
}
|
|
333
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._colorTextureCore, firstColorTransferFunc);
|
|
334
|
+
model._colorTextureCore = firstColorTransferFunc;
|
|
259
335
|
|
|
260
336
|
// Build piecewise function buffer. This buffer is used either
|
|
261
337
|
// for component weighting or opacity, depending on whether we're
|
|
262
338
|
// rendering components independently or not.
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
339
|
+
const opacityFunctions = [];
|
|
340
|
+
for (let component = 0; component < numIComps; ++component) {
|
|
341
|
+
opacityFunctions.push(firstActorProperty.getPiecewiseFunction(component));
|
|
342
|
+
}
|
|
343
|
+
const opacityFuncHash = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
|
|
344
|
+
const firstPwFunc = firstActorProperty.getPiecewiseFunction();
|
|
345
|
+
const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
|
|
346
|
+
const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== opacityFuncHash;
|
|
268
347
|
if (reBuildPwf) {
|
|
269
348
|
const pwfWidth = 1024;
|
|
270
349
|
const pwfSize = pwfWidth * textureHeight;
|
|
271
350
|
const pwfTable = new Uint8ClampedArray(pwfSize);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (
|
|
351
|
+
const newOpacityTexture = vtkOpenGLTexture.newInstance();
|
|
352
|
+
newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
353
|
+
if (firstPwFunc) {
|
|
275
354
|
const pwfFloatTable = new Float32Array(pwfSize);
|
|
276
355
|
const tmpTable = new Float32Array(pwfWidth);
|
|
277
356
|
for (let c = 0; c < numIComps; ++c) {
|
|
278
|
-
const pwfun =
|
|
357
|
+
const pwfun = firstActorProperty.getPiecewiseFunction(c);
|
|
279
358
|
if (pwfun === null) {
|
|
280
359
|
// Piecewise constant max if no function supplied for this component
|
|
281
360
|
pwfFloatTable.fill(1.0);
|
|
@@ -290,30 +369,28 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
290
369
|
}
|
|
291
370
|
} else {
|
|
292
371
|
for (let i = 0; i < pwfWidth; i++) {
|
|
293
|
-
pwfFloatTable[
|
|
372
|
+
pwfFloatTable[i] = tmpTable[i];
|
|
294
373
|
}
|
|
295
374
|
}
|
|
296
375
|
}
|
|
297
376
|
}
|
|
298
|
-
|
|
299
|
-
|
|
377
|
+
newOpacityTexture.resetFormatAndType();
|
|
378
|
+
newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
|
|
300
379
|
} else {
|
|
301
380
|
// default is opaque
|
|
302
381
|
pwfTable.fill(255.0);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
if (pwFunc) {
|
|
307
|
-
model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, toString);
|
|
308
|
-
if (pwFunc !== model._pwFunc) {
|
|
309
|
-
model._openGLRenderWindow.registerGraphicsResourceUser(pwFunc, publicAPI);
|
|
310
|
-
model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
|
|
311
|
-
}
|
|
312
|
-
model._pwFunc = pwFunc;
|
|
382
|
+
newOpacityTexture.resetFormatAndType();
|
|
383
|
+
newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
|
|
313
384
|
}
|
|
385
|
+
if (firstPwFunc) {
|
|
386
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, newOpacityTexture, opacityFuncHash);
|
|
387
|
+
}
|
|
388
|
+
model.pwfTexture = newOpacityTexture;
|
|
314
389
|
} else {
|
|
315
390
|
model.pwfTexture = pwfTex.oglObject;
|
|
316
391
|
}
|
|
392
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._pwfTextureCore, firstPwFunc);
|
|
393
|
+
model._pwfTextureCore = firstPwFunc;
|
|
317
394
|
const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
|
|
318
395
|
if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
|
|
319
396
|
const points = vtkDataArray.newInstance({
|
|
@@ -374,11 +451,12 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
374
451
|
};
|
|
375
452
|
publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
|
|
376
453
|
const program = cellBO.getProgram();
|
|
454
|
+
const firstImageData = model.currentValidInputs[0].imageData;
|
|
377
455
|
if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
|
|
378
456
|
// Set the 3D texture
|
|
379
|
-
|
|
380
|
-
program.setUniformi(
|
|
381
|
-
}
|
|
457
|
+
model.scalarTextures.forEach((scalarTexture, component) => {
|
|
458
|
+
program.setUniformi(`volumeTexture[${component}]`, scalarTexture.getTextureUnit());
|
|
459
|
+
});
|
|
382
460
|
|
|
383
461
|
// Set the plane vertex attributes
|
|
384
462
|
if (program.isAttributeUsed('vertexWC')) {
|
|
@@ -397,7 +475,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
397
475
|
program.setUniformf('slabThickness', model.renderable.getSlabThickness());
|
|
398
476
|
}
|
|
399
477
|
if (program.isUniformUsed('spacing')) {
|
|
400
|
-
program.setUniform3fv('spacing',
|
|
478
|
+
program.setUniform3fv('spacing', firstImageData.getSpacing());
|
|
401
479
|
}
|
|
402
480
|
if (program.isUniformUsed('slabType')) {
|
|
403
481
|
program.setUniformi('slabType', model.renderable.getSlabType());
|
|
@@ -413,9 +491,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
413
491
|
|
|
414
492
|
// Set the world->texture matrix
|
|
415
493
|
if (program.isUniformUsed('WCTCMatrix')) {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
mat4.copy(model.tmpMat4, image.getIndexToWorld());
|
|
494
|
+
const dim = firstImageData.getDimensions();
|
|
495
|
+
mat4.copy(model.tmpMat4, firstImageData.getIndexToWorld());
|
|
419
496
|
mat4.translate(model.tmpMat4, model.tmpMat4, [-0.5, -0.5, -0.5]);
|
|
420
497
|
mat4.scale(model.tmpMat4, model.tmpMat4, dim);
|
|
421
498
|
mat4.invert(model.tmpMat4, model.tmpMat4);
|
|
@@ -464,8 +541,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
464
541
|
};
|
|
465
542
|
publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
|
|
466
543
|
const program = cellBO.getProgram();
|
|
467
|
-
const
|
|
468
|
-
const opacity =
|
|
544
|
+
const firstPpty = actor.getProperty(model.currentValidInputs[0].inputIndex);
|
|
545
|
+
const opacity = firstPpty.getOpacity();
|
|
469
546
|
program.setUniformf('opacity', opacity);
|
|
470
547
|
|
|
471
548
|
// Component mix
|
|
@@ -474,53 +551,56 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
474
551
|
// - 2 comps => LA
|
|
475
552
|
// - 3 comps => RGB + opacity from pwf
|
|
476
553
|
// - 4 comps => RGBA
|
|
477
|
-
const numComp = model.
|
|
478
|
-
const iComps =
|
|
554
|
+
const numComp = model.numberOfComponents;
|
|
555
|
+
const iComps = firstPpty.getIndependentComponents();
|
|
479
556
|
if (iComps) {
|
|
480
557
|
for (let i = 0; i < numComp; ++i) {
|
|
481
|
-
program.setUniformf(`mix${i}`,
|
|
558
|
+
program.setUniformf(`mix${i}`, firstPpty.getComponentWeight(i));
|
|
482
559
|
}
|
|
483
560
|
}
|
|
484
561
|
|
|
485
|
-
// Color opacity map
|
|
486
|
-
const volInfo = model.openGLTexture.getVolumeInfo();
|
|
487
|
-
|
|
488
562
|
// three levels of shift scale combined into one
|
|
489
563
|
// for performance in the fragment shader
|
|
490
|
-
for (let
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const
|
|
494
|
-
const
|
|
495
|
-
|
|
564
|
+
for (let component = 0; component < numComp; component++) {
|
|
565
|
+
const useMultiTexture = model.multiTexturePerVolumeEnabled;
|
|
566
|
+
const textureIndex = useMultiTexture ? component : 0;
|
|
567
|
+
const volInfoIndex = useMultiTexture ? 0 : component;
|
|
568
|
+
const scalarTexture = model.scalarTextures[textureIndex];
|
|
569
|
+
const volInfo = scalarTexture.getVolumeInfo();
|
|
570
|
+
const volScale = volInfo.scale[volInfoIndex];
|
|
571
|
+
const volOffset = volInfo.offset[volInfoIndex];
|
|
572
|
+
const target = iComps ? component : 0;
|
|
573
|
+
|
|
574
|
+
// color shift/scale
|
|
575
|
+
let cw = firstPpty.getColorWindow();
|
|
576
|
+
let cl = firstPpty.getColorLevel();
|
|
577
|
+
const cfun = firstPpty.getRGBTransferFunction(target);
|
|
578
|
+
if (cfun && firstPpty.getUseLookupTableScalarRange()) {
|
|
496
579
|
const cRange = cfun.getRange();
|
|
497
580
|
cw = cRange[1] - cRange[0];
|
|
498
581
|
cl = 0.5 * (cRange[1] + cRange[0]);
|
|
499
582
|
}
|
|
500
|
-
const
|
|
501
|
-
const
|
|
502
|
-
program.setUniformf(`cshift${
|
|
503
|
-
program.setUniformf(`cscale${
|
|
504
|
-
}
|
|
505
|
-
const texColorUnit = model.colorTexture.getTextureUnit();
|
|
506
|
-
program.setUniformi('colorTexture1', texColorUnit);
|
|
583
|
+
const colorScale = volScale / cw;
|
|
584
|
+
const colorShift = (volOffset - cl) / cw + 0.5;
|
|
585
|
+
program.setUniformf(`cshift${component}`, colorShift);
|
|
586
|
+
program.setUniformf(`cscale${component}`, colorScale);
|
|
507
587
|
|
|
508
|
-
|
|
509
|
-
for (let i = 0; i < numComp; i++) {
|
|
588
|
+
// pwf shift/scale
|
|
510
589
|
let pwfScale = 1.0;
|
|
511
590
|
let pwfShift = 0.0;
|
|
512
|
-
const
|
|
513
|
-
const pwfun = ppty.getPiecewiseFunction(target);
|
|
591
|
+
const pwfun = firstPpty.getPiecewiseFunction(target);
|
|
514
592
|
if (pwfun) {
|
|
515
593
|
const pwfRange = pwfun.getRange();
|
|
516
594
|
const length = pwfRange[1] - pwfRange[0];
|
|
517
595
|
const mid = 0.5 * (pwfRange[0] + pwfRange[1]);
|
|
518
|
-
pwfScale =
|
|
519
|
-
pwfShift = (
|
|
596
|
+
pwfScale = volScale / length;
|
|
597
|
+
pwfShift = (volOffset - mid) / length + 0.5;
|
|
520
598
|
}
|
|
521
|
-
program.setUniformf(`pwfshift${
|
|
522
|
-
program.setUniformf(`pwfscale${
|
|
599
|
+
program.setUniformf(`pwfshift${component}`, pwfShift);
|
|
600
|
+
program.setUniformf(`pwfscale${component}`, pwfScale);
|
|
523
601
|
}
|
|
602
|
+
const texColorUnit = model.colorTexture.getTextureUnit();
|
|
603
|
+
program.setUniformi('colorTexture1', texColorUnit);
|
|
524
604
|
const texOpacityUnit = model.pwfTexture.getTextureUnit();
|
|
525
605
|
program.setUniformi('pwfTexture1', texOpacityUnit);
|
|
526
606
|
|
|
@@ -534,8 +614,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
534
614
|
// input modified
|
|
535
615
|
// light complexity changed
|
|
536
616
|
// render pass shader replacement changed
|
|
537
|
-
const
|
|
538
|
-
const iComp = actor.getProperty().getIndependentComponents();
|
|
617
|
+
const iComp = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
|
|
539
618
|
const slabTh = model.renderable.getSlabThickness();
|
|
540
619
|
const slabType = model.renderable.getSlabType();
|
|
541
620
|
const slabTrap = model.renderable.getSlabTrapezoidIntegration();
|
|
@@ -545,9 +624,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
545
624
|
if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
|
|
546
625
|
needRebuild = true;
|
|
547
626
|
}
|
|
548
|
-
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram()?.getHandle() === 0 || model.
|
|
627
|
+
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || model.lastNumberOfComponents !== model.numberOfComponents || model.lastMultiTexturePerVolumeEnabled !== model.multiTexturePerVolumeEnabled || cellBO.getProgram()?.getHandle() === 0 || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
|
|
549
628
|
model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
|
|
550
|
-
model.
|
|
629
|
+
model.lastNumberOfComponents = model.numberOfComponents;
|
|
630
|
+
model.lastMultiTexturePerVolumeEnabled = model.multiTexturePerVolumeEnabled;
|
|
551
631
|
model.lastIndependentComponents = iComp;
|
|
552
632
|
model.lastSlabThickness = slabTh;
|
|
553
633
|
model.lastSlabType = slabType;
|
|
@@ -581,9 +661,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
581
661
|
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
|
|
582
662
|
const tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
|
|
583
663
|
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
|
|
584
|
-
const tNumComp = model.
|
|
585
|
-
const iComps = actor.getProperty().getIndependentComponents();
|
|
586
|
-
let tcoordFSDec = ['in vec3 fragTexCoord;',
|
|
664
|
+
const tNumComp = model.numberOfComponents;
|
|
665
|
+
const iComps = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
|
|
666
|
+
let tcoordFSDec = ['in vec3 fragTexCoord;', `uniform highp sampler3D volumeTexture[${model.scalarTextures.length}];`, 'uniform mat4 WCTCMatrix;',
|
|
587
667
|
// color shift and scale
|
|
588
668
|
'uniform float cshift0;', 'uniform float cscale0;',
|
|
589
669
|
// pwf shift and scale
|
|
@@ -594,6 +674,18 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
594
674
|
'uniform float opacity;',
|
|
595
675
|
// background color
|
|
596
676
|
'uniform vec4 backgroundColor;'];
|
|
677
|
+
|
|
678
|
+
// Function to sample texture
|
|
679
|
+
tcoordFSDec.push('vec4 rawSampleTexture(vec3 pos) {');
|
|
680
|
+
if (!model.multiTexturePerVolumeEnabled) {
|
|
681
|
+
tcoordFSDec.push('return texture(volumeTexture[0], pos);', '}');
|
|
682
|
+
} else {
|
|
683
|
+
tcoordFSDec.push('vec4 rawSample;');
|
|
684
|
+
for (let component = 0; component < model.scalarTextures.length; ++component) {
|
|
685
|
+
tcoordFSDec.push(`rawSample[${component}] = texture(volumeTexture[${component}], pos)[0];`);
|
|
686
|
+
}
|
|
687
|
+
tcoordFSDec.push('return rawSample;', '}');
|
|
688
|
+
}
|
|
597
689
|
if (iComps) {
|
|
598
690
|
for (let comp = 1; comp < tNumComp; comp++) {
|
|
599
691
|
tcoordFSDec = tcoordFSDec.concat([
|
|
@@ -629,14 +721,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
629
721
|
tcoordFSDec = tcoordFSDec.concat(['vec4 compositeValue(vec4 currVal, vec4 valToComp, int trapezoid)', '{', ' vec4 retVal = vec4(1.0);', ' if (slabType == 0) // min', ' {', ' retVal = min(currVal, valToComp);', ' }', ' else if (slabType == 1) // max', ' {', ' retVal = max(currVal, valToComp);', ' }', ' else if (slabType == 3) // sum', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' else // mean', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' return retVal;', '}']);
|
|
630
722
|
}
|
|
631
723
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
|
|
632
|
-
let tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue =
|
|
724
|
+
let tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = rawSampleTexture(fragTexCoord);'];
|
|
633
725
|
if (slabThickness > 0.0) {
|
|
634
|
-
tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'float scaling = min(min(spacing.x, spacing.y), spacing.z) * 0.5;', 'vec3 normalxspacing = scaling * normalWCVSOutput;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal =
|
|
726
|
+
tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'float scaling = min(min(spacing.x, spacing.y), spacing.z) * 0.5;', 'vec3 normalxspacing = scaling * normalWCVSOutput;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = rawSampleTexture(fragTCoordNeg);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', ' vec3 fragTCoordPos = (WCTCMatrix * vec4(vertexWCVSOutput.xyz + fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = rawSampleTexture(fragTCoordPos);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', '}', '// Finally, if slab type is *mean*, divide the sum by the numSlices', 'if (slabType == 2)', '{', ' tvalue = tvalue / float(numSlices);', '}']);
|
|
635
727
|
}
|
|
636
728
|
if (iComps) {
|
|
637
729
|
const rgba = ['r', 'g', 'b', 'a'];
|
|
638
730
|
for (let comp = 0; comp < tNumComp; ++comp) {
|
|
639
|
-
tcoordFSImpl = tcoordFSImpl.concat([`vec3 tcolor${comp} =
|
|
731
|
+
tcoordFSImpl = tcoordFSImpl.concat([`vec3 tcolor${comp} = texture2D(colorTexture1, vec2(tvalue.${rgba[comp]} * cscale${comp} + cshift${comp}, height${comp})).rgb;`, `float compWeight${comp} = mix${comp} * texture2D(pwfTexture1, vec2(tvalue.${rgba[comp]} * pwfscale${comp} + pwfshift${comp}, height${comp})).r;`]);
|
|
640
732
|
}
|
|
641
733
|
switch (tNumComp) {
|
|
642
734
|
case 1:
|
|
@@ -722,8 +814,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
722
814
|
}
|
|
723
815
|
publicAPI.updateResliceGeometry = () => {
|
|
724
816
|
let resGeomString = '';
|
|
725
|
-
const
|
|
726
|
-
const imageBounds =
|
|
817
|
+
const firstImageData = model.currentValidInputs[0].imageData;
|
|
818
|
+
const imageBounds = firstImageData?.getBounds();
|
|
727
819
|
// Orthogonal slicing by default
|
|
728
820
|
let orthoSlicing = true;
|
|
729
821
|
let orthoAxis = 2;
|
|
@@ -735,11 +827,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
735
827
|
resGeomString = resGeomString.concat(`Plane${slicePlane.getMTime()}`);
|
|
736
828
|
// Compute a world-to-image-orientation matrix.
|
|
737
829
|
const w2io = mat3.create();
|
|
738
|
-
if (
|
|
739
|
-
resGeomString = resGeomString.concat(`Image${
|
|
830
|
+
if (firstImageData) {
|
|
831
|
+
resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
|
|
740
832
|
// Ignore the translation component since we are
|
|
741
833
|
// using it on vectors rather than positions.
|
|
742
|
-
mat3.set(w2io, ...
|
|
834
|
+
mat3.set(w2io, ...firstImageData.getDirection());
|
|
743
835
|
mat3.invert(w2io, w2io);
|
|
744
836
|
}
|
|
745
837
|
// Check to see if we can bypass oblique slicing related bounds computation
|
|
@@ -752,14 +844,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
752
844
|
const plane = vtkPlane.newInstance();
|
|
753
845
|
plane.setNormal(0, 0, 1);
|
|
754
846
|
let bds = [0, 1, 0, 1, 0, 1];
|
|
755
|
-
if (
|
|
847
|
+
if (firstImageData) {
|
|
756
848
|
bds = imageBounds;
|
|
757
849
|
}
|
|
758
850
|
plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
|
|
759
851
|
model.renderable.setSlicePlane(plane);
|
|
760
852
|
resGeomString = resGeomString.concat(`Plane${slicePlane?.getMTime()}`);
|
|
761
|
-
if (
|
|
762
|
-
resGeomString = resGeomString.concat(`Image${
|
|
853
|
+
if (firstImageData) {
|
|
854
|
+
resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
|
|
763
855
|
}
|
|
764
856
|
}
|
|
765
857
|
if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
|
|
@@ -772,7 +864,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
772
864
|
model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
|
|
773
865
|
} else if (slicePlane) {
|
|
774
866
|
if (!orthoSlicing) {
|
|
775
|
-
model.outlineFilter.setInputData(
|
|
867
|
+
model.outlineFilter.setInputData(firstImageData);
|
|
776
868
|
model.cutter.setInputConnection(model.outlineFilter.getOutputPort());
|
|
777
869
|
model.cutter.setCutFunction(slicePlane);
|
|
778
870
|
model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
|
|
@@ -805,9 +897,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
805
897
|
// Since the image-local normal is axis-aligned, we
|
|
806
898
|
// can quickly construct the cutting plane using indexToWorld transforms.
|
|
807
899
|
const ptsArray = new Float32Array(12);
|
|
808
|
-
const indexSpacePlaneOrigin =
|
|
900
|
+
const indexSpacePlaneOrigin = firstImageData.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
|
|
809
901
|
const otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
|
|
810
|
-
const ext =
|
|
902
|
+
const ext = firstImageData.getSpatialExtent();
|
|
811
903
|
let ptIdx = 0;
|
|
812
904
|
for (let i = 0; i < 2; ++i) {
|
|
813
905
|
for (let j = 0; j < 2; ++j) {
|
|
@@ -817,7 +909,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
817
909
|
ptIdx += 3;
|
|
818
910
|
}
|
|
819
911
|
}
|
|
820
|
-
model.transform.setMatrix(
|
|
912
|
+
model.transform.setMatrix(firstImageData.getIndexToWorld());
|
|
821
913
|
model.transform.transformPoints(ptsArray, ptsArray);
|
|
822
914
|
const cellArray = new Uint16Array(8);
|
|
823
915
|
cellArray[0] = 3;
|
|
@@ -855,11 +947,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
855
947
|
model.resliceGeom?.modified();
|
|
856
948
|
}
|
|
857
949
|
};
|
|
858
|
-
publicAPI.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
model._externalOpenGLTexture = true;
|
|
862
|
-
}
|
|
950
|
+
publicAPI.setScalarTextures = scalarTextures => {
|
|
951
|
+
model.scalarTextures = [...scalarTextures];
|
|
952
|
+
model._externalOpenGLTexture = true;
|
|
863
953
|
};
|
|
864
954
|
publicAPI.delete = chain(() => {
|
|
865
955
|
if (model._openGLRenderWindow) {
|
|
@@ -878,22 +968,21 @@ const DEFAULT_VALUES = {
|
|
|
878
968
|
haveSeenDepthRequest: false,
|
|
879
969
|
lastHaveSeenDepthRequest: false,
|
|
880
970
|
lastIndependentComponents: false,
|
|
881
|
-
|
|
971
|
+
lastNumberOfComponents: 0,
|
|
972
|
+
lastMultiTexturePerVolumeEnabled: false,
|
|
882
973
|
lastSlabThickness: 0,
|
|
883
974
|
lastSlabTrapezoidIntegration: 0,
|
|
884
975
|
lastSlabType: -1,
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
pwfTextureString: null,
|
|
888
|
-
resliceGeom: null,
|
|
889
|
-
resliceGeomUpdateString: null,
|
|
890
|
-
tris: null,
|
|
976
|
+
scalarTextures: [],
|
|
977
|
+
_scalarTexturesCore: [],
|
|
891
978
|
colorTexture: null,
|
|
979
|
+
_colorTextureCore: null,
|
|
892
980
|
pwfTexture: null,
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
981
|
+
_pwfTextureCore: null,
|
|
982
|
+
_externalOpenGLTexture: false,
|
|
983
|
+
resliceGeom: null,
|
|
984
|
+
resliceGeomUpdateString: null,
|
|
985
|
+
tris: null
|
|
897
986
|
};
|
|
898
987
|
|
|
899
988
|
// ----------------------------------------------------------------------------
|
|
@@ -907,7 +996,7 @@ function extend(publicAPI, model) {
|
|
|
907
996
|
vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
|
|
908
997
|
vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
|
|
909
998
|
model.tris = vtkHelper.newInstance();
|
|
910
|
-
model.
|
|
999
|
+
model.scalarTextures = [];
|
|
911
1000
|
model.colorTexture = null;
|
|
912
1001
|
model.pwfTexture = null;
|
|
913
1002
|
model.VBOBuildTime = {};
|
|
@@ -922,7 +1011,7 @@ function extend(publicAPI, model) {
|
|
|
922
1011
|
model.cutter = vtkCutter.newInstance();
|
|
923
1012
|
model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
|
|
924
1013
|
model.transform = vtkTransform.newInstance();
|
|
925
|
-
get(publicAPI, model, ['
|
|
1014
|
+
get(publicAPI, model, ['scalarTextures']);
|
|
926
1015
|
|
|
927
1016
|
// Object methods
|
|
928
1017
|
vtkOpenGLImageResliceMapper(publicAPI, model);
|