@kitware/vtk.js 24.14.3 → 24.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Rendering/Core/Camera.js +0 -3
- package/Rendering/Core/RenderWindowInteractor.d.ts +63 -17
- package/Rendering/Core/RenderWindowInteractor.js +225 -170
- package/Rendering/Core/VolumeMapper.js +4 -3
- package/Rendering/OpenGL/VolumeMapper.js +5 -0
- package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
- package/package.json +1 -1
package/Rendering/Core/Camera.js
CHANGED
|
@@ -61,7 +61,6 @@ function vtkCamera(publicAPI, model) {
|
|
|
61
61
|
model.position[2] = z; // recompute the focal distance
|
|
62
62
|
|
|
63
63
|
publicAPI.computeDistance();
|
|
64
|
-
publicAPI.computeCameraLightTransform();
|
|
65
64
|
publicAPI.modified();
|
|
66
65
|
};
|
|
67
66
|
|
|
@@ -75,7 +74,6 @@ function vtkCamera(publicAPI, model) {
|
|
|
75
74
|
model.focalPoint[2] = z; // recompute the focal distance
|
|
76
75
|
|
|
77
76
|
publicAPI.computeDistance();
|
|
78
|
-
publicAPI.computeCameraLightTransform();
|
|
79
77
|
publicAPI.modified();
|
|
80
78
|
};
|
|
81
79
|
|
|
@@ -97,7 +95,6 @@ function vtkCamera(publicAPI, model) {
|
|
|
97
95
|
model.focalPoint[0] = model.position[0] + vec[0] * model.distance;
|
|
98
96
|
model.focalPoint[1] = model.position[1] + vec[1] * model.distance;
|
|
99
97
|
model.focalPoint[2] = model.position[2] + vec[2] * model.distance;
|
|
100
|
-
publicAPI.computeCameraLightTransform();
|
|
101
98
|
publicAPI.modified();
|
|
102
99
|
}; //----------------------------------------------------------------------------
|
|
103
100
|
// This method must be called when the focal point or camera position changes
|
|
@@ -173,6 +173,16 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
173
173
|
*
|
|
174
174
|
* @param {IRenderWindowInteractorEvent} callData
|
|
175
175
|
*/
|
|
176
|
+
invokePointerEnter(callData: IRenderWindowInteractorEvent): void;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
*
|
|
180
|
+
*/
|
|
181
|
+
invokePointerLeave(callData: IRenderWindowInteractorEvent): void;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
*
|
|
185
|
+
*/
|
|
176
186
|
invokeMouseEnter(callData: IRenderWindowInteractorEvent): void;
|
|
177
187
|
|
|
178
188
|
/**
|
|
@@ -392,6 +402,18 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
392
402
|
* @param {InteractorEventCallback} cb The callback to be called.
|
|
393
403
|
* @param {Number} [priority] The priority of the event.
|
|
394
404
|
*/
|
|
405
|
+
onPointerEnter(cb: InteractorEventCallback, priority?: number): Readonly<vtkSubscription>;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
*
|
|
409
|
+
* @param cb The callback to be called
|
|
410
|
+
*/
|
|
411
|
+
onPointerLeave(cb: InteractorEventCallback, priority?: number): Readonly<vtkSubscription>;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
*
|
|
415
|
+
* @param cb The callback to be called
|
|
416
|
+
*/
|
|
395
417
|
onMouseEnter(cb: InteractorEventCallback, priority?: number): Readonly<vtkSubscription>;
|
|
396
418
|
|
|
397
419
|
/**
|
|
@@ -949,11 +971,35 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
949
971
|
*/
|
|
950
972
|
handleKeyUp(event: KeyboardEvent): void;
|
|
951
973
|
|
|
974
|
+
/**
|
|
975
|
+
*
|
|
976
|
+
* @param {PointerEvent} event
|
|
977
|
+
*/
|
|
978
|
+
handlePointerDown(event: PointerEvent): void;
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
*
|
|
982
|
+
* @param {PointerEvent} event
|
|
983
|
+
*/
|
|
984
|
+
handlePointerUp(event: PointerEvent): void;
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
*
|
|
988
|
+
* @param {PointerEvent} event
|
|
989
|
+
*/
|
|
990
|
+
handlePointerCancel(event: PointerEvent): void;
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
*
|
|
994
|
+
* @param {PointerEvent} event
|
|
995
|
+
*/
|
|
996
|
+
handlePointerMove(event: PointerEvent): void;
|
|
997
|
+
|
|
952
998
|
/**
|
|
953
999
|
*
|
|
954
|
-
* @param {
|
|
1000
|
+
* @param {PointerEvent} event
|
|
955
1001
|
*/
|
|
956
|
-
handleMouseDown(event:
|
|
1002
|
+
handleMouseDown(event: PointerEvent): void;
|
|
957
1003
|
|
|
958
1004
|
/**
|
|
959
1005
|
*
|
|
@@ -1011,9 +1057,9 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
1011
1057
|
|
|
1012
1058
|
/**
|
|
1013
1059
|
*
|
|
1014
|
-
* @param {
|
|
1060
|
+
* @param {PointerEvent} event
|
|
1015
1061
|
*/
|
|
1016
|
-
handleMouseMove(event:
|
|
1062
|
+
handleMouseMove(event: PointerEvent): void;
|
|
1017
1063
|
|
|
1018
1064
|
/**
|
|
1019
1065
|
*
|
|
@@ -1028,39 +1074,39 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
1028
1074
|
|
|
1029
1075
|
/**
|
|
1030
1076
|
*
|
|
1031
|
-
* @param {
|
|
1077
|
+
* @param {PointerEvent} event
|
|
1032
1078
|
*/
|
|
1033
|
-
|
|
1079
|
+
handlePointerEnter(event: PointerEvent): void;
|
|
1034
1080
|
|
|
1035
1081
|
/**
|
|
1036
1082
|
*
|
|
1037
|
-
* @param {
|
|
1083
|
+
* @param {PointerEvent} event
|
|
1038
1084
|
*/
|
|
1039
|
-
|
|
1085
|
+
handlePointerLeave(event: PointerEvent): void;
|
|
1040
1086
|
|
|
1041
1087
|
/**
|
|
1042
1088
|
*
|
|
1043
|
-
* @param {
|
|
1089
|
+
* @param {PointerEvent} event
|
|
1044
1090
|
*/
|
|
1045
|
-
handleMouseUp(event:
|
|
1091
|
+
handleMouseUp(event: PointerEvent): void;
|
|
1046
1092
|
|
|
1047
1093
|
/**
|
|
1048
1094
|
*
|
|
1049
|
-
* @param {
|
|
1095
|
+
* @param {PointerEvent} event
|
|
1050
1096
|
*/
|
|
1051
|
-
handleTouchStart(event:
|
|
1097
|
+
handleTouchStart(event: PointerEvent): void;
|
|
1052
1098
|
|
|
1053
1099
|
/**
|
|
1054
1100
|
*
|
|
1055
|
-
* @param {
|
|
1101
|
+
* @param {PointerEvent} event
|
|
1056
1102
|
*/
|
|
1057
|
-
handleTouchMove(event:
|
|
1103
|
+
handleTouchMove(event: PointerEvent): void;
|
|
1058
1104
|
|
|
1059
1105
|
/**
|
|
1060
1106
|
*
|
|
1061
|
-
* @param {
|
|
1107
|
+
* @param {PointerEvent} event
|
|
1062
1108
|
*/
|
|
1063
|
-
handleTouchEnd(event:
|
|
1109
|
+
handleTouchEnd(event: PointerEvent): void;
|
|
1064
1110
|
|
|
1065
1111
|
/**
|
|
1066
1112
|
*
|
|
@@ -1093,7 +1139,7 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
1093
1139
|
* @param event
|
|
1094
1140
|
* @param positions
|
|
1095
1141
|
*/
|
|
1096
|
-
recognizeGesture(event: 'TouchStart' | '
|
|
1142
|
+
recognizeGesture(event: 'TouchStart' | 'TouchMove' | 'TouchEnd', positions: IPosition): void;
|
|
1097
1143
|
|
|
1098
1144
|
/**
|
|
1099
1145
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
1
2
|
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
2
3
|
import macro from '../../macros.js';
|
|
3
4
|
import { A as degreesFromRadians } from '../../Common/Core/Math/index.js';
|
|
@@ -15,10 +16,11 @@ var vtkWarningMacro = macro.vtkWarningMacro,
|
|
|
15
16
|
// Global methods
|
|
16
17
|
// ----------------------------------------------------------------------------
|
|
17
18
|
|
|
19
|
+
var EMPTY_MOUSE_EVENT = new MouseEvent('');
|
|
18
20
|
var deviceInputMap = {
|
|
19
21
|
'xr-standard': [Input.Trigger, Input.Grip, Input.TrackPad, Input.Thumbstick, Input.A, Input.B]
|
|
20
22
|
};
|
|
21
|
-
var handledEvents = ['StartAnimation', 'Animation', 'EndAnimation', 'MouseEnter', 'MouseLeave', 'StartMouseMove', 'MouseMove', 'EndMouseMove', 'LeftButtonPress', 'LeftButtonRelease', 'MiddleButtonPress', 'MiddleButtonRelease', 'RightButtonPress', 'RightButtonRelease', 'KeyPress', 'KeyDown', 'KeyUp', 'StartMouseWheel', 'MouseWheel', 'EndMouseWheel', 'StartPinch', 'Pinch', 'EndPinch', 'StartPan', 'Pan', 'EndPan', 'StartRotate', 'Rotate', 'EndRotate', 'Button3D', 'Move3D', 'StartPointerLock', 'EndPointerLock', 'StartInteraction', 'Interaction', 'EndInteraction', 'AnimationFrameRateUpdate'];
|
|
23
|
+
var handledEvents = ['StartAnimation', 'Animation', 'EndAnimation', 'PointerEnter', 'PointerLeave', 'MouseEnter', 'MouseLeave', 'StartMouseMove', 'MouseMove', 'EndMouseMove', 'LeftButtonPress', 'LeftButtonRelease', 'MiddleButtonPress', 'MiddleButtonRelease', 'RightButtonPress', 'RightButtonRelease', 'KeyPress', 'KeyDown', 'KeyUp', 'StartMouseWheel', 'MouseWheel', 'EndMouseWheel', 'StartPinch', 'Pinch', 'EndPinch', 'StartPan', 'Pan', 'EndPan', 'StartRotate', 'Rotate', 'EndRotate', 'Button3D', 'Move3D', 'StartPointerLock', 'EndPointerLock', 'StartInteraction', 'Interaction', 'EndInteraction', 'AnimationFrameRateUpdate'];
|
|
22
24
|
|
|
23
25
|
function preventDefault(event) {
|
|
24
26
|
if (event.cancelable) {
|
|
@@ -27,6 +29,16 @@ function preventDefault(event) {
|
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function pointerCacheToPositions(cache) {
|
|
35
|
+
var positions = Object.create(null);
|
|
36
|
+
cache.forEach(function (_ref) {
|
|
37
|
+
var pointerId = _ref.pointerId,
|
|
38
|
+
position = _ref.position;
|
|
39
|
+
positions[pointerId] = position;
|
|
40
|
+
});
|
|
41
|
+
return positions;
|
|
30
42
|
} // ----------------------------------------------------------------------------
|
|
31
43
|
// vtkRenderWindowInteractor methods
|
|
32
44
|
// ----------------------------------------------------------------------------
|
|
@@ -36,9 +48,9 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
36
48
|
// Set our className
|
|
37
49
|
model.classHierarchy.push('vtkRenderWindowInteractor'); // Initialize list of requesters
|
|
38
50
|
|
|
39
|
-
var animationRequesters = new Set(); //
|
|
51
|
+
var animationRequesters = new Set(); // map from pointerId to { pointerId: number, position: [x, y] }
|
|
40
52
|
|
|
41
|
-
var
|
|
53
|
+
var pointerCache = new Map(); // Public API methods
|
|
42
54
|
//----------------------------------------------------------------------
|
|
43
55
|
|
|
44
56
|
publicAPI.start = function () {
|
|
@@ -127,20 +139,13 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
127
139
|
x: scaleX * (source.clientX - bounds.left),
|
|
128
140
|
y: scaleY * (bounds.height - source.clientY + bounds.top),
|
|
129
141
|
z: 0
|
|
130
|
-
};
|
|
131
|
-
updateCurrentRenderer(position.x, position.y);
|
|
132
|
-
return position;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function getTouchEventPositionsFor(touches) {
|
|
136
|
-
var positions = {};
|
|
142
|
+
}; // if multitouch, do not update the current renderer
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
positions[touch.identifier] = getScreenEventPositionFor(touch);
|
|
144
|
+
if (pointerCache.size <= 1 || !model.currentRenderer) {
|
|
145
|
+
updateCurrentRenderer(position.x, position.y);
|
|
141
146
|
}
|
|
142
147
|
|
|
143
|
-
return
|
|
148
|
+
return position;
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
function getModifierKeysFor(event) {
|
|
@@ -162,40 +167,8 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
162
167
|
return keys;
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
function
|
|
166
|
-
|
|
167
|
-
var rootElm = document;
|
|
168
|
-
var method = addListeners ? 'addEventListener' : 'removeEventListener';
|
|
169
|
-
var invMethod = addListeners ? 'removeEventListener' : 'addEventListener';
|
|
170
|
-
|
|
171
|
-
if (!force && !addListeners && activeListenerCount > 0) {
|
|
172
|
-
--activeListenerCount;
|
|
173
|
-
} // only add/remove listeners when there are no registered listeners
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (!activeListenerCount || force) {
|
|
177
|
-
activeListenerCount = 0;
|
|
178
|
-
|
|
179
|
-
if (model.container) {
|
|
180
|
-
model.container[invMethod]('mousemove', publicAPI.handleMouseMove);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
rootElm[method]('mouseup', publicAPI.handleMouseUp);
|
|
184
|
-
rootElm[method]('mousemove', publicAPI.handleMouseMove);
|
|
185
|
-
rootElm[method]('touchend', publicAPI.handleTouchEnd, false);
|
|
186
|
-
rootElm[method]('touchcancel', publicAPI.handleTouchEnd, {
|
|
187
|
-
passive: false,
|
|
188
|
-
capture: false
|
|
189
|
-
});
|
|
190
|
-
rootElm[method]('touchmove', publicAPI.handleTouchMove, {
|
|
191
|
-
passive: false,
|
|
192
|
-
capture: false
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (!force && addListeners) {
|
|
197
|
-
++activeListenerCount;
|
|
198
|
-
}
|
|
170
|
+
function getDeviceTypeFor(event) {
|
|
171
|
+
return event.pointerType || '';
|
|
199
172
|
}
|
|
200
173
|
|
|
201
174
|
publicAPI.bindEvents = function (container) {
|
|
@@ -204,40 +177,50 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
204
177
|
|
|
205
178
|
container.addEventListener('wheel', publicAPI.handleWheel);
|
|
206
179
|
container.addEventListener('DOMMouseScroll', publicAPI.handleWheel);
|
|
207
|
-
container.addEventListener('
|
|
208
|
-
container.addEventListener('
|
|
209
|
-
container.addEventListener('
|
|
210
|
-
|
|
180
|
+
container.addEventListener('pointerenter', publicAPI.handlePointerEnter);
|
|
181
|
+
container.addEventListener('pointerleave', publicAPI.handlePointerLeave);
|
|
182
|
+
container.addEventListener('pointermove', publicAPI.handlePointerMove, {
|
|
183
|
+
passive: false
|
|
184
|
+
});
|
|
185
|
+
container.addEventListener('pointerdown', publicAPI.handlePointerDown, {
|
|
186
|
+
passive: false
|
|
187
|
+
});
|
|
188
|
+
container.addEventListener('pointerup', publicAPI.handlePointerUp);
|
|
189
|
+
container.addEventListener('pointercancel', publicAPI.handlePointerCancel);
|
|
211
190
|
document.addEventListener('keypress', publicAPI.handleKeyPress);
|
|
212
191
|
document.addEventListener('keydown', publicAPI.handleKeyDown);
|
|
213
192
|
document.addEventListener('keyup', publicAPI.handleKeyUp);
|
|
214
|
-
document.addEventListener('pointerlockchange', publicAPI.handlePointerLockChange);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
193
|
+
document.addEventListener('pointerlockchange', publicAPI.handlePointerLockChange); // using touchAction is more performant than preventDefault
|
|
194
|
+
// in a touchstart handler.
|
|
195
|
+
|
|
196
|
+
container.style.touchAction = 'none';
|
|
197
|
+
container.style.userSelect = 'none'; // disables tap highlight for when cursor is pointer
|
|
198
|
+
|
|
199
|
+
container.style.webkitTapHighlightColor = 'rgba(0,0,0,0)';
|
|
219
200
|
};
|
|
220
201
|
|
|
221
202
|
publicAPI.unbindEvents = function () {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
203
|
+
var container = model.container;
|
|
204
|
+
container.removeEventListener('contextmenu', preventDefault); // model.container.removeEventListener('click', preventDefault); // Avoid stopping event propagation
|
|
205
|
+
|
|
206
|
+
container.removeEventListener('wheel', publicAPI.handleWheel);
|
|
207
|
+
container.removeEventListener('DOMMouseScroll', publicAPI.handleWheel);
|
|
208
|
+
container.removeEventListener('pointerenter', publicAPI.handlePointerEnter);
|
|
209
|
+
container.removeEventListener('pointerleave', publicAPI.handlePointerLeave);
|
|
210
|
+
container.removeEventListener('pointermove', publicAPI.handlePointerMove, {
|
|
211
|
+
passive: false
|
|
212
|
+
});
|
|
213
|
+
container.removeEventListener('pointerdown', publicAPI.handlePointerDown, {
|
|
214
|
+
passive: false
|
|
215
|
+
});
|
|
216
|
+
container.removeEventListener('pointerup', publicAPI.handlePointerUp);
|
|
217
|
+
container.removeEventListener('pointercancel', publicAPI.handlePointerCancel);
|
|
232
218
|
document.removeEventListener('keypress', publicAPI.handleKeyPress);
|
|
233
219
|
document.removeEventListener('keydown', publicAPI.handleKeyDown);
|
|
234
220
|
document.removeEventListener('keyup', publicAPI.handleKeyUp);
|
|
235
221
|
document.removeEventListener('pointerlockchange', publicAPI.handlePointerLockChange);
|
|
236
|
-
model.container.removeEventListener('touchstart', publicAPI.handleTouchStart, {
|
|
237
|
-
passive: false,
|
|
238
|
-
capture: false
|
|
239
|
-
});
|
|
240
222
|
model.container = null;
|
|
223
|
+
pointerCache.clear();
|
|
241
224
|
};
|
|
242
225
|
|
|
243
226
|
publicAPI.handleKeyPress = function (event) {
|
|
@@ -255,19 +238,131 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
255
238
|
publicAPI.keyUpEvent(data);
|
|
256
239
|
};
|
|
257
240
|
|
|
258
|
-
publicAPI.
|
|
259
|
-
|
|
241
|
+
publicAPI.handlePointerEnter = function (event) {
|
|
242
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
243
|
+
position: getScreenEventPositionFor(event),
|
|
244
|
+
deviceType: getDeviceTypeFor(event)
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
publicAPI.pointerEnterEvent(callData);
|
|
248
|
+
|
|
249
|
+
if (callData.deviceType === 'mouse') {
|
|
250
|
+
publicAPI.mouseEnterEvent(callData);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
publicAPI.handlePointerLeave = function (event) {
|
|
255
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
256
|
+
position: getScreenEventPositionFor(event),
|
|
257
|
+
deviceType: getDeviceTypeFor(event)
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
publicAPI.pointerLeaveEvent(callData);
|
|
261
|
+
|
|
262
|
+
if (callData.deviceType === 'mouse') {
|
|
263
|
+
publicAPI.mouseLeaveEvent(callData);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
publicAPI.handlePointerDown = function (event) {
|
|
268
|
+
if (event.button > 2 || publicAPI.isPointerLocked()) {
|
|
260
269
|
// ignore events from extra mouse buttons such as `back` and `forward`
|
|
261
270
|
return;
|
|
262
271
|
}
|
|
263
272
|
|
|
264
|
-
interactionRegistration(true);
|
|
265
273
|
preventDefault(event);
|
|
266
274
|
|
|
267
|
-
|
|
275
|
+
if (event.target.hasPointerCapture(event.pointerId)) {
|
|
276
|
+
event.target.releasePointerCapture(event.pointerId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
model.container.setPointerCapture(event.pointerId);
|
|
280
|
+
|
|
281
|
+
if (pointerCache.has(event.pointerId)) {
|
|
282
|
+
vtkWarningMacro('[RenderWindowInteractor] duplicate pointerId detected');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
pointerCache.set(event.pointerId, {
|
|
286
|
+
pointerId: event.pointerId,
|
|
268
287
|
position: getScreenEventPositionFor(event)
|
|
269
288
|
});
|
|
270
289
|
|
|
290
|
+
switch (event.pointerType) {
|
|
291
|
+
case 'pen':
|
|
292
|
+
case 'touch':
|
|
293
|
+
publicAPI.handleTouchStart(event);
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
case 'mouse':
|
|
297
|
+
default:
|
|
298
|
+
publicAPI.handleMouseDown(event);
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
publicAPI.handlePointerUp = function (event) {
|
|
304
|
+
if (pointerCache.has(event.pointerId)) {
|
|
305
|
+
preventDefault(event);
|
|
306
|
+
pointerCache.delete(event.pointerId);
|
|
307
|
+
model.container.releasePointerCapture(event.pointerId);
|
|
308
|
+
|
|
309
|
+
switch (event.pointerType) {
|
|
310
|
+
case 'pen':
|
|
311
|
+
case 'touch':
|
|
312
|
+
publicAPI.handleTouchEnd(event);
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
case 'mouse':
|
|
316
|
+
default:
|
|
317
|
+
publicAPI.handleMouseUp(event);
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
publicAPI.handlePointerCancel = function (event) {
|
|
324
|
+
if (pointerCache.has(event.pointerId)) {
|
|
325
|
+
pointerCache.delete(event.pointerId);
|
|
326
|
+
|
|
327
|
+
switch (event.pointerType) {
|
|
328
|
+
case 'pen':
|
|
329
|
+
case 'touch':
|
|
330
|
+
publicAPI.handleTouchEnd(event);
|
|
331
|
+
break;
|
|
332
|
+
|
|
333
|
+
case 'mouse':
|
|
334
|
+
default:
|
|
335
|
+
publicAPI.handleMouseUp(event);
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
publicAPI.handlePointerMove = function (event) {
|
|
342
|
+
if (pointerCache.has(event.pointerId)) {
|
|
343
|
+
var pointer = pointerCache.get(event.pointerId);
|
|
344
|
+
pointer.position = getScreenEventPositionFor(event);
|
|
345
|
+
|
|
346
|
+
switch (event.pointerType) {
|
|
347
|
+
case 'pen':
|
|
348
|
+
case 'touch':
|
|
349
|
+
publicAPI.handleTouchMove(event);
|
|
350
|
+
break;
|
|
351
|
+
|
|
352
|
+
case 'mouse':
|
|
353
|
+
default:
|
|
354
|
+
publicAPI.handleMouseMove(event);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
publicAPI.handleMouseDown = function (event) {
|
|
361
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
362
|
+
position: getScreenEventPositionFor(event),
|
|
363
|
+
deviceType: getDeviceTypeFor(event)
|
|
364
|
+
});
|
|
365
|
+
|
|
271
366
|
switch (event.button) {
|
|
272
367
|
case 0:
|
|
273
368
|
publicAPI.leftButtonPressEvent(callData);
|
|
@@ -457,10 +552,9 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
457
552
|
};
|
|
458
553
|
|
|
459
554
|
publicAPI.handleMouseMove = function (event) {
|
|
460
|
-
// Do not consume event for move
|
|
461
|
-
// preventDefault(event);
|
|
462
555
|
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
463
|
-
position: getScreenEventPositionFor(event)
|
|
556
|
+
position: getScreenEventPositionFor(event),
|
|
557
|
+
deviceType: getDeviceTypeFor(event)
|
|
464
558
|
});
|
|
465
559
|
|
|
466
560
|
if (model.moveTimeoutID === 0) {
|
|
@@ -522,7 +616,8 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
522
616
|
*/
|
|
523
617
|
|
|
524
618
|
var callData = _objectSpread(_objectSpread(_objectSpread({}, normalizeWheel(event)), getModifierKeysFor(event)), {}, {
|
|
525
|
-
position: getScreenEventPositionFor(event)
|
|
619
|
+
position: getScreenEventPositionFor(event),
|
|
620
|
+
deviceType: getDeviceTypeFor(event)
|
|
526
621
|
});
|
|
527
622
|
|
|
528
623
|
if (model.wheelTimeoutID === 0) {
|
|
@@ -540,28 +635,10 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
540
635
|
}, 200);
|
|
541
636
|
};
|
|
542
637
|
|
|
543
|
-
publicAPI.handleMouseEnter = function (event) {
|
|
544
|
-
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
545
|
-
position: getScreenEventPositionFor(event)
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
publicAPI.mouseEnterEvent(callData);
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
publicAPI.handleMouseLeave = function (event) {
|
|
552
|
-
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
553
|
-
position: getScreenEventPositionFor(event)
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
publicAPI.mouseLeaveEvent(callData);
|
|
557
|
-
};
|
|
558
|
-
|
|
559
638
|
publicAPI.handleMouseUp = function (event) {
|
|
560
|
-
interactionRegistration(false);
|
|
561
|
-
preventDefault(event);
|
|
562
|
-
|
|
563
639
|
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(event)), {}, {
|
|
564
|
-
position: getScreenEventPositionFor(event)
|
|
640
|
+
position: getScreenEventPositionFor(event),
|
|
641
|
+
deviceType: getDeviceTypeFor(event)
|
|
565
642
|
});
|
|
566
643
|
|
|
567
644
|
switch (event.button) {
|
|
@@ -584,107 +661,85 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
584
661
|
};
|
|
585
662
|
|
|
586
663
|
publicAPI.handleTouchStart = function (event) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (model.recognizeGestures &&
|
|
591
|
-
var positions =
|
|
592
|
-
|
|
593
|
-
if (
|
|
594
|
-
var
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
controlKey: false
|
|
600
|
-
};
|
|
664
|
+
var pointers = _toConsumableArray(pointerCache.values()); // If multitouch
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
if (model.recognizeGestures && pointers.length > 1) {
|
|
668
|
+
var positions = pointerCacheToPositions(pointerCache); // did we just transition to multitouch?
|
|
669
|
+
|
|
670
|
+
if (pointers.length === 2) {
|
|
671
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
672
|
+
position: pointers[0].position,
|
|
673
|
+
deviceType: getDeviceTypeFor(event)
|
|
674
|
+
});
|
|
675
|
+
|
|
601
676
|
publicAPI.leftButtonReleaseEvent(callData);
|
|
602
677
|
} // handle the gesture
|
|
603
678
|
|
|
604
679
|
|
|
605
680
|
publicAPI.recognizeGesture('TouchStart', positions);
|
|
606
681
|
} else {
|
|
607
|
-
var
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
controlKey: false
|
|
613
|
-
};
|
|
682
|
+
var _callData = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
683
|
+
position: getScreenEventPositionFor(event),
|
|
684
|
+
deviceType: getDeviceTypeFor(event)
|
|
685
|
+
});
|
|
686
|
+
|
|
614
687
|
publicAPI.leftButtonPressEvent(_callData);
|
|
615
688
|
}
|
|
616
689
|
};
|
|
617
690
|
|
|
618
691
|
publicAPI.handleTouchMove = function (event) {
|
|
619
|
-
|
|
692
|
+
var pointers = _toConsumableArray(pointerCache.values());
|
|
620
693
|
|
|
621
|
-
if (model.recognizeGestures &&
|
|
622
|
-
var positions =
|
|
694
|
+
if (model.recognizeGestures && pointers.length > 1) {
|
|
695
|
+
var positions = pointerCacheToPositions(pointerCache);
|
|
623
696
|
publicAPI.recognizeGesture('TouchMove', positions);
|
|
624
697
|
} else {
|
|
625
|
-
var
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
controlKey: false
|
|
631
|
-
};
|
|
698
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
699
|
+
position: pointers[0].position,
|
|
700
|
+
deviceType: getDeviceTypeFor(event)
|
|
701
|
+
});
|
|
702
|
+
|
|
632
703
|
publicAPI.mouseMoveEvent(callData);
|
|
633
704
|
}
|
|
634
705
|
};
|
|
635
706
|
|
|
636
707
|
publicAPI.handleTouchEnd = function (event) {
|
|
637
|
-
|
|
708
|
+
var pointers = _toConsumableArray(pointerCache.values());
|
|
638
709
|
|
|
639
710
|
if (model.recognizeGestures) {
|
|
640
711
|
// No more fingers down
|
|
641
|
-
if (
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
controlKey: false
|
|
650
|
-
};
|
|
651
|
-
publicAPI.leftButtonReleaseEvent(callData);
|
|
652
|
-
interactionRegistration(false);
|
|
653
|
-
} else {
|
|
654
|
-
// If more than one finger released, recognize touchend
|
|
655
|
-
var positions = getTouchEventPositionsFor(event.changedTouches);
|
|
656
|
-
publicAPI.recognizeGesture('TouchEnd', positions);
|
|
657
|
-
interactionRegistration(false);
|
|
658
|
-
}
|
|
659
|
-
} else if (event.touches.length === 1) {
|
|
712
|
+
if (pointers.length === 0) {
|
|
713
|
+
var callData = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
714
|
+
position: pointers[0].position,
|
|
715
|
+
deviceType: getDeviceTypeFor(event)
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
publicAPI.leftButtonReleaseEvent(callData);
|
|
719
|
+
} else if (pointers.length === 1) {
|
|
660
720
|
// If one finger left, end touch and start button press
|
|
661
|
-
var
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
var
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
controlKey: false
|
|
670
|
-
};
|
|
721
|
+
var positions = pointerCacheToPositions(pointerCache);
|
|
722
|
+
publicAPI.recognizeGesture('TouchEnd', positions);
|
|
723
|
+
|
|
724
|
+
var _callData2 = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
725
|
+
position: pointers[0].position,
|
|
726
|
+
deviceType: getDeviceTypeFor(event)
|
|
727
|
+
});
|
|
728
|
+
|
|
671
729
|
publicAPI.leftButtonPressEvent(_callData2);
|
|
672
730
|
} else {
|
|
673
731
|
// If more than one finger left, keep touch move
|
|
674
|
-
var
|
|
732
|
+
var _positions = pointerCacheToPositions(pointerCache);
|
|
675
733
|
|
|
676
|
-
publicAPI.recognizeGesture('TouchMove',
|
|
734
|
+
publicAPI.recognizeGesture('TouchMove', _positions);
|
|
677
735
|
}
|
|
678
736
|
} else {
|
|
679
|
-
var
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
controlKey: false
|
|
685
|
-
};
|
|
737
|
+
var _callData3 = _objectSpread(_objectSpread({}, getModifierKeysFor(EMPTY_MOUSE_EVENT)), {}, {
|
|
738
|
+
position: pointers[0].position,
|
|
739
|
+
deviceType: getDeviceTypeFor(event)
|
|
740
|
+
});
|
|
741
|
+
|
|
686
742
|
publicAPI.leftButtonReleaseEvent(_callData3);
|
|
687
|
-
interactionRegistration(false);
|
|
688
743
|
}
|
|
689
744
|
};
|
|
690
745
|
|
|
@@ -92,15 +92,16 @@ var DEFAULT_VALUES = {
|
|
|
92
92
|
ipScalarRange: [-1000000.0, 1000000.0],
|
|
93
93
|
filterMode: FilterMode.OFF,
|
|
94
94
|
// ignored by WebGL so no behavior change
|
|
95
|
-
preferSizeOverAccuracy: false
|
|
96
|
-
|
|
95
|
+
preferSizeOverAccuracy: false,
|
|
96
|
+
// Whether to use halfFloat representation of float, when it is inaccurate
|
|
97
|
+
computeNormalFromOpacity: false
|
|
97
98
|
}; // ----------------------------------------------------------------------------
|
|
98
99
|
|
|
99
100
|
function extend(publicAPI, model) {
|
|
100
101
|
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
101
102
|
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
102
103
|
vtkAbstractMapper.extend(publicAPI, model, initialValues);
|
|
103
|
-
macro.setGet(publicAPI, model, ['sampleDistance', 'imageSampleDistance', 'maximumSamplesPerRay', 'autoAdjustSampleDistances', 'blendMode', 'filterMode', 'preferSizeOverAccuracy']);
|
|
104
|
+
macro.setGet(publicAPI, model, ['sampleDistance', 'imageSampleDistance', 'maximumSamplesPerRay', 'autoAdjustSampleDistances', 'blendMode', 'filterMode', 'preferSizeOverAccuracy', 'computeNormalFromOpacity']);
|
|
104
105
|
macro.setGetArray(publicAPI, model, ['ipScalarRange'], 2);
|
|
105
106
|
macro.event(publicAPI, model, 'lightingActivated'); // Object methods
|
|
106
107
|
|
|
@@ -153,6 +153,11 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
|
|
|
153
153
|
|
|
154
154
|
if (model.gopacity) {
|
|
155
155
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::GradientOpacityOn', '#define vtkGradientOpacityOn').result;
|
|
156
|
+
} // set normal from density
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if (model.renderable.getComputeNormalFromOpacity()) {
|
|
160
|
+
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::vtkComputeNormalFromOpacity', "#define vtkComputeNormalFromOpacity").result;
|
|
156
161
|
} // if we have a ztexture then declare it and use it
|
|
157
162
|
|
|
158
163
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var vtkVolumeFS = "//VTK::System::Dec\n\n/*=========================================================================\n\n Program: Visualization Toolkit\n Module: vtkVolumeFS.glsl\n\n Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n All rights reserved.\n See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n This software is distributed WITHOUT ANY WARRANTY; without even\n the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n PURPOSE. See the above copyright notice for more information.\n\n=========================================================================*/\n// Template for the volume mappers fragment shader\n\n// the output of this shader\n//VTK::Output::Dec\n\nvarying vec3 vertexVCVSOutput;\n\n// first declare the settings from the mapper\n// that impact the code paths in here\n\n// always set vtkNumComponents 1,2,3,4\n//VTK::NumComponents\n\n// possibly define vtkTrilinearOn\n//VTK::TrilinearOn\n\n// possibly define vtkIndependentComponents\n//VTK::IndependentComponentsOn\n\n// possibly define any \"proportional\" components\n//VTK::vtkProportionalComponents\n\n// Define the blend mode to use\n#define vtkBlendMode //VTK::BlendMode\n\n// Possibly define vtkImageLabelOutlineOn\n//VTK::ImageLabelOutlineOn\n\n#ifdef vtkImageLabelOutlineOn\nuniform int outlineThickness;\nuniform float vpWidth;\nuniform float vpHeight;\nuniform float vpOffsetX;\nuniform float vpOffsetY;\nuniform mat4 PCWCMatrix;\nuniform mat4 vWCtoIDX;\n#endif\n\n// define vtkLightComplexity\n//VTK::LightComplexity\n#if vtkLightComplexity > 0\nuniform float vSpecularPower;\nuniform float vAmbient;\nuniform float vDiffuse;\nuniform float vSpecular;\n//VTK::Light::Dec\n#endif\n\n// possibly define vtkGradientOpacityOn\n//VTK::GradientOpacityOn\n#ifdef vtkGradientOpacityOn\nuniform float goscale0;\nuniform float goshift0;\nuniform float gomin0;\nuniform float gomax0;\n#if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\nuniform float goscale1;\nuniform float goshift1;\nuniform float gomin1;\nuniform float gomax1;\n#if vtkNumComponents >= 3\nuniform float goscale2;\nuniform float goshift2;\nuniform float gomin2;\nuniform float gomax2;\n#endif\n#if vtkNumComponents >= 4\nuniform float goscale3;\nuniform float goshift3;\nuniform float gomin3;\nuniform float gomax3;\n#endif\n#endif\n#endif\n\n// if you want to see the raw tiled\n// data in webgl1 uncomment the following line\n// #define debugtile\n\n// camera values\nuniform float camThick;\nuniform float camNear;\nuniform float camFar;\nuniform int cameraParallel;\n\n// values describing the volume geometry\nuniform vec3 vOriginVC;\nuniform vec3 vSpacing;\nuniform ivec3 volumeDimensions; // 3d texture dimensions\nuniform vec3 vPlaneNormal0;\nuniform float vPlaneDistance0;\nuniform vec3 vPlaneNormal1;\nuniform float vPlaneDistance1;\nuniform vec3 vPlaneNormal2;\nuniform float vPlaneDistance2;\nuniform vec3 vPlaneNormal3;\nuniform float vPlaneDistance3;\nuniform vec3 vPlaneNormal4;\nuniform float vPlaneDistance4;\nuniform vec3 vPlaneNormal5;\nuniform float vPlaneDistance5;\n\n//VTK::ClipPlane::Dec\n\n// opacity and color textures\nuniform sampler2D otexture;\nuniform float oshift0;\nuniform float oscale0;\nuniform sampler2D ctexture;\nuniform float cshift0;\nuniform float cscale0;\n\n// jitter texture\nuniform sampler2D jtexture;\n\n// some 3D texture values\nuniform float sampleDistance;\nuniform vec3 vVCToIJK;\n\n// the heights defined below are the locations\n// for the up to four components of the tfuns\n// the tfuns have a height of 2XnumComps pixels so the\n// values are computed to hit the middle of the two rows\n// for that component\n#ifdef vtkIndependentComponentsOn\n#if vtkNumComponents == 2\nuniform float mix0;\nuniform float mix1;\n#define height0 0.25\n#define height1 0.75\n#endif\n#if vtkNumComponents == 3\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\n#define height0 0.17\n#define height1 0.5\n#define height2 0.83\n#endif\n#if vtkNumComponents == 4\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\nuniform float mix3;\n#define height0 0.125\n#define height1 0.375\n#define height2 0.625\n#define height3 0.875\n#endif\n#endif\n\n#if vtkNumComponents >= 2\nuniform float oshift1;\nuniform float oscale1;\nuniform float cshift1;\nuniform float cscale1;\n#endif\n#if vtkNumComponents >= 3\nuniform float oshift2;\nuniform float oscale2;\nuniform float cshift2;\nuniform float cscale2;\n#endif\n#if vtkNumComponents >= 4\nuniform float oshift3;\nuniform float oscale3;\nuniform float cshift3;\nuniform float cscale3;\n#endif\n\nuniform vec4 ipScalarRangeMin;\nuniform vec4 ipScalarRangeMax;\n\n// declaration for intermixed geometry\n//VTK::ZBuffer::Dec\n\n//=======================================================================\n// global and custom variables (a temporary section before photorealistics rendering module is complete)\nvec3 rayDirVC;\n\n//=======================================================================\n// Webgl2 specific version of functions\n#if __VERSION__ == 300\n\nuniform highp sampler3D texture1;\n\nvec4 getTextureValue(vec3 pos)\n{\n vec4 tmp = texture(texture1, pos);\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.a = tmp.g;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n return tmp;\n}\n\n//=======================================================================\n// WebGL1 specific version of functions\n#else\n\nuniform sampler2D texture1;\n\nuniform float texWidth;\nuniform float texHeight;\nuniform int xreps;\nuniform int xstride;\nuniform int ystride;\n\n// if computing trilinear values from multiple z slices\n#ifdef vtkTrilinearOn\nvec4 getTextureValue(vec3 ijk)\n{\n float zoff = 1.0/float(volumeDimensions.z);\n vec4 val1 = getOneTextureValue(ijk);\n vec4 val2 = getOneTextureValue(vec3(ijk.xy, ijk.z + zoff));\n\n float indexZ = float(volumeDimensions)*ijk.z;\n float zmix = indexZ - floor(indexZ);\n\n return mix(val1, val2, zmix);\n}\n\nvec4 getOneTextureValue(vec3 ijk)\n#else // nearest or fast linear\nvec4 getTextureValue(vec3 ijk)\n#endif\n{\n vec3 tdims = vec3(volumeDimensions);\n\n#ifdef debugtile\n vec2 tpos = vec2(ijk.x, ijk.y);\n vec4 tmp = texture2D(texture1, tpos);\n tmp.a = 1.0;\n\n#else\n int z = int(ijk.z * tdims.z);\n int yz = z / xreps;\n int xz = z - yz*xreps;\n\n int tileWidth = volumeDimensions.x/xstride;\n int tileHeight = volumeDimensions.y/ystride;\n\n xz *= tileWidth;\n yz *= tileHeight;\n\n float ni = float(xz) + (ijk.x*float(tileWidth));\n float nj = float(yz) + (ijk.y*float(tileHeight));\n\n vec2 tpos = vec2(ni/texWidth, nj/texHeight);\n\n vec4 tmp = texture2D(texture1, tpos);\n\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.g = tmp.a;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n#endif\n\n return tmp;\n}\n\n// End of Webgl1 specific code\n//=======================================================================\n#endif\n\n//=======================================================================\n// compute the normal and gradient magnitude for a position\nvec4 computeNormal(vec3 pos, float scalar, vec3 tstep)\n{\n vec4 result;\n\n result.x = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)).a - scalar;\n result.y = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)).a - scalar;\n result.z = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)).a - scalar;\n\n // divide by spacing\n result.xyz /= vSpacing;\n\n result.w = length(result.xyz);\n\n // rotate to View Coords\n result.xyz =\n result.x * vPlaneNormal0 +\n result.y * vPlaneNormal2 +\n result.z * vPlaneNormal4;\n\n if (result.w > 0.0)\n {\n result.xyz /= result.w;\n }\n return result;\n}\n\n#ifdef vtkImageLabelOutlineOn\nvec3 fragCoordToIndexSpace(vec4 fragCoord) {\n vec4 pcPos = vec4(\n (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,\n (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,\n (fragCoord.z - 0.5) * 2.0,\n 1.0);\n\n vec4 worldCoord = PCWCMatrix * pcPos;\n vec4 vertex = (worldCoord/worldCoord.w);\n\n vec3 index = (vWCtoIDX * vertex).xyz;\n\n // half voxel fix for labelmapOutline \n return (index + vec3(0.5)) / vec3(volumeDimensions);\n}\n#endif\n\n//=======================================================================\n// compute the normals and gradient magnitudes for a position\n// for independent components\nmat4 computeMat4Normal(vec3 pos, vec4 tValue, vec3 tstep)\n{\n mat4 result;\n vec4 distX = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)) - tValue;\n vec4 distY = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)) - tValue;\n vec4 distZ = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)) - tValue;\n\n // divide by spacing\n distX /= vSpacing.x;\n distY /= vSpacing.y;\n distZ /= vSpacing.z;\n\n mat3 rot;\n rot[0] = vPlaneNormal0;\n rot[1] = vPlaneNormal2;\n rot[2] = vPlaneNormal4;\n\n#if !defined(vtkComponent0Proportional)\n result[0].xyz = vec3(distX.r, distY.r, distZ.r);\n result[0].a = length(result[0].xyz);\n result[0].xyz *= rot;\n if (result[0].w > 0.0)\n {\n result[0].xyz /= result[0].w;\n }\n#endif\n\n// optionally compute the 2nd component\n#if vtkNumComponents >= 2 && !defined(vtkComponent1Proportional)\n result[1].xyz = vec3(distX.g, distY.g, distZ.g);\n result[1].a = length(result[1].xyz);\n result[1].xyz *= rot;\n if (result[1].w > 0.0)\n {\n result[1].xyz /= result[1].w;\n }\n#endif\n\n// optionally compute the 3rd component\n#if vtkNumComponents >= 3 && !defined(vtkComponent2Proportional)\n result[2].xyz = vec3(distX.b, distY.b, distZ.b);\n result[2].a = length(result[2].xyz);\n result[2].xyz *= rot;\n if (result[2].w > 0.0)\n {\n result[2].xyz /= result[2].w;\n }\n#endif\n\n// optionally compute the 4th component\n#if vtkNumComponents >= 4 && !defined(vtkComponent3Proportional)\n result[3].xyz = vec3(distX.a, distY.a, distZ.a);\n result[3].a = length(result[3].xyz);\n result[3].xyz *= rot;\n if (result[3].w > 0.0)\n {\n result[3].xyz /= result[3].w;\n }\n#endif\n\n return result;\n}\n\n//=======================================================================\n// Given a normal compute the gradient opacity factors\n//\nfloat computeGradientOpacityFactor(\n vec4 normal, float goscale, float goshift, float gomin, float gomax)\n{\n#if defined(vtkGradientOpacityOn)\n return clamp(normal.a*goscale + goshift, gomin, gomax);\n#else\n return 1.0;\n#endif\n}\n\n\n//=======================================================================\n// surface light contribution\n\n#if vtkLightComplexity == 3\n// convert vector position from idx to vc\nvec3 IStoVC(vec3 posIS){\n vec3 posVC = posIS / vVCToIJK;\n return posVC.x * vPlaneNormal0 + posVC.y * vPlaneNormal2 + posVC.z * vPlaneNormal4 + vOriginVC;\n}\n#endif\n\n#if vtkLightComplexity > 0\nvoid applyLighting(inout vec3 tColor, vec4 normal)\n{\n vec3 diffuse = vec3(0.0, 0.0, 0.0);\n vec3 specular = vec3(0.0, 0.0, 0.0);\n float df, sf = 0.0;\n for (int i = 0; i < lightNum; i++){\n df = abs(dot(normal.rgb, -lightDirectionVC[i]));\n diffuse += df * lightColor[i];\n sf = pow( abs(dot(lightHalfAngleVC[i],normal.rgb)), vSpecularPower);\n specular += sf * lightColor[i];\n }\n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular;\n}\n #if vtkLightComplexity < 3\n void applyLightingDirectional(inout vec3 tColor, vec4 normal)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float ndotL,ndotH;\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n ndotH = dot(normal.xyz, normalize(rayDirVC + vertLightDirection));\n if (ndotH < 0.0 && twoSidedLighting)\n {\n ndotH = -ndotH;\n }\n if (ndotH > 0.0)\n {\n specular += pow(ndotH, vSpecularPower) * lightColor[i];\n }\n }\n }\n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular;\n }\n #else\n void applyLightingPositional(inout vec3 tColor, vec4 normal, vec3 posVC)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float distance,attenuation,ndotL,ndotH;\n vec3 lightDir;\n if (lightPositional[i] == 1){\n lightDir = lightDirectionVC[i];\n vertLightDirection = lightPositionVC[i] - posVC; // or reverse...?\n distance = length(vertLightDirection);\n vertLightDirection = normalize(vertLightDirection);\n attenuation = 1.0 / (lightAttenuation[i].x\n + lightAttenuation[i].y * distance\n + lightAttenuation[i].z * distance * distance);\n // per OpenGL standard cone angle is 90 or less for a spot light`,\n if (lightConeAngle[i] <= 90.0){\n float coneDot = dot(normalize(posVC - lightPositionVC[i]), lightDir);\n if (coneDot >= cos(radians(lightConeAngle[i]))){ // if inside cone\n attenuation = attenuation * pow(coneDot, lightExponent[i]);\n }\n else {\n attenuation = 0.0;\n }\n }\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * attenuation * lightColor[i];\n //specular\n ndotH = dot(normal.xyz, normalize(rayDirVC + vertLightDirection));\n if (ndotH < 0.0 && twoSidedLighting)\n {\n ndotH = -ndotH;\n }\n if (ndotH > 0.0)\n {\n specular += pow(ndotH, vSpecularPower) * attenuation * lightColor[i];\n }\n }\n } else {\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n ndotH = dot(normal.xyz, normalize(rayDirVC + vertLightDirection));\n if (ndotH < 0.0 && twoSidedLighting)\n {\n ndotH = -ndotH;\n }\n if (ndotH > 0.0)\n {\n specular += pow(ndotH, vSpecularPower) * lightColor[i];\n }\n }\n }\n }\n tColor.rgb = tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n }\n #endif \n#endif\n\n//=======================================================================\n// Given a texture value compute the color and opacity\n//\nvec4 getColorForValue(vec4 tValue, vec3 posIS, vec3 tstep)\n{\n#ifdef vtkImageLabelOutlineOn\n vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord); // pos in texture space\n vec4 centerValue = getTextureValue(centerPosIS);\n bool pixelOnBorder = false;\n vec4 tColor = texture2D(ctexture, vec2(centerValue.r * cscale0 + cshift0, 0.5));\n\n // Get alpha of segment from opacity function.\n tColor.a = texture2D(otexture, vec2(centerValue.r * oscale0 + oshift0, 0.5)).r;\n\n // Only perform outline check on fragments rendering voxels that aren't invisible.\n // Saves a bunch of needless checks on the background.\n // TODO define epsilon when building shader?\n if (float(tColor.a) > 0.01) {\n for (int i = -outlineThickness; i <= outlineThickness; i++) {\n for (int j = -outlineThickness; j <= outlineThickness; j++) {\n if (i == 0 || j == 0) {\n continue;\n }\n\n vec4 neighborPixelCoord = vec4(gl_FragCoord.x + float(i),\n gl_FragCoord.y + float(j),\n gl_FragCoord.z, gl_FragCoord.w);\n\n vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);\n vec4 value = getTextureValue(neighborPosIS);\n\n // If any of my neighbours are not the same value as I\n // am, this means I am on the border of the segment.\n // We can break the loops\n if (any(notEqual(value, centerValue))) {\n pixelOnBorder = true;\n break;\n }\n }\n\n if (pixelOnBorder == true) {\n break;\n }\n }\n\n // If I am on the border, I am displayed at full opacity\n if (pixelOnBorder == true) {\n tColor.a = 1.0;\n }\n }\n\n#else\n // compute the normal and gradient magnitude if needed\n // We compute it as a vec4 if possible otherwise a mat4\n //\n vec4 goFactor = vec4(1.0,1.0,1.0,1.0);\n\n // compute the normal vectors as needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n #if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\n mat4 normalMat = computeMat4Normal(posIS, tValue, tstep);\n #if !defined(vtkComponent0Proportional)\n vec4 normal0 = normalMat[0];\n #endif\n #if !defined(vtkComponent1Proportional)\n vec4 normal1 = normalMat[1];\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n vec4 normal2 = normalMat[2];\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n vec4 normal3 = normalMat[3];\n #endif\n #endif\n #endif\n #else\n vec4 normal0 = computeNormal(posIS, tValue.a, tstep);\n #endif\n #endif\n\n // compute gradient opacity factors as needed\n #if defined(vtkGradientOpacityOn)\n #if !defined(vtkComponent0Proportional)\n goFactor.x =\n computeGradientOpacityFactor(normal0, goscale0, goshift0, gomin0, gomax0);\n #endif\n #if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\n #if !defined(vtkComponent1Proportional)\n goFactor.y =\n computeGradientOpacityFactor(normal1, goscale1, goshift1, gomin1, gomax1);\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n goFactor.z =\n computeGradientOpacityFactor(normal2, goscale2, goshift2, gomin2, gomax2);\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n goFactor.w =\n computeGradientOpacityFactor(normal3, goscale3, goshift3, gomin3, gomax3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n // single component is always independent\n #if vtkNumComponents == 1\n vec4 tColor = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, 0.5));\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n #endif\n\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n vec4 tColor = mix0*texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, height0));\n #if !defined(vtkComponent0Proportional)\n tColor.a = goFactor.x*mix0*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n tColor *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix0));\n #endif\n\n vec3 tColor1 = mix1*texture2D(ctexture, vec2(tValue.g * cscale1 + cshift1, height1)).rgb;\n #if !defined(vtkComponent1Proportional)\n tColor.a += goFactor.y*mix1*texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n tColor1 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix1));\n #endif\n\n #if vtkNumComponents >= 3\n vec3 tColor2 = mix2*texture2D(ctexture, vec2(tValue.b * cscale2 + cshift2, height2)).rgb;\n #if !defined(vtkComponent2Proportional)\n tColor.a += goFactor.z*mix2*texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n tColor2 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix2));\n #endif\n\n #if vtkNumComponents >= 4\n vec3 tColor3 = mix3*texture2D(ctexture, vec2(tValue.a * cscale3 + cshift3, height3)).rgb;\n #if !defined(vtkComponent3Proportional)\n tColor.a += goFactor.w*mix3*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n tColor3 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix3));\n #endif\n #endif\n #endif\n #else // then not independent\n\n #if vtkNumComponents == 2\n float lum = tValue.r * cscale0 + cshift0;\n float alpha = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale1 + oshift1, 0.5)).r;\n vec4 tColor = vec4(lum, lum, lum, alpha);\n #endif\n #if vtkNumComponents == 3\n vec4 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale0 + oshift0, 0.5)).r;\n #endif\n #if vtkNumComponents == 4\n vec4 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, 0.5)).r;\n #endif\n #endif // dependent\n\n // apply lighting if requested as appropriate\n #if vtkLightComplexity > 0\n #if !defined(vtkComponent0Proportional)\n #if vtkLightComplexity < 3\n applyLightingDirectional(tColor.rgb, vec4(normalize(normal0.xyz),normal0.w));\n #else\n applyLightingPositional(tColor.rgb, vec4(normalize(normal0.xyz),normal0.w), IStoVC(posIS));\n #endif\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n #if !defined(vtkComponent1Proportional)\n applyLighting(tColor1, normal1);\n #endif\n #if vtkNumComponents >= 3\n #if !defined(vtkComponent2Proportional)\n applyLighting(tColor2, normal2);\n #endif\n #if vtkNumComponents >= 4\n #if !defined(vtkComponent3Proportional)\n applyLighting(tColor3, normal3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n// perform final independent blend as needed\n#if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n tColor.rgb += tColor1;\n#if vtkNumComponents >= 3\n tColor.rgb += tColor2;\n#if vtkNumComponents >= 4\n tColor.rgb += tColor3;\n#endif\n#endif\n#endif\n\n#endif\n\n\n\n\n\n\n\nreturn tColor;\n}\n\nbool valueWithinScalarRange(vec4 val, vec4 min, vec4 max) {\n bool withinRange = false;\n #if vtkNumComponents == 1\n if (val.r >= min.r && val.r <= max.r) {\n withinRange = true;\n }\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents == 2\n if (val.r >= min.r && val.r <= max.r &&\n val.g >= min.g && val.g <= max.g) {\n withinRange = true;\n }\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 3\n if (all(greaterThanEqual(val, ipScalarRangeMin)) &&\n all(lessThanEqual(val, ipScalarRangeMax))) {\n withinRange = true;\n }\n #endif\n return withinRange;\n}\n\n//=======================================================================\n// Apply the specified blend mode operation along the ray's path.\n//\nvoid applyBlend(vec3 posIS, vec3 endIS, float sampleDistanceIS, vec3 tdims)\n{\n vec3 tstep = 1.0/tdims;\n\n // start slightly inside and apply some jitter\n vec3 delta = endIS - posIS;\n vec3 stepIS = normalize(delta)*sampleDistanceIS;\n float raySteps = length(delta)/sampleDistanceIS;\n\n // avoid 0.0 jitter\n float jitter = 0.01 + 0.99*texture2D(jtexture, gl_FragCoord.xy/32.0).r;\n float stepsTraveled = jitter;\n\n // local vars for the loop\n vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n vec4 tValue;\n vec4 tColor;\n\n // if we have less than one step then pick the middle point\n // as our value\n // if (raySteps <= 1.0)\n // {\n // posIS = (posIS + endIS)*0.5;\n // }\n\n // Perform initial step at the volume boundary\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n #if vtkBlendMode == 0 // COMPOSITE_BLEND\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps);\n gl_FragData[0] = tColor;\n return;\n }\n\n tColor.a = 1.0 - pow(1.0 - tColor.a, jitter);\n color = vec4(tColor.rgb*tColor.a, tColor.a);\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n float mix = (1.0 - color.a);\n\n // this line should not be needed but nvidia seems to not handle\n // the break correctly on windows/chrome 58 angle\n //mix = mix * sign(max(raySteps - stepsTraveled - 1.0, 0.0));\n\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n stepsTraveled++;\n posIS += stepIS;\n if (color.a > 0.99) { color.a = 1.0; break; }\n }\n\n if (color.a < 0.99 && (raySteps - stepsTraveled) > 0.0)\n {\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps - stepsTraveled);\n\n float mix = (1.0 - color.a);\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n }\n\n gl_FragData[0] = vec4(color.rgb/color.a, color.a);\n #endif\n #if vtkBlendMode == 1 || vtkBlendMode == 2\n // MAXIMUM_INTENSITY_BLEND || MINIMUM_INTENSITY_BLEND\n // Find maximum/minimum intensity along the ray.\n\n // Define the operation we will use (min or max)\n #if vtkBlendMode == 1\n #define OP max\n #else\n #define OP min\n #endif\n\n // If the clipping range is shorter than the sample distance\n // we can skip the sampling loop along the ray.\n if (raySteps <= 1.0)\n {\n gl_FragData[0] = getColorForValue(tValue, posIS, tstep);\n return;\n }\n\n vec4 value = tValue;\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // Update the maximum value if necessary\n value = OP(tValue, value);\n\n // Otherwise, continue along the ray\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n tValue = getTextureValue(posIS);\n value = OP(tValue, value);\n\n // Now map through opacity and color\n gl_FragData[0] = getColorForValue(value, posIS, tstep);\n #endif\n #if vtkBlendMode == 3 || vtkBlendMode == 4 //AVERAGE_INTENSITY_BLEND || ADDITIVE_BLEND\n vec4 sum = vec4(0.);\n\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n }\n\n if (raySteps <= 1.0) {\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n return;\n }\n\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the AverageIPScalarRange to disregard scalar values, not in the range of interest, from the average computation.\n // Notes:\n // - We are comparing all values in the texture to see if any of them\n // are outside of the scalar range. In the future we might want to allow\n // scalar ranges for each component.\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n // Sum the values across each step in the path\n sum += tValue;\n }\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the IPScalarRange to disregard scalar values, not in the range of interest, from the average computation\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n\n stepsTraveled++;\n }\n\n #if vtkBlendMode == 3 // Average\n sum /= vec4(stepsTraveled, stepsTraveled, stepsTraveled, 1.0);\n #endif\n\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n #endif\n}\n\n//=======================================================================\n// Compute a new start and end point for a given ray based\n// on the provided bounded clipping plane (aka a rectangle)\nvoid getRayPointIntersectionBounds(\n vec3 rayPos, vec3 rayDir,\n vec3 planeDir, float planeDist,\n inout vec2 tbounds, vec3 vPlaneX, vec3 vPlaneY,\n float vSize1, float vSize2)\n{\n float result = dot(rayDir, planeDir);\n if (abs(result) < 1e-6)\n {\n return;\n }\n result = -1.0 * (dot(rayPos, planeDir) + planeDist) / result;\n vec3 xposVC = rayPos + rayDir*result;\n vec3 vxpos = xposVC - vOriginVC;\n vec2 vpos = vec2(\n dot(vxpos, vPlaneX),\n dot(vxpos, vPlaneY));\n\n // on some apple nvidia systems this does not work\n // if (vpos.x < 0.0 || vpos.x > vSize1 ||\n // vpos.y < 0.0 || vpos.y > vSize2)\n // even just\n // if (vpos.x < 0.0 || vpos.y < 0.0)\n // fails\n // so instead we compute a value that represents in and out\n //and then compute the return using this value\n float xcheck = max(0.0, vpos.x * (vpos.x - vSize1)); // 0 means in bounds\n float check = sign(max(xcheck, vpos.y * (vpos.y - vSize2))); // 0 means in bounds, 1 = out\n\n tbounds = mix(\n vec2(min(tbounds.x, result), max(tbounds.y, result)), // in value\n tbounds, // out value\n check); // 0 in 1 out\n}\n\n//=======================================================================\n// given a\n// - ray direction (rayDir)\n// - starting point (vertexVCVSOutput)\n// - bounding planes of the volume\n// - optionally depth buffer values\n// - far clipping plane\n// compute the start/end distances of the ray we need to cast\nvec2 computeRayDistances(vec3 rayDir, vec3 tdims)\n{\n vec2 dists = vec2(100.0*camFar, -1.0);\n\n vec3 vSize = vSpacing*tdims;\n\n // all this is in View Coordinates\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal0, vPlaneDistance0, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal1, vPlaneDistance1, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal2, vPlaneDistance2, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal3, vPlaneDistance3, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal4, vPlaneDistance4, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal5, vPlaneDistance5, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n\n //VTK::ClipPlane::Impl\n\n // do not go behind front clipping plane\n dists.x = max(0.0,dists.x);\n\n // do not go PAST far clipping plane\n float farDist = -camThick/rayDir.z;\n dists.y = min(farDist,dists.y);\n\n // Do not go past the zbuffer value if set\n // This is used for intermixing opaque geometry\n //VTK::ZBuffer::Impl\n\n return dists;\n}\n\n//=======================================================================\n// Compute the index space starting position (pos) and end\n// position\n//\nvoid computeIndexSpaceValues(out vec3 pos, out vec3 endPos, out float sampleDistanceIS, vec3 rayDir, vec2 dists)\n{\n // compute starting and ending values in volume space\n pos = vertexVCVSOutput + dists.x*rayDir;\n pos = pos - vOriginVC;\n // convert to volume basis and origin\n pos = vec3(\n dot(pos, vPlaneNormal0),\n dot(pos, vPlaneNormal2),\n dot(pos, vPlaneNormal4));\n\n endPos = vertexVCVSOutput + dists.y*rayDir;\n endPos = endPos - vOriginVC;\n endPos = vec3(\n dot(endPos, vPlaneNormal0),\n dot(endPos, vPlaneNormal2),\n dot(endPos, vPlaneNormal4));\n\n float delta = length(endPos - pos);\n\n pos *= vVCToIJK;\n endPos *= vVCToIJK;\n\n float delta2 = length(endPos - pos);\n sampleDistanceIS = sampleDistance*delta2/delta;\n}\n\nvoid main()\n{\n\n if (cameraParallel == 1)\n {\n // Camera is parallel, so the rayDir is just the direction of the camera.\n rayDirVC = vec3(0.0, 0.0, -1.0);\n } else {\n // camera is at 0,0,0 so rayDir for perspective is just the vc coord\n rayDirVC = normalize(vertexVCVSOutput);\n }\n\n vec3 tdims = vec3(volumeDimensions);\n\n // compute the start and end points for the ray\n vec2 rayStartEndDistancesVC = computeRayDistances(rayDirVC, tdims);\n\n // do we need to composite? aka does the ray have any length\n // If not, bail out early\n if (rayStartEndDistancesVC.y <= rayStartEndDistancesVC.x)\n {\n discard;\n }\n\n // IS = Index Space\n vec3 posIS;\n vec3 endIS;\n float sampleDistanceIS;\n computeIndexSpaceValues(posIS, endIS, sampleDistanceIS, rayDirVC, rayStartEndDistancesVC);\n\n // Perform the blending operation along the ray\n applyBlend(posIS, endIS, sampleDistanceIS, tdims);\n}\n";
|
|
1
|
+
var vtkVolumeFS = "//VTK::System::Dec\n\n/*=========================================================================\n\n Program: Visualization Toolkit\n Module: vtkVolumeFS.glsl\n\n Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n All rights reserved.\n See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n This software is distributed WITHOUT ANY WARRANTY; without even\n the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n PURPOSE. See the above copyright notice for more information.\n\n=========================================================================*/\n// Template for the volume mappers fragment shader\n\n// the output of this shader\n//VTK::Output::Dec\n\nvarying vec3 vertexVCVSOutput;\n\n// first declare the settings from the mapper\n// that impact the code paths in here\n\n// always set vtkNumComponents 1,2,3,4\n//VTK::NumComponents\n\n// possibly define vtkTrilinearOn\n//VTK::TrilinearOn\n\n// possibly define vtkIndependentComponents\n//VTK::IndependentComponentsOn\n\n// possibly define any \"proportional\" components\n//VTK::vtkProportionalComponents\n\n// Define the blend mode to use\n#define vtkBlendMode //VTK::BlendMode\n\n// Possibly define vtkImageLabelOutlineOn\n//VTK::ImageLabelOutlineOn\n\n#ifdef vtkImageLabelOutlineOn\nuniform int outlineThickness;\nuniform float vpWidth;\nuniform float vpHeight;\nuniform float vpOffsetX;\nuniform float vpOffsetY;\nuniform mat4 PCWCMatrix;\nuniform mat4 vWCtoIDX;\n#endif\n\n// define vtkLightComplexity\n//VTK::LightComplexity\n#if vtkLightComplexity > 0\nuniform float vSpecularPower;\nuniform float vAmbient;\nuniform float vDiffuse;\nuniform float vSpecular;\n//VTK::Light::Dec\n#endif\n\n// define vtkComputeNormalFromOpacity\n//VTK::vtkComputeNormalFromOpacity\n\n// possibly define vtkGradientOpacityOn\n//VTK::GradientOpacityOn\n#ifdef vtkGradientOpacityOn\nuniform float goscale0;\nuniform float goshift0;\nuniform float gomin0;\nuniform float gomax0;\n#if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\nuniform float goscale1;\nuniform float goshift1;\nuniform float gomin1;\nuniform float gomax1;\n#if vtkNumComponents >= 3\nuniform float goscale2;\nuniform float goshift2;\nuniform float gomin2;\nuniform float gomax2;\n#endif\n#if vtkNumComponents >= 4\nuniform float goscale3;\nuniform float goshift3;\nuniform float gomin3;\nuniform float gomax3;\n#endif\n#endif\n#endif\n\n// if you want to see the raw tiled\n// data in webgl1 uncomment the following line\n// #define debugtile\n\n// camera values\nuniform float camThick;\nuniform float camNear;\nuniform float camFar;\nuniform int cameraParallel;\n\n// values describing the volume geometry\nuniform vec3 vOriginVC;\nuniform vec3 vSpacing;\nuniform ivec3 volumeDimensions; // 3d texture dimensions\nuniform vec3 vPlaneNormal0;\nuniform float vPlaneDistance0;\nuniform vec3 vPlaneNormal1;\nuniform float vPlaneDistance1;\nuniform vec3 vPlaneNormal2;\nuniform float vPlaneDistance2;\nuniform vec3 vPlaneNormal3;\nuniform float vPlaneDistance3;\nuniform vec3 vPlaneNormal4;\nuniform float vPlaneDistance4;\nuniform vec3 vPlaneNormal5;\nuniform float vPlaneDistance5;\n\n//VTK::ClipPlane::Dec\n\n// opacity and color textures\nuniform sampler2D otexture;\nuniform float oshift0;\nuniform float oscale0;\nuniform sampler2D ctexture;\nuniform float cshift0;\nuniform float cscale0;\n\n// jitter texture\nuniform sampler2D jtexture;\n\n// some 3D texture values\nuniform float sampleDistance;\nuniform vec3 vVCToIJK;\n\n// the heights defined below are the locations\n// for the up to four components of the tfuns\n// the tfuns have a height of 2XnumComps pixels so the\n// values are computed to hit the middle of the two rows\n// for that component\n#ifdef vtkIndependentComponentsOn\n#if vtkNumComponents == 2\nuniform float mix0;\nuniform float mix1;\n#define height0 0.25\n#define height1 0.75\n#endif\n#if vtkNumComponents == 3\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\n#define height0 0.17\n#define height1 0.5\n#define height2 0.83\n#endif\n#if vtkNumComponents == 4\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\nuniform float mix3;\n#define height0 0.125\n#define height1 0.375\n#define height2 0.625\n#define height3 0.875\n#endif\n#endif\n\n#if vtkNumComponents >= 2\nuniform float oshift1;\nuniform float oscale1;\nuniform float cshift1;\nuniform float cscale1;\n#endif\n#if vtkNumComponents >= 3\nuniform float oshift2;\nuniform float oscale2;\nuniform float cshift2;\nuniform float cscale2;\n#endif\n#if vtkNumComponents >= 4\nuniform float oshift3;\nuniform float oscale3;\nuniform float cshift3;\nuniform float cscale3;\n#endif\n\nuniform vec4 ipScalarRangeMin;\nuniform vec4 ipScalarRangeMax;\n\n// declaration for intermixed geometry\n//VTK::ZBuffer::Dec\n\n//=======================================================================\n// global and custom variables (a temporary section before photorealistics rendering module is complete)\nvec3 rayDirVC;\n\n//=======================================================================\n// Webgl2 specific version of functions\n#if __VERSION__ == 300\n\nuniform highp sampler3D texture1;\n\nvec4 getTextureValue(vec3 pos)\n{\n vec4 tmp = texture(texture1, pos);\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.a = tmp.g;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n return tmp;\n}\n\n//=======================================================================\n// WebGL1 specific version of functions\n#else\n\nuniform sampler2D texture1;\n\nuniform float texWidth;\nuniform float texHeight;\nuniform int xreps;\nuniform int xstride;\nuniform int ystride;\n\n// if computing trilinear values from multiple z slices\n#ifdef vtkTrilinearOn\nvec4 getTextureValue(vec3 ijk)\n{\n float zoff = 1.0/float(volumeDimensions.z);\n vec4 val1 = getOneTextureValue(ijk);\n vec4 val2 = getOneTextureValue(vec3(ijk.xy, ijk.z + zoff));\n\n float indexZ = float(volumeDimensions)*ijk.z;\n float zmix = indexZ - floor(indexZ);\n\n return mix(val1, val2, zmix);\n}\n\nvec4 getOneTextureValue(vec3 ijk)\n#else // nearest or fast linear\nvec4 getTextureValue(vec3 ijk)\n#endif\n{\n vec3 tdims = vec3(volumeDimensions);\n\n#ifdef debugtile\n vec2 tpos = vec2(ijk.x, ijk.y);\n vec4 tmp = texture2D(texture1, tpos);\n tmp.a = 1.0;\n\n#else\n int z = int(ijk.z * tdims.z);\n int yz = z / xreps;\n int xz = z - yz*xreps;\n\n int tileWidth = volumeDimensions.x/xstride;\n int tileHeight = volumeDimensions.y/ystride;\n\n xz *= tileWidth;\n yz *= tileHeight;\n\n float ni = float(xz) + (ijk.x*float(tileWidth));\n float nj = float(yz) + (ijk.y*float(tileHeight));\n\n vec2 tpos = vec2(ni/texWidth, nj/texHeight);\n\n vec4 tmp = texture2D(texture1, tpos);\n\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.g = tmp.a;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n#endif\n\n return tmp;\n}\n\n// End of Webgl1 specific code\n//=======================================================================\n#endif\n\n//=======================================================================\n// Given a normal compute the gradient opacity factors\nfloat computeGradientOpacityFactor(\n float normalMag, float goscale, float goshift, float gomin, float gomax)\n{\n#if defined(vtkGradientOpacityOn)\n return clamp(normalMag * goscale + goshift, gomin, gomax);\n#else\n return 1.0;\n#endif\n}\n\n//=======================================================================\n//Rotate gradients to view coordinate\n#if (vtkLightComplexity > 0) || (defined vtkGradientOpacityOn)\nvoid rotateToViewCoord(inout vec3 normalIDX){\n normalIDX.xyz =\n normalIDX.x * vPlaneNormal0 +\n normalIDX.y * vPlaneNormal2 +\n normalIDX.z * vPlaneNormal4;\n}\n#endif\n//=======================================================================\n// compute the normal and gradient magnitude for a position, uses forward difference\n#if vtkLightComplexity > 0\n #ifdef vtkComputeNormalFromOpacity\n #ifdef vtkGradientOpacityOn\n vec4 computeNormalForDensity(vec3 pos, float scalar, vec3 tstep, out mat3 scalarInterp, out vec3 secondaryGradientMag)\n {\n vec4 result;\n scalarInterp[0][0] = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)).a;\n scalarInterp[0][1] = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)).a;\n scalarInterp[0][2] = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)).a;\n // look up scalar values for computing secondary gradient\n scalarInterp[1][0] = getTextureValue(pos + vec3(2.0*tstep.x, 0.0, 0.0)).a;\n scalarInterp[1][1] = getTextureValue(pos + vec3(0.0, 2.0*tstep.y, 0.0)).a;\n scalarInterp[1][2] = getTextureValue(pos + vec3(0.0, 0.0, 2.0*tstep.z)).a;\n scalarInterp[2][0] = getTextureValue(pos + vec3(tstep.x, tstep.y, 0.0)).a;\n scalarInterp[2][1] = getTextureValue(pos + vec3(tstep.x, 0.0, tstep.z)).a;\n scalarInterp[2][2] = getTextureValue(pos + vec3(0.0, tstep.y, tstep.z)).a;\n result.x = scalarInterp[0][0] - scalar;\n result.y = scalarInterp[0][1] - scalar;\n result.z = scalarInterp[0][2] - scalar;\n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz);\n rotateToViewCoord(result.xyz);\n secondaryGradientMag.x = length(vec3(scalarInterp[1][0] - scalarInterp[0][0],\n scalarInterp[2][0] - scalarInterp[0][0],\n scalarInterp[2][1] - scalarInterp[0][0]) / vSpacing);\n secondaryGradientMag.y = length(vec3(scalarInterp[2][0] - scalarInterp[0][1],\n scalarInterp[1][1] - scalarInterp[0][1],\n scalarInterp[2][2] - scalarInterp[0][1]) / vSpacing);\n secondaryGradientMag.z = length(vec3(scalarInterp[2][1] - scalarInterp[0][2],\n scalarInterp[2][2] - scalarInterp[0][2],\n scalarInterp[1][2] - scalarInterp[0][2]) / vSpacing);\n if (length(result.xyz) > 0.0) {\n return vec4(normalize(result.xyz),result.w);\n } else {\n return vec4(0.0);\n }\n }\n\n vec4 computeDensityNormal(float scalar, float gradientMag, mat3 scalarInterp, vec3 secondaryGradientMag)\n {\n vec4 opacityG;\n vec3 opacityInterp = vec3(0.0);\n float opacity = texture2D(otexture, vec2(scalar * oscale0 + oshift0, 0.5)).r;\n if (gradientMag >= 0.0){\n opacity *= computeGradientOpacityFactor(gradientMag, goscale0, goshift0, gomin0, gomax0);\n }\n opacityInterp.x = texture2D(otexture, vec2(scalarInterp[0][0] * oscale0 + oshift0, 0.5)).r; \n if (secondaryGradientMag.x >= 0.0){\n // opacityInterp.x *= computeGradientOpacityFactor(secondaryGradientMag.x, goscale0, goshift0, gomin0, gomax0);\n }\n \n opacityInterp.y = texture2D(otexture, vec2(scalarInterp[0][1] * oscale0 + oshift0, 0.5)).r;\n if (secondaryGradientMag.y >= 0.0){\n // opacityInterp.y *= computeGradientOpacityFactor(secondaryGradientMag.y, goscale0, goshift0, gomin0, gomax0);\n }\n\n opacityInterp.z = texture2D(otexture, vec2(scalarInterp[0][2] * oscale0 + oshift0, 0.5)).r;\n if (secondaryGradientMag.z >= 0.0){\n // opacityInterp.z *= computeGradientOpacityFactor(secondaryGradientMag.z, goscale0, goshift0, gomin0, gomax0);\n }\n\n opacityG.xyz = opacityInterp - vec3(opacity,opacity,opacity);\n // divide by spacing\n opacityG.xyz /= vSpacing;\n opacityG.w = length(opacityG.xyz);\n rotateToViewCoord(opacityG.xyz);\n if (length(opacityG.xyz) > 0.0) { \n return vec4(normalize(opacityG.xyz),opacityG.w);\n } else {\n return vec4(0.0);\n }\n } \n\n #else\n //if gradient opacity not on but using density gradient\n vec4 computeDensityNormal(float scalar, vec3 scalarInterp) \n { \n vec4 opacityG; \n float opacity = texture2D(otexture, vec2(scalar * oscale0 + oshift0, 0.5)).r; \n opacityG.x = texture2D(otexture, vec2(scalarInterp.x * oscale0 + oshift0, 0.5)).r - opacity; \n opacityG.y = texture2D(otexture, vec2(scalarInterp.y * oscale0 + oshift0, 0.5)).r - opacity; \n opacityG.z = texture2D(otexture, vec2(scalarInterp.z * oscale0 + oshift0, 0.5)).r - opacity; \n // divide by spacing \n opacityG.xyz /= vSpacing; \n opacityG.w = length(opacityG.xyz); \n // rotate to View Coords \n rotateToViewCoord(opacityG.xyz);\n if (length(opacityG.xyz) > 0.0) { \n return vec4(normalize(opacityG.xyz),opacityG.w); \n } else { \n return vec4(0.0); \n } \n } \n vec4 computeNormalForDensity(vec3 pos, float scalar, vec3 tstep, out vec3 scalarInterp) \n { \n vec4 result; \n scalarInterp.x = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)).a; \n scalarInterp.y = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)).a; \n scalarInterp.z = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)).a; \n result.x = scalarInterp.x - scalar; \n result.y = scalarInterp.y - scalar; \n result.z = scalarInterp.z - scalar; \n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz); \n // rotate to View Coords \n rotateToViewCoord(result.xyz); \n if (length(result.xyz) > 0.0) { \n return vec4(normalize(result.xyz),result.w); \n } else { \n return vec4(0.0); \n } \n } \n #endif\n #endif\n // compute scalar density\n vec4 computeNormal(vec3 pos, float scalar, vec3 tstep) \n { \n vec4 result; \n result.x = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)).a - scalar; \n result.y = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)).a - scalar; \n result.z = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)).a - scalar; \n // divide by spacing \n result.xyz /= vSpacing; \n result.w = length(result.xyz); \n // rotate to View Coords \n rotateToViewCoord(result.xyz);\n return vec4(normalize(result.xyz),result.w); \n } \n#endif\n\n#ifdef vtkImageLabelOutlineOn\nvec3 fragCoordToIndexSpace(vec4 fragCoord) {\n vec4 pcPos = vec4(\n (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,\n (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,\n (fragCoord.z - 0.5) * 2.0,\n 1.0);\n\n vec4 worldCoord = PCWCMatrix * pcPos;\n vec4 vertex = (worldCoord/worldCoord.w);\n\n vec3 index = (vWCtoIDX * vertex).xyz;\n\n // half voxel fix for labelmapOutline \n return (index + vec3(0.5)) / vec3(volumeDimensions);\n}\n#endif\n\n//=======================================================================\n// compute the normals and gradient magnitudes for a position\n// for independent components\nmat4 computeMat4Normal(vec3 pos, vec4 tValue, vec3 tstep)\n{\n mat4 result;\n vec4 distX = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)) - tValue;\n vec4 distY = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)) - tValue;\n vec4 distZ = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)) - tValue;\n\n // divide by spacing\n distX /= vSpacing.x;\n distY /= vSpacing.y;\n distZ /= vSpacing.z;\n\n mat3 rot;\n rot[0] = vPlaneNormal0;\n rot[1] = vPlaneNormal2;\n rot[2] = vPlaneNormal4;\n\n#if !defined(vtkComponent0Proportional)\n result[0].xyz = vec3(distX.r, distY.r, distZ.r);\n result[0].a = length(result[0].xyz);\n result[0].xyz *= rot;\n if (result[0].w > 0.0)\n {\n result[0].xyz /= result[0].w;\n }\n#endif\n\n// optionally compute the 2nd component\n#if vtkNumComponents >= 2 && !defined(vtkComponent1Proportional)\n result[1].xyz = vec3(distX.g, distY.g, distZ.g);\n result[1].a = length(result[1].xyz);\n result[1].xyz *= rot;\n if (result[1].w > 0.0)\n {\n result[1].xyz /= result[1].w;\n }\n#endif\n\n// optionally compute the 3rd component\n#if vtkNumComponents >= 3 && !defined(vtkComponent2Proportional)\n result[2].xyz = vec3(distX.b, distY.b, distZ.b);\n result[2].a = length(result[2].xyz);\n result[2].xyz *= rot;\n if (result[2].w > 0.0)\n {\n result[2].xyz /= result[2].w;\n }\n#endif\n\n// optionally compute the 4th component\n#if vtkNumComponents >= 4 && !defined(vtkComponent3Proportional)\n result[3].xyz = vec3(distX.a, distY.a, distZ.a);\n result[3].a = length(result[3].xyz);\n result[3].xyz *= rot;\n if (result[3].w > 0.0)\n {\n result[3].xyz /= result[3].w;\n }\n#endif\n\n return result;\n}\n\n//=======================================================================\n// surface light contribution\n\n#if vtkLightComplexity == 3\n// convert vector position from idx to vc\nvec3 IStoVC(vec3 posIS){\n vec3 posVC = posIS / vVCToIJK;\n return posVC.x * vPlaneNormal0 + posVC.y * vPlaneNormal2 + posVC.z * vPlaneNormal4 + vOriginVC;\n}\n#endif\n\n#if vtkLightComplexity > 0\n void applyLighting(inout vec3 tColor, vec4 normal)\n {\n vec3 diffuse = vec3(0.0, 0.0, 0.0);\n vec3 specular = vec3(0.0, 0.0, 0.0);\n float df, sf = 0.0;\n for (int i = 0; i < lightNum; i++){\n df = abs(dot(normal.rgb, -lightDirectionVC[i]));\n diffuse += df * lightColor[i];\n sf = pow( abs(dot(lightHalfAngleVC[i],normal.rgb)), vSpecularPower);\n specular += sf * lightColor[i];\n }\n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular;\n }\n #if vtkLightComplexity < 3\n void applyLightingDirectional(inout vec3 tColor, vec4 normal)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float ndotL,vdotR;\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n } \n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular; \n }\n #else\n void applyLightingPositional(inout vec3 tColor, vec4 normal, vec3 posVC)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float distance,attenuation,ndotL,vdotR;\n vec3 lightDir;\n if (lightPositional[i] == 1){\n lightDir = lightDirectionVC[i];\n vertLightDirection = posVC - lightPositionVC[i]; \n distance = length(vertLightDirection);\n vertLightDirection = normalize(vertLightDirection);\n attenuation = 1.0 / (lightAttenuation[i].x\n + lightAttenuation[i].y * distance\n + lightAttenuation[i].z * distance * distance);\n // per OpenGL standard cone angle is 90 or less for a spot light\n if (lightConeAngle[i] <= 90.0){\n float coneDot = dot(vertLightDirection, lightDir);\n if (coneDot >= cos(radians(lightConeAngle[i]))){ // if inside cone\n attenuation = attenuation * pow(coneDot, lightExponent[i]);\n }\n else {\n attenuation = 0.0;\n }\n }\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * attenuation * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * attenuation * lightColor[i];\n }\n }\n } else {\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n }\n }\n tColor.rgb = tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n }\n #endif \n#endif\n\n//=======================================================================\n// Given a texture value compute the color and opacity\n//\nvec4 getColorForValue(vec4 tValue, vec3 posIS, vec3 tstep)\n{\n#ifdef vtkImageLabelOutlineOn\n vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord); // pos in texture space\n vec4 centerValue = getTextureValue(centerPosIS);\n bool pixelOnBorder = false;\n vec4 tColor = texture2D(ctexture, vec2(centerValue.r * cscale0 + cshift0, 0.5));\n\n // Get alpha of segment from opacity function.\n tColor.a = texture2D(otexture, vec2(centerValue.r * oscale0 + oshift0, 0.5)).r;\n\n // Only perform outline check on fragments rendering voxels that aren't invisible.\n // Saves a bunch of needless checks on the background.\n // TODO define epsilon when building shader?\n if (float(tColor.a) > 0.01) {\n for (int i = -outlineThickness; i <= outlineThickness; i++) {\n for (int j = -outlineThickness; j <= outlineThickness; j++) {\n if (i == 0 || j == 0) {\n continue;\n }\n\n vec4 neighborPixelCoord = vec4(gl_FragCoord.x + float(i),\n gl_FragCoord.y + float(j),\n gl_FragCoord.z, gl_FragCoord.w);\n\n vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);\n vec4 value = getTextureValue(neighborPosIS);\n\n // If any of my neighbours are not the same value as I\n // am, this means I am on the border of the segment.\n // We can break the loops\n if (any(notEqual(value, centerValue))) {\n pixelOnBorder = true;\n break;\n }\n }\n\n if (pixelOnBorder == true) {\n break;\n }\n }\n\n // If I am on the border, I am displayed at full opacity\n if (pixelOnBorder == true) {\n tColor.a = 1.0;\n }\n }\n\n#else\n // compute the normal and gradient magnitude if needed\n // We compute it as a vec4 if possible otherwise a mat4\n //\n vec4 goFactor = vec4(1.0,1.0,1.0,1.0);\n\n // compute the normal vectors as needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n #if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\n mat4 normalMat = computeMat4Normal(posIS, tValue, tstep);\n #if !defined(vtkComponent0Proportional)\n vec4 normal0 = normalMat[0];\n #endif\n #if !defined(vtkComponent1Proportional)\n vec4 normal1 = normalMat[1];\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n vec4 normal2 = normalMat[2];\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n vec4 normal3 = normalMat[3];\n #endif\n #endif\n #endif\n #else\n #ifdef vtkComputeNormalFromOpacity\n #ifdef vtkGradientOpacityOn\n mat3 scalarInterp; \n vec3 secondaryGradientMag; \n vec4 normalOpacity = vec4(0.0); \n vec4 normal0 = computeNormalForDensity(posIS, tValue.a, tstep, scalarInterp, secondaryGradientMag); \n normalOpacity = computeDensityNormal(tValue.a, normal0.w, scalarInterp,secondaryGradientMag); \n if (length(normalOpacity) == 0.0){ \n normalOpacity = normal0; \n } \n #else\n vec3 scalarInterp; \n vec4 normal0 = computeNormalForDensity(posIS, tValue.a, tstep, scalarInterp); \n vec4 normalOpacity; \n if (length(normal0)>0.0){ \n normalOpacity = computeDensityNormal(tValue.a,scalarInterp); \n if (length(normalOpacity)==0.0){ \n normalOpacity = normal0; \n } \n } \n #endif\n #else \n vec4 normal0 = computeNormal(posIS, tValue.a, tstep); \n #endif\n #endif\n #endif\n\n // compute gradient opacity factors as needed\n #if defined(vtkGradientOpacityOn)\n #if !defined(vtkComponent0Proportional)\n goFactor.x =\n computeGradientOpacityFactor(normal0.a, goscale0, goshift0, gomin0, gomax0);\n #endif\n #if defined(vtkIndependentComponentsOn) && (vtkNumComponents > 1)\n #if !defined(vtkComponent1Proportional)\n goFactor.y =\n computeGradientOpacityFactor(normal1.a, goscale1, goshift1, gomin1, gomax1);\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n goFactor.z =\n computeGradientOpacityFactor(normal2.a, goscale2, goshift2, gomin2, gomax2);\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n goFactor.w =\n computeGradientOpacityFactor(normal3.a, goscale3, goshift3, gomin3, gomax3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n // single component is always independent\n #if vtkNumComponents == 1\n vec4 tColor = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, 0.5));\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n #endif\n\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n vec4 tColor = mix0*texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, height0));\n #if !defined(vtkComponent0Proportional)\n tColor.a = goFactor.x*mix0*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n tColor *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix0));\n #endif\n\n vec3 tColor1 = mix1*texture2D(ctexture, vec2(tValue.g * cscale1 + cshift1, height1)).rgb;\n #if !defined(vtkComponent1Proportional)\n tColor.a += goFactor.y*mix1*texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n tColor1 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix1));\n #endif\n\n #if vtkNumComponents >= 3\n vec3 tColor2 = mix2*texture2D(ctexture, vec2(tValue.b * cscale2 + cshift2, height2)).rgb;\n #if !defined(vtkComponent2Proportional)\n tColor.a += goFactor.z*mix2*texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n tColor2 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix2));\n #endif\n\n #if vtkNumComponents >= 4\n vec3 tColor3 = mix3*texture2D(ctexture, vec2(tValue.a * cscale3 + cshift3, height3)).rgb;\n #if !defined(vtkComponent3Proportional)\n tColor.a += goFactor.w*mix3*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n #else\n float pwfValue = texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n tColor3 *= pwfValue;\n tColor.a *= mix(pwfValue, 1.0, (1.0 - mix3));\n #endif\n #endif\n #endif\n #else // then not independent\n\n #if vtkNumComponents == 2\n float lum = tValue.r * cscale0 + cshift0;\n float alpha = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale1 + oshift1, 0.5)).r;\n vec4 tColor = vec4(lum, lum, lum, alpha);\n #endif\n #if vtkNumComponents == 3\n vec4 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale0 + oshift0, 0.5)).r;\n #endif\n #if vtkNumComponents == 4\n vec4 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n tColor.a = goFactor.x*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, 0.5)).r;\n #endif\n #endif // dependent\n\n // apply lighting if requested as appropriate\n #if vtkLightComplexity > 0\n #if !defined(vtkComponent0Proportional)\n #if vtkLightComplexity < 3\n #ifdef vtkComputeNormalFromOpacity\n applyLightingDirectional(tColor.rgb, normalOpacity);\n #else\n applyLightingDirectional(tColor.rgb, normal0);\n #endif\n #else\n #ifdef vtkComputeNormalFromOpacity\n applyLightingPositional(tColor.rgb, normalOpacity, IStoVC(posIS)); \n #else\n applyLightingPositional(tColor.rgb, normal0, IStoVC(posIS)); \n #endif\n #endif\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n #if !defined(vtkComponent1Proportional)\n applyLighting(tColor1, normal1);\n #endif\n #if vtkNumComponents >= 3\n #if !defined(vtkComponent2Proportional)\n applyLighting(tColor2, normal2);\n #endif\n #if vtkNumComponents >= 4\n #if !defined(vtkComponent3Proportional)\n applyLighting(tColor3, normal3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n// perform final independent blend as needed\n#if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 2\n tColor.rgb += tColor1;\n#if vtkNumComponents >= 3\n tColor.rgb += tColor2;\n#if vtkNumComponents >= 4\n tColor.rgb += tColor3;\n#endif\n#endif\n#endif\n\n#endif\n\n\n\n\n\n\n\nreturn tColor;\n}\n\nbool valueWithinScalarRange(vec4 val, vec4 min, vec4 max) {\n bool withinRange = false;\n #if vtkNumComponents == 1\n if (val.r >= min.r && val.r <= max.r) {\n withinRange = true;\n }\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents == 2\n if (val.r >= min.r && val.r <= max.r &&\n val.g >= min.g && val.g <= max.g) {\n withinRange = true;\n }\n #endif\n #if defined(vtkIndependentComponentsOn) && vtkNumComponents >= 3\n if (all(greaterThanEqual(val, ipScalarRangeMin)) &&\n all(lessThanEqual(val, ipScalarRangeMax))) {\n withinRange = true;\n }\n #endif\n return withinRange;\n}\n\n//=======================================================================\n// Apply the specified blend mode operation along the ray's path.\n//\nvoid applyBlend(vec3 posIS, vec3 endIS, float sampleDistanceIS, vec3 tdims)\n{\n vec3 tstep = 1.0/tdims;\n\n // start slightly inside and apply some jitter\n vec3 delta = endIS - posIS;\n vec3 stepIS = normalize(delta)*sampleDistanceIS;\n float raySteps = length(delta)/sampleDistanceIS;\n\n // avoid 0.0 jitter\n float jitter = 0.01 + 0.99*texture2D(jtexture, gl_FragCoord.xy/32.0).r;\n float stepsTraveled = jitter;\n\n // local vars for the loop\n vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n vec4 tValue;\n vec4 tColor;\n\n // if we have less than one step then pick the middle point\n // as our value\n // if (raySteps <= 1.0)\n // {\n // posIS = (posIS + endIS)*0.5;\n // }\n\n // Perform initial step at the volume boundary\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n #if vtkBlendMode == 0 // COMPOSITE_BLEND\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps);\n gl_FragData[0] = tColor;\n return;\n }\n\n tColor.a = 1.0 - pow(1.0 - tColor.a, jitter);\n color = vec4(tColor.rgb*tColor.a, tColor.a);\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n float mix = (1.0 - color.a);\n\n // this line should not be needed but nvidia seems to not handle\n // the break correctly on windows/chrome 58 angle\n //mix = mix * sign(max(raySteps - stepsTraveled - 1.0, 0.0));\n\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n stepsTraveled++;\n posIS += stepIS;\n if (color.a > 0.99) { color.a = 1.0; break; }\n }\n\n if (color.a < 0.99 && (raySteps - stepsTraveled) > 0.0)\n {\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps - stepsTraveled);\n\n float mix = (1.0 - color.a);\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n }\n\n gl_FragData[0] = vec4(color.rgb/color.a, color.a);\n #endif\n #if vtkBlendMode == 1 || vtkBlendMode == 2\n // MAXIMUM_INTENSITY_BLEND || MINIMUM_INTENSITY_BLEND\n // Find maximum/minimum intensity along the ray.\n\n // Define the operation we will use (min or max)\n #if vtkBlendMode == 1\n #define OP max\n #else\n #define OP min\n #endif\n\n // If the clipping range is shorter than the sample distance\n // we can skip the sampling loop along the ray.\n if (raySteps <= 1.0)\n {\n gl_FragData[0] = getColorForValue(tValue, posIS, tstep);\n return;\n }\n\n vec4 value = tValue;\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // Update the maximum value if necessary\n value = OP(tValue, value);\n\n // Otherwise, continue along the ray\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n tValue = getTextureValue(posIS);\n value = OP(tValue, value);\n\n // Now map through opacity and color\n gl_FragData[0] = getColorForValue(value, posIS, tstep);\n #endif\n #if vtkBlendMode == 3 || vtkBlendMode == 4 //AVERAGE_INTENSITY_BLEND || ADDITIVE_BLEND\n vec4 sum = vec4(0.);\n\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n }\n\n if (raySteps <= 1.0) {\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n return;\n }\n\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the AverageIPScalarRange to disregard scalar values, not in the range of interest, from the average computation.\n // Notes:\n // - We are comparing all values in the texture to see if any of them\n // are outside of the scalar range. In the future we might want to allow\n // scalar ranges for each component.\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n // Sum the values across each step in the path\n sum += tValue;\n }\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the IPScalarRange to disregard scalar values, not in the range of interest, from the average computation\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n\n stepsTraveled++;\n }\n\n #if vtkBlendMode == 3 // Average\n sum /= vec4(stepsTraveled, stepsTraveled, stepsTraveled, 1.0);\n #endif\n\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n #endif\n}\n\n//=======================================================================\n// Compute a new start and end point for a given ray based\n// on the provided bounded clipping plane (aka a rectangle)\nvoid getRayPointIntersectionBounds(\n vec3 rayPos, vec3 rayDir,\n vec3 planeDir, float planeDist,\n inout vec2 tbounds, vec3 vPlaneX, vec3 vPlaneY,\n float vSize1, float vSize2)\n{\n float result = dot(rayDir, planeDir);\n if (abs(result) < 1e-6)\n {\n return;\n }\n result = -1.0 * (dot(rayPos, planeDir) + planeDist) / result;\n vec3 xposVC = rayPos + rayDir*result;\n vec3 vxpos = xposVC - vOriginVC;\n vec2 vpos = vec2(\n dot(vxpos, vPlaneX),\n dot(vxpos, vPlaneY));\n\n // on some apple nvidia systems this does not work\n // if (vpos.x < 0.0 || vpos.x > vSize1 ||\n // vpos.y < 0.0 || vpos.y > vSize2)\n // even just\n // if (vpos.x < 0.0 || vpos.y < 0.0)\n // fails\n // so instead we compute a value that represents in and out\n //and then compute the return using this value\n float xcheck = max(0.0, vpos.x * (vpos.x - vSize1)); // 0 means in bounds\n float check = sign(max(xcheck, vpos.y * (vpos.y - vSize2))); // 0 means in bounds, 1 = out\n\n tbounds = mix(\n vec2(min(tbounds.x, result), max(tbounds.y, result)), // in value\n tbounds, // out value\n check); // 0 in 1 out\n}\n\n//=======================================================================\n// given a\n// - ray direction (rayDir)\n// - starting point (vertexVCVSOutput)\n// - bounding planes of the volume\n// - optionally depth buffer values\n// - far clipping plane\n// compute the start/end distances of the ray we need to cast\nvec2 computeRayDistances(vec3 rayDir, vec3 tdims)\n{\n vec2 dists = vec2(100.0*camFar, -1.0);\n\n vec3 vSize = vSpacing*tdims;\n\n // all this is in View Coordinates\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal0, vPlaneDistance0, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal1, vPlaneDistance1, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal2, vPlaneDistance2, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal3, vPlaneDistance3, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal4, vPlaneDistance4, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal5, vPlaneDistance5, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n\n //VTK::ClipPlane::Impl\n\n // do not go behind front clipping plane\n dists.x = max(0.0,dists.x);\n\n // do not go PAST far clipping plane\n float farDist = -camThick/rayDir.z;\n dists.y = min(farDist,dists.y);\n\n // Do not go past the zbuffer value if set\n // This is used for intermixing opaque geometry\n //VTK::ZBuffer::Impl\n\n return dists;\n}\n\n//=======================================================================\n// Compute the index space starting position (pos) and end\n// position\n//\nvoid computeIndexSpaceValues(out vec3 pos, out vec3 endPos, out float sampleDistanceIS, vec3 rayDir, vec2 dists)\n{\n // compute starting and ending values in volume space\n pos = vertexVCVSOutput + dists.x*rayDir;\n pos = pos - vOriginVC;\n // convert to volume basis and origin\n pos = vec3(\n dot(pos, vPlaneNormal0),\n dot(pos, vPlaneNormal2),\n dot(pos, vPlaneNormal4));\n\n endPos = vertexVCVSOutput + dists.y*rayDir;\n endPos = endPos - vOriginVC;\n endPos = vec3(\n dot(endPos, vPlaneNormal0),\n dot(endPos, vPlaneNormal2),\n dot(endPos, vPlaneNormal4));\n\n float delta = length(endPos - pos);\n\n pos *= vVCToIJK;\n endPos *= vVCToIJK;\n\n float delta2 = length(endPos - pos);\n sampleDistanceIS = sampleDistance*delta2/delta;\n}\n\nvoid main()\n{\n\n if (cameraParallel == 1)\n {\n // Camera is parallel, so the rayDir is just the direction of the camera.\n rayDirVC = vec3(0.0, 0.0, -1.0);\n } else {\n // camera is at 0,0,0 so rayDir for perspective is just the vc coord\n rayDirVC = normalize(vertexVCVSOutput);\n }\n\n vec3 tdims = vec3(volumeDimensions);\n\n // compute the start and end points for the ray\n vec2 rayStartEndDistancesVC = computeRayDistances(rayDirVC, tdims);\n\n // do we need to composite? aka does the ray have any length\n // If not, bail out early\n if (rayStartEndDistancesVC.y <= rayStartEndDistancesVC.x)\n {\n discard;\n }\n\n // IS = Index Space\n vec3 posIS;\n vec3 endIS;\n float sampleDistanceIS;\n computeIndexSpaceValues(posIS, endIS, sampleDistanceIS, rayDirVC, rayStartEndDistancesVC);\n\n // Perform the blending operation along the ray\n applyBlend(posIS, endIS, sampleDistanceIS, tdims);\n}\n";
|
|
2
2
|
|
|
3
3
|
export { vtkVolumeFS as v };
|