@niivue/niivue 0.24.3 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -17
- package/dist/niivue.es.js +2796 -520
- package/dist/niivue.umd.js +303 -142
- package/package.json +1 -1
- package/src/colortables.js +1 -1
- package/src/index.html +3 -2
- package/src/indexDraw.html +7 -2
- package/src/indexMM.html +229 -0
- package/src/indexModulate.html +223 -0
- package/src/niivue.js +1657 -575
- package/src/nvimage.js +125 -26
- package/src/shader-srcs.js +209 -59
package/src/nvimage.js
CHANGED
|
@@ -52,7 +52,8 @@ export function NVImage(
|
|
|
52
52
|
ignoreZeroVoxels = false,
|
|
53
53
|
visible = true,
|
|
54
54
|
isDICOMDIR = false,
|
|
55
|
-
useQFormNotSForm = false
|
|
55
|
+
useQFormNotSForm = false,
|
|
56
|
+
colorMapNegative = ""
|
|
56
57
|
) {
|
|
57
58
|
// https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h
|
|
58
59
|
this.DT_NONE = 0;
|
|
@@ -84,7 +85,9 @@ export function NVImage(
|
|
|
84
85
|
this.percentileFrac = percentileFrac;
|
|
85
86
|
this.ignoreZeroVoxels = ignoreZeroVoxels;
|
|
86
87
|
this.trustCalMinMax = trustCalMinMax;
|
|
88
|
+
this.colorMapNegative = colorMapNegative;
|
|
87
89
|
this.visible = visible;
|
|
90
|
+
this.modulationImage = null;
|
|
88
91
|
this.series = []; // for concatenating dicom images
|
|
89
92
|
|
|
90
93
|
// Added to support zerosLike
|
|
@@ -381,7 +384,36 @@ export function NVImage(
|
|
|
381
384
|
this.calMinMax();
|
|
382
385
|
}
|
|
383
386
|
|
|
387
|
+
NVImage.prototype.computeObliqueAngle = function (mtx44) {
|
|
388
|
+
//https://github.com/afni/afni/blob/25e77d564f2c67ff480fa99a7b8e48ec2d9a89fc/src/thd_coords.c#L717
|
|
389
|
+
let mtx = mat4.clone(mtx44);
|
|
390
|
+
mat4.transpose(mtx, mtx44);
|
|
391
|
+
let dxtmp = Math.sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1] + mtx[2] * mtx[2]);
|
|
392
|
+
let xmax =
|
|
393
|
+
Math.max(Math.max(Math.abs(mtx[0]), Math.abs(mtx[1])), Math.abs(mtx[2])) /
|
|
394
|
+
dxtmp;
|
|
395
|
+
let dytmp = Math.sqrt(mtx[4] * mtx[4] + mtx[5] * mtx[5] + mtx[6] * mtx[6]);
|
|
396
|
+
let ymax =
|
|
397
|
+
Math.max(Math.max(Math.abs(mtx[4]), Math.abs(mtx[5])), Math.abs(mtx[6])) /
|
|
398
|
+
dytmp;
|
|
399
|
+
let dztmp = Math.sqrt(mtx[8] * mtx[8] + mtx[9] * mtx[9] + mtx[10] * mtx[10]);
|
|
400
|
+
let zmax =
|
|
401
|
+
Math.max(Math.max(Math.abs(mtx[8]), Math.abs(mtx[9])), Math.abs(mtx[10])) /
|
|
402
|
+
dztmp;
|
|
403
|
+
let fig_merit = Math.min(Math.min(xmax, ymax), zmax);
|
|
404
|
+
let oblique_angle = Math.abs((Math.acos(fig_merit) * 180.0) / 3.141592653);
|
|
405
|
+
if (oblique_angle > 0.01)
|
|
406
|
+
console.log(
|
|
407
|
+
"Warning voxels not aligned with world space: " +
|
|
408
|
+
oblique_angle +
|
|
409
|
+
" degrees from plumb.\n"
|
|
410
|
+
);
|
|
411
|
+
else oblique_angle = 0.0;
|
|
412
|
+
return oblique_angle;
|
|
413
|
+
};
|
|
414
|
+
|
|
384
415
|
NVImage.prototype.calculateOblique = function () {
|
|
416
|
+
this.oblique_angle = this.computeObliqueAngle(this.matRAS);
|
|
385
417
|
let LPI = this.vox2mm([0.0, 0.0, 0.0], this.matRAS);
|
|
386
418
|
let X1mm = this.vox2mm([1.0 / this.pixDimsRAS[1], 0.0, 0.0], this.matRAS);
|
|
387
419
|
let Y1mm = this.vox2mm([0.0, 1.0 / this.pixDimsRAS[2], 0.0], this.matRAS);
|
|
@@ -414,6 +446,28 @@ NVImage.prototype.calculateOblique = function () {
|
|
|
414
446
|
let maxShear = Math.max(Math.max(XY, XZ), YZ);
|
|
415
447
|
if (maxShear > 0.1)
|
|
416
448
|
log.debug("Warning: shear detected (gantry tilt) of %f degrees", maxShear);
|
|
449
|
+
//compute a matrix to transform vectors from factional space to mm:
|
|
450
|
+
let dim = vec4.fromValues(
|
|
451
|
+
this.dimsRAS[1],
|
|
452
|
+
this.dimsRAS[2],
|
|
453
|
+
this.dimsRAS[3],
|
|
454
|
+
1
|
|
455
|
+
);
|
|
456
|
+
let sform = mat4.clone(this.matRAS);
|
|
457
|
+
mat4.transpose(sform, sform);
|
|
458
|
+
let shim = vec4.fromValues(-0.5, -0.5, -0.5, 0); //bitmap with 5 voxels scaled 0..1, voxel centers are 0.1,0.3,0.5,0.7,0.9
|
|
459
|
+
mat4.translate(sform, sform, shim);
|
|
460
|
+
//mat.mat4.scale(sform, sform, dim);
|
|
461
|
+
sform[0] *= dim[0];
|
|
462
|
+
sform[1] *= dim[0];
|
|
463
|
+
sform[2] *= dim[0];
|
|
464
|
+
sform[4] *= dim[1];
|
|
465
|
+
sform[5] *= dim[1];
|
|
466
|
+
sform[6] *= dim[1];
|
|
467
|
+
sform[8] *= dim[2];
|
|
468
|
+
sform[9] *= dim[2];
|
|
469
|
+
sform[10] *= dim[2];
|
|
470
|
+
this.frac2mm = mat4.clone(sform);
|
|
417
471
|
};
|
|
418
472
|
|
|
419
473
|
NVImage.prototype.THD_daxes_to_NIFTI = function (
|
|
@@ -2206,6 +2260,7 @@ NVImage.loadFromUrl = async function ({
|
|
|
2206
2260
|
percentileFrac = 0.02,
|
|
2207
2261
|
ignoreZeroVoxels = false,
|
|
2208
2262
|
visible = true,
|
|
2263
|
+
colorMapNegative = "",
|
|
2209
2264
|
} = {}) {
|
|
2210
2265
|
if (url === "") {
|
|
2211
2266
|
throw Error("url must not be empty");
|
|
@@ -2251,7 +2306,10 @@ NVImage.loadFromUrl = async function ({
|
|
|
2251
2306
|
trustCalMinMax,
|
|
2252
2307
|
percentileFrac,
|
|
2253
2308
|
ignoreZeroVoxels,
|
|
2254
|
-
visible
|
|
2309
|
+
visible,
|
|
2310
|
+
false,
|
|
2311
|
+
false,
|
|
2312
|
+
colorMapNegative
|
|
2255
2313
|
);
|
|
2256
2314
|
} else {
|
|
2257
2315
|
alert("Unable to load buffer properly from volume");
|
|
@@ -2589,27 +2647,23 @@ function getExtents(positions, forceOriginInVolume = true) {
|
|
|
2589
2647
|
*/
|
|
2590
2648
|
NVImage.prototype.toNiivueObject3D = function (id, gl) {
|
|
2591
2649
|
//cube has 8 vertices: left/right, posterior/anterior, inferior/superior
|
|
2592
|
-
|
|
2593
|
-
//
|
|
2594
|
-
let
|
|
2595
|
-
let
|
|
2596
|
-
let
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
let
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
);
|
|
2605
|
-
let
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
);
|
|
2609
|
-
let RAS = this.vox2mm(
|
|
2610
|
-
[this.dimsRAS[1] - 1, this.dimsRAS[2] - 1, this.dimsRAS[3] - 1],
|
|
2611
|
-
this.matRAS
|
|
2612
|
-
);
|
|
2650
|
+
//n.b. voxel coordinates are from VOXEL centers
|
|
2651
|
+
// add/subtract 0.5 to get full image field of view
|
|
2652
|
+
let L = -0.5;
|
|
2653
|
+
let P = -0.5;
|
|
2654
|
+
let I = -0.5;
|
|
2655
|
+
let R = this.dimsRAS[1] - 1 + 0.5;
|
|
2656
|
+
let A = this.dimsRAS[2] - 1 + 0.5;
|
|
2657
|
+
let S = this.dimsRAS[3] - 1 + 0.5;
|
|
2658
|
+
|
|
2659
|
+
let LPI = this.vox2mm([L, P, I], this.matRAS);
|
|
2660
|
+
let LAI = this.vox2mm([L, A, I], this.matRAS);
|
|
2661
|
+
let LPS = this.vox2mm([L, P, S], this.matRAS);
|
|
2662
|
+
let LAS = this.vox2mm([L, A, S], this.matRAS);
|
|
2663
|
+
let RPI = this.vox2mm([R, P, I], this.matRAS);
|
|
2664
|
+
let RAI = this.vox2mm([R, A, I], this.matRAS);
|
|
2665
|
+
let RPS = this.vox2mm([R, P, S], this.matRAS);
|
|
2666
|
+
let RAS = this.vox2mm([R, A, S], this.matRAS);
|
|
2613
2667
|
|
|
2614
2668
|
let posTex = [
|
|
2615
2669
|
//spatial position (XYZ), texture coordinates UVW
|
|
@@ -2712,7 +2766,6 @@ NVImage.prototype.toNiivueObject3D = function (id, gl) {
|
|
|
2712
2766
|
indexBuffer,
|
|
2713
2767
|
vao
|
|
2714
2768
|
);
|
|
2715
|
-
|
|
2716
2769
|
const extents = getExtents([
|
|
2717
2770
|
...LPS,
|
|
2718
2771
|
...RPS,
|
|
@@ -2723,10 +2776,56 @@ NVImage.prototype.toNiivueObject3D = function (id, gl) {
|
|
|
2723
2776
|
...RAI,
|
|
2724
2777
|
...RPI,
|
|
2725
2778
|
]);
|
|
2726
|
-
obj3D.extentsMin = extents.min;
|
|
2727
|
-
obj3D.extentsMax = extents.max;
|
|
2779
|
+
obj3D.extentsMin = extents.min.slice();
|
|
2780
|
+
obj3D.extentsMax = extents.max.slice();
|
|
2781
|
+
|
|
2728
2782
|
obj3D.furthestVertexFromOrigin = extents.furthestVertexFromOrigin;
|
|
2729
2783
|
obj3D.originNegate = vec3.clone(extents.origin);
|
|
2730
2784
|
vec3.negate(obj3D.originNegate, obj3D.originNegate);
|
|
2785
|
+
/*
|
|
2786
|
+
let matDeOblique = mat4.fromValues(
|
|
2787
|
+
this.pixDimsRAS[1],
|
|
2788
|
+
0,
|
|
2789
|
+
0,
|
|
2790
|
+
this.matRAS[3],
|
|
2791
|
+
0,
|
|
2792
|
+
this.pixDimsRAS[2],
|
|
2793
|
+
0,
|
|
2794
|
+
this.matRAS[7],
|
|
2795
|
+
0,
|
|
2796
|
+
0,
|
|
2797
|
+
this.pixDimsRAS[3],
|
|
2798
|
+
this.matRAS[11],
|
|
2799
|
+
0,
|
|
2800
|
+
0,
|
|
2801
|
+
0,
|
|
2802
|
+
1
|
|
2803
|
+
);
|
|
2804
|
+
LPI = this.vox2mm([L,P,I], matDeOblique);
|
|
2805
|
+
LAI = this.vox2mm([L,A,I], matDeOblique);
|
|
2806
|
+
LPS = this.vox2mm([L,P,S], matDeOblique);
|
|
2807
|
+
LAS = this.vox2mm([L,A,S], matDeOblique);
|
|
2808
|
+
RPI = this.vox2mm([R,P,I], matDeOblique);
|
|
2809
|
+
RAI = this.vox2mm([R,A,I], matDeOblique);
|
|
2810
|
+
RPS = this.vox2mm([R,P,S], matDeOblique);
|
|
2811
|
+
RAS = this.vox2mm([R,A,S], matDeOblique);
|
|
2812
|
+
const extentsDeOblique = getExtents([
|
|
2813
|
+
...LPS,
|
|
2814
|
+
...RPS,
|
|
2815
|
+
...RAS,
|
|
2816
|
+
...LAS,
|
|
2817
|
+
...LPI,
|
|
2818
|
+
...LAI,
|
|
2819
|
+
...RAI,
|
|
2820
|
+
...RPI,
|
|
2821
|
+
]);
|
|
2822
|
+
obj3D.extentsDeObliqueMin = extentsDeOblique.min.slice();
|
|
2823
|
+
obj3D.extentsDeObliqueMax = extentsDeOblique.max.slice();
|
|
2824
|
+
*/
|
|
2825
|
+
obj3D.fieldOfViewDeObliqueMM = [
|
|
2826
|
+
this.dimsRAS[1] * this.pixDimsRAS[1],
|
|
2827
|
+
this.dimsRAS[2] * this.pixDimsRAS[2],
|
|
2828
|
+
this.dimsRAS[3] * this.pixDimsRAS[3],
|
|
2829
|
+
];
|
|
2731
2830
|
return obj3D;
|
|
2732
2831
|
};
|
package/src/shader-srcs.js
CHANGED
|
@@ -130,12 +130,13 @@ void main() {
|
|
|
130
130
|
while (samplePos.a <= len) {
|
|
131
131
|
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
132
132
|
samplePos += deltaDir; //advance ray position
|
|
133
|
-
if (colorSample.a
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
if (colorSample.a >= 0.01) {
|
|
134
|
+
if (firstHit.a > lenNoClip)
|
|
135
|
+
firstHit = samplePos;
|
|
136
|
+
backNearest = min(backNearest, samplePos.a);
|
|
137
|
+
if (colorSample.a > colAcc.a) //ties generate errors for TT_desai_dd_mpm
|
|
138
|
+
colAcc = vec4(colorSample.rgb, colorSample.a+0.00001);
|
|
139
|
+
}
|
|
139
140
|
}
|
|
140
141
|
if (firstHit.a < len)
|
|
141
142
|
gl_FragDepth = frac2ndc(firstHit.xyz);
|
|
@@ -171,15 +172,16 @@ void main() {
|
|
|
171
172
|
while (samplePos.a <= len) {
|
|
172
173
|
vec4 colorSample = texture(overlay, samplePos.xyz);
|
|
173
174
|
samplePos += deltaDir; //advance ray position
|
|
174
|
-
if (colorSample.a
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
if (colorSample.a >= 0.01) {
|
|
176
|
+
if (overFirstHit.a > len)
|
|
177
|
+
overFirstHit = samplePos;
|
|
178
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
179
|
+
colorSample.rgb *= colorSample.a;
|
|
180
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
181
|
+
overFarthest = samplePos.a;
|
|
182
|
+
if ( colAcc.a > earlyTermination )
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
183
185
|
}
|
|
184
186
|
if (overFirstHit.a < firstHit.a)
|
|
185
187
|
//if (overFirstHit.a < len)
|
|
@@ -231,6 +233,10 @@ float frac2ndc(vec3 frac) {
|
|
|
231
233
|
|
|
232
234
|
}
|
|
233
235
|
void main() {
|
|
236
|
+
if (fColor.x > 2.0) {
|
|
237
|
+
fColor = vec4(1.0, 0.0, 0.0, 0.5);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
234
240
|
fColor = vec4(0.0,0.0,0.0,0.0);
|
|
235
241
|
vec4 clipPlaneColorX = clipPlaneColor;
|
|
236
242
|
//if (clipPlaneColor.a < 0.0)
|
|
@@ -266,19 +272,23 @@ void main() {
|
|
|
266
272
|
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
267
273
|
while (samplePos.a <= len) {
|
|
268
274
|
float val = texture(volume, samplePos.xyz).a;
|
|
269
|
-
|
|
275
|
+
if (val > 0.01) {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
270
278
|
samplePos += deltaDirFast; //advance ray position
|
|
271
279
|
}
|
|
272
280
|
if ((samplePos.a >= len) && ((overlays < 1.0) || (backgroundMasksOverlays > 0))) {
|
|
273
|
-
|
|
281
|
+
if (isClip){
|
|
274
282
|
fColor += clipPlaneColorX;
|
|
283
|
+
}
|
|
275
284
|
return;
|
|
276
285
|
}
|
|
277
286
|
fColor = vec4(1.0, 1.0, 1.0, 1.0);
|
|
278
287
|
//gl_FragDepth = frac2ndc(samplePos.xyz); //crude due to fast pass resolution
|
|
279
288
|
samplePos -= deltaDirFast;
|
|
280
|
-
|
|
289
|
+
if (samplePos.a < 0.0){
|
|
281
290
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
291
|
+
}
|
|
282
292
|
//end: fast pass
|
|
283
293
|
vec4 colAcc = vec4(0.0,0.0,0.0,0.0);
|
|
284
294
|
vec4 firstHit = vec4(0.0,0.0,0.0,2.0 * lenNoClip);
|
|
@@ -289,25 +299,29 @@ void main() {
|
|
|
289
299
|
while (samplePos.a <= len) {
|
|
290
300
|
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
291
301
|
samplePos += deltaDir; //advance ray position
|
|
292
|
-
if (colorSample.a
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
if (colorSample.a >= 0.01) {
|
|
303
|
+
if (firstHit.a > lenNoClip)
|
|
304
|
+
firstHit = samplePos;
|
|
305
|
+
backNearest = min(backNearest, samplePos.a);
|
|
306
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
307
|
+
colorSample.rgb *= colorSample.a;
|
|
308
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
309
|
+
if ( colAcc.a > earlyTermination )
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
301
312
|
}
|
|
302
|
-
|
|
313
|
+
if (firstHit.a < len){
|
|
303
314
|
gl_FragDepth = frac2ndc(firstHit.xyz);
|
|
315
|
+
}
|
|
304
316
|
colAcc.a = (colAcc.a / earlyTermination) * backOpacity;
|
|
305
317
|
fColor = colAcc;
|
|
306
318
|
//if (isClip) //CR
|
|
307
319
|
if ((isColorPlaneInVolume) && (clipPos.a != samplePos.a) && (abs(firstHit.a - clipPos.a) < deltaDir.a))
|
|
308
320
|
fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, abs(clipPlaneColor.a));
|
|
309
321
|
//fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, clipPlaneColorX.a * 0.65);
|
|
310
|
-
|
|
322
|
+
if (overlays < 1.0) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
311
325
|
//overlay pass
|
|
312
326
|
len = lenNoClip;
|
|
313
327
|
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
@@ -316,48 +330,56 @@ void main() {
|
|
|
316
330
|
deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
317
331
|
while (samplePos.a <= len) {
|
|
318
332
|
float val = texture(overlay, samplePos.xyz).a;
|
|
319
|
-
|
|
333
|
+
if (val > 0.01) {
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
320
336
|
samplePos += deltaDirFast; //advance ray position
|
|
321
337
|
}
|
|
322
338
|
if (samplePos.a >= len) {
|
|
323
|
-
|
|
339
|
+
if (isClip && (fColor.a == 0.0)) {
|
|
324
340
|
fColor += clipPlaneColorX;
|
|
341
|
+
}
|
|
325
342
|
return;
|
|
326
343
|
}
|
|
327
344
|
samplePos -= deltaDirFast;
|
|
328
|
-
|
|
345
|
+
if (samplePos.a < 0.0){
|
|
329
346
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
347
|
+
}
|
|
330
348
|
//end: fast pass
|
|
331
349
|
float overFarthest = len;
|
|
332
350
|
colAcc = vec4(0.0, 0.0, 0.0, 0.0);
|
|
333
351
|
samplePos += deltaDir * ran; //jitter ray
|
|
334
352
|
vec4 overFirstHit = vec4(0.0,0.0,0.0,2.0 * len);
|
|
335
|
-
|
|
353
|
+
if (backgroundMasksOverlays > 0){
|
|
336
354
|
samplePos = firstHit;
|
|
355
|
+
}
|
|
337
356
|
while (samplePos.a <= len) {
|
|
338
357
|
vec4 colorSample = texture(overlay, samplePos.xyz);
|
|
339
358
|
samplePos += deltaDir; //advance ray position
|
|
340
|
-
if (colorSample.a
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
359
|
+
if (colorSample.a >= 0.01) {
|
|
360
|
+
if (overFirstHit.a > len)
|
|
361
|
+
overFirstHit = samplePos;
|
|
362
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
363
|
+
colorSample.rgb *= colorSample.a;
|
|
364
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
365
|
+
overFarthest = samplePos.a;
|
|
366
|
+
if ( colAcc.a > earlyTermination )
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
349
369
|
}
|
|
350
370
|
if (samplePos.a >= len) {
|
|
351
|
-
|
|
371
|
+
if (isClip && (fColor.a == 0.0)){
|
|
352
372
|
fColor += clipPlaneColorX;
|
|
373
|
+
}
|
|
353
374
|
return;
|
|
354
375
|
}
|
|
355
376
|
//if (overFirstHit.a < len)
|
|
356
|
-
|
|
377
|
+
gl_FragDepth = frac2ndc(overFirstHit.xyz);
|
|
357
378
|
float overMix = colAcc.a;
|
|
358
379
|
float overlayDepth = 0.3;
|
|
359
|
-
|
|
380
|
+
if (fColor.a <= 0.0){
|
|
360
381
|
overMix = 1.0;
|
|
382
|
+
}
|
|
361
383
|
else if (((overFarthest) > backNearest)) {
|
|
362
384
|
float dx = (overFarthest - backNearest)/1.73;
|
|
363
385
|
dx = fColor.a * pow(dx, overlayDepth);
|
|
@@ -373,15 +395,22 @@ layout(location=0) in vec3 pos;
|
|
|
373
395
|
uniform int axCorSag;
|
|
374
396
|
uniform float slice;
|
|
375
397
|
uniform vec2 canvasWidthHeight;
|
|
398
|
+
uniform vec3 panXYscale;
|
|
376
399
|
uniform vec4 leftTopWidthHeight;
|
|
377
400
|
out vec3 texPos;
|
|
378
401
|
void main(void) {
|
|
379
402
|
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
380
403
|
vec2 frac;
|
|
381
|
-
|
|
382
|
-
frac.
|
|
404
|
+
vec3 vpos = pos;
|
|
405
|
+
frac.x = (leftTopWidthHeight.x + (vpos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
406
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - vpos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
407
|
+
//frac.x = pos.x; //0..1
|
|
408
|
+
//frac.y = pos.y; //1..0
|
|
409
|
+
|
|
383
410
|
frac = (frac * 2.0) - 1.0;
|
|
384
411
|
gl_Position = vec4(frac, 0.0, 1.0);
|
|
412
|
+
gl_Position.x += panXYscale.x;
|
|
413
|
+
gl_Position.y += panXYscale.y;
|
|
385
414
|
if (axCorSag == 1)
|
|
386
415
|
texPos = vec3(pos.x, slice, pos.y);
|
|
387
416
|
else if (axCorSag == 2)
|
|
@@ -432,7 +461,70 @@ void main() {
|
|
|
432
461
|
color.a = aout;
|
|
433
462
|
}`;
|
|
434
463
|
|
|
435
|
-
export var
|
|
464
|
+
export var vertSliceMMShader = `#version 300 es
|
|
465
|
+
#line 4
|
|
466
|
+
layout(location=0) in vec3 pos;
|
|
467
|
+
uniform int axCorSag;
|
|
468
|
+
uniform mat4 mvpMtx;
|
|
469
|
+
uniform mat4 frac2mm;
|
|
470
|
+
uniform float slice;
|
|
471
|
+
out vec3 texPos;
|
|
472
|
+
void main(void) {
|
|
473
|
+
texPos = vec3(pos.x, pos.y, slice);
|
|
474
|
+
if (axCorSag > 1)
|
|
475
|
+
texPos = vec3(slice, pos.x, pos.y);
|
|
476
|
+
else if (axCorSag > 0)
|
|
477
|
+
texPos = vec3(pos.x, slice, pos.y);
|
|
478
|
+
vec4 mm = frac2mm * vec4(texPos, 1.0);
|
|
479
|
+
//vec4 mm = vec4(texPos, 1.0) * frac2mm;
|
|
480
|
+
gl_Position = mvpMtx * mm;
|
|
481
|
+
//gl_Position = mm;
|
|
482
|
+
}`;
|
|
483
|
+
|
|
484
|
+
export var fragSliceMMShader = `#version 300 es
|
|
485
|
+
#line 228
|
|
486
|
+
precision highp int;
|
|
487
|
+
precision highp float;
|
|
488
|
+
uniform highp sampler3D volume, overlay;
|
|
489
|
+
uniform int backgroundMasksOverlays;
|
|
490
|
+
uniform float overlays;
|
|
491
|
+
uniform float opacity;
|
|
492
|
+
uniform float drawOpacity;
|
|
493
|
+
uniform highp sampler3D drawing;
|
|
494
|
+
in vec3 texPos;
|
|
495
|
+
out vec4 color;
|
|
496
|
+
void main() {
|
|
497
|
+
//color = vec4(1.0, 0.0, 1.0, 1.0);return;
|
|
498
|
+
vec4 background = texture(volume, texPos);
|
|
499
|
+
color = vec4(background.rgb, opacity);
|
|
500
|
+
vec4 ocolor = vec4(0.0);
|
|
501
|
+
if (overlays > 0.0) {
|
|
502
|
+
ocolor = texture(overlay, texPos);
|
|
503
|
+
}
|
|
504
|
+
float draw = texture(drawing, texPos).r;
|
|
505
|
+
if (draw > 0.0) {
|
|
506
|
+
vec3 dcolor = vec3(0.0, 0.0, 0.0);
|
|
507
|
+
if (draw >= (4.0/255.0))
|
|
508
|
+
dcolor.rgb = vec3(draw,0.0,draw);
|
|
509
|
+
else if (draw >= (3.0/255.0))
|
|
510
|
+
dcolor.b = 1.0;
|
|
511
|
+
else if (draw >= (2.0/255.0))
|
|
512
|
+
dcolor.g = 1.0;
|
|
513
|
+
else
|
|
514
|
+
dcolor.r = 1.0;
|
|
515
|
+
color.rgb = mix(color.rgb, dcolor, drawOpacity);
|
|
516
|
+
color.a = max(drawOpacity, color.a);
|
|
517
|
+
}
|
|
518
|
+
if ((backgroundMasksOverlays > 0) && (background.a == 0.0))
|
|
519
|
+
return;
|
|
520
|
+
//float aout = ocolor.a + (1.0 - ocolor.a) * color.a;
|
|
521
|
+
//if (aout <= 0.0) return;
|
|
522
|
+
//color.rgb = ((ocolor.rgb * ocolor.a) + (color.rgb * color.a * (1.0 - ocolor.a))) / aout;
|
|
523
|
+
color.rgb = mix(color.rgb, ocolor.rgb, ocolor.a);
|
|
524
|
+
color.a = 1.0;
|
|
525
|
+
}`;
|
|
526
|
+
|
|
527
|
+
export var fragRectShader = `#version 300 es
|
|
436
528
|
#line 189
|
|
437
529
|
precision highp int;
|
|
438
530
|
precision highp float;
|
|
@@ -463,10 +555,13 @@ export var fragColorbarShader = `#version 300 es
|
|
|
463
555
|
precision highp int;
|
|
464
556
|
precision highp float;
|
|
465
557
|
uniform highp sampler2D colormap;
|
|
558
|
+
uniform float layer;
|
|
466
559
|
in vec2 vColor;
|
|
467
560
|
out vec4 color;
|
|
468
561
|
void main() {
|
|
469
|
-
|
|
562
|
+
float nlayer = float(textureSize(colormap, 0).y);
|
|
563
|
+
float fmap = (0.5 + layer) / nlayer;
|
|
564
|
+
color = vec4(texture(colormap, vec2(vColor.x, fmap)).rgb, 1.0);
|
|
470
565
|
}`;
|
|
471
566
|
|
|
472
567
|
export var vertGraphShader = `#version 300 es
|
|
@@ -509,7 +604,7 @@ void main(void) {
|
|
|
509
604
|
gl_Position = vec4(frac, 0.0, 1.0);
|
|
510
605
|
}`;
|
|
511
606
|
|
|
512
|
-
export var
|
|
607
|
+
export var vertRectShader = `#version 300 es
|
|
513
608
|
#line 229
|
|
514
609
|
layout(location=0) in vec3 pos;
|
|
515
610
|
uniform vec2 canvasWidthHeight;
|
|
@@ -523,6 +618,21 @@ void main(void) {
|
|
|
523
618
|
gl_Position = vec4(frac, 0.0, 1.0);
|
|
524
619
|
}`;
|
|
525
620
|
|
|
621
|
+
export var vertLineShader = `#version 300 es
|
|
622
|
+
#line 229
|
|
623
|
+
layout(location=0) in vec3 pos;
|
|
624
|
+
uniform vec2 canvasWidthHeight;
|
|
625
|
+
uniform float thickness;
|
|
626
|
+
uniform vec4 startXYendXY;
|
|
627
|
+
void main(void) {
|
|
628
|
+
vec2 posXY = mix(startXYendXY.xy, startXYendXY.zw, pos.x);
|
|
629
|
+
vec2 dir = normalize(startXYendXY.xy - startXYendXY.zw);
|
|
630
|
+
posXY += vec2(-dir.y, dir.x) * thickness * (pos.y - 0.5);
|
|
631
|
+
posXY.x = (posXY.x) / canvasWidthHeight.x; //0..1
|
|
632
|
+
posXY.y = 1.0 - (posXY.y / canvasWidthHeight.y); //1..0
|
|
633
|
+
gl_Position = vec4((posXY * 2.0) - 1.0, 0.0, 1.0);
|
|
634
|
+
}`;
|
|
635
|
+
|
|
526
636
|
export var vertBmpShader = `#version 300 es
|
|
527
637
|
#line 229
|
|
528
638
|
layout(location=0) in vec3 pos;
|
|
@@ -618,7 +728,7 @@ in vec2 TexCoord;
|
|
|
618
728
|
out vec4 FragColor;
|
|
619
729
|
uniform float coordZ;
|
|
620
730
|
uniform float layer;
|
|
621
|
-
uniform float numLayers;
|
|
731
|
+
//uniform float numLayers;
|
|
622
732
|
uniform highp sampler2D colormap;
|
|
623
733
|
uniform lowp sampler3D blend3D;
|
|
624
734
|
uniform float opacity;
|
|
@@ -648,7 +758,9 @@ void main(void) {
|
|
|
648
758
|
}
|
|
649
759
|
idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
650
760
|
float fx = (float(idx)+0.5) / 256.0;
|
|
651
|
-
float
|
|
761
|
+
float nlayer = float(textureSize(colormap, 0).y) * 0.5; //0.5 as both each layer has positive and negative color slot
|
|
762
|
+
float y = (2.0 * layer + 1.0)/(4.0 * nlayer);
|
|
763
|
+
//float y = (2.0 * layer + 1.0)/(4.0 * numLayers);
|
|
652
764
|
FragColor = texture(colormap, vec2(fx, y)).rgba;
|
|
653
765
|
FragColor.a *= opacity;
|
|
654
766
|
if (layer < 2.0) return;
|
|
@@ -668,28 +780,43 @@ in vec2 TexCoord;
|
|
|
668
780
|
out vec4 FragColor;
|
|
669
781
|
uniform float coordZ;
|
|
670
782
|
uniform float layer;
|
|
671
|
-
uniform float numLayers;
|
|
783
|
+
//uniform float numLayers;
|
|
672
784
|
uniform float scl_slope;
|
|
673
785
|
uniform float scl_inter;
|
|
674
786
|
uniform float cal_max;
|
|
675
787
|
uniform float cal_min;
|
|
676
788
|
uniform highp sampler2D colormap;
|
|
677
789
|
uniform lowp sampler3D blend3D;
|
|
790
|
+
uniform int modulation;
|
|
791
|
+
uniform highp sampler3D modulationVol;
|
|
678
792
|
uniform float opacity;
|
|
679
793
|
uniform mat4 mtx;
|
|
680
794
|
void main(void) {
|
|
681
795
|
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
682
796
|
float f = (scl_slope * float(texture(intensityVol, vx.xyz).r)) + scl_inter;
|
|
797
|
+
bool isNegative = (f < 0.0);
|
|
683
798
|
float r = max(0.00001, abs(cal_max - cal_min));
|
|
684
799
|
float mn = min(cal_min, cal_max);
|
|
685
|
-
|
|
686
|
-
//float y = 1.0 / numLayers;
|
|
687
|
-
//y = ((layer + 0.5) * y);
|
|
800
|
+
float txl = mix(0.0, 1.0, (f - mn) / r);
|
|
688
801
|
//https://stackoverflow.com/questions/5879403/opengl-texture-coordinates-in-pixel-space
|
|
689
|
-
float
|
|
690
|
-
|
|
802
|
+
float nlayer = float(textureSize(colormap, 0).y) * 0.5; //0.5 as both each layer has positive and negative color slot
|
|
803
|
+
float y = (2.0 * layer + 1.0)/(4.0 * nlayer);
|
|
804
|
+
FragColor = texture(colormap, vec2(txl, y)).rgba;
|
|
805
|
+
if (isNegative) {
|
|
806
|
+
y = (2.0 * layer + nlayer + nlayer + 1.0)/(4.0 * nlayer);
|
|
807
|
+
//select texels at positions 0 and 1 of lookup table:
|
|
808
|
+
vec4 v0 = texture(colormap, vec2(0.5/256.0, y));
|
|
809
|
+
vec4 v1 = texture(colormap, vec2(1.5/256.0, y));
|
|
810
|
+
txl = mix(0.0, 1.0, (- f - mn) / r);
|
|
811
|
+
//detect bogus color: negative color slot not used than
|
|
812
|
+
// v0 = 1,1,1,0 and v1 = 0,0,0,1
|
|
813
|
+
if ((v0.r != 1.0) || (v0.a != 0.0) || (v1.r != 0.0) || (v1.a != 1.0))
|
|
814
|
+
FragColor = texture(colormap, vec2(txl, y));
|
|
815
|
+
}
|
|
691
816
|
if (layer > 0.7)
|
|
692
817
|
FragColor.a = step(0.00001, FragColor.a);
|
|
818
|
+
if (modulation > 0)
|
|
819
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
693
820
|
FragColor.a *= opacity;
|
|
694
821
|
if (layer < 1.0) return;
|
|
695
822
|
vec2 texXY = TexCoord.xy*0.5 +vec2(0.5,0.5);
|
|
@@ -708,7 +835,7 @@ in vec2 TexCoord;
|
|
|
708
835
|
out vec4 FragColor;
|
|
709
836
|
uniform float coordZ;
|
|
710
837
|
uniform float layer;
|
|
711
|
-
uniform float numLayers;
|
|
838
|
+
//uniform float numLayers;
|
|
712
839
|
uniform float scl_slope;
|
|
713
840
|
uniform float scl_inter;
|
|
714
841
|
uniform float cal_max;
|
|
@@ -718,10 +845,14 @@ uniform lowp sampler3D blend3D;
|
|
|
718
845
|
uniform float opacity;
|
|
719
846
|
uniform mat4 mtx;
|
|
720
847
|
uniform bool hasAlpha;
|
|
848
|
+
uniform int modulation;
|
|
849
|
+
uniform highp sampler3D modulationVol;
|
|
721
850
|
void main(void) {
|
|
722
851
|
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
723
852
|
uvec4 aColor = texture(intensityVol, vx.xyz);
|
|
724
853
|
FragColor = vec4(float(aColor.r) / 255.0, float(aColor.g) / 255.0, float(aColor.b) / 255.0, float(aColor.a) / 255.0);
|
|
854
|
+
if (modulation > 0)
|
|
855
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
725
856
|
if (!hasAlpha)
|
|
726
857
|
FragColor.a = (FragColor.r * 0.21 + FragColor.g * 0.72 + FragColor.b * 0.07);
|
|
727
858
|
FragColor.a *= opacity;
|
|
@@ -880,6 +1011,25 @@ void main(void) {
|
|
|
880
1011
|
vClr = clr;
|
|
881
1012
|
}`;
|
|
882
1013
|
|
|
1014
|
+
//report depth for fragment
|
|
1015
|
+
// https://github.com/rii-mango/Papaya/blob/782a19341af77a510d674c777b6da46afb8c65f1/src/js/viewer/screensurface.js#L89
|
|
1016
|
+
export var fragMeshDepthShader = `#version 300 es
|
|
1017
|
+
precision highp int;
|
|
1018
|
+
precision highp float;
|
|
1019
|
+
uniform float opacity;
|
|
1020
|
+
out vec4 color;
|
|
1021
|
+
vec4 packFloatToVec4i(const float value) {
|
|
1022
|
+
//this Papaya function uses BSD 3-clause license Copyright (c) 2012-2015, RII-UTHSCSA
|
|
1023
|
+
const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
|
|
1024
|
+
const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
|
|
1025
|
+
vec4 res = fract(value * bitSh);
|
|
1026
|
+
res -= res.xxyz * bitMsk;
|
|
1027
|
+
return res;
|
|
1028
|
+
}
|
|
1029
|
+
void main() {
|
|
1030
|
+
color = packFloatToVec4i(gl_FragCoord.z);
|
|
1031
|
+
}`;
|
|
1032
|
+
|
|
883
1033
|
//ToonShader https://prideout.net/blog/old/blog/index.html@tag=toon-shader.html
|
|
884
1034
|
export var fragMeshToonShader = `#version 300 es
|
|
885
1035
|
precision highp int;
|