@kitware/vtk.js 22.2.2 → 22.4.1

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.
Files changed (33) hide show
  1. package/Rendering/Core/ScalarBarActor.js +196 -143
  2. package/Rendering/OpenGL/Profiles/All.js +1 -0
  3. package/Rendering/OpenGL/Profiles/Geometry.js +1 -0
  4. package/Rendering/OpenGL/ScalarBarActor.js +61 -0
  5. package/Rendering/Profiles/All.js +2 -0
  6. package/Rendering/Profiles/Geometry.js +2 -0
  7. package/Rendering/WebGPU/BindGroup.js +5 -4
  8. package/Rendering/WebGPU/Buffer.js +6 -3
  9. package/Rendering/WebGPU/BufferManager.js +3 -1
  10. package/Rendering/WebGPU/Device.js +1 -1
  11. package/Rendering/WebGPU/Glyph3DMapper.js +3 -2
  12. package/Rendering/WebGPU/HardwareSelectionPass.js +11 -7
  13. package/Rendering/WebGPU/HardwareSelector.js +6 -2
  14. package/Rendering/WebGPU/ImageMapper.js +14 -12
  15. package/Rendering/WebGPU/MapperHelper.js +3 -2
  16. package/Rendering/WebGPU/OpaquePass.js +11 -7
  17. package/Rendering/WebGPU/OrderIndependentTranslucentPass.js +14 -8
  18. package/Rendering/WebGPU/Pipeline.js +6 -5
  19. package/Rendering/WebGPU/PolyDataMapper.js +7 -5
  20. package/Rendering/WebGPU/Profiles/All.js +1 -0
  21. package/Rendering/WebGPU/Profiles/Geometry.js +1 -0
  22. package/Rendering/WebGPU/RenderEncoder.js +12 -3
  23. package/Rendering/WebGPU/Renderer.js +9 -6
  24. package/Rendering/WebGPU/Sampler.js +4 -3
  25. package/Rendering/WebGPU/ScalarBarActor.js +61 -0
  26. package/Rendering/WebGPU/StorageBuffer.js +6 -5
  27. package/Rendering/WebGPU/Texture.js +13 -7
  28. package/Rendering/WebGPU/TextureView.js +10 -21
  29. package/Rendering/WebGPU/UniformBuffer.js +6 -5
  30. package/Rendering/WebGPU/VolumePass.js +42 -28
  31. package/Rendering/WebGPU/VolumePassFSQ.js +32 -16
  32. package/Widgets/Widgets3D/SplineWidget/behavior.js +9 -6
  33. package/package.json +5 -6
@@ -41,7 +41,8 @@ function vtkWebGPUStorageBuffer(publicAPI, model) {
41
41
  var req = {
42
42
  nativeArray: model.Float32Array,
43
43
  time: 0,
44
- usage: BufferUsage.Storage
44
+ usage: BufferUsage.Storage,
45
+ label: model.label
45
46
  };
46
47
  model._buffer = device.getBufferManager().getBuffer(req);
47
48
  model.bindGroupTime.modified();
@@ -171,14 +172,14 @@ function vtkWebGPUStorageBuffer(publicAPI, model) {
171
172
  };
172
173
 
173
174
  publicAPI.getShaderCode = function (binding, group) {
174
- var lines = ["struct ".concat(model.name, "StructEntry\n{")];
175
+ var lines = ["struct ".concat(model.label, "StructEntry\n{")];
175
176
 
176
177
  for (var i = 0; i < model.bufferEntries.length; i++) {
177
178
  var entry = model.bufferEntries[i];
178
179
  lines.push(" ".concat(entry.name, ": ").concat(entry.type, ";"));
179
180
  }
180
181
 
181
- lines.push("\n};\nstruct ".concat(model.name, "Struct\n{\n values: array<").concat(model.name, "StructEntry>;\n};\n@binding(").concat(binding, ") @group(").concat(group, ") var<storage, read> ").concat(model.name, ": ").concat(model.name, "Struct;\n"));
182
+ lines.push("\n};\nstruct ".concat(model.label, "Struct\n{\n values: array<").concat(model.label, "StructEntry>;\n};\n@binding(").concat(binding, ") @group(").concat(group, ") var<storage, read> ").concat(model.label, ": ").concat(model.label, "Struct;\n"));
182
183
  return lines.join('\n');
183
184
  };
184
185
 
@@ -209,7 +210,7 @@ var DEFAULT_VALUES = {
209
210
  bufferEntries: null,
210
211
  bufferEntryNames: null,
211
212
  sizeInBytes: 0,
212
- name: null,
213
+ label: null,
213
214
  numberOfInstances: 1
214
215
  }; // ----------------------------------------------------------------------------
215
216
 
@@ -236,7 +237,7 @@ function extend(publicAPI, model) {
236
237
  }
237
238
  };
