x_ite 8.6.7 → 8.6.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 (110) hide show
  1. package/.vscode/tasks.json +1 -1
  2. package/dist/assets/components/Annotation.js +13 -13
  3. package/dist/assets/components/Annotation.min.js +1 -1
  4. package/dist/assets/components/CADGeometry.js +13 -13
  5. package/dist/assets/components/CADGeometry.min.js +1 -1
  6. package/dist/assets/components/CubeMapTexturing.js +26 -26
  7. package/dist/assets/components/CubeMapTexturing.min.js +1 -1
  8. package/dist/assets/components/DIS.js +13 -13
  9. package/dist/assets/components/DIS.min.js +1 -1
  10. package/dist/assets/components/EventUtilities.js +9 -9
  11. package/dist/assets/components/EventUtilities.min.js +1 -1
  12. package/dist/assets/components/Geometry2D.js +19 -19
  13. package/dist/assets/components/Geometry2D.min.js +1 -1
  14. package/dist/assets/components/Geospatial.js +33 -33
  15. package/dist/assets/components/Geospatial.min.js +1 -1
  16. package/dist/assets/components/HAnim.js +18 -18
  17. package/dist/assets/components/HAnim.min.js +1 -1
  18. package/dist/assets/components/KeyDeviceSensor.js +8 -8
  19. package/dist/assets/components/KeyDeviceSensor.min.js +1 -1
  20. package/dist/assets/components/Layout.js +27 -27
  21. package/dist/assets/components/Layout.min.js +1 -1
  22. package/dist/assets/components/NURBS.js +24 -24
  23. package/dist/assets/components/NURBS.min.js +1 -1
  24. package/dist/assets/components/ParticleSystems.js +25 -27
  25. package/dist/assets/components/ParticleSystems.min.js +1 -1
  26. package/dist/assets/components/Picking.js +19 -19
  27. package/dist/assets/components/Picking.min.js +1 -1
  28. package/dist/assets/components/RigidBodyPhysics.js +18 -18
  29. package/dist/assets/components/RigidBodyPhysics.min.js +1 -1
  30. package/dist/assets/components/Scripting.js +28 -28
  31. package/dist/assets/components/Scripting.min.js +1 -1
  32. package/dist/assets/components/Text.js +24 -24
  33. package/dist/assets/components/Text.min.js +1 -1
  34. package/dist/assets/components/TextureProjector.js +14 -14
  35. package/dist/assets/components/TextureProjector.min.js +1 -1
  36. package/dist/assets/components/Texturing3D.js +33 -33
  37. package/dist/assets/components/Texturing3D.min.js +1 -1
  38. package/dist/assets/components/VolumeRendering.js +19 -19
  39. package/dist/assets/components/VolumeRendering.min.js +1 -1
  40. package/dist/assets/components/X_ITE.js +9 -9
  41. package/dist/assets/components/X_ITE.min.js +1 -1
  42. package/dist/x_ite.css +1 -1
  43. package/dist/x_ite.js +907 -689
  44. package/dist/x_ite.min.js +1 -1
  45. package/dist/x_ite.zip +0 -0
  46. package/docs/_config.yml +2 -2
  47. package/docs/laboratory/gltf-sample-viewer.html +4 -4
  48. package/package.json +1 -1
  49. package/src/assets/shaders/webgl1/Pointing.fs.js +1 -1
  50. package/src/assets/shaders/webgl1/include/Fragment.glsl.js +17 -1
  51. package/src/assets/shaders/webgl1/include/Point.glsl.js +10 -2
  52. package/src/assets/shaders/webgl1/include/Texture.glsl.js +31 -1
  53. package/src/assets/shaders/webgl1/include/Vertex.glsl.js +26 -3
  54. package/src/assets/shaders/webgl2/Pointing.fs.js +1 -1
  55. package/src/assets/shaders/webgl2/include/Fragment.glsl.js +18 -0
  56. package/src/assets/shaders/webgl2/include/Particle.glsl.js +9 -23
  57. package/src/assets/shaders/webgl2/include/Point.glsl.js +12 -4
  58. package/src/assets/shaders/webgl2/include/Texture.glsl.js +17 -20
  59. package/src/assets/shaders/webgl2/include/Vertex.glsl.js +24 -0
  60. package/src/bookmarks.js +1 -1
  61. package/src/standard/Math/Numbers/Color3.js +2 -2
  62. package/src/standard/Math/Numbers/Color4.js +1 -1
  63. package/src/tests.js +1 -0
  64. package/src/x_ite/Browser/Core/BrowserOptions.js +3 -0
  65. package/src/x_ite/Browser/Core/BrowserTimings.js +12 -11
  66. package/src/x_ite/Browser/Core/Context.js +64 -64
  67. package/src/x_ite/Browser/Core/ContextMenu.js +0 -9
  68. package/src/x_ite/Browser/Navigation/ExamineViewer.js +1 -1
  69. package/src/x_ite/Browser/Shaders/Shaders.js +0 -2
  70. package/src/x_ite/Browser/Texturing/X3DTexturingContext.js +8 -0
  71. package/src/x_ite/Browser/VERSION.js +1 -1
  72. package/src/x_ite/Browser/X3DBrowser.js +1 -1
  73. package/src/x_ite/Components/Core/X3DBindableNode.js +0 -2
  74. package/src/x_ite/Components/Core/X3DNode.js +3 -8
  75. package/src/x_ite/Components/CubeMapTexturing/ComposedCubeMapTexture.js +1 -1
  76. package/src/x_ite/Components/Layering/X3DLayerNode.js +6 -2
  77. package/src/x_ite/Components/Navigation/NavigationInfo.js +1 -0
  78. package/src/x_ite/Components/Navigation/X3DViewpointNode.js +34 -21
  79. package/src/x_ite/Components/ParticleSystems/ParticleSystem.js +2 -4
  80. package/src/x_ite/Components/Rendering/X3DGeometryNode.js +5 -19
  81. package/src/x_ite/Components/Rendering/X3DLineGeometryNode.js +6 -12
  82. package/src/x_ite/Components/Rendering/X3DPointGeometryNode.js +4 -8
  83. package/src/x_ite/Components/Shaders/X3DProgrammableShaderObject.js +28 -27
  84. package/src/x_ite/Components/Shape/Material.js +28 -23
  85. package/src/x_ite/Components/Shape/PhysicalMaterial.js +5 -0
  86. package/src/x_ite/Components/Shape/TwoSidedMaterial.js +1 -0
  87. package/src/x_ite/Components/Shape/UnlitMaterial.js +1 -0
  88. package/src/x_ite/Components/Shape/X3DMaterialNode.js +21 -19
  89. package/src/x_ite/Components/Shape/X3DOneSidedMaterialNode.js +16 -10
  90. package/src/x_ite/Components/Texturing/ImageTexture.js +86 -44
  91. package/src/x_ite/Components/Texturing/MovieTexture.js +5 -4
  92. package/src/x_ite/Components/Texturing/MultiTexture.js +7 -4
  93. package/src/x_ite/Components/Texturing/MultiTextureCoordinate.js +19 -16
  94. package/src/x_ite/Components/Texturing/MultiTextureTransform.js +16 -32
  95. package/src/x_ite/Components/Texturing/TextureCoordinateGenerator.js +1 -1
  96. package/src/x_ite/Components/Texturing/X3DSingleTextureCoordinateNode.js +2 -8
  97. package/src/x_ite/Components/Texturing/X3DSingleTextureTransformNode.js +2 -8
  98. package/src/x_ite/Execution/NamedNodesHandling.js +84 -0
  99. package/src/x_ite/Execution/X3DExecutionContext.js +7 -37
  100. package/src/x_ite/Execution/X3DScene.js +5 -0
  101. package/src/x_ite/InputOutput/FileLoader.js +1 -1
  102. package/src/x_ite/InputOutput/Generator.js +32 -81
  103. package/src/x_ite/Parser/GLTF2Parser.js +112 -52
  104. package/src/x_ite/Parser/OBJParser.js +48 -39
  105. package/src/x_ite/Parser/STLAParser.js +3 -0
  106. package/src/x_ite/Parser/SVGParser.js +4 -0
  107. package/src/x_ite/Rendering/X3DRenderObject.js +2 -0
  108. package/src/x_ite.html +52 -46
  109. package/x_ite.min.html +52 -46
  110. package/src/assets/shaders/webgl1/include/Particle.glsl.js +0 -7
