@xeokit/xeokit-sdk 2.6.35 → 2.6.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/xeokit-sdk.cjs.js +1035 -362
- package/dist/xeokit-sdk.es.js +1035 -362
- package/dist/xeokit-sdk.es5.js +111 -82
- package/dist/xeokit-sdk.min.cjs.js +4 -4
- package/dist/xeokit-sdk.min.es.js +4 -4
- package/dist/xeokit-sdk.min.es5.js +4 -4
- package/package.json +1 -1
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +21 -6
- package/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js +9 -11
- package/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js +8 -0
- package/src/plugins/XKTLoaderPlugin/parsers/ParserV11.js +657 -0
- package/src/plugins/ZonesPlugin/ZonesPlugin.js +3 -3
- package/src/plugins/lib/ui/index.js +1 -1
- package/src/viewer/Viewer.js +3 -0
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickDepthRenderer.js +10 -6
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickMeshRenderer.js +14 -8
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsFlatRenderer.js +13 -8
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsRenderer.js +7 -10
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesDepthRenderer.js +0 -11
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Parser for .XKT Format V11
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {utils} from "../../../viewer/scene/utils.js";
|
|
6
|
+
import {math} from "../../../viewer/scene/math/math.js";
|
|
7
|
+
import {geometryCompressionUtils} from "../../../viewer/scene/math/geometryCompressionUtils.js";
|
|
8
|
+
import {JPEGMediaType, PNGMediaType} from "../../../viewer/scene/constants/constants.js";
|
|
9
|
+
|
|
10
|
+
const tempVec4a = math.vec4();
|
|
11
|
+
const tempVec4b = math.vec4();
|
|
12
|
+
|
|
13
|
+
const NUM_TEXTURE_ATTRIBUTES = 9;
|
|
14
|
+
|
|
15
|
+
function decodeData(arrayBuffer) {
|
|
16
|
+
const requiresSwapFromLittleEndian = (function() {
|
|
17
|
+
const buffer = new ArrayBuffer(2);
|
|
18
|
+
new Uint16Array(buffer)[0] = 1;
|
|
19
|
+
return new Uint8Array(buffer)[0] !== 1;
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
const nextArray = (function() {
|
|
23
|
+
let i = 0;
|
|
24
|
+
const dataView = new DataView(arrayBuffer);
|
|
25
|
+
return function(type) {
|
|
26
|
+
const idx = 1 + 2 * i++; // `1' for the version nr
|
|
27
|
+
const byteOffset = dataView.getUint32(idx * 4, true);
|
|
28
|
+
const byteLength = dataView.getUint32((idx + 1) * 4, true);
|
|
29
|
+
|
|
30
|
+
const BPE = type.BYTES_PER_ELEMENT;
|
|
31
|
+
if (requiresSwapFromLittleEndian && (BPE > 1)) {
|
|
32
|
+
const subarray = new Uint8Array(arrayBuffer, byteOffset, byteLength);
|
|
33
|
+
const swaps = BPE / 2;
|
|
34
|
+
const cnt = subarray.length / BPE;
|
|
35
|
+
for (let b = 0; b < cnt; b++) {
|
|
36
|
+
const offset = b * BPE;
|
|
37
|
+
for (let j = 0; j < swaps; j++) {
|
|
38
|
+
const i1 = offset + j;
|
|
39
|
+
const i2 = offset - j + BPE - 1;
|
|
40
|
+
const tmp = subarray[i1];
|
|
41
|
+
subarray[i1] = subarray[i2];
|
|
42
|
+
subarray[i2] = tmp;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new type(arrayBuffer, byteOffset, byteLength / BPE);
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
|
|
51
|
+
const nextObject = (function() {
|
|
52
|
+
const decoder = new TextDecoder();
|
|
53
|
+
return () => JSON.parse(decoder.decode(nextArray(Uint8Array)));
|
|
54
|
+
})();
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
metadata: nextObject(),
|
|
58
|
+
textureData: nextArray(Uint8Array), // <<----------------------------- ??? ZIPPing to blame?
|
|
59
|
+
eachTextureDataPortion: nextArray(Uint32Array),
|
|
60
|
+
eachTextureAttributes: nextArray(Uint16Array),
|
|
61
|
+
positions: nextArray(Uint16Array),
|
|
62
|
+
normals: nextArray(Int8Array),
|
|
63
|
+
colors: nextArray(Uint8Array),
|
|
64
|
+
uvs: nextArray(Float32Array),
|
|
65
|
+
indices: nextArray(Uint32Array),
|
|
66
|
+
edgeIndices: nextArray(Uint32Array),
|
|
67
|
+
eachTextureSetTextures: nextArray(Int32Array),
|
|
68
|
+
matrices: nextArray(Float32Array),
|
|
69
|
+
reusedGeometriesDecodeMatrix: nextArray(Float32Array),
|
|
70
|
+
eachGeometryPrimitiveType: nextArray(Uint8Array),
|
|
71
|
+
eachGeometryPositionsPortion: nextArray(Uint32Array),
|
|
72
|
+
eachGeometryNormalsPortion: nextArray(Uint32Array),
|
|
73
|
+
eachGeometryColorsPortion: nextArray(Uint32Array),
|
|
74
|
+
eachGeometryUVsPortion: nextArray(Uint32Array),
|
|
75
|
+
eachGeometryIndicesPortion: nextArray(Uint32Array),
|
|
76
|
+
eachGeometryEdgeIndicesPortion: nextArray(Uint32Array),
|
|
77
|
+
eachMeshGeometriesPortion: nextArray(Uint32Array),
|
|
78
|
+
eachMeshMatricesPortion: nextArray(Uint32Array),
|
|
79
|
+
eachMeshTextureSet: nextArray(Int32Array), // Can be -1
|
|
80
|
+
eachMeshMaterialAttributes: nextArray(Uint8Array),
|
|
81
|
+
eachEntityId: nextObject(),
|
|
82
|
+
eachEntityMeshesPortion: nextArray(Uint32Array),
|
|
83
|
+
eachTileAABB: nextArray(Float64Array),
|
|
84
|
+
eachTileEntitiesPortion: nextArray(Uint32Array),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const decompressColor = (function () {
|
|
89
|
+
const floatColor = new Float32Array(3);
|
|
90
|
+
return function (intColor) {
|
|
91
|
+
floatColor[0] = intColor[0] / 255.0;
|
|
92
|
+
floatColor[1] = intColor[1] / 255.0;
|
|
93
|
+
floatColor[2] = intColor[2] / 255.0;
|
|
94
|
+
return floatColor;
|
|
95
|
+
};
|
|
96
|
+
})();
|
|
97
|
+
|
|
98
|
+
const imagDataToImage = (function () {
|
|
99
|
+
const canvas = document.createElement('canvas');
|
|
100
|
+
const context = canvas.getContext('2d');
|
|
101
|
+
return function (imagedata) {
|
|
102
|
+
canvas.width = imagedata.width;
|
|
103
|
+
canvas.height = imagedata.height;
|
|
104
|
+
context.putImageData(imagedata, 0, 0);
|
|
105
|
+
return canvas.toDataURL();
|
|
106
|
+
};
|
|
107
|
+
})();
|
|
108
|
+
|
|
109
|
+
function load(viewer, options, inflatedData, sceneModel, metaModel, manifestCtx) {
|
|
110
|
+
|
|
111
|
+
const modelPartId = manifestCtx.getNextId();
|
|
112
|
+
|
|
113
|
+
const metadata = inflatedData.metadata;
|
|
114
|
+
const textureData = inflatedData.textureData;
|
|
115
|
+
const eachTextureDataPortion = inflatedData.eachTextureDataPortion;
|
|
116
|
+
const eachTextureAttributes = inflatedData.eachTextureAttributes;
|
|
117
|
+
const positions = inflatedData.positions;
|
|
118
|
+
const normals = inflatedData.normals;
|
|
119
|
+
const colors = inflatedData.colors;
|
|
120
|
+
const uvs = inflatedData.uvs;
|
|
121
|
+
const indices = inflatedData.indices;
|
|
122
|
+
const edgeIndices = inflatedData.edgeIndices;
|
|
123
|
+
const eachTextureSetTextures = inflatedData.eachTextureSetTextures;
|
|
124
|
+
const matrices = inflatedData.matrices;
|
|
125
|
+
const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix;
|
|
126
|
+
const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType;
|
|
127
|
+
const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion;
|
|
128
|
+
const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion;
|
|
129
|
+
const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion;
|
|
130
|
+
const eachGeometryUVsPortion = inflatedData.eachGeometryUVsPortion;
|
|
131
|
+
const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion;
|
|
132
|
+
const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion;
|
|
133
|
+
const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion;
|
|
134
|
+
const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion;
|
|
135
|
+
const eachMeshTextureSet = inflatedData.eachMeshTextureSet;
|
|
136
|
+
const eachMeshMaterialAttributes = inflatedData.eachMeshMaterialAttributes;
|
|
137
|
+
const eachEntityId = inflatedData.eachEntityId;
|
|
138
|
+
const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion;
|
|
139
|
+
const eachTileAABB = inflatedData.eachTileAABB;
|
|
140
|
+
const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion;
|
|
141
|
+
|
|
142
|
+
const numTextures = eachTextureDataPortion.length;
|
|
143
|
+
const numTextureSets = eachTextureSetTextures.length / 5;
|
|
144
|
+
const numGeometries = eachGeometryPositionsPortion.length;
|
|
145
|
+
const numMeshes = eachMeshGeometriesPortion.length;
|
|
146
|
+
const numEntities = eachEntityMeshesPortion.length;
|
|
147
|
+
const numTiles = eachTileEntitiesPortion.length;
|
|
148
|
+
|
|
149
|
+
if (metaModel) {
|
|
150
|
+
metaModel.loadData(metadata, {
|
|
151
|
+
includeTypes: options.includeTypes,
|
|
152
|
+
excludeTypes: options.excludeTypes,
|
|
153
|
+
globalizeObjectIds: options.globalizeObjectIds
|
|
154
|
+
}); // Can be empty
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Create textures
|
|
158
|
+
|
|
159
|
+
for (let textureIndex = 0; textureIndex < numTextures; textureIndex++) {
|
|
160
|
+
const atLastTexture = (textureIndex === (numTextures - 1));
|
|
161
|
+
const textureDataPortionStart = eachTextureDataPortion[textureIndex];
|
|
162
|
+
const textureDataPortionEnd = atLastTexture ? textureData.length : (eachTextureDataPortion[textureIndex + 1]);
|
|
163
|
+
|
|
164
|
+
const textureDataPortionSize = textureDataPortionEnd - textureDataPortionStart;
|
|
165
|
+
const textureDataPortionExists = (textureDataPortionSize > 0);
|
|
166
|
+
|
|
167
|
+
const textureAttrBaseIdx = (textureIndex * NUM_TEXTURE_ATTRIBUTES);
|
|
168
|
+
|
|
169
|
+
const compressed = (eachTextureAttributes[textureAttrBaseIdx + 0] === 1);
|
|
170
|
+
const mediaType = eachTextureAttributes[textureAttrBaseIdx + 1];
|
|
171
|
+
const width = eachTextureAttributes[textureAttrBaseIdx + 2];
|
|
172
|
+
const height = eachTextureAttributes[textureAttrBaseIdx + 3];
|
|
173
|
+
const minFilter = eachTextureAttributes[textureAttrBaseIdx + 4];
|
|
174
|
+
const magFilter = eachTextureAttributes[textureAttrBaseIdx + 5]; // LinearFilter | NearestFilter
|
|
175
|
+
const wrapS = eachTextureAttributes[textureAttrBaseIdx + 6]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
|
|
176
|
+
const wrapT = eachTextureAttributes[textureAttrBaseIdx + 7]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
|
|
177
|
+
const wrapR = eachTextureAttributes[textureAttrBaseIdx + 8]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
|
|
178
|
+
|
|
179
|
+
if (textureDataPortionExists) {
|
|
180
|
+
|
|
181
|
+
const imageDataSubarray = new Uint8Array(textureData.subarray(textureDataPortionStart, textureDataPortionEnd));
|
|
182
|
+
const arrayBuffer = imageDataSubarray.buffer;
|
|
183
|
+
const textureId = `${modelPartId}-texture-${textureIndex}`;
|
|
184
|
+
|
|
185
|
+
if (compressed) {
|
|
186
|
+
|
|
187
|
+
sceneModel.createTexture({
|
|
188
|
+
id: textureId,
|
|
189
|
+
buffers: [arrayBuffer],
|
|
190
|
+
minFilter,
|
|
191
|
+
magFilter,
|
|
192
|
+
wrapS,
|
|
193
|
+
wrapT,
|
|
194
|
+
wrapR
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
} else {
|
|
198
|
+
|
|
199
|
+
const mimeType = mediaType === JPEGMediaType ? "image/jpeg" : (mediaType === PNGMediaType ? "image/png" : "image/gif");
|
|
200
|
+
const blob = new Blob([arrayBuffer], {type: mimeType});
|
|
201
|
+
const urlCreator = window.URL || window.webkitURL;
|
|
202
|
+
const imageUrl = urlCreator.createObjectURL(blob);
|
|
203
|
+
const img = document.createElement('img');
|
|
204
|
+
img.src = imageUrl;
|
|
205
|
+
|
|
206
|
+
sceneModel.createTexture({
|
|
207
|
+
id: textureId,
|
|
208
|
+
image: img,
|
|
209
|
+
//mediaType,
|
|
210
|
+
minFilter,
|
|
211
|
+
magFilter,
|
|
212
|
+
wrapS,
|
|
213
|
+
wrapT,
|
|
214
|
+
wrapR
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Create texture sets
|
|
221
|
+
|
|
222
|
+
for (let textureSetIndex = 0; textureSetIndex < numTextureSets; textureSetIndex++) {
|
|
223
|
+
const eachTextureSetTexturesIndex = textureSetIndex * 5;
|
|
224
|
+
const textureSetId = `${modelPartId}-textureSet-${textureSetIndex}`;
|
|
225
|
+
const colorTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 0];
|
|
226
|
+
const metallicRoughnessTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 1];
|
|
227
|
+
const normalsTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 2];
|
|
228
|
+
const emissiveTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 3];
|
|
229
|
+
const occlusionTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 4];
|
|
230
|
+
sceneModel.createTextureSet({
|
|
231
|
+
id: textureSetId,
|
|
232
|
+
colorTextureId: colorTextureIndex >= 0 ? `${modelPartId}-texture-${colorTextureIndex}` : null,
|
|
233
|
+
normalsTextureId: normalsTextureIndex >= 0 ? `${modelPartId}-texture-${normalsTextureIndex}` : null,
|
|
234
|
+
metallicRoughnessTextureId: metallicRoughnessTextureIndex >= 0 ? `${modelPartId}-texture-${metallicRoughnessTextureIndex}` : null,
|
|
235
|
+
emissiveTextureId: emissiveTextureIndex >= 0 ? `${modelPartId}-texture-${emissiveTextureIndex}` : null,
|
|
236
|
+
occlusionTextureId: occlusionTextureIndex >= 0 ? `${modelPartId}-texture-${occlusionTextureIndex}` : null
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Count instances of each geometry
|
|
241
|
+
|
|
242
|
+
const geometryReuseCounts = new Uint32Array(numGeometries);
|
|
243
|
+
|
|
244
|
+
for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) {
|
|
245
|
+
const geometryIndex = eachMeshGeometriesPortion[meshIndex];
|
|
246
|
+
if (geometryReuseCounts[geometryIndex] !== undefined) {
|
|
247
|
+
geometryReuseCounts[geometryIndex]++;
|
|
248
|
+
} else {
|
|
249
|
+
geometryReuseCounts[geometryIndex] = 1;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Iterate over tiles
|
|
254
|
+
|
|
255
|
+
const tileCenter = math.vec3();
|
|
256
|
+
const rtcAABB = math.AABB3();
|
|
257
|
+
|
|
258
|
+
const geometryArraysCache = {};
|
|
259
|
+
|
|
260
|
+
for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) {
|
|
261
|
+
|
|
262
|
+
const lastTileIndex = (numTiles - 1);
|
|
263
|
+
|
|
264
|
+
const atLastTile = (tileIndex === lastTileIndex);
|
|
265
|
+
|
|
266
|
+
const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex];
|
|
267
|
+
const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1);
|
|
268
|
+
|
|
269
|
+
const tileAABBIndex = tileIndex * 6;
|
|
270
|
+
const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6);
|
|
271
|
+
|
|
272
|
+
math.getAABB3Center(tileAABB, tileCenter);
|
|
273
|
+
|
|
274
|
+
rtcAABB[0] = tileAABB[0] - tileCenter[0];
|
|
275
|
+
rtcAABB[1] = tileAABB[1] - tileCenter[1];
|
|
276
|
+
rtcAABB[2] = tileAABB[2] - tileCenter[2];
|
|
277
|
+
rtcAABB[3] = tileAABB[3] - tileCenter[0];
|
|
278
|
+
rtcAABB[4] = tileAABB[4] - tileCenter[1];
|
|
279
|
+
rtcAABB[5] = tileAABB[5] - tileCenter[2];
|
|
280
|
+
|
|
281
|
+
const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB);
|
|
282
|
+
|
|
283
|
+
const geometryCreatedInTile = {};
|
|
284
|
+
|
|
285
|
+
// Iterate over each tile's entities
|
|
286
|
+
|
|
287
|
+
for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) {
|
|
288
|
+
|
|
289
|
+
const xktEntityId = eachEntityId[tileEntityIndex];
|
|
290
|
+
|
|
291
|
+
const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId;
|
|
292
|
+
|
|
293
|
+
const finalTileEntityIndex = (numEntities - 1);
|
|
294
|
+
const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex);
|
|
295
|
+
const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex];
|
|
296
|
+
const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1);
|
|
297
|
+
|
|
298
|
+
const meshIds = [];
|
|
299
|
+
|
|
300
|
+
const metaObject = viewer.metaScene.metaObjects[entityId];
|
|
301
|
+
const entityDefaults = {};
|
|
302
|
+
const meshDefaults = {};
|
|
303
|
+
|
|
304
|
+
if (metaObject) {
|
|
305
|
+
|
|
306
|
+
// Mask loading of object types
|
|
307
|
+
|
|
308
|
+
if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Get initial property values for object types
|
|
317
|
+
|
|
318
|
+
const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null;
|
|
319
|
+
|
|
320
|
+
if (props) {
|
|
321
|
+
if (props.visible === false) {
|
|
322
|
+
entityDefaults.visible = false;
|
|
323
|
+
}
|
|
324
|
+
if (props.pickable === false) {
|
|
325
|
+
entityDefaults.pickable = false;
|
|
326
|
+
}
|
|
327
|
+
if (props.colorize) {
|
|
328
|
+
meshDefaults.color = props.colorize;
|
|
329
|
+
}
|
|
330
|
+
if (props.opacity !== undefined && props.opacity !== null) {
|
|
331
|
+
meshDefaults.opacity = props.opacity;
|
|
332
|
+
}
|
|
333
|
+
if (props.metallic !== undefined && props.metallic !== null) {
|
|
334
|
+
meshDefaults.metallic = props.metallic;
|
|
335
|
+
}
|
|
336
|
+
if (props.roughness !== undefined && props.roughness !== null) {
|
|
337
|
+
meshDefaults.roughness = props.roughness;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
} else {
|
|
342
|
+
if (options.excludeUnclassifiedObjects) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Iterate each entity's meshes
|
|
348
|
+
|
|
349
|
+
for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) {
|
|
350
|
+
|
|
351
|
+
const geometryIndex = eachMeshGeometriesPortion[meshIndex];
|
|
352
|
+
const geometryReuseCount = geometryReuseCounts[geometryIndex];
|
|
353
|
+
const isReusedGeometry = (geometryReuseCount > 1);
|
|
354
|
+
|
|
355
|
+
const atLastGeometry = (geometryIndex === (numGeometries - 1));
|
|
356
|
+
|
|
357
|
+
const textureSetIndex = eachMeshTextureSet[meshIndex];
|
|
358
|
+
|
|
359
|
+
const textureSetId = (textureSetIndex >= 0) ? `${modelPartId}-textureSet-${textureSetIndex}` : null;
|
|
360
|
+
|
|
361
|
+
const meshColor = decompressColor(eachMeshMaterialAttributes.subarray((meshIndex * 6), (meshIndex * 6) + 3));
|
|
362
|
+
const meshOpacity = eachMeshMaterialAttributes[(meshIndex * 6) + 3] / 255.0;
|
|
363
|
+
const meshMetallic = eachMeshMaterialAttributes[(meshIndex * 6) + 4] / 255.0;
|
|
364
|
+
const meshRoughness = eachMeshMaterialAttributes[(meshIndex * 6) + 5] / 255.0;
|
|
365
|
+
|
|
366
|
+
const meshId = manifestCtx.getNextId();
|
|
367
|
+
|
|
368
|
+
if (isReusedGeometry) {
|
|
369
|
+
|
|
370
|
+
// Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry
|
|
371
|
+
|
|
372
|
+
const meshMatrixIndex = eachMeshMatricesPortion[meshIndex];
|
|
373
|
+
const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16);
|
|
374
|
+
|
|
375
|
+
const geometryId = `${modelPartId}-geometry.${tileIndex}.${geometryIndex}`; // These IDs are local to the SceneModel
|
|
376
|
+
|
|
377
|
+
let geometryArrays = geometryArraysCache[geometryId];
|
|
378
|
+
|
|
379
|
+
if (!geometryArrays) {
|
|
380
|
+
geometryArrays = {
|
|
381
|
+
batchThisMesh: (!options.reuseGeometries)
|
|
382
|
+
};
|
|
383
|
+
const primitiveType = eachGeometryPrimitiveType[geometryIndex];
|
|
384
|
+
let geometryValid = false;
|
|
385
|
+
switch (primitiveType) {
|
|
386
|
+
case 0:
|
|
387
|
+
geometryArrays.primitiveName = "solid";
|
|
388
|
+
geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
389
|
+
geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
|
|
390
|
+
geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
|
|
391
|
+
geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
392
|
+
geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
|
|
393
|
+
geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
|
|
394
|
+
break;
|
|
395
|
+
case 1:
|
|
396
|
+
geometryArrays.primitiveName = "surface";
|
|
397
|
+
geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
398
|
+
geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
|
|
399
|
+
geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
|
|
400
|
+
geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
401
|
+
geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
|
|
402
|
+
geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
|
|
403
|
+
break;
|
|
404
|
+
case 2:
|
|
405
|
+
geometryArrays.primitiveName = "points";
|
|
406
|
+
geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
407
|
+
geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]);
|
|
408
|
+
geometryValid = (geometryArrays.geometryPositions.length > 0);
|
|
409
|
+
break;
|
|
410
|
+
case 3:
|
|
411
|
+
geometryArrays.primitiveName = "lines";
|
|
412
|
+
geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
413
|
+
geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
414
|
+
geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
|
|
415
|
+
break;
|
|
416
|
+
case 4:
|
|
417
|
+
geometryArrays.primitiveName = "lines";
|
|
418
|
+
geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
419
|
+
geometryArrays.geometryIndices = lineStripToLines(
|
|
420
|
+
geometryArrays.geometryPositions,
|
|
421
|
+
indices.subarray(eachGeometryIndicesPortion [geometryIndex],
|
|
422
|
+
atLastGeometry
|
|
423
|
+
? indices.length
|
|
424
|
+
: eachGeometryIndicesPortion [geometryIndex + 1]));
|
|
425
|
+
geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
|
|
426
|
+
break;
|
|
427
|
+
default:
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!geometryValid) {
|
|
432
|
+
geometryArrays = null;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (geometryArrays) {
|
|
436
|
+
if (geometryReuseCount > 1000) { // TODO: Heuristic to force batching of instanced geometry beyond a certain reuse count (or budget)?
|
|
437
|
+
// geometryArrays.batchThisMesh = true;
|
|
438
|
+
}
|
|
439
|
+
if (geometryArrays.geometryPositions.length > 1000) { // TODO: Heuristic to force batching on instanced geometry above certain vertex size?
|
|
440
|
+
// geometryArrays.batchThisMesh = true;
|
|
441
|
+
}
|
|
442
|
+
if (geometryArrays.batchThisMesh) {
|
|
443
|
+
geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length);
|
|
444
|
+
geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length)
|
|
445
|
+
const geometryPositions = geometryArrays.geometryPositions;
|
|
446
|
+
const decompressedPositions = geometryArrays.decompressedPositions;
|
|
447
|
+
for (let i = 0, len = geometryPositions.length; i < len; i += 3) {
|
|
448
|
+
decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12];
|
|
449
|
+
decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13];
|
|
450
|
+
decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14];
|
|
451
|
+
}
|
|
452
|
+
geometryArrays.geometryPositions = null;
|
|
453
|
+
geometryArraysCache[geometryId] = geometryArrays;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (geometryArrays) {
|
|
459
|
+
|
|
460
|
+
if (geometryArrays.batchThisMesh) {
|
|
461
|
+
|
|
462
|
+
const decompressedPositions = geometryArrays.decompressedPositions;
|
|
463
|
+
const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions;
|
|
464
|
+
|
|
465
|
+
for (let i = 0, len = decompressedPositions.length; i < len; i += 3) {
|
|
466
|
+
tempVec4a[0] = decompressedPositions[i + 0];
|
|
467
|
+
tempVec4a[1] = decompressedPositions[i + 1];
|
|
468
|
+
tempVec4a[2] = decompressedPositions[i + 2];
|
|
469
|
+
tempVec4a[3] = 1;
|
|
470
|
+
math.transformVec4(meshMatrix, tempVec4a, tempVec4b);
|
|
471
|
+
geometryCompressionUtils.compressPosition(tempVec4b, rtcAABB, tempVec4a)
|
|
472
|
+
transformedAndRecompressedPositions[i + 0] = tempVec4a[0];
|
|
473
|
+
transformedAndRecompressedPositions[i + 1] = tempVec4a[1];
|
|
474
|
+
transformedAndRecompressedPositions[i + 2] = tempVec4a[2];
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
sceneModel.createMesh(utils.apply(meshDefaults, {
|
|
478
|
+
id: meshId,
|
|
479
|
+
textureSetId,
|
|
480
|
+
origin: tileCenter,
|
|
481
|
+
primitive: geometryArrays.primitiveName,
|
|
482
|
+
positionsCompressed: transformedAndRecompressedPositions,
|
|
483
|
+
normalsCompressed: geometryArrays.geometryNormals,
|
|
484
|
+
uv: geometryArrays.geometryUVs,
|
|
485
|
+
colorsCompressed: geometryArrays.geometryColors,
|
|
486
|
+
indices: geometryArrays.geometryIndices,
|
|
487
|
+
edgeIndices: geometryArrays.geometryEdgeIndices,
|
|
488
|
+
positionsDecodeMatrix: tileDecodeMatrix,
|
|
489
|
+
color: meshColor,
|
|
490
|
+
metallic: meshMetallic,
|
|
491
|
+
roughness: meshRoughness,
|
|
492
|
+
opacity: meshOpacity
|
|
493
|
+
}));
|
|
494
|
+
|
|
495
|
+
meshIds.push(meshId);
|
|
496
|
+
|
|
497
|
+
} else {
|
|
498
|
+
|
|
499
|
+
if (!geometryCreatedInTile[geometryId]) {
|
|
500
|
+
|
|
501
|
+
sceneModel.createGeometry({
|
|
502
|
+
id: geometryId,
|
|
503
|
+
primitive: geometryArrays.primitiveName,
|
|
504
|
+
positionsCompressed: geometryArrays.geometryPositions,
|
|
505
|
+
normalsCompressed: geometryArrays.geometryNormals,
|
|
506
|
+
uv: geometryArrays.geometryUVs,
|
|
507
|
+
colorsCompressed: geometryArrays.geometryColors,
|
|
508
|
+
indices: geometryArrays.geometryIndices,
|
|
509
|
+
edgeIndices: geometryArrays.geometryEdgeIndices,
|
|
510
|
+
positionsDecodeMatrix: reusedGeometriesDecodeMatrix
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
geometryCreatedInTile[geometryId] = true;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
sceneModel.createMesh(utils.apply(meshDefaults, {
|
|
517
|
+
id: meshId,
|
|
518
|
+
geometryId,
|
|
519
|
+
textureSetId,
|
|
520
|
+
matrix: meshMatrix,
|
|
521
|
+
color: meshColor,
|
|
522
|
+
metallic: meshMetallic,
|
|
523
|
+
roughness: meshRoughness,
|
|
524
|
+
opacity: meshOpacity,
|
|
525
|
+
origin: tileCenter
|
|
526
|
+
}));
|
|
527
|
+
|
|
528
|
+
meshIds.push(meshId);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
} else { // Do not reuse geometry
|
|
533
|
+
|
|
534
|
+
const primitiveType = eachGeometryPrimitiveType[geometryIndex];
|
|
535
|
+
|
|
536
|
+
let primitiveName;
|
|
537
|
+
let geometryPositions;
|
|
538
|
+
let geometryNormals;
|
|
539
|
+
let geometryUVs;
|
|
540
|
+
let geometryColors;
|
|
541
|
+
let geometryIndices;
|
|
542
|
+
let geometryEdgeIndices;
|
|
543
|
+
let geometryValid = false;
|
|
544
|
+
|
|
545
|
+
switch (primitiveType) {
|
|
546
|
+
case 0:
|
|
547
|
+
primitiveName = "solid";
|
|
548
|
+
geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
549
|
+
geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
|
|
550
|
+
geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
|
|
551
|
+
geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
552
|
+
geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
|
|
553
|
+
geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
|
|
554
|
+
break;
|
|
555
|
+
case 1:
|
|
556
|
+
primitiveName = "surface";
|
|
557
|
+
geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
558
|
+
geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
|
|
559
|
+
geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
|
|
560
|
+
geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
561
|
+
geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
|
|
562
|
+
geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
|
|
563
|
+
break;
|
|
564
|
+
case 2:
|
|
565
|
+
primitiveName = "points";
|
|
566
|
+
geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
567
|
+
geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]);
|
|
568
|
+
geometryValid = (geometryPositions.length > 0);
|
|
569
|
+
break;
|
|
570
|
+
case 3:
|
|
571
|
+
primitiveName = "lines";
|
|
572
|
+
geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
573
|
+
geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
|
|
574
|
+
geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
|
|
575
|
+
break;
|
|
576
|
+
case 4:
|
|
577
|
+
primitiveName = "lines";
|
|
578
|
+
geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
|
|
579
|
+
geometryIndices = lineStripToLines(
|
|
580
|
+
geometryPositions,
|
|
581
|
+
indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry
|
|
582
|
+
? indices.length
|
|
583
|
+
: eachGeometryIndicesPortion [geometryIndex + 1]));
|
|
584
|
+
geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
|
|
585
|
+
break;
|
|
586
|
+
default:
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (geometryValid) {
|
|
591
|
+
|
|
592
|
+
sceneModel.createMesh(utils.apply(meshDefaults, {
|
|
593
|
+
id: meshId,
|
|
594
|
+
textureSetId,
|
|
595
|
+
origin: tileCenter,
|
|
596
|
+
primitive: primitiveName,
|
|
597
|
+
positionsCompressed: geometryPositions,
|
|
598
|
+
normalsCompressed: geometryNormals,
|
|
599
|
+
uv: geometryUVs && geometryUVs.length > 0 ? geometryUVs : null,
|
|
600
|
+
colorsCompressed: geometryColors,
|
|
601
|
+
indices: geometryIndices,
|
|
602
|
+
edgeIndices: geometryEdgeIndices,
|
|
603
|
+
positionsDecodeMatrix: tileDecodeMatrix,
|
|
604
|
+
color: meshColor,
|
|
605
|
+
metallic: meshMetallic,
|
|
606
|
+
roughness: meshRoughness,
|
|
607
|
+
opacity: meshOpacity
|
|
608
|
+
}));
|
|
609
|
+
|
|
610
|
+
meshIds.push(meshId);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (meshIds.length > 0) {
|
|
616
|
+
|
|
617
|
+
sceneModel.createEntity(utils.apply(entityDefaults, {
|
|
618
|
+
id: entityId,
|
|
619
|
+
isObject: true,
|
|
620
|
+
meshIds: meshIds
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function lineStripToLines(positions, indices) {
|
|
628
|
+
const linesIndices = [];
|
|
629
|
+
if (indices.length > 1) {
|
|
630
|
+
for (let i = 0, len = indices.length - 1; i < len; i++) {
|
|
631
|
+
linesIndices.push(indices[i]);
|
|
632
|
+
linesIndices.push(indices[i + 1]);
|
|
633
|
+
}
|
|
634
|
+
} else if (positions.length > 1) {
|
|
635
|
+
for (let i = 0, len = (positions.length / 3) - 1; i < len; i++) {
|
|
636
|
+
linesIndices.push(i);
|
|
637
|
+
linesIndices.push(i + 1);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return linesIndices;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/** @private */
|
|
644
|
+
// V11 uses a single uncompressed Uint8Array buffer to store arrays of different types.
|
|
645
|
+
// To efficiently create typed arrays from this buffer,
|
|
646
|
+
// each typed array's source data needs to be aligned with its element byte size.
|
|
647
|
+
// This sometimes requires padding subarrays inside the single Uint8Array, so the byteOffset needs to be stored alongside element count.
|
|
648
|
+
// It is a different encoding than used in earlier versions, and requires different approach to parsing elements.
|
|
649
|
+
const ParserV11 = {
|
|
650
|
+
version: 11,
|
|
651
|
+
parseArrayBuffer: function (viewer, options, arrayBuffer, sceneModel, metaModel, manifestCtx) {
|
|
652
|
+
const inflatedData = decodeData(arrayBuffer);
|
|
653
|
+
load(viewer, options, inflatedData, sceneModel, metaModel, manifestCtx);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
export {ParserV11};
|