@headless-three/renderer 0.1.7 → 0.1.9

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.
Files changed (58) hide show
  1. package/README.md +227 -52
  2. package/dist/attributes.d.ts +7 -5
  3. package/dist/attributes.d.ts.map +1 -1
  4. package/dist/attributes.js +112 -36
  5. package/dist/attributes.js.map +1 -1
  6. package/dist/camera.d.ts +1 -0
  7. package/dist/camera.d.ts.map +1 -1
  8. package/dist/camera.js +52 -13
  9. package/dist/camera.js.map +1 -1
  10. package/dist/clipping.d.ts +6 -0
  11. package/dist/clipping.d.ts.map +1 -0
  12. package/dist/clipping.js +84 -0
  13. package/dist/clipping.js.map +1 -0
  14. package/dist/color.d.ts +8 -3
  15. package/dist/color.d.ts.map +1 -1
  16. package/dist/color.js +136 -11
  17. package/dist/color.js.map +1 -1
  18. package/dist/index.d.ts +770 -5
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +6213 -46
  21. package/dist/index.js.map +1 -1
  22. package/dist/layers.d.ts +3 -0
  23. package/dist/layers.d.ts.map +1 -0
  24. package/dist/layers.js +33 -0
  25. package/dist/layers.js.map +1 -0
  26. package/dist/lights.d.ts +5 -4
  27. package/dist/lights.d.ts.map +1 -1
  28. package/dist/lights.js +473 -77
  29. package/dist/lights.js.map +1 -1
  30. package/dist/loaders.d.ts +92 -0
  31. package/dist/loaders.d.ts.map +1 -0
  32. package/dist/loaders.js +858 -0
  33. package/dist/loaders.js.map +1 -0
  34. package/dist/materials.d.ts +38 -6
  35. package/dist/materials.d.ts.map +1 -1
  36. package/dist/materials.js +4236 -162
  37. package/dist/materials.js.map +1 -1
  38. package/dist/math.js +2 -2
  39. package/dist/math.js.map +1 -1
  40. package/dist/morphs.d.ts.map +1 -1
  41. package/dist/morphs.js +50 -15
  42. package/dist/morphs.js.map +1 -1
  43. package/dist/objects.d.ts +4 -0
  44. package/dist/objects.d.ts.map +1 -0
  45. package/dist/objects.js +25 -0
  46. package/dist/objects.js.map +1 -0
  47. package/dist/scene.d.ts +279 -2
  48. package/dist/scene.d.ts.map +1 -1
  49. package/dist/scene.js +3818 -104
  50. package/dist/scene.js.map +1 -1
  51. package/dist/skinning.d.ts.map +1 -1
  52. package/dist/skinning.js +37 -18
  53. package/dist/skinning.js.map +1 -1
  54. package/dist/types.d.ts +1264 -12
  55. package/dist/types.d.ts.map +1 -1
  56. package/native.d.ts +767 -3
  57. package/native.js +54 -52
  58. package/package.json +20 -9
package/dist/scene.js CHANGED
@@ -1,46 +1,157 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSceneExtractionCache = createSceneExtractionCache;
3
4
  exports.flattenScene = flattenScene;
5
+ exports.commitNativeMeshPayloadCache = commitNativeMeshPayloadCache;
4
6
  const math_1 = require("./math");
5
7
  const attributes_1 = require("./attributes");
6
8
  const materials_1 = require("./materials");
7
9
  const skinning_1 = require("./skinning");
8
10
  const morphs_1 = require("./morphs");