@@ -61,9 +61,7 @@ import DEBUG from "../DEBUG.js"
61
61
  // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
62
62
  // https://github.com/KhronosGroup/glTF-Sample-Models
63
63
 
64
- const
65
- STEP_TIME = 1e-4, // in seconds
66
- SAMPLES_PER_SECOND = 30; // in 1/s
64
+ const SAMPLES_PER_SECOND = 30; // in 1/s
67
65
 
68
66
  function GLTF2Parser (scene)
69
67
  {
@@ -86,7 +84,7 @@ function GLTF2Parser (scene)
86
84
  this .accessors = [ ];
87
85
  this .samplers = [ ];
88
86
  this .materials = [ ];
89
- this .textureTransformNodes = new Map ();
87
+ this .textureTransformNodes = [ ];
90
88
  this .cameras = [ ];
91
89
  this .viewpoints = 0;
92
90
  this .nodes = [ ];
@@ -320,12 +318,16 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
320
318
  if (this .vectorValue (light .color, color))
321
319
  lightNode ._color = color;
322
320
 
321
+ lightNode ._global = true;
323
322
  lightNode ._intensity = this .numberValue (light .intensity, 1);
324
323
 
325
324
  lightNode .setup ();
326
325
 
327
326
  if (name)
327
+ {
328
328
  scene .addNamedNode (scene .getUniqueName (name), lightNode);
329
+ scene .addExportedNode (scene .getUniqueExportName (name), lightNode);
330
+ }
329
331
 
330
332
  return lightNode;
331
333
  },
