@kitware/vtk.js 22.2.1 → 22.4.0
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/Rendering/OpenGL/RenderWindow.js +6 -0
- package/Rendering/SceneGraph/RenderWindowViewNode.js +5 -0
- package/Rendering/WebGPU/BindGroup.js +5 -4
- package/Rendering/WebGPU/Buffer.js +6 -3
- package/Rendering/WebGPU/BufferManager.js +3 -1
- package/Rendering/WebGPU/Device.js +1 -1
- package/Rendering/WebGPU/Glyph3DMapper.js +3 -2
- package/Rendering/WebGPU/HardwareSelectionPass.js +11 -7
- package/Rendering/WebGPU/HardwareSelector.js +6 -2
- package/Rendering/WebGPU/ImageMapper.js +14 -12
- package/Rendering/WebGPU/MapperHelper.js +3 -2
- package/Rendering/WebGPU/OpaquePass.js +11 -7
- package/Rendering/WebGPU/OrderIndependentTranslucentPass.js +14 -8
- package/Rendering/WebGPU/Pipeline.js +6 -5
- package/Rendering/WebGPU/PolyDataMapper.js +7 -5
- package/Rendering/WebGPU/RenderEncoder.js +12 -3
- package/Rendering/WebGPU/RenderWindow.js +7 -0
- package/Rendering/WebGPU/Renderer.js +9 -6
- package/Rendering/WebGPU/Sampler.js +4 -3
- package/Rendering/WebGPU/StorageBuffer.js +6 -5
- package/Rendering/WebGPU/Texture.js +13 -7
- package/Rendering/WebGPU/TextureView.js +10 -21
- package/Rendering/WebGPU/UniformBuffer.js +6 -5
- package/Rendering/WebGPU/VolumePass.js +42 -28
- package/Rendering/WebGPU/VolumePassFSQ.js +32 -16
- package/Widgets/Core/WidgetManager.js +211 -71
- package/Widgets/Widgets3D/SplineWidget/behavior.js +9 -6
- package/package.json +5 -6
|
@@ -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 >
|
|
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.
|
|
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.
|
|
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
|
-
|
|
100
|
-
|
|
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', '
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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', '
|
|
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(
|
|
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
|
-
|
|
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
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
|
|
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
|
-
|
|
550
|
+
model.UBO = vtkWebGPUUniformBuffer.newInstance({
|
|
551
|
+
label: 'mapperUBO'
|
|
552
|
+
});
|
|
539
553
|
model.UBO.addEntry('SampleDistance', 'f32');
|
|
540
|
-
model.SSBO = vtkWebGPUStorageBuffer.newInstance(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
model.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
|