@xeokit/xeokit-sdk 2.6.29 → 2.6.31

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 (35) hide show
  1. package/dist/xeokit-sdk.cjs.js +635 -468
  2. package/dist/xeokit-sdk.es.js +635 -468
  3. package/dist/xeokit-sdk.es5.js +318 -330
  4. package/dist/xeokit-sdk.min.cjs.js +4 -4
  5. package/dist/xeokit-sdk.min.es.js +5 -5
  6. package/dist/xeokit-sdk.min.es5.js +3 -3
  7. package/package.json +1 -1
  8. package/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js +110 -33
  9. package/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js +2 -110
  10. package/src/plugins/GLTFLoaderPlugin/GLTFSceneModelLoader.js +257 -222
  11. package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +1 -1
  12. package/src/viewer/metadata/MetaScene.js +0 -2
  13. package/src/viewer/scene/model/SceneModel.js +9 -0
  14. package/src/viewer/scene/model/SceneModelTextureSet.js +5 -0
  15. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapInitRenderer.js +8 -0
  16. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapRenderer.js +8 -0
  17. package/src/viewer/scene/model/vbo/VBORenderer.js +10 -1
  18. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +1 -1
  19. package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +26 -6
  20. package/src/viewer/scene/model/vbo/batching/triangles/renderers/Renderers.js +40 -12
  21. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesBatchingRenderer.js +2 -3
  22. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorTextureRenderer.js +25 -7
  23. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +1 -1
  24. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +1 -1
  25. package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +17 -4
  26. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/Renderers.js +74 -47
  27. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorTextureRenderer.js +29 -14
  28. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesInstancingRenderer.js +5 -4
  29. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +1 -1
  30. package/src/viewer/scene/webgl/Renderer.js +6 -3
  31. package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
  32. package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +1 -4
  33. package/types/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.d.ts +5 -3
  34. package/types/plugins/LASLoaderPlugin/LASLoaderPlugin.d.ts +2 -2
  35. package/types/plugins/OBJLoaderPlugin/OBJLoaderPlugin.d.ts +3 -3
@@ -5,6 +5,7 @@ import {sRGBEncoding} from "../../viewer/scene/constants/constants.js";
5
5
  import {worldToRTCPositions} from "../../viewer/scene/math/rtcCoords.js";
6
6
  import {parse} from '@loaders.gl/core';
7
7
  import {GLTFLoader} from '@loaders.gl/gltf/dist/esm/gltf-loader.js';
8
+
8
9
  import {
9
10
  ClampToEdgeWrapping,
10
11
  LinearFilter,
@@ -65,42 +66,6 @@ class GLTFSceneModelLoader {
65
66
  }
66
67
  }
67
68
 