@@ -471,7 +473,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
471
473
  components = Components .get (accessor .type),
472
474
  count = accessor .count || 0,
473
475
  stride = byteStride ? byteStride / TypedArray .BYTES_PER_ELEMENT : components,
474
- length = stride * count,
476
+ length = Math .min (stride * count, (bufferView .byteLength - byteOffset) / TypedArray .BYTES_PER_ELEMENT),
475
477
  array = new TypedArray (bufferView .buffer, byteOffset, length);
476
478
 
477
479
  if (stride === components)
@@ -596,7 +598,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
596
598
  name = this .sanitizeName (sampler .name);
597
599
 
598
600
  if (name)
601
+ {
599
602
  scene .addNamedNode (scene .getUniqueName (name), texturePropertiesNode);
603
+ scene .addExportedNode (scene .getUniqueExportName (name), texturePropertiesNode);
604
+ }
600
605
 
601
606
  // minFilter
602
607
 
@@ -694,9 +699,13 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
694
699
  name = this .sanitizeName (texture .name || image .name);
695
700
 
696
701
  if (name)
702
+ {
697
703
  scene .addNamedNode (scene .getUniqueName (name), textureNode);
704
+ scene .addExportedNode (scene .getUniqueExportName (name), textureNode);
705
+ }
698
706
 
699
- textureNode ._url = [image .uri];
707
+ textureNode ._url = [image .uri];
708
+ textureNode ._flipVertically = true;
700
709
 
701
710
  const sampler = this .samplers [texture .sampler];
702
711
 
@@ -722,13 +731,18 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
722
731
  if (material .appearanceNode)
723
732
  return material .appearanceNode;
724
733
 
725
- if (!(material .extensions instanceof Object))
726
- material .extensions = { };
734
+ const texCoordIndices = this .texCoordIndices ("", material);
735
+
736
+ this .texCoordIndex = [... texCoordIndices] .reduce (Math .max, -1);
737
+
738
+ this .textureTransformNodes = [ ];
739
+ this .texCoordMappings = new Map ();
740
+ material .texCoordMappings = this .texCoordMappings;
727
741
 
728
742
  const
729
743
  scene = this .getExecutionContext (),
730
744
  appearanceNode = scene .createNode ("Appearance", false),
731
- materialNode = this .materialObjectMaterial (material),
745
+ materialNode = this .createMaterial (material),
732
746
  name = this .sanitizeName (material .name);
733
747
 
734
748
  const emissiveFactor = new Color3 (0, 0, 0);
@@ -736,8 +750,8 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
736
750
  if (this .vectorValue (material .emissiveFactor, emissiveFactor))
737
751
  materialNode ._emissiveColor = emissiveFactor;
738
752
 
739
- materialNode ._emissiveTextureMapping = this .textureMapping (material .emissiveTexture);
740
753
  materialNode ._emissiveTexture = this .textureInfo (material .emissiveTexture);
754
+ materialNode ._emissiveTextureMapping = this .textureMapping (material .emissiveTexture);
741
755
 
742
756
  this .occlusionTextureInfo (material .occlusionTexture, materialNode);
743
757
  this .normalTextureInfo (material .normalTexture, materialNode);
@@ -745,8 +759,28 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
745
759
 
746
760
  materialNode .setup ();
747
761
 
762
+ for (const i of texCoordIndices)
763
+ {
764
+ const mapping = `TEXCOORD_${i}`;
765
+
766
+ if (this .textureTransformNodes .length)
767
+ {
768
+ const textureTransformNode = scene .createNode ("TextureTransform", false);
769
+
770
+ textureTransformNode ._mapping = mapping;
771
+ textureTransformNode .setup ();
772
+
773
+ this .textureTransformNodes .push (textureTransformNode);
774
+ }
775
+
776
+ this .texCoordMappings .set (mapping, i);
777
+ }
778
+
748
779
  if (name)
780
+ {
749
781
  scene .addNamedNode (scene .getUniqueName (name), appearanceNode);
782
+ scene .addExportedNode (scene .getUniqueExportName (name), appearanceNode);
783
+ }
750
784
 
751
785
  appearanceNode ._alphaMode = this .stringValue (material .alphaMode, "OPAQUE");
752
786
  appearanceNode ._alphaCutoff = this .numberValue (material .alphaCutoff, 0.5);
@@ -757,11 +791,24 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
757
791
 
758
792
  return material .appearanceNode = appearanceNode;
759
793
  },