9
- function flattenScene(scene) {
11
+ const layers_1 = require("./layers");
12
+ const objects_1 = require("./objects");
13
+ const clipping_1 = require("./clipping");
14
+ const SupportedInstancedBufferGeometryAttributes = new Set([
15
+ 'color',
16
+ 'normal',
17
+ 'uv',
18
+ 'uv1',
19
+ 'uv2',
20
+ 'uv3',
21
+ 'instanceOffset',
22
+ 'instancePosition',
23
+ 'instanceScale',
24
+ 'offset',
25
+ 'scale',
26
+ 'translate',
27
+ 'translation',
28
+ ]);
29
+ const NativeRenderOrderLimit = 1000000000;
30
+ const MAX_POINT_SPRITE_SIZE = 64;
31
+ function createSceneExtractionCache() {
32
+ return {
33
+ meshGeometry: new WeakMap(),
34
+ instancedMeshes: new WeakMap(),
35
+ instancedPositionExpansions: new WeakMap(),
36
+ instancedNormalExpansions: new WeakMap(),
37
+ instancedUvExpansions: new WeakMap(),
38
+ instancedColorExpansions: new WeakMap(),
39
+ indexRanges: new WeakMap(),
40
+ batchedGeometryViews: new WeakMap(),
41
+ dashedLines: new WeakMap(),
42
+ instancedDashedLines: new WeakMap(),
43
+ texturePayloads: new WeakMap(),
44
+ materialColors: new WeakMap(),
45
+ textureStates: new WeakMap(),
46
+ materialRenderStates: new WeakMap(),
47
+ materialScalarFeatures: new WeakMap(),
48
+ pointBillboards: new WeakMap(),
49
+ spriteBillboards: new WeakMap(),
50
+ nativeMeshPayloads: {
51
+ objectIds: new WeakMap(),
52
+ payloads: new Map(),
53
+ pending: new Set(),
54
+ nextObjectId: 1,
55
+ nextPayloadId: 1,
56
+ },
57
+ };
58
+ }
59
+ function flattenScene(scene, camera, viewportHeight = 512, globalClippingPlanes = [], localClippingEnabled = true, shadowMaterialMode, materialContext = {}, sortOptions = {}, overrideMaterial, cache, callbackContext) {
10
60
  const meshes = [];
11
- visitObject(scene, true, meshes);
12
- return meshes;
61
+ const clippingContext = {
62
+ unionPlanes: globalClippingPlanes,
63
+ intersectionPlanes: [],
64
+ clipShadows: false,
65
+ };
66
+ visitObject(scene, camera, meshes, 0, viewportHeight, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext);
67
+ const nativeMeshes = nativeMeshesFromSortedFlattened(sortFlattenedMeshes(meshes, sortOptions));
68
+ if (cache) {
69
+ applyNativeMeshPayloadCache(nativeMeshes, cache.nativeMeshPayloads);
70
+ }
71
+ return nativeMeshes;
13
72
  }
14
- function visitObject(object, parentVisible, meshes) {
15
- if (!object || !parentVisible || object.visible === false)
16
- return;
17
- if (object.isMesh === true && object.geometry) {
18
- appendMesh(object, meshes);
73
+ function commitNativeMeshPayloadCache(cache) {
74
+ const payloads = cache.nativeMeshPayloads;
75
+ for (const signature of payloads.pending) {
76
+ const cached = payloads.payloads.get(signature);
77
+ if (cached)
78
+ cached.ready = true;
19
79
  }
20
- else if ((object.isLineSegments === true || object.isLineLoop === true || object.isLine === true) && object.geometry) {
21
- appendLineOrPoints(object, meshes, 'lines');
80
+ payloads.pending.clear();
81
+ }
82
+ function visitObject(object, camera, meshes, groupOrder, viewportHeight, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext) {
83
+ if (!object)
84
+ return;
85
+ if (optionalObjectBoolean(object.visible, 'object.visible') === false)
86
+ return;
87
+ const nextGroupOrder = object.isGroup === true
88
+ ? renderOrderNumber(object.renderOrder, 'object.renderOrder', 0)
89
+ : groupOrder;
90
+ const visibleToCamera = (0, layers_1.objectLayersMatchCamera)(object, camera);
91
+ const nextClippingContext = visibleToCamera
92
+ ? clippingContextForObject(clippingContext, object)
93
+ : clippingContext;
94
+ if (visibleToCamera) {
95
+ updateLodObject(object, camera);
96
+ if (object.isBatchedMesh === true && object.geometry) {
97
+ if (!renderableObjectOutsideFrustum(object, camera)) {
98
+ appendBatchedMesh(object, camera, meshes, nextGroupOrder, nextClippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext);
99
+ }
100
+ }
101
+ else if (object.isMesh === true && object.geometry) {
102
+ if (!renderableObjectOutsideFrustum(object, camera)) {
103
+ appendMesh(object, camera, meshes, nextGroupOrder, nextClippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, undefined, undefined, undefined, callbackContext);
104
+ }
105
+ }
106
+ else if ((object.isLineSegments === true || object.isLineLoop === true || object.isLine === true) && object.geometry) {
107
+ if (!renderableObjectOutsideFrustum(object, camera)) {
108
+ appendLineOrPoints(object, camera, meshes, 'lines', nextGroupOrder, viewportHeight, nextClippingContext, localClippingEnabled, materialContext, overrideMaterial, cache, callbackContext);
109
+ }
110
+ }
111
+ else if (object.isPoints === true && object.geometry) {
112
+ if (!renderableObjectOutsideFrustum(object, camera, viewportHeight, overrideMaterial)) {
113
+ appendPoints(object, camera, meshes, nextGroupOrder, viewportHeight, nextClippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext);
114
+ }
115
+ }
116
+ else if (object.isSprite === true) {
117
+ appendSprite(object, camera, meshes, nextGroupOrder, nextClippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext);
118
+ }
22
119
  }
23
- else if (object.isPoints === true && object.geometry) {
24
- appendLineOrPoints(object, meshes, 'points');
120
+ for (const child of (0, objects_1.objectChildren)(object)) {
121
+ visitObject(child, camera, meshes, nextGroupOrder, viewportHeight, nextClippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext);
25
122
  }
26
- const children = Array.isArray(object.children) ? object.children : [];
27
- for (const child of children) {
28
- visitObject(child, true, meshes);
123
+ }
124
+ function appendBatchedMesh(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext) {
125
+ const geometry = object.geometry;
126
+ const draws = batchedMeshDraws(object, camera, geometry);
127
+ if (draws.length === 0)
128
+ return;
129
+ const objectSortZ = camera ? projectedObjectZ(object, camera) : 0;
130
+ const sortIndexBase = unsignedSortKey(object.id, meshes.length);
131
+ for (let drawOrder = 0; drawOrder < draws.length; drawOrder += 1) {
132
+ const draw = draws[drawOrder];
133
+ const geometryView = batchedGeometryView(geometry, draw.range, cache);
134
+ const objectView = Object.create(object);
135
+ objectView.geometry = geometryView;
136
+ objectView.isInstancedMesh = false;
137
+ objectView.instanceMatrix = undefined;
138
+ objectView.instanceColor = undefined;
139
+ objectView.count = undefined;
140
+ const sortKeyOverride = {
141
+ sortZ: objectSortZ,
142
+ sortIndex: batchedDrawSortIndex(sortIndexBase, drawOrder),
143
+ };
144
+ appendMesh(objectView, camera, meshes, groupOrder, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, [draw.instance], sortKeyOverride, object, callbackContext, draw.z);
29
145
  }
30
146
  }
31
- function appendMesh(object, meshes) {
147
+ function appendMesh(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, instanceOverride, sortKeyOverride, sortItemObject, callbackContext, sortItemZOverride) {
32
148
  const geometry = object.geometry;
33
- const position = (0, attributes_1.getAttribute)(geometry, 'position');
34
- if (!position)
149
+ const geometryExtraction = meshGeometryExtraction(geometry, cache);
150
+ if (!geometryExtraction)
35
151
  return;
36
- let positions = (0, attributes_1.readVec3Attribute)(position);
37
- const uvAttribute = (0, attributes_1.getAttribute)(geometry, 'uv');
38
- const uvs = uvAttribute ? (0, attributes_1.readVec2Attribute)(uvAttribute) : null;
39
- const normalAttribute = (0, attributes_1.getAttribute)(geometry, 'normal');
40
- let normals = normalAttribute ? (0, attributes_1.readVec3Attribute)(normalAttribute) : null;
41
- const vertexColors = (0, attributes_1.getAttribute)(geometry, 'color');
42
- const index = geometry.index ? (0, attributes_1.readIndexAttribute)(geometry.index) : null;
43
- const groups = effectiveGroups(geometry, index, position.count);
152
+ const { position, uvChannels, uvs, normalAttribute, vertexColors, index, groups, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, } = geometryExtraction;
153
+ let positions = geometryExtraction.positions;
154
+ let normals = geometryExtraction.normals;
44
155
  // CPU-side morph targets (blend shapes / shape keys / VRM blendshapes)
45
156
  if (object.morphTargetInfluences && object.morphTargetInfluences.length > 0) {
46
157
  const morphed = (0, morphs_1.applyMorphTargets)(object, positions, normals);
@@ -55,140 +166,3743 @@ function appendMesh(object, meshes) {
55
166
  }
56
167
  // For skinned meshes, positions are already in world space after CPU skinning.
57
168
  const isSkinned = object.isSkinnedMesh === true && object.skeleton;
58
- const meshTransform = isSkinned
169
+ const meshTransform = instanceOverride
59
170
  ? math_1.IDENTITY_4X4.slice()
60
- : (0, math_1.matrixElements)(object.matrixWorld, 'mesh.matrixWorld');
171
+ : isSkinned
172
+ ? math_1.IDENTITY_4X4.slice()
173
+ : (0, math_1.matrixElements)(object.matrixWorld, 'mesh.matrixWorld');
174
+ const instances = instanceOverride ?? meshInstances(object, meshTransform, cache);
175
+ if (instances.length === 0)
176
+ return;
177
+ const objectCastsShadow = optionalObjectBoolean(object.castShadow, 'object.castShadow') === true;
178
+ const objectReceivesShadow = optionalObjectBoolean(object.receiveShadow, 'object.receiveShadow') === true;
179
+ const callbackObject = sortItemObject ?? object;
61
180
  for (const group of groups) {
62
- const material = (0, materials_1.materialForGroup)(object.material, group.materialIndex);
181
+ const material = materialForObjectGroup(object, group.materialIndex, overrideMaterial);
63
182
  if (material?.visible === false)
64
183
  continue;
65
- const color = (0, materials_1.materialColor)(material);
184
+ invokeObjectRenderCallback(callbackObject.onBeforeRender, 'onBeforeRender', callbackContext, callbackObject, camera, geometry, material, group);
185
+ const customShadowMaterial = customShadowMaterialForMode(object, shadowMaterialMode);
186
+ const usesCustomShadowMaterial = objectCastsShadow && customShadowMaterial != null;
187
+ const baseColor = (0, materials_1.materialColor)(material, materialContext);
66
188
  const useVertexColors = vertexColors && material?.vertexColors !== false;
67
- const pbrProps = (0, materials_1.extractPbrProperties)(material);
68
- const textureInfo = (0, materials_1.extractTextureData)(material);
69
- const castShadow = object.castShadow === true ? true : undefined;
70
- const receiveShadow = object.receiveShadow === true ? true : undefined;
189
+ const pbrProps = (0, materials_1.extractPbrProperties)(material, materialContext);
190
+ assertSupportedCustomFragmentInstancedAttributes(geometry, pbrProps);
191
+ const uvStreams = textureUvStreamsForMeshMaterial(uvChannels, material);
192
+ if (uvStreams.alphaMapUsesUv2 !== undefined) {
193
+ pbrProps.alphaMapUsesUv2 = uvStreams.alphaMapUsesUv2;
194
+ }
195
+ applyPbrUvStreamFlags(pbrProps, uvStreams);
196
+ const textureInfo = (0, materials_1.extractTextureData)(material, materialContext);
197
+ const castShadow = objectCastsShadow && !usesCustomShadowMaterial ? true : undefined;
198
+ const receiveShadow = objectReceivesShadow ? true : undefined;
199
+ const clipping = clippingState(clippingContext, material, localClippingEnabled);
200
+ const wireframe = isMeshWireframeMaterial(material);
71
201
  if (index) {
72
- const indices = index.slice(group.start, group.start + group.count);
202
+ const indices = indexRangeWithCache(cache, geometry, index, group.start, group.count);
73
203
  if (indices.length % 3 !== 0) {
74
204
  throw new Error(`THREE.Mesh "${object.name || object.uuid || '<unnamed>'}" has a non-triangle index range`);
75
205
  }
76
- meshes.push({
77
- positions,
78
- indices,
79
- normals: normals ?? undefined,
80
- color,
81
- colors: useVertexColors ? (0, attributes_1.readColorAttribute)(vertexColors, color) : undefined,
82
- uvs: uvs ?? undefined,
83
- texture: textureInfo?.data,
84
- textureWidth: textureInfo?.width ?? undefined,
85
- textureHeight: textureInfo?.height ?? undefined,
86
- textureWrapS: textureInfo?.wrapS,
87
- textureWrapT: textureInfo?.wrapT,
88
- transform: meshTransform,
89
- castShadow,
90
- receiveShadow,
91
- ...pbrProps,
92
- });
206
+ const renderIndices = wireframe ? wireframeIndicesForTriangles(indices) : indices;
207
+ const expandedIndices = expandIndicesForInstances(renderIndices, position.count, instancedGeometryCount);
208
+ const expandedPositions = expandVec3ValuesForInstancesWithCache(cache, geometry, position, positions, 0, position.count, instancedGeometryCount, instancedPositionOffset, instancedPositionScale);
209
+ const expandedNormals = normalAttribute && normals
210
+ ? expandNormalValuesForInstancesWithCache(cache, geometry, normalAttribute, normals, 0, position.count, instancedGeometryCount)
211
+ : undefined;
212
+ const expandedUvs = uvStreams.uvs
213
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs, 0, position.count, instancedGeometryCount)
214
+ : undefined;
215
+ const expandedSecondaryUvs = uvStreams.uvs2
216
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs2, 0, position.count, instancedGeometryCount)
217
+ : undefined;
218
+ for (const instance of instances) {
219
+ const color = instanceColor(baseColor, instance);
220
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, instance.transform, geometry, group, sortItemObject, sortItemZOverride);
221
+ const sortKeys = mergeSortKeys(sortInfo.keys, sortKeyOverride);
222
+ pushMesh(meshes, {
223
+ positions: expandedPositions,
224
+ indices: expandedIndices,
225
+ normals: expandedNormals,
226
+ color,
227
+ colors: useVertexColors
228
+ ? expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, 0, position.count, instancedGeometryCount)
229
+ : undefined,
230
+ uvs: expandedUvs,
231
+ uvs2: expandedSecondaryUvs,
232
+ texture: textureInfo?.data,
233
+ textureWidth: textureInfo?.width ?? undefined,
234
+ textureHeight: textureInfo?.height ?? undefined,
235
+ textureWrapS: textureInfo?.wrapS,
236
+ textureWrapT: textureInfo?.wrapT,
237
+ textureMagFilter: textureInfo?.magFilter,
238
+ textureMinFilter: textureInfo?.minFilter,
239
+ textureAnisotropy: textureInfo?.anisotropy,
240
+ textureTransform: textureInfo?.transform,
241
+ textureColorSpace: textureInfo?.colorSpace,
242
+ textureUsesUv2: uvStreams.textureUsesUv2 ?? textureInfo?.usesUv2,
243
+ transform: instance.transform,
244
+ topology: wireframe ? 'lines' : undefined,
245
+ castShadow,
246
+ receiveShadow,
247
+ clipShadows: clipShadowsForMaterial(material, clippingContext),
248
+ ...clipping,
249
+ ...sortKeys,
250
+ ...pbrProps,
251
+ }, sortInfo.item, needsTransparentDoubleSidePass(material, pbrProps, wireframe));
252
+ }
93
253
  }
94
254
  else {
95
255
  if (group.count % 3 !== 0) {
96
256
  throw new Error(`THREE.Mesh "${object.name || object.uuid || '<unnamed>'}" has a non-triangle vertex range`);
97
257
  }
98
- meshes.push({
99
- positions: positions.slice(group.start * 3, (group.start + group.count) * 3),
100
- normals: normals ? normals.slice(group.start * 3, (group.start + group.count) * 3) : undefined,
258
+ const expandedGroupPositions = expandVec3ValuesForInstancesWithCache(cache, geometry, position, positions, group.start, group.count, instancedGeometryCount, instancedPositionOffset, instancedPositionScale);
259
+ const expandedGroupNormals = normalAttribute && normals
260
+ ? expandNormalValuesForInstancesWithCache(cache, geometry, normalAttribute, normals, group.start, group.count, instancedGeometryCount)
261
+ : undefined;
262
+ const expandedGroupUvs = uvStreams.uvs
263
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs, group.start, group.count, instancedGeometryCount)
264
+ : undefined;
265
+ const expandedGroupSecondaryUvs = uvStreams.uvs2
266
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs2, group.start, group.count, instancedGeometryCount)
267
+ : undefined;
268
+ const expandedGroupIndices = wireframe
269
+ ? expandIndicesForInstances(wireframeIndicesForUnindexedTriangles(group.count), group.count, instancedGeometryCount)
270
+ : undefined;
271
+ for (const instance of instances) {
272
+ const color = instanceColor(baseColor, instance);
273
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, instance.transform, geometry, group, sortItemObject, sortItemZOverride);
274
+ const sortKeys = mergeSortKeys(sortInfo.keys, sortKeyOverride);
275
+ pushMesh(meshes, {
276
+ positions: expandedGroupPositions,
277
+ indices: expandedGroupIndices,
278
+ normals: expandedGroupNormals,
279
+ color,
280
+ colors: useVertexColors
281
+ ? expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, group.start, group.count, instancedGeometryCount)
282
+ : undefined,
283
+ uvs: expandedGroupUvs,
284
+ uvs2: expandedGroupSecondaryUvs,
285
+ texture: textureInfo?.data,
286
+ textureWidth: textureInfo?.width ?? undefined,
287
+ textureHeight: textureInfo?.height ?? undefined,
288
+ textureWrapS: textureInfo?.wrapS,
289
+ textureWrapT: textureInfo?.wrapT,
290
+ textureMagFilter: textureInfo?.magFilter,
291
+ textureMinFilter: textureInfo?.minFilter,
292
+ textureAnisotropy: textureInfo?.anisotropy,
293
+ textureTransform: textureInfo?.transform,
294
+ textureColorSpace: textureInfo?.colorSpace,
295
+ textureUsesUv2: uvStreams.textureUsesUv2 ?? textureInfo?.usesUv2,
296
+ transform: instance.transform,
297
+ topology: wireframe ? 'lines' : undefined,
298
+ castShadow,
299
+ receiveShadow,
300
+ clipShadows: clipShadowsForMaterial(material, clippingContext),
301
+ ...clipping,
302
+ ...sortKeys,
303
+ ...pbrProps,
304
+ }, sortInfo.item, needsTransparentDoubleSidePass(material, pbrProps, wireframe));
305
+ }
306
+ }
307
+ if (usesCustomShadowMaterial && customShadowMaterial?.visible !== false) {
308
+ appendShadowOnlyMeshGroup(object, camera, meshes, group, groupOrder, clippingContext, localClippingEnabled, customShadowMaterial, material, materialContext, positions, normals, normalAttribute, uvs, uvChannels, vertexColors, position.count, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, instances, cache);
309
+ }
310
+ invokeObjectRenderCallback(callbackObject.onAfterRender, 'onAfterRender', callbackContext, callbackObject, camera, geometry, material, group);
311
+ }
312
+ }
313
+ function meshGeometryExtraction(geometry, cache) {
314
+ const position = (0, attributes_1.getAttribute)(geometry, 'position');
315
+ if (!position)
316
+ return null;
317
+ const signature = meshGeometrySignature(geometry, position);
318
+ if (cache && signature.cacheable) {
319
+ const cached = cache.meshGeometry.get(geometry);
320
+ if (cached && sameMeshGeometrySignature(cached.signature, signature)) {
321
+ return cached.extraction;
322
+ }
323
+ }
324
+ const extraction = readMeshGeometryExtraction(geometry, position);
325
+ if (cache && signature.cacheable) {
326
+ cache.meshGeometry.set(geometry, { signature, extraction });
327
+ }
328
+ return extraction;
329
+ }
330
+ function readMeshGeometryExtraction(geometry, position) {
331
+ const positions = (0, attributes_1.readVec3Attribute)(position, 'geometry.attributes.position');
332
+ const uvChannels = readUvChannels(geometry);
333
+ const normalAttribute = (0, attributes_1.getAttribute)(geometry, 'normal');
334
+ const normals = normalAttribute ? (0, attributes_1.readVec3Attribute)(normalAttribute, 'geometry.attributes.normal') : null;
335
+ const vertexColors = (0, attributes_1.getAttribute)(geometry, 'color');
336
+ const index = geometry.index ? (0, attributes_1.readIndexAttribute)(geometry.index, 'geometry.index', position.count) : null;
337
+ const sourceIndex = index ?? rangeIndices(position.count);
338
+ const groups = effectiveGroups(geometry, index, position.count);
339
+ const instancedGeometryCount = instancedBufferGeometryCount(geometry);
340
+ const instancedPositionOffset = instancedOffsetAttribute(geometry);
341
+ const instancedPositionScale = instancedScaleAttribute(geometry);
342
+ return {
343
+ position,
344
+ positions,
345
+ uvChannels,
346
+ uvs: uvChannels[0]?.values ?? null,
347
+ normalAttribute,
348
+ normals,
349
+ vertexColors,
350
+ index,
351
+ sourceIndex,
352
+ groups,
353
+ instancedGeometryCount,
354
+ instancedPositionOffset,
355
+ instancedPositionScale,
356
+ };
357
+ }
358
+ function meshGeometrySignature(geometry, position) {
359
+ const attributes = (0, attributes_1.geometryAttributes)(geometry);
360
+ const instancedAttributes = Object.entries(attributes)
361
+ .filter((entry) => isInstancedAttribute(entry[1]))
362
+ .map(([name, attribute]) => ({ name, signature: attributeSignature(attribute) }));
363
+ const instancedPositionOffset = namedInstancedOffsetAttribute(geometry);
364
+ const instancedPositionScale = namedInstancedScaleAttribute(geometry);
365
+ const signature = {
366
+ cacheable: true,
367
+ geometryVersion: geometry.version,
368
+ isInstancedBufferGeometry: geometry.isInstancedBufferGeometry,
369
+ instanceCount: geometry.instanceCount,
370
+ drawRange: geometryDrawRangeSignature(geometry.drawRange),
371
+ drawRangeStart: geometry.drawRange?.start,
372
+ drawRangeCount: geometry.drawRange?.count,
373
+ groups: geometryGroupsSignature(geometry.groups),
374
+ position: attributeSignature(position),
375
+ normal: attributeSignature((0, attributes_1.getAttribute)(geometry, 'normal')),
376
+ color: attributeSignature((0, attributes_1.getAttribute)(geometry, 'color')),
377
+ index: attributeSignature(geometry.index),
378
+ uv: attributeSignature((0, attributes_1.getAttribute)(geometry, 'uv')),
379
+ uv1: attributeSignature((0, attributes_1.getAttribute)(geometry, 'uv1')),
380
+ uv2: attributeSignature((0, attributes_1.getAttribute)(geometry, 'uv2')),
381
+ uv3: attributeSignature((0, attributes_1.getAttribute)(geometry, 'uv3')),
382
+ instancedPositionOffsetName: instancedPositionOffset?.name,
383
+ instancedPositionOffset: attributeSignature(instancedPositionOffset?.attribute),
384
+ instancedPositionScaleName: instancedPositionScale?.name,
385
+ instancedPositionScale: attributeSignature(instancedPositionScale?.attribute),
386
+ instancedAttributes,
387
+ };
388
+ signature.cacheable = meshGeometrySignatureCacheable(signature);
389
+ return signature;
390
+ }
391
+ function meshGeometrySignatureCacheable(signature) {
392
+ return [
393
+ signature.position,
394
+ signature.normal,
395
+ signature.color,
396
+ signature.index,
397
+ signature.uv,
398
+ signature.uv1,
399
+ signature.uv2,
400
+ signature.uv3,
401
+ signature.instancedPositionOffset,
402
+ signature.instancedPositionScale,
403
+ ...signature.instancedAttributes.map(({ signature }) => signature),
404
+ ].every(attributeSignatureCacheable);
405
+ }
406
+ function attributeSignature(attribute) {
407
+ if (!attribute)
408
+ return {};
409
+ const data = attribute.data && typeof attribute.data === 'object' && !Array.isArray(attribute.data)
410
+ ? attribute.data
411
+ : undefined;
412
+ return {
413
+ ref: attribute,
414
+ version: attribute.version,
415
+ count: attribute.count,
416
+ itemSize: attribute.itemSize,
417
+ normalized: attribute.normalized,
418
+ array: attribute.array,
419
+ dataArray: data?.array,
420
+ dataStride: data?.stride,
421
+ offset: attribute.offset,
422
+ isInstancedBufferAttribute: attribute.isInstancedBufferAttribute,
423
+ meshPerAttribute: attribute.meshPerAttribute,
424
+ };
425
+ }
426
+ function attributeSignatureCacheable(signature) {
427
+ return signature.ref == null || typeof signature.version === 'number';
428
+ }
429
+ function namedInstancedOffsetAttribute(geometry) {
430
+ const names = ['instanceOffset', 'instancePosition', 'offset', 'translate', 'translation'];
431
+ for (const name of names) {
432
+ const attribute = (0, attributes_1.getAttribute)(geometry, name);
433
+ if (isInstancedAttribute(attribute))
434
+ return { name, attribute };
435
+ }
436
+ return null;
437
+ }
438
+ function namedInstancedScaleAttribute(geometry) {
439
+ const names = ['instanceScale', 'scale'];
440
+ for (const name of names) {
441
+ const attribute = (0, attributes_1.getAttribute)(geometry, name);
442
+ if (isInstancedAttribute(attribute))
443
+ return { name, attribute };
444
+ }
445
+ return null;
446
+ }
447
+ function geometryGroupsSignature(groups) {
448
+ if (groups == null)
449
+ return 'none';
450
+ if (!Array.isArray(groups))
451
+ return `invalid:${typeof groups}`;
452
+ return groups.map((group, index) => {
453
+ if (!group || typeof group !== 'object' || Array.isArray(group)) {
454
+ return `${index}:invalid:${typeof group}`;
455
+ }
456
+ return [
457
+ index,
458
+ typeof group.start,
459
+ String(group.start),
460
+ typeof group.count,
461
+ String(group.count),
462
+ typeof group.materialIndex,
463
+ String(group.materialIndex),
464
+ ].join(':');
465
+ }).join('|');
466
+ }
467
+ function geometryDrawRangeSignature(drawRange) {
468
+ if (drawRange == null)
469
+ return 'none';
470
+ if (typeof drawRange !== 'object' || Array.isArray(drawRange))
471
+ return `invalid:${typeof drawRange}`;
472
+ return [
473
+ typeof drawRange.start,
474
+ String(drawRange.start),
475
+ typeof drawRange.count,
476
+ String(drawRange.count),
477
+ ].join(':');
478
+ }
479
+ function sameMeshGeometrySignature(a, b) {
480
+ return a.cacheable === b.cacheable
481
+ && a.geometryVersion === b.geometryVersion
482
+ && a.isInstancedBufferGeometry === b.isInstancedBufferGeometry
483
+ && a.instanceCount === b.instanceCount
484
+ && a.drawRange === b.drawRange
485
+ && Object.is(a.drawRangeStart, b.drawRangeStart)
486
+ && Object.is(a.drawRangeCount, b.drawRangeCount)
487
+ && a.groups === b.groups
488
+ && a.instancedPositionOffsetName === b.instancedPositionOffsetName
489
+ && a.instancedPositionScaleName === b.instancedPositionScaleName
490
+ && sameAttributeSignature(a.position, b.position)
491
+ && sameAttributeSignature(a.normal, b.normal)
492
+ && sameAttributeSignature(a.color, b.color)
493
+ && sameAttributeSignature(a.index, b.index)
494
+ && sameAttributeSignature(a.uv, b.uv)
495
+ && sameAttributeSignature(a.uv1, b.uv1)
496
+ && sameAttributeSignature(a.uv2, b.uv2)
497
+ && sameAttributeSignature(a.uv3, b.uv3)
498
+ && sameAttributeSignature(a.instancedPositionOffset, b.instancedPositionOffset)
499
+ && sameAttributeSignature(a.instancedPositionScale, b.instancedPositionScale)
500
+ && sameInstancedAttributeSignatures(a.instancedAttributes, b.instancedAttributes);
501
+ }
502
+ function sameInstancedAttributeSignatures(a, b) {
503
+ if (a.length !== b.length)
504
+ return false;
505
+ for (let i = 0; i < a.length; i += 1) {
506
+ if (a[i].name !== b[i].name)
507
+ return false;
508
+ if (!sameAttributeSignature(a[i].signature, b[i].signature))
509
+ return false;
510
+ }
511
+ return true;
512
+ }
513
+ function sameAttributeSignature(a, b) {
514
+ return a.ref === b.ref
515
+ && a.version === b.version
516
+ && a.count === b.count
517
+ && a.itemSize === b.itemSize
518
+ && a.normalized === b.normalized
519
+ && a.array === b.array
520
+ && a.dataArray === b.dataArray
521
+ && a.dataStride === b.dataStride
522
+ && a.offset === b.offset
523
+ && a.isInstancedBufferAttribute === b.isInstancedBufferAttribute
524
+ && a.meshPerAttribute === b.meshPerAttribute;
525
+ }
526
+ function appendShadowOnlyMeshGroup(object, camera, meshes, group, groupOrder, clippingContext, localClippingEnabled, material, sourceMaterial, materialContext, positions, normals, normalAttribute, uvs, uvChannels, vertexColors, vertexCount, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, instances, cache) {
527
+ const shadowMaterial = shadowMaterialWithSourceShadowState(material, sourceMaterial);
528
+ const baseColor = (0, materials_1.materialColor)(shadowMaterial, materialContext);
529
+ const useVertexColors = vertexColors && material.vertexColors !== false;
530
+ const pbrProps = shadowPbrProperties(shadowMaterial, sourceMaterial, materialContext);
531
+ assertSupportedCustomFragmentInstancedAttributes(object.geometry, pbrProps);
532
+ const uvStreams = textureUvStreamsForMeshMaterial(uvChannels, shadowMaterial);
533
+ if (uvStreams.alphaMapUsesUv2 !== undefined) {
534
+ pbrProps.alphaMapUsesUv2 = uvStreams.alphaMapUsesUv2;
535
+ }
536
+ applyPbrUvStreamFlags(pbrProps, uvStreams);
537
+ const textureInfo = (0, materials_1.extractTextureData)(shadowMaterial, materialContext);
538
+ const clipping = clippingState(clippingContext, shadowMaterial, localClippingEnabled);
539
+ const wireframe = isDepthDistanceWireframeMaterial(shadowMaterial);
540
+ const hiddenMainPass = shadowOnlyMainPassState();
541
+ if (index) {
542
+ const indices = indexRangeWithCache(cache, object.geometry, index, group.start, group.count);
543
+ if (indices.length % 3 !== 0) {
544
+ throw new Error(`THREE.Mesh "${object.name || object.uuid || '<unnamed>'}" has a non-triangle index range`);
545
+ }
546
+ const renderIndices = wireframe ? wireframeIndicesForTriangles(indices) : indices;
547
+ const expandedIndices = expandIndicesForInstances(renderIndices, vertexCount, instancedGeometryCount);
548
+ const geometry = object.geometry;
549
+ const expandedPositions = expandVec3ValuesForInstancesWithCache(cache, geometry, (0, attributes_1.getAttribute)(geometry, 'position'), positions, 0, vertexCount, instancedGeometryCount, instancedPositionOffset, instancedPositionScale);
550
+ const expandedNormals = normalAttribute && normals
551
+ ? expandNormalValuesForInstancesWithCache(cache, geometry, normalAttribute, normals, 0, vertexCount, instancedGeometryCount)
552
+ : undefined;
553
+ const expandedUvs = uvStreams.uvs
554
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs, 0, vertexCount, instancedGeometryCount)
555
+ : undefined;
556
+ const expandedSecondaryUvs = uvStreams.uvs2
557
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs2, 0, vertexCount, instancedGeometryCount)
558
+ : undefined;
559
+ for (const instance of instances) {
560
+ const color = instanceColor(baseColor, instance);
561
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, instance.transform, object.geometry, group);
562
+ pushMesh(meshes, {
563
+ positions: expandedPositions,
564
+ indices: expandedIndices,
565
+ normals: expandedNormals,
101
566
  color,
102
567
  colors: useVertexColors
103
- ? (0, attributes_1.readColorAttribute)(vertexColors, color).slice(group.start * 4, (group.start + group.count) * 4)
568
+ ? expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, 0, vertexCount, instancedGeometryCount)
104
569
  : undefined,
105
- uvs: uvs ? uvs.slice(group.start * 2, (group.start + group.count) * 2) : undefined,
570
+ uvs: expandedUvs,
571
+ uvs2: expandedSecondaryUvs,
106
572
  texture: textureInfo?.data,
107
573
  textureWidth: textureInfo?.width ?? undefined,
108
574
  textureHeight: textureInfo?.height ?? undefined,
109
575
  textureWrapS: textureInfo?.wrapS,
110
576
  textureWrapT: textureInfo?.wrapT,
111
- transform: meshTransform,
112
- castShadow,
113
- receiveShadow,
577
+ textureMagFilter: textureInfo?.magFilter,
578
+ textureMinFilter: textureInfo?.minFilter,
579
+ textureAnisotropy: textureInfo?.anisotropy,
580
+ textureTransform: textureInfo?.transform,
581
+ textureColorSpace: textureInfo?.colorSpace,
582
+ textureUsesUv2: uvStreams.textureUsesUv2 ?? textureInfo?.usesUv2,
583
+ transform: instance.transform,
584
+ topology: wireframe ? 'lines' : undefined,
585
+ castShadow: true,
586
+ receiveShadow: false,
587
+ clipShadows: clipShadowsForMaterial(shadowMaterial, clippingContext),
588
+ ...clipping,
589
+ ...sortInfo.keys,
114
590
  ...pbrProps,
115
- });
591
+ ...hiddenMainPass,
592
+ }, sortInfo.item);
593
+ }
594
+ return;
595
+ }
596
+ if (group.count % 3 !== 0) {
597
+ throw new Error(`THREE.Mesh "${object.name || object.uuid || '<unnamed>'}" has a non-triangle vertex range`);
598
+ }
599
+ const geometry = object.geometry;
600
+ const expandedGroupPositions = expandVec3ValuesForInstancesWithCache(cache, geometry, (0, attributes_1.getAttribute)(geometry, 'position'), positions, group.start, group.count, instancedGeometryCount, instancedPositionOffset, instancedPositionScale);
601
+ const expandedGroupNormals = normalAttribute && normals
602
+ ? expandNormalValuesForInstancesWithCache(cache, geometry, normalAttribute, normals, group.start, group.count, instancedGeometryCount)
603
+ : undefined;
604
+ const expandedGroupUvs = uvStreams.uvs
605
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs, group.start, group.count, instancedGeometryCount)
606
+ : undefined;
607
+ const expandedGroupSecondaryUvs = uvStreams.uvs2
608
+ ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs2, group.start, group.count, instancedGeometryCount)
609
+ : undefined;
610
+ const expandedGroupIndices = wireframe
611
+ ? expandIndicesForInstances(wireframeIndicesForUnindexedTriangles(group.count), group.count, instancedGeometryCount)
612
+ : undefined;
613
+ for (const instance of instances) {
614
+ const color = instanceColor(baseColor, instance);
615
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, instance.transform, object.geometry, group);
616
+ pushMesh(meshes, {
617
+ positions: expandedGroupPositions,
618
+ indices: expandedGroupIndices,
619
+ normals: expandedGroupNormals,
620
+ color,
621
+ colors: useVertexColors
622
+ ? expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, group.start, group.count, instancedGeometryCount)
623
+ : undefined,
624
+ uvs: expandedGroupUvs,
625
+ uvs2: expandedGroupSecondaryUvs,
626
+ texture: textureInfo?.data,
627
+ textureWidth: textureInfo?.width ?? undefined,
628
+ textureHeight: textureInfo?.height ?? undefined,
629
+ textureWrapS: textureInfo?.wrapS,
630
+ textureWrapT: textureInfo?.wrapT,
631
+ textureMagFilter: textureInfo?.magFilter,
632
+ textureMinFilter: textureInfo?.minFilter,
633
+ textureAnisotropy: textureInfo?.anisotropy,
634
+ textureTransform: textureInfo?.transform,
635
+ textureColorSpace: textureInfo?.colorSpace,
636
+ textureUsesUv2: uvStreams.textureUsesUv2 ?? textureInfo?.usesUv2,
637
+ transform: instance.transform,
638
+ topology: wireframe ? 'lines' : undefined,
639
+ castShadow: true,
640
+ receiveShadow: false,
641
+ clipShadows: clipShadowsForMaterial(shadowMaterial, clippingContext),
642
+ ...clipping,
643
+ ...sortInfo.keys,
644
+ ...pbrProps,
645
+ ...hiddenMainPass,
646
+ }, sortInfo.item);
647
+ }
648
+ }
649
+ function customShadowMaterialForMode(object, mode) {
650
+ if (mode === 'depth') {
651
+ (0, materials_1.assertMaterialLike)(object.customDepthMaterial, 'Object3D.customDepthMaterial');
652
+ optionalSceneBoolean(object.customDepthMaterial?.visible, 'Object3D.customDepthMaterial.visible');
653
+ return object.customDepthMaterial;
654
+ }
655
+ if (mode === 'distance') {
656
+ (0, materials_1.assertMaterialLike)(object.customDistanceMaterial, 'Object3D.customDistanceMaterial');
657
+ optionalSceneBoolean(object.customDistanceMaterial?.visible, 'Object3D.customDistanceMaterial.visible');
658
+ return object.customDistanceMaterial;
659
+ }
660
+ return undefined;
661
+ }
662
+ function materialForObjectGroup(object, materialIndex, overrideMaterial) {
663
+ if (overrideMaterial !== undefined) {
664
+ (0, materials_1.assertMaterialLike)(overrideMaterial, 'scene.overrideMaterial');
665
+ return overrideMaterial;
666
+ }
667
+ return (0, materials_1.materialForGroup)(object.material, materialIndex);
668
+ }
669
+ function invokeObjectRenderCallback(callback, name, context, object, camera, geometry, material, group) {
670
+ if (callback == null)
671
+ return;
672
+ if (typeof callback !== 'function') {
673
+ throw new TypeError(`THREE.Object3D.${name} must be a function when provided.`);
674
+ }
675
+ if (isInternalBatchedMeshRenderCallback(object, callback, name))
676
+ return;
677
+ if (!context)
678
+ return;
679
+ callback.call(object, context.renderer, context.scene, camera, geometry, material, group);
680
+ }
681
+ function isInternalBatchedMeshRenderCallback(object, callback, name) {
682
+ if (name !== 'onBeforeRender' || object.isBatchedMesh !== true)
683
+ return false;
684
+ if (Object.prototype.hasOwnProperty.call(object, name))
685
+ return false;
686
+ let prototype = Object.getPrototypeOf(object);
687
+ while (prototype && prototype !== Object.prototype) {
688
+ if (prototype.constructor?.name === 'BatchedMesh' && typeof prototype[name] === 'function') {
689
+ return callback === prototype[name];
690
+ }
691
+ prototype = Object.getPrototypeOf(prototype);
692
+ }
693
+ return false;
694
+ }
695
+ function shadowOnlyMainPassState() {
696
+ return {
697
+ blending: 'none',
698
+ colorWrite: false,
699
+ depthTest: false,
700
+ depthWrite: false,
701
+ stencilWrite: false,
702
+ transparent: false,
703
+ };
704
+ }
705
+ function appendSprite(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext) {
706
+ const objectCastsShadow = optionalObjectBoolean(object.castShadow, 'object.castShadow') === true;
707
+ optionalObjectBoolean(object.receiveShadow, 'object.receiveShadow');
708
+ const material = materialForObjectGroup(object, 0, overrideMaterial);
709
+ if (material?.visible === false)
710
+ return;
711
+ validateSpriteScale(object);
712
+ const matrix = (0, math_1.matrixElements)(object.matrixWorld, 'sprite.matrixWorld');
713
+ const center = [
714
+ finiteMaterialOrObjectNumber(object.center?.x, 'Sprite.center.x', 0.5),
715
+ finiteMaterialOrObjectNumber(object.center?.y, 'Sprite.center.y', 0.5),
716
+ ];
717
+ if (spriteOutsideFrustum(object, camera, matrix, center))
718
+ return;
719
+ invokeObjectRenderCallback(object.onBeforeRender, 'onBeforeRender', callbackContext, object, camera, object.geometry, material);
720
+ const worldPosition = [matrix[12], matrix[13], matrix[14]];
721
+ let scaleX = columnLength3(matrix, 0);
722
+ let scaleY = columnLength3(matrix, 4);
723
+ const sizeAttenuation = optionalSceneBoolean(material?.sizeAttenuation, 'material.sizeAttenuation');
724
+ if (sizeAttenuation === false && camera?.isPerspectiveCamera === true) {
725
+ const viewZ = viewSpaceZ(worldPosition, camera);
726
+ if (Number.isFinite(viewZ)) {
727
+ scaleX *= -viewZ;
728
+ scaleY *= -viewZ;
729
+ }
730
+ }
731
+ if (scaleX <= 0 || scaleY <= 0)
732
+ return;
733
+ const axes = cameraBillboardAxes(camera);
734
+ const rotation = finiteMaterialOrObjectNumber(material?.rotation, 'material.rotation', 0);
735
+ const billboard = spriteBillboardExpansion(object, matrix, worldPosition, center, scaleX, scaleY, rotation, sizeAttenuation, axes, camera, cache);
736
+ const positions = billboard.positions;
737
+ const indices = billboard.indices;
738
+ const uvs = billboard.uvs;
739
+ const textureInfo = (0, materials_1.extractTextureData)(material, materialContext);
740
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder);
741
+ const pbrProps = (0, materials_1.extractPbrProperties)(material, materialContext);
742
+ pbrProps.alphaMapUsesUv2 = false;
743
+ const clipping = clippingState(clippingContext, material, localClippingEnabled);
744
+ const customShadowMaterial = customShadowMaterialForMode(object, shadowMaterialMode);
745
+ const usesCustomShadowMaterial = objectCastsShadow && customShadowMaterial != null;
746
+ pushMesh(meshes, {
747
+ positions,
748
+ indices,
749
+ uvs,
750
+ color: (0, materials_1.materialColor)(material, materialContext),
751
+ texture: textureInfo?.data,
752
+ textureWidth: textureInfo?.width ?? undefined,
753
+ textureHeight: textureInfo?.height ?? undefined,
754
+ textureWrapS: textureInfo?.wrapS,
755
+ textureWrapT: textureInfo?.wrapT,
756
+ textureMagFilter: textureInfo?.magFilter,
757
+ textureMinFilter: textureInfo?.minFilter,
758
+ textureAnisotropy: textureInfo?.anisotropy,
759
+ textureTransform: textureInfo?.transform,
760
+ textureColorSpace: textureInfo?.colorSpace,
761
+ textureUsesUv2: false,
762
+ transform: math_1.IDENTITY_4X4.slice(),
763
+ transparent: material?.transparent !== false,
764
+ castShadow: objectCastsShadow && !usesCustomShadowMaterial ? true : undefined,
765
+ receiveShadow: undefined,
766
+ clipShadows: clipShadowsForMaterial(material, clippingContext),
767
+ ...clipping,
768
+ ...sortInfo.keys,
769
+ ...pbrProps,
770
+ }, sortInfo.item);
771
+ if (usesCustomShadowMaterial && customShadowMaterial?.visible !== false) {
772
+ appendShadowOnlyBillboardMesh(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, customShadowMaterial, material, materialContext, positions, indices, uvs);
773
+ }
774
+ invokeObjectRenderCallback(object.onAfterRender, 'onAfterRender', callbackContext, object, camera, object.geometry, material);
775
+ }
776
+ function spriteBillboardExpansion(object, matrix, worldPosition, center, scaleX, scaleY, rotation, sizeAttenuation, axes, camera, cache) {
777
+ const signature = spriteBillboardSignature(matrix, center, scaleX, scaleY, rotation, sizeAttenuation, axes, camera);
778
+ if (cache) {
779
+ const cached = cache.spriteBillboards.get(object);
780
+ if (cached && sameSpriteBillboardSignature(cached.signature, signature)) {
781
+ return cached.expansion;
782
+ }
783
+ }
784
+ const expansion = readSpriteBillboardExpansion(worldPosition, center, scaleX, scaleY, rotation, axes);
785
+ if (cache) {
786
+ cache.spriteBillboards.set(object, { signature, expansion });
787
+ }
788
+ return expansion;
789
+ }
790
+ function readSpriteBillboardExpansion(worldPosition, center, scaleX, scaleY, rotation, axes) {
791
+ const cos = Math.cos(rotation);
792
+ const sin = Math.sin(rotation);
793
+ const corners = [
794
+ [-0.5, -0.5, 0, 0],
795
+ [0.5, -0.5, 1, 0],
796
+ [0.5, 0.5, 1, 1],
797
+ [-0.5, 0.5, 0, 1],
798
+ ];
799
+ const positions = [];
800
+ const uvs = [];
801
+ for (const [x, y, u, v] of corners) {
802
+ const alignedX = (x - (center[0] - 0.5)) * scaleX;
803
+ const alignedY = (y - (center[1] - 0.5)) * scaleY;
804
+ const rotatedX = cos * alignedX - sin * alignedY;
805
+ const rotatedY = sin * alignedX + cos * alignedY;
806
+ positions.push(worldPosition[0] + axes.right[0] * rotatedX + axes.up[0] * rotatedY, worldPosition[1] + axes.right[1] * rotatedX + axes.up[1] * rotatedY, worldPosition[2] + axes.right[2] * rotatedX + axes.up[2] * rotatedY);
807
+ uvs.push(u, v);
808
+ }
809
+ return {
810
+ positions,
811
+ indices: [0, 1, 2, 0, 2, 3],
812
+ uvs,
813
+ };
814
+ }
815
+ function spriteBillboardSignature(matrix, center, scaleX, scaleY, rotation, sizeAttenuation, axes, camera) {
816
+ return {
817
+ matrix: matrix.slice(0, 16),
818
+ center: center.slice(),
819
+ scaleX,
820
+ scaleY,
821
+ rotation,
822
+ sizeAttenuation,
823
+ cameraRight: axes.right.slice(),
824
+ cameraUp: axes.up.slice(),
825
+ cameraView: matrixValues(camera?.matrixWorldInverse?.elements),
826
+ cameraIsPerspective: camera?.isPerspectiveCamera,
827
+ };
828
+ }
829
+ function sameSpriteBillboardSignature(a, b) {
830
+ return sameNumberArray(a.matrix, b.matrix)
831
+ && sameNumberArray(a.center, b.center)
832
+ && a.scaleX === b.scaleX
833
+ && a.scaleY === b.scaleY
834
+ && a.rotation === b.rotation
835
+ && a.sizeAttenuation === b.sizeAttenuation
836
+ && sameNumberArray(a.cameraRight, b.cameraRight)
837
+ && sameNumberArray(a.cameraUp, b.cameraUp)
838
+ && sameOptionalNumberArray(a.cameraView, b.cameraView)
839
+ && a.cameraIsPerspective === b.cameraIsPerspective;
840
+ }
841
+ function validateSpriteScale(object) {
842
+ finiteMaterialOrObjectNumber(object.scale?.x, 'Sprite.scale.x', 1);
843
+ finiteMaterialOrObjectNumber(object.scale?.y, 'Sprite.scale.y', 1);
844
+ finiteMaterialOrObjectNumber(object.scale?.z, 'Sprite.scale.z', 1);
845
+ }
846
+ function appendPoints(object, camera, meshes, groupOrder, viewportHeight, clippingContext, localClippingEnabled, shadowMaterialMode, materialContext, overrideMaterial, cache, callbackContext) {
847
+ const objectCastsShadow = optionalObjectBoolean(object.castShadow, 'object.castShadow') === true;
848
+ optionalObjectBoolean(object.receiveShadow, 'object.receiveShadow');
849
+ const geometry = object.geometry;
850
+ const geometryExtraction = meshGeometryExtraction(geometry, cache);
851
+ if (!geometryExtraction)
852
+ return;
853
+ const { position, positions, vertexColors, index, sourceIndex, groups, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, } = geometryExtraction;
854
+ const pointUvChannels = geometryExtraction.uvChannels;
855
+ const transform = (0, math_1.matrixElements)(object.matrixWorld, 'points.matrixWorld');
856
+ const axes = cameraBillboardAxes(camera);
857
+ for (const group of groups) {
858
+ const material = materialForObjectGroup(object, group.materialIndex, overrideMaterial);
859
+ if (material?.visible === false)
860
+ continue;
861
+ invokeObjectRenderCallback(object.onBeforeRender, 'onBeforeRender', callbackContext, object, camera, geometry, material, group);
862
+ const pointUvStreams = material?.map || material?.alphaMap
863
+ ? textureUvStreamsForMapAlphaMaterial(pointUvChannels, {
864
+ map: material.map,
865
+ alphaMap: material.alphaMap,
866
+ })
867
+ : null;
868
+ const baseColor = (0, materials_1.materialColor)(material, materialContext);
869
+ const useVertexColors = vertexColors && material?.vertexColors !== false;
870
+ const pointSize = positiveMaterialOrObjectNumber(material?.size, 'material.size', 1);
871
+ const sizeAttenuation = optionalSceneBoolean(material?.sizeAttenuation, 'material.sizeAttenuation');
872
+ const billboard = pointBillboardExpansion(object, group, position, positions, index ?? sourceIndex, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, useVertexColors ? baseColor : undefined, cache);
873
+ if (billboard.positions.length === 0)
874
+ continue;
875
+ const outputPositions = billboard.positions;
876
+ const outputUvs = billboard.uvs;
877
+ const outputUvs2 = billboard.uvs2;
878
+ const outputColors = billboard.colors;
879
+ const outputIndices = billboard.indices;
880
+ const outputPointRefs = billboard.pointRefs;
881
+ const textureInfo = (0, materials_1.extractTextureData)(material, materialContext);
882
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, undefined, geometry, group);
883
+ const pbrProps = (0, materials_1.extractPbrProperties)(material, materialContext);
884
+ assertSupportedCustomFragmentInstancedAttributes(geometry, pbrProps);
885
+ pbrProps.alphaMapUsesUv2 = pointUvStreams?.alphaMapUsesUv2 ?? false;
886
+ const clipping = clippingState(clippingContext, material, localClippingEnabled);
887
+ const customShadowMaterial = customShadowMaterialForMode(object, shadowMaterialMode);
888
+ const usesCustomShadowMaterial = objectCastsShadow && customShadowMaterial != null;
889
+ const effectiveCustomShadowMaterial = usesCustomShadowMaterial
890
+ ? shadowMaterialWithSourceShadowState(customShadowMaterial, material)
891
+ : null;
892
+ const pointShadowUvStreams = effectiveCustomShadowMaterial && (effectiveCustomShadowMaterial.map ||
893
+ effectiveCustomShadowMaterial.alphaMap)
894
+ ? textureUvStreamsForMapAlphaMaterial(pointUvChannels, {
895
+ map: effectiveCustomShadowMaterial.map,
896
+ alphaMap: effectiveCustomShadowMaterial.alphaMap,
897
+ })
898
+ : null;
899
+ pushMesh(meshes, {
900
+ positions: outputPositions,
901
+ indices: outputIndices,
902
+ uvs: outputUvs,
903
+ uvs2: outputUvs2,
904
+ color: baseColor,
905
+ colors: outputColors,
906
+ texture: textureInfo?.data,
907
+ textureWidth: textureInfo?.width ?? undefined,
908
+ textureHeight: textureInfo?.height ?? undefined,
909
+ textureWrapS: textureInfo?.wrapS,
910
+ textureWrapT: textureInfo?.wrapT,
911
+ textureMagFilter: textureInfo?.magFilter,
912
+ textureMinFilter: textureInfo?.minFilter,
913
+ textureAnisotropy: textureInfo?.anisotropy,
914
+ textureTransform: textureInfo?.transform,
915
+ textureColorSpace: textureInfo?.colorSpace,
916
+ textureUsesUv2: pointUvStreams?.textureUsesUv2 ?? false,
917
+ transform: math_1.IDENTITY_4X4.slice(),
918
+ transparent: material?.transparent === true || (material?.opacity != null && material.opacity < 1),
919
+ topology: 'triangles',
920
+ castShadow: objectCastsShadow && !usesCustomShadowMaterial ? true : undefined,
921
+ receiveShadow: false,
922
+ clipShadows: clipShadowsForMaterial(material, clippingContext),
923
+ ...clipping,
924
+ ...sortInfo.keys,
925
+ ...pbrProps,
926
+ shadingModel: 'basic',
927
+ }, sortInfo.item);
928
+ if (usesCustomShadowMaterial && customShadowMaterial?.visible !== false) {
929
+ appendShadowOnlyBillboardMesh(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, customShadowMaterial, material, materialContext, outputPositions, outputIndices, pointShadowUvStreams?.uvs ? expandPointBillboardUvStream(pointShadowUvStreams.uvs, outputPointRefs) : outputUvs, pointShadowUvStreams?.uvs2 ? expandPointBillboardUvStream(pointShadowUvStreams.uvs2, outputPointRefs) : undefined, pointShadowUvStreams?.textureUsesUv2 ?? false, pointShadowUvStreams?.alphaMapUsesUv2 ?? false);
930
+ }
931
+ invokeObjectRenderCallback(object.onAfterRender, 'onAfterRender', callbackContext, object, camera, geometry, material, group);
932
+ }
933
+ }
934
+ function pointBillboardExpansion(object, group, position, positions, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, vertexColorBase, cache) {
935
+ const signature = pointBillboardSignature(group, position, positions, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, vertexColorBase);
936
+ const cacheKey = `${group.start}:${group.count}:${group.materialIndex ?? 0}`;
937
+ if (cache && signature.cacheable) {
938
+ const objectCache = cache.pointBillboards.get(object);
939
+ const cached = objectCache?.get(cacheKey);
940
+ if (cached && samePointBillboardSignature(cached.signature, signature)) {
941
+ return cached.expansion;
942
+ }
943
+ }
944
+ const expansion = readPointBillboardExpansion(group, position, positions, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, vertexColorBase);
945
+ if (cache && signature.cacheable) {
946
+ let objectCache = cache.pointBillboards.get(object);
947
+ if (!objectCache) {
948
+ objectCache = new Map();
949
+ cache.pointBillboards.set(object, objectCache);
950
+ }
951
+ objectCache.set(cacheKey, { signature, expansion });
952
+ }
953
+ return expansion;
954
+ }
955
+ function readPointBillboardExpansion(group, position, positions, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, vertexColorBase) {
956
+ const source = index ?? rangeIndices(position.count);
957
+ const points = source.slice(group.start, group.start + group.count);
958
+ const outputPositions = [];
959
+ const outputUvs = [];
960
+ const outputUvs2 = pointUvStreams?.uvs2 ? [] : undefined;
961
+ const outputColors = vertexColorBase ? [] : undefined;
962
+ const outputIndices = [];
963
+ const outputPointRefs = [];
964
+ const corners = [
965
+ [-0.5, -0.5, 0, 0],
966
+ [0.5, -0.5, 1, 0],
967
+ [0.5, 0.5, 1, 1],
968
+ [-0.5, 0.5, 0, 1],
969
+ ];
970
+ for (let instance = 0; instance < instancedGeometryCount; instance += 1) {
971
+ const offsetIndex = instancedPositionOffset
972
+ ? instancedAttributeIndex(instancedPositionOffset.attribute, instance, instancedPositionOffset.label)
973
+ : 0;
974
+ const offset = instancedPositionOffset
975
+ ? [
976
+ (0, attributes_1.attributeComponent)(instancedPositionOffset.attribute, offsetIndex, 0, instancedPositionOffset.label),
977
+ (0, attributes_1.attributeComponent)(instancedPositionOffset.attribute, offsetIndex, 1, instancedPositionOffset.label),
978
+ (0, attributes_1.attributeComponent)(instancedPositionOffset.attribute, offsetIndex, 2, instancedPositionOffset.label),
979
+ ]
980
+ : [0, 0, 0];
981
+ const scale = instanceScaleComponents(instancedPositionScale, instance);
982
+ for (let pointOffset = 0; pointOffset < points.length; pointOffset += 1) {
983
+ const pointIndex = points[pointOffset];
984
+ if (!Number.isInteger(pointIndex) || pointIndex < 0 || pointIndex >= position.count)
985
+ continue;
986
+ const center = transformPoint(transform, [
987
+ positions[pointIndex * 3] * scale[0] + offset[0],
988
+ positions[pointIndex * 3 + 1] * scale[1] + offset[1],
989
+ positions[pointIndex * 3 + 2] * scale[2] + offset[2],
990
+ ]);
991
+ const worldSize = pointWorldSize(pointSize, center, sizeAttenuation, camera, viewportHeight);
992
+ if (worldSize <= 0)
993
+ continue;
994
+ const vertexBase = outputPositions.length / 3;
995
+ outputPointRefs.push({ pointIndex, instance });
996
+ const pointColor = outputColors ? pointVertexColor(vertexColors, vertexColorBase, pointIndex, instance) : null;
997
+ for (const [x, y, u, v] of corners) {
998
+ outputPositions.push(center[0] + axes.right[0] * x * worldSize + axes.up[0] * y * worldSize, center[1] + axes.right[1] * x * worldSize + axes.up[1] * y * worldSize, center[2] + axes.right[2] * x * worldSize + axes.up[2] * y * worldSize);
999
+ if (pointUvStreams) {
1000
+ if (pointUvStreams.uvs) {
1001
+ appendUvForVertex(outputUvs, pointUvStreams.uvs, pointIndex, instance);
1002
+ }
1003
+ else {
1004
+ outputUvs.push(u, v);
1005
+ }
1006
+ if (outputUvs2 && pointUvStreams.uvs2) {
1007
+ appendUvForVertex(outputUvs2, pointUvStreams.uvs2, pointIndex, instance);
1008
+ }
1009
+ }
1010
+ else {
1011
+ outputUvs.push(u, v);
1012
+ }
1013
+ if (pointColor) {
1014
+ outputColors.push(pointColor[0], pointColor[1], pointColor[2], pointColor[3]);
1015
+ }
1016
+ }
1017
+ outputIndices.push(vertexBase, vertexBase + 1, vertexBase + 2, vertexBase, vertexBase + 2, vertexBase + 3);
1018
+ }
1019
+ }
1020
+ return {
1021
+ positions: outputPositions,
1022
+ indices: outputIndices,
1023
+ uvs: outputUvs,
1024
+ uvs2: outputUvs2,
1025
+ colors: outputColors,
1026
+ pointRefs: outputPointRefs,
1027
+ };
1028
+ }
1029
+ function pointBillboardSignature(group, position, positions, index, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, transform, axes, camera, viewportHeight, pointSize, sizeAttenuation, pointUvStreams, vertexColors, vertexColorBase) {
1030
+ const signature = {
1031
+ cacheable: true,
1032
+ positions,
1033
+ positionCount: position.count,
1034
+ index,
1035
+ groupStart: group.start,
1036
+ groupCount: group.count,
1037
+ instancedGeometryCount,
1038
+ instancedPositionOffset: attributeSignature(instancedPositionOffset?.attribute),
1039
+ instancedPositionScale: attributeSignature(instancedPositionScale?.attribute),
1040
+ transform: transform.slice(0, 16),
1041
+ cameraRight: axes.right.slice(),
1042
+ cameraUp: axes.up.slice(),
1043
+ cameraProjection: matrixValues(camera?.projectionMatrix?.elements),
1044
+ cameraView: matrixValues(camera?.matrixWorldInverse?.elements),
1045
+ cameraIsPerspective: camera?.isPerspectiveCamera,
1046
+ viewportHeight,
1047
+ pointSize,
1048
+ sizeAttenuation,
1049
+ uvs: uvChannelSignature(pointUvStreams?.uvs),
1050
+ uvs2: uvChannelSignature(pointUvStreams?.uvs2),
1051
+ useVertexColors: !!vertexColorBase,
1052
+ vertexColors: attributeSignature(vertexColorBase ? vertexColors : undefined),
1053
+ baseColor: vertexColorBase ? vertexColorBase.slice() : undefined,
1054
+ };
1055
+ signature.cacheable = pointBillboardSignatureCacheable(signature);
1056
+ return signature;
1057
+ }
1058
+ function pointBillboardSignatureCacheable(signature) {
1059
+ return attributeSignatureCacheable(signature.instancedPositionOffset)
1060
+ && attributeSignatureCacheable(signature.instancedPositionScale)
1061
+ && attributeSignatureCacheable(signature.uvs.attribute)
1062
+ && attributeSignatureCacheable(signature.uvs2.attribute)
1063
+ && attributeSignatureCacheable(signature.vertexColors);
1064
+ }
1065
+ function uvChannelSignature(channel) {
1066
+ if (!channel)
1067
+ return { attribute: {} };
1068
+ return {
1069
+ attribute: attributeSignature(channel.attribute),
1070
+ values: channel.values,
1071
+ label: channel.label,
1072
+ };
1073
+ }
1074
+ function matrixValues(matrix) {
1075
+ if (!matrix || matrix.length < 16)
1076
+ return null;
1077
+ const out = new Array(16);
1078
+ for (let i = 0; i < 16; i += 1)
1079
+ out[i] = matrix[i];
1080
+ return out;
1081
+ }
1082
+ function samePointBillboardSignature(a, b) {
1083
+ return a.cacheable === b.cacheable
1084
+ && a.positions === b.positions
1085
+ && a.positionCount === b.positionCount
1086
+ && a.index === b.index
1087
+ && a.groupStart === b.groupStart
1088
+ && a.groupCount === b.groupCount
1089
+ && a.instancedGeometryCount === b.instancedGeometryCount
1090
+ && sameAttributeSignature(a.instancedPositionOffset, b.instancedPositionOffset)
1091
+ && sameAttributeSignature(a.instancedPositionScale, b.instancedPositionScale)
1092
+ && sameNumberArray(a.transform, b.transform)
1093
+ && sameNumberArray(a.cameraRight, b.cameraRight)
1094
+ && sameNumberArray(a.cameraUp, b.cameraUp)
1095
+ && sameOptionalNumberArray(a.cameraProjection, b.cameraProjection)
1096
+ && sameOptionalNumberArray(a.cameraView, b.cameraView)
1097
+ && a.cameraIsPerspective === b.cameraIsPerspective
1098
+ && a.viewportHeight === b.viewportHeight
1099
+ && a.pointSize === b.pointSize
1100
+ && a.sizeAttenuation === b.sizeAttenuation
1101
+ && sameUvChannelSignature(a.uvs, b.uvs)
1102
+ && sameUvChannelSignature(a.uvs2, b.uvs2)
1103
+ && a.useVertexColors === b.useVertexColors
1104
+ && sameAttributeSignature(a.vertexColors, b.vertexColors)
1105
+ && sameOptionalNumberArray(a.baseColor, b.baseColor);
1106
+ }
1107
+ function sameUvChannelSignature(a, b) {
1108
+ return sameAttributeSignature(a.attribute, b.attribute)
1109
+ && a.values === b.values
1110
+ && a.label === b.label;
1111
+ }
1112
+ function sameOptionalNumberArray(a, b) {
1113
+ if (a == null || b == null)
1114
+ return a == null && b == null;
1115
+ return sameNumberArray(a, b);
1116
+ }
1117
+ function sameNumberArray(a, b) {
1118
+ if (a.length !== b.length)
1119
+ return false;
1120
+ for (let i = 0; i < a.length; i += 1) {
1121
+ if (!Object.is(a[i], b[i]))
1122
+ return false;
1123
+ }
1124
+ return true;
1125
+ }
1126
+ function expandPointBillboardUvStream(channel, pointRefs) {
1127
+ const outputUvs = [];
1128
+ for (const { pointIndex, instance } of pointRefs) {
1129
+ for (let corner = 0; corner < 4; corner += 1) {
1130
+ appendUvForVertex(outputUvs, channel, pointIndex, instance);
1131
+ }
1132
+ }
1133
+ return outputUvs;
1134
+ }
1135
+ function appendShadowOnlyBillboardMesh(object, camera, meshes, groupOrder, clippingContext, localClippingEnabled, material, sourceMaterial, materialContext, positions, indices, uvs, uvs2 = undefined, textureUsesUv2 = false, alphaMapUsesUv2 = false) {
1136
+ const shadowMaterial = shadowMaterialWithSourceShadowState(material, sourceMaterial);
1137
+ const textureInfo = (0, materials_1.extractTextureData)(shadowMaterial, materialContext);
1138
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder);
1139
+ const clipping = clippingState(clippingContext, shadowMaterial, localClippingEnabled);
1140
+ const hiddenMainPass = shadowOnlyMainPassState();
1141
+ const shadowProps = shadowPbrProperties(shadowMaterial, sourceMaterial, materialContext);
1142
+ shadowProps.alphaMapUsesUv2 = alphaMapUsesUv2;
1143
+ pushMesh(meshes, {
1144
+ positions,
1145
+ indices,
1146
+ uvs,
1147
+ uvs2,
1148
+ color: (0, materials_1.materialColor)(shadowMaterial, materialContext),
1149
+ texture: textureInfo?.data,
1150
+ textureWidth: textureInfo?.width ?? undefined,
1151
+ textureHeight: textureInfo?.height ?? undefined,
1152
+ textureWrapS: textureInfo?.wrapS,
1153
+ textureWrapT: textureInfo?.wrapT,
1154
+ textureMagFilter: textureInfo?.magFilter,
1155
+ textureMinFilter: textureInfo?.minFilter,
1156
+ textureAnisotropy: textureInfo?.anisotropy,
1157
+ textureTransform: textureInfo?.transform,
1158
+ textureColorSpace: textureInfo?.colorSpace,
1159
+ textureUsesUv2,
1160
+ transform: math_1.IDENTITY_4X4.slice(),
1161
+ topology: 'triangles',
1162
+ castShadow: true,
1163
+ receiveShadow: false,
1164
+ clipShadows: clipShadowsForMaterial(shadowMaterial, clippingContext),
1165
+ ...clipping,
1166
+ ...sortInfo.keys,
1167
+ ...shadowProps,
1168
+ ...hiddenMainPass,
1169
+ }, sortInfo.item);
1170
+ }
1171
+ function shadowMaterialWithSourceShadowState(material, sourceMaterial) {
1172
+ if (!sourceMaterialHasShadowState(sourceMaterial))
1173
+ return material;
1174
+ const shadowMaterial = Object.create(material);
1175
+ if (sourceMaterialHasShadowAlphaState(sourceMaterial)) {
1176
+ shadowMaterial.map = sourceMaterial.map ?? null;
1177
+ shadowMaterial.alphaMap = sourceMaterial.alphaMap ?? null;
1178
+ shadowMaterial.alphaTest = sourceMaterial.alphaToCoverage === true ? 0.5 : sourceMaterial.alphaTest;
1179
+ shadowMaterial.alphaToCoverage = sourceMaterial.alphaToCoverage;
1180
+ if (sourceMaterial.alphaHash === true)
1181
+ shadowMaterial.alphaHash = true;
1182
+ if (sourceMaterial.alphaHash === true || sourceMaterial.alphaToCoverage === true) {
1183
+ if (sourceMaterial.opacity != null) {
1184
+ shadowMaterial.opacity = sourceMaterial.opacity;
1185
+ }
116
1186
  }
117
1187
  }
1188
+ if (sourceMaterialHasShadowDisplacementState(sourceMaterial)) {
1189
+ shadowMaterial.displacementMap = sourceMaterial.displacementMap ?? null;
1190
+ shadowMaterial.displacementScale = sourceMaterial.displacementScale;
1191
+ shadowMaterial.displacementBias = sourceMaterial.displacementBias;
1192
+ }
1193
+ if (sourceMaterialHasShadowClippingState(sourceMaterial)) {
1194
+ shadowMaterial.clipShadows = sourceMaterial.clipShadows;
1195
+ shadowMaterial.clippingPlanes = sourceMaterial.clippingPlanes;
1196
+ shadowMaterial.clipIntersection = sourceMaterial.clipIntersection;
1197
+ }
1198
+ if (sourceMaterialHasShadowWireframeState(sourceMaterial)) {
1199
+ shadowMaterial.wireframe = sourceMaterial.wireframe;
1200
+ }
1201
+ return shadowMaterial;
1202
+ }
1203
+ function sourceMaterialHasShadowState(material) {
1204
+ return sourceMaterialHasShadowAlphaState(material) ||
1205
+ sourceMaterialHasShadowDisplacementState(material) ||
1206
+ sourceMaterialHasShadowClippingState(material) ||
1207
+ sourceMaterialHasShadowWireframeState(material);
1208
+ }
1209
+ function sourceMaterialHasShadowAlphaState(material) {
1210
+ if (!material)
1211
+ return false;
1212
+ const hasAlphaTexture = !!(material.map || material.alphaMap);
1213
+ const hasOpacityAlpha = typeof material.opacity === 'number' && Number.isFinite(material.opacity) && material.opacity < 1;
1214
+ if (material.alphaHash === true && (hasAlphaTexture || hasOpacityAlpha))
1215
+ return true;
1216
+ if (material.alphaToCoverage === true && (hasAlphaTexture || hasOpacityAlpha))
1217
+ return true;
1218
+ if (!hasAlphaTexture)
1219
+ return false;
1220
+ if (material.alphaToCoverage === true)
1221
+ return true;
1222
+ return typeof material.alphaTest === 'number' && Number.isFinite(material.alphaTest) && material.alphaTest > 0;
1223
+ }
1224
+ function sourceMaterialHasShadowDisplacementState(material) {
1225
+ return !!material?.displacementMap;
1226
+ }
1227
+ function sourceMaterialHasShadowClippingState(material) {
1228
+ return !!material && ('clipShadows' in material ||
1229
+ material.clippingPlanes != null ||
1230
+ 'clipIntersection' in material);
1231
+ }
1232
+ function sourceMaterialHasShadowWireframeState(material) {
1233
+ return material?.wireframe === true;
1234
+ }
1235
+ function shadowPbrProperties(material, sourceMaterial, materialContext) {
1236
+ const props = (0, materials_1.extractPbrProperties)(material, materialContext);
1237
+ const sourceShadowSide = (0, materials_1.materialShadowSide)(sourceMaterial);
1238
+ if (sourceShadowSide) {
1239
+ props.shadowSide = sourceShadowSide;
1240
+ }
1241
+ return props;
1242
+ }
1243
+ function validateObjectShadowFlags(object) {
1244
+ optionalObjectBoolean(object.castShadow, 'object.castShadow');
1245
+ optionalObjectBoolean(object.receiveShadow, 'object.receiveShadow');
1246
+ }
1247
+ function optionalObjectBoolean(value, label) {
1248
+ return optionalSceneBoolean(value, label);
1249
+ }
1250
+ function optionalSceneBoolean(value, label) {
1251
+ if (value == null)
1252
+ return undefined;
1253
+ if (typeof value === 'boolean')
1254
+ return value;
1255
+ throw new TypeError(`${label} must be a boolean.`);
1256
+ }
1257
+ function pointVertexColor(attribute, materialColor, pointIndex, instanceIndex, label = 'geometry.attributes.color') {
1258
+ const sourceIndex = isInstancedAttribute(attribute)
1259
+ ? instancedAttributeIndex(attribute, instanceIndex, label)
1260
+ : pointIndex;
1261
+ return [
1262
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 0, label) * materialColor[0]),
1263
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 1, label) * materialColor[1]),
1264
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 2, label) * materialColor[2]),
1265
+ (0, math_1.clamp01)((attribute.itemSize && attribute.itemSize >= 4 ? (0, attributes_1.attributeComponent)(attribute, sourceIndex, 3, label) : 1) * materialColor[3]),
1266
+ ];
118
1267
  }
