zincjs 3.0.0 → 3.0.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 +27 -22
- package/build/zinc.js +2 -2
- package/build/zinc.js.map +1 -1
- package/package.json +4 -1
- package/src/controls.js +1332 -1241
- package/src/geometryCSG.js +111 -115
- package/src/glyphsetCSG.js +51 -55
- package/src/loaders/GLTFToZincJSLoader.js +31 -33
- package/src/loaders/JSONLoader.js +339 -449
- package/src/loaders/OBJLoader.js +654 -851
- package/src/loaders/STLLoader.js +271 -329
- package/src/loaders/niftiReader.js +90 -59
- package/src/loaders/primitivesLoader.js +55 -52
- package/src/minimap.js +63 -43
- package/src/primitives/geometry.js +40 -44
- package/src/primitives/glyph.js +16 -19
- package/src/primitives/glyphset.js +229 -185
- package/src/primitives/label.js +29 -31
- package/src/primitives/lines.js +20 -20
- package/src/primitives/lines2.js +33 -39
- package/src/primitives/lod.js +43 -43
- package/src/primitives/marker.js +31 -32
- package/src/primitives/markerCluster.js +32 -35
- package/src/primitives/pointset.js +86 -83
- package/src/primitives/texturePrimitive.js +9 -10
- package/src/primitives/textureSlides.js +84 -97
- package/src/primitives/textureVolume.js +46 -49
- package/src/primitives/tubeLines.js +108 -108
- package/src/primitives/zincObject.js +176 -184
- package/src/region.js +145 -155
- package/src/renderRequests.js +3 -3
- package/src/renderer.js +649 -629
- package/src/scene.js +502 -430
- package/src/sceneExporter.js +22 -17
- package/src/sceneLoader.js +542 -296
- package/src/shaders/rgbVolumeRender.js +11 -18
- package/src/shaders/textureArray.js +5 -12
- package/src/shaders/textureSlide.js +10 -17
- package/src/shaders/volumeRender.js +11 -18
- package/src/shaders/volumeRender_old.js +11 -18
- package/src/shaders/volumeTexture.js +7 -14
- package/src/textSprite.js +23 -19
- package/src/texture/texture.js +14 -15
- package/src/texture/textureArray.js +14 -16
- package/src/three/InstancedPoints.js +2 -9
- package/src/three/Loader.js +334 -315
- package/src/three/line/Line.js +165 -215
- package/src/three/line/LineSegments.js +40 -55
- package/src/three/line/LineSegments2.js +322 -366
- package/src/three/line/LineSegmentsGeometry.js +239 -280
- package/src/three-js-csg.js +260 -252
- package/src/tsl/glyphRenderMaterial.js +12 -3
- package/src/tsl/glyphTransform.js +51 -29
- package/src/tsl/textureSlides.js +23 -24
- package/src/utilities.js +309 -371
- package/src/videoHandler.js +76 -83
- package/src/workers/geometryCSG.worker.js +33 -36
- package/src/workers/geometryCSGInternal.js +39 -44
- package/src/zinc.js +4 -7
- package/vite.config.js +7 -7
package/src/utilities.js
CHANGED
|
@@ -6,20 +6,20 @@ import { createTextSprite } from './textSprite';
|
|
|
6
6
|
function createNewURL(target, reference) {
|
|
7
7
|
const getNewURL = (target, reference) => {
|
|
8
8
|
try {
|
|
9
|
-
let newURL =
|
|
9
|
+
let newURL = new URL(target, reference).href;
|
|
10
10
|
//Make sure the target url does not contain parameters
|
|
11
|
-
if (target && target.split(
|
|
12
|
-
const paramsStrings = reference.split(
|
|
11
|
+
if (target && target.split('?').length < 2) {
|
|
12
|
+
const paramsStrings = reference.split('?');
|
|
13
13
|
//There are parameters, add them to the target
|
|
14
14
|
if (paramsStrings.length === 2) {
|
|
15
|
-
newURL = newURL +
|
|
15
|
+
newURL = newURL + '?' + paramsStrings[1];
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
return newURL;
|
|
19
19
|
} catch {
|
|
20
|
-
console.error(`There is an issue creating the url link with: ${target}.`
|
|
20
|
+
console.error(`There is an issue creating the url link with: ${target}.`);
|
|
21
21
|
}
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
23
|
if (!Array.isArray(target)) {
|
|
24
24
|
return getNewURL(target, reference);
|
|
25
25
|
} else {
|
|
@@ -62,8 +62,7 @@ function updateWorldMatrixFromAncestors(object) {
|
|
|
62
62
|
function getBoundingBox(mesh, cachedBox, b1, v1, v2) {
|
|
63
63
|
let influences = mesh.morphTargetInfluences;
|
|
64
64
|
let attributes = undefined;
|
|
65
|
-
if (mesh.geometry)
|
|
66
|
-
attributes = mesh.geometry.morphAttributes;
|
|
65
|
+
if (mesh.geometry) attributes = mesh.geometry.morphAttributes;
|
|
67
66
|
let found = false;
|
|
68
67
|
if (influences && attributes && attributes.position) {
|
|
69
68
|
v1.set(0.0, 0.0, 0.0);
|
|
@@ -81,82 +80,78 @@ function getBoundingBox(mesh, cachedBox, b1, v1, v2) {
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
if (!found) {
|
|
84
|
-
cachedBox.setFromBufferAttribute(
|
|
85
|
-
mesh.geometry.attributes.position);
|
|
83
|
+
cachedBox.setFromBufferAttribute(mesh.geometry.attributes.position);
|
|
86
84
|
}
|
|
87
85
|
cachedBox.applyMatrix4(updateWorldMatrixFromAncestors(mesh));
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
|
|
91
88
|
//Convenient function
|
|
92
89
|
function loadExternalFile(url, data, callback, errorCallback) {
|
|
93
|
-
|
|
90
|
+
// Set up an asynchronous request
|
|
94
91
|
fetch(url)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
92
|
+
.then((response) => {
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
95
|
+
}
|
|
96
|
+
return response.text();
|
|
97
|
+
})
|
|
98
|
+
.then((responseText) => {
|
|
99
|
+
callback(responseText, data);
|
|
100
|
+
})
|
|
101
|
+
.catch((error) => {
|
|
102
|
+
console.error(`Fetch string payload retrieval failed for: ${requestURL}`, error);
|
|
103
|
+
errorCallback(url);
|
|
104
|
+
});
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
function loadExternalFiles(urls, callback, errorCallback) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// Callback for a single file
|
|
116
|
-
function partialCallback(text, urlIndex) {
|
|
117
|
-
result[urlIndex] = text;
|
|
118
|
-
numComplete++;
|
|
119
|
-
|
|
120
|
-
// When all files have downloaded
|
|
121
|
-
if (numComplete == numUrls) {
|
|
122
|
-
callback(result);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
108
|
+
const numUrls = urls.length;
|
|
109
|
+
let numComplete = 0;
|
|
110
|
+
const result = [];
|
|
125
111
|
|
|
126
|
-
|
|
127
|
-
|
|
112
|
+
// Callback for a single file
|
|
113
|
+
function partialCallback(text, urlIndex) {
|
|
114
|
+
result[urlIndex] = text;
|
|
115
|
+
numComplete++;
|
|
116
|
+
|
|
117
|
+
// When all files have downloaded
|
|
118
|
+
if (numComplete == numUrls) {
|
|
119
|
+
callback(result);
|
|
128
120
|
}
|
|
129
|
-
}
|
|
121
|
+
}
|
|
130
122
|
|
|
123
|
+
for (let i = 0; i < numUrls; i++) {
|
|
124
|
+
loadExternalFile(urls[i], i, partialCallback, errorCallback);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
131
127
|
|
|
132
128
|
//Get the colours at index
|
|
133
129
|
const getColorsRGB = (colors, index) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
hex_value = colors[index_in_colors].b;
|
|
148
|
-
}
|
|
149
|
-
const mycolor = new THREE.Color(hex_value);
|
|
150
|
-
return [mycolor.r, mycolor.g, mycolor.b];
|
|
151
|
-
}
|
|
130
|
+
const index_in_colors = Math.floor(index / 3);
|
|
131
|
+
const remainder = index % 3;
|
|
132
|
+
let hex_value = 0;
|
|
133
|
+
if (remainder == 0) {
|
|
134
|
+
hex_value = colors[index_in_colors].r;
|
|
135
|
+
} else if (remainder == 1) {
|
|
136
|
+
hex_value = colors[index_in_colors].g;
|
|
137
|
+
} else if (remainder == 2) {
|
|
138
|
+
hex_value = colors[index_in_colors].b;
|
|
139
|
+
}
|
|
140
|
+
const mycolor = new THREE.Color(hex_value);
|
|
141
|
+
return [mycolor.r, mycolor.g, mycolor.b];
|
|
142
|
+
};
|
|
152
143
|
|
|
153
144
|
//morphColor0/morphColor1 attribute -> morph colour target last copied into it
|
|
154
145
|
const morphColorSources = new WeakMap();
|
|
155
146
|
|
|
156
|
-
const updateMorphColorAttribute = function(targetGeometry, morph) {
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
147
|
+
const updateMorphColorAttribute = function (targetGeometry, morph) {
|
|
148
|
+
if (
|
|
149
|
+
morph &&
|
|
150
|
+
targetGeometry &&
|
|
151
|
+
targetGeometry.morphAttributes &&
|
|
152
|
+
targetGeometry.morphAttributes['color']
|
|
153
|
+
) {
|
|
154
|
+
const morphColors = targetGeometry.morphAttributes['color'];
|
|
160
155
|
const influences = morph.morphTargetInfluences;
|
|
161
156
|
const length = influences.length;
|
|
162
157
|
//Find the first two morph targets with non-zero influence
|
|
@@ -199,9 +194,13 @@ const updateMorphColorAttribute = function(targetGeometry, morph) {
|
|
|
199
194
|
let attribute1 = targetGeometry.getAttribute('morphColor1');
|
|
200
195
|
if (!attribute0 || !attribute1) {
|
|
201
196
|
attribute0 = new THREE.Float32BufferAttribute(
|
|
202
|
-
new Float32Array(morphColors[0].array.length),
|
|
197
|
+
new Float32Array(morphColors[0].array.length),
|
|
198
|
+
morphColors[0].itemSize,
|
|
199
|
+
);
|
|
203
200
|
attribute1 = new THREE.Float32BufferAttribute(
|
|
204
|
-
new Float32Array(morphColors[0].array.length),
|
|
201
|
+
new Float32Array(morphColors[0].array.length),
|
|
202
|
+
morphColors[0].itemSize,
|
|
203
|
+
);
|
|
205
204
|
attribute0.setUsage(THREE.DynamicDrawUsage);
|
|
206
205
|
attribute1.setUsage(THREE.DynamicDrawUsage);
|
|
207
206
|
targetGeometry.setAttribute('morphColor0', attribute0);
|
|
@@ -221,24 +220,25 @@ const updateMorphColorAttribute = function(targetGeometry, morph) {
|
|
|
221
220
|
attribute1.needsUpdate = true;
|
|
222
221
|
morphColorSources.set(attribute1, source1);
|
|
223
222
|
}
|
|
224
|
-
const morphColorMix =
|
|
225
|
-
morph.material
|
|
223
|
+
const morphColorMix =
|
|
224
|
+
morph.material &&
|
|
225
|
+
morph.material.userData &&
|
|
226
|
+
morph.material.userData.uniforms &&
|
|
227
|
+
morph.material.userData.uniforms.morphColorMix;
|
|
226
228
|
if (morphColorMix) {
|
|
227
229
|
morphColorMix.value = mix;
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
+
};
|
|
232
233
|
|
|
233
234
|
const toBufferGeometry = (geometryIn) => {
|
|
234
235
|
const geometry = geometryIn.clone();
|
|
235
236
|
geometry.colorsNeedUpdate = true;
|
|
236
237
|
geometry.computeBoundingBox();
|
|
237
238
|
geometry.computeBoundingSphere();
|
|
238
|
-
if (geometryIn._video)
|
|
239
|
-
geometry._video = geometryIn._video;
|
|
239
|
+
if (geometryIn._video) geometry._video = geometryIn._video;
|
|
240
240
|
return geometry;
|
|
241
|
-
}
|
|
241
|
+
};
|
|
242
242
|
|
|
243
243
|
/**
|
|
244
244
|
* Merges a set of attributes into a single instance. All attributes must have compatible properties and types.
|
|
@@ -247,93 +247,77 @@ const toBufferGeometry = (geometryIn) => {
|
|
|
247
247
|
* @param {Array<BufferAttribute>} attributes - The attributes to merge.
|
|
248
248
|
* @return {?BufferAttribute} The merged attribute. Returns `null` if the merge does not succeed.
|
|
249
249
|
*/
|
|
250
|
-
function mergeAttributes(
|
|
251
|
-
|
|
250
|
+
function mergeAttributes(attributes) {
|
|
252
251
|
let TypedArray;
|
|
253
252
|
let itemSize;
|
|
254
253
|
let normalized;
|
|
255
|
-
let gpuType = -
|
|
254
|
+
let gpuType = -1;
|
|
256
255
|
let arrayLength = 0;
|
|
257
256
|
|
|
258
|
-
for (
|
|
259
|
-
|
|
260
|
-
const attribute = attributes[ i ];
|
|
257
|
+
for (let i = 0; i < attributes.length; ++i) {
|
|
258
|
+
const attribute = attributes[i];
|
|
261
259
|
|
|
262
|
-
if (
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
if (TypedArray === undefined) TypedArray = attribute.array.constructor;
|
|
261
|
+
if (TypedArray !== attribute.array.constructor) {
|
|
262
|
+
console.error(
|
|
263
|
+
'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes.',
|
|
264
|
+
);
|
|
266
265
|
return null;
|
|
267
|
-
|
|
268
266
|
}
|
|
269
267
|
|
|
270
|
-
if (
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
if (itemSize === undefined) itemSize = attribute.itemSize;
|
|
269
|
+
if (itemSize !== attribute.itemSize) {
|
|
270
|
+
console.error(
|
|
271
|
+
'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes.',
|
|
272
|
+
);
|
|
274
273
|
return null;
|
|
275
|
-
|
|
276
274
|
}
|
|
277
275
|
|
|
278
|
-
if (
|
|
279
|
-
if (
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
if (normalized === undefined) normalized = attribute.normalized;
|
|
277
|
+
if (normalized !== attribute.normalized) {
|
|
278
|
+
console.error(
|
|
279
|
+
'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes.',
|
|
280
|
+
);
|
|
282
281
|
return null;
|
|
283
|
-
|
|
284
282
|
}
|
|
285
283
|
|
|
286
|
-
if (
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
|
|
284
|
+
if (gpuType === -1) gpuType = attribute.gpuType;
|
|
285
|
+
if (gpuType !== attribute.gpuType) {
|
|
286
|
+
console.error(
|
|
287
|
+
'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.gpuType must be consistent across matching attributes.',
|
|
288
|
+
);
|
|
290
289
|
return null;
|
|
291
|
-
|
|
292
290
|
}
|
|
293
291
|
|
|
294
292
|
arrayLength += attribute.count * itemSize;
|
|
295
|
-
|
|
296
293
|
}
|
|
297
294
|
|
|
298
|
-
const array = new TypedArray(
|
|
299
|
-
const result = new THREE.BufferAttribute(
|
|
295
|
+
const array = new TypedArray(arrayLength);
|
|
296
|
+
const result = new THREE.BufferAttribute(array, itemSize, normalized);
|
|
300
297
|
let offset = 0;
|
|
301
298
|
|
|
302
|
-
for (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if ( attribute.isInterleavedBufferAttribute ) {
|
|
306
|
-
|
|
299
|
+
for (let i = 0; i < attributes.length; ++i) {
|
|
300
|
+
const attribute = attributes[i];
|
|
301
|
+
if (attribute.isInterleavedBufferAttribute) {
|
|
307
302
|
const tupleOffset = offset / itemSize;
|
|
308
|
-
for (
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const value = attribute.getComponent( j, c );
|
|
313
|
-
result.setComponent( j + tupleOffset, c, value );
|
|
314
|
-
|
|
303
|
+
for (let j = 0, l = attribute.count; j < l; j++) {
|
|
304
|
+
for (let c = 0; c < itemSize; c++) {
|
|
305
|
+
const value = attribute.getComponent(j, c);
|
|
306
|
+
result.setComponent(j + tupleOffset, c, value);
|
|
315
307
|
}
|
|
316
|
-
|
|
317
308
|
}
|
|
318
|
-
|
|
319
309
|
} else {
|
|
320
|
-
|
|
321
|
-
array.set( attribute.array, offset );
|
|
322
|
-
|
|
310
|
+
array.set(attribute.array, offset);
|
|
323
311
|
}
|
|
324
312
|
|
|
325
313
|
offset += attribute.count * itemSize;
|
|
326
|
-
|
|
327
314
|
}
|
|
328
315
|
|
|
329
|
-
if (
|
|
330
|
-
|
|
316
|
+
if (gpuType !== undefined) {
|
|
331
317
|
result.gpuType = gpuType;
|
|
332
|
-
|
|
333
318
|
}
|
|
334
319
|
|
|
335
320
|
return result;
|
|
336
|
-
|
|
337
321
|
}
|
|
338
322
|
|
|
339
323
|
/**
|
|
@@ -343,378 +327,331 @@ function mergeAttributes( attributes ) {
|
|
|
343
327
|
* @param {boolean} [useGroups=false] - Whether to use groups or not.
|
|
344
328
|
* @return {?BufferGeometry} The merged geometry. Returns `null` if the merge does not succeed.
|
|
345
329
|
*/
|
|
346
|
-
const mergeGeometries = (
|
|
347
|
-
|
|
348
|
-
const isIndexed = geometries[ 0 ].index !== null;
|
|
330
|
+
const mergeGeometries = (geometries, useGroups = false) => {
|
|
331
|
+
const isIndexed = geometries[0].index !== null;
|
|
349
332
|
|
|
350
|
-
const attributesUsed = new Set(
|
|
351
|
-
const morphAttributesUsed = new Set(
|
|
333
|
+
const attributesUsed = new Set(Object.keys(geometries[0].attributes));
|
|
334
|
+
const morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));
|
|
352
335
|
|
|
353
336
|
const attributes = {};
|
|
354
337
|
const morphAttributes = {};
|
|
355
338
|
|
|
356
|
-
const morphTargetsRelative = geometries[
|
|
339
|
+
const morphTargetsRelative = geometries[0].morphTargetsRelative;
|
|
357
340
|
|
|
358
341
|
const mergedGeometry = new THREE.BufferGeometry();
|
|
359
342
|
|
|
360
343
|
let offset = 0;
|
|
361
344
|
|
|
362
|
-
for (
|
|
363
|
-
|
|
364
|
-
const geometry = geometries[ i ];
|
|
345
|
+
for (let i = 0; i < geometries.length; ++i) {
|
|
346
|
+
const geometry = geometries[i];
|
|
365
347
|
let attributesCount = 0;
|
|
366
348
|
|
|
367
349
|
// ensure that all geometries are indexed, or none
|
|
368
350
|
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
351
|
+
if (isIndexed !== (geometry.index !== null)) {
|
|
352
|
+
console.error(
|
|
353
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
354
|
+
i +
|
|
355
|
+
'. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.',
|
|
356
|
+
);
|
|
372
357
|
return null;
|
|
373
|
-
|
|
374
358
|
}
|
|
375
359
|
|
|
376
360
|
// gather attributes, exit early if they're different
|
|
377
361
|
|
|
378
|
-
for (
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
362
|
+
for (const name in geometry.attributes) {
|
|
363
|
+
if (!attributesUsed.has(name)) {
|
|
364
|
+
console.error(
|
|
365
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
366
|
+
i +
|
|
367
|
+
'. All geometries must have compatible attributes; make sure "' +
|
|
368
|
+
name +
|
|
369
|
+
'" attribute exists among all geometries, or in none of them.',
|
|
370
|
+
);
|
|
383
371
|
return null;
|
|
384
|
-
|
|
385
372
|
}
|
|
386
373
|
|
|
387
|
-
if (
|
|
374
|
+
if (attributes[name] === undefined) attributes[name] = [];
|
|
388
375
|
|
|
389
|
-
attributes[
|
|
390
|
-
|
|
391
|
-
attributesCount ++;
|
|
376
|
+
attributes[name].push(geometry.attributes[name]);
|
|
392
377
|
|
|
378
|
+
attributesCount++;
|
|
393
379
|
}
|
|
394
380
|
|
|
395
381
|
// ensure geometries have the same number of attributes
|
|
396
382
|
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
383
|
+
if (attributesCount !== attributesUsed.size) {
|
|
384
|
+
console.error(
|
|
385
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
386
|
+
i +
|
|
387
|
+
'. Make sure all geometries have the same number of attributes.',
|
|
388
|
+
);
|
|
400
389
|
return null;
|
|
401
|
-
|
|
402
390
|
}
|
|
403
391
|
|
|
404
392
|
// gather morph attributes, exit early if they're different
|
|
405
393
|
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
|
|
394
|
+
if (morphTargetsRelative !== geometry.morphTargetsRelative) {
|
|
395
|
+
console.error(
|
|
396
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
397
|
+
i +
|
|
398
|
+
'. .morphTargetsRelative must be consistent throughout all geometries.',
|
|
399
|
+
);
|
|
409
400
|
return null;
|
|
410
|
-
|
|
411
401
|
}
|
|
412
402
|
|
|
413
|
-
for (
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
403
|
+
for (const name in geometry.morphAttributes) {
|
|
404
|
+
if (!morphAttributesUsed.has(name)) {
|
|
405
|
+
console.error(
|
|
406
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
407
|
+
i +
|
|
408
|
+
'. .morphAttributes must be consistent throughout all geometries.',
|
|
409
|
+
);
|
|
418
410
|
return null;
|
|
419
|
-
|
|
420
411
|
}
|
|
421
412
|
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
morphAttributes[ name ].push( geometry.morphAttributes[ name ] );
|
|
413
|
+
if (morphAttributes[name] === undefined) morphAttributes[name] = [];
|
|
425
414
|
|
|
415
|
+
morphAttributes[name].push(geometry.morphAttributes[name]);
|
|
426
416
|
}
|
|
427
417
|
|
|
428
|
-
if (
|
|
429
|
-
|
|
418
|
+
if (useGroups) {
|
|
430
419
|
let count;
|
|
431
420
|
|
|
432
|
-
if (
|
|
433
|
-
|
|
421
|
+
if (isIndexed) {
|
|
434
422
|
count = geometry.index.count;
|
|
435
|
-
|
|
436
|
-
} else if ( geometry.attributes.position !== undefined ) {
|
|
437
|
-
|
|
423
|
+
} else if (geometry.attributes.position !== undefined) {
|
|
438
424
|
count = geometry.attributes.position.count;
|
|
439
|
-
|
|
440
425
|
} else {
|
|
441
|
-
|
|
442
|
-
|
|
426
|
+
console.error(
|
|
427
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' +
|
|
428
|
+
i +
|
|
429
|
+
'. The geometry must have either an index or a position attribute',
|
|
430
|
+
);
|
|
443
431
|
return null;
|
|
444
|
-
|
|
445
432
|
}
|
|
446
433
|
|
|
447
|
-
mergedGeometry.addGroup(
|
|
434
|
+
mergedGeometry.addGroup(offset, count, i);
|
|
448
435
|
|
|
449
436
|
offset += count;
|
|
450
|
-
|
|
451
437
|
}
|
|
452
|
-
|
|
453
438
|
}
|
|
454
439
|
|
|
455
440
|
// merge indices
|
|
456
441
|
|
|
457
|
-
if (
|
|
458
|
-
|
|
442
|
+
if (isIndexed) {
|
|
459
443
|
let indexOffset = 0;
|
|
460
444
|
const mergedIndex = [];
|
|
461
445
|
|
|
462
|
-
for (
|
|
463
|
-
|
|
464
|
-
const index = geometries[ i ].index;
|
|
465
|
-
|
|
466
|
-
for ( let j = 0; j < index.count; ++ j ) {
|
|
467
|
-
|
|
468
|
-
mergedIndex.push( index.getX( j ) + indexOffset );
|
|
446
|
+
for (let i = 0; i < geometries.length; ++i) {
|
|
447
|
+
const index = geometries[i].index;
|
|
469
448
|
|
|
449
|
+
for (let j = 0; j < index.count; ++j) {
|
|
450
|
+
mergedIndex.push(index.getX(j) + indexOffset);
|
|
470
451
|
}
|
|
471
452
|
|
|
472
|
-
indexOffset += geometries[
|
|
473
|
-
|
|
453
|
+
indexOffset += geometries[i].attributes.position.count;
|
|
474
454
|
}
|
|
475
455
|
|
|
476
|
-
mergedGeometry.setIndex(
|
|
477
|
-
|
|
456
|
+
mergedGeometry.setIndex(mergedIndex);
|
|
478
457
|
}
|
|
479
458
|
|
|
480
459
|
// merge attributes
|
|
481
460
|
|
|
482
|
-
for (
|
|
483
|
-
|
|
484
|
-
const mergedAttribute = mergeAttributes( attributes[ name ] );
|
|
485
|
-
|
|
486
|
-
if ( ! mergedAttribute ) {
|
|
461
|
+
for (const name in attributes) {
|
|
462
|
+
const mergedAttribute = mergeAttributes(attributes[name]);
|
|
487
463
|
|
|
488
|
-
|
|
464
|
+
if (!mergedAttribute) {
|
|
465
|
+
console.error(
|
|
466
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' +
|
|
467
|
+
name +
|
|
468
|
+
' attribute.',
|
|
469
|
+
);
|
|
489
470
|
return null;
|
|
490
|
-
|
|
491
471
|
}
|
|
492
472
|
|
|
493
|
-
mergedGeometry.setAttribute(
|
|
494
|
-
|
|
473
|
+
mergedGeometry.setAttribute(name, mergedAttribute);
|
|
495
474
|
}
|
|
496
475
|
|
|
497
476
|
// merge morph attributes
|
|
498
477
|
|
|
499
|
-
for (
|
|
500
|
-
|
|
501
|
-
const numMorphTargets = morphAttributes[ name ][ 0 ].length;
|
|
478
|
+
for (const name in morphAttributes) {
|
|
479
|
+
const numMorphTargets = morphAttributes[name][0].length;
|
|
502
480
|
|
|
503
|
-
if (
|
|
481
|
+
if (numMorphTargets === 0) break;
|
|
504
482
|
|
|
505
483
|
mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
|
|
506
|
-
mergedGeometry.morphAttributes[
|
|
507
|
-
|
|
508
|
-
for ( let i = 0; i < numMorphTargets; ++ i ) {
|
|
484
|
+
mergedGeometry.morphAttributes[name] = [];
|
|
509
485
|
|
|
486
|
+
for (let i = 0; i < numMorphTargets; ++i) {
|
|
510
487
|
const morphAttributesToMerge = [];
|
|
511
488
|
|
|
512
|
-
for (
|
|
513
|
-
|
|
514
|
-
morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
|
|
515
|
-
|
|
489
|
+
for (let j = 0; j < morphAttributes[name].length; ++j) {
|
|
490
|
+
morphAttributesToMerge.push(morphAttributes[name][j][i]);
|
|
516
491
|
}
|
|
517
492
|
|
|
518
|
-
const mergedMorphAttribute = mergeAttributes(
|
|
519
|
-
|
|
520
|
-
if ( ! mergedMorphAttribute ) {
|
|
493
|
+
const mergedMorphAttribute = mergeAttributes(morphAttributesToMerge);
|
|
521
494
|
|
|
522
|
-
|
|
495
|
+
if (!mergedMorphAttribute) {
|
|
496
|
+
console.error(
|
|
497
|
+
'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' +
|
|
498
|
+
name +
|
|
499
|
+
' morphAttribute.',
|
|
500
|
+
);
|
|
523
501
|
return null;
|
|
524
|
-
|
|
525
502
|
}
|
|
526
503
|
|
|
527
|
-
mergedGeometry.morphAttributes[
|
|
528
|
-
|
|
504
|
+
mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);
|
|
529
505
|
}
|
|
530
|
-
|
|
531
506
|
}
|
|
532
507
|
|
|
533
508
|
return mergedGeometry;
|
|
509
|
+
};
|
|
534
510
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const mergeVertices = ( geometry, tolerance = 1e-4 ) => {
|
|
538
|
-
|
|
539
|
-
tolerance = Math.max( tolerance, Number.EPSILON );
|
|
511
|
+
const mergeVertices = (geometry, tolerance = 1e-4) => {
|
|
512
|
+
tolerance = Math.max(tolerance, Number.EPSILON);
|
|
540
513
|
|
|
541
514
|
// Generate an index buffer if the geometry doesn't have one, or optimize it
|
|
542
515
|
// if it's already available.
|
|
543
516
|
var hashToIndex = {};
|
|
544
517
|
var indices = geometry.getIndex();
|
|
545
|
-
var positions = geometry.getAttribute(
|
|
518
|
+
var positions = geometry.getAttribute('position');
|
|
546
519
|
var vertexCount = indices ? indices.count : positions.count;
|
|
547
520
|
|
|
548
521
|
// next value for triangle indices
|
|
549
522
|
var nextIndex = 0;
|
|
550
523
|
|
|
551
524
|
// attributes and new attribute arrays
|
|
552
|
-
var attributeNames = Object.keys(
|
|
525
|
+
var attributeNames = Object.keys(geometry.attributes);
|
|
553
526
|
var attrArrays = {};
|
|
554
527
|
var morphAttrsArrays = {};
|
|
555
528
|
var newIndices = [];
|
|
556
|
-
var getters = [
|
|
529
|
+
var getters = ['getX', 'getY', 'getZ', 'getW'];
|
|
557
530
|
|
|
558
531
|
// initialize the arrays
|
|
559
|
-
for (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
attrArrays[ name ] = [];
|
|
532
|
+
for (var i = 0, l = attributeNames.length; i < l; i++) {
|
|
533
|
+
var name = attributeNames[i];
|
|
563
534
|
|
|
564
|
-
|
|
565
|
-
if ( morphAttr ) {
|
|
566
|
-
|
|
567
|
-
morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] );
|
|
568
|
-
|
|
569
|
-
}
|
|
535
|
+
attrArrays[name] = [];
|
|
570
536
|
|
|
537
|
+
var morphAttr = geometry.morphAttributes[name];
|
|
538
|
+
if (morphAttr) {
|
|
539
|
+
morphAttrsArrays[name] = new Array(morphAttr.length).fill().map(() => []);
|
|
540
|
+
}
|
|
571
541
|
}
|
|
572
542
|
|
|
573
543
|
// convert the error tolerance to an amount of decimal places to truncate to
|
|
574
|
-
var decimalShift = Math.log10(
|
|
575
|
-
var shiftMultiplier = Math.pow(
|
|
576
|
-
for (
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
// double tilde truncates the decimal value
|
|
591
|
-
hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier ) },`;
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
544
|
+
var decimalShift = Math.log10(1 / tolerance);
|
|
545
|
+
var shiftMultiplier = Math.pow(10, decimalShift);
|
|
546
|
+
for (var i = 0; i < vertexCount; i++) {
|
|
547
|
+
var index = indices ? indices.getX(i) : i;
|
|
548
|
+
|
|
549
|
+
// Generate a hash for the vertex attributes at the current index 'i'
|
|
550
|
+
var hash = '';
|
|
551
|
+
for (var j = 0, l = attributeNames.length; j < l; j++) {
|
|
552
|
+
var name = attributeNames[j];
|
|
553
|
+
var attribute = geometry.getAttribute(name);
|
|
554
|
+
var itemSize = attribute.itemSize;
|
|
555
|
+
|
|
556
|
+
for (var k = 0; k < itemSize; k++) {
|
|
557
|
+
// double tilde truncates the decimal value
|
|
558
|
+
hash += `${~~(attribute[getters[k]](index) * shiftMultiplier)},`;
|
|
595
559
|
}
|
|
560
|
+
}
|
|
596
561
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if ( morphAttr ) {
|
|
621
|
-
|
|
622
|
-
for ( var m = 0, ml = morphAttr.length; m < ml; m ++ ) {
|
|
623
|
-
|
|
624
|
-
newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
|
|
562
|
+
// Add another reference to the vertex if it's already
|
|
563
|
+
// used by another index
|
|
564
|
+
if (hash in hashToIndex) {
|
|
565
|
+
newIndices.push(hashToIndex[hash]);
|
|
566
|
+
} else {
|
|
567
|
+
// copy data to the new index in the attribute arrays
|
|
568
|
+
for (var j = 0, l = attributeNames.length; j < l; j++) {
|
|
569
|
+
var name = attributeNames[j];
|
|
570
|
+
var attribute = geometry.getAttribute(name);
|
|
571
|
+
var morphAttr = geometry.morphAttributes[name];
|
|
572
|
+
var itemSize = attribute.itemSize;
|
|
573
|
+
var newarray = attrArrays[name];
|
|
574
|
+
var newMorphArrays = morphAttrsArrays[name];
|
|
575
|
+
|
|
576
|
+
for (var k = 0; k < itemSize; k++) {
|
|
577
|
+
var getterFunc = getters[k];
|
|
578
|
+
newarray.push(attribute[getterFunc](index));
|
|
579
|
+
|
|
580
|
+
if (morphAttr) {
|
|
581
|
+
for (var m = 0, ml = morphAttr.length; m < ml; m++) {
|
|
582
|
+
newMorphArrays[m].push(morphAttr[m][getterFunc](index));
|
|
583
|
+
}
|
|
632
584
|
}
|
|
633
|
-
|
|
634
|
-
hashToIndex[ hash ] = nextIndex;
|
|
635
|
-
newIndices.push( nextIndex );
|
|
636
|
-
nextIndex ++;
|
|
637
|
-
|
|
585
|
+
}
|
|
638
586
|
}
|
|
639
587
|
|
|
588
|
+
hashToIndex[hash] = nextIndex;
|
|
589
|
+
newIndices.push(nextIndex);
|
|
590
|
+
nextIndex++;
|
|
591
|
+
}
|
|
640
592
|
}
|
|
641
593
|
|
|
642
594
|
// Generate typed arrays from new attribute arrays and update
|
|
643
595
|
// the attributeBuffers
|
|
644
596
|
const result = geometry.clone();
|
|
645
|
-
for (
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
attribute = geometry.getAttribute( name ).clone();
|
|
659
|
-
attribute.setArray( buffer );
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
result.setAttribute( name, attribute );
|
|
664
|
-
|
|
665
|
-
// Update the attribute arrays
|
|
666
|
-
if ( name in morphAttrsArrays ) {
|
|
667
|
-
|
|
668
|
-
for ( var j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
|
|
597
|
+
for (var i = 0, l = attributeNames.length; i < l; i++) {
|
|
598
|
+
var name = attributeNames[i];
|
|
599
|
+
var oldAttribute = geometry.getAttribute(name);
|
|
600
|
+
var attribute;
|
|
601
|
+
|
|
602
|
+
var buffer = new oldAttribute.array.constructor(attrArrays[name]);
|
|
603
|
+
if (oldAttribute.isInterleavedBufferAttribute) {
|
|
604
|
+
attribute = new THREE.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.itemSize);
|
|
605
|
+
} else {
|
|
606
|
+
attribute = geometry.getAttribute(name).clone();
|
|
607
|
+
attribute.setArray(buffer);
|
|
608
|
+
}
|
|
669
609
|
|
|
670
|
-
|
|
671
|
-
morphAttribute.setArray( new morphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] ) );
|
|
672
|
-
result.morphAttributes[ name ][ j ] = morphAttribute;
|
|
673
|
-
|
|
674
|
-
}
|
|
610
|
+
result.setAttribute(name, attribute);
|
|
675
611
|
|
|
612
|
+
// Update the attribute arrays
|
|
613
|
+
if (name in morphAttrsArrays) {
|
|
614
|
+
for (var j = 0; j < morphAttrsArrays[name].length; j++) {
|
|
615
|
+
var morphAttribute = geometry.morphAttributes[name][j].clone();
|
|
616
|
+
morphAttribute.setArray(new morphAttribute.array.constructor(morphAttrsArrays[name][j]));
|
|
617
|
+
result.morphAttributes[name][j] = morphAttribute;
|
|
676
618
|
}
|
|
677
|
-
|
|
619
|
+
}
|
|
678
620
|
}
|
|
679
621
|
|
|
680
622
|
// Generate an index buffer typed array
|
|
681
623
|
var cons = Uint8Array;
|
|
682
|
-
if (
|
|
683
|
-
if (
|
|
624
|
+
if (newIndices.length >= Math.pow(2, 8)) cons = Uint16Array;
|
|
625
|
+
if (newIndices.length >= Math.pow(2, 16)) cons = Uint32Array;
|
|
684
626
|
|
|
685
|
-
var newIndexBuffer = new cons(
|
|
627
|
+
var newIndexBuffer = new cons(newIndices);
|
|
686
628
|
var newIndices = null;
|
|
687
|
-
if (
|
|
688
|
-
|
|
689
|
-
newIndices = new THREE.BufferAttribute( newIndexBuffer, 1 );
|
|
690
|
-
|
|
629
|
+
if (indices === null) {
|
|
630
|
+
newIndices = new THREE.BufferAttribute(newIndexBuffer, 1);
|
|
691
631
|
} else {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
newIndices.setArray( newIndexBuffer );
|
|
695
|
-
|
|
632
|
+
newIndices = geometry.getIndex().clone();
|
|
633
|
+
newIndices.setArray(newIndexBuffer);
|
|
696
634
|
}
|
|
697
635
|
|
|
698
|
-
result.setIndex(
|
|
636
|
+
result.setIndex(newIndices);
|
|
699
637
|
|
|
700
638
|
return result;
|
|
701
|
-
}
|
|
639
|
+
};
|
|
702
640
|
|
|
703
641
|
function PhongToToon(materialIn) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
return materialIn;
|
|
642
|
+
if (materialIn.isMeshPhongMaterial) {
|
|
643
|
+
let material = new THREE.MeshToonMaterial({
|
|
644
|
+
color: materialIn.color.clone(),
|
|
645
|
+
vertexColors: materialIn.vertexColors,
|
|
646
|
+
transparent: materialIn.transparent,
|
|
647
|
+
opacity: materialIn.opacity,
|
|
648
|
+
side: materialIn.side,
|
|
649
|
+
});
|
|
650
|
+
if (materialIn.map) material.map = materialIn.map;
|
|
651
|
+
return material;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
return materialIn;
|
|
718
655
|
}
|
|
719
656
|
|
|
720
657
|
/**
|
|
@@ -722,21 +659,21 @@ function PhongToToon(materialIn) {
|
|
|
722
659
|
* and initial coords.
|
|
723
660
|
*/
|
|
724
661
|
function createBufferGeometry(length, coords) {
|
|
725
|
-
if (coords &&
|
|
726
|
-
const geometry = new THREE.BufferGeometry()
|
|
662
|
+
if (coords && length >= coords.length) {
|
|
663
|
+
const geometry = new THREE.BufferGeometry();
|
|
727
664
|
const vertices = new Float32Array(length * 3);
|
|
728
665
|
let i = 0;
|
|
729
|
-
coords.forEach(coord => {
|
|
666
|
+
coords.forEach((coord) => {
|
|
730
667
|
vertices[i++] = coord[0];
|
|
731
668
|
vertices[i++] = coord[1];
|
|
732
669
|
vertices[i++] = coord[2];
|
|
733
670
|
});
|
|
734
|
-
geometry.setAttribute(
|
|
671
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
|
|
735
672
|
geometry.setDrawRange(0, coords.length);
|
|
736
673
|
return geometry;
|
|
737
674
|
}
|
|
738
675
|
return undefined;
|
|
739
|
-
}
|
|
676
|
+
}
|
|
740
677
|
|
|
741
678
|
/*
|
|
742
679
|
* WebGPURenderer converts 16 bit index buffers to 32 bit and keeps the
|
|
@@ -830,23 +767,25 @@ function createNewSpriteText(text, height, colour, font, pixel, weight) {
|
|
|
830
767
|
*/
|
|
831
768
|
function isRegionGroup(regionPath, groupName, comparePath) {
|
|
832
769
|
if (comparePath) {
|
|
833
|
-
const region = regionPath ? regionPath :
|
|
834
|
-
const group = groupName ? groupName :
|
|
770
|
+
const region = regionPath ? regionPath : '';
|
|
771
|
+
const group = groupName ? groupName : '';
|
|
835
772
|
const n = comparePath.lastIndexOf('/');
|
|
836
773
|
if (n > -1) {
|
|
837
774
|
let r = undefined;
|
|
838
775
|
let g = undefined;
|
|
839
776
|
r = comparePath.substring(0, n);
|
|
840
777
|
g = comparePath.substring(n + 1);
|
|
841
|
-
if (r ===
|
|
842
|
-
if (g ===
|
|
778
|
+
if (r === '*' || r === '**' || r.toLowerCase() === region.toLowerCase()) {
|
|
779
|
+
if (g === '*' || g === '**' || g.toLowerCase() === group.toLowerCase()) {
|
|
843
780
|
return true;
|
|
844
781
|
}
|
|
845
782
|
}
|
|
846
783
|
} else {
|
|
847
784
|
//one single value if one of the region / group matches
|
|
848
|
-
if (
|
|
849
|
-
|
|
785
|
+
if (
|
|
786
|
+
region.toLowerCase() === comparePath.toLowerCase() ||
|
|
787
|
+
group.toLowerCase() === comparePath.toLowerCase()
|
|
788
|
+
) {
|
|
850
789
|
return true;
|
|
851
790
|
}
|
|
852
791
|
}
|
|
@@ -869,7 +808,7 @@ function removeVertexAtIndex(geometry, index, maintainLength) {
|
|
|
869
808
|
// Helper to remove elements from a typed array
|
|
870
809
|
const removeElements = (attribute, name) => {
|
|
871
810
|
const array = attribute.array;
|
|
872
|
-
if (array.length <
|
|
811
|
+
if (array.length < start + deleteCount) {
|
|
873
812
|
return false;
|
|
874
813
|
}
|
|
875
814
|
if (maintainLength) {
|
|
@@ -894,8 +833,8 @@ function removeVertexAtIndex(geometry, index, maintainLength) {
|
|
|
894
833
|
|
|
895
834
|
// If the geometry is indexed, the index buffer will also need adjustment
|
|
896
835
|
if (geometry.index !== null) {
|
|
897
|
-
|
|
898
|
-
|
|
836
|
+
// This is more complex, typically easier to work with non-indexed geometry when modifying vertices
|
|
837
|
+
console.warn('Removing vertices from indexed geometry requires index buffer recalculation.');
|
|
899
838
|
}
|
|
900
839
|
|
|
901
840
|
return removed;
|
|
@@ -985,5 +924,4 @@ export {
|
|
|
985
924
|
removeVertexAtIndex,
|
|
986
925
|
updateMorphColorAttribute,
|
|
987
926
|
toBufferGeometry,
|
|
988
|
-
|
|
989
|
-
|
|
927
|
+
};
|