760
- materialObjectMaterial: function (material)
794
+ texCoordIndices: function (key, object, indices = new Set ())
795
+ {
796
+ if (!(object instanceof Object))
797
+ return indices;
798
+
799
+ if (key .endsWith ("Texture") && !object?.extensions?.KHR_texture_transform)
800
+ indices .add (object .texCoord || 0);
801
+
802
+ for (const [key, value] of Object .entries (object))
803
+ this .texCoordIndices (key, value, indices);
804
+
805
+ return indices;
806
+ },
807
+ createMaterial: function (material)
761
808
  {
762
809
  const materials = [
763
810
  this .pbrMetallicRoughnessObject .bind (this, material .pbrMetallicRoughness),
764
- this .pbrSpecularGlossinessObject .bind (this, material .extensions .KHR_materials_pbrSpecularGlossiness),
811
+ this .pbrSpecularGlossinessObject .bind (this, material .extensions?.KHR_materials_pbrSpecularGlossiness),
765
812
  this .pbrMetallicRoughnessObject .bind (this, { }),
766
813
  ];
767
814
 
@@ -795,10 +842,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
795
842
  materialNode ._metallic = this .numberValue (pbrMetallicRoughness .metallicFactor, 1);
796
843
  materialNode ._roughness = this .numberValue (pbrMetallicRoughness .roughnessFactor, 1);
797
844
 
798
- materialNode ._baseTextureMapping = this .textureMapping (pbrMetallicRoughness .baseColorTexture);
799
845
  materialNode ._baseTexture = this .textureInfo (pbrMetallicRoughness .baseColorTexture);
800
- materialNode ._metallicRoughnessTextureMapping = this .textureMapping (pbrMetallicRoughness .metallicRoughnessTexture);
846
+ materialNode ._baseTextureMapping = this .textureMapping (pbrMetallicRoughness .baseColorTexture);
801
847
  materialNode ._metallicRoughnessTexture = this .textureInfo (pbrMetallicRoughness .metallicRoughnessTexture);
848
+ materialNode ._metallicRoughnessTextureMapping = this .textureMapping (pbrMetallicRoughness .metallicRoughnessTexture);
802
849
 
803
850
  return materialNode;
804
851
  },
@@ -833,30 +880,23 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
833
880
 
834
881
  materialNode ._shininess = this .numberValue (pbrSpecularGlossiness .glossinessFactor, 1);
835
882
 
836
- materialNode ._diffuseTextureMapping = this .textureMapping (pbrSpecularGlossiness .diffuseTexture);
837
883
  materialNode ._diffuseTexture = this .textureInfo (pbrSpecularGlossiness .diffuseTexture);
838
- materialNode ._specularTextureMapping = this .textureMapping (pbrSpecularGlossiness .specularGlossinessTexture);
884
+ materialNode ._diffuseTextureMapping = this .textureMapping (pbrSpecularGlossiness .diffuseTexture);
839
885
  materialNode ._specularTexture = this .textureInfo (pbrSpecularGlossiness .specularGlossinessTexture);
840
- materialNode ._shininessTextureMapping = this .textureMapping (pbrSpecularGlossiness .specularGlossinessTexture);
886
+ materialNode ._specularTextureMapping = this .textureMapping (pbrSpecularGlossiness .specularGlossinessTexture);
841
887
  materialNode ._shininessTexture = this .textureInfo (pbrSpecularGlossiness .specularGlossinessTexture);
888
+ materialNode ._shininessTextureMapping = this .textureMapping (pbrSpecularGlossiness .specularGlossinessTexture);
842
889
 
843
890
  return materialNode;
844
891
  },
845
- textureMapping: function (texture)
846
- {
847
- if (!(texture instanceof Object))
848
- return "";
849
-
850
- return "TEXCOORD_" + (texture .texCoord || 0);
851
- },
852
892
  occlusionTextureInfo: function (occlusionTexture, materialNode)
853
893
  {
854
894
  if (!(occlusionTexture instanceof Object))
855
895
  return null;
856
896
 
857
897
  materialNode ._occlusionStrength = this .numberValue (occlusionTexture .strength, 1);
858
- materialNode ._occlusionTextureMapping = this .textureMapping (occlusionTexture);
859
898
  materialNode ._occlusionTexture = this .textureInfo (occlusionTexture);
899
+ materialNode ._occlusionTextureMapping = this .textureMapping (occlusionTexture);
860
900
  },
861
901
  normalTextureInfo: function (normalTexture, materialNode)
862
902
  {
@@ -864,8 +904,8 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
864
904
  return null;
865
905
 
866
906
  materialNode ._normalScale = this .numberValue (normalTexture .scale, 1);
867
- materialNode ._normalTextureMapping = this .textureMapping (normalTexture);
868
907
  materialNode ._normalTexture = this .textureInfo (normalTexture);
908
+ materialNode ._normalTextureMapping = this .textureMapping (normalTexture);
869
909
  },