238
239
  macro.get(publicAPI, model, ['bindGroupTime']);
239
- macro.setGet(publicAPI, model, ['device', 'bindGroupLayoutEntry', 'name', 'numberOfInstances', 'sizeInBytes']); // Object methods
240
+ macro.setGet(publicAPI, model, ['device', 'bindGroupLayoutEntry', 'label', 'numberOfInstances', 'sizeInBytes']); // Object methods
240
241
 
241
242
  vtkWebGPUStorageBuffer(publicAPI, model);
242
243
  } // ----------------------------------------------------------------------------
@@ -36,6 +36,7 @@ function vtkWebGPUTexture(publicAPI, model) {
36
36
  format: model.format,
37
37
  // 'rgba8unorm',
38
38
  usage: model.usage,
39
+ label: model.label,
39
40
  dimension: dimension
40
41
  });
41
42
  };
@@ -172,7 +173,8 @@ function vtkWebGPUTexture(publicAPI, model) {
172
173
  model.handle = model.device.getHandle().createTexture({
173
174
  size: [model.width, model.height, model.depth],
174
175
  format: model.format,
175
- usage: model.usage
176
+ usage: model.usage,
177
+ label: model.label
176
178
  });
177
179
  }
178
180
  };
@@ -187,20 +189,23 @@ function vtkWebGPUTexture(publicAPI, model) {
187
189
  model.handle = model.device.getHandle().createTexture({
188
190
  size: [model.width, model.height, model.depth],
189
191
  format: model.format,
190
- usage: model.usage
192
+ usage: model.usage,
193
+ label: model.label
191
194
  });
192
195
  }
193
196
  };
194
197
 
195
- publicAPI.createView = function () {
196
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
198
+ publicAPI.createView = function (label) {
199
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
197
200
 
198
201
  // if options is missing values try to add them in
199
202
  if (!options.dimension) {
200
203
  options.dimension = model.depth === 1 ? '2d' : '3d';
201
204
  }
202
205
 
203
- var view = vtkWebGPUTextureView.newInstance();
206
+ var view = vtkWebGPUTextureView.newInstance({
207
+ label: label
208
+ });
204
209
  view.create(publicAPI, options);
205
210
  return view;
206
211
  };
@@ -213,7 +218,8 @@ var DEFAULT_VALUES = {
213
218
  device: null,
214
219
  handle: null,
215
220
  buffer: null,
216
- ready: false
221
+ ready: false,
222
+ label: null
217
223
  }; // ----------------------------------------------------------------------------
218
224
 
219
225
  function extend(publicAPI, model) {
@@ -222,7 +228,7 @@ function extend(publicAPI, model) {
222
228
 
223
229
  macro.obj(publicAPI, model);
224
230
  macro.get(publicAPI, model, ['handle', 'ready', 'width', 'height', 'depth', 'format', 'usage']);
225
- macro.setGet(publicAPI, model, ['device']);
231
+ macro.setGet(publicAPI, model, ['device', 'label']);
226
232
  vtkWebGPUTexture(publicAPI, model);
227
233
  } // ----------------------------------------------------------------------------
228
234
 
@@ -15,6 +15,7 @@ function vtkWebGPUTextureView(publicAPI, model) {
15
15
  model.texture = texture;
16
16
  model.options = options;
17
17
  model.options.dimension = model.options.dimension || '2d';
18
+ model.options.label = model.label;
18
19
  model.textureHandle = texture.getHandle();
19
20
  model.handle = model.textureHandle.createView(model.options);
20
21
  model.bindGroupLayoutEntry.texture.viewDimension = model.options.dimension;
@@ -38,33 +39,21 @@ function vtkWebGPUTextureView(publicAPI, model) {
38
39
  ttype = 'u32';
39
40
  }
40
41
 
41
- var result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.name, ": texture_").concat(model.options.dimension, "<").concat(ttype, ">;");
42
+ var result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.label, ": texture_").concat(model.options.dimension, "<").concat(ttype, ">;");
42
43
 
43
44
  if (model.bindGroupLayoutEntry.texture.sampleType === 'depth') {
44
- result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.name, ": texture_depth_").concat(model.options.dimension, ";");
45
+ result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.label, ": texture_depth_").concat(model.options.dimension, ";");
45
46
  }