119
1268
  function effectiveGroups(geometry, index, vertexCount) {
120
1269
  const range = geometry.drawRange ?? {};
1270
+ if (range != null && (typeof range !== 'object' || Array.isArray(range))) {
1271
+ throw new TypeError('geometry.drawRange must be an object.');
1272
+ }
121
1273
  const maxCount = index ? index.length : vertexCount;
122
- const drawStart = (0, math_1.clampInteger)(range.start ?? 0, 0, maxCount);
123
- const requestedCount = range.count == null || range.count === Infinity ? maxCount : range.count;
1274
+ const drawStart = (0, math_1.clampInteger)(geometryDrawRangeStart(range.start), 0, maxCount);
1275
+ const requestedCount = geometryDrawRangeCount(range.count, maxCount);
124
1276
  const drawEnd = (0, math_1.clampInteger)(drawStart + requestedCount, drawStart, maxCount);
1277
+ if (geometry.groups != null && !Array.isArray(geometry.groups)) {
1278
+ throw new TypeError('geometry.groups must be an array.');
1279
+ }
125
1280
  const sourceGroups = Array.isArray(geometry.groups) && geometry.groups.length
126
1281
  ? geometry.groups
127
- : [{ start: drawStart, count: drawEnd - drawStart, materialIndex: 0 }];
1282
+ : null;
1283
+ if (!sourceGroups) {
1284
+ return [{ start: drawStart, count: drawEnd - drawStart, materialIndex: 0 }];
1285
+ }
128
1286
  const groups = [];
129
- for (const group of sourceGroups) {
130
- const start = Math.max(drawStart, (0, math_1.clampInteger)(group.start ?? 0, 0, maxCount));
131
- const end = Math.min(drawEnd, (0, math_1.clampInteger)((group.start ?? 0) + (group.count ?? 0), 0, maxCount));
1287
+ for (let groupIndex = 0; groupIndex < sourceGroups.length; groupIndex += 1) {
1288
+ const group = sourceGroups[groupIndex];
1289
+ if (!group || typeof group !== 'object' || Array.isArray(group)) {
1290
+ throw new TypeError(`geometry.groups[${groupIndex}] must be an object.`);
1291
+ }
1292
+ const groupStart = geometryGroupNonNegativeInteger(group.start, `geometry.groups[${groupIndex}].start`);
1293
+ const groupCount = geometryGroupNonNegativeInteger(group.count, `geometry.groups[${groupIndex}].count`);
1294
+ const groupMaterialIndex = group.materialIndex == null
1295
+ ? 0
1296
+ : geometryGroupNonNegativeInteger(group.materialIndex, `geometry.groups[${groupIndex}].materialIndex`);
1297
+ const start = Math.max(drawStart, (0, math_1.clampInteger)(groupStart, 0, maxCount));
1298
+ const end = Math.min(drawEnd, (0, math_1.clampInteger)(groupStart + groupCount, 0, maxCount));
132
1299
  if (end > start) {
133
1300
  groups.push({
134
1301
  start,
135
1302
  count: end - start,
136
- materialIndex: group.materialIndex ?? 0,
1303
+ materialIndex: groupMaterialIndex,
137
1304
  });
138
1305
  }
139
1306
  }
140
1307
  return groups;
141
1308
  }
1309
+ function geometryDrawRangeStart(value) {
1310
+ if (value == null)
1311
+ return 0;
1312
+ return geometryGroupNonNegativeInteger(value, 'geometry.drawRange.start');
1313
+ }
1314
+ function geometryDrawRangeCount(value, fallback) {
1315
+ if (value == null || value === Infinity)
1316
+ return fallback;
1317
+ return geometryGroupNonNegativeInteger(value, 'geometry.drawRange.count');
1318
+ }
1319
+ function geometryGroupNonNegativeInteger(value, label) {
1320
+ if (typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value) && value >= 0) {
1321
+ return value;
1322
+ }
1323
+ throw new TypeError(`${label} must be a non-negative integer.`);
1324
+ }
142
1325
  /**
143
1326
  * Emit a `NativeSceneMesh` with `topology: 'lines'` or `'points'` for
144
1327
  * `THREE.Line` / `THREE.LineSegments` / `THREE.LineLoop` / `THREE.Points`.
145
1328
  * Lines are always expanded to a LineList (pairs of vertex indices) so the
146
1329
  * Rust side only has to deal with one line topology.
147
1330
  */