870
910
  textureInfo: function (texture)
871
911
  {
@@ -873,10 +913,19 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
873
913
  return null;
874
914
 
875
915
  if (texture .extensions instanceof Object)
876
- this .textureTransformObject (texture .extensions .KHR_texture_transform, this .textureMapping (texture));
916
+ texture .mapping = this .textureTransformObject (texture .extensions .KHR_texture_transform, texture .texCoord || 0);
917
+ else
918
+ texture .mapping = `TEXCOORD_${texture .texCoord || 0}`;
877
919
 
878
920
  return this .textureObject (this .textures [texture .index]);
879
921
  },
922
+ textureMapping: function (texture)
923
+ {
924
+ if (!(texture instanceof Object))
925
+ return "";
926
+
927
+ return texture .mapping;
928
+ },
880
929
  materialExtensions: function (extensions, materialNode)
881
930
  {
882
931
  if (!(extensions instanceof Object))
@@ -926,16 +975,9 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
926
975
  if (!(KHR_materials_emissive_strength instanceof Object))
927
976
  return;
928
977
 
929
- const emissiveStrength = this .numberValue (KHR_materials_emissive_strength .emissiveStrength, 1);
930
-
931
- // Will not always get the desired result, because colors are clamped values,
932
- // especially if there is an emissiveTexture.
933
-
934
- materialNode ._emissiveColor .r *= emissiveStrength;
935
- materialNode ._emissiveColor .g *= emissiveStrength;
936
- materialNode ._emissiveColor .b *= emissiveStrength;
978
+ materialNode ._emissiveStrength = this .numberValue (KHR_materials_emissive_strength .emissiveStrength, 1);
937
979
  },
938
- textureTransformObject: function (KHR_texture_transform, mapping)
980
+ textureTransformObject: function (KHR_texture_transform, texCoord)
939
981
  {
940
982
  if (!(KHR_texture_transform instanceof Object))
941
983
  return;
@@ -945,7 +987,8 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
945
987
 
946
988
  const
947
989
  scene = this .getExecutionContext (),
948
- textureTransformNode = scene .createNode ("TextureTransformMatrix3D", false);
990
+ textureTransformNode = scene .createNode ("TextureTransformMatrix3D", false),
991
+ mapping = `TEXCOORD_${this .texCoordIndex + this .textureTransformNodes .length + 1}`;
949
992
 
950
993
  const
951
994
  translation = new Vector2 (0, 0),
@@ -965,7 +1008,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
965
1008
 
966
1009
  textureTransformNode .setup ();
967
1010
 
968
- this .textureTransformNodes .set (mapping, textureTransformNode);
1011
+ this .textureTransformNodes .push (textureTransformNode);
1012
+ this .texCoordMappings .set (mapping, KHR_texture_transform .texCoord ?? texCoord);
1013
+
1014
+ return mapping;
969
1015
  },
970
1016
  meshesArray: function (meshes)
