@kitware/vtk.js 22.3.0 → 22.5.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/IO/Core/DataAccessHelper/HttpDataAccessHelper.js +8 -1
- package/Rendering/Core/ScalarBarActor.js +196 -143
- package/Rendering/OpenGL/Profiles/All.js +1 -0
- package/Rendering/OpenGL/Profiles/Geometry.js +1 -0
- package/Rendering/OpenGL/ScalarBarActor.js +61 -0
- package/Rendering/Profiles/All.js +2 -0
- package/Rendering/Profiles/Geometry.js +2 -0
- package/Rendering/WebGPU/HardwareSelectionPass.js +2 -2
- package/Rendering/WebGPU/OrderIndependentTranslucentPass.js +7 -5
- package/Rendering/WebGPU/Profiles/All.js +1 -0
- package/Rendering/WebGPU/Profiles/Geometry.js +1 -0
- package/Rendering/WebGPU/RenderEncoder.js +5 -3
- package/Rendering/WebGPU/ScalarBarActor.js +61 -0
- package/Rendering/WebGPU/VolumePass.js +22 -13
- package/Rendering/WebGPU/VolumePassFSQ.js +17 -1
- package/Widgets/Widgets3D/ShapeWidget/behavior.js +1 -1
- package/package.json +1 -1
|
@@ -74,7 +74,14 @@ function fetchArray(instance, baseURL, array) {
|
|
|
74
74
|
|
|
75
75
|
if (array.ref && !array.ref.pending) {
|
|
76
76
|
return new Promise(function (resolve, reject) {
|
|
77
|
-
var url =
|
|
77
|
+
var url = null;
|
|
78
|
+
|
|
79
|
+
if (array.ref.url) {
|
|
80
|
+
url = array.ref.url;
|
|
81
|
+
} else {
|
|
82
|
+
url = [baseURL, array.ref.basepath, options.compression ? "".concat(array.ref.id, ".gz") : array.ref.id].join('/');
|
|
83
|
+
}
|
|
84
|
+
|
|
78
85
|
var xhr = openAsyncXHR('GET', url, options);
|
|
79
86
|
|
|
80
87
|
xhr.onreadystatechange = function (e) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
2
1
|
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
2
|
+
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
3
3
|
import { vec3, mat4 } from 'gl-matrix';
|
|
4
4
|
import * as d3 from 'd3-scale';
|
|
5
5
|
import { K as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
|
|
@@ -8,7 +8,6 @@ import vtkActor from './Actor.js';
|
|
|
8
8
|
import vtkDataArray from '../../Common/Core/DataArray.js';
|
|
9
9
|
import vtkScalarsToColors from '../../Common/Core/ScalarsToColors.js';
|
|
10
10
|
import vtkMapper from './Mapper.js';
|
|
11
|
-
import vtkPixelSpaceCallbackMapper from './PixelSpaceCallbackMapper.js';
|
|
12
11
|
import vtkPolyData from '../../Common/DataModel/PolyData.js';
|
|
13
12
|
import vtkTexture from './Texture.js';
|
|
14
13
|
|
|
@@ -19,6 +18,16 @@ var VectorMode = vtkScalarsToColors.VectorMode; // -----------------------------
|
|
|
19
18
|
// vtkScalarBarActor
|
|
20
19
|
//
|
|
21
20
|
// Note log scales are currently not supported
|
|
21
|
+
//
|
|
22
|
+
// Developer note: This class is broken into the main class and a helper
|
|
23
|
+
// class. The main class holds view independent properties (those properties
|
|
24
|
+
// that do not change as the view's resolution/aspect ratio change). The
|
|
25
|
+
// helper class is instantiated one per view and holds properties that can
|
|
26
|
+
// depend on view specific values such as resolution. The helper class code
|
|
27
|
+
// could have been left to the View specific implementation (such as
|
|
28
|
+
// vtkWebGPUScalarBarActor) but is instead placed here to it can be shared by
|
|
29
|
+
// multiple rendering backends.
|
|
30
|
+
//
|
|
22
31
|
// ----------------------------------------------------------------------------
|
|
23
32
|
// some shared temp variables to reduce heap allocs
|
|
24
33
|
|
|
@@ -38,10 +47,9 @@ function applyTextStyle(ctx, style) {
|
|
|
38
47
|
} // ----------------------------------------------------------------------------
|
|
39
48
|
// Default autoLayout function
|
|
40
49
|
// ----------------------------------------------------------------------------
|
|
41
|
-
// compute good values to use based on window size etc
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
// could be redically changed. The basic gist is
|
|
50
|
+
// compute good values to use based on window size etc a bunch of heuristics
|
|
51
|
+
// here with hand tuned constants These values worked for me but really this
|
|
52
|
+
// method could be redically changed. The basic gist is
|
|
45
53
|
// 1) compute a resonable font size
|
|
46
54
|
// 2) render the text atlas using those font sizes
|
|
47
55
|
// 3) pick horizontal or vertical bsed on window size
|
|
@@ -49,96 +57,151 @@ function applyTextStyle(ctx, style) {
|
|
|
49
57
|
// compute the box size and position such that
|
|
50
58
|
// the text will all fit nicely and the bar will be a resonable size
|
|
51
59
|
// 5) compute the bar segments based on the above settings
|
|
60
|
+
//
|
|
61
|
+
// Note that this function can and should read values from the
|
|
62
|
+
// ScalarBarActor but should only write values to the view dependent helper
|
|
63
|
+
// instance that is provided as those values are the ones that will be used
|
|
64
|
+
// for rendering.
|
|
65
|
+
//
|
|
52
66
|
|
|
53
67
|
|
|
54
68
|
function defaultAutoLayout(publicAPI, model) {
|
|
55
|
-
return function () {
|
|
69
|
+
return function (helper) {
|
|
56
70
|
// we don't do a linear scale, the proportions for
|
|
57
71
|
// a 700 pixel window differ from a 1400
|
|
58
|
-
var
|
|
59
|
-
var
|
|
60
|
-
var
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
var lastSize = helper.getLastSize();
|
|
73
|
+
var xAxisAdjust = Math.pow(lastSize[0] / 700, 0.8);
|
|
74
|
+
var yAxisAdjust = Math.pow(lastSize[1] / 700, 0.8);
|
|
75
|
+
var minAdjust = Math.min(xAxisAdjust, yAxisAdjust);
|
|
76
|
+
var axisTextStyle = helper.getAxisTextStyle();
|
|
77
|
+
var tickTextStyle = helper.getTickTextStyle();
|
|
78
|
+
Object.assign(axisTextStyle, model.axisTextStyle);
|
|
79
|
+
Object.assign(tickTextStyle, model.tickTextStyle); // compute a reasonable font size first
|
|
80
|
+
|
|
81
|
+
axisTextStyle.fontSize = Math.max(24 * minAdjust, 12);
|
|
82
|
+
|
|
83
|
+
if (helper.getLastAspectRatio() > 1.0) {
|
|
84
|
+
tickTextStyle.fontSize = Math.max(20 * minAdjust, 10);
|
|
66
85
|
} else {
|
|
67
|
-
|
|
86
|
+
tickTextStyle.fontSize = Math.max(16 * minAdjust, 10);
|
|
68
87
|
} // rebuild the text atlas
|
|
69
88
|
|
|
70
89
|
|
|
71
|
-
var textSizes =
|
|
90
|
+
var textSizes = helper.updateTextureAtlas(); // now compute the boxSize and pixel offsets, different algorithm
|
|
72
91
|
// for horizonal versus vertical
|
|
73
92
|
|
|
74
|
-
|
|
93
|
+
helper.setTopTitle(false);
|
|
94
|
+
var boxSize = helper.getBoxSizeByReference(); // if vertical
|
|
75
95
|
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
var tickWidth = 2.0 * (textSizes.tickWidth +
|
|
79
|
-
|
|
96
|
+
if (helper.getLastAspectRatio() > 1.0) {
|
|
97
|
+
helper.setTickLabelPixelOffset(0.4 * tickTextStyle.fontSize);
|
|
98
|
+
var tickWidth = 2.0 * (textSizes.tickWidth + helper.getTickLabelPixelOffset()) / lastSize[0];
|
|
99
|
+
helper.setAxisTitlePixelOffset(0.8 * axisTextStyle.fontSize); // width required if the title is vertical
|
|
80
100
|
|
|
81
|
-
var titleWidth = 2.0 * (textSizes.titleHeight +
|
|
82
|
-
// nicer to put it at the top (
|
|
101
|
+
var titleWidth = 2.0 * (textSizes.titleHeight + helper.getAxisTitlePixelOffset()) / lastSize[0]; // if the title will fit within the width of the bar then that looks
|
|
102
|
+
// nicer to put it at the top (helper.topTitle), otherwise rotate it
|
|
83
103
|
// and place it sideways
|
|
84
104
|
|
|
85
|
-
if (tickWidth + 0.4 * titleWidth > 2.0 * textSizes.titleWidth /
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
if (tickWidth + 0.4 * titleWidth > 2.0 * textSizes.titleWidth / lastSize[0]) {
|
|
106
|
+
helper.setTopTitle(true);
|
|
107
|
+
boxSize[0] = tickWidth + 0.4 * titleWidth;
|
|
108
|
+
helper.setBoxPosition([0.98 - boxSize[0], -0.92]);
|
|
89
109
|
} else {
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
boxSize[0] = tickWidth + 1.4 * titleWidth;
|
|
111
|
+
helper.setBoxPosition([0.99 - boxSize[0], -0.92]);
|
|
92
112
|
}
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
boxSize[1] = Math.max(1.2, Math.min(1.84 / yAxisAdjust, 1.84));
|
|
95
115
|
} else {
|
|
96
116
|
// horizontal
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
var tickHeight = 2.0 * (textSizes.tickHeight +
|
|
100
|
-
var titleHeight = 2.0 * (textSizes.titleHeight +
|
|
117
|
+
helper.setAxisTitlePixelOffset(2.0 * tickTextStyle.fontSize);
|
|
118
|
+
helper.setTickLabelPixelOffset(0.5 * tickTextStyle.fontSize);
|
|
119
|
+
var tickHeight = 2.0 * (textSizes.tickHeight + helper.getTickLabelPixelOffset()) / lastSize[1];
|
|
120
|
+
var titleHeight = 2.0 * (textSizes.titleHeight + helper.getAxisTitlePixelOffset()) / lastSize[1];
|
|
101
121
|
|
|
102
|
-
var _tickWidth = 2.0 * textSizes.tickWidth /
|
|
122
|
+
var _tickWidth = 2.0 * textSizes.tickWidth / lastSize[0];
|
|
103
123
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
boxSize[0] = Math.min(1.9, Math.max(1.4, 1.4 * _tickWidth * (helper.getTicks().length + 3)));
|
|
125
|
+
boxSize[1] = tickHeight + titleHeight;
|
|
126
|
+
helper.setBoxPosition([-0.5 * boxSize[0], -0.97]);
|
|
107
127
|
} // recomute bar segments based on positioning
|
|
108
128
|
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
helper.recomputeBarSegments(textSizes);
|
|
111
131
|
};
|
|
112
|
-
}
|
|
132
|
+
} // many properties of this actor depend on the API specific view The main
|
|
133
|
+
// dependency being the resolution as that drives what font sizes to use.
|
|
134
|
+
// Bacause of this we need to do some of the calculations in a API specific
|
|
135
|
+
// subclass. But... we don't want a lot of duplicated code between WebGL and
|
|
136
|
+
// WebGPU for example so we have this helper class, that is designed to be
|
|
137
|
+
// fairly API independent so that API specific views can call this to do
|
|
138
|
+
// most of the work.
|
|
113
139
|
|
|
114
|
-
|
|
140
|
+
|
|
141
|
+
function vtkScalarBarActorHelper(publicAPI, model) {
|
|
115
142
|
// Set our className
|
|
116
|
-
model.classHierarchy.push('
|
|
117
|
-
|
|
143
|
+
model.classHierarchy.push('vtkScalarBarActorHelper');
|
|
144
|
+
|
|
145
|
+
publicAPI.setRenderable = function (renderable) {
|
|
146
|
+
if (model.renderable === renderable) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
118
149
|
|
|
119
|
-
|
|
120
|
-
|
|
150
|
+
model.renderable = renderable;
|
|
151
|
+
model.barActor.setProperty(renderable.getProperty());
|
|
152
|
+
model.barActor.setParentProp(renderable);
|
|
153
|
+
model.tmActor.setProperty(renderable.getProperty());
|
|
154
|
+
model.tmActor.setParentProp(renderable);
|
|
155
|
+
model.axisTextStyle = _objectSpread({}, renderable.getAxisTextStyle());
|
|
156
|
+
model.tickTextStyle = _objectSpread({}, renderable.getTickTextStyle());
|
|
157
|
+
publicAPI.modified();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
publicAPI.updateAPISpecificData = function (size, camera, renderWindow) {
|
|
161
|
+
// has the size changed?
|
|
162
|
+
if (model.lastSize[0] !== size[0] || model.lastSize[1] !== size[1]) {
|
|
163
|
+
model.lastSize[0] = size[0];
|
|
164
|
+
model.lastSize[1] = size[1];
|
|
165
|
+
model.lastAspectRatio = size[0] / size[1];
|
|
166
|
+
model.forceUpdate = true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
var scalarsToColors = model.renderable.getScalarsToColors();
|
|
170
|
+
|
|
171
|
+
if (!scalarsToColors || !model.renderable.getVisibility()) {
|
|
121
172
|
return;
|
|
122
173
|
} // make sure the lut is assigned to our mapper
|
|
123
174
|
|
|
124
175
|
|
|
125
|
-
model.barMapper.setLookupTable(
|
|
176
|
+
model.barMapper.setLookupTable(scalarsToColors); // camera should be the same for all views
|
|
126
177
|
|
|
127
|
-
|
|
128
|
-
|
|
178
|
+
model.camera = camera;
|
|
179
|
+
model.renderWindow = renderWindow; // did something significant change? If so rebuild a lot of things
|
|
180
|
+
|
|
181
|
+
if (model.forceUpdate || Math.max(scalarsToColors.getMTime(), publicAPI.getMTime()) > model.lastRebuildTime.getMTime()) {
|
|
182
|
+
var range = scalarsToColors.getMappingRange();
|
|
129
183
|
model.lastTickBounds = _toConsumableArray(range);
|
|
130
184
|
model.barMapper.setScalarRange(model.lastTickBounds); // compute tick marks for axes (update for log scale)
|
|
131
185
|
|
|
132
186
|
var scale = d3.scaleLinear().domain([model.lastTickBounds[0], model.lastTickBounds[1]]);
|
|
133
187
|
model.ticks = scale.ticks(5);
|
|
134
188
|
var format = scale.tickFormat(5);
|
|
135
|
-
model.
|
|
189
|
+
model.tickstrings = model.ticks.map(format);
|
|
136
190
|
|
|
137
|
-
if (model.
|
|
138
|
-
model.
|
|
191
|
+
if (model.renderable.getAutomated()) {
|
|
192
|
+
model.renderable.getAutoLayout()(publicAPI);
|
|
139
193
|
} else {
|
|
140
|
-
//
|
|
194
|
+
// copy values from renderable
|
|
195
|
+
model.axisTextStyle = _objectSpread({}, model.renderable.getAxisTextStyle());
|
|
196
|
+
model.tickTextStyle = _objectSpread({}, model.renderable.getTickTextStyle());
|
|
197
|
+
model.barPosition = _toConsumableArray(model.renderable.getBarPosition());
|
|
198
|
+
model.barSize = _toConsumableArray(model.renderable.getBarSize());
|
|
199
|
+
model.boxPosition = _toConsumableArray(model.renderable.getBoxPosition());
|
|
200
|
+
model.boxSize = _toConsumableArray(model.renderable.getBoxSize());
|
|
201
|
+
model.axisTitlePixelOffset = model.renderable.getAxisTitlePixelOffset();
|
|
202
|
+
model.tickLabelPixelOffset = model.renderable.getTickLabelPixelOffset(); // rebuild the texture only when force or changed bounds, face
|
|
141
203
|
// visibility changes do to change the atlas
|
|
204
|
+
|
|
142
205
|
var textSizes = publicAPI.updateTextureAtlas(); // recompute bar segments based on positioning
|
|
143
206
|
|
|
144
207
|
publicAPI.recomputeBarSegments(textSizes);
|
|
@@ -171,7 +234,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
171
234
|
|
|
172
235
|
if (doUpdate) {
|
|
173
236
|
model.forceViewUpdate = true;
|
|
174
|
-
|
|
237
|
+
model.renderWindow.render();
|
|
175
238
|
}
|
|
176
239
|
}
|
|
177
240
|
}; // create the texture map atlas that contains the rendering of
|
|
@@ -191,14 +254,14 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
191
254
|
var totalHeight = 1; // start one pixel in so we have a border
|
|
192
255
|
|
|
193
256
|
applyTextStyle(model.tmContext, model.axisTextStyle);
|
|
194
|
-
var metrics = model.tmContext.measureText(model.
|
|
257
|
+
var metrics = model.tmContext.measureText(model.renderable.getAxisLabel());
|
|
195
258
|
var entry = {
|
|
196
259
|
height: metrics.actualBoundingBoxAscent + 2,
|
|
197
260
|
startingHeight: totalHeight,
|
|
198
261
|
width: metrics.width + 2,
|
|
199
262
|
textStyle: model.axisTextStyle
|
|
200
263
|
};
|
|
201
|
-
newTmAtlas.set(model.
|
|
264
|
+
newTmAtlas.set(model.renderable.getAxisLabel(), entry);
|
|
202
265
|
totalHeight += entry.height;
|
|
203
266
|
maxWidth = entry.width;
|
|
204
267
|
results.titleWidth = entry.width;
|
|
@@ -207,7 +270,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
207
270
|
results.tickWidth = 0;
|
|
208
271
|
results.tickHeight = 0;
|
|
209
272
|
applyTextStyle(model.tmContext, model.tickTextStyle);
|
|
210
|
-
var strings = [].concat(_toConsumableArray(model.
|
|
273
|
+
var strings = [].concat(_toConsumableArray(model.tickstrings), ['NaN', 'Below', 'Above']);
|
|
211
274
|
|
|
212
275
|
for (var t = 0; t < strings.length; t++) {
|
|
213
276
|
if (!newTmAtlas.has(strings[t])) {
|
|
@@ -319,7 +382,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
319
382
|
|
|
320
383
|
|
|
321
384
|
publicAPI.recomputeBarSegments = function (textSizes) {
|
|
322
|
-
var _model$
|
|
385
|
+
var _model$renderable$get, _model$renderable$get2, _model$renderable$get3, _model$renderable$get4;
|
|
323
386
|
|
|
324
387
|
// first compute the barSize/Position
|
|
325
388
|
var segSize = publicAPI.computeBarSize(textSizes);
|
|
@@ -339,22 +402,22 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
339
402
|
startPos[barAxis] += segSize[barAxis] + segSpace;
|
|
340
403
|
}
|
|
341
404
|
|
|
342
|
-
if (model.
|
|
405
|
+
if (model.renderable.getDrawNanAnnotation() && model.renderable.getScalarsToColors().getNanColor()) {
|
|
343
406
|
pushSeg('NaN', [NaN, NaN, NaN, NaN]);
|
|
344
407
|
}
|
|
345
408
|
|
|
346
|
-
if (model.
|
|
409
|
+
if (model.renderable.getDrawBelowRangeSwatch() && (_model$renderable$get = (_model$renderable$get2 = model.renderable.getScalarsToColors()).getUseBelowRangeColor) !== null && _model$renderable$get !== void 0 && _model$renderable$get.call(_model$renderable$get2)) {
|
|
347
410
|
pushSeg('Below', [-0.1, -0.1, -0.1, -0.1]);
|
|
348
411
|
}
|
|
349
412
|
|
|
350
|
-
var haveAbove = (_model$
|
|
413
|
+
var haveAbove = (_model$renderable$get3 = (_model$renderable$get4 = model.renderable.getScalarsToColors()).getUseAboveRangeColor) === null || _model$renderable$get3 === void 0 ? void 0 : _model$renderable$get3.call(_model$renderable$get4); // extra space around the ticks section
|
|
351
414
|
|
|
352
415
|
startPos[barAxis] += segSpace;
|
|
353
416
|
var oldSegSize = segSize[barAxis];
|
|
354
417
|
segSize[barAxis] = haveAbove ? 1.0 - 2.0 * segSpace - segSize[barAxis] - startPos[barAxis] : 1.0 - segSpace - startPos[barAxis];
|
|
355
418
|
pushSeg('ticks', model.vertical ? [0, 0, 0.995, 0.995] : [0, 0.995, 0.995, 0]);
|
|
356
419
|
|
|
357
|
-
if (model.
|
|
420
|
+
if (model.renderable.getDrawAboveRangeSwatch() && haveAbove) {
|
|
358
421
|
segSize[barAxis] = oldSegSize;
|
|
359
422
|
startPos[barAxis] += segSpace;
|
|
360
423
|
pushSeg('Above', [1.1, 1.1, 1.1, 1.1]);
|
|
@@ -464,7 +527,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
464
527
|
} // update the polydata
|
|
465
528
|
|
|
466
529
|
|
|
467
|
-
var numLabels = model.
|
|
530
|
+
var numLabels = model.tickstrings.length + model.barSegments.length;
|
|
468
531
|
var numPts = numLabels * 4;
|
|
469
532
|
var numTris = numLabels * 2;
|
|
470
533
|
var points = new Float64Array(numPts * 3);
|
|
@@ -489,14 +552,14 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
489
552
|
tmpv3[1] = model.barPosition[1] + model.barSize[1];
|
|
490
553
|
vec3.transformMat4(ptv3, tmpv3, invmat); // write the axis label
|
|
491
554
|
|
|
492
|
-
publicAPI.createPolyDataForOneLabel(model.
|
|
555
|
+
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, xDir, yDir, [0, 1], model.axisTitlePixelOffset, results);
|
|
493
556
|
} else {
|
|
494
557
|
tmpv3[0] = model.barPosition[0] + model.barSize[0];
|
|
495
558
|
tmpv3[1] = model.barPosition[1] + 0.5 * model.barSize[1];
|
|
496
559
|
vec3.transformMat4(ptv3, tmpv3, invmat); // write the axis label
|
|
497
560
|
|
|
498
561
|
vec3.scale(xDir, xDir, -1);
|
|
499
|
-
publicAPI.createPolyDataForOneLabel(model.
|
|
562
|
+
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, yDir, xDir, [0, -1], model.axisTitlePixelOffset, results);
|
|
500
563
|
vec3.scale(xDir, xDir, -1);
|
|
501
564
|
}
|
|
502
565
|
|
|
@@ -505,7 +568,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
505
568
|
tmpv3[0] = model.barPosition[0] + 0.5 * model.barSize[0];
|
|
506
569
|
tmpv3[1] = model.barPosition[1] + model.barSize[1];
|
|
507
570
|
vec3.transformMat4(ptv3, tmpv3, invmat);
|
|
508
|
-
publicAPI.createPolyDataForOneLabel(model.
|
|
571
|
+
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, xDir, yDir, dir, model.axisTitlePixelOffset, results);
|
|
509
572
|
}
|
|
510
573
|
|
|
511
574
|
tmp2v3[2] = -0.99; // near plane
|
|
@@ -536,7 +599,7 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
536
599
|
var tickPos = (model.ticks[t] - model.lastTickBounds[0]) / (model.lastTickBounds[1] - model.lastTickBounds[0]);
|
|
537
600
|
tmp2v3[spacedAxis] = tickSegmentStart + tickSegmentSize * tickPos;
|
|
538
601
|
vec3.transformMat4(ptv3, tmp2v3, invmat);
|
|
539
|
-
publicAPI.createPolyDataForOneLabel(model.
|
|
602
|
+
publicAPI.createPolyDataForOneLabel(model.tickstrings[t], ptv3, xDir, yDir, dir, model.tickLabelPixelOffset, results);
|
|
540
603
|
}
|
|
541
604
|
|
|
542
605
|
var tcoordDA = vtkDataArray.newInstance({
|
|
@@ -553,22 +616,23 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
553
616
|
};
|
|
554
617
|
|
|
555
618
|
publicAPI.updatePolyDataForBarSegments = function () {
|
|
556
|
-
var
|
|
619
|
+
var _scalarsToColors$getU, _scalarsToColors$getU2;
|
|
557
620
|
|
|
558
621
|
var cmat = model.camera.getCompositeProjectionMatrix(model.lastAspectRatio, -1, 1);
|
|
559
622
|
mat4.transpose(cmat, cmat);
|
|
560
623
|
mat4.invert(invmat, cmat);
|
|
624
|
+
var scalarsToColors = model.renderable.getScalarsToColors();
|
|
561
625
|
var numberOfExtraColors = 0;
|
|
562
626
|
|
|
563
|
-
if (model.
|
|
627
|
+
if (model.renderable.getDrawNanAnnotation() && scalarsToColors.getNanColor()) {
|
|
564
628
|
numberOfExtraColors += 1;
|
|
565
629
|
}
|
|
566
630
|
|
|
567
|
-
if (model.
|
|
631
|
+
if (model.renderable.getDrawBelowRangeSwatch() && (_scalarsToColors$getU = scalarsToColors.getUseBelowRangeColor) !== null && _scalarsToColors$getU !== void 0 && _scalarsToColors$getU.call(scalarsToColors)) {
|
|
568
632
|
numberOfExtraColors += 1;
|
|
569
633
|
}
|
|
570
634
|
|
|
571
|
-
if (model.
|
|
635
|
+
if (model.renderable.getDrawAboveRangeSwatch() && (_scalarsToColors$getU2 = scalarsToColors.getUseAboveRangeColor) !== null && _scalarsToColors$getU2 !== void 0 && _scalarsToColors$getU2.call(scalarsToColors)) {
|
|
572
636
|
numberOfExtraColors += 1;
|
|
573
637
|
}
|
|
574
638
|
|
|
@@ -577,8 +641,8 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
577
641
|
|
|
578
642
|
var numComps = 1;
|
|
579
643
|
|
|
580
|
-
if (
|
|
581
|
-
numComps =
|
|
644
|
+
if (scalarsToColors.getVectorMode() === VectorMode.COMPONENT) {
|
|
645
|
+
numComps = scalarsToColors.getVectorComponent() + 1;
|
|
582
646
|
} // create the colored bars
|
|
583
647
|
|
|
584
648
|
|
|
@@ -628,14 +692,66 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
628
692
|
model.polyData.getPolys().modified();
|
|
629
693
|
model.polyData.modified();
|
|
630
694
|
};
|
|
695
|
+
}
|
|
631
696
|
|
|
632
|
-
|
|
633
|
-
|
|
697
|
+
var newScalarBarActorHelper = macro.newInstance(function (publicAPI, model) {
|
|
698
|
+
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
699
|
+
renderable: null
|
|
634
700
|
};
|
|
701
|
+
Object.assign(model, {}, initialValues); // Inheritance
|
|
635
702
|
|
|
636
|
-
publicAPI
|
|
637
|
-
|
|
638
|
-
|
|
703
|
+
macro.obj(publicAPI, model);
|
|
704
|
+
macro.setGet(publicAPI, model, ['axisTitlePixelOffset', 'tickLabelPixelOffset', 'renderable', 'topTitle']);
|
|
705
|
+
macro.get(publicAPI, model, ['lastSize', 'lastAspectRatio', 'axisTextStyle', 'tickTextStyle', 'barActor', 'tmActor', 'ticks']);
|
|
706
|
+
macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
|
|
707
|
+
macro.setArray(publicAPI, model, ['boxPosition', 'boxSize'], 2);
|
|
708
|
+
model.forceUpdate = false;
|
|
709
|
+
model.lastRedrawTime = {};
|
|
710
|
+
macro.obj(model.lastRedrawTime, {
|
|
711
|
+
mtime: 0
|
|
712
|
+
});
|
|
713
|
+
model.lastRebuildTime = {};
|
|
714
|
+
macro.obj(model.lastRebuildTime, {
|
|
715
|
+
mtime: 0
|
|
716
|
+
});
|
|
717
|
+
model.lastSize = [-1, -1];
|
|
718
|
+
model.tmCanvas = document.createElement('canvas');
|
|
719
|
+
model.tmContext = model.tmCanvas.getContext('2d');
|
|
720
|
+
model._tmAtlas = new Map();
|
|
721
|
+
model.barMapper = vtkMapper.newInstance();
|
|
722
|
+
model.barMapper.setInterpolateScalarsBeforeMapping(true);
|
|
723
|
+
model.polyData = vtkPolyData.newInstance();
|
|
724
|
+
model.barMapper.setInputData(model.polyData);
|
|
725
|
+
model.barActor = vtkActor.newInstance();
|
|
726
|
+
model.barActor.setMapper(model.barMapper); // for texture atlas
|
|
727
|
+
|
|
728
|
+
model.tmPolyData = vtkPolyData.newInstance();
|
|
729
|
+
model.tmMapper = vtkMapper.newInstance();
|
|
730
|
+
model.tmMapper.setInputData(model.tmPolyData);
|
|
731
|
+
model.tmTexture = vtkTexture.newInstance();
|
|
732
|
+
model.tmTexture.setInterpolate(false);
|
|
733
|
+
model.tmActor = vtkActor.newInstance({
|
|
734
|
+
parentProp: publicAPI
|
|
735
|
+
});
|
|
736
|
+
model.tmActor.setMapper(model.tmMapper);
|
|
737
|
+
model.tmActor.addTexture(model.tmTexture);
|
|
738
|
+
model.barPosition = [0, 0];
|
|
739
|
+
model.barSize = [0, 0];
|
|
740
|
+
model.boxPosition = [0.88, -0.92];
|
|
741
|
+
model.boxSize = [0.1, 1.1]; // internal variables
|
|
742
|
+
|
|
743
|
+
model.lastTickBounds = [];
|
|
744
|
+
vtkScalarBarActorHelper(publicAPI, model);
|
|
745
|
+
}, 'vtkScalarBarActorHelper'); //
|
|
746
|
+
// Now we define the public class that the application sets view independent
|
|
747
|
+
// properties on. This class is fairly small as it mainly just holds
|
|
748
|
+
// properties setter and getters leaving all calculations to the helper
|
|
749
|
+
// class.
|
|
750
|
+
//
|
|
751
|
+
|
|
752
|
+
function vtkScalarBarActor(publicAPI, model) {
|
|
753
|
+
// Set our className
|
|
754
|
+
model.classHierarchy.push('vtkScalarBarActor');
|
|
639
755
|
|
|
640
756
|
publicAPI.setTickTextStyle = function (tickStyle) {
|
|
641
757
|
model.tickTextStyle = _objectSpread(_objectSpread({}, model.tickTextStyle), tickStyle);
|
|
@@ -647,12 +763,6 @@ function vtkScalarBarActor(publicAPI, model) {
|
|
|
647
763
|
publicAPI.modified();
|
|
648
764
|
};
|
|
649
765
|
|
|
650
|
-
var setVisibility = macro.chain(publicAPI.setVisibility, model.barActor.setVisibility, model.tmActor.setVisibility);
|
|
651
|
-
|
|
652
|
-
publicAPI.setVisibility = function () {
|
|
653
|
-
return setVisibility.apply(void 0, arguments).some(Boolean);
|
|
654
|
-
};
|
|
655
|
-
|
|
656
766
|
publicAPI.resetAutoLayoutToDefault = function () {
|
|
657
767
|
model.autoLayout = defaultAutoLayout(publicAPI, model);
|
|
658
768
|
};
|
|
@@ -700,64 +810,6 @@ function extend(publicAPI, model) {
|
|
|
700
810
|
vtkActor.extend(publicAPI, model, initialValues);
|
|
701
811
|
publicAPI.getProperty().setDiffuse(0.0);
|
|
702
812
|
publicAPI.getProperty().setAmbient(1.0);
|
|
703
|
-
model._tmAtlas = new Map(); // internal variables
|
|
704
|
-
|
|
705
|
-
model.lastSize = [800, 800];
|
|
706
|
-
model.lastAspectRatio = 1.0;
|
|
707
|
-
model.textValues = [];
|
|
708
|
-
model.lastTickBounds = [];
|
|
709
|
-
model.barMapper = vtkMapper.newInstance();
|
|
710
|
-
model.barMapper.setInterpolateScalarsBeforeMapping(true);
|
|
711
|
-
model.polyData = vtkPolyData.newInstance();
|
|
712
|
-
model.barMapper.setInputData(model.polyData);
|
|
713
|
-
model.barActor = vtkActor.newInstance({
|
|
714
|
-
parentProp: publicAPI
|
|
715
|
-
});
|
|
716
|
-
model.barActor.setMapper(model.barMapper);
|
|
717
|
-
model.barActor.setProperty(publicAPI.getProperty());
|
|
718
|
-
model.lastRedrawTime = {};
|
|
719
|
-
macro.obj(model.lastRedrawTime, {
|
|
720
|
-
mtime: 0
|
|
721
|
-
});
|
|
722
|
-
model.lastRebuildTime = {};
|
|
723
|
-
macro.obj(model.lastRebuildTime, {
|
|
724
|
-
mtime: 0
|
|
725
|
-
});
|
|
726
|
-
model.textPolyData = vtkPolyData.newInstance(); // for texture atlas
|
|
727
|
-
|
|
728
|
-
model.tmPolyData = vtkPolyData.newInstance();
|
|
729
|
-
model.tmMapper = vtkMapper.newInstance();
|
|
730
|
-
model.tmMapper.setInputData(model.tmPolyData);
|
|
731
|
-
model.tmTexture = vtkTexture.newInstance();
|
|
732
|
-
model.tmTexture.setInterpolate(false);
|
|
733
|
-
model.tmActor = vtkActor.newInstance({
|
|
734
|
-
parentProp: publicAPI
|
|
735
|
-
});
|
|
736
|
-
model.tmActor.setMapper(model.tmMapper);
|
|
737
|
-
model.tmActor.addTexture(model.tmTexture);
|
|
738
|
-
model.tmActor.setProperty(publicAPI.getProperty());
|
|
739
|
-
model.tmCanvas = document.createElement('canvas');
|
|
740
|
-
model.tmContext = model.tmCanvas.getContext('2d'); // PixelSpaceCallbackMapper - we do need an empty polydata
|
|
741
|
-
// really just used to get the window size which we need to do
|
|
742
|
-
// proper text positioning and scaling.
|
|
743
|
-
|
|
744
|
-
model.mapper = vtkPixelSpaceCallbackMapper.newInstance();
|
|
745
|
-
model.pixelMapperPolyData = vtkPolyData.newInstance();
|
|
746
|
-
model.mapper.setInputData(model.pixelMapperPolyData);
|
|
747
|
-
model.mapper.setCallback(function (coords, camera, aspect, depthValues, size) {
|
|
748
|
-
model.camera = camera;
|
|
749
|
-
|
|
750
|
-
if (model.lastSize[0] !== size[0] || model.lastSize[1] !== size[1]) {
|
|
751
|
-
model.lastSize[0] = size[0];
|
|
752
|
-
model.lastSize[1] = size[1];
|
|
753
|
-
model.lastAspectRatio = size[0] / size[1]; // we could use modified, but really the public state is not
|
|
754
|
-
// modified
|
|
755
|
-
|
|
756
|
-
model.forceUpdate = true;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
publicAPI.update();
|
|
760
|
-
});
|
|
761
813
|
macro.setGet(publicAPI, model, ['automated', 'autoLayout', 'axisTitlePixelOffset', 'axisLabel', 'scalarsToColors', 'tickLabelPixelOffset', 'drawNanAnnotation', 'drawBelowRangeSwatch', 'drawAboveRangeSwatch']);
|
|
762
814
|
macro.get(publicAPI, model, ['axisTextStyle', 'tickTextStyle']);
|
|
763
815
|
macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
|
|
@@ -770,7 +822,8 @@ var newInstance = macro.newInstance(extend, 'vtkScalarBarActor'); // -----------
|
|
|
770
822
|
|
|
771
823
|
var vtkScalarBarActor$1 = {
|
|
772
824
|
newInstance: newInstance,
|
|
773
|
-
extend: extend
|
|
825
|
+
extend: extend,
|
|
826
|
+
newScalarBarActorHelper: newScalarBarActorHelper
|
|
774
827
|
};
|
|
775
828
|
|
|
776
829
|
export { vtkScalarBarActor$1 as default, extend, newInstance };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { newInstance as newInstance$1 } from '../../macros.js';
|
|
2
|
+
import vtkScalarBarActor from '../Core/ScalarBarActor.js';
|
|
3
|
+
import vtkViewNode from '../SceneGraph/ViewNode.js';
|
|
4
|
+
import { registerOverride } from './ViewNodeFactory.js';
|
|
5
|
+
|
|
6
|
+
// vtkOpenGLScalarBarActor methods
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
function vtkOpenGLScalarBarActor(publicAPI, model) {
|
|
10
|
+
model.classHierarchy.push('vtkOpenGLScalarBarActor'); // Builds myself.
|
|
11
|
+
|
|
12
|
+
publicAPI.buildPass = function (prepass) {
|
|
13
|
+
if (prepass) {
|
|
14
|
+
model.openGLRenderer = publicAPI.getFirstAncestorOfType('vtkOpenGLRenderer');
|
|
15
|
+
model.openGLRenderWindow = model.openGLRenderer.getParent();
|
|
16
|
+
|
|
17
|
+
if (!model.scalarBarActorHelper.getRenderable()) {
|
|
18
|
+
model.scalarBarActorHelper.setRenderable(model.renderable);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
publicAPI.prepareNodes();
|
|
22
|
+
publicAPI.addMissingNode(model.scalarBarActorHelper.getBarActor());
|
|
23
|
+
publicAPI.addMissingNode(model.scalarBarActorHelper.getTmActor());
|
|
24
|
+
publicAPI.removeUnusedNodes();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
publicAPI.opaquePass = function (prepass, renderPass) {
|
|
29
|
+
if (prepass) {
|
|
30
|
+
var camera = model.openGLRenderer ? model.openGLRenderer.getRenderable().getActiveCamera() : null;
|
|
31
|
+
var tsize = model.openGLRenderer.getTiledSizeAndOrigin();
|
|
32
|
+
model.scalarBarActorHelper.updateAPISpecificData([tsize.usize, tsize.vsize], camera, model.openGLRenderWindow.getRenderable());
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
} // ----------------------------------------------------------------------------
|
|
36
|
+
// Object factory
|
|
37
|
+
// ----------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
function extend(publicAPI, model) {
|
|
43
|
+
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
44
|
+
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
|
|
45
|
+
|
|
46
|
+
vtkViewNode.extend(publicAPI, model, initialValues);
|
|
47
|
+
model.scalarBarActorHelper = vtkScalarBarActor.newScalarBarActorHelper(); // Object methods
|
|
48
|
+
|
|
49
|
+
vtkOpenGLScalarBarActor(publicAPI, model);
|
|
50
|
+
} // ----------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
var newInstance = newInstance$1(extend, 'vtkOpenGLScalarBarActor'); // ----------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
var index = {
|
|
55
|
+
newInstance: newInstance,
|
|
56
|
+
extend: extend
|
|
57
|
+
}; // Register ourself to OpenGL backend if imported
|
|
58
|
+
|
|
59
|
+
registerOverride('vtkScalarBarActor', newInstance);
|
|
60
|
+
|
|
61
|
+
export { index as default, extend, newInstance };
|
|
@@ -4,6 +4,7 @@ import '../OpenGL/Actor.js';
|
|
|
4
4
|
import '../OpenGL/Actor2D.js';
|
|
5
5
|
import '../OpenGL/PolyDataMapper.js';
|
|
6
6
|
import '../OpenGL/PolyDataMapper2D.js';
|
|
7
|
+
import '../OpenGL/ScalarBarActor.js';
|
|
7
8
|
import '../OpenGL/Skybox.js';
|
|
8
9
|
import '../OpenGL/Texture.js';
|
|
9
10
|
import '../OpenGL/Glyph3DMapper.js';
|
|
@@ -19,6 +20,7 @@ import '../WebGPU/Camera.js';
|
|
|
19
20
|
import '../WebGPU/Renderer.js';
|
|
20
21
|
import '../WebGPU/Actor.js';
|
|
21
22
|
import '../WebGPU/PolyDataMapper.js';
|
|
23
|
+
import '../WebGPU/ScalarBarActor.js';
|
|
22
24
|
import '../WebGPU/Texture.js';
|
|
23
25
|
import '../WebGPU/Glyph3DMapper.js';
|
|
24
26
|
import '../WebGPU/ImageMapper.js';
|
|
@@ -4,6 +4,7 @@ import '../OpenGL/Actor.js';
|
|
|
4
4
|
import '../OpenGL/Actor2D.js';
|
|
5
5
|
import '../OpenGL/PolyDataMapper.js';
|
|
6
6
|
import '../OpenGL/PolyDataMapper2D.js';
|
|
7
|
+
import '../OpenGL/ScalarBarActor.js';
|
|
7
8
|
import '../OpenGL/Skybox.js';
|
|
8
9
|
import '../OpenGL/Texture.js';
|
|
9
10
|
import '../OpenGL/PixelSpaceCallbackMapper.js';
|
|
@@ -11,5 +12,6 @@ import '../WebGPU/Camera.js';
|
|
|
11
12
|
import '../WebGPU/Renderer.js';
|
|
12
13
|
import '../WebGPU/Actor.js';
|
|
13
14
|
import '../WebGPU/PolyDataMapper.js';
|
|
15
|
+
import '../WebGPU/ScalarBarActor.js';
|
|
14
16
|
import '../WebGPU/Texture.js';
|
|
15
17
|
import '../WebGPU/PixelSpaceCallbackMapper.js';
|
|
@@ -84,8 +84,8 @@ function vtkWebGPUHardwareSelectionPass(publicAPI, model) {
|
|
|
84
84
|
fDesc.setCode(code);
|
|
85
85
|
});
|
|
86
86
|
var renDesc = model.selectionRenderEncoder.getDescription();
|
|
87
|
-
renDesc.colorAttachments[0].
|
|
88
|
-
renDesc.depthStencilAttachment.
|
|
87
|
+
renDesc.colorAttachments[0].clearValue = [0.0, 0.0, 0.0, 0.0];
|
|
88
|
+
renDesc.depthStencilAttachment.stencilLoadOp = 'load';
|
|
89
89
|
model.selectionRenderEncoder.setPipelineSettings({
|
|
90
90
|
primitive: {
|
|
91
91
|
cullMode: 'none'
|
|
@@ -96,18 +96,20 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
|
|
|
96
96
|
var rDesc = model.translucentRenderEncoder.getDescription();
|
|
97
97
|
rDesc.colorAttachments = [{
|
|
98
98
|
view: undefined,
|
|
99
|
-
|
|
99
|
+
clearValue: [0.0, 0.0, 0.0, 0.0],
|
|
100
|
+
loadOp: 'clear',
|
|
100
101
|
storeOp: 'store'
|
|
101
102
|
}, {
|
|
102
103
|
view: undefined,
|
|
103
|
-
|
|
104
|
+
clearValue: [1.0, 0.0, 0.0, 0.0],
|
|
105
|
+
loadOp: 'clear',
|
|
104
106
|
storeOp: 'store'
|
|
105
107
|
}];
|
|
106
108
|
rDesc.depthStencilAttachment = {
|
|
107
109
|
view: undefined,
|
|
108
|
-
|
|
110
|
+
depthLoadOp: 'load',
|
|
109
111
|
depthStoreOp: 'store',
|
|
110
|
-
|
|
112
|
+
stencilLoadOp: 'load',
|
|
111
113
|
stencilStoreOp: 'store'
|
|
112
114
|
};
|
|
113
115
|
model.translucentRenderEncoder.setReplaceShaderCodeFunction(function (pipeline) {
|
|
@@ -167,7 +169,7 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
|
|
|
167
169
|
model.translucentFinalEncoder.setDescription({
|
|
168
170
|
colorAttachments: [{
|
|
169
171
|
view: null,
|
|
170
|
-
|
|
172
|
+
loadOp: 'load',
|
|
171
173
|
storeOp: 'store'
|
|
172
174
|
}]
|
|
173
175
|
});
|
|
@@ -138,14 +138,16 @@ function extend(publicAPI, model) {
|
|
|
138
138
|
model.description = {
|
|
139
139
|
colorAttachments: [{
|
|
140
140
|
view: undefined,
|
|
141
|
-
|
|
141
|
+
loadOp: 'load',
|
|
142
142
|
storeOp: 'store'
|
|
143
143
|
}],
|
|
144
144
|
depthStencilAttachment: {
|
|
145
145
|
view: undefined,
|
|
146
|
-
|
|
146
|
+
depthLoadOp: 'clear',
|
|
147
|
+
depthClearValue: 0.0,
|
|
147
148
|
depthStoreOp: 'store',
|
|
148
|
-
|
|
149
|
+
stencilLoadOp: 'clear',
|
|
150
|
+
stencilClearValue: 0,
|
|
149
151
|
stencilStoreOp: 'store'
|
|
150
152
|
}
|
|
151
153
|
}; // default shader code just writes out the computedColor
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { newInstance as newInstance$1 } from '../../macros.js';
|
|
2
|
+
import vtkScalarBarActor from '../Core/ScalarBarActor.js';
|
|
3
|
+
import vtkViewNode from '../SceneGraph/ViewNode.js';
|
|
4
|
+
import { registerOverride } from './ViewNodeFactory.js';
|
|
5
|
+
|
|
6
|
+
// vtkWebGPUScalarBarActor methods
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
function vtkWebGPUScalarBarActor(publicAPI, model) {
|
|
10
|
+
model.classHierarchy.push('vtkWebGPUScalarBarActor'); // Builds myself.
|
|
11
|
+
|
|
12
|
+
publicAPI.buildPass = function (prepass) {
|
|
13
|
+
if (prepass) {
|
|
14
|
+
model.WebGPURenderer = publicAPI.getFirstAncestorOfType('vtkWebGPURenderer');
|
|
15
|
+
model.WebGPURenderWindow = model.WebGPURenderer.getParent();
|
|
16
|
+
|
|
17
|
+
if (!model.scalarBarActorHelper.getRenderable()) {
|
|
18
|
+
model.scalarBarActorHelper.setRenderable(model.renderable);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
publicAPI.prepareNodes();
|
|
22
|
+
publicAPI.addMissingNode(model.scalarBarActorHelper.getBarActor());
|
|
23
|
+
publicAPI.addMissingNode(model.scalarBarActorHelper.getTmActor());
|
|
24
|
+
publicAPI.removeUnusedNodes();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
publicAPI.opaquePass = function (prepass, renderPass) {
|
|
29
|
+
if (prepass) {
|
|
30
|
+
var camera = model.WebGPURenderer ? model.WebGPURenderer.getRenderable().getActiveCamera() : null;
|
|
31
|
+
var tsize = model.WebGPURenderer.getTiledSizeAndOrigin();
|
|
32
|
+
model.scalarBarActorHelper.updateAPISpecificData([tsize.usize, tsize.vsize], camera, model.WebGPURenderWindow.getRenderable());
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
} // ----------------------------------------------------------------------------
|
|
36
|
+
// Object factory
|
|
37
|
+
// ----------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
function extend(publicAPI, model) {
|
|
43
|
+
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
44
|
+
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
|
|
45
|
+
|
|
46
|
+
vtkViewNode.extend(publicAPI, model, initialValues);
|
|
47
|
+
model.scalarBarActorHelper = vtkScalarBarActor.newScalarBarActorHelper(); // Object methods
|
|
48
|
+
|
|
49
|
+
vtkWebGPUScalarBarActor(publicAPI, model);
|
|
50
|
+
} // ----------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
var newInstance = newInstance$1(extend, 'vtkWebGPUScalarBarActor'); // ----------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
var index = {
|
|
55
|
+
newInstance: newInstance,
|
|
56
|
+
extend: extend
|
|
57
|
+
}; // Register ourself to WebGPU backend if imported
|
|
58
|
+
|
|
59
|
+
registerOverride('vtkScalarBarActor', newInstance);
|
|
60
|
+
|
|
61
|
+
export { index as default, extend, newInstance };
|
|
@@ -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) {
|
|
@@ -384,11 +390,13 @@ function vtkWebGPUVolumePass(publicAPI, model) {
|
|
|
384
390
|
model._depthRangeEncoder.setDescription({
|
|
385
391
|
colorAttachments: [{
|
|
386
392
|
view: null,
|
|
387
|
-
|
|
393
|
+
clearValue: [0.0, 0.0, 0.0, 0.0],
|
|
394
|
+
loadOp: 'clear',
|
|
388
395
|
storeOp: 'store'
|
|
389
396
|
}, {
|
|
390
397
|
view: null,
|
|
391
|
-
|
|
398
|
+
clearValue: [1.0, 1.0, 1.0, 1.0],
|
|
399
|
+
loadOp: 'clear',
|
|
392
400
|
storeOp: 'store'
|
|
393
401
|
}]
|
|
394
402
|
});
|
|
@@ -498,7 +506,8 @@ function vtkWebGPUVolumePass(publicAPI, model) {
|
|
|
498
506
|
model._clearEncoder.setDescription({
|
|
499
507
|
colorAttachments: [{
|
|
500
508
|
view: null,
|
|
501
|
-
|
|
509
|
+
clearValue: [0.0, 0.0, 0.0, 0.0],
|
|
510
|
+
loadOp: 'clear',
|
|
502
511
|
storeOp: 'store'
|
|
503
512
|
}]
|
|
504
513
|
});
|
|
@@ -535,7 +544,7 @@ function vtkWebGPUVolumePass(publicAPI, model) {
|
|
|
535
544
|
model._copyEncoder.setDescription({
|
|
536
545
|
colorAttachments: [{
|
|
537
546
|
view: null,
|
|
538
|
-
|
|
547
|
+
loadOp: 'load',
|
|
539
548
|
storeOp: 'store'
|
|
540
549
|
}]
|
|
541
550
|
});
|
|
@@ -574,7 +583,7 @@ function vtkWebGPUVolumePass(publicAPI, model) {
|
|
|
574
583
|
model._mergeEncoder.setDescription({
|
|
575
584
|
colorAttachments: [{
|
|
576
585
|
view: null,
|
|
577
|
-
|
|
586
|
+
loadOp: 'load',
|
|
578
587
|
storeOp: 'store'
|
|
579
588
|
}]
|
|
580
589
|
});
|
|
@@ -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
|
|
@@ -240,7 +240,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
240
240
|
//
|
|
241
241
|
|
|
242
242
|
var marray = new Float64Array(model.volumes.length * 16);
|
|
243
|
+
var vPlaneArray = new Float64Array(model.volumes.length * 16);
|
|
243
244
|
var tstepArray = new Float64Array(model.volumes.length * 4);
|
|
245
|
+
var shadeArray = new Float64Array(model.volumes.length * 4);
|
|
244
246
|
var spacingArray = new Float64Array(model.volumes.length * 4);
|
|
245
247
|
var ipScalarRangeArray = new Float64Array(model.volumes.length * 4);
|
|
246
248
|
|
|
@@ -277,10 +279,20 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
277
279
|
marray[vidx * 16 + j] = tmpMat4[j];
|
|
278
280
|
}
|
|
279
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
|
+
|
|
280
291
|
tstepArray[vidx * 4] = 1.0 / dims[0];
|
|
281
292
|
tstepArray[vidx * 4 + 1] = 1.0 / dims[1];
|
|
282
293
|
tstepArray[vidx * 4 + 2] = 1.0 / dims[2];
|
|
283
294
|
tstepArray[vidx * 4 + 3] = 1.0;
|
|
295
|
+
shadeArray[vidx * 4] = actor.getProperty().getShade() ? 1.0 : 0.0;
|
|
284
296
|
|
|
285
297
|
var spacing = _image3.getSpacing();
|
|
286
298
|
|
|
@@ -299,10 +311,14 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
299
311
|
}
|
|
300
312
|
|
|
301
313
|
model.SSBO.addEntry('SCTCMatrix', 'mat4x4<f32>');
|
|
314
|
+
model.SSBO.addEntry('planeNormals', 'mat4x4<f32>');
|
|
315
|
+
model.SSBO.addEntry('shade', 'vec4<f32>');
|
|
302
316
|
model.SSBO.addEntry('tstep', 'vec4<f32>');
|
|
303
317
|
model.SSBO.addEntry('spacing', 'vec4<f32>');
|
|
304
318
|
model.SSBO.addEntry('ipScalarRange', 'vec4<f32>');
|
|
305
319
|
model.SSBO.setAllInstancesFromArray('SCTCMatrix', marray);
|
|
320
|
+
model.SSBO.setAllInstancesFromArray('planeNormals', vPlaneArray);
|
|
321
|
+
model.SSBO.setAllInstancesFromArray('shade', shadeArray);
|
|
306
322
|
model.SSBO.setAllInstancesFromArray('tstep', tstepArray);
|
|
307
323
|
model.SSBO.setAllInstancesFromArray('spacing', spacingArray);
|
|
308
324
|
model.SSBO.setAllInstancesFromArray('ipScalarRange', ipScalarRangeArray);
|
|
@@ -388,7 +388,7 @@ function widgetBehavior(publicAPI, model) {
|
|
|
388
388
|
publicAPI.invokeInteractionEvent();
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
return model.hasFocus ? macro.EVENT_ABORT : macro.VOID;
|
|
391
|
+
return model.hasFocus || model.isDragging ? macro.EVENT_ABORT : macro.VOID;
|
|
392
392
|
}; // --------------------------------------------------------------------------
|
|
393
393
|
// Left click: Add point / End interaction
|
|
394
394
|
// --------------------------------------------------------------------------
|