46
47
 
47
48
  return result;
48
49
  };
49
50
 
50
51
  publicAPI.addSampler = function (device, options) {
51
- var newSamp = vtkWebGPUSampler.newInstance();
52
+ var newSamp = vtkWebGPUSampler.newInstance({
53
+ label: "".concat(model.label, "Sampler")
54
+ });
52
55
  newSamp.create(device, options);
53
56
  publicAPI.setSampler(newSamp);
54
- model.sampler.setName("".concat(model.name, "Sampler"));
55
- };
56
-
57
- publicAPI.setName = function (val) {
58
- if (model.sampler) {
59
- model.sampler.setName("".concat(val, "Sampler"));
60
- }
61
-
62
- if (model.name === val) {
63
- return;
64
- }
65
-
66
- model.name = val;
67
- publicAPI.modified();
68
57
  };
69
58
 
70
59
  publicAPI.getBindGroupTime = function () {
@@ -96,8 +85,8 @@ function vtkWebGPUTextureView(publicAPI, model) {
96
85
  var DEFAULT_VALUES = {
97
86
  texture: null,
98
87
  handle: null,
99
- name: null,
100
- sampler: null
88
+ sampler: null,
89
+ label: null
101
90
  }; // ----------------------------------------------------------------------------
102
91
 
103
92
  function extend(publicAPI, model) {
@@ -120,8 +109,8 @@ function extend(publicAPI, model) {
120
109
  macro.obj(model.bindGroupTime, {
121
110
  mtime: 0
122
111
  });
123
- macro.get(publicAPI, model, ['bindGroupTime', 'name', 'texture']);
124
- macro.setGet(publicAPI, model, ['bindGroupLayoutEntry', 'sampler']);
112
+ macro.get(publicAPI, model, ['bindGroupTime', 'texture']);
113
+ macro.setGet(publicAPI, model, ['bindGroupLayoutEntry', 'label', 'sampler']);
125
114
  vtkWebGPUTextureView(publicAPI, model);
126
115
  } // ----------------------------------------------------------------------------
127
116
 
@@ -207,7 +207,8 @@ function vtkWebGPUUniformBuffer(publicAPI, model) {
207
207
  var req = {
208
208
  nativeArray: model.Float32Array,
209
209
  time: 0,
210
- usage: BufferUsage.UniformArray
210
+ usage: BufferUsage.UniformArray,
211
+ label: model.label
211
212
  };
212
213
  model.UBO = device.getBufferManager().getBuffer(req);
213
214
  model.bindGroupTime.modified();
@@ -301,14 +302,14 @@ function vtkWebGPUUniformBuffer(publicAPI, model) {
301
302
  publicAPI.getShaderCode = function (binding, group) {
302
303
  // sort the entries
303
304
  publicAPI.sortBufferEntries();
304
- var lines = ["struct ".concat(model.name, "Struct\n{")];
305
+ var lines = ["struct ".concat(model.label, "Struct\n{")];
305
306
 
306
307
  for (var i = 0; i < model.bufferEntries.length; i++) {
307
308
  var entry = model.bufferEntries[i];
308
309
  lines.push(" ".concat(entry.name, ": ").concat(entry.type, ";"));
309
310
  }
310
311
 
311
- lines.push("};\n@binding(".concat(binding, ") @group(").concat(group, ") var<uniform> ").concat(model.name, ": ").concat(model.name, "Struct;"));
312
+ lines.push("};\n@binding(".concat(binding, ") @group(").concat(group, ") var<uniform> ").concat(model.label, ": ").concat(model.label, "Struct;"));
312
313
  return lines.join('\n');
313
314
  };
314
315
  } // ----------------------------------------------------------------------------
@@ -320,7 +321,7 @@ var DEFAULT_VALUES = {
320
321
  bufferEntries: null,
321
322
  bufferEntryNames: null,
322
323
  sizeInBytes: 0,
323
- name: null,
324
+ label: null,
324
325
  bindGroupLayoutEntry: null,
325
326
  bindGroupEntry: null
326
327
  }; // ----------------------------------------------------------------------------
@@ -350,7 +351,7 @@ function extend(publicAPI, model) {
350
351
  model.sendDirty = true;
351
352
  model.sortDirty = true;
352
353
  macro.get(publicAPI, model, ['binding', 'bindGroupTime']);
353
- macro.setGet(publicAPI, model, ['bindGroupLayoutEntry', 'device', 'name', 'sizeInBytes']); // Object methods
354
+ macro.setGet(publicAPI, model, ['bindGroupLayoutEntry', 'device', 'label', 'sizeInBytes']); // Object methods
354
355
 
355
356
  vtkWebGPUUniformBuffer(publicAPI, model);
356
357
  } // ----------------------------------------------------------------------------
@@ -34,7 +34,7 @@ var BufferUsage = vtkWebGPUBufferManager.BufferUsage,
34
34
 
35
35
  var cubeFaceTriangles = [[0, 4, 6], [0, 6, 2], [1, 3, 7], [1, 7, 5], [0, 5, 4], [0, 1, 5], [2, 6, 7], [2, 7, 3], [0, 3, 1], [0, 2, 3], [4, 5, 7], [4, 7, 6]];
36
36
  var DepthBoundsFS = "\n//VTK::Renderer::Dec\n\n//VTK::Select::Dec\n\n//VTK::VolumePass::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n //VTK::Select::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::VolumePass::Impl\n\n // use the maximum (closest) of the current value and the zbuffer\n // the blend func will then take the min to find the farthest stop value\n var stopval: f32 = max(input.fragPos.z, textureLoad(opaquePassDepthTexture, vec2<i32>(i32(input.fragPos.x), i32(input.fragPos.y)), 0));\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
37
- var volumeCopyFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = textureSample(volumePassSmallColorTexture,\n volumePassSmallColorTextureSampler, mapperUBO.tscale*input.tcoordVS);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
37
+ var volumeCopyFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = textureSample(volumePassColorTexture,\n volumePassColorTextureSampler, mapperUBO.tscale*input.tcoordVS);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
38
38
  /* eslint-disable no-undef */
39
39
 
40
40
  /* eslint-disable no-bitwise */
@@ -76,9 +76,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
76
76
 
77
77
  model._volumeCopyQuad.setFragmentShaderTemplate(volumeCopyFragTemplate);
78
78
 
79
- model._copyUBO = vtkWebGPUUniformBuffer.newInstance();
80
-
81
- model._copyUBO.setName('mapperUBO');
79
+ model._copyUBO = vtkWebGPUUniformBuffer.newInstance({
80
+ label: 'mapperUBO'
81
+ });
82
82
 
83
83
  model._copyUBO.addEntry('tscale', 'vec2<f32>');
84
84
 
@@ -206,14 +206,20 @@ function vtkWebGPUVolumePass(publicAPI, model) {
206
206
  if (!model._animationRateSubscription) {
207
207
  // when the animation frame rate changes recompute the scale factor
208
208
  model._animationRateSubscription = rwi.onAnimationFrameRateUpdate(function () {
209
- var frate = rwi.getRecentAnimationFrameRate();
210
- var targetScale = model._lastScale * rwi.getDesiredUpdateRate() / frate;
211
- model._lastScale = targetScale; // clamp scale to some reasonable values.
212
- // Below 1.5 we will just be using full resolution as that is close enough
213
- // Above 400 seems like a lot so we limit to that 1/20th per axis
214
-
215
- if (model._lastScale > 400) {
216
- model._lastScale = 400;
209
+ var firstMapper = model.volumes[0].getRenderable().getMapper();
210
+
211
+ if (firstMapper.getAutoAdjustSampleDistances()) {
212
+ var frate = rwi.getRecentAnimationFrameRate();
213
+ var targetScale = model._lastScale * rwi.getDesiredUpdateRate() / frate;
214
+ model._lastScale = targetScale; // clamp scale to some reasonable values.
215
+ // Below 1.5 we will just be using full resolution as that is close enough
216
+ // Above 400 seems like a lot so we limit to that 1/20th per axis
217
+
218
+ if (model._lastScale > 400) {
219
+ model._lastScale = 400;
220
+ }
221
+ } else {
222
+ model._lastScale = firstMapper.getImageSampleDistance() * firstMapper.getImageSampleDistance();
217
223
  }
218
224
 
219
225
  if (model._lastScale < 1.5) {
@@ -366,7 +372,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
366
372
 
367
373
  publicAPI.createDepthRangeEncoder = function (viewNode) {
368
374
  var device = viewNode.getDevice();
369
- model._depthRangeEncoder = vtkWebGPURenderEncoder.newInstance();
375
+ model._depthRangeEncoder = vtkWebGPURenderEncoder.newInstance({
376
+ label: 'VolumePass DepthRange'
377
+ });
370
378
 
371
379
  model._depthRangeEncoder.setPipelineHash('volr');
372
380
 
@@ -429,7 +437,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
429
437
  }); // and the textures it needs
430
438
 
431
439
 
432
- model._depthRangeTexture = vtkWebGPUTexture.newInstance();
440
+ model._depthRangeTexture = vtkWebGPUTexture.newInstance({
441
+ label: 'volumePassMaxDepth'
442
+ });
433
443
 
434
444
  model._depthRangeTexture.create(device, {
435
445
  width: viewNode.getCanvas().width,
@@ -438,13 +448,13 @@ function vtkWebGPUVolumePass(publicAPI, model) {
438
448
  usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
439
449
  });
440
450
 
441
- var maxView = model._depthRangeTexture.createView();
442
-
443
- maxView.setName('maxTexture');
451
+ var maxView = model._depthRangeTexture.createView('maxTexture');
444
452
 
445
453
  model._depthRangeEncoder.setColorTextureView(0, maxView);
446
454
 
447
- model._depthRangeTexture2 = vtkWebGPUTexture.newInstance();
455
+ model._depthRangeTexture2 = vtkWebGPUTexture.newInstance({
456
+ label: 'volumePassDepthMin'
457
+ });
448
458
 
449
459
  model._depthRangeTexture2.create(device, {
450
460
  width: viewNode.getCanvas().width,
@@ -453,9 +463,7 @@ function vtkWebGPUVolumePass(publicAPI, model) {
453
463
  usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
454
464
  });
455
465
 
456
- var minView = model._depthRangeTexture2.createView();
457
-
458
- minView.setName('minTexture');
466
+ var minView = model._depthRangeTexture2.createView('minTexture');
459
467
 
460
468
  model._depthRangeEncoder.setColorTextureView(1, minView);
461
469
 
@@ -465,7 +473,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
465
473
  };
466
474
 
467
475
  publicAPI.createClearEncoder = function (viewNode) {
468
- model._colorTexture = vtkWebGPUTexture.newInstance();
476
+ model._colorTexture = vtkWebGPUTexture.newInstance({
477
+ label: 'volumePassColor'
478
+ });
469
479
 
470
480
  model._colorTexture.create(viewNode.getDevice(), {
471
481
  width: viewNode.getCanvas().width,
@@ -478,16 +488,16 @@ function vtkWebGPUVolumePass(publicAPI, model) {
478
488
  usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC
479
489
  });
480
490
 
481
- model._colorTextureView = model._colorTexture.createView();
482
-
483
- model._colorTextureView.setName('volumePassSmallColorTexture');
491
+ model._colorTextureView = model._colorTexture.createView('volumePassColorTexture');
484
492
 
485
493
  model._colorTextureView.addSampler(viewNode.getDevice(), {
486
494
  minFilter: 'linear',
487
495
  magFilter: 'linear'
488
496
  });
489
497
 
490
- model._clearEncoder = vtkWebGPURenderEncoder.newInstance();
498
+ model._clearEncoder = vtkWebGPURenderEncoder.newInstance({
499
+ label: 'VolumePass Clear'
500
+ });
491
501
 
492
502
  model._clearEncoder.setColorTextureView(0, model._colorTextureView);
493
503
 
@@ -524,7 +534,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
524
534
  };
525
535
 
526
536
  publicAPI.createCopyEncoder = function (viewNode) {
527
- model._copyEncoder = vtkWebGPURenderEncoder.newInstance();
537
+ model._copyEncoder = vtkWebGPURenderEncoder.newInstance({
538
+ label: 'volumePassCopy'
539
+ });
528
540
 
529
541
  model._copyEncoder.setDescription({
530
542
  colorAttachments: [{
@@ -559,7 +571,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
559
571
  };
560
572
 
561
573
  publicAPI.createMergeEncoder = function (viewNode) {
562
- model._mergeEncoder = vtkWebGPURenderEncoder.newInstance();
574
+ model._mergeEncoder = vtkWebGPURenderEncoder.newInstance({
575
+ label: 'volumePassMerge'
576
+ });
563
577
 
564
578
  model._mergeEncoder.setColorTextureView(0, model._colorTextureView);
565
579
 
@@ -9,7 +9,7 @@ import vtkWebGPUSampler from './Sampler.js';
9
9
  import vtkWebGPUTypes from './Types.js';
10
10
  import { BlendMode } from '../Core/VolumeMapper/Constants.js';
11
11
 
12
- var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n\n // divide by spacing\n result = result / volumeSSBO.values[vNum].spacing;\n\n var grad: f32 = length(result.xyz);\n\n // // rotate to View Coords, needed for lighting and shading\n // result.xyz =\n // result.x * vPlaneNormal0 +\n // result.y * vPlaneNormal2 +\n // result.z * vPlaneNormal4;\n\n if (grad > 0.0)\n {\n result = result * (1.0 / grad);\n }\n\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n var normal: vec4<f32> = getGradient(vTex, tpos, vNum, scalar);\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n//VTK::Volume::Process\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
12
+ var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n result.w = 0.0;\n\n // divide by spacing as that is our delta\n result = result / volumeSSBO.values[vNum].spacing;\n // now we have a gradient in unit tcoords\n\n var grad: f32 = length(result.xyz);\n if (grad > 0.0)\n {\n // rotate to View Coords, needed for lighting and shading\n var nMat: mat4x4<f32> = rendererUBO.SCVCMatrix * volumeSSBO.values[vNum].planeNormals;\n result = nMat * result;\n result = result / length(result);\n }\n\n // store gradient magnitude in .w\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n var normal: vec4<f32> = vec4<f32>(0.0,0.0,0.0,0.0);\n if (componentSSBO.values[cNum].gomin < 1.0 || volumeSSBO.values[vNum].shade[0] > 0.0)\n {\n normal = getGradient(vTex, tpos, vNum, scalar);\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n if (volumeSSBO.values[vNum].shade[0] > 0.0)\n {\n color = color*abs(normal.z);\n }\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
13
13
  var tmpMat4 = new Float64Array(16);
14
14
  var tmp2Mat4 = new Float64Array(16); // ----------------------------------------------------------------------------
15
15
  // vtkWebGPUVolumePassFSQ methods
@@ -189,8 +189,7 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
189
189
  format: 'rgba8unorm'
190
190
  };
191
191
  var newTex = device.getTextureManager().getTexture(treq);
192
- var tview = newTex.createView();
193
- tview.setName('tfunTexture');
192
+ var tview = newTex.createView('tfunTexture');
194
193
  model.textureViews[2] = tview;
195
194
  }
196
195
  {
@@ -204,9 +203,7 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
204
203
 
205
204
  var _newTex = device.getTextureManager().getTexture(_treq);
206
205
 
207
- var _tview = _newTex.createView();
208
-
209
- _tview.setName('ofunTexture');
206
+ var _tview = _newTex.createView('ofunTexture');
210
207
 
211
208
  model.textureViews[3] = _tview;
212
209
  }
@@ -243,7 +240,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
243
240
  //
244
241
 
245
242
  var marray = new Float64Array(model.volumes.length * 16);
243
+ var vPlaneArray = new Float64Array(model.volumes.length * 16);
246
244
  var tstepArray = new Float64Array(model.volumes.length * 4);
245
+ var shadeArray = new Float64Array(model.volumes.length * 4);
247
246
  var spacingArray = new Float64Array(model.volumes.length * 4);
248
247
  var ipScalarRangeArray = new Float64Array(model.volumes.length * 4);
249
248
 
@@ -280,10 +279,20 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
280
279
  marray[vidx * 16 + j] = tmpMat4[j];
281
280
  }
282
281
 
282
+ mat4.invert(tmpMat4, tmpMat4); // now it is Tcoord To SC
283
+
284
+ for (var _j = 0; _j < 4; _j++) {
285
+ vPlaneArray[vidx * 16 + _j * 4] = tmpMat4[_j * 4];
286
+ vPlaneArray[vidx * 16 + _j * 4 + 1] = tmpMat4[_j * 4 + 1];
287
+ vPlaneArray[vidx * 16 + _j * 4 + 2] = tmpMat4[_j * 4 + 2];
288
+ vPlaneArray[vidx * 16 + _j * 4 + 3] = 0.0;
289
+ }
290
+
283
291
  tstepArray[vidx * 4] = 1.0 / dims[0];
284
292
  tstepArray[vidx * 4 + 1] = 1.0 / dims[1];
285
293
  tstepArray[vidx * 4 + 2] = 1.0 / dims[2];
286
294
  tstepArray[vidx * 4 + 3] = 1.0;
295
+ shadeArray[vidx * 4] = actor.getProperty().getShade() ? 1.0 : 0.0;
287
296
 
288
297
  var spacing = _image3.getSpacing();
289
298
 
@@ -302,10 +311,14 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
302
311
  }
303
312
 
304
313
  model.SSBO.addEntry('SCTCMatrix', 'mat4x4<f32>');
314
+ model.SSBO.addEntry('planeNormals', 'mat4x4<f32>');
315
+ model.SSBO.addEntry('shade', 'vec4<f32>');
305
316
  model.SSBO.addEntry('tstep', 'vec4<f32>');
306
317
  model.SSBO.addEntry('spacing', 'vec4<f32>');
307
318
  model.SSBO.addEntry('ipScalarRange', 'vec4<f32>');
308
319
  model.SSBO.setAllInstancesFromArray('SCTCMatrix', marray);
320
+ model.SSBO.setAllInstancesFromArray('planeNormals', vPlaneArray);
321
+ model.SSBO.setAllInstancesFromArray('shade', shadeArray);
309
322
  model.SSBO.setAllInstancesFromArray('tstep', tstepArray);
310
323
  model.SSBO.setAllInstancesFromArray('spacing', spacingArray);
311
324
  model.SSBO.setAllInstancesFromArray('ipScalarRange', ipScalarRangeArray);
@@ -446,8 +459,7 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
446
459
  var newTex = device.getTextureManager().getTexture(treq);
447
460
 
448
461
  if (!model.textureViews[vidx + 4] || model.textureViews[vidx + 4].getTexture() !== newTex) {
449
- var tview = newTex.createView();
450
- tview.setName("volTexture".concat(vidx));
462
+ var tview = newTex.createView("volTexture".concat(vidx));
451
463
  model.textureViews[vidx + 4] = tview;
452
464
  }
453
465
  } // clear any old leftovers
@@ -498,8 +510,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
498
510
  publicAPI.updateBuffers(device);
499
511
 
500
512
  if (!model.clampSampler) {
501
- model.clampSampler = vtkWebGPUSampler.newInstance();
502
- model.clampSampler.setName('clampSampler');
513
+ model.clampSampler = vtkWebGPUSampler.newInstance({
514
+ label: 'clampSampler'
515
+ });
503
516
  model.clampSampler.create(device, {
504
517
  minFilter: 'linear',
505
518
  magFilter: 'linear'
@@ -534,13 +547,16 @@ function extend(publicAPI, model) {
534
547
 
535
548
  vtkWebGPUFullScreenQuad.extend(publicAPI, model, initialValues);
536
549
  model.fragmentShaderTemplate = volFragTemplate;
537
- model.UBO = vtkWebGPUUniformBuffer.newInstance();
538
- model.UBO.setName('mapperUBO');
550
+ model.UBO = vtkWebGPUUniformBuffer.newInstance({
551
+ label: 'mapperUBO'
552
+ });
539
553
  model.UBO.addEntry('SampleDistance', 'f32');
540
- model.SSBO = vtkWebGPUStorageBuffer.newInstance();
541
- model.SSBO.setName('volumeSSBO');
542
- model.componentSSBO = vtkWebGPUStorageBuffer.newInstance();
543
- model.componentSSBO.setName('componentSSBO');
554
+ model.SSBO = vtkWebGPUStorageBuffer.newInstance({
555
+ label: 'volumeSSBO'
556
+ });
557
+ model.componentSSBO = vtkWebGPUStorageBuffer.newInstance({
558
+ label: 'componentSSBO'
559
+ });
544
560
  model.lutBuildTime = {};
545
561
  macro.obj(model.lutBuildTime, {
546
562
  mtime: 0
@@ -48,13 +48,16 @@ function widgetBehavior(publicAPI, model) {
48
48
  return handles.reduce(function (_ref, handle) {
49
49
  var closestHandle = _ref.closestHandle,
50
50
  closestDistance = _ref.closestDistance;
51
- var distance = vec3.squaredDistance(model.moveHandle.getOrigin(), handle.getOrigin());
52
51
 
53
- if (handle !== model.moveHandle) {
54
- return {
55
- closestHandle: distance < closestDistance ? handle : closestHandle,
56
- closestDistance: distance < closestDistance ? distance : closestDistance
57
- };
52
+ if (handle !== model.moveHandle && model.moveHandle.getOrigin() && handle.getOrigin()) {
53
+ var distance = vec3.squaredDistance(model.moveHandle.getOrigin(), handle.getOrigin());
54
+
55
+ if (distance < closestDistance) {
56
+ return {
57
+ closestHandle: handle,
58
+ closestDistance: distance
59
+ };
60
+ }
58
61
  }
59
62
 
60
63
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "22.2.2",
3
+ "version": "22.4.1",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",
@@ -38,7 +38,6 @@
38
38
  "globalthis": "1.0.2",
39
39
  "jszip": "3.7.1",
40
40
  "pako": "2.0.4",
41
- "patch-package": "6.4.7",
42
41
  "seedrandom": "3.0.5",
43
42
  "shader-loader": "1.3.1",
44
43
  "shelljs": "0.8.5",
@@ -98,6 +97,7 @@
98
97
  "lodash": "4.17.21",
99
98
  "magic-string": "0.25.7",
100
99
  "moment": "2.29.1",
100
+ "patch-package": "6.4.7",
101
101
  "pixelmatch": "5.2.1",
102
102
  "postcss-loader": "6.2.1",
103
103
  "prettier": "2.5.1",
@@ -112,10 +112,9 @@
112
112
  "rollup-plugin-string": "3.0.0",
113
113
  "rollup-plugin-svgo": "1.1.0",
114
114
  "rollup-plugin-web-worker-loader": "1.6.1",
115
- "semantic-release": "18.0.1",
115
+ "semantic-release": "19.0.2",
116
116
  "string-replace-loader": "3.1.0",
117
117
  "style-loader": "3.3.1",
118
- "tap-spec": "5.0.0",
119
118
  "tape": "5.4.0",
120
119
  "tape-catch": "1.0.6",
121
120
  "webpack": "5.65.0",
@@ -145,7 +144,7 @@
145
144
  "dev:esm": "npm run build:esm -- -w",
146
145
  "dev:umd": "webpack --watch --config webpack.dev.js --progress",
147
146
  "build": "npm run build:release",
148
- "build:esm": "rollup -c rollup.config.js",
147
+ "build:esm": "npm run patch-build-deps && rollup -c rollup.config.js",
149
148
  "build:umd": "webpack --config webpack.prod.js --progress",
150
149
  "build:release": "npm run lint && concurrently \"cross-env NOLINT=1 npm run build:esm\" \"cross-env NOLINT=1 npm run build:umd\"",
151
150
  "release:create-packages": "node ./Utilities/ci/build-npm-package.js",
@@ -158,7 +157,7 @@
158
157
  "commit": "git cz",
159
158
  "semantic-release": "semantic-release",
160
159
  "prepare": "node ./Utilities/prepare.js",
161
- "postinstall": "patch-package --patch-dir ./Utilities/build/patches"
160
+ "patch-build-deps": "patch-package --patch-dir ./Utilities/build/patches"
162
161
  },
163
162
  "config": {
164
163
  "commitizen": {