@kitware/vtk.js 33.3.2 → 34.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 +10 -0
- package/IO/Geometry/GLTFImporter/Decoder.js +21 -35
- package/IO/Geometry/GLTFImporter/ORMTexture.worker.js +42 -0
- package/IO/Geometry/GLTFImporter/Parser.js +6 -15
- package/IO/Geometry/GLTFImporter/Reader.js +10 -7
- package/IO/Geometry/GLTFImporter/Utils.js +27 -9
- 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/ImageCPRMapper.d.ts +1 -20
- package/Rendering/Core/ImageCPRMapper.js +1 -2
- package/Rendering/Core/ImageProperty.d.ts +20 -1
- package/Rendering/Core/ImageProperty.js +7 -5
- package/Rendering/Core/ImageResliceMapper.d.ts +1 -20
- package/Rendering/Core/ImageResliceMapper.js +1 -2
- package/Rendering/Core/ImageSlice.d.ts +7 -23
- package/Rendering/Core/ImageSlice.js +9 -68
- package/Rendering/Core/Prop3D.d.ts +39 -2
- package/Rendering/Core/Prop3D.js +81 -2
- package/Rendering/Core/RenderWindowInteractor.d.ts +6 -0
- package/Rendering/Core/RenderWindowInteractor.js +7 -5
- 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 -173
- package/Rendering/Core/VolumeMapper.js +16 -51
- package/Rendering/Core/VolumeProperty/Constants.d.ts +12 -3
- package/Rendering/Core/VolumeProperty/Constants.js +11 -4
- package/Rendering/Core/VolumeProperty.d.ts +140 -5
- package/Rendering/Core/VolumeProperty.js +54 -7
- package/Rendering/OpenGL/Framebuffer.js +7 -1
- package/Rendering/OpenGL/ImageCPRMapper.js +72 -27
- package/Rendering/OpenGL/ImageMapper.js +71 -33
- package/Rendering/OpenGL/ImageResliceMapper.js +306 -183
- package/Rendering/OpenGL/OrderIndependentTranslucentPass.js +20 -3
- package/Rendering/OpenGL/PolyDataMapper.js +8 -9
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +3 -3
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +8 -5
- package/Rendering/OpenGL/SurfaceLIC/LineIntegralConvolution2D/pingpong.js +7 -1
- package/Rendering/OpenGL/SurfaceLIC/SurfaceLICInterface.js +20 -3
- package/Rendering/OpenGL/Texture.d.ts +110 -62
- package/Rendering/OpenGL/Texture.js +145 -37
- package/Rendering/OpenGL/VolumeMapper.js +763 -783
- package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
- package/Rendering/WebGPU/CellArrayMapper.js +17 -17
- package/Rendering/WebGPU/PolyDataMapper.js +15 -35
- package/Rendering/WebGPU/Renderer.js +1 -1
- package/Rendering/WebGPU/Texture.js +12 -13
- package/Rendering/WebGPU/TextureManager.js +7 -12
- package/Rendering/WebGPU/VolumePassFSQ.js +2 -2
- package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +296 -0
- package/index.d.ts +1 -0
- package/macros.js +1 -1
- package/macros2.js +8 -3
- package/package.json +1 -1
|
@@ -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,57 +238,74 @@ 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
|
-
const
|
|
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
|
-
model._openGLRenderWindow.
|
|
204
|
-
model.
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
248
|
+
const actorProperties = actor.getProperties();
|
|
249
|
+
model.currentValidInputs.forEach((_ref3, component) => {
|
|
250
|
+
let {
|
|
251
|
+
imageData
|
|
252
|
+
} = _ref3;
|
|
253
|
+
// rebuild the scalarTexture if the data has changed
|
|
254
|
+
const scalars = imageData.getPointData().getScalars();
|
|
255
|
+
const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
|
|
256
|
+
const scalarsHash = getImageDataHash(imageData, scalars);
|
|
257
|
+
const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
|
|
258
|
+
const actorProperty = actorProperties[component];
|
|
259
|
+
const updatedExtents = actorProperty.getUpdatedExtents();
|
|
260
|
+
const hasUpdatedExtents = !!updatedExtents.length;
|
|
261
|
+
if (reBuildTex && !hasUpdatedExtents) {
|
|
262
|
+
const newScalarTexture = vtkOpenGLTexture.newInstance();
|
|
263
|
+
newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
264
|
+
// Build the textures
|
|
265
|
+
const dims = imageData.getDimensions();
|
|
266
|
+
// Use norm16 for scalar texture if the extension is available
|
|
267
|
+
newScalarTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
|
|
268
|
+
newScalarTexture.resetFormatAndType();
|
|
269
|
+
newScalarTexture.create3DFilterableFromDataArray({
|
|
270
|
+
width: dims[0],
|
|
271
|
+
height: dims[1],
|
|
272
|
+
depth: dims[2],
|
|
273
|
+
dataArray: scalars
|
|
274
|
+
});
|
|
275
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(scalars, newScalarTexture, scalarsHash);
|
|
276
|
+
model.scalarTextures[component] = newScalarTexture;
|
|
277
|
+
} else {
|
|
278
|
+
model.scalarTextures[component] = tex.oglObject;
|
|
279
|
+
}
|
|
280
|
+
if (hasUpdatedExtents) {
|
|
281
|
+
// If hasUpdatedExtents, then the texture is partially updated.
|
|
282
|
+
// clear the array to acknowledge the update.
|
|
283
|
+
actorProperty.setUpdatedExtents([]);
|
|
284
|
+
const dims = imageData.getDimensions();
|
|
285
|
+
model.scalarTextures[component].create3DFilterableFromDataArray({
|
|
286
|
+
width: dims[0],
|
|
287
|
+
height: dims[1],
|
|
288
|
+
depth: dims[2],
|
|
289
|
+
dataArray: scalars,
|
|
290
|
+
updatedExtents
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
|
|
294
|
+
model._scalarTexturesCore[component] = scalars;
|
|
295
|
+
});
|
|
296
|
+
const firstValidInput = model.currentValidInputs[0];
|
|
297
|
+
const firstActorProperty = actorProperties[firstValidInput.inputIndex];
|
|
298
|
+
const iComps = firstActorProperty.getIndependentComponents();
|
|
299
|
+
const numIComps = iComps ? model.numberOfComponents : 1;
|
|
220
300
|
const textureHeight = iComps ? 2 * numIComps : 1;
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
301
|
+
const colorTransferFunctions = [];
|
|
302
|
+
for (let component = 0; component < numIComps; ++component) {
|
|
303
|
+
colorTransferFunctions.push(firstActorProperty.getRGBTransferFunction(component));
|
|
304
|
+
}
|
|
305
|
+
const colorFuncHash = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
|
|
306
|
+
const firstColorTransferFunc = firstActorProperty.getRGBTransferFunction();
|
|
307
|
+
const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
|
|
308
|
+
const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== colorFuncHash;
|
|
225
309
|
if (reBuildC) {
|
|
226
310
|
let cWidth = model.renderable.getColorTextureWidth();
|
|
227
311
|
if (cWidth <= 0) {
|
|
@@ -229,12 +313,12 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
229
313
|
}
|
|
230
314
|
const cSize = cWidth * textureHeight * 3;
|
|
231
315
|
const cTable = new Uint8ClampedArray(cSize);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (
|
|
316
|
+
const newColorTexture = vtkOpenGLTexture.newInstance();
|
|
317
|
+
newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
318
|
+
if (firstColorTransferFunc) {
|
|
235
319
|
const tmpTable = new Float32Array(cWidth * 3);
|
|
236
320
|
for (let c = 0; c < numIComps; c++) {
|
|
237
|
-
const cfun =
|
|
321
|
+
const cfun = firstActorProperty.getRGBTransferFunction(c);
|
|
238
322
|
const cRange = cfun.getRange();
|
|
239
323
|
cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
|
|
240
324
|
if (iComps) {
|
|
@@ -244,41 +328,58 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
244
328
|
}
|
|
245
329
|
} else {
|
|
246
330
|
for (let i = 0; i < cWidth * 3; i++) {
|
|
247
|
-
cTable[c * cWidth *
|
|
331
|
+
cTable[c * cWidth * 3 + i] = 255.0 * tmpTable[i];
|
|
248
332
|
}
|
|
249
333
|
}
|
|
250
334
|
}
|
|
251
|
-
|
|
252
|
-
|
|
335
|
+
newColorTexture.resetFormatAndType();
|
|
336
|
+
newColorTexture.create2DFromRaw({
|
|
337
|
+
width: cWidth,
|
|
338
|
+
height: textureHeight,
|
|
339
|
+
numComps: 3,
|
|
340
|
+
dataType: VtkDataTypes.UNSIGNED_CHAR,
|
|
341
|
+
data: cTable
|
|
342
|
+
});
|
|
253
343
|
} else {
|
|
254
|
-
for (let
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (colorTransferFunc) {
|
|
263
|
-
model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, toString);
|
|
264
|
-
if (colorTransferFunc !== model._colorTransferFunc) {
|
|
265
|
-
model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
|
|
266
|
-
model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
|
|
344
|
+
for (let column = 0; column < cWidth * 3; ++column) {
|
|
345
|
+
const opacity = 255.0 * column / ((cWidth - 1) * 3);
|
|
346
|
+
for (let row = 0; row < textureHeight; ++row) {
|
|
347
|
+
// R, G, B
|
|
348
|
+
cTable[row * cWidth * 3 + column + 0] = opacity;
|
|
349
|
+
cTable[row * cWidth * 3 + column + 1] = opacity;
|
|
350
|
+
cTable[row * cWidth * 3 + column + 2] = opacity;
|
|
351
|
+
}
|
|
267
352
|
}
|
|
268
|
-
|
|
353
|
+
newColorTexture.resetFormatAndType();
|
|
354
|
+
newColorTexture.create2DFromRaw({
|
|
355
|
+
width: cWidth,
|
|
356
|
+
height: 1,
|
|
357
|
+
numComps: 3,
|
|
358
|
+
dataType: VtkDataTypes.UNSIGNED_CHAR,
|
|
359
|
+
data: cTable
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (firstColorTransferFunc) {
|
|
363
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, newColorTexture, colorFuncHash);
|
|
269
364
|
}
|
|
365
|
+
model.colorTexture = newColorTexture;
|
|
270
366
|
} else {
|
|
271
367
|
model.colorTexture = cTex.oglObject;
|
|
272
368
|
}
|
|
369
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._colorTextureCore, firstColorTransferFunc);
|
|
370
|
+
model._colorTextureCore = firstColorTransferFunc;
|
|
273
371
|
|
|
274
372
|
// Build piecewise function buffer. This buffer is used either
|
|
275
373
|
// for component weighting or opacity, depending on whether we're
|
|
276
374
|
// rendering components independently or not.
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const
|
|
375
|
+
const opacityFunctions = [];
|
|
376
|
+
for (let component = 0; component < numIComps; ++component) {
|
|
377
|
+
opacityFunctions.push(firstActorProperty.getPiecewiseFunction(component));
|
|
378
|
+
}
|
|
379
|
+
const opacityFuncHash = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
|
|
380
|
+
const firstPwFunc = firstActorProperty.getPiecewiseFunction();
|
|
381
|
+
const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
|
|
382
|
+
const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== opacityFuncHash;
|
|
282
383
|
if (reBuildPwf) {
|
|
283
384
|
let pwfWidth = model.renderable.getOpacityTextureWidth();
|
|
284
385
|
if (pwfWidth <= 0) {
|
|
@@ -286,13 +387,13 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
286
387
|
}
|
|
287
388
|
const pwfSize = pwfWidth * textureHeight;
|
|
288
389
|
const pwfTable = new Uint8ClampedArray(pwfSize);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (
|
|
390
|
+
const newOpacityTexture = vtkOpenGLTexture.newInstance();
|
|
391
|
+
newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
392
|
+
if (firstPwFunc) {
|
|
292
393
|
const pwfFloatTable = new Float32Array(pwfSize);
|
|
293
394
|
const tmpTable = new Float32Array(pwfWidth);
|
|
294
395
|
for (let c = 0; c < numIComps; ++c) {
|
|
295
|
-
const pwfun =
|
|
396
|
+
const pwfun = firstActorProperty.getPiecewiseFunction(c);
|
|
296
397
|
if (pwfun === null) {
|
|
297
398
|
// Piecewise constant max if no function supplied for this component
|
|
298
399
|
pwfFloatTable.fill(1.0);
|
|
@@ -307,30 +408,40 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
307
408
|
}
|
|
308
409
|
} else {
|
|
309
410
|
for (let i = 0; i < pwfWidth; i++) {
|
|
310
|
-
pwfFloatTable[
|
|
411
|
+
pwfFloatTable[i] = tmpTable[i];
|
|
311
412
|
}
|
|
312
413
|
}
|
|
313
414
|
}
|
|
314
415
|
}
|
|
315
|
-
|
|
316
|
-
|
|
416
|
+
newOpacityTexture.resetFormatAndType();
|
|
417
|
+
newOpacityTexture.create2DFromRaw({
|
|
418
|
+
width: pwfWidth,
|
|
419
|
+
height: textureHeight,
|
|
420
|
+
numComps: 1,
|
|
421
|
+
dataType: VtkDataTypes.FLOAT,
|
|
422
|
+
data: pwfFloatTable
|
|
423
|
+
});
|
|
317
424
|
} else {
|
|
318
425
|
// default is opaque
|
|
319
426
|
pwfTable.fill(255.0);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
model._pwFunc = pwFunc;
|
|
427
|
+
newOpacityTexture.resetFormatAndType();
|
|
428
|
+
newOpacityTexture.create2DFromRaw({
|
|
429
|
+
width: pwfWidth,
|
|
430
|
+
height: textureHeight,
|
|
431
|
+
numComps: 1,
|
|
432
|
+
dataType: VtkDataTypes.UNSIGNED_CHAR,
|
|
433
|
+
data: pwfTable
|
|
434
|
+
});
|
|
330
435
|
}
|
|
436
|
+
if (firstPwFunc) {
|
|
437
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, newOpacityTexture, opacityFuncHash);
|
|
438
|
+
}
|
|
439
|
+
model.pwfTexture = newOpacityTexture;
|
|
331
440
|
} else {
|
|
332
441
|
model.pwfTexture = pwfTex.oglObject;
|
|
333
442
|
}
|
|
443
|
+
replaceGraphicsResource(model._openGLRenderWindow, model._pwfTextureCore, firstPwFunc);
|
|
444
|
+
model._pwfTextureCore = firstPwFunc;
|
|
334
445
|
const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
|
|
335
446
|
if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
|
|
336
447
|
const points = vtkDataArray.newInstance({
|
|
@@ -391,11 +502,12 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
391
502
|
};
|
|
392
503
|
publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
|
|
393
504
|
const program = cellBO.getProgram();
|
|
505
|
+
const firstImageData = model.currentValidInputs[0].imageData;
|
|
394
506
|
if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
|
|
395
507
|
// Set the 3D texture
|
|
396
|
-
|
|
397
|
-
program.setUniformi(
|
|
398
|
-
}
|
|
508
|
+
model.scalarTextures.forEach((scalarTexture, component) => {
|
|
509
|
+
program.setUniformi(`volumeTexture[${component}]`, scalarTexture.getTextureUnit());
|
|
510
|
+
});
|
|
399
511
|
|
|
400
512
|
// Set the plane vertex attributes
|
|
401
513
|
if (program.isAttributeUsed('vertexWC')) {
|
|
@@ -414,7 +526,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
414
526
|
program.setUniformf('slabThickness', model.renderable.getSlabThickness());
|
|
415
527
|
}
|
|
416
528
|
if (program.isUniformUsed('spacing')) {
|
|
417
|
-
program.setUniform3fv('spacing',
|
|
529
|
+
program.setUniform3fv('spacing', firstImageData.getSpacing());
|
|
418
530
|
}
|
|
419
531
|
if (program.isUniformUsed('slabType')) {
|
|
420
532
|
program.setUniformi('slabType', model.renderable.getSlabType());
|
|
@@ -430,9 +542,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
430
542
|
|
|
431
543
|
// Set the world->texture matrix
|
|
432
544
|
if (program.isUniformUsed('WCTCMatrix')) {
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
mat4.copy(model.tmpMat4, image.getIndexToWorld());
|
|
545
|
+
const dim = firstImageData.getDimensions();
|
|
546
|
+
mat4.copy(model.tmpMat4, firstImageData.getIndexToWorld());
|
|
436
547
|
mat4.translate(model.tmpMat4, model.tmpMat4, [-0.5, -0.5, -0.5]);
|
|
437
548
|
mat4.scale(model.tmpMat4, model.tmpMat4, dim);
|
|
438
549
|
mat4.invert(model.tmpMat4, model.tmpMat4);
|
|
@@ -481,8 +592,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
481
592
|
};
|
|
482
593
|
publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
|
|
483
594
|
const program = cellBO.getProgram();
|
|
484
|
-
const
|
|
485
|
-
const opacity =
|
|
595
|
+
const firstPpty = actor.getProperty(model.currentValidInputs[0].inputIndex);
|
|
596
|
+
const opacity = firstPpty.getOpacity();
|
|
486
597
|
program.setUniformf('opacity', opacity);
|
|
487
598
|
|
|
488
599
|
// Component mix
|
|
@@ -491,53 +602,56 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
491
602
|
// - 2 comps => LA
|
|
492
603
|
// - 3 comps => RGB + opacity from pwf
|
|
493
604
|
// - 4 comps => RGBA
|
|
494
|
-
const numComp = model.
|
|
495
|
-
const iComps =
|
|
605
|
+
const numComp = model.numberOfComponents;
|
|
606
|
+
const iComps = firstPpty.getIndependentComponents();
|
|
496
607
|
if (iComps) {
|
|
497
608
|
for (let i = 0; i < numComp; ++i) {
|
|
498
|
-
program.setUniformf(`mix${i}`,
|
|
609
|
+
program.setUniformf(`mix${i}`, firstPpty.getComponentWeight(i));
|
|
499
610
|
}
|
|
500
611
|
}
|
|
501
612
|
|
|
502
|
-
// Color opacity map
|
|
503
|
-
const volInfo = model.openGLTexture.getVolumeInfo();
|
|
504
|
-
|
|
505
613
|
// three levels of shift scale combined into one
|
|
506
614
|
// for performance in the fragment shader
|
|
507
|
-
for (let
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const
|
|
511
|
-
const
|
|
512
|
-
|
|
615
|
+
for (let component = 0; component < numComp; component++) {
|
|
616
|
+
const useMultiTexture = model.multiTexturePerVolumeEnabled;
|
|
617
|
+
const textureIndex = useMultiTexture ? component : 0;
|
|
618
|
+
const volInfoIndex = useMultiTexture ? 0 : component;
|
|
619
|
+
const scalarTexture = model.scalarTextures[textureIndex];
|
|
620
|
+
const volInfo = scalarTexture.getVolumeInfo();
|
|
621
|
+
const volScale = volInfo.scale[volInfoIndex];
|
|
622
|
+
const volOffset = volInfo.offset[volInfoIndex];
|
|
623
|
+
const target = iComps ? component : 0;
|
|
624
|
+
|
|
625
|
+
// color shift/scale
|
|
626
|
+
let cw = firstPpty.getColorWindow();
|
|
627
|
+
let cl = firstPpty.getColorLevel();
|
|
628
|
+
const cfun = firstPpty.getRGBTransferFunction(target);
|
|
629
|
+
if (cfun && firstPpty.getUseLookupTableScalarRange()) {
|
|
513
630
|
const cRange = cfun.getRange();
|
|
514
631
|
cw = cRange[1] - cRange[0];
|
|
515
632
|
cl = 0.5 * (cRange[1] + cRange[0]);
|
|
516
633
|
}
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
program.setUniformf(`cshift${
|
|
520
|
-
program.setUniformf(`cscale${
|
|
521
|
-
}
|
|
522
|
-
const texColorUnit = model.colorTexture.getTextureUnit();
|
|
523
|
-
program.setUniformi('colorTexture1', texColorUnit);
|
|
634
|
+
const colorScale = volScale / cw;
|
|
635
|
+
const colorShift = (volOffset - cl) / cw + 0.5;
|
|
636
|
+
program.setUniformf(`cshift${component}`, colorShift);
|
|
637
|
+
program.setUniformf(`cscale${component}`, colorScale);
|
|
524
638
|
|
|
525
|
-
|
|
526
|
-
for (let i = 0; i < numComp; i++) {
|
|
639
|
+
// pwf shift/scale
|
|
527
640
|
let pwfScale = 1.0;
|
|
528
641
|
let pwfShift = 0.0;
|
|
529
|
-
const
|
|
530
|
-
const pwfun = ppty.getPiecewiseFunction(target);
|
|
642
|
+
const pwfun = firstPpty.getPiecewiseFunction(target);
|
|
531
643
|
if (pwfun) {
|
|
532
644
|
const pwfRange = pwfun.getRange();
|
|
533
645
|
const length = pwfRange[1] - pwfRange[0];
|
|
534
646
|
const mid = 0.5 * (pwfRange[0] + pwfRange[1]);
|
|
535
|
-
pwfScale =
|
|
536
|
-
pwfShift = (
|
|
647
|
+
pwfScale = volScale / length;
|
|
648
|
+
pwfShift = (volOffset - mid) / length + 0.5;
|
|
537
649
|
}
|
|
538
|
-
program.setUniformf(`pwfshift${
|
|
539
|
-
program.setUniformf(`pwfscale${
|
|
650
|
+
program.setUniformf(`pwfshift${component}`, pwfShift);
|
|
651
|
+
program.setUniformf(`pwfscale${component}`, pwfScale);
|
|
540
652
|
}
|
|
653
|
+
const texColorUnit = model.colorTexture.getTextureUnit();
|
|
654
|
+
program.setUniformi('colorTexture1', texColorUnit);
|
|
541
655
|
const texOpacityUnit = model.pwfTexture.getTextureUnit();
|
|
542
656
|
program.setUniformi('pwfTexture1', texOpacityUnit);
|
|
543
657
|
|
|
@@ -551,8 +665,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
551
665
|
// input modified
|
|
552
666
|
// light complexity changed
|
|
553
667
|
// render pass shader replacement changed
|
|
554
|
-
const
|
|
555
|
-
const iComp = actor.getProperty().getIndependentComponents();
|
|
668
|
+
const iComp = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
|
|
556
669
|
const slabTh = model.renderable.getSlabThickness();
|
|
557
670
|
const slabType = model.renderable.getSlabType();
|
|
558
671
|
const slabTrap = model.renderable.getSlabTrapezoidIntegration();
|
|
@@ -562,9 +675,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
562
675
|
if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
|
|
563
676
|
needRebuild = true;
|
|
564
677
|
}
|
|
565
|
-
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram()?.getHandle() === 0 || model.
|
|
678
|
+
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) {
|
|
566
679
|
model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
|
|
567
|
-
model.
|
|
680
|
+
model.lastNumberOfComponents = model.numberOfComponents;
|
|
681
|
+
model.lastMultiTexturePerVolumeEnabled = model.multiTexturePerVolumeEnabled;
|
|
568
682
|
model.lastIndependentComponents = iComp;
|
|
569
683
|
model.lastSlabThickness = slabTh;
|
|
570
684
|
model.lastSlabType = slabType;
|
|
@@ -598,9 +712,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
598
712
|
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
|
|
599
713
|
const tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
|
|
600
714
|
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
|
|
601
|
-
const tNumComp = model.
|
|
602
|
-
const iComps = actor.getProperty().getIndependentComponents();
|
|
603
|
-
let tcoordFSDec = ['in vec3 fragTexCoord;',
|
|
715
|
+
const tNumComp = model.numberOfComponents;
|
|
716
|
+
const iComps = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
|
|
717
|
+
let tcoordFSDec = ['in vec3 fragTexCoord;', `uniform highp sampler3D volumeTexture[${model.scalarTextures.length}];`, 'uniform mat4 WCTCMatrix;',
|
|
604
718
|
// color shift and scale
|
|
605
719
|
'uniform float cshift0;', 'uniform float cscale0;',
|
|
606
720
|
// pwf shift and scale
|
|
@@ -611,6 +725,18 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
611
725
|
'uniform float opacity;',
|
|
612
726
|
// background color
|
|
613
727
|
'uniform vec4 backgroundColor;'];
|
|
728
|
+
|
|
729
|
+
// Function to sample texture
|
|
730
|
+
tcoordFSDec.push('vec4 rawSampleTexture(vec3 pos) {');
|
|
731
|
+
if (!model.multiTexturePerVolumeEnabled) {
|
|
732
|
+
tcoordFSDec.push('return texture(volumeTexture[0], pos);', '}');
|
|
733
|
+
} else {
|
|
734
|
+
tcoordFSDec.push('vec4 rawSample;');
|
|
735
|
+
for (let component = 0; component < model.scalarTextures.length; ++component) {
|
|
736
|
+
tcoordFSDec.push(`rawSample[${component}] = texture(volumeTexture[${component}], pos)[0];`);
|
|
737
|
+
}
|
|
738
|
+
tcoordFSDec.push('return rawSample;', '}');
|
|
739
|
+
}
|
|
614
740
|
if (iComps) {
|
|
615
741
|
for (let comp = 1; comp < tNumComp; comp++) {
|
|
616
742
|
tcoordFSDec = tcoordFSDec.concat([
|
|
@@ -646,14 +772,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
646
772
|
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;', '}']);
|
|
647
773
|
}
|
|
648
774
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
|
|
649
|
-
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 =
|
|
775
|
+
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);'];
|
|
650
776
|
if (slabThickness > 0.0) {
|
|
651
|
-
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 =
|
|
777
|
+
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);', '}']);
|
|
652
778
|
}
|
|
653
779
|
if (iComps) {
|
|
654
780
|
const rgba = ['r', 'g', 'b', 'a'];
|
|
655
781
|
for (let comp = 0; comp < tNumComp; ++comp) {
|
|
656
|
-
tcoordFSImpl = tcoordFSImpl.concat([`vec3 tcolor${comp} =
|
|
782
|
+
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;`]);
|
|
657
783
|
}
|
|
658
784
|
switch (tNumComp) {
|
|
659
785
|
case 1:
|
|
@@ -739,8 +865,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
739
865
|
}
|
|
740
866
|
publicAPI.updateResliceGeometry = () => {
|
|
741
867
|
let resGeomString = '';
|
|
742
|
-
const
|
|
743
|
-
const imageBounds =
|
|
868
|
+
const firstImageData = model.currentValidInputs[0].imageData;
|
|
869
|
+
const imageBounds = firstImageData?.getBounds();
|
|
744
870
|
// Orthogonal slicing by default
|
|
745
871
|
let orthoSlicing = true;
|
|
746
872
|
let orthoAxis = 2;
|
|
@@ -752,11 +878,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
752
878
|
resGeomString = resGeomString.concat(`Plane${slicePlane.getMTime()}`);
|
|
753
879
|
// Compute a world-to-image-orientation matrix.
|
|
754
880
|
const w2io = mat3.create();
|
|
755
|
-
if (
|
|
756
|
-
resGeomString = resGeomString.concat(`Image${
|
|
881
|
+
if (firstImageData) {
|
|
882
|
+
resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
|
|
757
883
|
// Ignore the translation component since we are
|
|
758
884
|
// using it on vectors rather than positions.
|
|
759
|
-
mat3.set(w2io, ...
|
|
885
|
+
mat3.set(w2io, ...firstImageData.getDirection());
|
|
760
886
|
mat3.invert(w2io, w2io);
|
|
761
887
|
}
|
|
762
888
|
// Check to see if we can bypass oblique slicing related bounds computation
|
|
@@ -769,14 +895,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
769
895
|
const plane = vtkPlane.newInstance();
|
|
770
896
|
plane.setNormal(0, 0, 1);
|
|
771
897
|
let bds = [0, 1, 0, 1, 0, 1];
|
|
772
|
-
if (
|
|
898
|
+
if (firstImageData) {
|
|
773
899
|
bds = imageBounds;
|
|
774
900
|
}
|
|
775
901
|
plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
|
|
776
902
|
model.renderable.setSlicePlane(plane);
|
|
777
903
|
resGeomString = resGeomString.concat(`Plane${slicePlane?.getMTime()}`);
|
|
778
|
-
if (
|
|
779
|
-
resGeomString = resGeomString.concat(`Image${
|
|
904
|
+
if (firstImageData) {
|
|
905
|
+
resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
|
|
780
906
|
}
|
|
781
907
|
}
|
|
782
908
|
if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
|
|
@@ -789,7 +915,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
789
915
|
model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
|
|
790
916
|
} else if (slicePlane) {
|
|
791
917
|
if (!orthoSlicing) {
|
|
792
|
-
model.outlineFilter.setInputData(
|
|
918
|
+
model.outlineFilter.setInputData(firstImageData);
|
|
793
919
|
model.cutter.setInputConnection(model.outlineFilter.getOutputPort());
|
|
794
920
|
model.cutter.setCutFunction(slicePlane);
|
|
795
921
|
model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
|
|
@@ -822,9 +948,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
822
948
|
// Since the image-local normal is axis-aligned, we
|
|
823
949
|
// can quickly construct the cutting plane using indexToWorld transforms.
|
|
824
950
|
const ptsArray = new Float32Array(12);
|
|
825
|
-
const indexSpacePlaneOrigin =
|
|
951
|
+
const indexSpacePlaneOrigin = firstImageData.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
|
|
826
952
|
const otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
|
|
827
|
-
const ext =
|
|
953
|
+
const ext = firstImageData.getSpatialExtent();
|
|
828
954
|
let ptIdx = 0;
|
|
829
955
|
for (let i = 0; i < 2; ++i) {
|
|
830
956
|
for (let j = 0; j < 2; ++j) {
|
|
@@ -834,7 +960,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
834
960
|
ptIdx += 3;
|
|
835
961
|
}
|
|
836
962
|
}
|
|
837
|
-
model.transform.setMatrix(
|
|
963
|
+
model.transform.setMatrix(firstImageData.getIndexToWorld());
|
|
838
964
|
model.transform.transformPoints(ptsArray, ptsArray);
|
|
839
965
|
const cellArray = new Uint16Array(8);
|
|
840
966
|
cellArray[0] = 3;
|
|
@@ -872,11 +998,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
872
998
|
model.resliceGeom?.modified();
|
|
873
999
|
}
|
|
874
1000
|
};
|
|
875
|
-
publicAPI.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
model._externalOpenGLTexture = true;
|
|
879
|
-
}
|
|
1001
|
+
publicAPI.setScalarTextures = scalarTextures => {
|
|
1002
|
+
model.scalarTextures = [...scalarTextures];
|
|
1003
|
+
model._externalOpenGLTexture = true;
|
|
880
1004
|
};
|
|
881
1005
|
publicAPI.delete = chain(() => {
|
|
882
1006
|
if (model._openGLRenderWindow) {
|
|
@@ -895,22 +1019,21 @@ const DEFAULT_VALUES = {
|
|
|
895
1019
|
haveSeenDepthRequest: false,
|
|
896
1020
|
lastHaveSeenDepthRequest: false,
|
|
897
1021
|
lastIndependentComponents: false,
|
|
898
|
-
|
|
1022
|
+
lastNumberOfComponents: 0,
|
|
1023
|
+
lastMultiTexturePerVolumeEnabled: false,
|
|
899
1024
|
lastSlabThickness: 0,
|
|
900
1025
|
lastSlabTrapezoidIntegration: 0,
|
|
901
1026
|
lastSlabType: -1,
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
pwfTextureString: null,
|
|
905
|
-
resliceGeom: null,
|
|
906
|
-
resliceGeomUpdateString: null,
|
|
907
|
-
tris: null,
|
|
1027
|
+
scalarTextures: [],
|
|
1028
|
+
_scalarTexturesCore: [],
|
|
908
1029
|
colorTexture: null,
|
|
1030
|
+
_colorTextureCore: null,
|
|
909
1031
|
pwfTexture: null,
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1032
|
+
_pwfTextureCore: null,
|
|
1033
|
+
_externalOpenGLTexture: false,
|
|
1034
|
+
resliceGeom: null,
|
|
1035
|
+
resliceGeomUpdateString: null,
|
|
1036
|
+
tris: null
|
|
914
1037
|
};
|
|
915
1038
|
|
|
916
1039
|
// ----------------------------------------------------------------------------
|
|
@@ -924,7 +1047,7 @@ function extend(publicAPI, model) {
|
|
|
924
1047
|
vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
|
|
925
1048
|
vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
|
|
926
1049
|
model.tris = vtkHelper.newInstance();
|
|
927
|
-
model.
|
|
1050
|
+
model.scalarTextures = [];
|
|
928
1051
|
model.colorTexture = null;
|
|
929
1052
|
model.pwfTexture = null;
|
|
930
1053
|
model.VBOBuildTime = {};
|
|
@@ -939,7 +1062,7 @@ function extend(publicAPI, model) {
|
|
|
939
1062
|
model.cutter = vtkCutter.newInstance();
|
|
940
1063
|
model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
|
|
941
1064
|
model.transform = vtkTransform.newInstance();
|
|
942
|
-
get(publicAPI, model, ['
|
|
1065
|
+
get(publicAPI, model, ['scalarTextures']);
|
|
943
1066
|
|
|
944
1067
|
// Object methods
|
|
945
1068
|
vtkOpenGLImageResliceMapper(publicAPI, model);
|