971
1017
  {
@@ -993,7 +1039,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
993
1039
  if (name)
994
1040
  {
995
1041
  for (const shapeNode of shapeNodes)
1042
+ {
996
1043
  scene .addNamedNode (scene .getUniqueName (name), shapeNode);
1044
+ scene .addExportedNode (scene .getUniqueExportName (name), shapeNode);
1045
+ }
997
1046
  }
998
1047
 
999
1048
  return mesh .shapeNodes = shapeNodes;
@@ -1227,7 +1276,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1227
1276
  // Name
1228
1277
 
1229
1278
  if (name)
1279
+ {
1230
1280
  scene .addNamedNode (scene .getUniqueName (name), viewpointNode);
1281
+ scene .addExportedNode (scene .getUniqueExportName (name), viewpointNode);
1282
+ }
1231
1283
 
1232
1284
  if (camera .name)
1233
1285
  viewpointNode ._description = camera .name;
@@ -1323,7 +1375,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1323
1375
  // Name
1324
1376
 
1325
1377
  if (name)
1378
+ {
1326
1379
  scene .addNamedNode (scene .getUniqueName (name), transformNode);
1380
+ scene .addExportedNode (scene .getUniqueExportName (name), transformNode);
1381
+ }
1327
1382
 
1328
1383
  // Set transformation matrix.
1329
1384
 
@@ -1455,6 +1510,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1455
1510
  const switchNode = scene .createNode ("Switch", false);
1456
1511
 
1457
1512
  scene .addNamedNode (scene .getUniqueName ("Scenes"), switchNode);
1513
+ scene .addExportedNode (scene .getUniqueExportName ("Scenes"), switchNode);
1458
1514
 
1459
1515
  // Scenes.
1460
1516
 
@@ -1493,7 +1549,10 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1493
1549
  name = this .sanitizeName (sceneObject .name);
1494
1550
 
1495
1551
  if (name)
1552
+ {
1496
1553
  scene .addNamedNode (scene .getUniqueName (name), groupNode);
1554
+ scene .addExportedNode (scene .getUniqueExportName (name), groupNode);
1555
+ }
1497
1556
 
1498
1557
  groupNode ._children = nodes;
1499
1558
 
@@ -1524,7 +1583,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1524
1583
  groupNode = scene .createNode ("Group", false);
1525
1584
 
1526
1585
  scene .addNamedNode (scene .getUniqueName ("Animations"), groupNode);
1527
- scene .addExportedNode ("Animations", groupNode);
1586
+ scene .addExportedNode (scene .getUniqueExportName ("Animations"), groupNode);
1528
1587
 
1529
1588
  groupNode ._children = animationNodes;
1530
1589
 
@@ -1553,6 +1612,8 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1553
1612
 
1554
1613
  scene .addNamedNode (scene .getUniqueName (name || `Animation${this .animations}`), groupNode);
1555
1614
  scene .addNamedNode (scene .getUniqueName (`Timer${this .animations}`), timeSensorNode);
1615
+ scene .addExportedNode (scene .getUniqueExportName (name || `Animation${this .animations}`), groupNode);
1616
+ scene .addExportedNode (scene .getUniqueExportName (`Timer${this .animations}`), timeSensorNode);
1556
1617
 
1557
1618
  timeSensorNode ._description = animation .name || `Animation ${this .animations}`;
1558
1619
  groupNode ._children .push (timeSensorNode, ... channelNodes);
@@ -1687,11 +1748,9 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
1687
1748
  if (!+materialNode .getTextureBits ())
1688
1749
  return null;
1689
1750
 
1690
- const textureTransformNodes = [... this .textureTransformNodes .values ()]
1751
+ const textureTransformNodes = this .textureTransformNodes
1691
1752
  .sort ((a, b) => Algorithm .cmp (a ._mapping .getValue (), b ._mapping .getValue ()));
1692
1753
 
1693
- this .textureTransformNodes .clear ();
1694
-
1695
1754
  switch (textureTransformNodes .length)
1696
1755
  {
1697
1756
  case 0:
@@ -2028,7 +2087,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
2028
2087
  if (texCoords .textureCoordinateNode)
2029
2088
  return texCoords .textureCoordinateNode;
2030
2089
 
2031
- switch (texCoords .length)
2090
+ switch (material .texCoordMappings .size)
2032
2091
  {
2033
2092
  case 0:
2034
2093
  {
@@ -2036,12 +2095,13 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
2036
2095
  }
2037
2096
  case 1:
2038
2097
  {
2039
- return texCoords .textureCoordinateNode = this .createTextureCoordinate (texCoords [0], 0);
2098
+ return texCoords .textureCoordinateNode = [... material .texCoordMappings .entries ()]
2099
+ .map (([mapping, i]) => this .createTextureCoordinate (texCoords [i], mapping)) [0];
2040
2100
  }
2041
2101
  default:
2042
2102
  {
2043
- const textureCoordinateNodes = texCoords
2044
- .map ((texCoord, i) => this .createTextureCoordinate (texCoord, i))
2103
+ const textureCoordinateNodes = [... material .texCoordMappings .entries ()]
2104
+ .map (([mapping, i]) => this .createTextureCoordinate (texCoords [i], mapping))
2045
2105
  .filter (node => node)
2046
2106
  .sort ((a, b) => Algorithm .cmp (a ._mapping .getValue (), b ._mapping .getValue ()));
2047
2107
 
@@ -2068,19 +2128,19 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
2068
2128
  if (texCoord .type !== "VEC2")
2069
2129
  return null;
2070
2130
 
2071
- if (texCoord .textureCoordinateNode)
2072
- return texCoord .textureCoordinateNode;
2131
+ if (texCoord [mapping])
2132
+ return texCoord [mapping];
2073
2133
 
2074
2134
  const
2075
2135
  scene = this .getExecutionContext (),
2076
2136
  textureCoordinateNode = scene .createNode ("TextureCoordinate", false);
2077
2137
 
2078
- textureCoordinateNode ._mapping = "TEXCOORD_" + mapping;
2138
+ textureCoordinateNode ._mapping = mapping;
2079
2139
  textureCoordinateNode ._point = texCoord .array;
2080
2140
 
2081
2141
  textureCoordinateNode .setup ();
2082
2142
 
2083
- return texCoord .textureCoordinateNode = textureCoordinateNode;
2143
+ return texCoord [mapping] = textureCoordinateNode;
2084
2144
  },
2085
2145
  createNormal: function (normal)
2086
2146
  {
@@ -2176,7 +2236,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
2176
2236
  interpolatorNode ._key .push (times [0] / cycleInterval);
2177
2237
 
2178
2238
  for (let i = 1, length = times .length; i < length; ++ i)
2179
- interpolatorNode ._key .push ((times [i] - STEP_TIME) / cycleInterval, times [i] / cycleInterval);
2239
+ interpolatorNode ._key .push (times [i] / cycleInterval, times [i] / cycleInterval);
2180
2240
 
2181
2241
  // KeyValue
2182
2242
 
@@ -2250,7 +2310,7 @@ GLTF2Parser .prototype = Object .assign (Object .create (X3DParser .prototype),
2250
2310
  interpolatorNode ._key .push (times [0] / cycleInterval);
2251
2311
 
2252
2312
  for (let i = 1, length = times .length; i < length; ++ i)
2253
- interpolatorNode ._key .push ((times [i] - STEP_TIME) / cycleInterval, times [i] / cycleInterval);
2313
+ interpolatorNode ._key .push (times [i] / cycleInterval, times [i] / cycleInterval);
2254
2314
 
2255
2315
  // KeyValue
2256
2316
 
@@ -275,36 +275,39 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
275
275
  try
276
276
  {
277
277
  const
278
- scene = this .getExecutionContext (),
279
- url = new URL (path, scene .getWorldURL ());
280
-
281
- const input = await fetch (url)
282
- .then (response => response .arrayBuffer ())
283
- .then (arrayBuffer => $.decodeText ($.ungzip (arrayBuffer)))
284
- .catch (Function .prototype);
285
-
286
- const parser = new MaterialParser (scene, input);
278
+ scene = this .getExecutionContext (),
279
+ url = new URL (path, scene .getWorldURL ()),
280
+ response = await fetch (url),
281
+ arrayBuffer = await response .arrayBuffer (),
282
+ input = $.decodeText ($.ungzip (arrayBuffer)),
283
+ parser = new MaterialParser (scene, input);
287
284
 
288
285
  parser .parse ();
289
286
 
290
- for (const [name, material] of parser .materials)
287
+ for (const [id, material] of parser .materials)
291
288
  {
292
- const nodeName = this .sanitizeName (name);
289
+ const name = this .sanitizeName (id);
293
290
 
294
- if (nodeName)
295
- scene .addNamedNode (scene .getUniqueName (nodeName), material);
291
+ if (name)
292
+ {
293
+ scene .addNamedNode (scene .getUniqueName (name), material);
294
+ scene .addExportedNode (scene .getUniqueExportName (name), material);
295
+ }
296
296
 
297
- this .materials .set (name, material);
297
+ this .materials .set (id, material);
298
298
  }
299
299
 
300
- for (const [name, texture] of parser .textures)
300
+ for (const [id, texture] of parser .textures)
301
301
  {
302
- const nodeName = this .sanitizeName (name);
302
+ const name = this .sanitizeName (id);
303
303
 
304
- if (nodeName)
305
- scene .addNamedNode (scene .getUniqueName (nodeName), texture);
304
+ if (name)
305
+ {
306
+ scene .addNamedNode (scene .getUniqueName (name), texture);
307
+ scene .addExportedNode (scene .getUniqueExportName (name), texture);
308
+ }
306
309
 
307
- this .textures .set (name, texture);
310
+ this .textures .set (id, texture);
308
311
  }
309
312
  }
310
313
  catch (error)
@@ -322,10 +325,10 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
322
325
 
323
326
  if (Grammar .untilEndOfLine .parse (this))
324
327
  {
325
- const name = this .result [1];
328
+ const id = this .result [1];
326
329
 
327
- this .material = this .materials .get (name) || this .defaultMaterial;
328
- this .texture = this .textures .get (name);
330
+ this .material = this .materials .get (id) || this .defaultMaterial;
331
+ this .texture = this .textures .get (id);
329
332
 
330
333
  const smoothingGroup = this .smoothingGroups .get (this .group .getNodeName ());
331
334
 
@@ -349,8 +352,8 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
349
352
  if (Grammar .untilEndOfLine .parse (this))
350
353
  {
351
354
  const
352
- scene = this .getExecutionContext (),
353
- nodeName = this .sanitizeName (this .result [1]);
355
+ scene = this .getExecutionContext (),
356
+ name = this .sanitizeName (this .result [1]);
354
357
 
355
358
  if (this .group .children .length)
356
359
  {
@@ -361,8 +364,11 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
361
364
  scene .getRootNodes () .push (this .object);
362
365
  }
363
366
 
364
- if (nodeName)
365
- scene .addNamedNode (scene .getUniqueName (nodeName), this .object);
367
+ if (name)
368
+ {
369
+ scene .addNamedNode (scene .getUniqueName (name), this .object);
370
+ scene .addExportedNode (scene .getUniqueExportName (name), this .object);
371
+ }
366
372
  }
367
373
 
368
374
  return true;
@@ -381,10 +387,10 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
381
387
  if (Grammar .untilEndOfLine .parse (this))
382
388
  {
383
389
  const
384
- scene = this .getExecutionContext (),
385
- name = this .result [1],
386
- nodeName = this .sanitizeName (name),
387
- group = this .groups .get (name);
390
+ scene = this .getExecutionContext (),
391
+ id = this .result [1],
392
+ name = this .sanitizeName (id),
393
+ group = this .groups .get (id);
388
394
 
389
395
  if (group)
390
396
  {
@@ -400,10 +406,13 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
400
406
  }
401
407
  }
402
408
 
403
- this .groups .set (name, this .group);
409
+ this .groups .set (id, this .group);
404
410
 
405
- if (nodeName)
406
- scene .addNamedNode (scene .getUniqueName (nodeName), this .group);
411
+ if (name)
412
+ {
413
+ scene .addNamedNode (scene .getUniqueName (name), this .group);
414
+ scene .addExportedNode (scene .getUniqueExportName (name), this .group);
415
+ }
407
416
 
408
417
  this .smoothingGroup = 0;
409
418
  }
@@ -728,7 +737,7 @@ function MaterialParser (scene, input)
728
737
  this .materials = new Map ();
729
738
  this .textures = new Map ();
730
739
  this .color3 = new Color3 ();
731
- this .name = "";
740
+ this .id = "";
732
741
  }
733
742
 
734
743
  MaterialParser .prototype =
@@ -821,15 +830,15 @@ MaterialParser .prototype =
821
830
  {
822
831
  this .whitespacesNoLineTerminator ();
823
832
 
824
- this .name = "";
833
+ this .id = "";
825
834
 
826
835
  if (Grammar .untilEndOfLine .parse (this))
827
836
  {
828
- this .name = this .result [1];
837
+ this .id = this .result [1];
829
838
 
830
839
  this .material = this .executionContext .createNode ("Material");
831
840
 
832
- this .materials .set (this .name, this .material);
841
+ this .materials .set (this .id, this .material);
833
842
 
834
843
  return true;
835
844
  }
@@ -994,7 +1003,7 @@ MaterialParser .prototype =
994
1003
  {
995
1004
  const string = this .result [1];
996
1005
 
997
- if (string .length && this .name .length)
1006
+ if (string .length && this .id .length)
998
1007
  {
999
1008
  const paths = string .trim () .split (/\s+/);
1000
1009
 
@@ -1007,7 +1016,7 @@ MaterialParser .prototype =
1007
1016
 
1008
1017
  texture .url = [path];
1009
1018
 
1010
- this .textures .set (this .name, texture);
1019
+ this .textures .set (this .id, texture);
1011
1020
  }
1012
1021
  }
1013
1022
 
@@ -208,7 +208,10 @@ STLAParser .prototype = Object .assign (Object .create (X3DParser .prototype),
208
208
  coordinate .point = this .point;
209
209
 
210
210
  if (name)
211
+ {
211
212
  scene .addNamedNode (scene .getUniqueName (name), shape);
213
+ scene .addExportedNode (scene .getUniqueExportName (name), shape);
214
+ }
212
215
 
213
216
  scene .getRootNodes () .push (shape);
214
217
 
@@ -354,6 +354,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
354
354
  // Add root Transform node.
355
355
 
356
356
  scene .addNamedNode (scene .getUniqueName ("ViewBox"), this .rootTransform);
357
+ scene .addExportedNode (scene .getUniqueExportName ("ViewBox"), this .rootTransform);
357
358
  scene .getRootNodes () .push (this .rootTransform);
358
359
 
359
360
  // Optimize scene graph.
@@ -1212,7 +1213,10 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1212
1213
  name = this .sanitizeName (attribute);
1213
1214
 
1214
1215
  if (name)
1216
+ {
1215
1217
  scene .addNamedNode (scene .getUniqueName (name), node);
1218
+ scene .addExportedNode (scene .getUniqueExportName (name), node);
1219
+ }
1216
1220
  },
1217
1221
  viewBoxAttribute: function (attribute, defaultValue)
1218
1222
  {
@@ -1051,6 +1051,7 @@ X3DRenderObject .prototype =
1051
1051
  gl .depthMask (true);
1052
1052
  gl .enable (gl .DEPTH_TEST);
1053
1053
  gl .disable (gl .BLEND);
1054
+ gl .colorMask (true, true, true, false);
1054
1055
 
1055
1056
  const opaqueShapes = this .opaqueShapes;
1056
1057
 
@@ -1072,6 +1073,7 @@ X3DRenderObject .prototype =
1072
1073
 
1073
1074
  gl .depthMask (false);
1074
1075
  gl .enable (gl .BLEND);
1076
+ gl .colorMask (true, true, true, true);
1075
1077
 
1076
1078
  const transparentShapes = this .transparentShapes;
1077
1079