148
- function appendLineOrPoints(object, meshes, topology) {
1331
+ function appendLineOrPoints(object, camera, meshes, topology, groupOrder, viewportHeight, clippingContext, localClippingEnabled, materialContext, overrideMaterial, cache, callbackContext) {
1332
+ validateObjectShadowFlags(object);
1333
+ const objectCastsShadow = topology === 'lines' && optionalObjectBoolean(object.castShadow, 'object.castShadow') === true;
149
1334
  const geometry = object.geometry;
150
- const position = (0, attributes_1.getAttribute)(geometry, 'position');
151
- if (!position)
1335
+ const geometryExtraction = meshGeometryExtraction(geometry, cache);
1336
+ if (!geometryExtraction)
152
1337
  return;
153
- const material = (0, materials_1.materialForGroup)(object.material, 0);
154
- if (material?.visible === false)
155
- return;
156
- const positions = (0, attributes_1.readVec3Attribute)(position);
157
- const vertexColors = (0, attributes_1.getAttribute)(geometry, 'color');
158
- const indexAttr = geometry.index ? (0, attributes_1.readIndexAttribute)(geometry.index) : null;
1338
+ const { position, positions, uvChannels, uvs, vertexColors, index, sourceIndex, groups, instancedGeometryCount, instancedPositionOffset, instancedPositionScale, } = geometryExtraction;
159
1339
  const vertexCount = position.count;
160
- const range = geometry.drawRange ?? {};
161
- const sourceCount = indexAttr ? indexAttr.length : vertexCount;
162
- const drawStart = (0, math_1.clampInteger)(range.start ?? 0, 0, sourceCount);
163
- const requestedCount = range.count == null || range.count === Infinity ? sourceCount : range.count;
164
- const drawEnd = (0, math_1.clampInteger)(drawStart + requestedCount, drawStart, sourceCount);
165
- let indices = null;
166
- if (topology === 'lines') {
167
- const source = indexAttr ?? rangeIndices(vertexCount);
168
- indices = expandLineIndices(source, drawStart, drawEnd, object);
169
- if (indices.length < 2)
170
- return;
1340
+ const indexAttr = index;
1341
+ for (const group of groups) {
1342
+ const material = materialForObjectGroup(object, group.materialIndex, overrideMaterial);
1343
+ if (material?.visible === false)
1344
+ continue;
1345
+ invokeObjectRenderCallback(object.onBeforeRender, 'onBeforeRender', callbackContext, object, camera, geometry, material, group);
1346
+ const uvStreams = topology === 'lines'
1347
+ ? textureUvStreamsForMapAlphaMaterial(uvChannels, material)
1348
+ : { uvs: uvChannels[0], uvs2: secondaryUvsForMaterial(uvChannels, material) };
1349
+ let indices = null;
1350
+ let outputPositions = positions;
1351
+ let outputUvs = topology === 'lines' ? uvStreams.uvs?.values : undefined;
1352
+ let outputSecondaryUvs = topology === 'lines' ? uvStreams.uvs2?.values : undefined;
1353
+ let outputColors;
1354
+ let thickCenter;
1355
+ const color = (0, materials_1.materialColor)(material, materialContext);
1356
+ const useVertexColors = vertexColors && material?.vertexColors !== false;
1357
+ const pbrProps = (0, materials_1.extractPbrProperties)(material, materialContext);
1358
+ assertSupportedCustomFragmentInstancedAttributes(geometry, pbrProps);
1359
+ if (topology === 'lines') {
1360
+ pbrProps.alphaMapUsesUv2 = uvStreams.alphaMapUsesUv2;
1361
+ }
1362
+ const textureInfo = (0, materials_1.extractTextureData)(material, materialContext);
1363
+ const drawStart = group.start;
1364
+ const drawEnd = group.start + group.count;
1365
+ if (topology === 'lines') {
1366
+ validateLineMaterialCompatibilityHints(material);
1367
+ }
1368
+ const lineWidth = positiveMaterialOrObjectNumber(material?.linewidth, 'material.linewidth', 1);
1369
+ const thickLine = topology === 'lines' && lineWidth > 1;
1370
+ if (topology === 'lines') {
1371
+ const source = sourceIndex;
1372
+ if (material?.isLineDashedMaterial === true) {
1373
+ const lineDistance = (0, attributes_1.getAttribute)(geometry, 'lineDistance');
1374
+ const dashed = instancedGeometryCount > 1 || instancedPositionOffset || instancedPositionScale
1375
+ ? dashedLineAttributesForInstancesWithCache(cache, geometry, position, positions, uvStreams.uvs, uvStreams.uvs2, useVertexColors ? vertexColors : undefined, color, source, drawStart, drawEnd, object, lineDistance, material, instancedGeometryCount, instancedPositionOffset, instancedPositionScale)
1376
+ : dashedLineAttributesWithCache(cache, geometry, position, positions, uvStreams.uvs, uvStreams.uvs2, useVertexColors ? (0, attributes_1.readColorAttribute)(vertexColors, color, 'geometry.attributes.color') : undefined, source, drawStart, drawEnd, object, lineDistance, material);
1377
+ if (dashed.positions.length < 6)
1378
+ continue;
1379
+ outputPositions = dashed.positions;
1380
+ outputUvs = dashed.uvs;
1381
+ outputSecondaryUvs = dashed.uvs2;
1382
+ outputColors = dashed.colors;
1383
+ indices = rangeIndices(dashed.positions.length / 3);
1384
+ if (thickLine) {
1385
+ const transform = (0, math_1.matrixElements)(object.matrixWorld, 'object.matrixWorld');
1386
+ const thick = thickLineAttributes(outputPositions, outputUvs, outputSecondaryUvs, outputColors, indices, transform, camera, viewportHeight, lineWidth);
1387
+ if (thick.positions.length < 12)
1388
+ continue;
1389
+ outputPositions = thick.positions;
1390
+ outputUvs = thick.uvs;
1391
+ outputSecondaryUvs = thick.uvs2;
1392
+ outputColors = thick.colors;
1393
+ indices = thick.indices;
1394
+ thickCenter = thick.center;
1395
+ }
1396
+ else {
1397
+ indices = null;
1398
+ }
1399
+ }
1400
+ else {
1401
+ indices = expandLineIndices(source, drawStart, drawEnd, object);
1402
+ if (indices.length < 2)
1403
+ continue;
1404
+ if (instancedGeometryCount > 1 || instancedPositionOffset || instancedPositionScale) {
1405
+ outputPositions = expandVec3ValuesForInstancesWithCache(cache, geometry, position, positions, 0, vertexCount, instancedGeometryCount, instancedPositionOffset, instancedPositionScale);
1406
+ outputUvs = uvStreams.uvs ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs, 0, vertexCount, instancedGeometryCount) : undefined;
1407
+ outputSecondaryUvs = uvStreams.uvs2 ? expandUvChannelForInstancesWithCache(cache, geometry, uvStreams.uvs2, 0, vertexCount, instancedGeometryCount) : undefined;
1408
+ indices = expandIndicesForInstances(indices, vertexCount, instancedGeometryCount);
1409
+ }
1410
+ if (thickLine) {
1411
+ const transform = (0, math_1.matrixElements)(object.matrixWorld, 'object.matrixWorld');
1412
+ const thick = thickLineAttributes(outputPositions, outputUvs, outputSecondaryUvs, useVertexColors ? outputColors ?? expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, 0, vertexCount, instancedGeometryCount) : undefined, indices, transform, camera, viewportHeight, lineWidth);
1413
+ if (thick.positions.length < 12)
1414
+ continue;
1415
+ outputPositions = thick.positions;
1416
+ outputUvs = thick.uvs;
1417
+ outputSecondaryUvs = thick.uvs2;
1418
+ outputColors = thick.colors;
1419
+ indices = thick.indices;
1420
+ thickCenter = thick.center;
1421
+ }
1422
+ }
1423
+ }
1424
+ else if (indexAttr) {
1425
+ indices = indexAttr.slice(drawStart, drawEnd);
1426
+ if (indices.length === 0)
1427
+ continue;
1428
+ }
1429
+ if (useVertexColors && material?.isLineDashedMaterial !== true && !thickLine) {
1430
+ outputColors = expandColorAttributeForInstancesWithCache(cache, geometry, vertexColors, color, 0, vertexCount, instancedGeometryCount);
1431
+ }
1432
+ const sortInfo = sortInfoForObject(object, material, camera, meshes.length, groupOrder, undefined, geometry, group);
1433
+ if (thickCenter && camera) {
1434
+ sortInfo.keys.sortZ = projectedWorldPointZ(thickCenter, camera);
1435
+ sortInfo.item.z = sortInfo.keys.sortZ;
1436
+ }
1437
+ const clipping = clippingState(clippingContext, material, localClippingEnabled);
1438
+ pushMesh(meshes, {
1439
+ positions: outputPositions,
1440
+ indices: indices ?? undefined,
1441
+ uvs: topology === 'lines' ? outputUvs : undefined,
1442
+ uvs2: topology === 'lines' ? outputSecondaryUvs : undefined,
1443
+ color,
1444
+ colors: outputColors,
1445
+ texture: textureInfo?.data,
1446
+ textureWidth: textureInfo?.width ?? undefined,
1447
+ textureHeight: textureInfo?.height ?? undefined,
1448
+ textureWrapS: textureInfo?.wrapS,
1449
+ textureWrapT: textureInfo?.wrapT,
1450
+ textureMagFilter: textureInfo?.magFilter,
1451
+ textureMinFilter: textureInfo?.minFilter,
1452
+ textureAnisotropy: textureInfo?.anisotropy,
1453
+ textureTransform: textureInfo?.transform,
1454
+ textureColorSpace: textureInfo?.colorSpace,
1455
+ textureUsesUv2: topology === 'lines' ? uvStreams.textureUsesUv2 : textureInfo?.usesUv2,
1456
+ transform: thickLine ? math_1.IDENTITY_4X4.slice() : (0, math_1.matrixElements)(object.matrixWorld, 'object.matrixWorld'),
1457
+ transparent: material?.transparent === true || (material?.opacity != null && material.opacity < 1),
1458
+ alphaTest: material && Number.isFinite(material.alphaTest) && material.alphaTest > 0 ? material.alphaTest : undefined,
1459
+ clipShadows: clipShadowsForMaterial(material, clippingContext),
1460
+ ...pbrProps,
1461
+ ...(thickLine ? { side: 'double' } : {}),
1462
+ shadingModel: 'basic',
1463
+ topology: thickLine ? 'triangles' : topology,
1464
+ castShadow: objectCastsShadow ? true : undefined,
1465
+ ...clipping,
1466
+ ...sortInfo.keys,
1467
+ }, sortInfo.item);
1468
+ invokeObjectRenderCallback(object.onAfterRender, 'onAfterRender', callbackContext, object, camera, geometry, material, group);
171
1469
  }
172
- else if (indexAttr) {
173
- indices = indexAttr.slice(drawStart, drawEnd);
174
- if (indices.length === 0)
175
- return;
1470
+ }
1471
+ function thickLineAttributes(positions, uvs, uvs2, colors, lineIndices, transform, camera, viewportHeight, lineWidth) {
1472
+ const axes = cameraBillboardAxes(camera);
1473
+ const outputPositions = [];
1474
+ const outputUvs = uvs ? [] : undefined;
1475
+ const outputUvs2 = uvs2 ? [] : undefined;
1476
+ const outputColors = colors ? [] : undefined;
1477
+ const outputIndices = [];
1478
+ for (let i = 0; i + 1 < lineIndices.length; i += 2) {
1479
+ const aIndex = lineIndices[i];
1480
+ const bIndex = lineIndices[i + 1];
1481
+ if (!validPositionIndex(positions, aIndex) || !validPositionIndex(positions, bIndex))
1482
+ continue;
1483
+ const a = transformPoint(transform, [
1484
+ positions[aIndex * 3],
1485
+ positions[aIndex * 3 + 1],
1486
+ positions[aIndex * 3 + 2],
1487
+ ]);
1488
+ const b = transformPoint(transform, [
1489
+ positions[bIndex * 3],
1490
+ positions[bIndex * 3 + 1],
1491
+ positions[bIndex * 3 + 2],
1492
+ ]);
1493
+ const dx = b[0] - a[0];
1494
+ const dy = b[1] - a[1];
1495
+ const dz = b[2] - a[2];
1496
+ if (Math.hypot(dx, dy, dz) <= 1e-8)
1497
+ continue;
1498
+ const screenDx = dx * axes.right[0] + dy * axes.right[1] + dz * axes.right[2];
1499
+ const screenDy = dx * axes.up[0] + dy * axes.up[1] + dz * axes.up[2];
1500
+ const side = normalizeVec3([
1501
+ -screenDy * axes.right[0] + screenDx * axes.up[0],
1502
+ -screenDy * axes.right[1] + screenDx * axes.up[1],
1503
+ -screenDy * axes.right[2] + screenDx * axes.up[2],
1504
+ ], axes.up);
1505
+ const midpoint = [
1506
+ (a[0] + b[0]) * 0.5,
1507
+ (a[1] + b[1]) * 0.5,
1508
+ (a[2] + b[2]) * 0.5,
1509
+ ];
1510
+ const halfWidth = linePixelWorldSize(lineWidth, midpoint, camera, viewportHeight) * 0.5;
1511
+ if (halfWidth <= 0)
1512
+ continue;
1513
+ const vertexBase = outputPositions.length / 3;
1514
+ pushThickLineVertex(outputPositions, a, side, -halfWidth);
1515
+ pushThickLineVertex(outputPositions, a, side, halfWidth);
1516
+ pushThickLineVertex(outputPositions, b, side, halfWidth);
1517
+ pushThickLineVertex(outputPositions, b, side, -halfWidth);
1518
+ outputIndices.push(vertexBase, vertexBase + 1, vertexBase + 2, vertexBase, vertexBase + 2, vertexBase + 3);
1519
+ pushRepeatedVec2(outputUvs, uvs, aIndex);
1520
+ pushRepeatedVec2(outputUvs, uvs, aIndex);
1521
+ pushRepeatedVec2(outputUvs, uvs, bIndex);
1522
+ pushRepeatedVec2(outputUvs, uvs, bIndex);
1523
+ pushRepeatedVec2(outputUvs2, uvs2, aIndex);
1524
+ pushRepeatedVec2(outputUvs2, uvs2, aIndex);
1525
+ pushRepeatedVec2(outputUvs2, uvs2, bIndex);
1526
+ pushRepeatedVec2(outputUvs2, uvs2, bIndex);
1527
+ pushRepeatedColor(outputColors, colors, aIndex);
1528
+ pushRepeatedColor(outputColors, colors, aIndex);
1529
+ pushRepeatedColor(outputColors, colors, bIndex);
1530
+ pushRepeatedColor(outputColors, colors, bIndex);
1531
+ }
1532
+ return {
1533
+ center: thickLineCenter(outputPositions),
1534
+ colors: outputColors,
1535
+ indices: outputIndices,
1536
+ positions: outputPositions,
1537
+ uvs: outputUvs,
1538
+ uvs2: outputUvs2,
1539
+ };
1540
+ }
1541
+ function validPositionIndex(positions, index) {
1542
+ return Number.isInteger(index) && index >= 0 && index * 3 + 2 < positions.length;
1543
+ }
1544
+ function pushThickLineVertex(positions, point, side, offset) {
1545
+ positions.push(point[0] + side[0] * offset, point[1] + side[1] * offset, point[2] + side[2] * offset);
1546
+ }
1547
+ function pushRepeatedVec2(target, source, index) {
1548
+ if (!target || !source || index * 2 + 1 >= source.length)
1549
+ return;
1550
+ target.push(source[index * 2], source[index * 2 + 1]);
1551
+ }
1552
+ function pushRepeatedColor(target, source, index) {
1553
+ if (!target || !source || index * 4 + 3 >= source.length)
1554
+ return;
1555
+ target.push(source[index * 4], source[index * 4 + 1], source[index * 4 + 2], source[index * 4 + 3]);
1556
+ }
1557
+ function linePixelWorldSize(lineWidth, worldPosition, camera, viewportHeight) {
1558
+ const projectionY = Math.abs(finiteOrDefault(camera?.projectionMatrix?.elements?.[5], 1));
1559
+ if (projectionY <= 0)
1560
+ return 0;
1561
+ if (camera?.isPerspectiveCamera === true) {
1562
+ const viewZ = viewSpaceZ(worldPosition, camera);
1563
+ const depth = Number.isFinite(viewZ) ? Math.max(0.0001, Math.abs(viewZ)) : 1;
1564
+ return lineWidth * 2 * depth / Math.max(1, viewportHeight) / projectionY;
1565
+ }
1566
+ return lineWidth * 2 / Math.max(1, viewportHeight) / projectionY;
1567
+ }
1568
+ function thickLineCenter(positions) {
1569
+ if (positions.length < 3)
1570
+ return [0, 0, 0];
1571
+ let x = 0;
1572
+ let y = 0;
1573
+ let z = 0;
1574
+ let count = 0;
1575
+ for (let i = 0; i + 2 < positions.length; i += 3) {
1576
+ x += positions[i];
1577
+ y += positions[i + 1];
1578
+ z += positions[i + 2];
1579
+ count += 1;
176
1580
  }
177
- const color = (0, materials_1.materialColor)(material);
178
- const useVertexColors = vertexColors && material?.vertexColors !== false;
179
- const colors = useVertexColors ? (0, attributes_1.readColorAttribute)(vertexColors, color) : undefined;
1581
+ return count > 0 ? [x / count, y / count, z / count] : [0, 0, 0];
1582
+ }
1583
+ function clippingState(clippingContext, material, localClippingEnabled) {
1584
+ const inheritedUnionPlanes = clippingContext.unionPlanes.slice(0, clipping_1.MAX_CLIPPING_PLANES);
1585
+ const inheritedIntersectionPlanes = clippingContext.intersectionPlanes.slice(0, Math.max(0, clipping_1.MAX_CLIPPING_PLANES - inheritedUnionPlanes.length));
1586
+ const localBudget = Math.max(0, clipping_1.MAX_CLIPPING_PLANES - inheritedUnionPlanes.length - inheritedIntersectionPlanes.length);
1587
+ const localPlanes = localClippingEnabled
1588
+ ? (0, clipping_1.extractClippingPlanes)(material?.clippingPlanes, 'material.clippingPlanes', localBudget)
1589
+ : [];
1590
+ const clipIntersection = optionalObjectBoolean(material?.clipIntersection, 'material.clipIntersection') === true;
1591
+ const localUnionPlanes = clipIntersection ? [] : localPlanes;
1592
+ const localIntersectionPlanes = clipIntersection ? localPlanes : [];
1593
+ const unionPlanes = [...inheritedUnionPlanes, ...localUnionPlanes];
1594
+ const intersectionPlanes = [...inheritedIntersectionPlanes, ...localIntersectionPlanes];
1595
+ const planes = [...unionPlanes, ...intersectionPlanes];
1596
+ if (planes.length === 0)
1597
+ return {};
1598
+ return {
1599
+ clippingPlanes: (0, clipping_1.flattenClippingPlanes)(planes),
1600
+ clippingUnionCount: unionPlanes.length,
1601
+ };
1602
+ }
1603
+ function clippingContextForObject(parent, object) {
1604
+ if (object.isClippingGroup !== true)
1605
+ return parent;
1606
+ if (optionalObjectBoolean(object.enabled, 'ClippingGroup.enabled') === false)
1607
+ return parent;
1608
+ const clipIntersection = optionalObjectBoolean(object.clipIntersection, 'ClippingGroup.clipIntersection') === true;
1609
+ const clipShadows = parent.clipShadows || optionalObjectBoolean(object.clipShadows, 'ClippingGroup.clipShadows') === true;
1610
+ const currentCount = parent.unionPlanes.length + parent.intersectionPlanes.length;
1611
+ const remainingBudget = Math.max(0, clipping_1.MAX_CLIPPING_PLANES - currentCount);
1612
+ const planes = (0, clipping_1.extractClippingPlanes)(object.clippingPlanes, 'ClippingGroup.clippingPlanes', remainingBudget);
1613
+ if (planes.length === 0)
1614
+ return parent;
1615
+ return clipIntersection
1616
+ ? {
1617
+ unionPlanes: parent.unionPlanes,
1618
+ intersectionPlanes: [...parent.intersectionPlanes, ...planes],
1619
+ clipShadows,
1620
+ }
1621
+ : {
1622
+ unionPlanes: [...parent.unionPlanes, ...planes],
1623
+ intersectionPlanes: parent.intersectionPlanes,
1624
+ clipShadows,
1625
+ };
1626
+ }
1627
+ function clipShadowsForMaterial(material, clippingContext) {
1628
+ return optionalObjectBoolean(material?.clipShadows, 'material.clipShadows') === true || clippingContext.clipShadows ? true : undefined;
1629
+ }
1630
+ function pushMesh(meshes, mesh, sortItem, transparentDoubleSidePass = false) {
1631
+ const groupOrder = mesh.groupOrder ?? 0;
1632
+ const renderOrder = mesh.renderOrder ?? 0;
180
1633
  meshes.push({
181
- positions,
182
- indices: indices ?? undefined,
183
- color,
184
- colors,
185
- transform: (0, math_1.matrixElements)(object.matrixWorld, 'object.matrixWorld'),
186
- transparent: material?.transparent === true || (material?.opacity != null && material.opacity < 1),
187
- alphaTest: material && Number.isFinite(material.alphaTest) && material.alphaTest > 0 ? material.alphaTest : undefined,
188
- shadingModel: 'basic',
189
- topology,
1634
+ mesh: {
1635
+ ...mesh,
1636
+ groupOrder: nativeRenderOrderKey(groupOrder),
1637
+ renderOrder: nativeRenderOrderKey(renderOrder),
1638
+ },
1639
+ sortItem,
1640
+ groupOrder,
1641
+ renderOrder,
1642
+ sortZ: mesh.sortZ ?? 0,
1643
+ materialSortKey: mesh.materialSortKey ?? 0,
1644
+ materialVariant: mesh.materialVariant ?? 0,
1645
+ sortIndex: mesh.sortIndex ?? meshes.length,
1646
+ transparentDoubleSidePass,
1647
+ });
1648
+ }
1649
+ function needsTransparentDoubleSidePass(material, props, wireframe) {
1650
+ return !wireframe
1651
+ && material?.transparent === true
1652
+ && material.forceSinglePass === false
1653
+ && props.side === 'double';
1654
+ }
1655
+ function nativeMeshesFromSortedFlattened(meshes) {
1656
+ const nativeMeshes = [];
1657
+ for (const { mesh, transparentDoubleSidePass } of meshes) {
1658
+ if (transparentDoubleSidePass) {
1659
+ nativeMeshes.push({ ...mesh, side: 'back' });
1660
+ nativeMeshes.push({ ...mesh, side: 'front' });
1661
+ }
1662
+ else {
1663
+ nativeMeshes.push(mesh);
1664
+ }
1665
+ }
1666
+ return nativeMeshes;
1667
+ }
1668
+ const NativeMeshPayloadCacheLimit = 2048;
1669
+ function applyNativeMeshPayloadCache(meshes, cache) {
1670
+ for (const mesh of meshes) {
1671
+ const signature = nativeMeshPayloadSignature(mesh, cache);
1672
+ if (!signature)
1673
+ continue;
1674
+ let cached = cache.payloads.get(signature);
1675
+ if (!cached) {
1676
+ const positions = mesh.positions;
1677
+ cached = {
1678
+ key: cache.nextPayloadId++,
1679
+ vertexCount: positions.length / 3,
1680
+ indexCount: mesh.indices?.length,
1681
+ ready: false,
1682
+ };
1683
+ evictNativeMeshPayloads(cache);
1684
+ cache.payloads.set(signature, cached);
1685
+ }
1686
+ mesh.nativeMeshKey = cached.key;
1687
+ mesh.nativeVertexCount = cached.vertexCount;
1688
+ mesh.nativeIndexCount = cached.indexCount;
1689
+ if (cached.ready) {
1690
+ mesh.positions = [];
1691
+ delete mesh.indices;
1692
+ delete mesh.normals;
1693
+ delete mesh.colors;
1694
+ delete mesh.uvs;
1695
+ delete mesh.uvs2;
1696
+ }
1697
+ else {
1698
+ cache.pending.add(signature);
1699
+ }
1700
+ }
1701
+ }
1702
+ function nativeMeshPayloadSignature(mesh, cache) {
1703
+ if (!mesh.positions || mesh.positions.length === 0)
1704
+ return null;
1705
+ if (mesh.positions.length % 3 !== 0)
1706
+ return null;
1707
+ if (!nativeMeshPayloadCacheable(mesh))
1708
+ return null;
1709
+ return [
1710
+ 'p', nativeMeshPayloadObjectId(cache, mesh.positions),
1711
+ 'i', nativeMeshPayloadObjectId(cache, mesh.indices),
1712
+ 'n', nativeMeshPayloadObjectId(cache, mesh.normals),
1713
+ 'c', nativeMeshPayloadObjectId(cache, mesh.colors),
1714
+ 'u', nativeMeshPayloadObjectId(cache, mesh.uvs),
1715
+ 'v', nativeMeshPayloadObjectId(cache, mesh.uvs2),
1716
+ 'flat', mesh.flatShading === true ? 1 : 0,
1717
+ 'topology', mesh.topology ?? 'triangles',
1718
+ ].join(':');
1719
+ }
1720
+ function nativeMeshPayloadCacheable(mesh) {
1721
+ return mesh.displacementMap == null
1722
+ && mesh.normalMap == null
1723
+ && mesh.bumpMap == null
1724
+ && mesh.clearcoatNormalMap == null
1725
+ && (mesh.anisotropy == null || mesh.anisotropy <= 0);
1726
+ }
1727
+ function nativeMeshPayloadObjectId(cache, value) {
1728
+ if (value == null)
1729
+ return 'none';
1730
+ let id = cache.objectIds.get(value);
1731
+ if (id === undefined) {
1732
+ id = cache.nextObjectId++;
1733
+ cache.objectIds.set(value, id);
1734
+ }
1735
+ return String(id);
1736
+ }
1737
+ function evictNativeMeshPayloads(cache) {
1738
+ while (cache.payloads.size >= NativeMeshPayloadCacheLimit) {
1739
+ const first = cache.payloads.keys().next();
1740
+ if (first.done)
1741
+ return;
1742
+ cache.payloads.delete(first.value);
1743
+ cache.pending.delete(first.value);
1744
+ }
1745
+ }
1746
+ function sortInfoForObject(object, material, camera, sortIndex, groupOrder, transform, geometry, group, sortItemObject, sortItemZOverride) {
1747
+ const renderOrder = renderOrderNumber(object.renderOrder, 'object.renderOrder', 0);
1748
+ const z = camera ? projectedObjectZ(object, camera, transform) : 0;
1749
+ const itemZ = sortItemZOverride ?? z;
1750
+ const id = unsignedSortKey(object.id, sortIndex);
1751
+ const materialSortKey = finiteOrDefault(material?.id, 0);
1752
+ const materialVariant = materialVariantForObject(object);
1753
+ return {
1754
+ keys: {
1755
+ groupOrder,
1756
+ renderOrder,
1757
+ sortZ: z,
1758
+ sortIndex: id,
1759
+ materialSortKey,
1760
+ materialVariant,
1761
+ },
1762
+ item: {
1763
+ id,
1764
+ object: sortItemObject ?? object,
1765
+ geometry,
1766
+ material,
1767
+ group,
1768
+ groupOrder,
1769
+ renderOrder,
1770
+ z: itemZ,
1771
+ materialVariant,
1772
+ },
1773
+ };
1774
+ }
1775
+ function mergeSortKeys(keys, override) {
1776
+ return override ? { ...keys, ...override } : keys;
1777
+ }
1778
+ function sortFlattenedMeshes(meshes, options) {
1779
+ const sortObjects = options.sortObjects !== false;
1780
+ const buckets = partitionFlattenedMeshes(meshes);
1781
+ if (options.opaque === false)
1782
+ buckets.opaque.length = 0;
1783
+ if (options.transparent === false) {
1784
+ buckets.transmissive.length = 0;
1785
+ buckets.transparent.length = 0;
1786
+ }
1787
+ if (!sortObjects) {
1788
+ normalizeSortKeys(buckets.opaque);
1789
+ normalizeSortKeys(buckets.transmissive);
1790
+ normalizeSortKeys(buckets.transparent);
1791
+ return [...buckets.opaque, ...buckets.transmissive, ...buckets.transparent];
1792
+ }
1793
+ if (options.opaqueSort) {
1794
+ buckets.opaque.sort(compareWithSort(options.opaqueSort));
1795
+ normalizeSortKeys(buckets.opaque);
1796
+ }
1797
+ else {
1798
+ buckets.opaque.sort(compareFlattenedMeshes);
1799
+ }
1800
+ if (options.transparentSort) {
1801
+ const transparentSort = compareWithSort(options.transparentSort);
1802
+ buckets.transmissive.sort(transparentSort);
1803
+ buckets.transparent.sort(transparentSort);
1804
+ normalizeSortKeys(buckets.transmissive);
1805
+ normalizeSortKeys(buckets.transparent);
1806
+ }
1807
+ else {
1808
+ buckets.transmissive.sort(compareTransparentFlattenedMeshes);
1809
+ buckets.transparent.sort(compareTransparentFlattenedMeshes);
1810
+ }
1811
+ return [...buckets.opaque, ...buckets.transmissive, ...buckets.transparent];
1812
+ }
1813
+ function partitionFlattenedMeshes(meshes) {
1814
+ const opaque = [];
1815
+ const transmissive = [];
1816
+ const transparent = [];
1817
+ for (const mesh of meshes) {
1818
+ if (finitePositive(mesh.mesh.transmission)) {
1819
+ transmissive.push(mesh);
1820
+ }
1821
+ else if (meshDefaultsTransparent(mesh.mesh)) {
1822
+ transparent.push(mesh);
1823
+ }
1824
+ else {
1825
+ opaque.push(mesh);
1826
+ }
1827
+ }
1828
+ return { opaque, transmissive, transparent };
1829
+ }
1830
+ function compareWithSort(sort) {
1831
+ return (a, b) => {
1832
+ const result = Number(sort(a.sortItem, b.sortItem));
1833
+ return Number.isFinite(result) ? result : 0;
1834
+ };
1835
+ }
1836
+ function normalizeSortKeys(meshes) {
1837
+ meshes.forEach((entry, index) => {
1838
+ entry.mesh.groupOrder = 0;
1839
+ entry.mesh.renderOrder = 0;
1840
+ entry.mesh.materialSortKey = 0;
1841
+ entry.mesh.materialVariant = 0;
1842
+ entry.mesh.sortZ = 0;
1843
+ entry.mesh.sortIndex = index;
190
1844
  });
191
1845
  }
1846
+ function compareFlattenedMeshes(a, b) {
1847
+ return a.groupOrder - b.groupOrder
1848
+ || a.renderOrder - b.renderOrder
1849
+ || a.materialSortKey - b.materialSortKey
1850
+ || a.materialVariant - b.materialVariant
1851
+ || a.sortZ - b.sortZ
1852
+ || a.sortIndex - b.sortIndex;
1853
+ }
1854
+ function compareTransparentFlattenedMeshes(a, b) {
1855
+ return a.groupOrder - b.groupOrder
1856
+ || a.renderOrder - b.renderOrder
1857
+ || b.sortZ - a.sortZ
1858
+ || a.sortIndex - b.sortIndex;
1859
+ }
1860
+ function meshDefaultsTransparent(mesh) {
1861
+ if (mesh.alphaHash === true)
1862
+ return false;
1863
+ if (mesh.transparent === true)
1864
+ return true;
1865
+ if (mesh.transparent === false)
1866
+ return false;
1867
+ return materialAlpha(mesh) < 0.999;
1868
+ }
1869
+ function materialAlpha(mesh) {
1870
+ return mesh.color && mesh.color.length >= 4 ? finiteOrDefault(mesh.color[3], 1) : 1;
1871
+ }
1872
+ function finitePositive(value) {
1873
+ return typeof value === 'number' && Number.isFinite(value) && value > 0.0001;
1874
+ }
1875
+ function materialVariantForObject(object) {
1876
+ return (object.isInstancedMesh === true ? 2 : 0) + (object.isSkinnedMesh === true ? 1 : 0);
1877
+ }
1878
+ function projectedObjectZ(object, camera, transform) {
1879
+ const world = transform ?? object.matrixWorld?.elements;
1880
+ if (!world || world.length < 16)
1881
+ return 0;
1882
+ const view = camera.matrixWorldInverse?.elements;
1883
+ const projection = camera.projectionMatrix?.elements;
1884
+ if (!view || view.length < 16 || !projection || projection.length < 16)
1885
+ return 0;
1886
+ const center = objectSortCenter(object);
1887
+ const x = world[0] * center[0] + world[4] * center[1] + world[8] * center[2] + world[12];
1888
+ const y = world[1] * center[0] + world[5] * center[1] + world[9] * center[2] + world[13];
1889
+ const z = world[2] * center[0] + world[6] * center[1] + world[10] * center[2] + world[14];
1890
+ const vx = view[0] * x + view[4] * y + view[8] * z + view[12];
1891
+ const vy = view[1] * x + view[5] * y + view[9] * z + view[13];
1892
+ const vz = view[2] * x + view[6] * y + view[10] * z + view[14];
1893
+ const vw = view[3] * x + view[7] * y + view[11] * z + view[15];
1894
+ const clipZ = projection[2] * vx + projection[6] * vy + projection[10] * vz + projection[14] * vw;
1895
+ const clipW = projection[3] * vx + projection[7] * vy + projection[11] * vz + projection[15] * vw;
1896
+ return clipW === 0 ? clipZ : clipZ / clipW;
1897
+ }
1898
+ function projectedWorldPointZ(worldPoint, camera) {
1899
+ const view = camera.matrixWorldInverse?.elements;
1900
+ const projection = camera.projectionMatrix?.elements;
1901
+ if (!view || view.length < 16 || !projection || projection.length < 16)
1902
+ return 0;
1903
+ const x = worldPoint[0];
1904
+ const y = worldPoint[1];
1905
+ const z = worldPoint[2];
1906
+ const vx = view[0] * x + view[4] * y + view[8] * z + view[12];
1907
+ const vy = view[1] * x + view[5] * y + view[9] * z + view[13];
1908
+ const vz = view[2] * x + view[6] * y + view[10] * z + view[14];
1909
+ const vw = view[3] * x + view[7] * y + view[11] * z + view[15];
1910
+ const clipZ = projection[2] * vx + projection[6] * vy + projection[10] * vz + projection[14] * vw;
1911
+ const clipW = projection[3] * vx + projection[7] * vy + projection[11] * vz + projection[15] * vw;
1912
+ return clipW === 0 ? clipZ : clipZ / clipW;
1913
+ }
1914
+ function objectSortCenter(object) {
1915
+ if (object.boundingSphere !== undefined) {
1916
+ if (object.boundingSphere == null && typeof object.computeBoundingSphere === 'function') {
1917
+ try {
1918
+ object.computeBoundingSphere();
1919
+ }
1920
+ catch {
1921
+ return [0, 0, 0];
1922
+ }
1923
+ }
1924
+ if (object.boundingSphere == null)
1925
+ return [0, 0, 0];
1926
+ if (!object.boundingSphere || typeof object.boundingSphere !== 'object') {
1927
+ throw new TypeError('object.boundingSphere must be a THREE.Sphere-like object.');
1928
+ }
1929
+ return requiredVec3Like(object.boundingSphere.center, 'object.boundingSphere.center');
1930
+ }
1931
+ const geometry = object.geometry;
1932
+ if (!geometry)
1933
+ return [0, 0, 0];
1934
+ if (geometry.boundingSphere == null && typeof geometry.computeBoundingSphere === 'function') {
1935
+ try {
1936
+ geometry.computeBoundingSphere();
1937
+ }
1938
+ catch {
1939
+ return [0, 0, 0];
1940
+ }
1941
+ }
1942
+ const sphere = geometry.boundingSphere;
1943
+ if (sphere == null)
1944
+ return [0, 0, 0];
1945
+ if (!sphere || typeof sphere !== 'object') {
1946
+ throw new TypeError('geometry.boundingSphere must be a THREE.Sphere-like object.');
1947
+ }
1948
+ return requiredVec3Like(sphere.center, 'geometry.boundingSphere.center');
1949
+ }
1950
+ function renderableObjectOutsideFrustum(object, camera, viewportHeight = 512, overrideMaterial) {
1951
+ if (!camera)
1952
+ return false;
1953
+ const frustumCulled = optionalObjectBoolean(object.frustumCulled, 'object.frustumCulled');
1954
+ if (frustumCulled === false)
1955
+ return false;
1956
+ const sphere = objectBoundingSphere(object);
1957
+ if (!sphere)
1958
+ return false;
1959
+ const transform = (0, math_1.matrixElements)(object.matrixWorld, renderableMatrixWorldLabel(object));
1960
+ const extraRadius = object.isPoints === true
1961
+ ? pointBillboardCullRadius(object, camera, transform, sphere, viewportHeight, overrideMaterial)
1962
+ : 0;
1963
+ return transformedSphereOutsideFrustum(camera, transform, sphere, extraRadius);
1964
+ }
1965
+ function validateInstancedMeshMatrices(object) {
1966
+ const instanceMatrix = object.instanceMatrix;
1967
+ if (!instanceMatrix || instanceMatrix.count == null)
1968
+ return;
1969
+ const instanceMatrixCount = (0, attributes_1.attributeCount)(instanceMatrix, 'InstancedMesh.instanceMatrix');
1970
+ const count = (0, math_1.clampInteger)(integerCountOrDefault(object.count, 'InstancedMesh.count', instanceMatrixCount), 0, instanceMatrixCount);
1971
+ for (let i = 0; i < count; i += 1) {
1972
+ readMat4Attribute(instanceMatrix, i);
1973
+ }
1974
+ }
1975
+ function renderableMatrixWorldLabel(object) {
1976
+ if (object.isBatchedMesh === true)
1977
+ return 'batchedMesh.matrixWorld';
1978
+ if (object.isMesh === true)
1979
+ return 'mesh.matrixWorld';
1980
+ if (object.isPoints === true)
1981
+ return 'points.matrixWorld';
1982
+ return 'object.matrixWorld';
1983
+ }
1984
+ function objectBoundingSphere(object) {
1985
+ if (object.isBatchedMesh === true) {
1986
+ if (object.boundingSphere != null)
1987
+ return sphereLike(object.boundingSphere, 'object.boundingSphere');
1988
+ return batchedMeshBoundingSphere(object);
1989
+ }
1990
+ if (object.boundingSphere !== undefined) {
1991
+ const hadBoundingSphere = object.boundingSphere != null;
1992
+ if (object.boundingSphere == null && typeof object.computeBoundingSphere === 'function') {
1993
+ if (object.isInstancedMesh === true) {
1994
+ validateInstancedMeshMatrices(object);
1995
+ }
1996
+ try {
1997
+ object.computeBoundingSphere();
1998
+ }
1999
+ catch {
2000
+ return null;
2001
+ }
2002
+ }
2003
+ if (object.boundingSphere == null)
2004
+ return null;
2005
+ try {
2006
+ return object.isInstancedMesh === true
2007
+ ? instancedMeshBoundingSphere(object)
2008
+ : sphereLike(object.boundingSphere, 'object.boundingSphere');
2009
+ }
2010
+ catch (error) {
2011
+ if (!hadBoundingSphere)
2012
+ return null;
2013
+ throw error;
2014
+ }
2015
+ }
2016
+ const geometry = object.geometry;
2017
+ if (!geometry)
2018
+ return null;
2019
+ const hadBoundingSphere = geometry.boundingSphere != null;
2020
+ if (geometry.boundingSphere == null && typeof geometry.computeBoundingSphere === 'function') {
2021
+ try {
2022
+ geometry.computeBoundingSphere();
2023
+ }
2024
+ catch {
2025
+ return null;
2026
+ }
2027
+ }
2028
+ if (geometry.boundingSphere == null)
2029
+ return null;
2030
+ try {
2031
+ return sphereLike(geometry.boundingSphere, 'geometry.boundingSphere');
2032
+ }
2033
+ catch (error) {
2034
+ if (!hadBoundingSphere)
2035
+ return null;
2036
+ throw error;
2037
+ }
2038
+ }
2039
+ function batchedMeshBoundingSphere(object) {
2040
+ const geometry = object.geometry;
2041
+ if (!geometry)
2042
+ return null;
2043
+ const instanceInfo = object._instanceInfo;
2044
+ if (!Array.isArray(instanceInfo)) {
2045
+ throw new Error('THREE.BatchedMesh instance table is not readable. Use a real THREE.BatchedMesh or expand the batch to ordinary Mesh or InstancedMesh objects before rendering.');
2046
+ }
2047
+ let bounds = null;
2048
+ for (let instanceId = 0; instanceId < instanceInfo.length; instanceId += 1) {
2049
+ const info = instanceInfo[instanceId];
2050
+ if (!info || typeof info !== 'object') {
2051
+ throw new TypeError(`THREE.BatchedMesh._instanceInfo[${instanceId}] must be an object.`);
2052
+ }
2053
+ if (!batchedOptionalBoolean(info.active, `THREE.BatchedMesh._instanceInfo[${instanceId}].active`, true))
2054
+ continue;
2055
+ batchedOptionalBoolean(info.visible, `THREE.BatchedMesh._instanceInfo[${instanceId}].visible`, true);
2056
+ const geometryId = batchedNonNegativeInteger(info.geometryIndex, `THREE.BatchedMesh._instanceInfo[${instanceId}].geometryIndex`);
2057
+ const range = batchedGeometryRange(object, geometry, geometryId);
2058
+ if (range.count === 0)
2059
+ continue;
2060
+ const sphere = batchedGeometryBoundingSphere(object, geometry, geometryId, range);
2061
+ if (!sphere)
2062
+ continue;
2063
+ bounds = unionSpheres(bounds, transformSphere(sphere, batchedInstanceMatrix(object, instanceId)));
2064
+ }
2065
+ return bounds;
2066
+ }
2067
+ function transformSphere(sphere, transform) {
2068
+ const center = transformPoint(transform, sphere.center);
2069
+ const scale = Math.max(columnLength3(transform, 0), columnLength3(transform, 4), columnLength3(transform, 8));
2070
+ return { center, radius: sphere.radius * scale };
2071
+ }
2072
+ function unionSpheres(a, b) {
2073
+ if (!a)
2074
+ return { center: [...b.center], radius: b.radius };
2075
+ const dx = b.center[0] - a.center[0];
2076
+ const dy = b.center[1] - a.center[1];
2077
+ const dz = b.center[2] - a.center[2];
2078
+ const distance = Math.hypot(dx, dy, dz);
2079
+ if (distance <= Math.abs(a.radius - b.radius)) {
2080
+ return a.radius >= b.radius ? a : { center: [...b.center], radius: b.radius };
2081
+ }
2082
+ if (distance === 0)
2083
+ return { center: [...a.center], radius: Math.max(a.radius, b.radius) };
2084
+ const radius = (distance + a.radius + b.radius) * 0.5;
2085
+ const centerShift = (radius - a.radius) / distance;
2086
+ return {
2087
+ center: [
2088
+ a.center[0] + dx * centerShift,
2089
+ a.center[1] + dy * centerShift,
2090
+ a.center[2] + dz * centerShift,
2091
+ ],
2092
+ radius,
2093
+ };
2094
+ }
2095
+ function instancedMeshBoundingSphere(object) {
2096
+ try {
2097
+ return sphereLike(object.boundingSphere, 'object.boundingSphere');
2098
+ }
2099
+ catch (error) {
2100
+ validateInstancedMeshMatrices(object);
2101
+ throw error;
2102
+ }
2103
+ }
2104
+ function pointBillboardCullRadius(object, camera, transform, sphere, viewportHeight, overrideMaterial) {
2105
+ const center = transformPoint(transform, sphere.center);
2106
+ let radius = 0;
2107
+ for (const material of pointCullMaterials(object, overrideMaterial)) {
2108
+ const pointSize = safePositiveNumber(material?.size, 1);
2109
+ const sizeAttenuation = typeof material?.sizeAttenuation === 'boolean'
2110
+ ? material.sizeAttenuation
2111
+ : undefined;
2112
+ const worldSize = pointWorldSize(pointSize, center, sizeAttenuation, camera, viewportHeight);
2113
+ radius = Math.max(radius, worldSize * Math.SQRT1_2);
2114
+ }
2115
+ return radius;
2116
+ }
2117
+ function pointCullMaterials(object, overrideMaterial) {
2118
+ if (overrideMaterial !== undefined)
2119
+ return [overrideMaterial];
2120
+ if (Array.isArray(object.material)) {
2121
+ return object.material.filter((material) => material != null && typeof material === 'object' && !Array.isArray(material));
2122
+ }
2123
+ return object.material != null && typeof object.material === 'object' && !Array.isArray(object.material)
2124
+ ? [object.material]
2125
+ : [undefined];
2126
+ }
2127
+ function spriteOutsideFrustum(object, camera, transform, center) {
2128
+ if (!camera)
2129
+ return false;
2130
+ const frustumCulled = optionalObjectBoolean(object.frustumCulled, 'object.frustumCulled');
2131
+ if (frustumCulled === false)
2132
+ return false;
2133
+ const offset = Math.hypot(center[0] - 0.5, center[1] - 0.5);
2134
+ return transformedSphereOutsideFrustum(camera, transform, {
2135
+ center: [0, 0, 0],
2136
+ radius: 0.7071067811865476 + offset,
2137
+ });
2138
+ }
2139
+ function transformedSphereOutsideFrustum(camera, transform, sphere, extraRadius = 0) {
2140
+ const center = transformPoint(transform, sphere.center);
2141
+ const scale = Math.max(columnLength3(transform, 0), columnLength3(transform, 4), columnLength3(transform, 8));
2142
+ const radius = sphere.radius * scale + extraRadius;
2143
+ if (!Number.isFinite(radius) || radius < 0)
2144
+ return false;
2145
+ return !cameraFrustumIntersectsSphere(camera, center, radius);
2146
+ }
2147
+ function vec3Like(value) {
2148
+ if (!value)
2149
+ return null;
2150
+ const objectValue = value;
2151
+ const x = typeof objectValue.x === 'number' ? objectValue.x : value[0];
2152
+ const y = typeof objectValue.y === 'number' ? objectValue.y : value[1];
2153
+ const z = typeof objectValue.z === 'number' ? objectValue.z : value[2];
2154
+ return typeof x === 'number' && Number.isFinite(x)
2155
+ && typeof y === 'number' && Number.isFinite(y)
2156
+ && typeof z === 'number' && Number.isFinite(z)
2157
+ ? [x, y, z]
2158
+ : null;
2159
+ }
2160
+ function requiredVec3Like(value, label) {
2161
+ const vector = vec3Like(value);
2162
+ if (vector)
2163
+ return vector;
2164
+ throw new TypeError(`${label} must be a finite Vector3-like value.`);
2165
+ }
2166
+ function columnLength3(matrix, start) {
2167
+ const x = matrix[start];
2168
+ const y = matrix[start + 1];
2169
+ const z = matrix[start + 2];
2170
+ return Math.hypot(x, y, z);
2171
+ }
2172
+ function cameraBillboardAxes(camera) {
2173
+ const matrix = camera?.matrixWorld?.elements;
2174
+ if (!matrix || matrix.length < 16) {
2175
+ return { right: [1, 0, 0], up: [0, 1, 0] };
2176
+ }
2177
+ return {
2178
+ right: normalizeVec3([matrix[0], matrix[1], matrix[2]], [1, 0, 0]),
2179
+ up: normalizeVec3([matrix[4], matrix[5], matrix[6]], [0, 1, 0]),
2180
+ };
2181
+ }
2182
+ function normalizeVec3(value, fallback) {
2183
+ const length = Math.hypot(value[0], value[1], value[2]);
2184
+ if (!Number.isFinite(length) || length <= 1e-8)
2185
+ return fallback;
2186
+ return [value[0] / length, value[1] / length, value[2] / length];
2187
+ }
2188
+ function viewSpaceZ(worldPosition, camera) {
2189
+ const view = camera.matrixWorldInverse?.elements;
2190
+ if (!view || view.length < 16)
2191
+ return Number.NaN;
2192
+ return view[2] * worldPosition[0] + view[6] * worldPosition[1] + view[10] * worldPosition[2] + view[14];
2193
+ }
2194
+ function transformPoint(matrix, point) {
2195
+ const x = point[0];
2196
+ const y = point[1];
2197
+ const z = point[2];
2198
+ return [
2199
+ matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12],
2200
+ matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13],
2201
+ matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14],
2202
+ ];
2203
+ }
2204
+ function pointWorldSize(pointSize, worldPosition, sizeAttenuation, camera, viewportHeight) {
2205
+ const projectionY = Math.abs(finiteOrDefault(camera?.projectionMatrix?.elements?.[5], 1));
2206
+ if (projectionY <= 0)
2207
+ return 0;
2208
+ if (camera?.isPerspectiveCamera === true && sizeAttenuation !== false) {
2209
+ const viewZ = viewSpaceZ(worldPosition, camera);
2210
+ const depth = Number.isFinite(viewZ) ? Math.max(0.0001, Math.abs(viewZ)) : 1;
2211
+ const pixelSize = clampPointSpriteSize(pointSize * Math.max(1, viewportHeight) / (2 * depth));
2212
+ return pixelSize * 2 * depth / Math.max(1, viewportHeight) / projectionY;
2213
+ }
2214
+ const cappedPointSize = clampPointSpriteSize(pointSize);
2215
+ if (camera?.isPerspectiveCamera !== true) {
2216
+ return cappedPointSize * 2 / Math.max(1, viewportHeight) / projectionY;
2217
+ }
2218
+ const viewZ = camera ? viewSpaceZ(worldPosition, camera) : -1;
2219
+ const depth = Number.isFinite(viewZ) ? Math.max(0.0001, Math.abs(viewZ)) : 1;
2220
+ return cappedPointSize * 2 * depth / Math.max(1, viewportHeight) / projectionY;
2221
+ }
2222
+ function clampPointSpriteSize(pixelSize) {
2223
+ return Math.min(pixelSize, MAX_POINT_SPRITE_SIZE);
2224
+ }
2225
+ function finiteOrDefault(value, fallback) {
2226
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
2227
+ }
2228
+ function safePositiveNumber(value, fallback) {
2229
+ return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;
2230
+ }
2231
+ function finiteMaterialOrObjectNumber(value, label, fallback) {
2232
+ if (value == null)
2233
+ return fallback;
2234
+ if (typeof value === 'number' && Number.isFinite(value))
2235
+ return value;
2236
+ throw new TypeError(`${label} must be a finite number.`);
2237
+ }
2238
+ function renderOrderNumber(value, label, fallback) {
2239
+ if (value == null)
2240
+ return fallback;
2241
+ if (typeof value === 'number' && (Number.isFinite(value) || value === Infinity || value === -Infinity)) {
2242
+ return value;
2243
+ }
2244
+ throw new TypeError(`${label} must be a finite number or +/-Infinity.`);
2245
+ }
2246
+ function nativeRenderOrderKey(value) {
2247
+ if (value === Infinity)
2248
+ return NativeRenderOrderLimit;
2249
+ if (value === -Infinity)
2250
+ return -NativeRenderOrderLimit;
2251
+ return value;
2252
+ }
2253
+ function nonNegativeMaterialOrObjectNumber(value, label, fallback) {
2254
+ const number = finiteMaterialOrObjectNumber(value, label, fallback);
2255
+ if (number < 0) {
2256
+ throw new TypeError(`${label} must be non-negative.`);
2257
+ }
2258
+ return number;
2259
+ }
2260
+ function positiveMaterialOrObjectNumber(value, label, fallback) {
2261
+ const number = finiteMaterialOrObjectNumber(value, label, fallback);
2262
+ if (number <= 0) {
2263
+ throw new TypeError(`${label} must be positive.`);
2264
+ }
2265
+ return number;
2266
+ }
2267
+ function validateLineMaterialCompatibilityHints(material) {
2268
+ if (!material)
2269
+ return;
2270
+ optionalLineCap(material.linecap);
2271
+ optionalLineJoin(material.linejoin);
2272
+ }
2273
+ function optionalLineCap(value) {
2274
+ if (value == null)
2275
+ return;
2276
+ if (typeof value !== 'string') {
2277
+ throw new TypeError('material.linecap must be a string.');
2278
+ }
2279
+ if (value !== 'butt' && value !== 'round' && value !== 'square') {
2280
+ throw new Error(`material.linecap ${JSON.stringify(value)} is not supported by @headless-three/renderer. Use "butt", "round", "square", null, or undefined.`);
2281
+ }
2282
+ }
2283
+ function optionalLineJoin(value) {
2284
+ if (value == null)
2285
+ return;
2286
+ if (typeof value !== 'string') {
2287
+ throw new TypeError('material.linejoin must be a string.');
2288
+ }
2289
+ if (value !== 'round' && value !== 'bevel' && value !== 'miter') {
2290
+ throw new Error(`material.linejoin ${JSON.stringify(value)} is not supported by @headless-three/renderer. Use "round", "bevel", "miter", null, or undefined.`);
2291
+ }
2292
+ }
2293
+ function normalizedMaterialOrObjectNumber(value, label, fallback) {
2294
+ const number = finiteMaterialOrObjectNumber(value, label, fallback);
2295
+ if (number < 0 || number > 1) {
2296
+ throw new TypeError(`${label} must be between 0 and 1.`);
2297
+ }
2298
+ return number;
2299
+ }
2300
+ function cameraZoomOrDefault(value) {
2301
+ if (value == null)
2302
+ return 1;
2303
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
2304
+ throw new TypeError('camera.zoom must be a finite number.');
2305
+ }
2306
+ if (value <= 0) {
2307
+ throw new TypeError('camera.zoom must be positive.');
2308
+ }
2309
+ return value;
2310
+ }
2311
+ function finiteCountOrDefault(value, label, fallback, allowInfinity = false) {
2312
+ if (value == null)
2313
+ return fallback;
2314
+ if (allowInfinity && value === Infinity)
2315
+ return value;
2316
+ if (typeof value === 'number' && Number.isFinite(value))
2317
+ return value;
2318
+ throw new TypeError(`${label} must be a finite number.`);
2319
+ }
2320
+ function integerCountOrDefault(value, label, fallback, allowInfinity = false) {
2321
+ const number = finiteCountOrDefault(value, label, fallback, allowInfinity);
2322
+ if (number === Infinity)
2323
+ return number;
2324
+ if (!Number.isInteger(number)) {
2325
+ throw new TypeError(`${label} must be an integer.`);
2326
+ }
2327
+ if (number < 0) {
2328
+ throw new TypeError(`${label} must be non-negative.`);
2329
+ }
2330
+ return number;
2331
+ }
2332
+ function unsignedSortKey(value, fallback) {
2333
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : fallback;
2334
+ }
2335
+ function instancedBufferGeometryCount(geometry) {
2336
+ const attributes = Object.entries((0, attributes_1.geometryAttributes)(geometry));
2337
+ const instancedAttributes = attributes.filter((entry) => isInstancedAttribute(entry[1]));
2338
+ if (geometry.isInstancedBufferGeometry !== true && instancedAttributes.length === 0)
2339
+ return 1;
2340
+ let maxCount = Infinity;
2341
+ for (const [name, attribute] of instancedAttributes) {
2342
+ const label = `geometry.attributes.${name}`;
2343
+ maxCount = Math.min(maxCount, (0, attributes_1.attributeCount)(attribute, label) * meshPerAttribute(attribute, `${label}.meshPerAttribute`));
2344
+ }
2345
+ const requested = integerCountOrDefault(geometry.instanceCount, 'geometry.instanceCount', Infinity, true);
2346
+ const effectiveCount = Math.min(requested, maxCount);
2347
+ if (effectiveCount === Infinity)
2348
+ return 1;
2349
+ return (0, math_1.clampInteger)(effectiveCount, 0, Math.max(0, Math.floor(maxCount)));
2350
+ }
2351
+ function assertSupportedCustomFragmentInstancedAttributes(geometry, pbrProps) {
2352
+ if (!pbrProps.customFragmentShader)
2353
+ return;
2354
+ const unsupported = [];
2355
+ for (const [name, attribute] of Object.entries((0, attributes_1.geometryAttributes)(geometry))) {
2356
+ if (!isInstancedAttribute(attribute))
2357
+ continue;
2358
+ if (!SupportedInstancedBufferGeometryAttributes.has(name))
2359
+ unsupported.push(`geometry.attributes.${name}`);
2360
+ }
2361
+ if (unsupported.length === 0)
2362
+ return;
2363
+ throw new Error(`Custom WGSL fragment materials cannot bind arbitrary InstancedBufferGeometry vertex attributes (${unsupported.join(', ')}) in @headless-three/renderer yet. Use supported instanced offset, color, normal, or UV attributes, expand the geometry on the CPU, or render separate draws until custom vertex-attribute shader integration is implemented.`);
2364
+ }
2365
+ function isInstancedAttribute(attribute) {
2366
+ return attribute?.isInstancedBufferAttribute === true;
2367
+ }
2368
+ function meshPerAttribute(attribute, label = 'InstancedBufferAttribute.meshPerAttribute') {
2369
+ const value = attribute.meshPerAttribute;
2370
+ if (value == null)
2371
+ return 1;
2372
+ if (typeof value === 'number' && Number.isFinite(value)) {
2373
+ if (value <= 0) {
2374
+ throw new TypeError(`${label} must be a positive finite number.`);
2375
+ }
2376
+ if (!Number.isInteger(value)) {
2377
+ throw new TypeError(`${label} must be a positive integer.`);
2378
+ }
2379
+ return value;
2380
+ }
2381
+ throw new TypeError(`${label} must be a positive finite number.`);
2382
+ }
2383
+ function instancedAttributeIndex(attribute, instanceIndex, label = 'InstancedBufferAttribute') {
2384
+ return Math.min((0, attributes_1.attributeCount)(attribute, label) - 1, Math.floor(instanceIndex / meshPerAttribute(attribute, `${label}.meshPerAttribute`)));
2385
+ }
2386
+ function instancedOffsetAttribute(geometry) {
2387
+ const names = ['instanceOffset', 'instancePosition', 'offset', 'translate', 'translation'];
2388
+ for (const name of names) {
2389
+ const attribute = (0, attributes_1.getAttribute)(geometry, name);
2390
+ if (isInstancedAttribute(attribute))
2391
+ return { attribute, label: `geometry.attributes.${name}` };
2392
+ }
2393
+ return null;
2394
+ }
2395
+ function instancedScaleAttribute(geometry) {
2396
+ const names = ['instanceScale', 'scale'];
2397
+ for (const name of names) {
2398
+ const attribute = (0, attributes_1.getAttribute)(geometry, name);
2399
+ if (isInstancedAttribute(attribute))
2400
+ return { attribute, label: `geometry.attributes.${name}` };
2401
+ }
2402
+ return null;
2403
+ }
2404
+ function expandVec3ValuesForInstances(values, start, count, instanceCount, offsetAttribute, scaleAttribute) {
2405
+ if (instanceCount <= 1 && !offsetAttribute && !scaleAttribute) {
2406
+ return values.slice(start * 3, (start + count) * 3);
2407
+ }
2408
+ const out = new Array(count * instanceCount * 3);
2409
+ let dst = 0;
2410
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2411
+ const offsetIndex = offsetAttribute
2412
+ ? instancedAttributeIndex(offsetAttribute.attribute, instance, offsetAttribute.label)
2413
+ : 0;
2414
+ const ox = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 0, offsetAttribute.label) : 0;
2415
+ const oy = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 1, offsetAttribute.label) : 0;
2416
+ const oz = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 2, offsetAttribute.label) : 0;
2417
+ const scale = instanceScaleComponents(scaleAttribute, instance);
2418
+ for (let vertex = start; vertex < start + count; vertex += 1) {
2419
+ out[dst++] = values[vertex * 3] * scale[0] + ox;
2420
+ out[dst++] = values[vertex * 3 + 1] * scale[1] + oy;
2421
+ out[dst++] = values[vertex * 3 + 2] * scale[2] + oz;
2422
+ }
2423
+ }
2424
+ return out;
2425
+ }
2426
+ function expandVec3ValuesForInstancesWithCache(cache, geometry, position, values, start, count, instanceCount, offsetAttribute, scaleAttribute) {
2427
+ if (!cache) {
2428
+ return expandVec3ValuesForInstances(values, start, count, instanceCount, offsetAttribute, scaleAttribute);
2429
+ }
2430
+ const signature = instancedPositionExpansionSignature(geometry, position, values, start, count, instanceCount, offsetAttribute, scaleAttribute);
2431
+ if (!signature.cacheable) {
2432
+ return expandVec3ValuesForInstances(values, start, count, instanceCount, offsetAttribute, scaleAttribute);
2433
+ }
2434
+ const key = `${start}:${count}:${instanceCount}`;
2435
+ let geometryCache = cache.instancedPositionExpansions.get(geometry);
2436
+ const cached = geometryCache?.get(key);
2437
+ if (cached && sameInstancedPositionExpansionSignature(cached.signature, signature)) {
2438
+ return cached.positions;
2439
+ }
2440
+ const positions = expandVec3ValuesForInstances(values, start, count, instanceCount, offsetAttribute, scaleAttribute);
2441
+ if (!geometryCache) {
2442
+ geometryCache = new Map();
2443
+ cache.instancedPositionExpansions.set(geometry, geometryCache);
2444
+ }
2445
+ geometryCache.set(key, { signature, positions });
2446
+ return positions;
2447
+ }
2448
+ function instancedPositionExpansionSignature(geometry, position, values, start, count, instanceCount, offsetAttribute, scaleAttribute) {
2449
+ const signature = {
2450
+ cacheable: true,
2451
+ geometryVersion: geometry.version,
2452
+ sourcePositions: values,
2453
+ start,
2454
+ count,
2455
+ instanceCount,
2456
+ position: attributeSignature(position),
2457
+ instancedPositionOffset: attributeSignature(offsetAttribute?.attribute),
2458
+ instancedPositionScale: attributeSignature(scaleAttribute?.attribute),
2459
+ };
2460
+ signature.cacheable = attributeSignatureCacheable(signature.position)
2461
+ && attributeSignatureCacheable(signature.instancedPositionOffset)
2462
+ && attributeSignatureCacheable(signature.instancedPositionScale);
2463
+ return signature;
2464
+ }
2465
+ function sameInstancedPositionExpansionSignature(a, b) {
2466
+ return a.cacheable === b.cacheable
2467
+ && a.geometryVersion === b.geometryVersion
2468
+ && a.sourcePositions === b.sourcePositions
2469
+ && a.start === b.start
2470
+ && a.count === b.count
2471
+ && a.instanceCount === b.instanceCount
2472
+ && sameAttributeSignature(a.position, b.position)
2473
+ && sameAttributeSignature(a.instancedPositionOffset, b.instancedPositionOffset)
2474
+ && sameAttributeSignature(a.instancedPositionScale, b.instancedPositionScale);
2475
+ }
2476
+ function instanceScaleComponents(scaleAttribute, instance) {
2477
+ if (!scaleAttribute)
2478
+ return [1, 1, 1];
2479
+ const sourceIndex = instancedAttributeIndex(scaleAttribute.attribute, instance, scaleAttribute.label);
2480
+ const itemSize = scaleAttribute.attribute.itemSize ?? 1;
2481
+ const sx = (0, attributes_1.attributeComponent)(scaleAttribute.attribute, sourceIndex, 0, scaleAttribute.label);
2482
+ const sy = itemSize >= 2
2483
+ ? (0, attributes_1.attributeComponent)(scaleAttribute.attribute, sourceIndex, 1, scaleAttribute.label)
2484
+ : sx;
2485
+ const sz = itemSize >= 3
2486
+ ? (0, attributes_1.attributeComponent)(scaleAttribute.attribute, sourceIndex, 2, scaleAttribute.label)
2487
+ : sx;
2488
+ return [sx, sy, sz];
2489
+ }
2490
+ function expandVec2ValuesForInstances(values, start, count, instanceCount) {
2491
+ if (instanceCount <= 1)
2492
+ return values.slice(start * 2, (start + count) * 2);
2493
+ const out = new Array(count * instanceCount * 2);
2494
+ let dst = 0;
2495
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2496
+ for (let vertex = start; vertex < start + count; vertex += 1) {
2497
+ out[dst++] = values[vertex * 2];
2498
+ out[dst++] = values[vertex * 2 + 1];
2499
+ }
2500
+ }
2501
+ return out;
2502
+ }
2503
+ function expandNormalValuesForInstances(attribute, values, start, count, instanceCount, label = 'geometry.attributes.normal') {
2504
+ if (!isInstancedAttribute(attribute)) {
2505
+ return expandVec3ValuesForInstances(values, start, count, instanceCount);
2506
+ }
2507
+ const out = new Array(count * instanceCount * 3);
2508
+ let dst = 0;
2509
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2510
+ const sourceIndex = instancedAttributeIndex(attribute, instance, label);
2511
+ const nx = (0, attributes_1.attributeComponent)(attribute, sourceIndex, 0, label);
2512
+ const ny = (0, attributes_1.attributeComponent)(attribute, sourceIndex, 1, label);
2513
+ const nz = (0, attributes_1.attributeComponent)(attribute, sourceIndex, 2, label);
2514
+ for (let vertex = 0; vertex < count; vertex += 1) {
2515
+ out[dst++] = nx;
2516
+ out[dst++] = ny;
2517
+ out[dst++] = nz;
2518
+ }
2519
+ }
2520
+ return out;
2521
+ }
2522
+ function expandNormalValuesForInstancesWithCache(cache, geometry, attribute, values, start, count, instanceCount, label = 'geometry.attributes.normal') {
2523
+ if (!cache) {
2524
+ return expandNormalValuesForInstances(attribute, values, start, count, instanceCount, label);
2525
+ }
2526
+ const signature = instancedNormalExpansionSignature(geometry, attribute, values, start, count, instanceCount, label);
2527
+ if (!signature.cacheable) {
2528
+ return expandNormalValuesForInstances(attribute, values, start, count, instanceCount, label);
2529
+ }
2530
+ const key = `${label}:${start}:${count}:${instanceCount}`;
2531
+ let geometryCache = cache.instancedNormalExpansions.get(geometry);
2532
+ const cached = geometryCache?.get(key);
2533
+ if (cached && sameInstancedNormalExpansionSignature(cached.signature, signature)) {
2534
+ return cached.normals;
2535
+ }
2536
+ const normals = expandNormalValuesForInstances(attribute, values, start, count, instanceCount, label);
2537
+ if (!geometryCache) {
2538
+ geometryCache = new Map();
2539
+ cache.instancedNormalExpansions.set(geometry, geometryCache);
2540
+ }
2541
+ geometryCache.set(key, { signature, normals });
2542
+ return normals;
2543
+ }
2544
+ function instancedNormalExpansionSignature(geometry, attribute, values, start, count, instanceCount, label) {
2545
+ const signature = {
2546
+ cacheable: true,
2547
+ geometryVersion: geometry.version,
2548
+ sourceNormals: values,
2549
+ start,
2550
+ count,
2551
+ instanceCount,
2552
+ normal: attributeSignature(attribute),
2553
+ label,
2554
+ };
2555
+ signature.cacheable = attributeSignatureCacheable(signature.normal);
2556
+ return signature;
2557
+ }
2558
+ function sameInstancedNormalExpansionSignature(a, b) {
2559
+ return a.cacheable === b.cacheable
2560
+ && a.geometryVersion === b.geometryVersion
2561
+ && a.sourceNormals === b.sourceNormals
2562
+ && a.start === b.start
2563
+ && a.count === b.count
2564
+ && a.instanceCount === b.instanceCount
2565
+ && sameAttributeSignature(a.normal, b.normal)
2566
+ && a.label === b.label;
2567
+ }
2568
+ function expandUvChannelForInstances(channel, start, count, instanceCount) {
2569
+ if (!isInstancedAttribute(channel.attribute)) {
2570
+ return expandVec2ValuesForInstances(channel.values, start, count, instanceCount);
2571
+ }
2572
+ const out = new Array(count * instanceCount * 2);
2573
+ let dst = 0;
2574
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2575
+ const sourceIndex = instancedAttributeIndex(channel.attribute, instance, labelForMeshPerAttribute(channel));
2576
+ const u = (0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 0, channel.label);
2577
+ const v = (0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 1, channel.label);
2578
+ for (let vertex = 0; vertex < count; vertex += 1) {
2579
+ out[dst++] = u;
2580
+ out[dst++] = v;
2581
+ }
2582
+ }
2583
+ return out;
2584
+ }
2585
+ function expandUvChannelForInstancesWithCache(cache, geometry, channel, start, count, instanceCount) {
2586
+ if (!cache) {
2587
+ return expandUvChannelForInstances(channel, start, count, instanceCount);
2588
+ }
2589
+ const signature = instancedUvExpansionSignature(geometry, channel, start, count, instanceCount);
2590
+ if (!signature.cacheable) {
2591
+ return expandUvChannelForInstances(channel, start, count, instanceCount);
2592
+ }
2593
+ const key = `${channel.label}:${start}:${count}:${instanceCount}`;
2594
+ let geometryCache = cache.instancedUvExpansions.get(geometry);
2595
+ const cached = geometryCache?.get(key);
2596
+ if (cached && sameInstancedUvExpansionSignature(cached.signature, signature)) {
2597
+ return cached.uvs;
2598
+ }
2599
+ const uvs = expandUvChannelForInstances(channel, start, count, instanceCount);
2600
+ if (!geometryCache) {
2601
+ geometryCache = new Map();
2602
+ cache.instancedUvExpansions.set(geometry, geometryCache);
2603
+ }
2604
+ geometryCache.set(key, { signature, uvs });
2605
+ return uvs;
2606
+ }
2607
+ function instancedUvExpansionSignature(geometry, channel, start, count, instanceCount) {
2608
+ const signature = {
2609
+ cacheable: true,
2610
+ geometryVersion: geometry.version,
2611
+ channel: uvChannelSignature(channel),
2612
+ start,
2613
+ count,
2614
+ instanceCount,
2615
+ };
2616
+ signature.cacheable = attributeSignatureCacheable(signature.channel.attribute);
2617
+ return signature;
2618
+ }
2619
+ function sameInstancedUvExpansionSignature(a, b) {
2620
+ return a.cacheable === b.cacheable
2621
+ && a.geometryVersion === b.geometryVersion
2622
+ && sameUvChannelSignature(a.channel, b.channel)
2623
+ && a.start === b.start
2624
+ && a.count === b.count
2625
+ && a.instanceCount === b.instanceCount;
2626
+ }
2627
+ function appendUvForVertex(out, channel, vertexIndex, instanceIndex) {
2628
+ const sourceIndex = isInstancedAttribute(channel.attribute)
2629
+ ? instancedAttributeIndex(channel.attribute, instanceIndex, labelForMeshPerAttribute(channel))
2630
+ : vertexIndex;
2631
+ out.push((0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 0, channel.label), (0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 1, channel.label));
2632
+ }
2633
+ function uvValuesForInstance(channel, vertexCount, instanceIndex) {
2634
+ if (!channel)
2635
+ return null;
2636
+ if (!isInstancedAttribute(channel.attribute))
2637
+ return channel.values;
2638
+ const out = new Array(vertexCount * 2);
2639
+ let dst = 0;
2640
+ const sourceIndex = instancedAttributeIndex(channel.attribute, instanceIndex, labelForMeshPerAttribute(channel));
2641
+ const u = (0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 0, channel.label);
2642
+ const v = (0, attributes_1.attributeComponent)(channel.attribute, sourceIndex, 1, channel.label);
2643
+ for (let vertex = 0; vertex < vertexCount; vertex += 1) {
2644
+ out[dst++] = u;
2645
+ out[dst++] = v;
2646
+ }
2647
+ return out;
2648
+ }
2649
+ function labelForMeshPerAttribute(channel) {
2650
+ return `${channel.label}.meshPerAttribute`;
2651
+ }
2652
+ function expandColorAttributeForInstances(attribute, materialColor, start, count, instanceCount, label = 'geometry.attributes.color') {
2653
+ if (!isInstancedAttribute(attribute)) {
2654
+ const colors = (0, attributes_1.readColorAttribute)(attribute, materialColor, label);
2655
+ if (instanceCount <= 1)
2656
+ return colors.slice(start * 4, (start + count) * 4);
2657
+ const out = new Array(count * instanceCount * 4);
2658
+ let dst = 0;
2659
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2660
+ for (let vertex = start; vertex < start + count; vertex += 1) {
2661
+ out[dst++] = colors[vertex * 4];
2662
+ out[dst++] = colors[vertex * 4 + 1];
2663
+ out[dst++] = colors[vertex * 4 + 2];
2664
+ out[dst++] = colors[vertex * 4 + 3];
2665
+ }
2666
+ }
2667
+ return out;
2668
+ }
2669
+ const itemSize = attribute.itemSize ?? 3;
2670
+ const out = new Array(count * instanceCount * 4);
2671
+ let dst = 0;
2672
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2673
+ const sourceIndex = instancedAttributeIndex(attribute, instance, label);
2674
+ const r = (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 0, label) * materialColor[0]);
2675
+ const g = (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 1, label) * materialColor[1]);
2676
+ const b = (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 2, label) * materialColor[2]);
2677
+ const a = (0, math_1.clamp01)((itemSize >= 4 ? (0, attributes_1.attributeComponent)(attribute, sourceIndex, 3, label) : 1) * materialColor[3]);
2678
+ for (let vertex = 0; vertex < count; vertex += 1) {
2679
+ out[dst++] = r;
2680
+ out[dst++] = g;
2681
+ out[dst++] = b;
2682
+ out[dst++] = a;
2683
+ }
2684
+ }
2685
+ return out;
2686
+ }
2687
+ function expandColorAttributeForInstancesWithCache(cache, geometry, attribute, materialColor, start, count, instanceCount, label = 'geometry.attributes.color') {
2688
+ if (!cache) {
2689
+ return expandColorAttributeForInstances(attribute, materialColor, start, count, instanceCount, label);
2690
+ }
2691
+ const signature = instancedColorExpansionSignature(geometry, attribute, materialColor, start, count, instanceCount, label);
2692
+ if (!signature.cacheable) {
2693
+ return expandColorAttributeForInstances(attribute, materialColor, start, count, instanceCount, label);
2694
+ }
2695
+ const key = `${label}:${start}:${count}:${instanceCount}`;
2696
+ let geometryCache = cache.instancedColorExpansions.get(geometry);
2697
+ const cached = geometryCache?.get(key);
2698
+ if (cached && sameInstancedColorExpansionSignature(cached.signature, signature)) {
2699
+ return cached.colors;
2700
+ }
2701
+ const colors = expandColorAttributeForInstances(attribute, materialColor, start, count, instanceCount, label);
2702
+ if (!geometryCache) {
2703
+ geometryCache = new Map();
2704
+ cache.instancedColorExpansions.set(geometry, geometryCache);
2705
+ }
2706
+ geometryCache.set(key, { signature, colors });
2707
+ return colors;
2708
+ }
2709
+ function instancedColorExpansionSignature(geometry, attribute, materialColor, start, count, instanceCount, label) {
2710
+ const signature = {
2711
+ cacheable: true,
2712
+ geometryVersion: geometry.version,
2713
+ materialColor: materialColor.slice(),
2714
+ start,
2715
+ count,
2716
+ instanceCount,
2717
+ color: attributeSignature(attribute),
2718
+ label,
2719
+ };
2720
+ signature.cacheable = attributeSignatureCacheable(signature.color);
2721
+ return signature;
2722
+ }
2723
+ function sameInstancedColorExpansionSignature(a, b) {
2724
+ return a.cacheable === b.cacheable
2725
+ && a.geometryVersion === b.geometryVersion
2726
+ && sameNumberArray(a.materialColor, b.materialColor)
2727
+ && a.start === b.start
2728
+ && a.count === b.count
2729
+ && a.instanceCount === b.instanceCount
2730
+ && sameAttributeSignature(a.color, b.color)
2731
+ && a.label === b.label;
2732
+ }
2733
+ function indexRangeWithCache(cache, geometry, indices, start, count) {
2734
+ if (!cache)
2735
+ return indices.slice(start, start + count);
2736
+ const signature = indexRangeExpansionSignature(geometry, indices, start, count);
2737
+ if (!signature.cacheable)
2738
+ return indices.slice(start, start + count);
2739
+ const key = `${start}:${count}`;
2740
+ let geometryCache = cache.indexRanges.get(geometry);
2741
+ const cached = geometryCache?.get(key);
2742
+ if (cached && sameIndexRangeExpansionSignature(cached.signature, signature)) {
2743
+ return cached.indices;
2744
+ }
2745
+ const range = indices.slice(start, start + count);
2746
+ if (!geometryCache) {
2747
+ geometryCache = new Map();
2748
+ cache.indexRanges.set(geometry, geometryCache);
2749
+ }
2750
+ geometryCache.set(key, { signature, indices: range });
2751
+ return range;
2752
+ }
2753
+ function indexRangeExpansionSignature(geometry, indices, start, count) {
2754
+ const signature = {
2755
+ cacheable: true,
2756
+ geometryVersion: geometry.version,
2757
+ sourceIndices: indices,
2758
+ start,
2759
+ count,
2760
+ index: attributeSignature(geometry.index),
2761
+ };
2762
+ signature.cacheable = attributeSignatureCacheable(signature.index);
2763
+ return signature;
2764
+ }
2765
+ function sameIndexRangeExpansionSignature(a, b) {
2766
+ return a.cacheable === b.cacheable
2767
+ && a.geometryVersion === b.geometryVersion
2768
+ && a.sourceIndices === b.sourceIndices
2769
+ && a.start === b.start
2770
+ && a.count === b.count
2771
+ && sameAttributeSignature(a.index, b.index);
2772
+ }
2773
+ function expandIndicesForInstances(indices, vertexCount, instanceCount) {
2774
+ if (instanceCount <= 1)
2775
+ return indices;
2776
+ const out = new Array(indices.length * instanceCount);
2777
+ let dst = 0;
2778
+ for (let instance = 0; instance < instanceCount; instance += 1) {
2779
+ const offset = instance * vertexCount;
2780
+ for (const index of indices) {
2781
+ out[dst++] = index + offset;
2782
+ }
2783
+ }
2784
+ return out;
2785
+ }
2786
+ function wireframeIndicesForTriangles(indices) {
2787
+ const out = new Array(indices.length * 2);
2788
+ let dst = 0;
2789
+ for (let i = 0; i < indices.length; i += 3) {
2790
+ const a = indices[i];
2791
+ const b = indices[i + 1];
2792
+ const c = indices[i + 2];
2793
+ out[dst++] = a;
2794
+ out[dst++] = b;
2795
+ out[dst++] = b;
2796
+ out[dst++] = c;
2797
+ out[dst++] = c;
2798
+ out[dst++] = a;
2799
+ }
2800
+ return out;
2801
+ }
2802
+ function wireframeIndicesForUnindexedTriangles(vertexCount) {
2803
+ const out = new Array(vertexCount * 2);
2804
+ let dst = 0;
2805
+ for (let i = 0; i < vertexCount; i += 3) {
2806
+ out[dst++] = i;
2807
+ out[dst++] = i + 1;
2808
+ out[dst++] = i + 1;
2809
+ out[dst++] = i + 2;
2810
+ out[dst++] = i + 2;
2811
+ out[dst++] = i;
2812
+ }
2813
+ return out;
2814
+ }
2815
+ function isDepthDistanceWireframeMaterial(material) {
2816
+ return material?.wireframe === true
2817
+ && (material.isMeshDepthMaterial === true || material.isMeshDistanceMaterial === true);
2818
+ }
2819
+ function isMeshWireframeMaterial(material) {
2820
+ return material?.wireframe === true;
2821
+ }
2822
+ function readUvChannels(geometry) {
2823
+ const primaryUvs = readOptionalUvAttribute(geometry, 'uv');
2824
+ return [
2825
+ primaryUvs,
2826
+ readOptionalUvAttribute(geometry, 'uv1') ?? readOptionalUvAttribute(geometry, 'uv2') ?? primaryUvs,
2827
+ readOptionalUvAttribute(geometry, 'uv2') ?? readOptionalUvAttribute(geometry, 'uv1') ?? primaryUvs,
2828
+ readOptionalUvAttribute(geometry, 'uv3') ?? primaryUvs,
2829
+ ];
2830
+ }
2831
+ function readOptionalUvAttribute(geometry, name) {
2832
+ const attribute = (0, attributes_1.getAttribute)(geometry, name);
2833
+ if (!attribute)
2834
+ return null;
2835
+ const label = `geometry.attributes.${name}`;
2836
+ return {
2837
+ attribute,
2838
+ label,
2839
+ values: (0, attributes_1.readVec2Attribute)(attribute, label),
2840
+ };
2841
+ }
2842
+ function textureUvStreamsForMapAlphaMaterial(channels, material) {
2843
+ const mapChannel = material?.map ? (0, materials_1.textureUvChannel)(material.map) : undefined;
2844
+ const alphaChannel = material?.alphaMap ? (0, materials_1.textureUvChannel)(material.alphaMap) : undefined;
2845
+ const requestedChannels = [mapChannel, alphaChannel]
2846
+ .filter((channel) => channel !== undefined);
2847
+ const distinctChannels = [...new Set(requestedChannels)];
2848
+ let primaryChannel = 0;
2849
+ let secondaryChannel;
2850
+ if (mapChannel !== undefined
2851
+ && alphaChannel !== undefined
2852
+ && mapChannel !== alphaChannel
2853
+ && mapChannel > 0
2854
+ && alphaChannel > 0) {
2855
+ primaryChannel = mapChannel;
2856
+ secondaryChannel = alphaChannel;
2857
+ }
2858
+ else {
2859
+ secondaryChannel = distinctChannels.find((channel) => channel > 0);
2860
+ }
2861
+ return {
2862
+ uvs: channels[primaryChannel] ?? channels[0],
2863
+ uvs2: secondaryChannel !== undefined
2864
+ ? channels[secondaryChannel] ?? channels[0]
2865
+ : null,
2866
+ textureUsesUv2: mapChannel !== undefined ? mapChannel !== primaryChannel : undefined,
2867
+ alphaMapUsesUv2: alphaChannel !== undefined ? alphaChannel !== primaryChannel : undefined,
2868
+ };
2869
+ }
2870
+ function textureUvStreamsForMeshMaterial(channels, material) {
2871
+ return textureUvStreamsForMaterialSlots(channels, meshTextureUvSlots(material));
2872
+ }
2873
+ function meshTextureUvSlots(material) {
2874
+ if (!material)
2875
+ return [];
2876
+ const slots = material.isMeshMatcapMaterial === true
2877
+ ? [{ texture: material.map, pbrFlag: 'matcapMapUsesUv2' }]
2878
+ : [{ texture: material.map, textureFlag: 'textureUsesUv2' }];
2879
+ slots.push({ texture: material.clearcoatMap, pbrFlag: 'clearcoatMapUsesUv2' }, { texture: material.clearcoatRoughnessMap, pbrFlag: 'clearcoatRoughnessMapUsesUv2' }, { texture: material.clearcoatNormalMap, pbrFlag: 'clearcoatNormalMapUsesUv2' }, { texture: material.sheenColorMap, pbrFlag: 'sheenColorMapUsesUv2' }, { texture: material.sheenRoughnessMap, pbrFlag: 'sheenRoughnessMapUsesUv2' }, { texture: material.anisotropyMap, pbrFlag: 'anisotropyMapUsesUv2' }, { texture: material.iridescenceMap, pbrFlag: 'iridescenceMapUsesUv2' }, { texture: material.iridescenceThicknessMap, pbrFlag: 'iridescenceThicknessMapUsesUv2' }, { texture: material.normalMap, pbrFlag: 'normalMapUsesUv2' }, { texture: material.bumpMap, pbrFlag: 'bumpMapUsesUv2' }, { texture: material.transmissionMap, pbrFlag: 'transmissionMapUsesUv2' }, { texture: material.thicknessMap, pbrFlag: 'thicknessMapUsesUv2' }, { texture: material.specularColorMap, pbrFlag: 'specularColorMapUsesUv2' }, { texture: material.specularIntensityMap, pbrFlag: 'specularIntensityMapUsesUv2' }, { texture: material.displacementMap, pbrFlag: 'displacementMapUsesUv2' }, { texture: material.metalnessMap ?? material.roughnessMap, pbrFlag: 'metallicRoughnessTextureUsesUv2' }, { texture: material.emissiveMap, pbrFlag: 'emissiveMapUsesUv2' }, { texture: material.lightMap, pbrFlag: 'lightMapUsesUv2' }, { texture: material.aoMap, pbrFlag: 'aoMapUsesUv2' }, { texture: material.specularMap, pbrFlag: 'specularMapUsesUv2' }, { texture: material.alphaMap, textureFlag: 'alphaMapUsesUv2' });
2880
+ return slots;
2881
+ }
2882
+ function textureUvStreamsForMaterialSlots(channels, slots) {
2883
+ const activeSlots = slots.filter((slot) => slot.texture != null);
2884
+ const requestedChannels = [];
2885
+ for (const slot of activeSlots) {
2886
+ const channel = (0, materials_1.textureUvChannel)(slot.texture);
2887
+ if (!requestedChannels.includes(channel))
2888
+ requestedChannels.push(channel);
2889
+ }
2890
+ if (requestedChannels.length > 2) {
2891
+ const channelList = [...requestedChannels].sort((a, b) => a - b).join(', ');
2892
+ throw new Error(`Material uses texture.channel values ${channelList}, but @headless-three/renderer can bind only two UV attributes per draw. Use at most two texture channels or render separate passes.`);
2893
+ }
2894
+ const preferredPrimary = preferredPrimaryTextureChannel(activeSlots);
2895
+ const primaryChannel = requestedChannels.includes(0)
2896
+ ? 0
2897
+ : preferredPrimary !== undefined && requestedChannels.includes(preferredPrimary)
2898
+ ? preferredPrimary
2899
+ : requestedChannels[0] ?? 0;
2900
+ const secondaryChannel = requestedChannels.find((channel) => channel !== primaryChannel);
2901
+ const out = {
2902
+ uvs: channels[primaryChannel] ?? channels[0],
2903
+ uvs2: secondaryChannel !== undefined
2904
+ ? channels[secondaryChannel] ?? channels[0]
2905
+ : null,
2906
+ };
2907
+ for (const slot of activeSlots) {
2908
+ const usesUv2 = secondaryChannel !== undefined
2909
+ && (0, materials_1.textureUvChannel)(slot.texture) === secondaryChannel;
2910
+ if (slot.textureFlag === 'textureUsesUv2') {
2911
+ out.textureUsesUv2 = usesUv2;
2912
+ }
2913
+ else if (slot.textureFlag === 'alphaMapUsesUv2') {
2914
+ out.alphaMapUsesUv2 = usesUv2;
2915
+ }
2916
+ else if (slot.pbrFlag) {
2917
+ out.pbrUsesUv2 ?? (out.pbrUsesUv2 = {});
2918
+ out.pbrUsesUv2[slot.pbrFlag] = usesUv2;
2919
+ }
2920
+ }
2921
+ return out;
2922
+ }
2923
+ function preferredPrimaryTextureChannel(slots) {
2924
+ for (const flag of ['textureUsesUv2', 'alphaMapUsesUv2']) {
2925
+ const slot = slots.find((candidate) => candidate.textureFlag === flag);
2926
+ if (slot?.texture != null)
2927
+ return (0, materials_1.textureUvChannel)(slot.texture);
2928
+ }
2929
+ return slots[0]?.texture ? (0, materials_1.textureUvChannel)(slots[0].texture) : undefined;
2930
+ }
2931
+ function applyPbrUvStreamFlags(props, uvStreams) {
2932
+ if (!uvStreams.pbrUsesUv2)
2933
+ return;
2934
+ for (const [flag, usesUv2] of Object.entries(uvStreams.pbrUsesUv2)) {
2935
+ props[flag] = usesUv2;
2936
+ }
2937
+ }
2938
+ function secondaryUvsForMaterial(channels, material) {
2939
+ const textures = [
2940
+ material?.clearcoatMap,
2941
+ material?.clearcoatRoughnessMap,
2942
+ material?.clearcoatNormalMap,
2943
+ material?.sheenColorMap,
2944
+ material?.sheenRoughnessMap,
2945
+ material?.anisotropyMap,
2946
+ material?.iridescenceMap,
2947
+ material?.iridescenceThicknessMap,
2948
+ material?.normalMap,
2949
+ material?.bumpMap,
2950
+ material?.transmissionMap,
2951
+ material?.thicknessMap,
2952
+ material?.specularColorMap,
2953
+ material?.specularIntensityMap,
2954
+ material?.displacementMap,
2955
+ material?.map,
2956
+ material?.metalnessMap,
2957
+ material?.roughnessMap,
2958
+ material?.emissiveMap,
2959
+ material?.lightMap,
2960
+ material?.aoMap,
2961
+ material?.specularMap,
2962
+ material?.alphaMap,
2963
+ ];
2964
+ let channel = 0;
2965
+ for (const texture of textures) {
2966
+ const textureChannel = (0, materials_1.textureUvChannel)(texture);
2967
+ if (textureChannel === 0)
2968
+ continue;
2969
+ if (channel === 0) {
2970
+ channel = textureChannel;
2971
+ continue;
2972
+ }
2973
+ if (channel !== textureChannel) {
2974
+ throw new Error(`Material uses multiple non-primary texture.channel values (${channel} and ${textureChannel}), but @headless-three/renderer can bind one secondary UV attribute per draw. Use one shared non-primary channel or render separate passes.`);
2975
+ }
2976
+ }
2977
+ return channels[channel] ?? channels[0];
2978
+ }
2979
+ function updateLodObject(object, camera) {
2980
+ if (object.isLOD !== true || !camera)
2981
+ return;
2982
+ if (optionalObjectBoolean(object.autoUpdate, 'LOD.autoUpdate') === false)
2983
+ return;
2984
+ const levels = object.levels;
2985
+ const normalizedLevels = normalizeLodLevels(levels);
2986
+ const cameraZoom = cameraZoomOrDefault(camera.zoom);
2987
+ if (typeof object.update === 'function') {
2988
+ object.update(camera);
2989
+ return;
2990
+ }
2991
+ if (normalizedLevels.length <= 1)
2992
+ return;
2993
+ const distance = distanceBetweenMatrices(camera.matrixWorld, object.matrixWorld) / cameraZoom;
2994
+ normalizedLevels[0].object.visible = true;
2995
+ let i = 1;
2996
+ for (; i < normalizedLevels.length; i += 1) {
2997
+ const level = normalizedLevels[i];
2998
+ let levelDistance = level.distance;
2999
+ if (level.object.visible) {
3000
+ levelDistance -= levelDistance * level.hysteresis;
3001
+ }
3002
+ if (distance >= levelDistance) {
3003
+ normalizedLevels[i - 1].object.visible = false;
3004
+ level.object.visible = true;
3005
+ }
3006
+ else {
3007
+ break;
3008
+ }
3009
+ }
3010
+ ;
3011
+ object._currentLevel = i - 1;
3012
+ for (; i < normalizedLevels.length; i += 1) {
3013
+ normalizedLevels[i].object.visible = false;
3014
+ }
3015
+ }
3016
+ function normalizeLodLevels(levels) {
3017
+ if (levels == null)
3018
+ return [];
3019
+ if (!Array.isArray(levels)) {
3020
+ throw new TypeError('LOD.levels must be an array.');
3021
+ }
3022
+ return levels.map((level, index) => {
3023
+ if (!level || typeof level !== 'object' || Array.isArray(level)) {
3024
+ throw new TypeError(`LOD.levels[${index}] must be an object.`);
3025
+ }
3026
+ const object = level.object;
3027
+ if (!object || typeof object !== 'object' || Array.isArray(object)) {
3028
+ throw new TypeError(`LOD.levels[${index}].object must be a THREE.Object3D-like object.`);
3029
+ }
3030
+ return {
3031
+ object: object,
3032
+ distance: nonNegativeMaterialOrObjectNumber(level.distance, `LOD.levels[${index}].distance`, 0),
3033
+ hysteresis: normalizedMaterialOrObjectNumber(level.hysteresis, `LOD.levels[${index}].hysteresis`, 0),
3034
+ };
3035
+ });
3036
+ }
3037
+ function distanceBetweenMatrices(a, b) {
3038
+ const ae = a?.elements;
3039
+ const be = b?.elements;
3040
+ if (!ae || ae.length < 16 || !be || be.length < 16)
3041
+ return 0;
3042
+ const dx = ae[12] - be[12];
3043
+ const dy = ae[13] - be[13];
3044
+ const dz = ae[14] - be[14];
3045
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
3046
+ }
3047
+ function dashedLineAttributes(positions, uvs, uvs2, colors, source, start, end, object, lineDistance, material) {
3048
+ const dashSize = positiveMaterialOrObjectNumber(material.dashSize, 'material.dashSize', 3);
3049
+ const gapSize = nonNegativeMaterialOrObjectNumber(material.gapSize, 'material.gapSize', 1);
3050
+ const scale = nonNegativeMaterialOrObjectNumber(material.scale, 'material.scale', 1);
3051
+ const segments = lineSegmentsWithDistances(positions, source, start, end, object, lineDistance);
3052
+ const out = createDashedLineExpansion(uvs, uvs2, colors);
3053
+ if (!lineDistance || gapSize <= 0 || scale === 0) {
3054
+ for (const segment of segments) {
3055
+ appendInterpolatedLine(out, positions, uvs, uvs2, colors, segment.a, segment.b, 0, 1);
3056
+ }
3057
+ return out;
3058
+ }
3059
+ const totalSize = dashSize + gapSize;
3060
+ for (const segment of segments) {
3061
+ appendDashedSegment(out, positions, uvs, uvs2, colors, segment, scale, dashSize, totalSize);
3062
+ }
3063
+ return out;
3064
+ }
3065
+ function dashedLineAttributesWithCache(cache, geometry, position, positions, uvChannel, uvChannel2, colors, source, start, end, object, lineDistance, material) {
3066
+ const dashSize = positiveMaterialOrObjectNumber(material.dashSize, 'material.dashSize', 3);
3067
+ const gapSize = nonNegativeMaterialOrObjectNumber(material.gapSize, 'material.gapSize', 1);
3068
+ const scale = nonNegativeMaterialOrObjectNumber(material.scale, 'material.scale', 1);
3069
+ const uvs = uvChannel?.values ?? null;
3070
+ const uvs2 = uvChannel2?.values ?? null;
3071
+ if (!cache || colors) {
3072
+ return dashedLineAttributes(positions, uvs, uvs2, colors, source, start, end, object, lineDistance, material);
3073
+ }
3074
+ const signature = dashedLineSignature(geometry, position, uvChannel, uvChannel2, lineDistance, start, end, source.length, object, dashSize, gapSize, scale);
3075
+ if (!signature.cacheable) {
3076
+ return dashedLineAttributes(positions, uvs, uvs2, colors, source, start, end, object, lineDistance, material);
3077
+ }
3078
+ const cacheKey = dashedLineCacheKey(signature);
3079
+ const geometryCache = cache.dashedLines.get(geometry);
3080
+ const cached = geometryCache?.get(cacheKey);
3081
+ if (cached && sameDashedLineSignature(cached.signature, signature)) {
3082
+ return cached.expansion;
3083
+ }
3084
+ const expansion = dashedLineAttributes(positions, uvs, uvs2, colors, source, start, end, object, lineDistance, material);
3085
+ let writableGeometryCache = geometryCache;
3086
+ if (!writableGeometryCache) {
3087
+ writableGeometryCache = new Map();
3088
+ cache.dashedLines.set(geometry, writableGeometryCache);
3089
+ }
3090
+ writableGeometryCache.set(cacheKey, { signature, expansion });
3091
+ return expansion;
3092
+ }
3093
+ function dashedLineSignature(geometry, position, uvChannel, uvChannel2, lineDistance, start, end, sourceLength, object, dashSize, gapSize, scale) {
3094
+ const signature = {
3095
+ cacheable: true,
3096
+ geometryVersion: geometry.version,
3097
+ position: attributeSignature(position),
3098
+ index: attributeSignature(geometry.index),
3099
+ uv: uvChannelSignature(uvChannel),
3100
+ uv2: uvChannelSignature(uvChannel2),
3101
+ lineDistance: attributeSignature(lineDistance),
3102
+ start,
3103
+ end,
3104
+ sourceLength,
3105
+ isLineSegments: object.isLineSegments,
3106
+ isLineLoop: object.isLineLoop,
3107
+ isLine: object.isLine,
3108
+ dashSize,
3109
+ gapSize,
3110
+ scale,
3111
+ };
3112
+ signature.cacheable = dashedLineSignatureCacheable(signature);
3113
+ return signature;
3114
+ }
3115
+ function dashedLineSignatureCacheable(signature) {
3116
+ return attributeSignatureCacheable(signature.position)
3117
+ && attributeSignatureCacheable(signature.index)
3118
+ && attributeSignatureCacheable(signature.uv.attribute)
3119
+ && attributeSignatureCacheable(signature.uv2.attribute)
3120
+ && attributeSignatureCacheable(signature.lineDistance);
3121
+ }
3122
+ function dashedLineCacheKey(signature) {
3123
+ return [
3124
+ signature.start,
3125
+ signature.end,
3126
+ signature.sourceLength,
3127
+ signature.isLineSegments ? 1 : 0,
3128
+ signature.isLineLoop ? 1 : 0,
3129
+ signature.isLine ? 1 : 0,
3130
+ signature.uv.attribute.ref ? 1 : 0,
3131
+ signature.uv2.attribute.ref ? 1 : 0,
3132
+ signature.dashSize,
3133
+ signature.gapSize,
3134
+ signature.scale,
3135
+ ].join(':');
3136
+ }
3137
+ function sameDashedLineSignature(a, b) {
3138
+ return a.cacheable === b.cacheable
3139
+ && a.geometryVersion === b.geometryVersion
3140
+ && sameAttributeSignature(a.position, b.position)
3141
+ && sameAttributeSignature(a.index, b.index)
3142
+ && sameUvChannelSignature(a.uv, b.uv)
3143
+ && sameUvChannelSignature(a.uv2, b.uv2)
3144
+ && sameAttributeSignature(a.lineDistance, b.lineDistance)
3145
+ && a.start === b.start
3146
+ && a.end === b.end
3147
+ && a.sourceLength === b.sourceLength
3148
+ && a.isLineSegments === b.isLineSegments
3149
+ && a.isLineLoop === b.isLineLoop
3150
+ && a.isLine === b.isLine
3151
+ && Object.is(a.dashSize, b.dashSize)
3152
+ && Object.is(a.gapSize, b.gapSize)
3153
+ && Object.is(a.scale, b.scale);
3154
+ }
3155
+ function dashedLineAttributesForInstancesWithCache(cache, geometry, position, positions, uvChannel, uvChannel2, vertexColors, materialColor, source, start, end, object, lineDistance, material, instanceCount, offsetAttribute, scaleAttribute) {
3156
+ const dashSize = positiveMaterialOrObjectNumber(material.dashSize, 'material.dashSize', 3);
3157
+ const gapSize = nonNegativeMaterialOrObjectNumber(material.gapSize, 'material.gapSize', 1);
3158
+ const scale = nonNegativeMaterialOrObjectNumber(material.scale, 'material.scale', 1);
3159
+ if (!cache) {
3160
+ return dashedLineAttributesForInstances(positions, uvChannel, uvChannel2, vertexColors, materialColor, source, start, end, object, lineDistance, material, instanceCount, offsetAttribute, scaleAttribute);
3161
+ }
3162
+ const signature = instancedDashedLineSignature(geometry, position, uvChannel, uvChannel2, vertexColors, materialColor, lineDistance, start, end, source.length, object, dashSize, gapSize, scale, instanceCount, offsetAttribute, scaleAttribute);
3163
+ if (!signature.cacheable) {
3164
+ return dashedLineAttributesForInstances(positions, uvChannel, uvChannel2, vertexColors, materialColor, source, start, end, object, lineDistance, material, instanceCount, offsetAttribute, scaleAttribute);
3165
+ }
3166
+ const cacheKey = instancedDashedLineCacheKey(signature);
3167
+ let geometryCache = cache.instancedDashedLines.get(geometry);
3168
+ const cached = geometryCache?.get(cacheKey);
3169
+ if (cached && sameInstancedDashedLineSignature(cached.signature, signature)) {
3170
+ return cached.expansion;
3171
+ }
3172
+ const expansion = dashedLineAttributesForInstances(positions, uvChannel, uvChannel2, vertexColors, materialColor, source, start, end, object, lineDistance, material, instanceCount, offsetAttribute, scaleAttribute);
3173
+ if (!geometryCache) {
3174
+ geometryCache = new Map();
3175
+ cache.instancedDashedLines.set(geometry, geometryCache);
3176
+ }
3177
+ geometryCache.set(cacheKey, { signature, expansion });
3178
+ return expansion;
3179
+ }
3180
+ function instancedDashedLineSignature(geometry, position, uvChannel, uvChannel2, vertexColors, materialColor, lineDistance, start, end, sourceLength, object, dashSize, gapSize, scale, instanceCount, offsetAttribute, scaleAttribute) {
3181
+ const signature = {
3182
+ cacheable: true,
3183
+ geometryVersion: geometry.version,
3184
+ position: attributeSignature(position),
3185
+ index: attributeSignature(geometry.index),
3186
+ uv: uvChannelSignature(uvChannel),
3187
+ uv2: uvChannelSignature(uvChannel2),
3188
+ lineDistance: attributeSignature(lineDistance),
3189
+ vertexColors: attributeSignature(vertexColors),
3190
+ instancedPositionOffset: attributeSignature(offsetAttribute?.attribute),
3191
+ instancedPositionScale: attributeSignature(scaleAttribute?.attribute),
3192
+ materialColor: vertexColors ? materialColor.slice() : undefined,
3193
+ start,
3194
+ end,
3195
+ sourceLength,
3196
+ instanceCount,
3197
+ isLineSegments: object.isLineSegments,
3198
+ isLineLoop: object.isLineLoop,
3199
+ isLine: object.isLine,
3200
+ dashSize,
3201
+ gapSize,
3202
+ scale,
3203
+ };
3204
+ signature.cacheable = instancedDashedLineSignatureCacheable(signature);
3205
+ return signature;
3206
+ }
3207
+ function instancedDashedLineSignatureCacheable(signature) {
3208
+ return attributeSignatureCacheable(signature.position)
3209
+ && attributeSignatureCacheable(signature.index)
3210
+ && attributeSignatureCacheable(signature.uv.attribute)
3211
+ && attributeSignatureCacheable(signature.uv2.attribute)
3212
+ && attributeSignatureCacheable(signature.lineDistance)
3213
+ && attributeSignatureCacheable(signature.vertexColors)
3214
+ && attributeSignatureCacheable(signature.instancedPositionOffset)
3215
+ && attributeSignatureCacheable(signature.instancedPositionScale);
3216
+ }
3217
+ function instancedDashedLineCacheKey(signature) {
3218
+ return [
3219
+ 'instanced',
3220
+ signature.start,
3221
+ signature.end,
3222
+ signature.sourceLength,
3223
+ signature.instanceCount,
3224
+ signature.isLineSegments ? 1 : 0,
3225
+ signature.isLineLoop ? 1 : 0,
3226
+ signature.isLine ? 1 : 0,
3227
+ signature.uv.attribute.ref ? 1 : 0,
3228
+ signature.uv2.attribute.ref ? 1 : 0,
3229
+ signature.vertexColors.ref ? 1 : 0,
3230
+ signature.instancedPositionOffset.ref ? 1 : 0,
3231
+ signature.instancedPositionScale.ref ? 1 : 0,
3232
+ signature.dashSize,
3233
+ signature.gapSize,
3234
+ signature.scale,
3235
+ ].join(':');
3236
+ }
3237
+ function sameInstancedDashedLineSignature(a, b) {
3238
+ return a.cacheable === b.cacheable
3239
+ && a.geometryVersion === b.geometryVersion
3240
+ && sameAttributeSignature(a.position, b.position)
3241
+ && sameAttributeSignature(a.index, b.index)
3242
+ && sameUvChannelSignature(a.uv, b.uv)
3243
+ && sameUvChannelSignature(a.uv2, b.uv2)
3244
+ && sameAttributeSignature(a.lineDistance, b.lineDistance)
3245
+ && sameAttributeSignature(a.vertexColors, b.vertexColors)
3246
+ && sameAttributeSignature(a.instancedPositionOffset, b.instancedPositionOffset)
3247
+ && sameAttributeSignature(a.instancedPositionScale, b.instancedPositionScale)
3248
+ && sameOptionalNumberArray(a.materialColor, b.materialColor)
3249
+ && a.start === b.start
3250
+ && a.end === b.end
3251
+ && a.sourceLength === b.sourceLength
3252
+ && a.instanceCount === b.instanceCount
3253
+ && a.isLineSegments === b.isLineSegments
3254
+ && a.isLineLoop === b.isLineLoop
3255
+ && a.isLine === b.isLine
3256
+ && Object.is(a.dashSize, b.dashSize)
3257
+ && Object.is(a.gapSize, b.gapSize)
3258
+ && Object.is(a.scale, b.scale);
3259
+ }
3260
+ function dashedLineAttributesForInstances(positions, uvChannel, uvChannel2, vertexColors, materialColor, source, start, end, object, lineDistance, material, instanceCount, offsetAttribute, scaleAttribute) {
3261
+ const out = {
3262
+ positions: [],
3263
+ uvs: uvChannel ? [] : undefined,
3264
+ uvs2: uvChannel2 ? [] : undefined,
3265
+ colors: vertexColors ? [] : undefined,
3266
+ };
3267
+ const baseColors = vertexColors && !isInstancedAttribute(vertexColors)
3268
+ ? (0, attributes_1.readColorAttribute)(vertexColors, materialColor, 'geometry.attributes.color')
3269
+ : undefined;
3270
+ const vertexCount = positions.length / 3;
3271
+ for (let instance = 0; instance < instanceCount; instance += 1) {
3272
+ const instancePositions = offsetAttribute
3273
+ ? transformVec3ValuesForInstance(positions, offsetAttribute, scaleAttribute, instance)
3274
+ : scaleAttribute
3275
+ ? transformVec3ValuesForInstance(positions, null, scaleAttribute, instance)
3276
+ : positions;
3277
+ const instanceUvs = uvValuesForInstance(uvChannel, vertexCount, instance);
3278
+ const instanceUvs2 = uvValuesForInstance(uvChannel2, vertexCount, instance);
3279
+ const instanceColors = vertexColors
3280
+ ? baseColors ?? repeatedInstancedColorValues(vertexColors, materialColor, positions.length / 3, instance)
3281
+ : undefined;
3282
+ const dashed = dashedLineAttributes(instancePositions, instanceUvs, instanceUvs2, instanceColors, source, start, end, object, lineDistance, material);
3283
+ appendDashedLineExpansion(out, dashed);
3284
+ }
3285
+ return out;
3286
+ }
3287
+ function transformVec3ValuesForInstance(values, offsetAttribute, scaleAttribute, instance) {
3288
+ const offsetIndex = offsetAttribute
3289
+ ? instancedAttributeIndex(offsetAttribute.attribute, instance, offsetAttribute.label)
3290
+ : 0;
3291
+ const ox = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 0, offsetAttribute.label) : 0;
3292
+ const oy = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 1, offsetAttribute.label) : 0;
3293
+ const oz = offsetAttribute ? (0, attributes_1.attributeComponent)(offsetAttribute.attribute, offsetIndex, 2, offsetAttribute.label) : 0;
3294
+ const scale = instanceScaleComponents(scaleAttribute, instance);
3295
+ const out = new Array(values.length);
3296
+ for (let i = 0; i < values.length; i += 3) {
3297
+ out[i] = values[i] * scale[0] + ox;
3298
+ out[i + 1] = values[i + 1] * scale[1] + oy;
3299
+ out[i + 2] = values[i + 2] * scale[2] + oz;
3300
+ }
3301
+ return out;
3302
+ }
3303
+ function repeatedInstancedColorValues(attribute, materialColor, vertexCount, instance, label = 'geometry.attributes.color') {
3304
+ const sourceIndex = instancedAttributeIndex(attribute, instance, label);
3305
+ const itemSize = attribute.itemSize ?? 3;
3306
+ const color = [
3307
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 0, label) * materialColor[0]),
3308
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 1, label) * materialColor[1]),
3309
+ (0, math_1.clamp01)((0, attributes_1.attributeComponent)(attribute, sourceIndex, 2, label) * materialColor[2]),
3310
+ (0, math_1.clamp01)((itemSize >= 4 ? (0, attributes_1.attributeComponent)(attribute, sourceIndex, 3, label) : 1) * materialColor[3]),
3311
+ ];
3312
+ const out = new Array(vertexCount * 4);
3313
+ let dst = 0;
3314
+ for (let i = 0; i < vertexCount; i += 1) {
3315
+ out[dst++] = color[0];
3316
+ out[dst++] = color[1];
3317
+ out[dst++] = color[2];
3318
+ out[dst++] = color[3];
3319
+ }
3320
+ return out;
3321
+ }
3322
+ function appendDashedLineExpansion(out, value) {
3323
+ appendNumberArray(out.positions, value.positions);
3324
+ if (out.uvs && value.uvs)
3325
+ appendNumberArray(out.uvs, value.uvs);
3326
+ if (out.uvs2 && value.uvs2)
3327
+ appendNumberArray(out.uvs2, value.uvs2);
3328
+ if (out.colors && value.colors)
3329
+ appendNumberArray(out.colors, value.colors);
3330
+ }
3331
+ function batchedMeshDraws(object, camera, geometry) {
3332
+ const instanceInfo = object._instanceInfo;
3333
+ if (!Array.isArray(instanceInfo)) {
3334
+ throw new Error('THREE.BatchedMesh instance table is not readable. Use a real THREE.BatchedMesh or expand the batch to ordinary Mesh or InstancedMesh objects before rendering.');
3335
+ }
3336
+ const baseTransform = (0, math_1.matrixElements)(object.matrixWorld, 'batchedMesh.matrixWorld');
3337
+ const cullPerObject = batchedPerObjectFrustumCulled(object, camera);
3338
+ const sortObjects = batchedSortObjects(object);
3339
+ const customSort = batchedCustomSort(object);
3340
+ const draws = [];
3341
+ for (let instanceId = 0; instanceId < instanceInfo.length; instanceId += 1) {
3342
+ const info = instanceInfo[instanceId];
3343
+ if (!info || typeof info !== 'object') {
3344
+ throw new TypeError(`THREE.BatchedMesh._instanceInfo[${instanceId}] must be an object.`);
3345
+ }
3346
+ if (!batchedOptionalBoolean(info.active, `THREE.BatchedMesh._instanceInfo[${instanceId}].active`, true))
3347
+ continue;
3348
+ if (!batchedOptionalBoolean(info.visible, `THREE.BatchedMesh._instanceInfo[${instanceId}].visible`, true))
3349
+ continue;
3350
+ const geometryId = batchedNonNegativeInteger(info.geometryIndex, `THREE.BatchedMesh._instanceInfo[${instanceId}].geometryIndex`);
3351
+ const range = batchedGeometryRange(object, geometry, geometryId);
3352
+ if (range.count === 0)
3353
+ continue;
3354
+ const transform = multiplyMat4(baseTransform, batchedInstanceMatrix(object, instanceId));
3355
+ if (cullPerObject && batchedDrawOutsideFrustum(object, geometry, geometryId, range, transform, camera)) {
3356
+ continue;
3357
+ }
3358
+ draws.push({
3359
+ range,
3360
+ instanceId,
3361
+ instance: {
3362
+ transform,
3363
+ color: batchedInstanceColor(object, instanceId),
3364
+ },
3365
+ z: sortObjects ? batchedDrawDistanceZ(object, geometry, geometryId, range, transform, camera) : 0,
3366
+ });
3367
+ }
3368
+ if (!sortObjects || draws.length < 2)
3369
+ return draws;
3370
+ if (customSort) {
3371
+ return customSortedBatchedMeshDraws(object, draws, customSort, camera);
3372
+ }
3373
+ return draws
3374
+ .slice()
3375
+ .sort(batchedMeshUsesTransparentSort(object) ? compareBatchedDrawsTransparent : compareBatchedDrawsOpaque);
3376
+ }
3377
+ function batchedPerObjectFrustumCulled(object, camera) {
3378
+ if (!camera || camera.isArrayCamera === true)
3379
+ return false;
3380
+ return batchedOptionalBoolean(object.perObjectFrustumCulled, 'THREE.BatchedMesh.perObjectFrustumCulled', true);
3381
+ }
3382
+ function batchedSortObjects(object) {
3383
+ return batchedOptionalBoolean(object.sortObjects, 'THREE.BatchedMesh.sortObjects', true);
3384
+ }
3385
+ function batchedCustomSort(object) {
3386
+ if (object.customSort == null)
3387
+ return null;
3388
+ if (typeof object.customSort === 'function')
3389
+ return object.customSort;
3390
+ throw new TypeError('THREE.BatchedMesh.customSort must be a function or null.');
3391
+ }
3392
+ function customSortedBatchedMeshDraws(object, draws, customSort, camera) {
3393
+ const drawByInstance = new Map(draws.map((draw) => [draw.instanceId, draw]));
3394
+ const list = draws.map((draw) => ({
3395
+ start: draw.range.start,
3396
+ count: draw.range.count,
3397
+ z: draw.z,
3398
+ index: draw.instanceId,
3399
+ }));
3400
+ customSort.call(object, list, camera);
3401
+ if (list.length !== draws.length) {
3402
+ throw new Error(`THREE.BatchedMesh.customSort must keep ${draws.length} draw items; received ${list.length}.`);
3403
+ }
3404
+ const seenInstances = new Set();
3405
+ return list.map((item, itemIndex) => {
3406
+ if (!item || typeof item !== 'object') {
3407
+ throw new TypeError(`THREE.BatchedMesh.customSort list[${itemIndex}] must be an object.`);
3408
+ }
3409
+ const instanceId = batchedNonNegativeInteger(item.index, `THREE.BatchedMesh.customSort list[${itemIndex}].index`);
3410
+ if (seenInstances.has(instanceId)) {
3411
+ throw new Error(`THREE.BatchedMesh.customSort returned duplicate instance index ${instanceId}.`);
3412
+ }
3413
+ seenInstances.add(instanceId);
3414
+ const draw = drawByInstance.get(instanceId);
3415
+ if (!draw) {
3416
+ throw new Error(`THREE.BatchedMesh.customSort returned unknown instance index ${instanceId}.`);
3417
+ }
3418
+ return draw;
3419
+ });
3420
+ }
3421
+ function compareBatchedDrawsOpaque(a, b) {
3422
+ return a.z - b.z || a.instanceId - b.instanceId;
3423
+ }
3424
+ function compareBatchedDrawsTransparent(a, b) {
3425
+ return b.z - a.z || a.instanceId - b.instanceId;
3426
+ }
3427
+ function batchedMeshUsesTransparentSort(object) {
3428
+ const materials = Array.isArray(object.material)
3429
+ ? object.material
3430
+ : [object.material];
3431
+ return materials.some((material) => material?.transparent === true || finitePositive(material?.transmission));
3432
+ }
3433
+ function batchedDrawDistanceZ(object, geometry, geometryId, range, transform, camera) {
3434
+ if (!camera)
3435
+ return 0;
3436
+ const sphere = batchedGeometryBoundingSphere(object, geometry, geometryId, range);
3437
+ if (!sphere)
3438
+ return 0;
3439
+ const center = transformPoint(transform, sphere.center);
3440
+ const viewZ = viewSpaceZ(center, camera);
3441
+ return Number.isFinite(viewZ) ? -viewZ : 0;
3442
+ }
3443
+ function batchedDrawSortIndex(base, drawOrder) {
3444
+ return Math.max(0, Math.min(0xffffffff, base + drawOrder));
3445
+ }
3446
+ function batchedDrawOutsideFrustum(object, geometry, geometryId, range, transform, camera) {
3447
+ const sphere = batchedGeometryBoundingSphere(object, geometry, geometryId, range);
3448
+ if (!sphere)
3449
+ return false;
3450
+ return transformedSphereOutsideFrustum(camera, transform, sphere);
3451
+ }
3452
+ function batchedGeometryRange(object, geometry, geometryId) {
3453
+ const cachedRange = object._geometryInfo?.[geometryId];
3454
+ const cachedActive = cachedRange && typeof cachedRange === 'object' && !Array.isArray(cachedRange)
3455
+ ? cachedRange.active
3456
+ : null;
3457
+ if (cachedActive != null && !batchedOptionalBoolean(cachedActive, `THREE.BatchedMesh._geometryInfo[${geometryId}].active`, true)) {
3458
+ return { start: 0, count: 0 };
3459
+ }
3460
+ const range = typeof object.getGeometryRangeAt === 'function'
3461
+ ? object.getGeometryRangeAt(geometryId, {})
3462
+ : cachedRange ?? null;
3463
+ if (!range || typeof range !== 'object') {
3464
+ throw new Error(`THREE.BatchedMesh geometry range ${geometryId} is not readable. Use a real THREE.BatchedMesh or expand the batch before rendering.`);
3465
+ }
3466
+ const rawActive = range.active;
3467
+ if (rawActive != null && !batchedOptionalBoolean(rawActive, `THREE.BatchedMesh._geometryInfo[${geometryId}].active`, true)) {
3468
+ return { start: 0, count: 0 };
3469
+ }
3470
+ const startLabel = `THREE.BatchedMesh._geometryInfo[${geometryId}].start`;
3471
+ const countLabel = `THREE.BatchedMesh._geometryInfo[${geometryId}].count`;
3472
+ const start = batchedNonNegativeInteger(range.start, startLabel);
3473
+ const count = batchedNonNegativeInteger(range.count, countLabel);
3474
+ const limit = batchedGeometryRangeLimit(geometry);
3475
+ if (start > limit) {
3476
+ throw new RangeError(`${startLabel} must be less than or equal to packed geometry count (${limit}).`);
3477
+ }
3478
+ if (count > limit - start) {
3479
+ throw new RangeError(`${countLabel} must fit within packed geometry count (${limit}) from start ${start}.`);
3480
+ }
3481
+ return { start, count };
3482
+ }
3483
+ function batchedGeometryRangeLimit(geometry) {
3484
+ if (geometry.index)
3485
+ return (0, attributes_1.attributeCount)(geometry.index, 'geometry.index');
3486
+ const position = (0, attributes_1.getAttribute)(geometry, 'position');
3487
+ return position ? (0, attributes_1.attributeCount)(position, 'geometry.attributes.position') : 0;
3488
+ }
3489
+ function batchedGeometryBoundingSphere(object, geometry, geometryId, range) {
3490
+ const cached = object._geometryInfo?.[geometryId]?.boundingSphere;
3491
+ if (cached != null) {
3492
+ return batchedSphereLike(cached, `THREE.BatchedMesh._geometryInfo[${geometryId}].boundingSphere`);
3493
+ }
3494
+ const computed = batchedGeometryRangeBoundingSphere(geometry, range);
3495
+ return computed ? batchedSphereLike(computed, `THREE.BatchedMesh._geometryInfo[${geometryId}].computedBoundingSphere`) : null;
3496
+ }
3497
+ function batchedSphereLike(sphere, label) {
3498
+ return sphereLike(sphere, label);
3499
+ }
3500
+ function sphereLike(sphere, label) {
3501
+ if (!sphere || typeof sphere !== 'object') {
3502
+ throw new TypeError(`${label} must be a THREE.Sphere-like object.`);
3503
+ }
3504
+ const center = vec3Like(sphere.center);
3505
+ if (!center) {
3506
+ throw new TypeError(`${label}.center must be a finite Vector3-like value.`);
3507
+ }
3508
+ const radius = nonNegativeMaterialOrObjectNumber(sphere.radius, `${label}.radius`, 0);
3509
+ return { center, radius };
3510
+ }
3511
+ function batchedGeometryView(geometry, range, cache) {
3512
+ const signature = batchedGeometryViewSignature(geometry, range);
3513
+ if (cache && signature.cacheable) {
3514
+ let views = cache.batchedGeometryViews.get(geometry);
3515
+ if (!views) {
3516
+ views = new Map();
3517
+ cache.batchedGeometryViews.set(geometry, views);
3518
+ }
3519
+ const key = batchedGeometryViewKey(range);
3520
+ const cached = views.get(key);
3521
+ if (cached && sameBatchedGeometryViewSignature(cached.signature, signature)) {
3522
+ return cached.view;
3523
+ }
3524
+ const view = cached?.view ?? createBatchedGeometryView(geometry);
3525
+ updateBatchedGeometryView(view, geometry, range);
3526
+ views.set(key, { signature, view });
3527
+ return view;
3528
+ }
3529
+ const view = createBatchedGeometryView(geometry);
3530
+ updateBatchedGeometryView(view, geometry, range);
3531
+ return view;
3532
+ }
3533
+ function createBatchedGeometryView(geometry) {
3534
+ return Object.create(geometry);
3535
+ }
3536
+ function updateBatchedGeometryView(view, geometry, range) {
3537
+ view.drawRange = { start: range.start, count: range.count };
3538
+ view.boundingSphere = batchedGeometryRangeBoundingSphere(geometry, range);
3539
+ }
3540
+ function batchedGeometryViewSignature(geometry, range) {
3541
+ const signature = {
3542
+ cacheable: true,
3543
+ geometryVersion: geometry.version,
3544
+ rangeStart: range.start,
3545
+ rangeCount: range.count,
3546
+ position: attributeSignature((0, attributes_1.getAttribute)(geometry, 'position')),
3547
+ index: attributeSignature(geometry.index),
3548
+ };
3549
+ signature.cacheable = attributeSignatureCacheable(signature.position)
3550
+ && attributeSignatureCacheable(signature.index);
3551
+ return signature;
3552
+ }
3553
+ function sameBatchedGeometryViewSignature(a, b) {
3554
+ return a.cacheable === b.cacheable
3555
+ && a.geometryVersion === b.geometryVersion
3556
+ && a.rangeStart === b.rangeStart
3557
+ && a.rangeCount === b.rangeCount
3558
+ && sameAttributeSignature(a.position, b.position)
3559
+ && sameAttributeSignature(a.index, b.index);
3560
+ }
3561
+ function batchedGeometryViewKey(range) {
3562
+ return `${range.start}:${range.count}`;
3563
+ }
3564
+ function batchedGeometryRangeBoundingSphere(geometry, range) {
3565
+ const position = (0, attributes_1.getAttribute)(geometry, 'position');
3566
+ if (!position || range.count <= 0)
3567
+ return undefined;
3568
+ const index = geometry.index ? (0, attributes_1.readIndexAttribute)(geometry.index, 'geometry.index', position.count) : null;
3569
+ const start = Math.max(0, range.start);
3570
+ const end = Math.max(start, range.start + range.count);
3571
+ let minX = Number.POSITIVE_INFINITY;
3572
+ let minY = Number.POSITIVE_INFINITY;
3573
+ let minZ = Number.POSITIVE_INFINITY;
3574
+ let maxX = Number.NEGATIVE_INFINITY;
3575
+ let maxY = Number.NEGATIVE_INFINITY;
3576
+ let maxZ = Number.NEGATIVE_INFINITY;
3577
+ const vertexIndices = [];
3578
+ for (let offset = start; offset < end; offset += 1) {
3579
+ const vertexIndex = index ? index[offset] : offset;
3580
+ if (!Number.isInteger(vertexIndex) || vertexIndex < 0 || vertexIndex >= position.count)
3581
+ continue;
3582
+ vertexIndices.push(vertexIndex);
3583
+ const x = (0, attributes_1.attributeComponent)(position, vertexIndex, 0, 'geometry.attributes.position');
3584
+ const y = (0, attributes_1.attributeComponent)(position, vertexIndex, 1, 'geometry.attributes.position');
3585
+ const z = (0, attributes_1.attributeComponent)(position, vertexIndex, 2, 'geometry.attributes.position');
3586
+ minX = Math.min(minX, x);
3587
+ minY = Math.min(minY, y);
3588
+ minZ = Math.min(minZ, z);
3589
+ maxX = Math.max(maxX, x);
3590
+ maxY = Math.max(maxY, y);
3591
+ maxZ = Math.max(maxZ, z);
3592
+ }
3593
+ if (vertexIndices.length === 0)
3594
+ return undefined;
3595
+ const center = {
3596
+ x: (minX + maxX) * 0.5,
3597
+ y: (minY + maxY) * 0.5,
3598
+ z: (minZ + maxZ) * 0.5,
3599
+ };
3600
+ let radiusSq = 0;
3601
+ for (const vertexIndex of vertexIndices) {
3602
+ const dx = (0, attributes_1.attributeComponent)(position, vertexIndex, 0, 'geometry.attributes.position') - center.x;
3603
+ const dy = (0, attributes_1.attributeComponent)(position, vertexIndex, 1, 'geometry.attributes.position') - center.y;
3604
+ const dz = (0, attributes_1.attributeComponent)(position, vertexIndex, 2, 'geometry.attributes.position') - center.z;
3605
+ radiusSq = Math.max(radiusSq, dx * dx + dy * dy + dz * dz);
3606
+ }
3607
+ return { center, radius: Math.sqrt(radiusSq) };
3608
+ }
3609
+ function batchedInstanceMatrix(object, instanceId) {
3610
+ const data = batchedTextureImageData(object._matricesTexture, 'THREE.BatchedMesh._matricesTexture', instanceId);
3611
+ const offset = instanceId * 16;
3612
+ if (typeof data.length !== 'number' || data.length < offset + 16) {
3613
+ throw new Error(`THREE.BatchedMesh matrix texture is not readable for instance ${instanceId}. Use a real THREE.BatchedMesh or expand the batch before rendering.`);
3614
+ }
3615
+ const matrix = new Array(16);
3616
+ for (let component = 0; component < 16; component += 1) {
3617
+ matrix[component] = finiteArrayValue(data, offset + component, 'THREE.BatchedMesh._matricesTexture.image.data');
3618
+ }
3619
+ return matrix;
3620
+ }
3621
+ function batchedInstanceColor(object, instanceId) {
3622
+ const texture = object._colorsTexture;
3623
+ if (texture == null)
3624
+ return undefined;
3625
+ const data = batchedTextureImageData(texture, 'THREE.BatchedMesh._colorsTexture', instanceId);
3626
+ const offset = instanceId * 4;
3627
+ if (typeof data.length !== 'number' || data.length < offset + 4) {
3628
+ throw new Error(`THREE.BatchedMesh color texture is not readable for instance ${instanceId}. Use a real THREE.BatchedMesh or expand the batch before rendering.`);
3629
+ }
3630
+ return [
3631
+ finiteArrayValue(data, offset, 'THREE.BatchedMesh._colorsTexture.image.data'),
3632
+ finiteArrayValue(data, offset + 1, 'THREE.BatchedMesh._colorsTexture.image.data'),
3633
+ finiteArrayValue(data, offset + 2, 'THREE.BatchedMesh._colorsTexture.image.data'),
3634
+ finiteArrayValue(data, offset + 3, 'THREE.BatchedMesh._colorsTexture.image.data'),
3635
+ ];
3636
+ }
3637
+ function batchedTextureImageData(texture, label, instanceId) {
3638
+ if (!texture || typeof texture !== 'object') {
3639
+ throw new TypeError(`${label} must be a texture-like object for instance ${instanceId}.`);
3640
+ }
3641
+ const image = texture.image;
3642
+ if (!image || typeof image !== 'object') {
3643
+ throw new TypeError(`${label}.image must be an image-like object for instance ${instanceId}.`);
3644
+ }
3645
+ const data = image.data;
3646
+ if (!data || typeof data !== 'object') {
3647
+ throw new TypeError(`${label}.image.data must be an array-like object for instance ${instanceId}.`);
3648
+ }
3649
+ return data;
3650
+ }
3651
+ function batchedOptionalBoolean(value, label, fallback) {
3652
+ if (value == null)
3653
+ return fallback;
3654
+ if (typeof value === 'boolean')
3655
+ return value;
3656
+ throw new TypeError(`${label} must be a boolean.`);
3657
+ }
3658
+ function batchedNonNegativeInteger(value, label) {
3659
+ if (typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value) && value >= 0) {
3660
+ return value;
3661
+ }
3662
+ throw new TypeError(`${label} must be a non-negative integer.`);
3663
+ }
3664
+ function finiteArrayValue(values, index, label) {
3665
+ const value = values[index];
3666
+ if (typeof value === 'number' && Number.isFinite(value))
3667
+ return value;
3668
+ throw new TypeError(`${label}[${index}] must be a finite number.`);
3669
+ }
3670
+ function appendNumberArray(out, values) {
3671
+ for (const value of values)
3672
+ out.push(value);
3673
+ }
3674
+ function createDashedLineExpansion(uvs, uvs2, colors) {
3675
+ return {
3676
+ positions: [],
3677
+ uvs: uvs ? [] : undefined,
3678
+ uvs2: uvs2 ? [] : undefined,
3679
+ colors: colors ? [] : undefined,
3680
+ };
3681
+ }
3682
+ function cameraFrustumIntersectsSphere(camera, center, radius) {
3683
+ const view = camera.matrixWorldInverse?.elements;
3684
+ const projection = camera.projectionMatrix?.elements;
3685
+ if (!view || view.length < 16 || !projection || projection.length < 16)
3686
+ return true;
3687
+ const viewProjection = multiplyMat4(projection, view);
3688
+ const planes = [
3689
+ [viewProjection[3] + viewProjection[0], viewProjection[7] + viewProjection[4], viewProjection[11] + viewProjection[8], viewProjection[15] + viewProjection[12]],
3690
+ [viewProjection[3] - viewProjection[0], viewProjection[7] - viewProjection[4], viewProjection[11] - viewProjection[8], viewProjection[15] - viewProjection[12]],
3691
+ [viewProjection[3] + viewProjection[1], viewProjection[7] + viewProjection[5], viewProjection[11] + viewProjection[9], viewProjection[15] + viewProjection[13]],
3692
+ [viewProjection[3] - viewProjection[1], viewProjection[7] - viewProjection[5], viewProjection[11] - viewProjection[9], viewProjection[15] - viewProjection[13]],
3693
+ [viewProjection[3] + viewProjection[2], viewProjection[7] + viewProjection[6], viewProjection[11] + viewProjection[10], viewProjection[15] + viewProjection[14]],
3694
+ [viewProjection[3] - viewProjection[2], viewProjection[7] - viewProjection[6], viewProjection[11] - viewProjection[10], viewProjection[15] - viewProjection[14]],
3695
+ ];
3696
+ for (const [a, b, c, d] of planes) {
3697
+ const length = Math.hypot(a, b, c);
3698
+ if (!Number.isFinite(length) || length <= 1e-8)
3699
+ continue;
3700
+ const distance = (a * center[0] + b * center[1] + c * center[2] + d) / length;
3701
+ if (distance < -radius)
3702
+ return false;
3703
+ }
3704
+ return true;
3705
+ }
3706
+ function lineSegmentsWithDistances(positions, source, start, end, object, lineDistance) {
3707
+ const count = end - start;
3708
+ const segments = [];
3709
+ if (count < 2)
3710
+ return segments;
3711
+ if (object.isLineSegments === true) {
3712
+ let cumulative = 0;
3713
+ const aligned = count - (count % 2);
3714
+ for (let i = 0; i < aligned; i += 2) {
3715
+ const a = source[start + i];
3716
+ const b = source[start + i + 1];
3717
+ const length = vertexDistance(positions, a, b);
3718
+ const d0 = lineDistance ? (0, attributes_1.attributeComponent)(lineDistance, a, 0, 'geometry.attributes.lineDistance') : cumulative;
3719
+ const d1 = lineDistance ? (0, attributes_1.attributeComponent)(lineDistance, b, 0, 'geometry.attributes.lineDistance') : d0 + length;
3720
+ segments.push({ a, b, d0, d1 });
3721
+ cumulative = d1;
3722
+ }
3723
+ return segments;
3724
+ }
3725
+ let previous = source[start];
3726
+ let previousDistance = lineDistance ? (0, attributes_1.attributeComponent)(lineDistance, previous, 0, 'geometry.attributes.lineDistance') : 0;
3727
+ for (let i = 1; i < count; i += 1) {
3728
+ const current = source[start + i];
3729
+ const length = vertexDistance(positions, previous, current);
3730
+ const currentDistance = lineDistance ? (0, attributes_1.attributeComponent)(lineDistance, current, 0, 'geometry.attributes.lineDistance') : previousDistance + length;
3731
+ segments.push({ a: previous, b: current, d0: previousDistance, d1: currentDistance });
3732
+ previous = current;
3733
+ previousDistance = currentDistance;
3734
+ }
3735
+ if (object.isLineLoop === true && count >= 2) {
3736
+ const first = source[start];
3737
+ segments.push({
3738
+ a: previous,
3739
+ b: first,
3740
+ d0: previousDistance,
3741
+ d1: lineDistance
3742
+ ? (0, attributes_1.attributeComponent)(lineDistance, first, 0, 'geometry.attributes.lineDistance')
3743
+ : previousDistance + vertexDistance(positions, previous, first),
3744
+ });
3745
+ }
3746
+ return segments;
3747
+ }
3748
+ function appendDashedSegment(out, positions, uvs, uvs2, colors, segment, scale, dashSize, totalSize) {
3749
+ const s0 = segment.d0 * scale;
3750
+ const s1 = segment.d1 * scale;
3751
+ const span = s1 - s0;
3752
+ const direction = Math.sign(span);
3753
+ if (Math.abs(span) <= 1e-6 || direction === 0)
3754
+ return;
3755
+ let cursor = s0;
3756
+ let guard = 0;
3757
+ while ((direction > 0 ? cursor < s1 - 1e-6 : cursor > s1 + 1e-6) && guard < 10000) {
3758
+ guard += 1;
3759
+ const cycle = Math.floor(cursor / totalSize);
3760
+ const cycleStart = cycle * totalSize;
3761
+ const inCycle = cursor - cycleStart;
3762
+ const visible = inCycle <= dashSize;
3763
+ const boundary = direction > 0
3764
+ ? cycleStart + (visible ? dashSize : totalSize)
3765
+ : cycleStart + (visible ? 0 : dashSize);
3766
+ const next = direction > 0
3767
+ ? Math.min(s1, boundary <= cursor + 1e-6 ? cursor + 1e-6 : boundary)
3768
+ : Math.max(s1, boundary >= cursor - 1e-6 ? cursor - 1e-6 : boundary);
3769
+ const hasVisibleSpan = direction > 0 ? next > cursor + 1e-6 : next < cursor - 1e-6;
3770
+ if (visible && hasVisibleSpan) {
3771
+ const t0 = (cursor - s0) / span;
3772
+ const t1 = (next - s0) / span;
3773
+ appendInterpolatedLine(out, positions, uvs, uvs2, colors, segment.a, segment.b, t0, t1);
3774
+ }
3775
+ cursor = next;
3776
+ }
3777
+ }
3778
+ function appendInterpolatedLine(out, positions, uvs, uvs2, colors, a, b, t0, t1) {
3779
+ appendInterpolatedAttribute(out.positions, positions, 3, a, b, t0);
3780
+ appendInterpolatedAttribute(out.positions, positions, 3, a, b, t1);
3781
+ if (out.uvs && uvs) {
3782
+ appendInterpolatedAttribute(out.uvs, uvs, 2, a, b, t0);
3783
+ appendInterpolatedAttribute(out.uvs, uvs, 2, a, b, t1);
3784
+ }
3785
+ if (out.uvs2 && uvs2) {
3786
+ appendInterpolatedAttribute(out.uvs2, uvs2, 2, a, b, t0);
3787
+ appendInterpolatedAttribute(out.uvs2, uvs2, 2, a, b, t1);
3788
+ }
3789
+ if (out.colors && colors) {
3790
+ appendInterpolatedAttribute(out.colors, colors, 4, a, b, t0);
3791
+ appendInterpolatedAttribute(out.colors, colors, 4, a, b, t1);
3792
+ }
3793
+ }
3794
+ function appendInterpolatedAttribute(out, values, itemSize, a, b, t) {
3795
+ const aBase = a * itemSize;
3796
+ const bBase = b * itemSize;
3797
+ for (let component = 0; component < itemSize; component += 1) {
3798
+ const av = values[aBase + component];
3799
+ const bv = values[bBase + component];
3800
+ out.push(av + (bv - av) * t);
3801
+ }
3802
+ }
3803
+ function vertexDistance(positions, a, b) {
3804
+ const dx = positions[a * 3] - positions[b * 3];
3805
+ const dy = positions[a * 3 + 1] - positions[b * 3 + 1];
3806
+ const dz = positions[a * 3 + 2] - positions[b * 3 + 2];
3807
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
3808
+ }
3809
+ function meshInstances(object, baseTransform, cache) {
3810
+ if (object.isInstancedMesh !== true) {
3811
+ return [{ transform: baseTransform }];
3812
+ }
3813
+ const instanceMatrix = object.instanceMatrix;
3814
+ if (!instanceMatrix || instanceMatrix.count == null)
3815
+ return [];
3816
+ const instanceMatrixCount = (0, attributes_1.attributeCount)(instanceMatrix, 'InstancedMesh.instanceMatrix');
3817
+ const count = (0, math_1.clampInteger)(integerCountOrDefault(object.count, 'InstancedMesh.count', instanceMatrixCount), 0, instanceMatrixCount);
3818
+ const signature = instancedMeshSignature(object, instanceMatrix, count);
3819
+ let localInstances;
3820
+ if (cache && signature.cacheable) {
3821
+ const cached = cache.instancedMeshes.get(object);
3822
+ if (cached && sameInstancedMeshSignature(cached.signature, signature)) {
3823
+ localInstances = cached.localInstances;
3824
+ }
3825
+ }
3826
+ if (!localInstances) {
3827
+ localInstances = readLocalInstancedMeshInstances(object, instanceMatrix, count);
3828
+ if (cache && signature.cacheable) {
3829
+ cache.instancedMeshes.set(object, { signature, localInstances });
3830
+ }
3831
+ }
3832
+ return localInstances.map((instance) => ({
3833
+ transform: multiplyMat4(baseTransform, instance.transform),
3834
+ color: instance.color,
3835
+ }));
3836
+ }
3837
+ function instancedMeshSignature(object, instanceMatrix, count) {
3838
+ const signature = {
3839
+ cacheable: true,
3840
+ count,
3841
+ instanceMatrix: attributeSignature(instanceMatrix),
3842
+ instanceColor: attributeSignature(object.instanceColor),
3843
+ };
3844
+ signature.cacheable = attributeSignatureCacheable(signature.instanceMatrix)
3845
+ && attributeSignatureCacheable(signature.instanceColor);
3846
+ return signature;
3847
+ }
3848
+ function sameInstancedMeshSignature(a, b) {
3849
+ return a.cacheable === b.cacheable
3850
+ && a.count === b.count
3851
+ && sameAttributeSignature(a.instanceMatrix, b.instanceMatrix)
3852
+ && sameAttributeSignature(a.instanceColor, b.instanceColor);
3853
+ }
3854
+ function readLocalInstancedMeshInstances(object, instanceMatrix, count) {
3855
+ const instances = new Array(count);
3856
+ for (let i = 0; i < count; i += 1) {
3857
+ instances[i] = {
3858
+ transform: readMat4Attribute(instanceMatrix, i),
3859
+ color: readInstanceColor(object.instanceColor, i),
3860
+ };
3861
+ }
3862
+ return instances;
3863
+ }
3864
+ function readMat4Attribute(attribute, index) {
3865
+ if (!attribute)
3866
+ return math_1.IDENTITY_4X4.slice();
3867
+ const matrix = new Array(16);
3868
+ for (let component = 0; component < 16; component += 1) {
3869
+ matrix[component] = (0, attributes_1.attributeComponent)(attribute, index, component, 'InstancedMesh.instanceMatrix');
3870
+ }
3871
+ return matrix;
3872
+ }
3873
+ function readInstanceColor(attribute, index) {
3874
+ if (!attribute || index >= (0, attributes_1.attributeCount)(attribute, 'InstancedMesh.instanceColor'))
3875
+ return undefined;
3876
+ return [
3877
+ (0, attributes_1.attributeComponent)(attribute, index, 0, 'InstancedMesh.instanceColor'),
3878
+ (0, attributes_1.attributeComponent)(attribute, index, 1, 'InstancedMesh.instanceColor'),
3879
+ (0, attributes_1.attributeComponent)(attribute, index, 2, 'InstancedMesh.instanceColor'),
3880
+ attribute.itemSize && attribute.itemSize >= 4 ? (0, attributes_1.attributeComponent)(attribute, index, 3, 'InstancedMesh.instanceColor') : 1,
3881
+ ];
3882
+ }
3883
+ function instanceColor(baseColor, instance) {
3884
+ if (!instance.color)
3885
+ return baseColor;
3886
+ return [
3887
+ baseColor[0] * instance.color[0],
3888
+ baseColor[1] * instance.color[1],
3889
+ baseColor[2] * instance.color[2],
3890
+ baseColor[3] * instance.color[3],
3891
+ ];
3892
+ }
3893
+ function multiplyMat4(a, b) {
3894
+ const out = new Array(16);
3895
+ for (let col = 0; col < 4; col += 1) {
3896
+ for (let row = 0; row < 4; row += 1) {
3897
+ out[col * 4 + row] =
3898
+ a[row] * b[col * 4]
3899
+ + a[4 + row] * b[col * 4 + 1]
3900
+ + a[8 + row] * b[col * 4 + 2]
3901
+ + a[12 + row] * b[col * 4 + 3];
3902
+ }
3903
+ }
3904
+ return out;
3905
+ }
192
3906
  function rangeIndices(count) {
193
3907
  const out = new Array(count);
194
3908
  for (let i = 0; i < count; i++)