68
- function getMetaModelCorrections(metaModelJSON) {
69
- const eachRootStats = {};
70
- const eachChildRoot = {};
71
- const metaObjects = metaModelJSON.metaObjects || [];
72
- const metaObjectsMap = {};
73
- for (let i = 0, len = metaObjects.length; i < len; i++) {
74
- const metaObject = metaObjects[i];
75
- metaObjectsMap[metaObject.id] = metaObject;
76
- }
77
- for (let i = 0, len = metaObjects.length; i < len; i++) {
78
- const metaObject = metaObjects[i];
79
- if (metaObject.parent !== undefined && metaObject.parent !== null) {
80
- const metaObjectParent = metaObjectsMap[metaObject.parent];
81
- if (metaObject.type === metaObjectParent.type) {
82
- let rootMetaObject = metaObjectParent;
83
- while (rootMetaObject.parent && metaObjectsMap[rootMetaObject.parent].type === rootMetaObject.type) {
84
- rootMetaObject = metaObjectsMap[rootMetaObject.parent];
85
- }
86
- const rootStats = eachRootStats[rootMetaObject.id] || (eachRootStats[rootMetaObject.id] = {
87
- numChildren: 0,
88
- countChildren: 0
89
- });
90
- rootStats.numChildren++;
91
- eachChildRoot[metaObject.id] = rootMetaObject;
92
- } else {
93
-
94
- }
95
- }
96
- }
97
- return {
98
- metaObjectsMap,
99
- eachRootStats,
100
- eachChildRoot
101
- };
102
- }
103
-
104
69
  function loadGLTF(plugin, src, metaModelJSON, options, sceneModel, ok, error) {
105
70
  const spinner = plugin.viewer.scene.canvas.spinner;
106
71
  spinner.processes++;
@@ -142,7 +107,9 @@ function parseGLTF(plugin, src, gltf, metaModelJSON, options, sceneModel, ok) {
142
107
  const ctx = {
143
108
  src: src,
144
109
  entityId: options.entityId,
145
- metaModelCorrections: metaModelJSON ? getMetaModelCorrections(metaModelJSON) : null,
110
+ metaModelJSON,
111
+ autoMetaModel: options.autoMetaModel,
112
+ metaObjects: [],
146
113
  loadBuffer: options.loadBuffer,
147
114
  basePath: options.basePath,
148
115
  handlenode: options.handlenode,
@@ -161,8 +128,20 @@ function parseGLTF(plugin, src, gltf, metaModelJSON, options, sceneModel, ok) {
161
128
  };
162
129
  loadTextures(ctx);
163
130
  loadMaterials(ctx);
131
+ if (options.autoMetaModel) {
132
+ ctx.metaObjects.push({
133
+ id: sceneModel.id,
134
+ type: "Default",
135
+ name: sceneModel.id
136
+ });
137
+ }
164
138
  loadDefaultScene(ctx);
165
139
  sceneModel.finalize();
140
+ if (options.autoMetaModel) {
141
+ plugin.viewer.metaScene.createMetaModel(sceneModel.id, {
142
+ metaObjects: ctx.metaObjects
143
+ });
144
+ }
166
145
  spinner.processes--;
167
146
  ok();
168
147
  });
@@ -291,23 +270,21 @@ function loadTextureSet(ctx, material) {
291
270
  if (material.emissiveTexture) {
292
271
  textureSetCfg.emissiveTextureId = material.emissiveTexture.texture._textureId;
293
272
  }
294
- // const alphaMode = material.alphaMode;
295
- // switch (alphaMode) {
296
- // case "NORMAL_OPAQUE":
297
- // materialCfg.alphaMode = "opaque";
298
- // break;
299
- // case "MASK":
300
- // materialCfg.alphaMode = "mask";
301
- // break;
302
- // case "BLEND":
303
- // materialCfg.alphaMode = "blend";
304
- // break;
305
- // default:
306
- // }
307
- // const alphaCutoff = material.alphaCutoff;
308
- // if (alphaCutoff !== undefined) {
309
- // materialCfg.alphaCutoff = alphaCutoff;
310
- // }
273
+
274
+ switch (material.alphaMode) {
275
+ case "OPAQUE":
276
+ break;
277
+ case "MASK":
278
+ const alphaCutoff = material.alphaCutoff;
279
+ // Default from the spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material
280
+ textureSetCfg.alphaCutoff = (alphaCutoff !== undefined) ? alphaCutoff : 0.5;
281
+ break;
282
+ case "BLEND":
283
+ break;
284
+ default:
285
+ break;
286
+ }
287
+
311
288
  const metallicPBR = material.pbrMetallicRoughness;
312
289
  if (material.pbrMetallicRoughness) {
313
290
  const pbrMetallicRoughness = material.pbrMetallicRoughness;
@@ -356,7 +333,7 @@ function loadMaterialAttributes(ctx, material) { // Substitute RGBA for material
356
333
  opacity: 1,
357
334
  metallic: 0,
358
335
  roughness: 1,
359
- doubleSided : true
336
+ doubleSided: true
360
337
  };
361
338
  if (extensions) {
362
339
  const specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"];
@@ -430,9 +407,22 @@ function loadScene(ctx, scene) {
430
407
  const node = nodes[i];
431
408
  countMeshUsage(ctx, node);
432
409
  }
433
- for (let i = 0, len = nodes.length; i < len; i++) {
410
+ for (let i = 0, len = nodes.length; i < len && !ctx.nodesHaveNames; i++) {
434
411
  const node = nodes[i];
435
- loadNode(ctx, node, 0, null);
412
+ if (testIfNodesHaveNames(node)) {
413
+ ctx.nodesHaveNames = true;
414
+ }
415
+ }
416
+ if (!ctx.nodesHaveNames) {
417
+ for (let i = 0, len = nodes.length; i < len; i++) {
418
+ const node = nodes[i];
419
+ parseNodesWithoutNames(ctx, node, 0, null);
420
+ }
421
+ } else {
422
+ for (let i = 0, len = nodes.length; i < len; i++) {
423
+ const node = nodes[i];
424
+ parseNodesWithNames(ctx, node, 0, null);
425
+ }
436
426
  }
437
427
  }
438
428
 
@@ -454,10 +444,133 @@ function countMeshUsage(ctx, node) {
454
444
  }
455
445
  }
456
446
 
457
- const deferredMeshIds = [];
447
+ function testIfNodesHaveNames(node) {
448
+ if (node.name) {
449
+ return true;
450
+ }
451
+ if (node.children) {
452
+ const children = node.children;
453
+ for (let i = 0, len = children.length; i < len; i++) {
454
+ const childNode = children[i];
455
+ if (testIfNodesHaveNames(childNode)) {
456
+ return true;
457
+ }
458
+ }
459
+ }
460
+ return false;
461
+ }
462
+
463
+ /**
464
+ * Parses a glTF node hierarchy that is known to NOT contain "name" attributes on the nodes.
465
+ * Create a SceneMesh for each mesh primitive, and a single SceneObject.
466
+ */
467
+ const parseNodesWithoutNames = (function () {
468
+ const meshIds = [];
469
+ return function (ctx, node, depth, matrix, parentNode) {
470
+ matrix = parseNodeMatrix(node, matrix);
471
+ if (node.mesh) {
472
+ parseNodeMesh(node, ctx, matrix, meshIds);
473
+ }
474
+ if (node.children) {
475
+ const children = node.children;
476
+ for (let i = 0, len = children.length; i < len; i++) {
477
+ const childNode = children[i];
478
+ parseNodesWithoutNames(ctx, childNode, depth + 1, matrix, node);
479
+ }
480
+ }
481
+ if (depth === 0) {
482
+ let entityId = "entity-" + ctx.nextId++;
483
+ if (meshIds && meshIds.length > 0) {
484
+ ctx.sceneModel.createEntity({
485
+ id: entityId,
486
+ meshIds,
487
+ isObject: true
488
+ });
489
+ if (ctx.autoMetaModel) {
490
+ ctx.metaObjects.push({
491
+ id: entityId,
492
+ type: "Default",
493
+ name: entityId,
494
+ parent: ctx.sceneModel.id
495
+ });
496
+ }
497
+ meshIds.length = 0;
498
+ }
499
+ }
500
+ }
501
+ })();
502
+
503
+ const parseNodesWithNames = (function () {
458
504
 
459
- function loadNode(ctx, node, depth, matrix) {
460
- const gltfData = ctx.gltfData;
505
+ const objectIdStack = [];
506
+ const meshIdsStack = [];
507
+ let meshIds = [];
508
+
509
+ return function (ctx, node, depth, matrix) {
510
+ matrix = parseNodeMatrix(node, matrix);
511
+ if (meshIds && node.mesh) {
512
+ parseNodeMesh(node, ctx, matrix, meshIds);
513
+ }
514
+
515
+ if (node.name) {
516
+ meshIds = [];
517
+ let entityId = node.name;
518
+ if (!!entityId && ctx.sceneModel.objects[entityId]) {
519
+ // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${entityId} - will randomly-generating an object ID in XKT`);
520
+ }
521
+ while (!entityId || ctx.sceneModel.objects[entityId]) {
522
+ entityId = "entity-" + ctx.nextId++;
523
+ }
524
+ objectIdStack.push(entityId);
525
+ meshIdsStack.push(meshIds);
526
+ }
527
+
528
+ if (node.children) {
529
+ const children = node.children;
530
+ for (let i = 0, len = children.length; i < len; i++) {
531
+ const childNode = children[i];
532
+ parseNodesWithNames(ctx, childNode, depth + 1, matrix);
533
+ }
534
+ }
535
+
536
+ // Post-order visit scene node
537
+
538
+ const nodeName = node.name;
539
+ if ((nodeName !== undefined && nodeName !== null) || depth === 0) {
540
+ let entityId = objectIdStack.pop();
541
+ if (!entityId) { // For when there are no nodes with names
542
+ entityId = "entity-" + ctx.nextId++;
543
+ }
544
+ let entityMeshIds = meshIdsStack.pop();
545
+ if (meshIds && meshIds.length > 0) {
546
+ ctx.sceneModel.createEntity({
547
+ id: entityId,
548
+ meshIds: entityMeshIds,
549
+ isObject: true
550
+ });
551
+ if (ctx.autoMetaModel) {
552
+ ctx.metaObjects.push({
553
+ id: entityId,
554
+ type: "Default",
555
+ name: entityId,
556
+ parent: ctx.sceneModel.id
557
+ });
558
+ }
559
+ }
560
+ meshIds = meshIdsStack.length > 0 ? meshIdsStack[meshIdsStack.length - 1] : null;
561
+ }
562
+ };
563
+ })();
564
+
565
+
566
+ /**
567
+ * Parses transform at the given glTF node.
568
+ *
569
+ * @param node the glTF node
570
+ * @param matrix Transfor matrix from parent nodes
571
+ * @returns {*} Transform matrix for the node
572
+ */
573
+ function parseNodeMatrix(node, matrix) {
461
574
  let localMatrix;
462
575
  if (node.matrix) {
463
576
  localMatrix = node.matrix;
@@ -491,174 +604,96 @@ function loadNode(ctx, node, depth, matrix) {
491
604
  matrix = localMatrix;
492
605
  }
493
606
  }
607
+ return matrix;
608
+ }
494
609
 
495
- const sceneModel = ctx.sceneModel;
496
- if (node.mesh) {
497
- const mesh = node.mesh;
498
- let createEntity;
499
- if (ctx.handlenode) {
500
- const actions = {};
501
- if (!ctx.handlenode(ctx.sceneModel.id, node, actions)) {
502
- return;
610
+ /**
611
+ * Parses primitives referenced by the mesh belonging to the given node, creating XKTMeshes in the XKTModel.
612
+ *
613
+ * @param node glTF node
614
+ * @param ctx Parsing context
615
+ * @param matrix Matrix for the XKTMeshes
616
+ * @param meshIds returns IDs of the new XKTMeshes
617
+ */
618
+ function parseNodeMesh(node, ctx, matrix, meshIds) {
619
+ const mesh = node.mesh;
620
+ if (!mesh) {
621
+ return;
622
+ }
623
+ const numPrimitives = mesh.primitives.length;
624
+ if (numPrimitives > 0) {
625
+ for (let i = 0; i < numPrimitives; i++) {
626
+ const primitive = mesh.primitives[i];
627
+ if (primitive.mode < 4) {
628
+ continue;
503
629
  }
504
- if (actions.createEntity) {
505
- createEntity = actions.createEntity;
630
+ const meshCfg = {
631
+ id: ctx.sceneModel.id + "." + ctx.numObjects++
632
+ };
633
+ const material = primitive.material;
634
+ if (material) {
635
+ meshCfg.textureSetId = material._textureSetId;
636
+ meshCfg.color = material._attributes.color;
637
+ meshCfg.opacity = material._attributes.opacity;
638
+ meshCfg.metallic = material._attributes.metallic;
639
+ meshCfg.roughness = material._attributes.roughness;
640
+ } else {
641
+ meshCfg.color = new Float32Array([1.0, 1.0, 1.0]);
642
+ meshCfg.opacity = 1.0;
506
643
  }
507
- }
508
- const worldMatrix = matrix ? matrix.slice() : math.identityMat4();
509
- const numPrimitives = mesh.primitives.length;
510
-
511
- if (numPrimitives > 0) {
512
-
513
- for (let i = 0; i < numPrimitives; i++) {
514
-
515
- const primitive = mesh.primitives[i];
516
- if (primitive.mode < 4) {
517
- continue;
518
- }
519
-
520
- const meshCfg = {
521
- id: sceneModel.id + "." + ctx.numObjects++
522
- };
523
-
524
- const material = primitive.material;
525
- if (material) {
526
- meshCfg.textureSetId = material._textureSetId;
527
- meshCfg.color = material._attributes.color;
528
- meshCfg.opacity = material._attributes.opacity;
529
- meshCfg.metallic = material._attributes.metallic;
530
- meshCfg.roughness = material._attributes.roughness;
531
- } else {
532
- meshCfg.color = new Float32Array([1.0, 1.0, 1.0]);
533
- meshCfg.opacity = 1.0;
534
- }
535
-
536
- const backfaces = ((ctx.backfaces !== false) || (material && material.doubleSided !== false));
537
-
538
- switch (primitive.mode) {
539
- case 0: // POINTS
540
- meshCfg.primitive = "points";
541
- break;
542
- case 1: // LINES
543
- meshCfg.primitive = "lines";
544
- break;
545
- case 2: // LINE_LOOP
546
- meshCfg.primitive = "lines";
547
- break;
548
- case 3: // LINE_STRIP
549
- meshCfg.primitive = "lines";
550
- break;
551
- case 4: // TRIANGLES
552
- meshCfg.primitive = backfaces ? "triangles" : "solid";
553
- break;
554
- case 5: // TRIANGLE_STRIP
555
- meshCfg.primitive = backfaces ? "triangles" : "solid";
556
- break;
557
- case 6: // TRIANGLE_FAN
558
- meshCfg.primitive = backfaces ? "triangles" : "solid";
559
- break;
560
- default:
561
- meshCfg.primitive = backfaces ? "triangles" : "solid";
562
- }
563
-
564
- const POSITION = primitive.attributes.POSITION;
565
- if (!POSITION) {
566
- continue;
567
- }
568
- meshCfg.localPositions = POSITION.value;
569
- meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
570
-
571
- if (primitive.attributes.NORMAL) {
572
- meshCfg.normals = primitive.attributes.NORMAL.value;
573
- }
574
-
575
- if (primitive.attributes.TEXCOORD_0) {
576
- meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
577
- }
578
-
579
- if (primitive.indices) {
580
- meshCfg.indices = primitive.indices.value;
581
- }
582
-
583
- math.transformPositions3(worldMatrix, meshCfg.localPositions, meshCfg.positions);
584
- const origin = math.vec3();
585
- const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy
586
- if (rtcNeeded) {
587
- meshCfg.origin = origin;
588
- }
589
-
590
- sceneModel.createMesh(meshCfg);
591
- deferredMeshIds.push(meshCfg.id);
644
+ const backfaces = ((ctx.backfaces !== false) || (material && material.doubleSided !== false));
645
+ switch (primitive.mode) {
646
+ case 0: // POINTS
647
+ meshCfg.primitive = "points";
648
+ break;
649
+ case 1: // LINES
650
+ meshCfg.primitive = "lines";
651
+ break;
652
+ case 2: // LINE_LOOP
653
+ meshCfg.primitive = "lines";
654
+ break;
655
+ case 3: // LINE_STRIP
656
+ meshCfg.primitive = "lines";
657
+ break;
658
+ case 4: // TRIANGLES
659
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
660
+ break;
661
+ case 5: // TRIANGLE_STRIP
662
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
663
+ break;
664
+ case 6: // TRIANGLE_FAN
665
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
666
+ break;
667
+ default:
668
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
592
669
  }
593
- }
594
- }
595
-
596
- if (node.children) {
597
- const children = node.children;
598
- for (let i = 0, len = children.length; i < len; i++) {
599
- const childNode = children[i];
600
- loadNode(ctx, childNode, depth + 1, matrix);
601
- }
602
- }
603
-
604
- // Post-order visit scene node
605
-
606
- if (ctx.entityId) {
607
- if (depth ===0) {
608
- sceneModel.createEntity({
609
- id: ctx.entityId,
610
- meshIds: deferredMeshIds,
611
- isObject: true
612
- });
613
- deferredMeshIds.length = 0;
614
- }
615
- } else {
616
- const nodeName = node.name;
617
- if (((nodeName !== undefined && nodeName !== null) || depth === 0) && deferredMeshIds.length > 0) {
618
- if (nodeName === undefined || nodeName === null) {
619
- ctx.log(`Warning: 'name' properties not found on glTF scene nodes - will randomly-generate object IDs in XKT`);
670
+ const POSITION = primitive.attributes.POSITION;
671
+ if (!POSITION) {
672
+ continue;
620
673
  }
621
- let entityId = nodeName; // Fall back on generated ID when `name` not found on glTF scene node(s)
622
- // if (!!entityId && sceneModel.entities[entityId]) {
623
- // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${nodeName} - will randomly-generating an object ID in XKT`);
624
- // }
625
- // while (!entityId || sceneModel.entities[entityId]) {
626
- // entityId = "entity-" + ctx.nextId++;
627
- // }
628
- if (ctx.metaModelCorrections) {
629
- // Merging meshes into XKTObjects that map to metaobjects
630
- const rootMetaObject = ctx.metaModelCorrections.eachChildRoot[entityId];
631
- if (rootMetaObject) {
632
- const rootMetaObjectStats = ctx.metaModelCorrections.eachRootStats[rootMetaObject.id];
633
- rootMetaObjectStats.countChildren++;
634
- if (rootMetaObjectStats.countChildren >= rootMetaObjectStats.numChildren) {
635
- sceneModel.createEntity({
636
- id: rootMetaObject.id,
637
- meshIds: deferredMeshIds,
638
- isObject: true
639
- });
640
- deferredMeshIds.length = 0;
641
- }
642
- } else {
643
- const metaObject = ctx.metaModelCorrections.metaObjectsMap[entityId];
644
- if (metaObject) {
645
- sceneModel.createEntity({
646
- id: entityId,
647
- meshIds: deferredMeshIds,
648
- isObject: true
649
- });
650
- deferredMeshIds.length = 0;
651
- }
652
- }
653
- } else {
654
- // Create an XKTObject from the meshes at each named glTF node, don't care about metaobjects
655
- sceneModel.createEntity({
656
- id: entityId,
657
- meshIds: deferredMeshIds,
658
- isObject: true
659
- });
660
- deferredMeshIds.length = 0;
674
+ meshCfg.localPositions = POSITION.value;
675
+ meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
676
+ if (primitive.attributes.NORMAL) {
677
+ meshCfg.normals = primitive.attributes.NORMAL.value;
678
+ }
679
+ if (primitive.attributes.TEXCOORD_0) {
680
+ meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
681
+ }
682
+ if (primitive.indices) {
683
+ meshCfg.indices = primitive.indices.value;
684
+ }
685
+ if (matrix) {
686
+ math.transformPositions3(matrix, meshCfg.localPositions, meshCfg.positions);
687
+ } else { // eqiv to math.transformPositions3(math.identityMat4(), meshCfg.localPositions, meshCfg.positions);
688
+ meshCfg.positions.set(meshCfg.localPositions);
689
+ }
690
+ const origin = math.vec3();
691
+ const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy
692
+ if (rtcNeeded) {
693
+ meshCfg.origin = origin;
661
694
  }
695
+ ctx.sceneModel.createMesh(meshCfg);
696
+ meshIds.push(meshCfg.id);
662
697
  }
663
698
  }
664
699
  }
@@ -990,7 +990,7 @@ export class TreeViewPlugin extends Plugin {
990
990
  this._nodeNodes[buildingNode.nodeId] = buildingNode;
991
991
  } else if (metaObjectType === "IfcBuildingStorey") {
992
992
  if (!buildingNode) {
993
- this.error("Failed to build storeys hierarchy for model '" + this.metaModel.id + "' - model does not have an IfcBuilding object, or is not an IFC model");
993
+ this.error("Failed to build storeys hierarchy for model - model does not have an IfcBuilding object, or is not an IFC model");
994
994
  return;
995
995
  }
996
996
  storeyNode = {
@@ -126,8 +126,6 @@ class MetaScene {
126
126
  * @param {String} modelId ID for the new {@link MetaModel}, which will have {@link MetaModel#id} set to this value.
127
127
  * @param {Object} metaModelData Data for the {@link MetaModel}.
128
128
  * @param {Object} [options] Options for creating the {@link MetaModel}.
129
- * @param {Object} [options.includeTypes] When provided, only create {@link MetaObject}s with types in this list.
130
- * @param {Object} [options.excludeTypes] When provided, never create {@link MetaObject}s with types in this list.
131
129
  * @param {Boolean} [options.globalizeObjectIds=false] Whether to globalize each {@link MetaObject#id}. Set this ````true```` when you need to load multiple instances of the same meta model, to avoid ID clashes between the meta objects in the different instances.
132
130
  * @returns {MetaModel} The new MetaModel.
133
131
  */
@@ -2644,6 +2644,7 @@ export class SceneModel extends Component {
2644
2644
  id: textureSetId,
2645
2645
  model: this,
2646
2646
  colorTexture,
2647
+ alphaCutoff: cfg.alphaCutoff,
2647
2648
  metallicRoughnessTexture,
2648
2649
  normalsTexture,
2649
2650
  emissiveTexture,
@@ -3077,6 +3078,14 @@ export class SceneModel extends Component {
3077
3078
  return this._createMesh(cfg);
3078
3079
  }
3079
3080
 
3081
+ _createDefaultIndices(numIndices) {
3082
+ const indices = [];
3083
+ for (let i = 0; i < numIndices; i++) {
3084
+ indices.push(i);
3085
+ }
3086
+ return indices;
3087
+ }
3088
+
3080
3089
  _createMesh(cfg) {
3081
3090
  const mesh = new SceneModelMesh(this, cfg.id, cfg.color, cfg.opacity, cfg.transform, cfg.textureSet);
3082
3091
  mesh.pickId = this.scene._renderer.getPickID(mesh);
@@ -26,6 +26,11 @@ export class SceneModelTextureSet {
26
26
  */
27
27
  this.colorTexture = cfg.colorTexture;
28
28
 
29
+ /**
30
+ * The alpha cutoff [float]
31
+ */
32
+ this.alphaCutoff = cfg.alphaCutoff;
33
+
29
34
  /**
30
35
  * The metallic-roughness texture.
31
36
  * @type {SceneModelTexture|*}
@@ -304,6 +304,14 @@ export class DTXTrianglesSnapInitRenderer {
304
304
  src.push("uvec4 flags = texelFetch (uObjectPerObjectColorsAndFlags, ivec2(objectIndexCoords.x*8+2, objectIndexCoords.y), 0);");
305
305
  src.push("uvec4 flags2 = texelFetch (uObjectPerObjectColorsAndFlags, ivec2(objectIndexCoords.x*8+3, objectIndexCoords.y), 0);");
306
306
 
307
+ // flags.w = NOT_RENDERED | PICK
308
+ // renderPass = PICK
309
+
310
+ src.push(`if (int(flags.w) != renderPass) {`);
311
+ src.push(" gl_Position = vec4(3.0, 3.0, 3.0, 1.0);"); // Cull vertex
312
+ src.push(" return;"); // Cull vertex
313
+ src.push("}");
314
+
307
315
  src.push("{");
308
316
 
309
317
  // get color
@@ -311,6 +311,14 @@ export class DTXTrianglesSnapRenderer {
311
311
  src.push("uvec4 flags = texelFetch (uObjectPerObjectColorsAndFlags, ivec2(objectIndexCoords.x*8+2, objectIndexCoords.y), 0);");
312
312
  src.push("uvec4 flags2 = texelFetch (uObjectPerObjectColorsAndFlags, ivec2(objectIndexCoords.x*8+3, objectIndexCoords.y), 0);");
313
313
 
314
+ // flags.w = NOT_RENDERED | PICK
315
+ // renderPass = PICK
316
+
317
+ src.push(`if (int(flags.w) != renderPass) {`);
318
+ src.push(" gl_Position = vec4(3.0, 3.0, 3.0, 1.0);"); // Cull vertex
319
+ src.push(" return;"); // Cull vertex
320
+ src.push("}");
321
+
314
322
  src.push("{");
315
323
 
316
324
  // get vertex base
@@ -17,11 +17,12 @@ const tempMat4a = math.mat4();
17
17
  * @private
18
18
  */
19
19
  export class VBORenderer {
20
- constructor(scene, withSAO = false, {instancing = false, edges = false} = {}) {
20
+ constructor(scene, withSAO = false, {instancing = false, edges = false, useAlphaCutoff = false} = {}) {
21
21
  this._scene = scene;
22
22
  this._withSAO = withSAO;
23
23
  this._instancing = instancing;
24
24
  this._edges = edges;
25
+ this._useAlphaCutoff = useAlphaCutoff;
25
26
  this._hash = this._getHash();
26
27
 
27
28
  /**
@@ -272,6 +273,10 @@ export class VBORenderer {
272
273
  this._uSAOParams = program.getLocation("uSAOParams");
273
274
  }
274
275
 
276
+ if (this._useAlphaCutoff) {
277
+ this._alphaCutoffLocation = program.getLocation("materialAlphaCutoff");
278
+ }
279
+
275
280
  if (scene.logarithmicDepthBufferEnabled) {
276
281
  this._uLogDepthBufFC = program.getLocation("logDepthBufFC");
277
282
  }
@@ -609,6 +614,10 @@ export class VBORenderer {
609
614
  }
610
615
  }
611
616
 
617
+ if (this._useAlphaCutoff) {
618
+ gl.uniform1f(this._alphaCutoffLocation, textureSet.alphaCutoff);
619
+ }
620
+
612
621
  if (colorUniform) {
613
622
  const colorKey = this._edges ? "edgeColor" : "fillColor";
614
623
  const alphaKey = this._edges ? "edgeAlpha" : "fillAlpha";