zincjs 1.19.4 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/zinc.frontend.js +1 -1
- package/build/zinc.js +5 -5
- package/build/zinc.js.map +1 -1
- package/package.json +1 -1
- package/src/loaders/niftiReader.js +79 -193
- package/src/primitives/textureSlides.js +38 -22
- package/src/shaders/textureSlide.js +20 -9
package/package.json
CHANGED
|
@@ -39,7 +39,6 @@ const defaultTextureSettings = {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
const defaultOptions = {
|
|
42
|
-
hideWhitePixel: false,
|
|
43
42
|
hideBlackPixel: true,
|
|
44
43
|
keepScalePosition: true,
|
|
45
44
|
filterByValue: true,
|
|
@@ -127,197 +126,81 @@ function readNIFTI(data) {
|
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (maskWidth === width && maskHeight === height && maskDepth === depth) {
|
|
145
|
-
const maskedTypedData = getTypedData(maskHeader, maskImage);
|
|
146
|
-
maskData = maskedTypedData.typedData;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
let slope = niftiHeader.scl_slope || 1;
|
|
150
|
-
let intercept = niftiHeader.scl_inter || 0;
|
|
129
|
+
function convertNiftiToUint8Array(niftiHeader, niftiImage) {
|
|
130
|
+
// 1. Parse the raw array using the correct native typed array view
|
|
131
|
+
let rawData;
|
|
132
|
+
switch (niftiHeader.datatypeCode) {
|
|
133
|
+
case nifti.NIFTI1.TYPE_UINT8: rawData = new Uint8Array(niftiImage); break;
|
|
134
|
+
case nifti.NIFTI1.TYPE_INT8: rawData = new Int8Array(niftiImage); break;
|
|
135
|
+
case nifti.NIFTI1.TYPE_UINT16: rawData = new Uint16Array(niftiImage); break;
|
|
136
|
+
case nifti.NIFTI1.TYPE_INT16: rawData = new Int16Array(niftiImage); break;
|
|
137
|
+
case nifti.NIFTI1.TYPE_UINT32: rawData = new Uint32Array(niftiImage); break;
|
|
138
|
+
case nifti.NIFTI1.TYPE_INT32: rawData = new Int32Array(niftiImage); break;
|
|
139
|
+
case nifti.NIFTI1.TYPE_FLOAT32: rawData = new Float32Array(niftiImage); break;
|
|
140
|
+
case nifti.NIFTI1.TYPE_FLOAT64: rawData = new Float64Array(niftiImage); break;
|
|
141
|
+
default: throw new Error("Unsupported NIfTI data type");
|
|
142
|
+
}
|
|
151
143
|
|
|
152
|
-
|
|
153
|
-
|
|
144
|
+
const slope = niftiHeader.scl_slope || 1.0;
|
|
145
|
+
const intercept = niftiHeader.scl_inter || 0.0;
|
|
154
146
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let val = (typedData[i] * slope) + intercept;
|
|
158
|
-
if (val < min) min = val;
|
|
159
|
-
if (val > max) max = val;
|
|
160
|
-
}
|
|
161
|
-
let range = max - min;
|
|
147
|
+
let min = Infinity;
|
|
148
|
+
let max = -Infinity;
|
|
162
149
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
let trueVal = typedData[offset] * slope + intercept;
|
|
170
|
-
let value = 0;
|
|
171
|
-
if (range !== 0) {
|
|
172
|
-
// Map [min, max] to [0, 255]
|
|
173
|
-
value = ((trueVal - min) / range) * 255;
|
|
174
|
-
}
|
|
175
|
-
fullArray[offset * 4] = value;
|
|
176
|
-
fullArray[offset * 4 + 1] = value;
|
|
177
|
-
fullArray[offset * 4 + 2] = value;
|
|
178
|
-
fullArray[offset * 4 + 3] = 255;
|
|
179
|
-
if (maskData) {
|
|
180
|
-
const maskedValue = maskData[offset];
|
|
181
|
-
if (options.hideBlackPixel) {
|
|
182
|
-
//if (maskedValue === 0 && 20 > value) {
|
|
183
|
-
if (maskedValue === 0) {
|
|
184
|
-
fullArray[offset * 4 + 3] = 0;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} else if (options.filterByValue) {
|
|
188
|
-
if (options.hideWhitePixel && value === 255) {
|
|
189
|
-
fullArray[offset * 4 + 3] = 0;
|
|
190
|
-
}
|
|
191
|
-
if (options.hideBlackPixel && 2 >= value) {
|
|
192
|
-
fullArray[offset * 4] = 240;
|
|
193
|
-
fullArray[offset * 4 + 1] = 240;
|
|
194
|
-
fullArray[offset * 4 + 2] = 240;
|
|
195
|
-
fullArray[offset * 4 + 3] = 1.0;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
150
|
+
const len = rawData.length;
|
|
151
|
+
for (let i = 0; i < len; i++) {
|
|
152
|
+
let val = rawData[i];
|
|
153
|
+
if (val < min) min = val;
|
|
154
|
+
if (val > max) max = val;
|
|
155
|
+
}
|
|
201
156
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
157
|
+
const uint8Data = new Uint8Array(len);
|
|
158
|
+
const range = max - min;
|
|
159
|
+
|
|
160
|
+
for (let i = 0; i < len; i++) {
|
|
161
|
+
let physicalVal = rawData[i];
|
|
162
|
+
let normalised = (physicalVal - min) / range;
|
|
163
|
+
normalised = Math.max(0.0, Math.min(1.0, normalised));
|
|
164
|
+
uint8Data[i] = Math.round(normalised * 255.0);
|
|
208
165
|
}
|
|
209
|
-
|
|
166
|
+
|
|
167
|
+
return uint8Data;
|
|
210
168
|
}
|
|
211
|
-
|
|
212
|
-
function createSources(niftiHeader, niftiImage, maskHeader, maskImage
|
|
169
|
+
|
|
170
|
+
function createSources(niftiHeader, niftiImage, maskHeader, maskImage) {
|
|
213
171
|
if (niftiHeader?.dims && niftiHeader.dims[0] === 3) {
|
|
214
172
|
const width = niftiHeader.dims[1];
|
|
215
173
|
const height = niftiHeader.dims[2];
|
|
216
174
|
const depth = niftiHeader.dims[3];
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
175
|
+
let isRGB = false;
|
|
176
|
+
if (niftiHeader.intent_code === 1007 || niftiHeader.intent_code === 1008 ||
|
|
177
|
+
niftiHeader.datatypeCode === 128 || niftiHeader.datatypeCode === 2304) {
|
|
178
|
+
isRGB = true;
|
|
179
|
+
}
|
|
180
|
+
const typedData = convertNiftiToUint8Array(niftiHeader, niftiImage);
|
|
221
181
|
let maskData = undefined;
|
|
222
182
|
if (maskHeader && maskImage) {
|
|
223
183
|
const maskWidth = maskHeader.dims[1];
|
|
224
184
|
const maskHeight = maskHeader.dims[2];
|
|
225
185
|
const maskDepth = maskHeader.dims[3];
|
|
226
186
|
if (maskWidth === width && maskHeight === height && maskDepth === depth) {
|
|
227
|
-
const maskedTypedData =
|
|
228
|
-
maskData = maskedTypedData
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
let scale = 1;
|
|
232
|
-
let valueOffset = 0.0;
|
|
233
|
-
if (dataType === "float") {
|
|
234
|
-
//It should be like
|
|
235
|
-
// scl_slope = 0, intensity will be stored in value between 0, 1
|
|
236
|
-
// Otherwise the following
|
|
237
|
-
//y = scl_slope * x + scl_inter
|
|
238
|
-
if (niftiHeader.scl_slope === 0) {
|
|
239
|
-
scale = 255;
|
|
240
|
-
} else {
|
|
241
|
-
valueOffset = niftiHeader.scl_inter;
|
|
242
|
-
}
|
|
243
|
-
} else if (dataType === "uint") {
|
|
244
|
-
scale = 255;
|
|
245
|
-
} else if (dataType === "int16") {
|
|
246
|
-
//scale = 1 / 255;
|
|
247
|
-
if (niftiHeader.scl_slope === 0) {
|
|
248
|
-
scale = 255;
|
|
249
|
-
} else {
|
|
250
|
-
valueOffset = niftiHeader.scl_inter;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
for (let slice = 0; slice < depth; slice++) {
|
|
254
|
-
const sliceOffset = sliceSize * slice;
|
|
255
|
-
for (let row = 0; row < height; row++) {
|
|
256
|
-
const rowOffset = row * width;
|
|
257
|
-
for (let col = 0; col < width; col++) {
|
|
258
|
-
const offset = sliceOffset + rowOffset + col;
|
|
259
|
-
let value = typedData[offset] * scale + valueOffset;
|
|
260
|
-
if (value < 0) value = 0;
|
|
261
|
-
fullArray[offset * 4] = value;
|
|
262
|
-
fullArray[offset * 4 + 1] = value;
|
|
263
|
-
fullArray[offset * 4 + 2] = value;
|
|
264
|
-
fullArray[offset * 4 + 3] = 255;
|
|
265
|
-
if (maskData) {
|
|
266
|
-
const maskedValue = maskData[offset];
|
|
267
|
-
if (options.hideBlackPixel) {
|
|
268
|
-
//if (maskedValue === 0 && 20 > value) {
|
|
269
|
-
if (maskedValue === 0) {
|
|
270
|
-
fullArray[offset * 4 + 3] = 0;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
} else if (options.filterByValue) {
|
|
274
|
-
if (options.hideWhitePixel && value === 255) {
|
|
275
|
-
fullArray[offset * 4 + 3] = 0;
|
|
276
|
-
}
|
|
277
|
-
if (options.hideBlackPixel && 2 >= value) {
|
|
278
|
-
fullArray[offset * 4] = 240;
|
|
279
|
-
fullArray[offset * 4 + 1] = 240;
|
|
280
|
-
fullArray[offset * 4 + 2] = 240;
|
|
281
|
-
fullArray[offset * 4 + 3] = 1.0;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
187
|
+
const maskedTypedData = convertNiftiToUint8Array(maskHeader, maskImage);
|
|
188
|
+
maskData = maskedTypedData;
|
|
285
189
|
}
|
|
286
190
|
}
|
|
191
|
+
|
|
287
192
|
return {
|
|
288
|
-
data:
|
|
193
|
+
data: typedData,
|
|
194
|
+
maskData: maskData,
|
|
289
195
|
width,
|
|
290
196
|
height,
|
|
291
197
|
depth,
|
|
198
|
+
isRGB,
|
|
292
199
|
};
|
|
293
200
|
}
|
|
294
201
|
return undefined;
|
|
295
202
|
}
|
|
296
203
|
|
|
297
|
-
*/
|
|
298
|
-
|
|
299
|
-
function getTypedData(niftiHeader, niftiImage) {
|
|
300
|
-
if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_UINT8) {
|
|
301
|
-
return { typedData: new Uint8Array(niftiImage), dataType: "uint" };
|
|
302
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_INT16) {
|
|
303
|
-
return { typedData: new Int16Array(niftiImage), dataType: "int16" };
|
|
304
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_INT32) {
|
|
305
|
-
return { typedData: new Int32Array(niftiImage), dataType: "int32" };
|
|
306
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_FLOAT32) {
|
|
307
|
-
return { typedData: new Float32Array(niftiImage), dataType: "float" };
|
|
308
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_FLOAT64) {
|
|
309
|
-
return { typedData: new Float64Array(niftiImage), dataType: "float" };
|
|
310
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_INT8) {
|
|
311
|
-
return { typedData: new Int8Array(niftiImage), dataType: "int" };
|
|
312
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_UINT16) {
|
|
313
|
-
return { typedData: new Uint16Array(niftiImage), dataType: "int" };
|
|
314
|
-
} else if (niftiHeader.datatypeCode === nifti.NIFTI1.TYPE_UINT32) {
|
|
315
|
-
return { typedData: new Uint32Array(niftiImage), dataType: "int" };
|
|
316
|
-
} else {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
204
|
function getSFormTransformation(header, options) {
|
|
322
205
|
if (header?.affine && header.dims) {
|
|
323
206
|
const affine = header.affine;
|
|
@@ -349,26 +232,41 @@ function getTransformationFromHeader(header, options) {
|
|
|
349
232
|
return {position: undefined, scale: undefined}
|
|
350
233
|
}
|
|
351
234
|
|
|
235
|
+
function createDataTexture(data, width, height, depth, isRGB) {
|
|
236
|
+
const dataTexture = new THREE.DataTexture2DArray(
|
|
237
|
+
data, width, height, depth);
|
|
238
|
+
dataTexture.anisotropy = 4;
|
|
239
|
+
if (!isRGB) {
|
|
240
|
+
dataTexture.format = THREE.RedFormat;
|
|
241
|
+
}
|
|
242
|
+
dataTexture.minFilter = THREE.NearestFilter;
|
|
243
|
+
dataTexture.magFilter = THREE.NearestFilter;
|
|
244
|
+
dataTexture.needsUpdate = true;
|
|
245
|
+
return dataTexture;
|
|
246
|
+
}
|
|
247
|
+
|
|
352
248
|
function createTextureArray(sources) {
|
|
353
249
|
if (sources?.data) {
|
|
354
250
|
const tArray = new TextureArray();
|
|
355
|
-
tArray.impl = new
|
|
251
|
+
tArray.impl = new createDataTexture(
|
|
356
252
|
sources.data, sources.width, sources.height, sources.depth);
|
|
357
|
-
tArray.impl.anisotropy = 4;
|
|
358
253
|
tArray.size = {
|
|
359
254
|
width: sources.width,
|
|
360
255
|
height: sources.height,
|
|
361
256
|
depth: sources.depth,
|
|
362
257
|
};
|
|
363
258
|
tArray.isLoading = false;
|
|
364
|
-
tArray.impl.needsUpdate = true;
|
|
365
259
|
return tArray;
|
|
366
260
|
}
|
|
367
261
|
return undefined;
|
|
368
262
|
}
|
|
369
263
|
|
|
370
|
-
function createTexturePrimitives(niftiHeader, sources, useHeaderInfo, textureSettings,
|
|
264
|
+
function createTexturePrimitives(niftiHeader, sources, useHeaderInfo, textureSettings, optionsIn) {
|
|
371
265
|
if (sources?.data) {
|
|
266
|
+
const options = {...defaultOptions};
|
|
267
|
+
if (optionsIn) {
|
|
268
|
+
Object.assign(options, optionsIn);
|
|
269
|
+
}
|
|
372
270
|
const newTexture = new TextureSlides();
|
|
373
271
|
const tArray = createTextureArray(sources);
|
|
374
272
|
if (tArray) {
|
|
@@ -385,36 +283,23 @@ function createTexturePrimitives(niftiHeader, sources, useHeaderInfo, textureSet
|
|
|
385
283
|
settings.locations[0].scale = scale;
|
|
386
284
|
settings.locations[0].position = position;
|
|
387
285
|
}
|
|
388
|
-
/*
|
|
389
|
-
if (niftiHeader.qoffset_x) {
|
|
390
|
-
settings.locations[0].position[0] = niftiHeader.qoffset_x;
|
|
391
|
-
}
|
|
392
|
-
if (niftiHeader.qoffset_y) {
|
|
393
|
-
settings.locations[0].position[1] = niftiHeader.qoffset_y;
|
|
394
|
-
}
|
|
395
|
-
if (niftiHeader.qoffset_y) {
|
|
396
|
-
settings.locations[0].position[2] = niftiHeader.qoffset_z;
|
|
397
|
-
}
|
|
398
|
-
if (niftiHeader.dims) {
|
|
399
|
-
settings.locations[0].scale[0] = niftiHeader.dims[1];
|
|
400
|
-
settings.locations[0].scale[1] = niftiHeader.dims[2];
|
|
401
|
-
settings.locations[0].scale[2] = niftiHeader.dims[3];
|
|
402
|
-
}
|
|
403
|
-
*/
|
|
404
286
|
}
|
|
405
287
|
newTexture.initialise(settings, undefined);
|
|
406
288
|
newTexture.showEdges(0x999999);
|
|
289
|
+
if (sources.maskData && !options.timeEnabled) {
|
|
290
|
+
const maskTexture = createDataTexture(sources.maskData,
|
|
291
|
+
sources.width, sources.height, sources.depth, false);
|
|
292
|
+
newTexture.setMask(maskTexture);
|
|
293
|
+
}
|
|
294
|
+
newTexture.setNumberOfChannels(sources.isRGB ? 3 : 1);
|
|
295
|
+
|
|
407
296
|
return newTexture;
|
|
408
297
|
}
|
|
409
298
|
}
|
|
410
299
|
return undefined;
|
|
411
300
|
}
|
|
412
301
|
|
|
413
|
-
async function getImagesFromURL(url, maskURL
|
|
414
|
-
const options = {...defaultOptions};
|
|
415
|
-
if (optionsIn) {
|
|
416
|
-
Object.assign(options, optionsIn);
|
|
417
|
-
}
|
|
302
|
+
async function getImagesFromURL(url, maskURL) {
|
|
418
303
|
|
|
419
304
|
// try {
|
|
420
305
|
let maskHeader = undefined, maskImage = undefined;
|
|
@@ -428,13 +313,13 @@ async function getImagesFromURL(url, maskURL, optionsIn) {
|
|
|
428
313
|
const response = await fetch(url);
|
|
429
314
|
const buffer = await response.arrayBuffer();
|
|
430
315
|
const {niftiHeader, niftiImage} = readNIFTI(buffer);
|
|
431
|
-
const sources = createSources(niftiHeader, niftiImage, maskHeader, maskImage
|
|
432
|
-
|
|
316
|
+
const sources = createSources(niftiHeader, niftiImage, maskHeader, maskImage);
|
|
433
317
|
return {sources, niftiHeader};
|
|
434
318
|
}
|
|
435
319
|
|
|
436
320
|
|
|
437
|
-
async function createPrimitivesFromNIFTI(
|
|
321
|
+
async function createPrimitivesFromNIFTI(
|
|
322
|
+
url, useHeaderInfo, maskURL, textureSettings, optionsIn) {
|
|
438
323
|
let timeEnabled = false;
|
|
439
324
|
let textureP = undefined;
|
|
440
325
|
let firstURL = url;
|
|
@@ -455,6 +340,7 @@ async function createPrimitivesFromNIFTI(url, useHeaderInfo, maskURL, textureSet
|
|
|
455
340
|
}
|
|
456
341
|
textureP.timeEnabled = true;
|
|
457
342
|
}
|
|
343
|
+
|
|
458
344
|
return textureP;
|
|
459
345
|
}
|
|
460
346
|
|
|
@@ -24,6 +24,9 @@ const TextureSlides = function (textureIn) {
|
|
|
24
24
|
let flipZ = false;
|
|
25
25
|
let brightness = 0.0;
|
|
26
26
|
let contrast = 1.0;
|
|
27
|
+
let nChannels = 1;
|
|
28
|
+
let maskTexture = undefined;
|
|
29
|
+
let maskEnabled = false;
|
|
27
30
|
let discardAlpha = true;
|
|
28
31
|
let lt0 = 0;
|
|
29
32
|
let lt1 = 0;
|
|
@@ -126,6 +129,9 @@ const TextureSlides = function (textureIn) {
|
|
|
126
129
|
uniforms.depth.value = this.texture.size.depth;
|
|
127
130
|
uniforms.flipY.value = flipY;
|
|
128
131
|
uniforms.flipZ.value = flipZ;
|
|
132
|
+
uniforms.mask.value = maskTexture;
|
|
133
|
+
uniforms.maskEnabled.value = maskEnabled;
|
|
134
|
+
uniforms.nChannels.value = nChannels;
|
|
129
135
|
const options = {
|
|
130
136
|
fs: shader.fs,
|
|
131
137
|
vs: shader.vs,
|
|
@@ -356,36 +362,34 @@ const TextureSlides = function (textureIn) {
|
|
|
356
362
|
edgesLine.visible = true;
|
|
357
363
|
}
|
|
358
364
|
|
|
359
|
-
this.isAlphaPixelDiscarded = () => {
|
|
360
|
-
return discardAlpha;
|
|
361
|
-
}
|
|
362
365
|
|
|
363
|
-
this.
|
|
364
|
-
discardAlpha = flag;
|
|
366
|
+
this.setUniformsValue = (name, val) => {
|
|
365
367
|
this.morph.children.forEach((mesh) => {
|
|
366
368
|
const material = mesh.material;
|
|
367
369
|
if (material.type === "ShaderMaterial") {
|
|
368
370
|
const uniforms = material.uniforms;
|
|
369
|
-
uniforms.
|
|
371
|
+
uniforms[name].value = val;
|
|
370
372
|
material.needsUpdate = true;
|
|
371
373
|
}
|
|
372
374
|
});
|
|
373
375
|
}
|
|
374
376
|
|
|
377
|
+
this.isAlphaPixelDiscarded = () => {
|
|
378
|
+
return discardAlpha;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
this.discardAlphaPixel = (flag) => {
|
|
382
|
+
discardAlpha = flag;
|
|
383
|
+
this.setUniformsValue("discardAlpha", discardAlpha);
|
|
384
|
+
}
|
|
385
|
+
|
|
375
386
|
this.getBrightness = () => {
|
|
376
387
|
return brightness;
|
|
377
388
|
}
|
|
378
389
|
|
|
379
390
|
this.setBrightness = (brightnessIn) => {
|
|
380
391
|
brightness = brightnessIn;
|
|
381
|
-
this.
|
|
382
|
-
const material = mesh.material;
|
|
383
|
-
if (material.type === "ShaderMaterial") {
|
|
384
|
-
const uniforms = material.uniforms;
|
|
385
|
-
uniforms.brightness.value = brightness;
|
|
386
|
-
material.needsUpdate = true;
|
|
387
|
-
}
|
|
388
|
-
});
|
|
392
|
+
this.setUniformsValue("brightness", brightness);
|
|
389
393
|
}
|
|
390
394
|
|
|
391
395
|
this.getContrast = () => {
|
|
@@ -395,17 +399,29 @@ const TextureSlides = function (textureIn) {
|
|
|
395
399
|
this.setContrast = (contrastIn) => {
|
|
396
400
|
if (contrast >= 0 ) {
|
|
397
401
|
contrast = contrastIn;
|
|
398
|
-
this.
|
|
399
|
-
const material = mesh.material;
|
|
400
|
-
if (material.type === "ShaderMaterial") {
|
|
401
|
-
const uniforms = material.uniforms;
|
|
402
|
-
uniforms.contrast.value = contrast;
|
|
403
|
-
material.needsUpdate = true;
|
|
404
|
-
}
|
|
405
|
-
});
|
|
402
|
+
this.setUniformsValue("contrast", contrast);
|
|
406
403
|
}
|
|
407
404
|
}
|
|
408
405
|
|
|
406
|
+
this.getNumberOfChannels = () => {
|
|
407
|
+
return nChannels;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
this.setNumberOfChannels = (numbersIn) => {
|
|
411
|
+
nChannels = numbersIn;
|
|
412
|
+
this.setUniformsValue("nChannels", nChannels);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
this.getMask = () => {
|
|
416
|
+
return maskTexture;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
this.setMask = (maskTextureIn) => {
|
|
420
|
+
maskTexture = maskTextureIn;
|
|
421
|
+
this.setUniformsValue("mask", maskTexture);
|
|
422
|
+
this.setUniformsValue("maskEnabled", maskTexture ? true : false);
|
|
423
|
+
}
|
|
424
|
+
|
|
409
425
|
this.hideEdges = () => {
|
|
410
426
|
if (edgesLine) {
|
|
411
427
|
edgesLine.visible = false;
|
|
@@ -10,27 +10,35 @@ precision highp sampler2DArray;
|
|
|
10
10
|
|
|
11
11
|
uniform sampler2DArray diffuse0;
|
|
12
12
|
uniform sampler2DArray diffuse1;
|
|
13
|
+
uniform sampler2DArray mask;
|
|
13
14
|
uniform bool discardAlpha;
|
|
15
|
+
uniform bool maskEnabled;
|
|
14
16
|
uniform float brightness;
|
|
15
17
|
uniform float contrast;
|
|
16
18
|
uniform float time;
|
|
19
|
+
uniform int nChannels;
|
|
17
20
|
in vec3 vUw;
|
|
18
21
|
|
|
19
22
|
out vec4 outColor;
|
|
20
23
|
|
|
21
24
|
void main() {
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
float color0 = texture( diffuse0, vUw ).r;
|
|
27
|
+
float color1 = texture( diffuse1, vUw ).r;
|
|
28
|
+
float color = mix(color0, color1, time);
|
|
29
|
+
// discard if alpha is zero
|
|
30
|
+
if (maskEnabled && discardAlpha) {
|
|
31
|
+
float mask = texture(mask, vUw).r;
|
|
32
|
+
if (mask == 0.0) discard;
|
|
33
|
+
}
|
|
26
34
|
|
|
27
35
|
// discard if alpha is zero
|
|
28
|
-
if (discardAlpha && color.a == 0.0) discard;
|
|
36
|
+
//if (discardAlpha && color.a == 0.0) discard;
|
|
29
37
|
// Apply brightness
|
|
30
|
-
vec3 brightenedColor = color
|
|
38
|
+
vec3 brightenedColor = vec3(color) + vec3(brightness);
|
|
31
39
|
// Apply contrast
|
|
32
40
|
vec3 contrastedColor = (brightenedColor - vec3(0.5)) * contrast + vec3(0.5);
|
|
33
|
-
outColor = vec4(contrastedColor,
|
|
41
|
+
outColor = vec4(contrastedColor, 1.0);
|
|
34
42
|
}
|
|
35
43
|
`;
|
|
36
44
|
|
|
@@ -73,9 +81,12 @@ const getUniforms = function() {
|
|
|
73
81
|
discardAlpha: {value: true},
|
|
74
82
|
diffuse0: { value: undefined },
|
|
75
83
|
diffuse1: { value: undefined },
|
|
76
|
-
direction: {value: 1},
|
|
77
|
-
flipY: { value: true},
|
|
78
|
-
flipZ: { value: false},
|
|
84
|
+
direction: { value: 1 },
|
|
85
|
+
flipY: { value: true },
|
|
86
|
+
flipZ: { value: false },
|
|
87
|
+
nChannels: { value: 1 },
|
|
88
|
+
mask: { value: undefined },
|
|
89
|
+
maskEnabled: { value: false },
|
|
79
90
|
slide: { value: new THREE.Vector3( 0, 0, 1 ) },
|
|
80
91
|
time: { value: 0 }
|
|
81
92
|
};
|