瀏覽代碼

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 年之前
父節點
當前提交
a90cbd9db8
共有 100 個文件被更改,包括 134094 次插入15648 次删除
  1. 26 13
      .vscode/launch.json
  2. 1 1
      .vscode/settings.json
  3. 2 0
      Playground/_headers
  4. 77 0
      Playground/full.html
  5. 19 9
      Playground/js/frame.js
  6. 1 1
      Playground/js/index.js
  7. 17 17
      Playground/package.json
  8. 143 0
      Playground/scripts/physics.js
  9. 2 1
      Playground/scripts/scripts.txt
  10. 二進制
      Playground/textures/WhiteTransarentRamp.png
  11. 2 4
      Playground/zipContent/index.html
  12. 37 16
      Tools/Gulp/config.json
  13. 4 2
      Tools/Gulp/gulpfile.js
  14. 42 40
      Tools/Gulp/package.json
  15. 35 0
      Viewer/README.md
  16. 二進制
      Viewer/assets/img/close.png
  17. 二進制
      Viewer/assets/img/fullscreen.png
  18. 二進制
      Viewer/assets/img/help-circle.png
  19. 二進制
      Viewer/assets/img/loading.png
  20. 3 0
      Viewer/assets/templates/default/defaultTemplate.html
  21. 26 0
      Viewer/assets/templates/default/defaultViewer.html
  22. 1 0
      Viewer/assets/templates/default/error.html
  23. 1 0
      Viewer/assets/templates/default/help.html
  24. 41 0
      Viewer/assets/templates/default/loadingScreen.html
  25. 112 0
      Viewer/assets/templates/default/navbar.html
  26. 46 0
      Viewer/assets/templates/default/overlay.html
  27. 1 0
      Viewer/assets/templates/default/share.html
  28. 31 0
      Viewer/dist/basicExample.html
  29. 41 0
      Viewer/dist/domExample.html
  30. 二進制
      Viewer/dist/environment.dds
  31. 107292 0
      Viewer/dist/viewer.js
  32. 48 0
      Viewer/package.json
  33. 178 0
      Viewer/src/configuration/configuration.ts
  34. 0 0
      Viewer/src/configuration/index.ts
  35. 79 0
      Viewer/src/configuration/loader.ts
  36. 123 0
      Viewer/src/configuration/mappers.ts
  37. 126 0
      Viewer/src/configuration/types/default.ts
  38. 16 0
      Viewer/src/configuration/types/index.ts
  39. 34 0
      Viewer/src/configuration/types/minimal.ts
  40. 41 0
      Viewer/src/helper.ts
  41. 30 0
      Viewer/src/index.ts
  42. 15 0
      Viewer/src/initializer.ts
  43. 5 0
      Viewer/src/interfaces.ts
  44. 316 0
      Viewer/src/templateManager.ts
  45. 462 0
      Viewer/src/viewer/defaultViewer.ts
  46. 144 0
      Viewer/src/viewer/viewer.ts
  47. 28 0
      Viewer/src/viewer/viewerManager.ts
  48. 27 0
      Viewer/tsconfig.json
  49. 63 0
      Viewer/webpack.config.js
  50. 2587 2145
      dist/preview release/babylon.d.ts
  51. 49 48
      dist/preview release/babylon.js
  52. 3284 1199
      dist/preview release/babylon.max.js
  53. 2587 2145
      dist/preview release/babylon.module.d.ts
  54. 50 49
      dist/preview release/babylon.worker.js
  55. 3383 2940
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  56. 53 50
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  57. 4926 1834
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  58. 3383 2940
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  59. 53 51
      dist/preview release/gui/babylon.gui.d.ts
  60. 110 46
      dist/preview release/gui/babylon.gui.js
  61. 3 3
      dist/preview release/gui/babylon.gui.min.js
  62. 53 51
      dist/preview release/gui/babylon.gui.module.d.ts
  63. 1 1
      dist/preview release/gui/package.json
  64. 4 3
      dist/preview release/inspector/babylon.inspector.bundle.js
  65. 9 7
      dist/preview release/inspector/babylon.inspector.d.ts
  66. 222 111
      dist/preview release/inspector/babylon.inspector.js
  67. 4 3
      dist/preview release/inspector/babylon.inspector.min.js
  68. 14 17
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  69. 166 136
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  70. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  71. 56 48
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  72. 612 469
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  73. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  74. 59 50
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  75. 713 531
      dist/preview release/loaders/babylon.glTFFileLoader.js
  76. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  77. 1 1
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  78. 18 16
      dist/preview release/loaders/babylon.objFileLoader.js
  79. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  80. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.d.ts
  81. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.js
  82. 731 547
      dist/preview release/loaders/babylonjs.loaders.js
  83. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  84. 61 52
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  85. 1 1
      dist/preview release/loaders/package.json
  86. 1 1
      dist/preview release/loaders/readme.md
  87. 246 0
      dist/preview release/materialsLibrary/babylon.backgroundMaterial.d.ts
  88. 849 0
      dist/preview release/materialsLibrary/babylon.backgroundMaterial.js
  89. 1 0
      dist/preview release/materialsLibrary/babylon.backgroundMaterial.min.js
  90. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.d.ts
  91. 9 6
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  92. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.min.js
  93. 3 2
      dist/preview release/materialsLibrary/babylon.customMaterial.d.ts
  94. 18 11
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  95. 2 2
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  96. 4 4
      dist/preview release/materialsLibrary/babylon.fireMaterial.d.ts
  97. 13 7
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  98. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  99. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.d.ts
  100. 0 0
      dist/preview release/materialsLibrary/babylon.furMaterial.js

+ 26 - 13
.vscode/launch.json

@@ -2,6 +2,19 @@
     "version": "0.1.0",
     "configurations": [
         {
+            "name": "Launch Viewer (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:9000/",
+            "webRoot": "${workspaceRoot}/Viewer/dist/",
+            "sourceMaps": true,
+            //"preLaunchTask": "build-viewer", // TODO - test why this fails.
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },
+        {
             "name": "Launch nullEngine",
             "type": "node",
             "request": "launch",
@@ -17,22 +30,22 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },         
+        },
         {
             "name": "Launch playground (Chrome)",
             "type": "chrome",
             "request": "launch",
             "url": "http://localhost:1338/Playground/index-local.html",
             "webRoot": "${workspaceRoot}/",
-            "sourceMaps": true,            
+            "sourceMaps": true,
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },        
+        },
         {
             "name": "Launch playground (Chrome+WebGL 1.0 forced)",
             "type": "chrome",
@@ -43,7 +56,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--disable-es3-apis" 
+                "--disable-es3-apis"
             ]
         },
         {
@@ -56,7 +69,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -69,7 +82,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -82,7 +95,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -95,7 +108,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -108,9 +121,9 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },      
+        },
         {
             "name": "Launch Build Validation (Chrome)",
             "type": "chrome",
@@ -121,7 +134,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         }
     ]

+ 1 - 1
.vscode/settings.json

@@ -36,4 +36,4 @@
         "assets":true
     },
     "typescript.check.workspaceVersion": false
-}
+}

+ 2 - 0
Playground/_headers

@@ -0,0 +1,2 @@
+/*
+	Access-Control-Allow-Origin: *

+ 77 - 0
Playground/full.html

@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <title>Babylon.js Playground</title>
+    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+	<meta name="msapplication-TileColor" content="#ffffff">
+	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+	<meta name="theme-color" content="#ffffff">
+
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <!-- Babylon.js -->
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://preview.babylonjs.com/babylon.js"></script>    
+    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
+
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+    
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>    
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
+    <link href="frame.css" rel="stylesheet" />
+</head>
+
+<body>
+    <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
+    <script src="https://code.jquery.com/jquery.js"></script>
+    <script src="js/frame.js"></script>
+</body>
+
+</html>

+ 19 - 9
Playground/js/frame.js

@@ -1,5 +1,5 @@
 (function () {
-    var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
+    var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
     var currentSnippetToken;
     var engine;
     var fpsLabel = document.getElementById("fpsLabel");
@@ -43,7 +43,7 @@
         xhr.send(null);
     };
 
-    var showError = function(error) {
+    var showError = function (error) {
         console.warn(error);
     };
 
@@ -61,7 +61,7 @@
             }
 
             var canvas = document.getElementById("renderCanvas");
-            engine = new BABYLON.Engine(canvas, true, {stencil: true});
+            engine = new BABYLON.Engine(canvas, true, { stencil: true });
             BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
 
             engine.runRenderLoop(function () {
@@ -79,7 +79,9 @@
                     scene.render();
                 }
 
-                fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                if (fpsLabel) {
+                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                }
             });
 
             var scene;
@@ -152,21 +154,29 @@
                             var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText)[0].jsonPayload).code;
                             compileAndRun(snippetCode);
 
-                            document.getElementById("refresh").addEventListener("click", function () {
-                                compileAndRun(snippetCode);
-                            });
+                            var refresh = document.getElementById("refresh");
+
+                            if (refresh) {
+                                refresh.addEventListener("click", function () {
+                                    compileAndRun(snippetCode);
+                                });
+                            }
                         }
                     }
                 };
 
                 var hash = location.hash.substr(1);
                 currentSnippetToken = hash.split("#")[0];
-                if(!hash.split("#")[1]) hash += "#0";
+                if (!hash.split("#")[1]) hash += "#0";
 
                 xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
                 xmlHttp.send();
 
-                document.getElementById("link").href = "//www.babylonjs-playground.com/#" + hash;
+                var link = document.getElementById("link");
+
+                if (link) {
+                    link.href = "//www.babylonjs-playground.com/#" + hash;
+                }
             } catch (e) {
 
             }

+ 1 - 1
Playground/js/index.js

@@ -75,7 +75,7 @@
             markDirty();
         });
 
-        var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
+        var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
         var currentSnippetToken;
         var currentSnippetTitle = null;
         var currentSnippetDescription = null;

+ 17 - 17
Playground/package.json

@@ -1,17 +1,17 @@
-{
-  "name": "babylonjsplayground",
-  "version": "3.0.0",
-  "description": "Babylon.js is a 3D engine based on webgl and javascript",
-  "main": "",
-  "repository": {
-    "url": "https://github.com/BabylonJS/Babylon.js/"
-  },
-  "readme": "https://github.com/BabylonJS/Babylon.js/blob/master/readme.md",
-  "license": "(Apache-2.0)",
-  "devDependencies": {
-    "monaco-editor": "~0.10.0"
-  },
-  "scripts": {
-    "test": "browser-sync start --server --files **/* --no-inject-changes --startPath index.html"
-  }
-}
+{
+  "name": "babylonjsplayground",
+  "version": "3.0.0",
+  "description": "Babylon.js is a 3D engine based on webgl and javascript",
+  "main": "",
+  "repository": {
+    "url": "https://github.com/BabylonJS/Babylon.js/"
+  },
+  "readme": "https://github.com/BabylonJS/Babylon.js/blob/master/readme.md",
+  "license": "(Apache-2.0)",
+  "devDependencies": {
+    "monaco-editor": "~0.10.0"
+  },
+  "scripts": {
+    "test": "browser-sync start --server --files **/* --no-inject-changes --startPath index.html"
+  }
+}

+ 143 - 0
Playground/scripts/physics.js

@@ -0,0 +1,143 @@
+var createScene = function () {
+    var scene = new BABYLON.Scene(engine);
+    scene.clearColor = BABYLON.Color3.Purple();
+
+    var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 0, -20), scene);
+    camera.attachControl(canvas, true);
+    camera.checkCollisions = true;
+    camera.applyGravity = true;
+    camera.setTarget(new BABYLON.Vector3(0, 0, 0));
+
+    var light = new BABYLON.DirectionalLight("dir02", new BABYLON.Vector3(0.2, -1, 0), scene);
+    light.position = new BABYLON.Vector3(0, 80, 0);
+
+    // Material
+    var materialAmiga = new BABYLON.StandardMaterial("amiga", scene);
+    materialAmiga.diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
+    materialAmiga.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+    materialAmiga.diffuseTexture.uScale = 5;
+    materialAmiga.diffuseTexture.vScale = 5;
+
+    var materialAmiga2 = new BABYLON.StandardMaterial("amiga", scene);
+    materialAmiga2.diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
+    materialAmiga2.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+
+    // Shadows
+    var shadowGenerator = new BABYLON.ShadowGenerator(2048, light);
+
+    // Physics
+    //scene.enablePhysics(null, new BABYLON.CannonJSPlugin());
+    scene.enablePhysics(null, new BABYLON.OimoJSPlugin());
+
+    // Spheres
+    var y = 0;
+    for (var index = 0; index < 100; index++) {
+        var sphere = BABYLON.Mesh.CreateSphere("Sphere0", 16, 3, scene);
+        sphere.material = materialAmiga;
+
+        sphere.position = new BABYLON.Vector3(Math.random() * 20 - 10, y, Math.random() * 10 - 5);
+
+        shadowGenerator.addShadowCaster(sphere);
+
+        sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, { mass: 1 }, scene);
+ 
+        y += 2;
+    }
+
+    // Link
+    var spheres = [];
+    for (index = 0; index < 10; index++) {
+        sphere = BABYLON.Mesh.CreateSphere("Sphere0", 16, 1, scene);
+        spheres.push(sphere);
+        sphere.material = materialAmiga2;
+        sphere.position = new BABYLON.Vector3(Math.random() * 20 - 10, y, Math.random() * 10 - 5);
+
+        shadowGenerator.addShadowCaster(sphere);
+
+        sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, { mass: 1 }, scene);
+    }
+
+    for (index = 0; index < 9; index++) {
+        spheres[index].setPhysicsLinkWith(spheres[index + 1], new BABYLON.Vector3(0, 0.5, 0), new BABYLON.Vector3(0, -0.5, 0));
+    }
+
+    // Box
+    var box0 = BABYLON.Mesh.CreateBox("Box0", 3, scene);
+    box0.position = new BABYLON.Vector3(3, 30, 0);
+    var materialWood = new BABYLON.StandardMaterial("wood", scene);
+    materialWood.diffuseTexture = new BABYLON.Texture("textures/crate.png", scene);
+    materialWood.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+    box0.material = materialWood;
+
+    shadowGenerator.addShadowCaster(box0);
+
+    // Compound
+    var part0 = BABYLON.Mesh.CreateBox("part0", 3, scene);
+    part0.position = new BABYLON.Vector3(3, 30, 0);
+    part0.material = materialWood;
+
+    var part1 = BABYLON.Mesh.CreateBox("part1", 3, scene);
+    part1.parent = part0; // We need a hierarchy for compound objects
+    part1.position = new BABYLON.Vector3(0, 3, 0);
+    part1.material = materialWood;
+
+    shadowGenerator.addShadowCaster(part0);
+    shadowGenerator.addShadowCaster(part1);
+	shadowGenerator.useBlurExponentialShadowMap = true;
+    shadowGenerator.useKernelBlur = true;
+    shadowGenerator.blurKernel = 32;
+
+
+    // Playground
+    var ground = BABYLON.Mesh.CreateBox("Ground", 1, scene);
+    ground.scaling = new BABYLON.Vector3(100, 1, 100);
+    ground.position.y = -5.0;
+    ground.checkCollisions = true;
+
+    var border0 = BABYLON.Mesh.CreateBox("border0", 1, scene);
+    border0.scaling = new BABYLON.Vector3(1, 100, 100);
+    border0.position.y = -5.0;
+    border0.position.x = -50.0;
+    border0.checkCollisions = true;
+
+    var border1 = BABYLON.Mesh.CreateBox("border1", 1, scene);
+    border1.scaling = new BABYLON.Vector3(1, 100, 100);
+    border1.position.y = -5.0;
+    border1.position.x = 50.0;
+    border1.checkCollisions = true;
+
+    var border2 = BABYLON.Mesh.CreateBox("border2", 1, scene);
+    border2.scaling = new BABYLON.Vector3(100, 100, 1);
+    border2.position.y = -5.0;
+    border2.position.z = 50.0;
+    border2.checkCollisions = true;
+
+    var border3 = BABYLON.Mesh.CreateBox("border3", 1, scene);
+    border3.scaling = new BABYLON.Vector3(100, 100, 1);
+    border3.position.y = -5.0;
+    border3.position.z = -50.0;
+    border3.checkCollisions = true;
+
+    var groundMat = new BABYLON.StandardMaterial("groundMat", scene);
+    groundMat.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+    groundMat.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
+    groundMat.backFaceCulling = false;
+    ground.material = groundMat;
+    border0.material = groundMat;
+    border1.material = groundMat;
+    border2.material = groundMat;
+    border3.material = groundMat;
+    ground.receiveShadows = true;
+
+    // Physics
+    box0.physicsImpostor = new BABYLON.PhysicsImpostor(box0, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 2, friction: 0.4, restitution: 0.3 }, scene);
+    ground.physicsImpostor = new BABYLON.PhysicsImpostor(ground, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 0, friction: 0.5, restitution: 0.7 }, scene);
+    border0.physicsImpostor = new BABYLON.PhysicsImpostor(border0, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 0 }, scene);
+    border1.physicsImpostor = new BABYLON.PhysicsImpostor(border1, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 0 }, scene);
+    border2.physicsImpostor = new BABYLON.PhysicsImpostor(border2, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 0 }, scene);
+    border3.physicsImpostor = new BABYLON.PhysicsImpostor(border3, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 0 }, scene);
+
+    part0.physicsImpostor = new BABYLON.PhysicsImpostor(part0, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 2, friction: 0.4, restitution: 0.3 }, scene);
+
+    return scene;
+}

+ 2 - 1
Playground/scripts/scripts.txt

@@ -29,4 +29,5 @@ pbr
 instanced bones
 pointer events handling
 webvr
-gui
+gui
+physics

二進制
Playground/textures/WhiteTransarentRamp.png


+ 2 - 4
Playground/zipContent/index.html

@@ -6,10 +6,10 @@
         <title>Babylon.js sample code</title>
         <!-- Babylon.js -->
         <script src="https://www.babylonjs.com/hand.minified-1.2.js"></script>
+        <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/oimo.js"></script>
-        <script src="https://preview.babylonjs.com/babylon.js"></script>
         
         <style>
             html, body {
@@ -28,9 +28,7 @@
         </style>
     </head>
 <body>
-    <div id="canvasZone">
-        <canvas id="renderCanvas"></canvas>
-    </div>
+    <canvas id="renderCanvas"></canvas>
     <script>
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);

+ 37 - 16
Tools/Gulp/config.json

@@ -26,6 +26,7 @@
             "picking",
             "collisions",
             "particles",
+            "gpuParticles",
             "solidParticles",
             "additionalMeshes",
             "meshBuilder",
@@ -72,7 +73,8 @@
             "layer",
             "textureTools",
             "cameraBehaviors",
-            "nullEngine"
+            "nullEngine",
+            "instrumentation"
         ],
         "minimal": [
             "standardMaterial",
@@ -146,7 +148,9 @@
             "layer",
             "textureTools",
             "cameraBehaviors",
+            "instrumentation",
             "materialsLibrary/babylon.gridMaterial.js",
+            "materialsLibrary/babylon.backgroundMaterial.js",
             "loaders/babylon.glTFFileLoader.js"
         ],
         "distributed": [
@@ -217,6 +221,20 @@
                 "particles.fragment"
             ]
         },
+        "gpuParticles": {
+            "files": [
+                "../../src/Particles/babylon.gpuParticleSystem.js"
+            ],
+            "dependUpon": [
+                "core"
+            ],
+            "shaders": [
+                "gpuRenderParticles.vertex",
+                "gpuRenderParticles.fragment",
+                "gpuUpdateParticles.vertex",
+                "gpuUpdateParticles.fragment"
+            ]
+        },
         "nullEngine": {
             "files": [
                 "../../src/Engine/babylon.nullEngine.js"
@@ -224,7 +242,17 @@
             "dependUpon": [
                 "core"
             ]
-        },        
+        },    
+        "instrumentation": {
+            "files": [
+                "../../src/Instrumentation/babylon.engineInstrumentation.js",
+                "../../src/Instrumentation/babylon.sceneInstrumentation.js",
+                "../../src/Instrumentation/babylon.timeToken.js"
+            ],
+            "dependUpon": [
+                "core"
+            ]
+        },      
         "cameraBehaviors": {
             "files": [
                 "../../src/Behaviors/Cameras/babylon.framingBehavior.js",
@@ -1218,25 +1246,18 @@
             },
             {
                 "files": [
-                    "../../materialsLibrary/src/legacyPBR/babylon.legacyPBRMaterial.ts"
+                    "../../materialsLibrary/src/background/babylon.backgroundMaterial.ts"
                 ],
                 "shaderFiles": [
-                    "../../materialsLibrary/src/legacyPBR/legacyPbr.vertex.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbr.fragment.fx"
+                    "../../materialsLibrary/src/background/background.vertex.fx",
+                    "../../materialsLibrary/src/background/background.fragment.fx"
                 ],
                 "shadersIncludeFiles": [
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrFragmentDeclaration.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrFunctions.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrLightFunctions.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrLightFunctionsCall.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrUboDeclaration.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyPbrVertexDeclaration.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyColorCurves.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyColorCurvesDefinition.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyColorGrading.fx",
-                    "../../materialsLibrary/src/legacyPBR/legacyColorGradingDefinition.fx"
+                    "../../materialsLibrary/src/background/backgroundFragmentDeclaration.fx",
+                    "../../materialsLibrary/src/background/backgroundUboDeclaration.fx",
+                    "../../materialsLibrary/src/background/backgroundVertexDeclaration.fx"
                 ],
-                "output": "babylon.legacyPbrMaterial.js"
+                "output": "babylon.backgroundMaterial.js"
             }
         ],
         "build": {

+ 4 - 2
Tools/Gulp/gulpfile.js

@@ -47,7 +47,8 @@ var tsConfig = {
     noImplicitAny: true,
     noImplicitReturns: true,
     noImplicitThis: true,
-    noUnusedLocals: true
+    noUnusedLocals: true,
+    strictNullChecks: true
 };
 var tsProject = typescript.createProject(tsConfig);
 
@@ -61,7 +62,8 @@ var externalTsConfig = {
     noImplicitAny: true,
     noImplicitReturns: true,
     noImplicitThis: true,
-    noUnusedLocals: true
+    noUnusedLocals: true,
+    strictNullChecks: true
 };
 
 function processDependency(kind, dependency, filesToLoad) {

+ 42 - 40
Tools/Gulp/package.json

@@ -1,40 +1,42 @@
-{
-  "name": "BabylonJS",
-  "version": "3.0.0",
-  "description": "Babylon.js is a 3D engine based on webgl and javascript",
-  "main": "",
-  "repository": { "url": "https://github.com/BabylonJS/Babylon.js/" },
-  "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
-  "license": "(Apache-2.0)",
-  "devDependencies": {
-    "gulp": "^3.8.11",
-    "gulp-uglify": "^2.1.2",
-    "gulp-sourcemaps": "~1.9.1",
-    "typescript": "~2.5.3",
-    "gulp-typescript": "^3.2.2",
-    "through2": "~0.6.5",
-    "gulp-util": "~3.0.4",
-    "gulp-concat": "~2.5.2",
-    "merge2": "~0.3.5",
-    "gulp-rename": "~1.2.2",
-    "gulp-clean-ts-extends": "~0.1.1",
-    "gulp-changed-in-place": "2.0.3",
-    "run-sequence": "~1.1.0",
-    "gulp-replace": "~0.5.3",
-    "gulp-content-to-variable": "^0.1.0",
-    "gulp-expect-file": "^0.0.7",
-    "gulp-optimize-js": "^1.0.2",
-    "gulp-webserver": "^0.9.1",
-    "gulp-debug": "^3.0.0",
-    "gulp-sass": "2.3.2",
-    "webpack-stream": "^3.2.0",
-    "css-loader": "^0.25.0",
-    "style-loader": "^0.13.1",
-    "exports-loader": "^0.6.3",
-    "imports-loader": "^0.7.0",
-    "del": "2.2.2"
-  },
-  "scripts": {
-    "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"
-  }
-}
+{
+  "name": "BabylonJS",
+  "version": "3.0.0",
+  "description": "Babylon.js is a 3D engine based on webgl and javascript",
+  "main": "",
+  "repository": {
+    "url": "https://github.com/BabylonJS/Babylon.js/"
+  },
+  "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
+  "license": "(Apache-2.0)",
+  "devDependencies": {
+    "gulp": "^3.8.11",
+    "gulp-uglify": "^2.1.2",
+    "gulp-sourcemaps": "~1.9.1",
+    "typescript": "~2.5.3",
+    "gulp-typescript": "^3.2.2",
+    "through2": "~0.6.5",
+    "gulp-util": "~3.0.4",
+    "gulp-concat": "~2.5.2",
+    "merge2": "~0.3.5",
+    "gulp-rename": "~1.2.2",
+    "gulp-clean-ts-extends": "~0.1.1",
+    "gulp-changed-in-place": "2.0.3",
+    "run-sequence": "~1.1.0",
+    "gulp-replace": "~0.5.3",
+    "gulp-content-to-variable": "^0.1.0",
+    "gulp-expect-file": "^0.0.7",
+    "gulp-optimize-js": "^1.0.2",
+    "gulp-webserver": "^0.9.1",
+    "gulp-debug": "^3.0.0",
+    "gulp-sass": "3.1.0",
+    "webpack-stream": "^3.2.0",
+    "css-loader": "^0.25.0",
+    "style-loader": "^0.13.1",
+    "exports-loader": "^0.6.3",
+    "imports-loader": "^0.7.0",
+    "del": "2.2.2"
+  },
+  "scripts": {
+    "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"
+  }
+}

+ 35 - 0
Viewer/README.md

@@ -0,0 +1,35 @@
+# BabylonJS Viewer
+
+This project is a 3d model viewer using babylonjs.
+
+Please note that this is an *initial release*. The API and project structure could (and probably SHOULD) be changed, so please don't rely on this yet in a productive environment.
+
+The viewer is using the latest Babylon from npm (3.1 alpha).
+
+This documentation is also not full. I will slowly add more and more exmplanations.
+
+## Basic usage
+
+See `basicExample.html` in `/dist`.
+
+Basically, all that is needed is an html tag, and the viewer.js, which includes everything needed to render a Scene:
+
+```html
+<babylon model="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoomBox/glTF/BoomBox.gltf" default-viewer="true"></babylon>
+<script src="viewer.js"></script>
+``` 
+
+This will create a (default) viewer and will load the model in this URL using the gltf loader.
+
+The `babylon` tag will be automatically initialized. 
+
+## Configuration
+
+Configuration can be provided using html attributes or a JSON (at the moment). A configuration Mapper can be registered to create new configuration readers. 
+
+Before I finish a full documentation, take a look at `configuration.ts`
+
+## Templating
+
+The default templates are integrated in the viewer.js file. The current templates are located in `/assets/templates/default/` . Those templates can be extended and registered using the configuration file.
+

二進制
Viewer/assets/img/close.png


二進制
Viewer/assets/img/fullscreen.png


二進制
Viewer/assets/img/help-circle.png


二進制
Viewer/assets/img/loading.png


+ 3 - 0
Viewer/assets/templates/default/defaultTemplate.html

@@ -0,0 +1,3 @@
+<viewer></viewer>
+<loading-screen></loading-screen>
+<overlay></overlay>

+ 26 - 0
Viewer/assets/templates/default/defaultViewer.html

@@ -0,0 +1,26 @@
+<style>
+    viewer {
+        position: relative;
+        overflow: hidden;
+        /* Start stage */
+        flex: 1;
+        z-index: 1;
+        justify-content: center;
+        align-items: center;
+
+        width: 100%;
+        height: 100%;
+    }
+
+    .babylonjs-canvas {
+        flex: 1;
+        width: 100%;
+        height: 100%;
+        touch-action: none;
+    }
+</style>
+
+<canvas class="babylonjs-canvas" id="{{canvasId}}">
+</canvas>
+
+<nav-bar></nav-bar>

+ 1 - 0
Viewer/assets/templates/default/error.html

@@ -0,0 +1 @@
+Error loading the model

+ 1 - 0
Viewer/assets/templates/default/help.html

@@ -0,0 +1 @@
+HELP

+ 41 - 0
Viewer/assets/templates/default/loadingScreen.html

@@ -0,0 +1,41 @@
+<style>
+    /* Loading Screen element */
+
+    loading-screen {
+        position: absolute;
+        z-index: 100;
+        opacity: 1;
+        pointer-events: none;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        -webkit-transition: opacity 2s ease;
+        -moz-transition: opacity 2s ease;
+        transition: opacity 2s ease;
+    }
+
+    img.loading-image {
+        -webkit-animation: spin 2s linear infinite;
+        animation: spin 2s linear infinite;
+    }
+
+    @-webkit-keyframes spin {
+        0% {
+            -webkit-transform: rotate(0deg);
+        }
+        100% {
+            -webkit-transform: rotate(360deg);
+        }
+    }
+
+    @keyframes spin {
+        0% {
+            transform: rotate(0deg);
+        }
+        100% {
+            transform: rotate(360deg);
+        }
+    }
+</style>
+
+<img class="loading-image" src="{{loadingImage}}">

+ 112 - 0
Viewer/assets/templates/default/navbar.html

@@ -0,0 +1,112 @@
+<style>
+    nav-bar {
+        position: absolute;
+        height: 160px;
+        width: 100%;
+        bottom: 0;
+        background-color: rgba(0, 0, 0, 0.3);
+        color: white;
+        transition: 1s;
+        align-items: flex-start;
+        justify-content: space-around;
+        display: flex;
+
+        flex-direction: column;
+    }
+
+    /* Big screens have room for the entire navbar */
+
+    @media screen and (min-width: 768px) {
+        nav-bar {
+            align-items: center;
+            flex-direction: row;
+            justify-content: space-between;
+            height: 80px;
+        }
+    }
+
+    div.flex-container {
+        display: flex;
+        width: 100%;
+    }
+
+    div.thumbnail {
+        position: relative;
+        overflow: hidden;
+        display: block;
+        width: 40px;
+        height: 40px;
+        background-size: cover;
+        background-position: center;
+        border-radius: 20px;
+        margin: 0 10px;
+    }
+
+    div.title-container {
+        flex-direction: column;
+        display: flex;
+        justify-content: space-between;
+    }
+
+    span.model-title {
+        font-size: 125%;
+    }
+
+    span.model-subtitle {
+        font-size: 90%;
+    }
+
+    div.button-container {
+        align-items: center;
+        justify-content: flex-end;
+    }
+
+    div.button {
+        cursor: pointer;
+        height: 30px;
+        margin: 0 10px;
+    }
+
+    div.button img {
+        height: 100%;
+    }
+</style>
+
+{{#if disableOnFullscreen}}
+<style>
+    viewer:fullscreen nav-bar {
+        display: none;
+    }
+
+    viewer:-moz-full-screen nav-bar {
+        display: none;
+    }
+
+    viewer:-webkit-full-screen nav-bar {
+        display: none;
+    }
+</style>
+{{/if}}
+
+<div class="flex-container" id="model-metadata">
+    <!-- holding the description -->
+    <div class="thumbnail">
+        <!-- holding the thumbnail 
+        <img src="{{thumbnail}}" alt="{{title}}">-->
+    </div>
+    <div class="title-container">
+
+        <span class="model-title">{{#if title}}{{title}}{{/if}}</span>
+        <span class="model-subtitle"> {{#if subtitle}}{{subtitle}} {{/if}}</span>
+    </div>
+</div>
+<div class="button-container flex-container">
+    <!-- holding the buttons -->
+    {{#each buttons}}
+    <div id="{{id}}" class="button">
+        {{#if text}}
+        <span>{{text}}</span>> {{/if}} {{#if image}}
+        <img src="{{image}}" alt="{{altText}}"> {{/if}}
+    </div>
+    {{/each}}
+</div>

+ 46 - 0
Viewer/assets/templates/default/overlay.html

@@ -0,0 +1,46 @@
+<style>
+    overlay {
+        position: absolute;
+        z-index: 99;
+        opacity: 0;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        -webkit-transition: opacity 1s ease;
+        -moz-transition: opacity 1s ease;
+        transition: opacity 1s ease;
+    }
+
+    .overlay-item {
+        width: 100%;
+        height: 100%;
+        display: none;
+        align-items: center;
+        justify-content: center;
+        background-color: rgba(121, 121, 121, 0.3);
+    }
+
+    error.overlay-item {
+        background-color: rgba(121, 121, 121, 1);
+    }
+
+    div#close-button {
+        position: absolute;
+        top: 10px;
+        right: 10px;
+        width: 30px;
+        height: 30px;
+        cursor: pointer;
+    }
+
+    div#close-button img {
+        width: 100%;
+    }
+</style>
+
+<div id="close-button">
+    <img src="{{closeImage}}" alt="{{closeText}}">
+</div>
+<help class="overlay-item"></help>
+<error class="overlay-item"></error>
+<share class="overlay-item"></share>

+ 1 - 0
Viewer/assets/templates/default/share.html

@@ -0,0 +1 @@
+SHARE

+ 31 - 0
Viewer/dist/basicExample.html

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                max-width: 800px;
+                max-height: 500px;
+                width: 100%;
+                height: 100%;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon model.title="Amazing Rabbit" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
+        <script src="viewer.js"></script>
+        <script>
+            // a simple way of disabling auto init 
+            BabylonViewer.disableInit = true;
+            // Initializing the viewer on specific HTML tags.
+            BabylonViewer.InitTags('babylon');
+        </script>
+    </body>
+
+</html>

+ 41 - 0
Viewer/dist/domExample.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - DOM usage</title>
+        <style>
+            babylon {
+                width: 800px;
+                height: 500px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon extends="minimal">
+            <model url="https://ugcorigin.s-microsoft.com/12/2e77b8e3-0000-0000-7a48-6505db2f0ef9/952/1508427934473.gltf" title="The Bus!"
+                subtitle="Remix3D" thumbnail="http://d33wubrfki0l68.cloudfront.net/7e08139ddee0ec38005f4232346c7f7386831300/fd934/githubuniverse/remix3d.png">
+            </model>
+            <camera>
+                <behaviors>
+                    <auto-rotate type="0"></auto-rotate>
+                </behaviors>
+            </camera>
+            <lights>
+                <light1 type="1" shadow-enabled="true" position.y="0.5" direction.y="-1" intensity="4.5">
+                    <shadow-config use-blur-exponential-shadow-map="true" use-kernel-blur="true" blur-kernel="64" blur-scale="4">
+
+                    </shadow-config>
+                </light1>
+            </lights>
+        </babylon>
+        <script src="viewer.js"></script>
+    </body>
+
+</html>
+<html>
+
+</html>

二進制
Viewer/dist/environment.dds


文件差異過大導致無法顯示
+ 107292 - 0
Viewer/dist/viewer.js


+ 48 - 0
Viewer/package.json

@@ -0,0 +1,48 @@
+{
+    "name": "babylonjs-viewer",
+    "version": "0.1.0",
+    "description": "A viewer using BabylonJS to display 3D elements natively",
+    "scripts": {
+        "start:server": "webpack-dev-server",
+        "build": "webpack",
+        "test": "echo \"Error: no test specified\" && exit 1"
+    },
+    "repository": {
+        "type": "git",
+        "url": "git+https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "keywords": [
+        "3d",
+        "webgl",
+        "viewer"
+    ],
+    "author": "Raanan Weber",
+    "license": "Apache2",
+    "bugs": {
+        "url": "https://github.com/BabylonJS/Babylon.js/issues"
+    },
+    "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
+    "devDependencies": {
+        "@types/node": "^8.0.47",
+        "base64-image-loader": "^1.2.0",
+        "html-loader": "^0.5.1",
+        "json-loader": "^0.5.7",
+        "ts-loader": "^2.3.7",
+        "typescript": "^2.6.1",
+        "uglifyjs-webpack-plugin": "^1.0.1",
+        "webpack": "^3.8.1",
+        "webpack-dev-server": "^2.9.4"
+    },
+    "dependencies": {
+        "babylonjs": "^3.1.0-alpha3.7",
+        "babylonjs-loaders": "^3.1.0-alpha3.7",
+        "babylonjs-materials": "^3.1.0-alpha3.7",
+        "babylonjs-post-process": "^3.1.0-alpha3.7",
+        "babylonjs-procedural-textures": "^3.1.0-alpha3.7",
+        "es6-promise": "^4.1.1",
+        "handlebars": "^4.0.11",
+        "lodash": "^4.17.4",
+        "lodash.merge": "^4.6.0",
+        "promise-polyfill": "^6.0.2"
+    }
+}

+ 178 - 0
Viewer/src/configuration/configuration.ts

@@ -0,0 +1,178 @@
+import { ITemplateConfiguration } from './../templateManager';
+
+export interface ViewerConfiguration {
+
+    // configuration version
+    version?: string;
+    extends?: string; // is this configuration extending an existing configuration?
+
+    pageUrl?: string; // will be used for sharing and other fun stuff. This is the page showing the model (not the model's url!)
+
+    configuration?: string | {
+        url: string;
+        mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
+    };
+
+    // native (!!!) javascript events. Mainly used in the JSON-format.
+    // those events will be triggered by the container element (the <babylon> tag);
+    events?: {
+        load: boolean | string;
+        init: boolean | string;
+        meshselected: boolean | string;
+        pointerdown: boolean | string;
+        pointerup: boolean | string;
+        pointermove: boolean | string;
+        // load: 'onViewerLoaded' // will trigger the event prefix-onViewerLoaded instead of prefix-onLoad (and ONLY this event).
+    } | boolean; //events: true - fire all events
+    eventPrefix?: string;
+
+    canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
+
+    model?: {
+        url?: string;
+        loader?: string; // obj, gltf?
+        position?: { x: number, y: number, z: number };
+        rotation?: { x: number, y: number, z: number, w: number };
+        scaling?: { x: number, y: number, z: number };
+        parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
+
+        [propName: string]: any; // further configuration, like title and creator
+    } | string,
+
+    description?: string | {
+        title: string;
+        subtitle?: string;
+        thumbnail?: string; // URL or data-url
+    };
+
+    scene?: {
+        autoRotate?: boolean;
+        rotationSpeed?: number;
+        defaultCamera?: boolean;
+        defaultLight?: boolean;
+        clearColor?: { r: number, g: number, b: number, a: number };
+        imageProcessingConfiguration?: IImageProcessingConfiguration;
+    },
+    // at the moment, support only a single camera.
+    camera?: {
+        position?: { x: number, y: number, z: number };
+        rotation?: { x: number, y: number, z: number, w: number };
+        fov?: number;
+        fovMode?: number;
+        minZ?: number;
+        maxZ?: number;
+        inertia?: number;
+        behaviors?: {
+            [name: string]: number | {
+                type: number;
+                [propName: string]: any;
+            };
+        };
+
+        [propName: string]: any;
+    },
+    skybox?: {
+        cubeTexture: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url: string | Array<string>;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+        };
+        infiniteDIstance?: boolean;
+
+    };
+
+    ground?: boolean | {
+        size?: number;
+        receiveShadows?: boolean;
+        shadowOnly?: boolean;
+        material?: {
+            [propName: string]: any;
+        }
+    };
+    lights?: {
+        [name: string]: {
+            type: number;
+            name?: string;
+            disabled?: boolean;
+            position?: { x: number, y: number, z: number };
+            target?: { x: number, y: number, z: number };
+            direction?: { x: number, y: number, z: number };
+            diffuse?: { r: number, g: number, b: number };
+            specular?: { r: number, g: number, b: number };
+            intensity?: number;
+            radius?: number;
+            shadownEnabled?: boolean; // only on specific lights!
+            shadowConfig?: {
+                useBlurExponentialShadowMap?: boolean;
+                useKernelBlur?: boolean;
+                blurKernel?: number;
+                blurScale?: number;
+                [propName: string]: any;
+            }
+            [propName: string]: any;
+
+            // no behaviors for light at the moment, but allowing configuration for future reference.
+            behaviors?: {
+                [name: string]: number | {
+                    type: number;
+                    [propName: string]: any;
+                };
+            };
+        }
+    },
+    // engine configuration. optional!
+    engine?: {
+        antialiasing?: boolean;
+    },
+    //templateStructure?: ITemplateStructure,
+    templates?: {
+        main: ITemplateConfiguration,
+        [key: string]: ITemplateConfiguration
+    };
+    // nodes?
+}
+
+export interface IImageProcessingConfiguration {
+    colorGradingEnabled?: boolean;
+    colorCurvesEnabled?: boolean;
+    colorCurves?: {
+        globalHue?: number;
+        globalDensity?: number;
+        globalSaturation?: number;
+        globalExposure?: number;
+        highlightsHue?: number;
+        highlightsDensity?: number;
+        highlightsSaturation?: number;
+        highlightsExposure?: number;
+        midtonesHue?: number;
+        midtonesDensity?: number;
+        midtonesSaturation?: number;
+        midtonesExposure?: number;
+        shadowsHue?: number;
+        shadowsDensity?: number;
+        shadowsSaturation?: number;
+        shadowsExposure?: number;
+    };
+    colorGradingWithGreenDepth?: boolean;
+    colorGradingBGR?: boolean;
+    exposure?: number;
+    toneMappingEnabled?: boolean;
+    contrast?: number;
+    vignetteEnabled?: boolean;
+    vignetteStretch?: number;
+    vignetteCentreX?: number;
+    vignetteCentreY?: number;
+    vignetteWeight?: number;
+    vignetteColor?: { r: number, g: number, b: number, a?: number };
+    vignetteCameraFov?: number;
+    vignetteBlendMode?: number;
+    vignetteM?: boolean;
+    applyByPostProcess?: boolean;
+
+}

+ 0 - 0
Viewer/src/configuration/index.ts


+ 79 - 0
Viewer/src/configuration/loader.ts

@@ -0,0 +1,79 @@
+import { mapperManager } from './mappers';
+import { ViewerConfiguration } from './configuration';
+import { getConfigurationType } from './types';
+
+import * as merge from 'lodash.merge';
+
+export class ConfigurationLoader {
+
+    private configurationCache: { (url: string): any };
+
+    public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
+
+        let loadedConfig = merge({}, initConfig);
+
+        let extendedConfiguration = getConfigurationType(loadedConfig && loadedConfig.extends);
+
+        loadedConfig = merge(extendedConfiguration, loadedConfig);
+
+        if (loadedConfig.configuration) {
+
+            let mapperType = "json";
+            let url = loadedConfig.configuration;
+
+            // if configuration is an object
+            if (loadedConfig.configuration.url) {
+                url = loadedConfig.configuration.url;
+                mapperType = loadedConfig.configuration.mapper;
+                if (!mapperType) {
+                    // load mapper type from filename / url
+                    mapperType = loadedConfig.configuration.url.split('.').pop();
+                }
+            }
+
+            let mapper = mapperManager.getMapper(mapperType);
+            return this.loadFile(url).then((data: any) => {
+                let parsed = mapper.map(data);
+                return merge(loadedConfig, parsed);
+            });
+        } else {
+            return Promise.resolve(loadedConfig);
+        }
+    }
+
+    public getConfigurationType(type: string) {
+
+    }
+
+    private loadFile(url: string): Promise<any> {
+        let cacheReference = this.configurationCache;
+        if (cacheReference[url]) {
+            return Promise.resolve(cacheReference[url]);
+        }
+
+        return new Promise(function (resolve, reject) {
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url);
+            xhr.send();
+            xhr.onreadystatechange = function () {
+                var DONE = 4;
+                var OK = 200;
+                if (xhr.readyState === DONE) {
+                    if (xhr.status === OK) {
+                        cacheReference[url] = xhr.responseText;
+                        resolve(xhr.responseText); // 'This is the returned text.'
+                    }
+                } else {
+                    console.log('Error: ' + xhr.status, url);
+                    reject('Error: ' + xhr.status); // An error occurred during the request.
+                }
+            }
+        });
+    }
+
+
+}
+
+export let configurationLoader = new ConfigurationLoader();
+
+export default configurationLoader;

+ 123 - 0
Viewer/src/configuration/mappers.ts

@@ -0,0 +1,123 @@
+import { Tools } from 'babylonjs';
+import { ViewerConfiguration } from './configuration';
+
+import { kebabToCamel } from '../helper';
+
+import * as merge from 'lodash.merge';
+
+export interface IMapper {
+    map(rawSource: any): ViewerConfiguration;
+}
+
+class HTMLMapper implements IMapper {
+
+    map(element: HTMLElement): ViewerConfiguration {
+
+        let config = {};
+        for (let attrIdx = 0; attrIdx < element.attributes.length; ++attrIdx) {
+            let attr = element.attributes.item(attrIdx);
+            // map "object.property" to the right configuration place.
+            let split = attr.nodeName.split('.');
+            split.reduce((currentConfig, key, idx) => {
+                //convert html-style to json-style
+                let camelKey = kebabToCamel(key);
+                if (idx === split.length - 1) {
+                    let val: any = attr.nodeValue; // firefox warns nodeValue is deprecated, but I found no sign of it anywhere.
+                    if (val === "true") {
+                        val = true;
+                    } else if (val === "false") {
+                        val = false;
+                    } else {
+                        let number = parseFloat(val);
+                        if (!isNaN(number)) {
+                            val = number;
+                        }
+                    }
+                    currentConfig[camelKey] = val;
+                } else {
+                    currentConfig[camelKey] = currentConfig[camelKey] || {};
+                }
+                return currentConfig[camelKey];
+            }, config);
+        }
+
+        return config;
+    }
+}
+
+class JSONMapper implements IMapper {
+    map(rawSource: any) {
+        return JSON.parse(rawSource);
+    }
+}
+
+// TODO - Dom configuration mapper.
+class DOMMapper implements IMapper {
+
+    map(baseElement: HTMLElement): ViewerConfiguration {
+        let htmlMapper = new HTMLMapper();
+        let config = htmlMapper.map(baseElement);
+
+        let traverseChildren = function (element: HTMLElement, partConfig) {
+            let children = element.children;
+            if (children.length) {
+                for (let i = 0; i < children.length; ++i) {
+                    let item = <HTMLElement>children.item(i);
+                    let configMapped = htmlMapper.map(item);
+                    let key = kebabToCamel(item.nodeName.toLowerCase());
+                    if (item.attributes.getNamedItem('array') && item.attributes.getNamedItem('array').nodeValue === 'true') {
+                        partConfig[key] = [];
+                    } else {
+                        if (element.attributes.getNamedItem('array') && element.attributes.getNamedItem('array').nodeValue === 'true') {
+                            partConfig.push(configMapped)
+                        } else if (partConfig[key]) {
+                            //exists already! problem... probably an array
+                            element.setAttribute('array', 'true');
+                            let oldItem = partConfig[key];
+                            partConfig = [oldItem, configMapped]
+                        } else {
+                            partConfig[key] = configMapped;
+                        }
+                    }
+                    traverseChildren(item, partConfig[key] || configMapped);
+                }
+            }
+            return partConfig;
+        }
+
+        traverseChildren(baseElement, config);
+
+
+        return config;
+    }
+
+}
+
+export class MapperManager {
+
+    private mappers: { [key: string]: IMapper };
+    public static DefaultMapper = 'json';
+
+    constructor() {
+        this.mappers = {
+            "html": new HTMLMapper(),
+            "json": new JSONMapper(),
+            "dom": new DOMMapper()
+        }
+    }
+
+    public getMapper(type: string) {
+        if (!this.mappers[type]) {
+            Tools.Error("No mapper defined for " + type);
+        }
+        return this.mappers[type] || this.mappers[MapperManager.DefaultMapper];
+    }
+
+    public registerMapper(type: string, mapper: IMapper) {
+        this.mappers[type] = mapper;
+    }
+
+}
+
+export let mapperManager = new MapperManager();
+export default mapperManager;

文件差異過大導致無法顯示
+ 126 - 0
Viewer/src/configuration/types/default.ts


+ 16 - 0
Viewer/src/configuration/types/index.ts

@@ -0,0 +1,16 @@
+import { minimalConfiguration } from './minimal';
+import { defaultConfiguration } from './default';
+
+let getConfigurationType = function (type: string) {
+    switch (type) {
+        case 'default':
+            return defaultConfiguration;
+        case 'minimal':
+            return minimalConfiguration;
+        default:
+            return defaultConfiguration;
+    }
+
+}
+
+export { getConfigurationType, defaultConfiguration, minimalConfiguration }

文件差異過大導致無法顯示
+ 34 - 0
Viewer/src/configuration/types/minimal.ts


+ 41 - 0
Viewer/src/helper.ts

@@ -0,0 +1,41 @@
+export function isUrl(urlToCheck: string): boolean {
+    if (urlToCheck.indexOf('http') === 0 || urlToCheck.indexOf('/') === 0 || urlToCheck.indexOf('./') === 0 || urlToCheck.indexOf('../') === 0) {
+        return true;
+    }
+    return false;
+}
+
+export function loadFile(url: string): Promise<any> {
+    /*let cacheReference = this.configurationCache;
+    if (cacheReference[url]) {
+        return Promise.resolve(cacheReference[url]);
+    }*/
+
+    return new Promise(function (resolve, reject) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url);
+        xhr.send();
+        xhr.onreadystatechange = function () {
+            var DONE = 4;
+            var OK = 200;
+            if (xhr.readyState === DONE) {
+                if (xhr.status === OK) {
+                    //cacheReference[url] = xhr.responseText;
+                    resolve(xhr.responseText); // 'This is the returned text.'
+                }
+            } else {
+                console.log('Error: ' + xhr.status, url);
+                reject('Error: ' + xhr.status); // An error occurred during the request.
+            }
+        }
+    });
+}
+
+export function kebabToCamel(s) {
+    return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
+}
+
+//https://gist.github.com/youssman/745578062609e8acac9f
+export function camelToKebab(str) {
+    return !str ? null : str.replace(/([A-Z])/g, function (g) { return '-' + g[0].toLowerCase() });
+}

+ 30 - 0
Viewer/src/index.ts

@@ -0,0 +1,30 @@
+import { viewerManager } from './viewer/viewerManager';
+import { DefaultViewer } from './viewer/defaultViewer';
+import { AbstractViewer } from './viewer/viewer';
+
+/**
+ * BabylonJS Viewer
+ * 
+ * An HTML-Based viewer for 3D models, based on BabylonJS and its extensions.
+ */
+
+
+// load babylon and needed modules.
+import 'babylonjs';
+import 'babylonjs-loaders';
+import 'babylonjs-materials';
+
+import { InitTags } from './initializer';
+
+// promise polyfill, if needed!
+global.Promise = Promise || require('es6-promise').Promise;
+
+export let disableInit: boolean = false;
+
+setTimeout(() => {
+    if (disableInit) return;
+    InitTags();
+});
+
+// public API for initialization
+export { InitTags, DefaultViewer, AbstractViewer, viewerManager };

+ 15 - 0
Viewer/src/initializer.ts

@@ -0,0 +1,15 @@
+import { DefaultViewer } from './viewer/defaultViewer';
+import { mapperManager } from './configuration/mappers';
+
+export function InitTags(selector: string = 'babylon') {
+    let elements = document.querySelectorAll(selector);
+    for (let i = 0; i < elements.length; ++i) {
+        let element: HTMLElement = <HTMLElement>elements.item(i);
+
+        // get the html configuration
+        let configMapper = mapperManager.getMapper('dom');
+        let config = configMapper.map(element);
+
+        let viewer = new DefaultViewer(element, config);
+    }
+}

+ 5 - 0
Viewer/src/interfaces.ts

@@ -0,0 +1,5 @@
+export const enum CameraBehavior {
+    AUTOROTATION,
+    BOUNCING,
+    FRAMING
+}

+ 316 - 0
Viewer/src/templateManager.ts

@@ -0,0 +1,316 @@
+
+import { Observable } from 'babylonjs';
+import { isUrl, loadFile, camelToKebab, kebabToCamel } from './helper';
+
+export interface ITemplateConfiguration {
+    location?: string; // #template-id OR http://example.com/loading.html
+    html?: string; // raw html string
+    id?: string;
+    params?: { [key: string]: string | number | boolean | object };
+    events?: {
+        // pointer events
+        pointerdown?: boolean | { [id: string]: boolean; };
+        pointerup?: boolean | { [id: string]: boolean; };
+        pointermove?: boolean | { [id: string]: boolean; };
+        pointerover?: boolean | { [id: string]: boolean; };
+        pointerout?: boolean | { [id: string]: boolean; };
+        pointerenter?: boolean | { [id: string]: boolean; };
+        pointerleave?: boolean | { [id: string]: boolean; };
+        pointercancel?: boolean | { [id: string]: boolean; };
+        //click, just in case
+        click?: boolean | { [id: string]: boolean; };
+        // drag and drop
+        dragstart?: boolean | { [id: string]: boolean; };
+        drop?: boolean | { [id: string]: boolean; };
+
+        [key: string]: boolean | { [id: string]: boolean; } | undefined;
+    }
+}
+
+export interface EventCallback {
+    event: Event;
+    template: Template;
+    selector: string;
+    payload?: any;
+}
+
+export class TemplateManager {
+
+    public onInit: Observable<Template>;
+    public onLoaded: Observable<Template>;
+    public onStateChange: Observable<Template>;
+    public onAllLoaded: Observable<TemplateManager>;
+
+    private templates: { [name: string]: Template };
+
+    constructor(public containerElement: HTMLElement) {
+        this.templates = {};
+
+        this.onInit = new Observable<Template>();
+        this.onLoaded = new Observable<Template>();
+        this.onStateChange = new Observable<Template>();
+        this.onAllLoaded = new Observable<TemplateManager>();
+    }
+
+    public initTemplate(templates: { [key: string]: ITemplateConfiguration }) {
+
+        let internalInit = (dependencyMap, name: string, parentTemplate?: Template) => {
+            //init template
+            let template = this.templates[name];
+
+            let childrenTemplates = Object.keys(dependencyMap).map(childName => {
+                return internalInit(dependencyMap[childName], childName, template);
+            });
+
+            // register the observers
+            //template.onLoaded.add(() => {
+            let addToParent = () => {
+                let containingElement = parentTemplate && parentTemplate.parent.querySelector(camelToKebab(name)) || this.containerElement;
+                template.appendTo(containingElement);
+                this.checkLoadedState();
+            }
+
+            if (parentTemplate && !parentTemplate.parent) {
+                parentTemplate.onAppended.add(() => {
+                    addToParent();
+                });
+            } else {
+                addToParent();
+            }
+            //});
+
+            return template;
+        }
+
+        //build the html tree
+        this.buildHTMLTree(templates).then(htmlTree => {
+            internalInit(htmlTree, 'main');
+        });
+    }
+
+    /**
+     * 
+     * This function will create a simple map with child-dependencies of the template html tree.
+     * It will compile each template, check if its children exist in the configuration and will add them if they do.
+     * It is expected that the main template will be called main!
+     * 
+     * @private
+     * @param {{ [key: string]: ITemplateConfiguration }} templates 
+     * @memberof TemplateManager
+     */
+    private buildHTMLTree(templates: { [key: string]: ITemplateConfiguration }): Promise<object> {
+        let promises = Object.keys(templates).map(name => {
+            let template = new Template(name, templates[name]);
+            this.templates[name] = template;
+            return template.initPromise;
+        });
+
+        return Promise.all(promises).then(() => {
+            let templateStructure = {};
+            // now iterate through all templates and check for children:
+            let buildTree = (parentObject, name) => {
+                let childNodes = this.templates[name].getChildElements().filter(n => !!this.templates[n]);
+                childNodes.forEach(element => {
+                    parentObject[element] = {};
+                    buildTree(parentObject[element], element);
+                });
+            }
+
+            buildTree(templateStructure, "main");
+            return templateStructure;
+        });
+    }
+
+    // assumiung only ONE(!) canvas
+    public getCanvas(): HTMLCanvasElement | null {
+        return this.containerElement.querySelector('canvas');
+    }
+
+    public getTemplate(name: string): Template | undefined {
+        return this.templates[name];
+    }
+
+    private checkLoadedState() {
+        let done = Object.keys(this.templates).every((key) => {
+            return this.templates[key].isLoaded && !!this.templates[key].parent;
+        });
+
+        if (done) {
+            this.onAllLoaded.notifyObservers(this);
+        }
+    }
+
+}
+
+
+import * as Handlebars from 'handlebars/dist/handlebars.min.js';
+
+export class Template {
+
+    public onInit: Observable<Template>;
+    public onLoaded: Observable<Template>;
+    public onAppended: Observable<Template>;
+    public onStateChange: Observable<Template>;
+    public onEventTriggered: Observable<EventCallback>;
+
+    public isLoaded: boolean;
+
+    public parent: HTMLElement;
+
+    public initPromise: Promise<Template>;
+
+    private fragment: DocumentFragment;
+
+    constructor(public name: string, private _configuration: ITemplateConfiguration) {
+        this.onInit = new Observable<Template>();
+        this.onLoaded = new Observable<Template>();
+        this.onAppended = new Observable<Template>();
+        this.onStateChange = new Observable<Template>();
+        this.onEventTriggered = new Observable<EventCallback>();
+
+        this.isLoaded = false;
+        /*
+        if (configuration.id) {
+            this.parent.id = configuration.id;
+        }
+        */
+        this.onInit.notifyObservers(this);
+
+        let htmlContentPromise = getTemplateAsHtml(_configuration);
+
+        this.initPromise = htmlContentPromise.then(htmlTemplate => {
+            if (htmlTemplate) {
+                let compiledTemplate = Handlebars.compile(htmlTemplate);
+                let config = this._configuration.params || {};
+                let rawHtml = compiledTemplate(config);
+                this.fragment = document.createRange().createContextualFragment(rawHtml);
+                this.isLoaded = true;
+                this.onLoaded.notifyObservers(this);
+            }
+            return this;
+        });
+    }
+
+    public get configuration(): ITemplateConfiguration {
+        return this._configuration;
+    }
+
+    public getChildElements(): Array<string> {
+        let childrenArray: string[] = [];
+        //Edge and IE don't support frage,ent.children
+        let children = this.fragment.children;
+        if (!children) {
+            // casting to HTMLCollection, as both NodeListOf and HTMLCollection have 'item()' and 'length'.
+            children = <HTMLCollection>this.fragment.querySelectorAll('*');
+        }
+        for (let i = 0; i < children.length; ++i) {
+            childrenArray.push(kebabToCamel(children.item(i).nodeName.toLowerCase()));
+        }
+        return childrenArray;
+    }
+
+    public appendTo(parent: HTMLElement) {
+        if (this.parent) {
+            console.error('Already appanded to ', this.parent);
+        } else {
+            this.parent = parent;
+
+            if (this._configuration.id) {
+                this.parent.id = this._configuration.id;
+            }
+            this.parent.appendChild(this.fragment);
+            // appended only one frame after.
+            setTimeout(() => {
+                this.registerEvents();
+                this.onAppended.notifyObservers(this);
+            });
+        }
+
+    }
+
+    public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (visibilityFunction) {
+            return visibilityFunction(this).then(() => {
+                this.onStateChange.notifyObservers(this);
+                return this;
+            });
+        } else {
+            // flex? box? should this be configurable easier than the visibilityFunction?
+            this.parent.style.display = 'flex';
+            this.onStateChange.notifyObservers(this);
+            return Promise.resolve(this);
+        }
+    }
+
+    public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (visibilityFunction) {
+            return visibilityFunction(this).then(() => {
+                this.onStateChange.notifyObservers(this);
+                return this;
+            });
+        } else {
+            this.parent.style.display = 'none';
+            this.onStateChange.notifyObservers(this);
+            return Promise.resolve(this);
+        }
+    }
+
+    // TODO - Should events be removed as well? when are templates disposed?
+    private registerEvents() {
+        if (this._configuration.events) {
+            for (let eventName in this._configuration.events) {
+                if (this._configuration.events && this._configuration.events[eventName]) {
+                    let functionToFire = (selector, event) => {
+                        this.onEventTriggered.notifyObservers({ event: event, template: this, selector: selector });
+                    }
+
+                    // if boolean, set the parent as the event listener
+                    if (typeof this._configuration.events[eventName] === 'boolean') {
+                        this.parent.addEventListener(eventName, functionToFire.bind(this, '#' + this.parent.id), false);
+                    } else if (typeof this._configuration.events[eventName] === 'object') {
+                        let selectorsArray: Array<string> = Object.keys(this._configuration.events[eventName] || {});
+                        // strict null checl is working incorrectly, must override:
+                        let event = this._configuration.events[eventName] || {};
+                        selectorsArray.filter(selector => event[selector]).forEach(selector => {
+                            if (selector.indexOf('#') !== 0) {
+                                selector = '#' + selector;
+                            }
+                            let htmlElement = <HTMLElement>this.parent.querySelector(selector);
+                            htmlElement && htmlElement.addEventListener(eventName, functionToFire.bind(this, selector), false)
+                        });
+                    }
+                }
+            }
+        }
+    }
+
+}
+
+export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
+    if (!templateConfig) {
+        return Promise.reject('No templateConfig provided');
+    } else if (templateConfig.html) {
+        return Promise.resolve(templateConfig.html);
+    } else {
+        let location = getTemplateLocation(templateConfig);
+        if (isUrl(location)) {
+            return loadFile(location);
+        } else {
+            location = location.replace('#', '');
+            let element = document.getElementById('#' + location);
+            if (element) {
+                return Promise.resolve(element.innerHTML);
+            } else {
+                return Promise.reject('Template ID not found');
+            }
+        }
+    }
+}
+
+export function getTemplateLocation(templateConfig): string {
+    if (!templateConfig || typeof templateConfig === 'string') {
+        return templateConfig;
+    } else {
+        return templateConfig.location;
+    }
+}

+ 462 - 0
Viewer/src/viewer/defaultViewer.ts

@@ -0,0 +1,462 @@
+import { Template } from './../templateManager';
+import { AbstractViewer } from './viewer';
+import { Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { CameraBehavior } from '../interfaces';
+
+// A small hack for the inspector. to be removed!
+import * as BABYLON from 'babylonjs';
+window['BABYLON'] = BABYLON;
+
+export class DefaultViewer extends AbstractViewer {
+
+    public camera: ArcRotateCamera;
+
+    public initScene(): Promise<Scene> {
+        return super.initScene().then(() => {
+            this.extendClassWithConfig(this.scene, this.configuration.scene);
+            return this.scene;
+        })
+    }
+
+    protected onTemplatesLoaded() {
+
+        this.showLoadingScreen();
+
+        // navbar
+        let viewerElement = this.templateManager.getTemplate('viewer');
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (viewerElement && navbar) {
+            let navbarHeight = navbar.parent.clientHeight + 'px';
+
+            let navbarShown: boolean = true;
+            let timeoutCancel /*: number*/;
+
+            let triggerNavbar = function (show: boolean = false, evt: PointerEvent) {
+                // only left-click on no-button.
+                if (!navbar || evt.button > 0) return;
+                // clear timeout
+                timeoutCancel && clearTimeout(timeoutCancel);
+                // if state is the same, do nothing
+                if (show === navbarShown) return;
+                //showing? simply show it!
+                if (show) {
+                    navbar.parent.style.bottom = show ? '0px' : '-' + navbarHeight;
+                    navbarShown = show;
+                } else {
+                    let visibilityTimeout = 2000;
+                    if (navbar.configuration.params && navbar.configuration.params.visibilityTimeout !== undefined) {
+                        visibilityTimeout = <number>navbar.configuration.params.visibilityTimeout;
+                    }
+                    // not showing? set timeout until it is removed.
+                    timeoutCancel = setTimeout(function () {
+                        if (navbar) {
+                            navbar.parent.style.bottom = '-' + navbarHeight;
+                        }
+                        navbarShown = show;
+                    }, visibilityTimeout);
+                }
+            }
+
+
+
+            viewerElement.parent.addEventListener('pointerout', triggerNavbar.bind(this, false));
+            viewerElement.parent.addEventListener('pointerdown', triggerNavbar.bind(this, true));
+            viewerElement.parent.addEventListener('pointerup', triggerNavbar.bind(this, false));
+            navbar.parent.addEventListener('pointerover', triggerNavbar.bind(this, true))
+            // triggerNavbar(false);
+
+            // events registration
+            this.registerNavbarButtons();
+        }
+
+        // close overlay button
+        let closeButton = document.getElementById('close-button');
+        if (closeButton) {
+            closeButton.addEventListener('pointerdown', () => {
+                this.hideOverlayScreen();
+            })
+        }
+
+        return super.onTemplatesLoaded();
+    }
+
+    private registerNavbarButtons() {
+        let isFullscreen = false;
+
+        let navbar = this.templateManager.getTemplate('navBar');
+        let viewerTemplate = this.templateManager.getTemplate('viewer');
+        if (!navbar || !viewerTemplate) return;
+
+        let viewerElement = viewerTemplate.parent;
+
+
+        navbar.onEventTriggered.add((data) => {
+            switch (data.event.type) {
+                case 'pointerdown':
+                    let event: PointerEvent = <PointerEvent>data.event;
+                    if (event.button === 0) {
+                        switch (data.selector) {
+                            case '#fullscreen-button':
+                                if (!isFullscreen) {
+                                    let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
+                                    requestFullScreen.call(viewerElement);
+                                } else {
+                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
+                                    exitFullscreen.call(document);
+                                }
+
+                                isFullscreen = !isFullscreen;
+                                break;
+                            case '#help-button':
+                                this.showOverlayScreen('help');
+                                break;
+                        }
+                    }
+                    break;
+            }
+        });
+    }
+
+    protected prepareContainerElement() {
+        this.containerElement.style.position = 'relative';
+        this.containerElement.style.display = 'flex';
+    }
+
+    public loadModel(model: any = this.configuration.model): Promise<Scene> {
+        this.showLoadingScreen();
+        return super.loadModel(model, true).catch((error) => {
+            console.log(error);
+            this.hideLoadingScreen();
+            this.showOverlayScreen('error');
+            return this.scene;
+        });
+    }
+
+    public onModelLoaded(meshes: Array<AbstractMesh>) {
+
+        // here we could set the navbar's model information:
+        this.setModelMetaData();
+
+        // with a short timeout, making sure everything is there already.
+        setTimeout(() => {
+            this.hideLoadingScreen();
+        }, 500);
+
+
+        // recreate the camera
+        this.scene.createDefaultCameraOrLight(true, true, true);
+        this.camera = <ArcRotateCamera>this.scene.activeCamera;
+
+        meshes[0].rotation.y += Math.PI;
+
+        this.setupCamera(meshes);
+        this.setupLights(meshes);
+
+        return this.initEnvironment();
+    }
+
+    private setModelMetaData() {
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (!navbar) return;
+
+        let metadataContainer = navbar.parent.querySelector('#model-metadata');
+
+        //title
+        if (metadataContainer && typeof this.configuration.model === 'object') {
+            if (this.configuration.model.title) {
+                let element = metadataContainer.querySelector('span.model-title');
+                if (element) {
+                    element.innerHTML = this.configuration.model.title;
+                }
+            }
+
+            if (this.configuration.model.subtitle) {
+                let element = metadataContainer.querySelector('span.model-subtitle');
+                if (element) {
+                    element.innerHTML = this.configuration.model.subtitle;
+                }
+            }
+
+            if (this.configuration.model.thumbnail) {
+                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${this.configuration.model.thumbnail}')`;
+            }
+        }
+
+    }
+
+    public initEnvironment(): Promise<Scene> {
+        if (this.configuration.skybox) {
+            // Define a general environment textue
+            let texture;
+            // this is obligatory, but still - making sure it is there.
+            if (this.configuration.skybox.cubeTexture) {
+                if (typeof this.configuration.skybox.cubeTexture.url === 'string') {
+                    texture = CubeTexture.CreateFromPrefilteredData(this.configuration.skybox.cubeTexture.url, this.scene);
+                } else {
+                    texture = CubeTexture.CreateFromImages(this.configuration.skybox.cubeTexture.url, this.scene, this.configuration.skybox.cubeTexture.noMipMap);
+                }
+            }
+            if (texture) {
+                this.extendClassWithConfig(texture, this.configuration.skybox.cubeTexture);
+
+                let scale = this.configuration.skybox.scale || this.scene.activeCamera && (this.scene.activeCamera.maxZ - this.scene.activeCamera.minZ) / 2 || 1;
+
+                let box = this.scene.createDefaultSkybox(texture, this.configuration.skybox.pbr, scale, this.configuration.skybox.blur);
+
+                // before extending, set the material's imageprocessing configuration object, if needed:
+                if (this.configuration.skybox.material && this.configuration.skybox.material.imageProcessingConfiguration && box) {
+                    (<StandardMaterial>box.material).imageProcessingConfiguration = new ImageProcessingConfiguration();
+                }
+
+                this.extendClassWithConfig(box, this.configuration.skybox);
+            }
+        }
+
+        if (this.configuration.ground) {
+            let groundConfig = (typeof this.configuration.ground === 'boolean') ? {} : this.configuration.ground;
+
+            var ground = Mesh.CreateGround('ground', groundConfig.size || 1000, groundConfig.size || 1000, 8, this.scene);
+            if (this.configuration.ground === true || groundConfig.shadowOnly) {
+                ground.material = new ShadowOnlyMaterial('groundmat', this.scene);
+            } else {
+                ground.material = new StandardMaterial('groundmat', this.scene);
+            }
+            //default configuration
+            if (this.configuration.ground === true) {
+                ground.receiveShadows = true;
+                ground.material.alpha = 0.4;
+            }
+
+
+            this.extendClassWithConfig(ground, groundConfig);
+        }
+
+        return Promise.resolve(this.scene);
+    }
+
+    public showOverlayScreen(subScreen: string) {
+        let template = this.templateManager.getTemplate('overlay');
+        if (!template) return Promise.reject('Overlay template not found');
+
+        return template.show((template => {
+
+            var canvasRect = this.containerElement.getBoundingClientRect();
+            var canvasPositioning = window.getComputedStyle(this.containerElement).position;
+
+            template.parent.style.display = 'flex';
+            template.parent.style.width = canvasRect.width + "px";
+            template.parent.style.height = canvasRect.height + "px";
+            template.parent.style.opacity = "1";
+
+            let subTemplate = this.templateManager.getTemplate(subScreen);
+            if (!subTemplate) {
+                return Promise.reject(subScreen + ' template not found');
+            }
+            return subTemplate.show((template => {
+                template.parent.style.display = 'flex';
+                return Promise.resolve(template);
+            }));
+        }));
+    }
+
+    public hideOverlayScreen() {
+        let template = this.templateManager.getTemplate('overlay');
+        if (!template) return Promise.reject('Overlay template not found');
+
+        return template.hide((template => {
+            template.parent.style.opacity = "0";
+            let onTransitionEnd = () => {
+                template.parent.removeEventListener("transitionend", onTransitionEnd);
+                template.parent.style.display = 'none';
+            }
+            template.parent.addEventListener("transitionend", onTransitionEnd);
+
+            let overlays = template.parent.querySelectorAll('.overlay');
+            if (overlays) {
+                for (let i = 0; i < overlays.length; ++i) {
+                    let htmlElement = <HTMLElement>overlays.item(i);
+                    htmlElement.style.display = 'none';
+                }
+            }
+
+            /*return this.templateManager.getTemplate(subScreen).show((template => {
+                template.parent.style.display = 'none';
+                return Promise.resolve(template);
+            }));*/
+            return Promise.resolve(template);
+        }));
+    }
+
+    public showLoadingScreen() {
+        let template = this.templateManager.getTemplate('loadingScreen');
+        if (!template) return Promise.reject('oading Screen template not found');
+
+        return template.show((template => {
+
+            var canvasRect = this.containerElement.getBoundingClientRect();
+            var canvasPositioning = window.getComputedStyle(this.containerElement).position;
+
+            template.parent.style.display = 'flex';
+            template.parent.style.width = canvasRect.width + "px";
+            template.parent.style.height = canvasRect.height + "px";
+            template.parent.style.opacity = "1";
+            // from the configuration!!!
+            template.parent.style.backgroundColor = "black";
+            return Promise.resolve(template);
+        }));
+    }
+
+    public hideLoadingScreen() {
+        let template = this.templateManager.getTemplate('loadingScreen');
+        if (!template) return Promise.reject('oading Screen template not found');
+
+        return template.hide((template => {
+            template.parent.style.opacity = "0";
+            let onTransitionEnd = () => {
+                template.parent.removeEventListener("transitionend", onTransitionEnd);
+                template.parent.style.display = 'none';
+            }
+            template.parent.addEventListener("transitionend", onTransitionEnd);
+            return Promise.resolve(template);
+        }));
+    }
+
+    private setupLights(focusMeshes: Array<AbstractMesh> = []) {
+
+        let sceneConfig = this.configuration.scene || { defaultLight: true };
+
+        if (!sceneConfig.defaultLight && (this.configuration.lights && Object.keys(this.configuration.lights).length)) {
+            // remove old lights
+            this.scene.lights.forEach(l => {
+                l.dispose();
+            });
+
+            Object.keys(this.configuration.lights).forEach((name, idx) => {
+                let lightConfig = this.configuration.lights && this.configuration.lights[name] || { name: name, type: 0 };
+                lightConfig.name = name;
+                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                if (!constructor) return;
+                let light = constructor();
+
+                //enabled
+                if (light.isEnabled() !== !lightConfig.disabled) {
+                    light.setEnabled(!lightConfig.disabled);
+                }
+
+                this.extendClassWithConfig(light, lightConfig);
+
+                //position. Some lights don't support shadows
+                if (light instanceof ShadowLight) {
+                    if (lightConfig.shadowEnabled) {
+                        var shadowGenerator = new BABYLON.ShadowGenerator(512, light);
+                        this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
+                        // add the focues meshes to the shadow list
+                        let shadownMap = shadowGenerator.getShadowMap();
+                        if (!shadownMap) return;
+                        let renderList = shadownMap.renderList;
+                        for (var index = 0; index < focusMeshes.length; index++) {
+                            renderList && renderList.push(focusMeshes[index]);
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
+
+        let sceneConfig = this.configuration.scene || { autoRotate: false, defaultCamera: true };
+
+        if (sceneConfig.defaultCamera) {
+            return;
+        }
+
+        let cameraConfig = this.configuration.camera || {};
+
+        if (cameraConfig.position) {
+            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
+        }
+
+        if (cameraConfig.rotation) {
+            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
+        }
+
+        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
+        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
+
+        if (cameraConfig.behaviors) {
+            for (let name in cameraConfig.behaviors) {
+                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
+            }
+        };
+
+        if (sceneConfig.autoRotate) {
+            this.camera.useAutoRotationBehavior = true;
+        }
+    }
+
+    private setCameraBehavior(behaviorConfig: number | {
+        type: number;
+        [propName: string]: any;
+    }, payload: any) {
+
+        let behavior: Behavior<ArcRotateCamera> | null;
+        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
+
+        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
+
+        // constructing behavior
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                behavior = new AutoRotationBehavior();
+                break;
+            case CameraBehavior.BOUNCING:
+                behavior = new BouncingBehavior();
+                break;
+            case CameraBehavior.FRAMING:
+                behavior = new FramingBehavior();
+                break;
+            default:
+                behavior = null;
+                break;
+        }
+
+        if (behavior) {
+            if (typeof behaviorConfig === "object") {
+                this.extendClassWithConfig(behavior, behaviorConfig);
+            }
+            this.camera.addBehavior(behavior);
+        }
+
+        // post attach configuration. Some functionalities require the attached camera.
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                break;
+            case CameraBehavior.BOUNCING:
+                break;
+            case CameraBehavior.FRAMING:
+                if (config.zoomOnBoundingInfo) {
+                    //payload is an array of meshes
+                    let meshes = <Array<AbstractMesh>>payload;
+                    let bounding = meshes[0].getHierarchyBoundingVectors();
+                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
+                }
+                break;
+        }
+    }
+
+    private extendClassWithConfig(object: any, config: any) {
+        if (!config) return;
+        Object.keys(config).forEach(key => {
+            if (key in object && typeof object[key] !== 'function') {
+                if (typeof object[key] === 'function') return;
+                // if it is an object, iterate internally until reaching basic types
+                if (typeof object[key] === 'object') {
+                    this.extendClassWithConfig(object[key], config[key]);
+                } else {
+                    object[key] = config[key];
+                }
+            }
+        });
+    }
+}

+ 144 - 0
Viewer/src/viewer/viewer.ts

@@ -0,0 +1,144 @@
+import { viewerManager } from './viewerManager';
+import { TemplateManager } from './../templateManager';
+import configurationLoader from './../configuration/loader';
+import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight } from 'babylonjs';
+import { ViewerConfiguration } from '../configuration/configuration';
+
+export abstract class AbstractViewer {
+
+    public templateManager: TemplateManager;
+
+    public engine: Engine;
+    public scene: Scene;
+    public baseId: string;
+
+    protected configuration: ViewerConfiguration;
+
+    constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
+        // if exists, use the container id. otherwise, generate a random string.
+        if (containerElement.id) {
+            this.baseId = containerElement.id;
+        } else {
+            this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
+        }
+
+        // add this viewer to the viewer manager
+        viewerManager.addViewer(this);
+
+        // create a new template manager. TODO - singleton?
+        this.templateManager = new TemplateManager(containerElement);
+
+        this.prepareContainerElement();
+
+        // extend the configuration
+        configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
+            this.configuration = configuration;
+            // initialize the templates
+            let templateConfiguration = this.configuration.templates || {};
+            this.templateManager.initTemplate(templateConfiguration);
+            // when done, execute onTemplatesLoaded()
+            this.templateManager.onAllLoaded.add(() => {
+                this.onTemplatesLoaded();
+            });
+        });
+
+    }
+
+    public getBaseId(): string {
+        return this.baseId;
+    }
+
+    protected abstract prepareContainerElement();
+
+    /**
+     * This function will execute when the HTML templates finished initializing.
+     * It should initialize the engine and continue execution.
+     * 
+     * @protected
+     * @returns {Promise<AbstractViewer>} The viewer object will be returned after the object was loaded.
+     * @memberof AbstractViewer
+     */
+    protected onTemplatesLoaded(): Promise<AbstractViewer> {
+        return this.initEngine().then(() => {
+            return this.loadModel();
+        }).then(() => {
+            return this;
+        });
+    }
+
+    /**
+     * Initialize the engine. Retruns a promise in case async calls are needed.
+     * 
+     * @protected
+     * @returns {Promise<Engine>} 
+     * @memberof Viewer
+     */
+    protected initEngine(): Promise<Engine> {
+        let canvasElement = this.templateManager.getCanvas();
+        if (!canvasElement) {
+            return Promise.reject('Canvas element not found!');
+        }
+        let config = this.configuration.engine || {};
+        // TDO enable further configuration
+        this.engine = new Engine(canvasElement, !!config.antialiasing);
+
+        window.addEventListener('resize', () => {
+            this.engine.resize();
+        });
+
+        this.engine.runRenderLoop(() => {
+            this.scene && this.scene.render();
+        });
+
+        var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
+        this.engine.setHardwareScalingLevel(scale);
+
+        return Promise.resolve(this.engine);
+    }
+
+    protected initScene(): Promise<Scene> {
+
+        // if the scen exists, dispose it.
+        if (this.scene) {
+            this.scene.dispose();
+        }
+
+        // create a new scene
+        this.scene = new Scene(this.engine);
+        // make sure there is a default camera and light.
+        this.scene.createDefaultCameraOrLight(true, true, true);
+        return Promise.resolve(this.scene);
+    }
+
+    public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
+        let modelUrl = (typeof model === 'string') ? model : model.url;
+        let parts = modelUrl.split('/');
+        let filename = parts.pop();
+        let base = parts.join('/') + '/';
+        let plugin = (typeof model === 'string') ? undefined : model.loader;
+
+        return Promise.resolve().then(() => {
+            if (!this.scene || clearScene) return this.initScene();
+            else return this.scene;
+        }).then(() => {
+            return new Promise<Array<AbstractMesh>>((resolve, reject) => {
+                SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                    resolve(meshes);
+                }, undefined, (e, m, exception) => {
+                    console.log(m, exception);
+                    reject(m);
+                }, plugin);
+            });
+        }).then((meshes: Array<AbstractMesh>) => {
+            return this.onModelLoaded(meshes);
+        });
+    }
+
+    protected onModelLoaded(meshes: Array<AbstractMesh>): Promise<Scene> {
+        console.log("model loaded");
+        return Promise.resolve(this.scene);
+    }
+
+    public abstract initEnvironment(): Promise<Scene>;
+
+}

+ 28 - 0
Viewer/src/viewer/viewerManager.ts

@@ -0,0 +1,28 @@
+import { AbstractViewer } from './viewer';
+
+class ViewerManager {
+
+    private viewers: { [key: string]: AbstractViewer };
+
+    constructor() {
+        this.viewers = {};
+    }
+
+    public addViewer(viewer: AbstractViewer) {
+        this.viewers[viewer.getBaseId()] = viewer;
+    }
+
+    public getViewerById(id: string): AbstractViewer {
+        return this.viewers[id];
+    }
+
+    public getViewerByHTMLElement(element: HTMLElement) {
+        for (let id in this.viewers) {
+            if (this.viewers[id].containerElement === element) {
+                return this.getViewerById(id);
+            }
+        }
+    }
+}
+
+export let viewerManager = new ViewerManager();

+ 27 - 0
Viewer/tsconfig.json

@@ -0,0 +1,27 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "commonjs",
+        "noResolve": true,
+        "noImplicitAny": false, //mainly due to usage of external libs without typings.
+        "strictNullChecks": true,
+        "removeComments": true,
+        "preserveConstEnums": true,
+        "sourceMap": true,
+        "experimentalDecorators": true,
+        "isolatedModules": false,
+        "lib": [
+            "dom",
+            "es2015.promise",
+            "es5"
+        ],
+        //"declaration": true,
+        "outDir": "./temp/",
+        "types": [
+            "node",
+            "babylonjs",
+            "babylonjs-loaders",
+            "babylonjs-materials"
+        ]
+    }
+}

+ 63 - 0
Viewer/webpack.config.js

@@ -0,0 +1,63 @@
+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+const path = require('path');
+const webpack = require('webpack');
+
+module.exports = {
+    entry: {
+        'viewer': './src/index.ts',
+        //'viewer.min': './src/index.ts',
+    },
+    output: {
+        path: path.resolve(__dirname, 'dist'),
+        filename: '[name].js',
+        libraryTarget: 'umd',
+        library: 'BabylonViewer',
+        umdNamedDefine: true,
+        devtoolModuleFilenameTemplate: '[absolute-resource-path]'
+    },
+    resolve: {
+        extensions: ['.ts', '.tsx', '.js']
+    },
+    devtool: 'source-map',
+    plugins: [
+        new webpack.WatchIgnorePlugin([
+            /\.d\.ts$/
+        ]),
+        /*new UglifyJSPlugin({
+
+            uglifyOptions: {
+                compress: {
+                    warnings: false,
+                },
+                output: {
+                    comments: false
+                }
+            },
+            sourceMap: true,
+            include: /\.min/,
+        })*/
+    ],
+    module: {
+        loaders: [{
+            test: /\.tsx?$/,
+            loader: 'ts-loader',
+            exclude: /node_modules/
+        },
+        {
+            test: /\.(html)$/,
+            use: {
+                loader: 'html-loader'
+            }
+        },
+        {
+            test: /\.(jpe?g|png|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
+            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        }]
+    },
+    devServer: {
+        contentBase: path.join(__dirname, "dist"),
+        compress: true,
+        //open: true,
+        port: 9000
+    }
+}

文件差異過大導致無法顯示
+ 2587 - 2145
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 49 - 48
dist/preview release/babylon.js


文件差異過大導致無法顯示
+ 3284 - 1199
dist/preview release/babylon.max.js


文件差異過大導致無法顯示
+ 2587 - 2145
dist/preview release/babylon.module.d.ts


文件差異過大導致無法顯示
+ 50 - 49
dist/preview release/babylon.worker.js


文件差異過大導致無法顯示
+ 3383 - 2940
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


文件差異過大導致無法顯示
+ 53 - 50
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


文件差異過大導致無法顯示
+ 4926 - 1834
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


文件差異過大導致無法顯示
+ 3383 - 2940
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 53 - 51
dist/preview release/gui/babylon.gui.d.ts

@@ -16,11 +16,11 @@ declare module BABYLON.GUI {
         private _background;
         _rootContainer: Container;
         _lastPickedControl: Control;
-        _lastControlOver: Control;
-        _lastControlDown: Control;
-        _capturingControl: Control;
+        _lastControlOver: Nullable<Control>;
+        _lastControlDown: Nullable<Control>;
+        _capturingControl: Nullable<Control>;
         _shouldBlockPointer: boolean;
-        _layerToDispose: Layer;
+        _layerToDispose: Nullable<Layer>;
         _linkedControls: Control[];
         private _isFullscreen;
         private _fullscreenViewport;
@@ -33,10 +33,10 @@ declare module BABYLON.GUI {
         idealWidth: number;
         idealHeight: number;
         renderAtIdealSize: boolean;
-        readonly layer: Layer;
+        readonly layer: Nullable<Layer>;
         readonly rootContainer: Container;
-        focusedControl: IFocusableControl;
-        constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
+        focusedControl: Nullable<IFocusableControl>;
+        constructor(name: string, width: number | undefined, height: number | undefined, scene: Nullable<Scene>, generateMipMaps?: boolean, samplingMode?: number);
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         markAsDirty(): void;
         addControl(control: Control): AdvancedDynamicTexture;
@@ -53,7 +53,7 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
-        static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
+        static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>): AdvancedDynamicTexture;
     }
 }
 
@@ -96,7 +96,7 @@ declare module BABYLON.GUI {
         private static _TempCompose0;
         private static _TempCompose1;
         private static _TempCompose2;
-        static ComposeToRef(tx: number, ty: number, angle: number, scaleX: number, scaleY: number, parentMatrix: Matrix2D, result: Matrix2D): void;
+        static ComposeToRef(tx: number, ty: number, angle: number, scaleX: number, scaleY: number, parentMatrix: Nullable<Matrix2D>, result: Matrix2D): void;
     }
 }
 
@@ -126,13 +126,13 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Control {
-        name: string;
+        name: string | undefined;
         private _alpha;
         private _alphaSet;
         private _zIndex;
-        _root: Container;
+        _root: Nullable<Container>;
         _host: AdvancedDynamicTexture;
-        parent: Container;
+        parent: Nullable<Container>;
         _currentMeasure: Measure;
         private _fontFamily;
         private _fontStyle;
@@ -168,7 +168,7 @@ declare module BABYLON.GUI {
         private _cachedOffsetX;
         private _cachedOffsetY;
         private _isVisible;
-        _linkedMesh: AbstractMesh;
+        _linkedMesh: Nullable<AbstractMesh>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -254,18 +254,18 @@ declare module BABYLON.GUI {
         readonly linkOffsetYInPixels: number;
         readonly centerX: number;
         readonly centerY: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         moveToVector3(position: Vector3, scene: Scene): void;
-        linkWithMesh(mesh: AbstractMesh): void;
+        linkWithMesh(mesh: Nullable<AbstractMesh>): void;
         _moveToProjectedPosition(projectedPosition: Vector3): void;
         _markMatrixAsDirty(): void;
         _markAsDirty(): void;
         _markAllAsDirty(): void;
-        _link(root: Container, host: AdvancedDynamicTexture): void;
+        _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         protected _transform(context: CanvasRenderingContext2D): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
@@ -315,16 +315,16 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Container extends Control {
-        name: string;
+        name: string | undefined;
         protected _children: Control[];
         protected _measureForChildren: Measure;
         protected _background: string;
         background: string;
         readonly children: Control[];
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        getChildByName(name: string): Control;
-        getChildByType(name: string, type: string): Control;
+        getChildByName(name: string): Nullable<Control>;
+        getChildByType(name: string, type: string): Nullable<Control>;
         containsControl(control: Control): boolean;
         addControl(control: Control): Container;
         removeControl(control: Control): Container;
@@ -332,7 +332,7 @@ declare module BABYLON.GUI {
         _markMatrixAsDirty(): void;
         _markAllAsDirty(): void;
         protected _localDraw(context: CanvasRenderingContext2D): void;
-        _link(root: Container, host: AdvancedDynamicTexture): void;
+        _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
@@ -344,7 +344,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class StackPanel extends Container {
-        name: string;
+        name: string | undefined;
         private _isVertical;
         private _manualWidth;
         private _manualHeight;
@@ -353,7 +353,7 @@ declare module BABYLON.GUI {
         isVertical: boolean;
         width: string | number;
         height: string | number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
     }
@@ -362,12 +362,12 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Rectangle extends Container {
-        name: string;
+        name: string | undefined;
         private _thickness;
         private _cornerRadius;
         thickness: number;
         cornerRadius: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -379,10 +379,10 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Ellipse extends Container {
-        name: string;
+        name: string | undefined;
         private _thickness;
         thickness: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -393,7 +393,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Line extends Control {
-        name: string;
+        name: string | undefined;
         private _lineWidth;
         private _x1;
         private _y1;
@@ -413,7 +413,7 @@ declare module BABYLON.GUI {
         verticalAlignment: number;
         private readonly _effectiveX2;
         private readonly _effectiveY2;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
@@ -425,7 +425,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Slider extends Control {
-        name: string;
+        name: string | undefined;
         private _thumbWidth;
         private _minimum;
         private _maximum;
@@ -433,6 +433,7 @@ declare module BABYLON.GUI {
         private _background;
         private _borderColor;
         private _barOffset;
+        private _isThumbCircle;
         onValueChangedObservable: Observable<number>;
         borderColor: string;
         background: string;
@@ -443,7 +444,8 @@ declare module BABYLON.GUI {
         minimum: number;
         maximum: number;
         value: number;
-        constructor(name?: string);
+        isThumbCircle: boolean;
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
@@ -457,7 +459,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Checkbox extends Control {
-        name: string;
+        name: string | undefined;
         private _isChecked;
         private _background;
         private _checkSizeRatio;
@@ -467,7 +469,7 @@ declare module BABYLON.GUI {
         checkSizeRatio: number;
         background: string;
         isChecked: boolean;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
@@ -477,7 +479,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class RadioButton extends Control {
-        name: string;
+        name: string | undefined;
         private _isChecked;
         private _background;
         private _checkSizeRatio;
@@ -488,7 +490,7 @@ declare module BABYLON.GUI {
         checkSizeRatio: number;
         background: string;
         isChecked: boolean;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
@@ -498,7 +500,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
-        name: string;
+        name: string | undefined;
         private _text;
         private _textWrapping;
         private _textHorizontalAlignment;
@@ -515,23 +517,23 @@ declare module BABYLON.GUI {
         text: string;
         textHorizontalAlignment: number;
         textVerticalAlignment: number;
-        constructor(name?: string, text?: string);
+        constructor(name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _parseLine(line: string, context: CanvasRenderingContext2D): object;
-        protected _parseLineWithTextWrapping(line: string, context: CanvasRenderingContext2D): object;
+        protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
+        protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _renderLines(context: CanvasRenderingContext2D): void;
         dispose(): void;
     }
 }
 
 
-declare var DOMImage: new (width?: number, height?: number) => HTMLImageElement;
+declare var DOMImage: new (width?: number | undefined, height?: number | undefined) => HTMLImageElement;
 declare module BABYLON.GUI {
     class Image extends Control {
-        name: string;
+        name: string | undefined;
         private _domImage;
         private _imageWidth;
         private _imageHeight;
@@ -551,8 +553,8 @@ declare module BABYLON.GUI {
         stretch: number;
         domImage: HTMLImageElement;
         private _onImageLoaded();
-        source: string;
-        constructor(name?: string, url?: string);
+        source: Nullable<string>;
+        constructor(name?: string | undefined, url?: Nullable<string>);
         protected _getTypeName(): string;
         synchronizeSizeWithContent(): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -570,12 +572,12 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Button extends Rectangle {
-        name: string;
+        name: string | undefined;
         pointerEnterAnimation: () => void;
         pointerOutAnimation: () => void;
         pointerDownAnimation: () => void;
         pointerUpAnimation: () => void;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
         _onPointerEnter(target: Control): boolean;
@@ -592,7 +594,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class ColorPicker extends Control {
-        name: string;
+        name: string | undefined;
         private _colorWheelCanvas;
         private _value;
         private _tmpColor;
@@ -609,7 +611,7 @@ declare module BABYLON.GUI {
         width: string | number;
         height: string | number;
         size: string | number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         private _updateSquareProps();
         private _drawGradientSquare(hueValue, left, top, width, height, context);
@@ -631,7 +633,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class InputText extends Control implements IFocusableControl {
-        name: string;
+        name: string | undefined;
         private _text;
         private _placeholderText;
         private _background;
@@ -663,7 +665,7 @@ declare module BABYLON.GUI {
         placeholderColor: string;
         placeholderText: string;
         text: string;
-        constructor(name?: string, text?: string);
+        constructor(name?: string | undefined, text?: string);
         onBlur(): void;
         onFocus(): void;
         protected _getTypeName(): string;
@@ -699,13 +701,13 @@ declare module BABYLON.GUI {
         defaultButtonColor: string;
         defaultButtonBackground: string;
         protected _getTypeName(): string;
-        private _createKey(key, propertySet?);
+        private _createKey(key, propertySet);
         addKeysRow(keys: Array<string>, propertySets?: Array<KeyPropertySet>): void;
         private _connectedInputText;
         private _onFocusObserver;
         private _onBlurObserver;
         private _onKeyPressObserver;
-        readonly connectedInputText: InputText;
+        readonly connectedInputText: Nullable<InputText>;
         connect(input: InputText): void;
         disconnect(): void;
         static CreateDefaultLayout(): VirtualKeyboard;

+ 110 - 46
dist/preview release/gui/babylon.gui.js

@@ -22,7 +22,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var AdvancedDynamicTexture = (function (_super) {
+        var AdvancedDynamicTexture = /** @class */ (function (_super) {
             __extends(AdvancedDynamicTexture, _super);
             function AdvancedDynamicTexture(name, width, height, scene, generateMipMaps, samplingMode) {
                 if (width === void 0) { width = 0; }
@@ -39,8 +39,12 @@ var BABYLON;
                 _this._idealHeight = 0;
                 _this._renderAtIdealSize = false;
                 _this._blockNextFocusCheck = false;
-                _this._renderObserver = _this.getScene().onBeforeCameraRenderObservable.add(function (camera) { return _this._checkUpdate(camera); });
-                _this._preKeyboardObserver = _this.getScene().onPreKeyboardObservable.add(function (info) {
+                scene = _this.getScene();
+                if (!scene || !_this._texture) {
+                    return _this;
+                }
+                _this._renderObserver = scene.onBeforeCameraRenderObservable.add(function (camera) { return _this._checkUpdate(camera); });
+                _this._preKeyboardObserver = scene.onPreKeyboardObservable.add(function (info) {
                     if (!_this._focusedControl) {
                         return;
                     }
@@ -52,7 +56,7 @@ var BABYLON;
                 _this._rootContainer._link(null, _this);
                 _this.hasAlpha = true;
                 if (!width || !height) {
-                    _this._resizeObserver = _this.getScene().getEngine().onResizeObservable.add(function () { return _this._onResize(); });
+                    _this._resizeObserver = scene.getEngine().onResizeObservable.add(function () { return _this._onResize(); });
                     _this._onResize();
                 }
                 _this._texture.isReady = true;
@@ -174,18 +178,22 @@ var BABYLON;
                 return this;
             };
             AdvancedDynamicTexture.prototype.dispose = function () {
-                this.getScene().onBeforeCameraRenderObservable.remove(this._renderObserver);
+                var scene = this.getScene();
+                if (!scene) {
+                    return;
+                }
+                scene.onBeforeCameraRenderObservable.remove(this._renderObserver);
                 if (this._resizeObserver) {
-                    this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
+                    scene.getEngine().onResizeObservable.remove(this._resizeObserver);
                 }
                 if (this._pointerMoveObserver) {
-                    this.getScene().onPrePointerObservable.remove(this._pointerMoveObserver);
+                    scene.onPrePointerObservable.remove(this._pointerMoveObserver);
                 }
                 if (this._pointerObserver) {
-                    this.getScene().onPointerObservable.remove(this._pointerObserver);
+                    scene.onPointerObservable.remove(this._pointerObserver);
                 }
                 if (this._canvasPointerOutObserver) {
-                    this.getScene().getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
+                    scene.getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
                 }
                 if (this._layerToDispose) {
                     this._layerToDispose.texture = null;
@@ -196,8 +204,12 @@ var BABYLON;
                 _super.prototype.dispose.call(this);
             };
             AdvancedDynamicTexture.prototype._onResize = function () {
+                var scene = this.getScene();
+                if (!scene) {
+                    return;
+                }
                 // Check size
-                var engine = this.getScene().getEngine();
+                var engine = scene.getEngine();
                 var textureSize = this.getSize();
                 var renderWidth = engine.getRenderWidth();
                 var renderHeight = engine.getRenderHeight();
@@ -231,6 +243,9 @@ var BABYLON;
                 }
                 if (this._isFullscreen && this._linkedControls.length) {
                     var scene = this.getScene();
+                    if (!scene) {
+                        return;
+                    }
                     var globalViewport = this._getGlobalViewport(scene);
                     for (var _i = 0, _a = this._linkedControls; _i < _a.length; _i++) {
                         var control = _a[_i];
@@ -282,6 +297,9 @@ var BABYLON;
             };
             AdvancedDynamicTexture.prototype._doPicking = function (x, y, type, buttonIndex) {
                 var scene = this.getScene();
+                if (!scene) {
+                    return;
+                }
                 var engine = scene.getEngine();
                 var textureSize = this.getSize();
                 if (this._isFullscreen) {
@@ -305,13 +323,22 @@ var BABYLON;
             AdvancedDynamicTexture.prototype.attach = function () {
                 var _this = this;
                 var scene = this.getScene();
+                if (!scene) {
+                    return;
+                }
                 this._pointerMoveObserver = scene.onPrePointerObservable.add(function (pi, state) {
                     if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
                         && pi.type !== BABYLON.PointerEventTypes.POINTERUP
                         && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                         return;
                     }
+                    if (!scene) {
+                        return;
+                    }
                     var camera = scene.cameraToUseForPointers || scene.activeCamera;
+                    if (!camera) {
+                        return;
+                    }
                     var engine = scene.getEngine();
                     var viewport = camera.viewport;
                     var x = (scene.pointerX / engine.getHardwareScalingLevel() - viewport.x * engine.getRenderWidth()) / viewport.width;
@@ -326,16 +353,21 @@ var BABYLON;
                 var _this = this;
                 if (supportPointerMove === void 0) { supportPointerMove = true; }
                 var scene = this.getScene();
+                if (!scene) {
+                    return;
+                }
                 this._pointerObserver = scene.onPointerObservable.add(function (pi, state) {
                     if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
                         && pi.type !== BABYLON.PointerEventTypes.POINTERUP
                         && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                         return;
                     }
-                    if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
+                    if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                         var uv = pi.pickInfo.getTextureCoordinates();
-                        var size = _this.getSize();
-                        _this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pi.event.button);
+                        if (uv) {
+                            var size = _this.getSize();
+                            _this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pi.event.button);
+                        }
                     }
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                         if (_this._lastControlDown) {
@@ -430,7 +462,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Measure = (function () {
+        var Measure = /** @class */ (function () {
             function Measure(left, top, width, height) {
                 this.left = left;
                 this.top = top;
@@ -475,7 +507,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Vector2WithInfo = (function (_super) {
+        var Vector2WithInfo = /** @class */ (function (_super) {
             __extends(Vector2WithInfo, _super);
             function Vector2WithInfo(source, buttonIndex) {
                 if (buttonIndex === void 0) { buttonIndex = 0; }
@@ -486,7 +518,7 @@ var BABYLON;
             return Vector2WithInfo;
         }(BABYLON.Vector2));
         GUI.Vector2WithInfo = Vector2WithInfo;
-        var Matrix2D = (function () {
+        var Matrix2D = /** @class */ (function () {
             function Matrix2D(m00, m01, m10, m11, m20, m21) {
                 this.m = new Float32Array(6);
                 this.fromValues(m00, m01, m10, m11, m20, m21);
@@ -607,7 +639,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var ValueAndUnit = (function () {
+        var ValueAndUnit = /** @class */ (function () {
             function ValueAndUnit(value, unit, negativeValueAllowed) {
                 if (unit === void 0) { unit = ValueAndUnit.UNITMODE_PIXEL; }
                 if (negativeValueAllowed === void 0) { negativeValueAllowed = true; }
@@ -725,7 +757,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Control = (function () {
+        var Control = /** @class */ (function () {
             // Functions
             function Control(name) {
                 this.name = name;
@@ -1771,7 +1803,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Container = (function (_super) {
+        var Container = /** @class */ (function (_super) {
             __extends(Container, _super);
             function Container(name) {
                 var _this = _super.call(this, name) || this;
@@ -1950,7 +1982,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var StackPanel = (function (_super) {
+        var StackPanel = /** @class */ (function (_super) {
             __extends(StackPanel, _super);
             function StackPanel(name) {
                 var _this = _super.call(this, name) || this;
@@ -2092,7 +2124,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Rectangle = (function (_super) {
+        var Rectangle = /** @class */ (function (_super) {
             __extends(Rectangle, _super);
             function Rectangle(name) {
                 var _this = _super.call(this, name) || this;
@@ -2208,7 +2240,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Ellipse = (function (_super) {
+        var Ellipse = /** @class */ (function (_super) {
             __extends(Ellipse, _super);
             function Ellipse(name) {
                 var _this = _super.call(this, name) || this;
@@ -2274,7 +2306,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Line = (function (_super) {
+        var Line = /** @class */ (function (_super) {
             __extends(Line, _super);
             function Line(name) {
                 var _this = _super.call(this, name) || this;
@@ -2474,7 +2506,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Slider = (function (_super) {
+        var Slider = /** @class */ (function (_super) {
             __extends(Slider, _super);
             function Slider(name) {
                 var _this = _super.call(this, name) || this;
@@ -2486,6 +2518,7 @@ var BABYLON;
                 _this._background = "black";
                 _this._borderColor = "white";
                 _this._barOffset = new GUI.ValueAndUnit(5, GUI.ValueAndUnit.UNITMODE_PIXEL, false);
+                _this._isThumbCircle = false;
                 _this.onValueChangedObservable = new BABYLON.Observable();
                 // Events
                 _this._pointerIsDown = false;
@@ -2610,6 +2643,20 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(Slider.prototype, "isThumbCircle", {
+                get: function () {
+                    return this._isThumbCircle;
+                },
+                set: function (value) {
+                    if (this._isThumbCircle === value) {
+                        return;
+                    }
+                    this._isThumbCircle = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Slider.prototype._getTypeName = function () {
                 return "Slider";
             };
@@ -2641,9 +2688,18 @@ var BABYLON;
                     context.fillStyle = this.color;
                     context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, thumbPosition, this._currentMeasure.height - effectiveBarOffset * 2);
                     // Thumb
-                    context.fillRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
-                    context.strokeStyle = this._borderColor;
-                    context.strokeRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
+                    if (this._isThumbCircle) {
+                        context.beginPath();
+                        context.arc(left + thumbPosition, this._currentMeasure.top + this._currentMeasure.height / 2, effectiveThumbWidth / 2, 0, 2 * Math.PI);
+                        context.fill();
+                        context.strokeStyle = this._borderColor;
+                        context.stroke();
+                    }
+                    else {
+                        context.fillRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
+                        context.strokeStyle = this._borderColor;
+                        context.strokeRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
+                    }
                 }
                 context.restore();
             };
@@ -2684,7 +2740,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Checkbox = (function (_super) {
+        var Checkbox = /** @class */ (function (_super) {
             __extends(Checkbox, _super);
             function Checkbox(name) {
                 var _this = _super.call(this, name) || this;
@@ -2800,7 +2856,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var RadioButton = (function (_super) {
+        var RadioButton = /** @class */ (function (_super) {
             __extends(RadioButton, _super);
             function RadioButton(name) {
                 var _this = _super.call(this, name) || this;
@@ -2937,7 +2993,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var TextBlock = (function (_super) {
+        var TextBlock = /** @class */ (function (_super) {
             __extends(TextBlock, _super);
             function TextBlock(name, text) {
                 if (text === void 0) { text = ""; }
@@ -3146,9 +3202,10 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Image = (function (_super) {
+        var Image = /** @class */ (function (_super) {
             __extends(Image, _super);
             function Image(name, url) {
+                if (url === void 0) { url = null; }
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
                 _this._loaded = false;
@@ -3288,8 +3345,10 @@ var BABYLON;
                     this._domImage.onload = function () {
                         _this._onImageLoaded();
                     };
-                    this._domImage.crossOrigin = "anonymous";
-                    this._domImage.src = value;
+                    if (value) {
+                        this._domImage.crossOrigin = "anonymous";
+                        this._domImage.src = value;
+                    }
                 },
                 enumerable: true,
                 configurable: true
@@ -3333,8 +3392,10 @@ var BABYLON;
                                 if (this._autoScale) {
                                     this.synchronizeSizeWithContent();
                                 }
-                                this._root.width = this.width;
-                                this._root.height = this.height;
+                                if (this._root) {
+                                    this._root.width = this.width;
+                                    this._root.height = this.height;
+                                }
                                 break;
                         }
                     }
@@ -3388,7 +3449,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var Button = (function (_super) {
+        var Button = /** @class */ (function (_super) {
             __extends(Button, _super);
             function Button(name) {
                 var _this = _super.call(this, name) || this;
@@ -3517,7 +3578,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var ColorPicker = (function (_super) {
+        var ColorPicker = /** @class */ (function (_super) {
             __extends(ColorPicker, _super);
             function ColorPicker(name) {
                 var _this = _super.call(this, name) || this;
@@ -3863,7 +3924,7 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var InputText = (function (_super) {
+        var InputText = /** @class */ (function (_super) {
             __extends(InputText, _super);
             function InputText(name, text) {
                 if (text === void 0) { text = ""; }
@@ -4112,12 +4173,12 @@ var BABYLON;
                         return;
                 }
                 // Printable characters
-                if ((keyCode === -1) ||
-                    (keyCode === 32) ||
-                    (keyCode > 47 && keyCode < 58) ||
-                    (keyCode > 64 && keyCode < 91) ||
-                    (keyCode > 185 && keyCode < 193) ||
-                    (keyCode > 218 && keyCode < 223) ||
+                if ((keyCode === -1) || // Direct access
+                    (keyCode === 32) || // Space
+                    (keyCode > 47 && keyCode < 58) || // Numbers
+                    (keyCode > 64 && keyCode < 91) || // Letters
+                    (keyCode > 185 && keyCode < 193) || // Special characters
+                    (keyCode > 218 && keyCode < 223) || // Special characters
                     (keyCode > 95 && keyCode < 112)) {
                     if (this._cursorOffset === 0) {
                         this.text += key;
@@ -4276,13 +4337,13 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
-        var KeyPropertySet = (function () {
+        var KeyPropertySet = /** @class */ (function () {
             function KeyPropertySet() {
             }
             return KeyPropertySet;
         }());
         GUI.KeyPropertySet = KeyPropertySet;
-        var VirtualKeyboard = (function (_super) {
+        var VirtualKeyboard = /** @class */ (function (_super) {
             __extends(VirtualKeyboard, _super);
             function VirtualKeyboard() {
                 var _this = _super !== null && _super.apply(this, arguments) || this;
@@ -4350,6 +4411,9 @@ var BABYLON;
                     _this.isVisible = false;
                 });
                 this._onKeyPressObserver = this.onKeyPressObservable.add(function (key) {
+                    if (!_this._connectedInputText) {
+                        return;
+                    }
                     switch (key) {
                         case "\u2190":
                             _this._connectedInputText.processKey(8);

文件差異過大導致無法顯示
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


+ 53 - 51
dist/preview release/gui/babylon.gui.module.d.ts

@@ -21,11 +21,11 @@ declare module BABYLON.GUI {
         private _background;
         _rootContainer: Container;
         _lastPickedControl: Control;
-        _lastControlOver: Control;
-        _lastControlDown: Control;
-        _capturingControl: Control;
+        _lastControlOver: Nullable<Control>;
+        _lastControlDown: Nullable<Control>;
+        _capturingControl: Nullable<Control>;
         _shouldBlockPointer: boolean;
-        _layerToDispose: Layer;
+        _layerToDispose: Nullable<Layer>;
         _linkedControls: Control[];
         private _isFullscreen;
         private _fullscreenViewport;
@@ -38,10 +38,10 @@ declare module BABYLON.GUI {
         idealWidth: number;
         idealHeight: number;
         renderAtIdealSize: boolean;
-        readonly layer: Layer;
+        readonly layer: Nullable<Layer>;
         readonly rootContainer: Container;
-        focusedControl: IFocusableControl;
-        constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
+        focusedControl: Nullable<IFocusableControl>;
+        constructor(name: string, width: number | undefined, height: number | undefined, scene: Nullable<Scene>, generateMipMaps?: boolean, samplingMode?: number);
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         markAsDirty(): void;
         addControl(control: Control): AdvancedDynamicTexture;
@@ -58,7 +58,7 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
-        static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
+        static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>): AdvancedDynamicTexture;
     }
 }
 
@@ -101,7 +101,7 @@ declare module BABYLON.GUI {
         private static _TempCompose0;
         private static _TempCompose1;
         private static _TempCompose2;
-        static ComposeToRef(tx: number, ty: number, angle: number, scaleX: number, scaleY: number, parentMatrix: Matrix2D, result: Matrix2D): void;
+        static ComposeToRef(tx: number, ty: number, angle: number, scaleX: number, scaleY: number, parentMatrix: Nullable<Matrix2D>, result: Matrix2D): void;
     }
 }
 
@@ -131,13 +131,13 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Control {
-        name: string;
+        name: string | undefined;
         private _alpha;
         private _alphaSet;
         private _zIndex;
-        _root: Container;
+        _root: Nullable<Container>;
         _host: AdvancedDynamicTexture;
-        parent: Container;
+        parent: Nullable<Container>;
         _currentMeasure: Measure;
         private _fontFamily;
         private _fontStyle;
@@ -173,7 +173,7 @@ declare module BABYLON.GUI {
         private _cachedOffsetX;
         private _cachedOffsetY;
         private _isVisible;
-        _linkedMesh: AbstractMesh;
+        _linkedMesh: Nullable<AbstractMesh>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -259,18 +259,18 @@ declare module BABYLON.GUI {
         readonly linkOffsetYInPixels: number;
         readonly centerX: number;
         readonly centerY: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         moveToVector3(position: Vector3, scene: Scene): void;
-        linkWithMesh(mesh: AbstractMesh): void;
+        linkWithMesh(mesh: Nullable<AbstractMesh>): void;
         _moveToProjectedPosition(projectedPosition: Vector3): void;
         _markMatrixAsDirty(): void;
         _markAsDirty(): void;
         _markAllAsDirty(): void;
-        _link(root: Container, host: AdvancedDynamicTexture): void;
+        _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         protected _transform(context: CanvasRenderingContext2D): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
@@ -320,16 +320,16 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Container extends Control {
-        name: string;
+        name: string | undefined;
         protected _children: Control[];
         protected _measureForChildren: Measure;
         protected _background: string;
         background: string;
         readonly children: Control[];
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        getChildByName(name: string): Control;
-        getChildByType(name: string, type: string): Control;
+        getChildByName(name: string): Nullable<Control>;
+        getChildByType(name: string, type: string): Nullable<Control>;
         containsControl(control: Control): boolean;
         addControl(control: Control): Container;
         removeControl(control: Control): Container;
@@ -337,7 +337,7 @@ declare module BABYLON.GUI {
         _markMatrixAsDirty(): void;
         _markAllAsDirty(): void;
         protected _localDraw(context: CanvasRenderingContext2D): void;
-        _link(root: Container, host: AdvancedDynamicTexture): void;
+        _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
@@ -349,7 +349,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class StackPanel extends Container {
-        name: string;
+        name: string | undefined;
         private _isVertical;
         private _manualWidth;
         private _manualHeight;
@@ -358,7 +358,7 @@ declare module BABYLON.GUI {
         isVertical: boolean;
         width: string | number;
         height: string | number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
     }
@@ -367,12 +367,12 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Rectangle extends Container {
-        name: string;
+        name: string | undefined;
         private _thickness;
         private _cornerRadius;
         thickness: number;
         cornerRadius: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -384,10 +384,10 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Ellipse extends Container {
-        name: string;
+        name: string | undefined;
         private _thickness;
         thickness: number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -398,7 +398,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Line extends Control {
-        name: string;
+        name: string | undefined;
         private _lineWidth;
         private _x1;
         private _y1;
@@ -418,7 +418,7 @@ declare module BABYLON.GUI {
         verticalAlignment: number;
         private readonly _effectiveX2;
         private readonly _effectiveY2;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
@@ -430,7 +430,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Slider extends Control {
-        name: string;
+        name: string | undefined;
         private _thumbWidth;
         private _minimum;
         private _maximum;
@@ -438,6 +438,7 @@ declare module BABYLON.GUI {
         private _background;
         private _borderColor;
         private _barOffset;
+        private _isThumbCircle;
         onValueChangedObservable: Observable<number>;
         borderColor: string;
         background: string;
@@ -448,7 +449,8 @@ declare module BABYLON.GUI {
         minimum: number;
         maximum: number;
         value: number;
-        constructor(name?: string);
+        isThumbCircle: boolean;
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
@@ -462,7 +464,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Checkbox extends Control {
-        name: string;
+        name: string | undefined;
         private _isChecked;
         private _background;
         private _checkSizeRatio;
@@ -472,7 +474,7 @@ declare module BABYLON.GUI {
         checkSizeRatio: number;
         background: string;
         isChecked: boolean;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
@@ -482,7 +484,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class RadioButton extends Control {
-        name: string;
+        name: string | undefined;
         private _isChecked;
         private _background;
         private _checkSizeRatio;
@@ -493,7 +495,7 @@ declare module BABYLON.GUI {
         checkSizeRatio: number;
         background: string;
         isChecked: boolean;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
@@ -503,7 +505,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
-        name: string;
+        name: string | undefined;
         private _text;
         private _textWrapping;
         private _textHorizontalAlignment;
@@ -520,23 +522,23 @@ declare module BABYLON.GUI {
         text: string;
         textHorizontalAlignment: number;
         textVerticalAlignment: number;
-        constructor(name?: string, text?: string);
+        constructor(name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _parseLine(line: string, context: CanvasRenderingContext2D): object;
-        protected _parseLineWithTextWrapping(line: string, context: CanvasRenderingContext2D): object;
+        protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
+        protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _renderLines(context: CanvasRenderingContext2D): void;
         dispose(): void;
     }
 }
 
 
-declare var DOMImage: new (width?: number, height?: number) => HTMLImageElement;
+declare var DOMImage: new (width?: number | undefined, height?: number | undefined) => HTMLImageElement;
 declare module BABYLON.GUI {
     class Image extends Control {
-        name: string;
+        name: string | undefined;
         private _domImage;
         private _imageWidth;
         private _imageHeight;
@@ -556,8 +558,8 @@ declare module BABYLON.GUI {
         stretch: number;
         domImage: HTMLImageElement;
         private _onImageLoaded();
-        source: string;
-        constructor(name?: string, url?: string);
+        source: Nullable<string>;
+        constructor(name?: string | undefined, url?: Nullable<string>);
         protected _getTypeName(): string;
         synchronizeSizeWithContent(): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -575,12 +577,12 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class Button extends Rectangle {
-        name: string;
+        name: string | undefined;
         pointerEnterAnimation: () => void;
         pointerOutAnimation: () => void;
         pointerDownAnimation: () => void;
         pointerUpAnimation: () => void;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
         _onPointerEnter(target: Control): boolean;
@@ -597,7 +599,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class ColorPicker extends Control {
-        name: string;
+        name: string | undefined;
         private _colorWheelCanvas;
         private _value;
         private _tmpColor;
@@ -614,7 +616,7 @@ declare module BABYLON.GUI {
         width: string | number;
         height: string | number;
         size: string | number;
-        constructor(name?: string);
+        constructor(name?: string | undefined);
         protected _getTypeName(): string;
         private _updateSquareProps();
         private _drawGradientSquare(hueValue, left, top, width, height, context);
@@ -636,7 +638,7 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class InputText extends Control implements IFocusableControl {
-        name: string;
+        name: string | undefined;
         private _text;
         private _placeholderText;
         private _background;
@@ -668,7 +670,7 @@ declare module BABYLON.GUI {
         placeholderColor: string;
         placeholderText: string;
         text: string;
-        constructor(name?: string, text?: string);
+        constructor(name?: string | undefined, text?: string);
         onBlur(): void;
         onFocus(): void;
         protected _getTypeName(): string;
@@ -704,13 +706,13 @@ declare module BABYLON.GUI {
         defaultButtonColor: string;
         defaultButtonBackground: string;
         protected _getTypeName(): string;
-        private _createKey(key, propertySet?);
+        private _createKey(key, propertySet);
         addKeysRow(keys: Array<string>, propertySets?: Array<KeyPropertySet>): void;
         private _connectedInputText;
         private _onFocusObserver;
         private _onBlurObserver;
         private _onKeyPressObserver;
-        readonly connectedInputText: InputText;
+        readonly connectedInputText: Nullable<InputText>;
         connect(input: InputText): void;
         disconnect(): void;
         static CreateDefaultLayout(): VirtualKeyboard;

+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.1.0-alpha3.6",
+    "version": "3.1.0-alpha3.7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

文件差異過大導致無法顯示
+ 4 - 3
dist/preview release/inspector/babylon.inspector.bundle.js


+ 9 - 7
dist/preview release/inspector/babylon.inspector.d.ts

@@ -22,7 +22,7 @@ declare module INSPECTOR {
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          */
-        constructor(scene: BABYLON.Scene, popup?: boolean, initialTab?: number, parentElement?: HTMLElement, newColors?: {
+        constructor(scene: BABYLON.Scene, popup?: boolean, initialTab?: number, parentElement?: Nullable<HTMLElement>, newColors?: {
             backgroundColor?: string;
             backgroundColorLighter?: string;
             backgroundColorLighter2?: string;
@@ -519,7 +519,7 @@ declare module INSPECTOR {
         private _prevY;
         /**Save value while slider is on */
         private _preValue;
-        constructor(prop: Property, parent?: PropertyLine, level?: number);
+        constructor(prop: Property, parent?: Nullable<PropertyLine>, level?: number);
         /**
          * Init the input element and al its handler :
          * - a click in the window remove the input and restore the old property value
@@ -709,7 +709,7 @@ declare module INSPECTOR {
         private _elem;
         /** The tooltip div */
         private _infoDiv;
-        constructor(elem: HTMLElement, tip: string, attachTo?: HTMLElement);
+        constructor(elem: HTMLElement, tip: string, attachTo?: Nullable<HTMLElement>);
     }
 }
 
@@ -745,12 +745,12 @@ declare module INSPECTOR {
         /**
          * Useful function used to create a div
          */
-        static CreateDiv(className?: string, parent?: HTMLElement): HTMLElement;
+        static CreateDiv(className?: Nullable<string>, parent?: HTMLElement): HTMLElement;
         /**
          * Useful function used to create a input
          */
         static CreateInput(className?: string, parent?: HTMLElement): HTMLInputElement;
-        static CreateElement(element: string, className?: string, parent?: HTMLElement): HTMLElement;
+        static CreateElement(element: string, className?: Nullable<string>, parent?: HTMLElement): HTMLElement;
         /**
          * Removes all children of the given div.
          */
@@ -846,7 +846,7 @@ declare module INSPECTOR {
         /** Set the given item as active in the tree */
         activateNode(item: TreeItem): void;
         /** Returns the treeitem corersponding to the given obj, null if not found */
-        getItemFor(_obj: any): TreeItem;
+        getItemFor(_obj: any): Nullable<TreeItem>;
         filter(filter: string): void;
         /** Builds the tree panel */
         protected abstract _getTree(): Array<TreeItem>;
@@ -984,6 +984,8 @@ declare module INSPECTOR {
         private _engine;
         private _glInfo;
         private _updateLoopHandler;
+        private _sceneInstrumentation;
+        private _engineInstrumentation;
         constructor(tabbar: TabBar, insp: Inspector);
         private _createStatLabel(content, parent);
         /** Update each properties of the stats panel */
@@ -1028,7 +1030,7 @@ declare module INSPECTOR {
          */
         switchMeshTab(mesh?: BABYLON.AbstractMesh): void;
         /** Returns the active tab */
-        getActiveTab(): Tab;
+        getActiveTab(): Nullable<Tab>;
         getActiveTabIndex(): number;
         readonly inspector: Inspector;
         /**

文件差異過大導致無法顯示
+ 222 - 111
dist/preview release/inspector/babylon.inspector.js


文件差異過大導致無法顯示
+ 4 - 3
dist/preview release/inspector/babylon.inspector.min.js


+ 14 - 17
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -7,13 +7,13 @@ declare module BABYLON {
     }
     interface IGLTFLoaderData {
         json: Object;
-        bin: ArrayBufferView;
+        bin: Nullable<ArrayBufferView>;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,27 +27,23 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data, onError);
-        private _getLoader(loaderData, onError);
-        private static _parseBinary(data, onError);
-        private static _parseV1(binaryReader, onError);
-        private static _parseV2(binaryReader, onError);
+        private static _parse(data);
+        private _getLoader(loaderData);
+        private static _parseBinary(data);
+        private static _parseV1(binaryReader);
+        private static _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -434,8 +430,8 @@ declare module BABYLON.GLTF1 {
     class GLTFLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
         static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
-        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): void;
-        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: Nullable<ArrayBufferView>) => void, onError: (message: string) => void): void;
+        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: Nullable<ArrayBufferView>, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
         static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void;
         static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
     }
@@ -447,6 +443,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);

+ 166 - 136
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -11,7 +11,7 @@ var BABYLON;
         // Sets the useRightHandedSystem flag on the scene.
         GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 2] = "FORCE_RIGHT_HANDED";
     })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
-    var GLTFFileLoader = (function () {
+    var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
             // V2 options
             this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
@@ -21,69 +21,63 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
-            var loaderData = GLTFFileLoader._parse(data, onError);
-            if (!loaderData) {
-                return;
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
             }
-            if (this.onParsed) {
-                this.onParsed(loaderData);
+        };
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            try {
+                var loaderData = GLTFFileLoader._parse(data);
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
+                this._loader = this._getLoader(loaderData);
+                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
-                return;
+            catch (e) {
+                onError(e.message);
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
-            var loaderData = GLTFFileLoader._parse(data, onError);
-            if (!loaderData) {
-                return;
-            }
-            if (this.onParsed) {
-                this.onParsed(loaderData);
+            try {
+                var loaderData = GLTFFileLoader._parse(data);
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
+                this._loader = this._getLoader(loaderData);
+                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
-                return;
+            catch (e) {
+                onError(e.message);
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         };
-        GLTFFileLoader._parse = function (data, onError) {
-            try {
-                if (data instanceof ArrayBuffer) {
-                    return GLTFFileLoader._parseBinary(data, onError);
-                }
-                return {
-                    json: JSON.parse(data),
-                    bin: null
-                };
-            }
-            catch (e) {
-                onError(e.message);
-                return null;
+        GLTFFileLoader._parse = function (data) {
+            if (data instanceof ArrayBuffer) {
+                return GLTFFileLoader._parseBinary(data);
             }
+            return {
+                json: JSON.parse(data),
+                bin: null
+            };
         };
-        GLTFFileLoader.prototype._getLoader = function (loaderData, onError) {
+        GLTFFileLoader.prototype._getLoader = function (loaderData) {
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                onError("Invalid version: " + asset.version);
-                return null;
+                throw new Error("Invalid version: " + asset.version);
             }
             if (asset.minVersion !== undefined) {
                 var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
                 if (!minVersion) {
-                    onError("Invalid minimum version: " + asset.minVersion);
-                    return null;
+                    throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    onError("Incompatible minimum version: " + asset.minVersion);
-                    return null;
+                    throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
             var createLoaders = {
@@ -92,48 +86,45 @@ var BABYLON;
             };
             var createLoader = createLoaders[version.major];
             if (!createLoader) {
-                onError("Unsupported version: " + asset.version);
-                return null;
+                throw new Error("Unsupported version: " + asset.version);
             }
             return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data, onError) {
+        GLTFFileLoader._parseBinary = function (data) {
             var Binary = {
                 Magic: 0x46546C67
             };
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                onError("Unexpected magic: " + magic);
-                return null;
+                throw new Error("Unexpected magic: " + magic);
             }
             var version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
-                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
+                case 1: return GLTFFileLoader._parseV1(binaryReader);
+                case 2: return GLTFFileLoader._parseV2(binaryReader);
             }
-            onError("Unsupported version: " + version);
-            return null;
+            throw new Error("Unsupported version: " + version);
         };
-        GLTFFileLoader._parseV1 = function (binaryReader, onError) {
+        GLTFFileLoader._parseV1 = function (binaryReader) {
             var ContentFormat = {
                 JSON: 0
             };
             var length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
-                return null;
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
             }
             var contentLength = binaryReader.readUint32();
             var contentFormat = binaryReader.readUint32();
             var content;
             switch (contentFormat) {
-                case ContentFormat.JSON:
+                case ContentFormat.JSON: {
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
-                default:
-                    onError("Unexpected content format: " + contentFormat);
-                    return null;
+                }
+                default: {
+                    throw new Error("Unexpected content format: " + contentFormat);
+                }
             }
             var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
             var body = binaryReader.readUint8Array(bytesRemaining);
@@ -142,40 +133,40 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader, onError) {
+        GLTFFileLoader._parseV2 = function (binaryReader) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
             };
             var length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
-                return null;
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
             }
             // JSON chunk
             var chunkLength = binaryReader.readUint32();
             var chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                onError("First chunk format is not JSON");
-                return null;
+                throw new Error("First chunk format is not JSON");
             }
             var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
             // Look for BIN chunk
             var bin = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
-                switch (chunkFormat) {
-                    case ChunkFormat.JSON:
-                        onError("Unexpected JSON chunk");
-                        return null;
-                    case ChunkFormat.BIN:
-                        bin = binaryReader.readUint8Array(chunkLength);
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
+                    case ChunkFormat.JSON: {
+                        throw new Error("Unexpected JSON chunk");
+                    }
+                    case ChunkFormat.BIN: {
+                        bin = binaryReader.readUint8Array(chunkLength_1);
                         break;
-                    default:
+                    }
+                    default: {
                         // ignore unrecognized chunkFormat
-                        binaryReader.skipBytes(chunkLength);
+                        binaryReader.skipBytes(chunkLength_1);
                         break;
+                    }
                 }
             }
             return {
@@ -207,7 +198,7 @@ var BABYLON;
         GLTFFileLoader._decodeBufferToText = function (buffer) {
             var result = "";
             var length = buffer.byteLength;
-            for (var i = 0; i < length; ++i) {
+            for (var i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
             return result;
@@ -218,7 +209,7 @@ var BABYLON;
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
-    var BinaryReader = (function () {
+    var BinaryReader = /** @class */ (function () {
         function BinaryReader(arrayBuffer) {
             this._arrayBuffer = arrayBuffer;
             this._dataView = new DataView(arrayBuffer);
@@ -364,7 +355,7 @@ var BABYLON;
             ETokenType[ETokenType["UNKNOWN"] = 2] = "UNKNOWN";
             ETokenType[ETokenType["END_OF_INPUT"] = 3] = "END_OF_INPUT";
         })(ETokenType || (ETokenType = {}));
-        var Tokenizer = (function () {
+        var Tokenizer = /** @class */ (function () {
             function Tokenizer(toParse) {
                 this._pos = 0;
                 this.isLetterOrDigitPattern = /^[a-zA-Z0-9]+$/;
@@ -457,7 +448,7 @@ var BABYLON;
             else if (attributeParameter.semantic === "COLOR") {
                 return "color";
             }
-            else if (attributeParameter.semantic.indexOf("TEXCOORD_") !== -1) {
+            else if (attributeParameter.semantic && attributeParameter.semantic.indexOf("TEXCOORD_") !== -1) {
                 var channel = Number(attributeParameter.semantic.split("_")[1]);
                 return "uv" + (channel === 0 ? "" : channel + 1);
             }
@@ -469,6 +460,9 @@ var BABYLON;
         var loadAnimations = function (gltfRuntime) {
             for (var anim in gltfRuntime.animations) {
                 var animation = gltfRuntime.animations[anim];
+                if (!animation.channels || !animation.samplers) {
+                    continue;
+                }
                 var lastAnimation = null;
                 for (var i = 0; i < animation.channels.length; i++) {
                     // Get parameters and load buffers
@@ -546,7 +540,7 @@ var BABYLON;
                             var scaling = BABYLON.Vector3.Zero();
                             // Warning on decompose
                             var mat = bone.getBaseMatrix();
-                            if (modifyKey) {
+                            if (modifyKey && lastAnimation) {
                                 mat = lastAnimation.getKeys()[j].value;
                             }
                             mat.decompose(scaling, rotationQuaternion, translation);
@@ -567,12 +561,12 @@ var BABYLON;
                                 value: value
                             });
                         }
-                        else {
+                        else if (lastAnimation) {
                             lastAnimation.getKeys()[j].value = value;
                         }
                     }
                     // Finish
-                    if (!modifyKey) {
+                    if (!modifyKey && babylonAnimation) {
                         babylonAnimation.setKeys(keys);
                         targetNode.animations.push(babylonAnimation);
                     }
@@ -623,7 +617,7 @@ var BABYLON;
                     }
                     if (child.jointName === jointName) {
                         var mat = configureBoneTransformation(node);
-                        var bone = new BABYLON.Bone(node.name, newSkeleton, getParentBone(gltfRuntime, skins, node.jointName, newSkeleton), mat);
+                        var bone = new BABYLON.Bone(node.name || "", newSkeleton, getParentBone(gltfRuntime, skins, node.jointName, newSkeleton), mat);
                         bone.id = nde;
                         return bone;
                     }
@@ -693,7 +687,7 @@ var BABYLON;
                 }
                 // Create node to root bone
                 var mat = configureBoneTransformation(node);
-                var bone = new BABYLON.Bone(node.name, newSkeleton, null, mat);
+                var bone = new BABYLON.Bone(node.name || "", newSkeleton, null, mat);
                 bone.id = id;
                 nodesToRoot.push({ bone: bone, node: node, id: id });
             }
@@ -721,7 +715,7 @@ var BABYLON;
         */
         var importSkeleton = function (gltfRuntime, skins, mesh, newSkeleton, id) {
             if (!newSkeleton) {
-                newSkeleton = new BABYLON.Skeleton(skins.name, "", gltfRuntime.scene);
+                newSkeleton = new BABYLON.Skeleton(skins.name || "", "", gltfRuntime.scene);
             }
             if (!skins.babylonSkeleton) {
                 return newSkeleton;
@@ -734,6 +728,9 @@ var BABYLON;
             // Joints
             for (var i = 0; i < skins.jointNames.length; i++) {
                 var jointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
+                if (!jointNode) {
+                    continue;
+                }
                 var node = jointNode.node;
                 if (!node) {
                     BABYLON.Tools.Warn("Joint named " + skins.jointNames[i] + " does not exist");
@@ -750,7 +747,11 @@ var BABYLON;
                 var foundBone = false;
                 var parentBone = null;
                 for (var j = 0; j < i; j++) {
-                    var joint = getJointNode(gltfRuntime, skins.jointNames[j]).node;
+                    var jointNode_1 = getJointNode(gltfRuntime, skins.jointNames[j]);
+                    if (!jointNode_1) {
+                        continue;
+                    }
+                    var joint = jointNode_1.node;
                     if (!joint) {
                         BABYLON.Tools.Warn("Joint named " + skins.jointNames[j] + " does not exist when looking for parent");
                         continue;
@@ -781,7 +782,7 @@ var BABYLON;
                         }
                     }
                 }
-                var bone = new BABYLON.Bone(node.jointName, newSkeleton, parentBone, mat);
+                var bone = new BABYLON.Bone(node.jointName || "", newSkeleton, parentBone, mat);
                 bone.id = id;
             }
             // Polish
@@ -811,7 +812,7 @@ var BABYLON;
         */
         var importMesh = function (gltfRuntime, node, meshes, id, newMesh) {
             if (!newMesh) {
-                newMesh = new BABYLON.Mesh(node.name, gltfRuntime.scene);
+                newMesh = new BABYLON.Mesh(node.name || "", gltfRuntime.scene);
                 newMesh.id = id;
             }
             if (!node.babylonNode) {
@@ -907,7 +908,6 @@ var BABYLON;
                         indexCounts.push(tempVertexData.indices.length);
                     }
                     vertexData.merge(tempVertexData);
-                    tempVertexData = undefined;
                     // Sub material
                     var material = gltfRuntime.scene.getMaterialByID(primitive.material);
                     multiMat.subMaterials.push(material === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
@@ -965,7 +965,7 @@ var BABYLON;
                 mat.decompose(scaling, rotation, position);
                 configureNode(newNode, position, rotation, scaling);
             }
-            else {
+            else if (node.translation && node.rotation && node.scale) {
                 configureNode(newNode, BABYLON.Vector3.FromArray(node.translation), BABYLON.Quaternion.FromArray(node.rotation), BABYLON.Vector3.FromArray(node.scale));
             }
             newNode.computeWorldMatrix(true);
@@ -976,7 +976,7 @@ var BABYLON;
         var importNode = function (gltfRuntime, node, id, parent) {
             var lastNode = null;
             if (gltfRuntime.importOnlyMeshes && (node.skin || node.meshes)) {
-                if (gltfRuntime.importMeshesNames.length > 0 && gltfRuntime.importMeshesNames.indexOf(node.name) === -1) {
+                if (gltfRuntime.importMeshesNames && gltfRuntime.importMeshesNames.length > 0 && gltfRuntime.importMeshesNames.indexOf(node.name || "") === -1) {
                     return null;
                 }
             }
@@ -986,7 +986,7 @@ var BABYLON;
                     var skin = gltfRuntime.skins[node.skin];
                     var newMesh = importMesh(gltfRuntime, node, node.meshes, id, node.babylonNode);
                     newMesh.skeleton = gltfRuntime.scene.getLastSkeletonByID(node.skin);
-                    if (newMesh.skeleton === null) {
+                    if (newMesh.skeleton === null && skin.babylonSkeleton) {
                         newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton, node.skin);
                         if (!skin.babylonSkeleton) {
                             skin.babylonSkeleton = newMesh.skeleton;
@@ -1008,7 +1008,7 @@ var BABYLON;
                     if (light.type === "ambient") {
                         var ambienLight = light[light.type];
                         var hemiLight = new BABYLON.HemisphericLight(node.light, BABYLON.Vector3.Zero(), gltfRuntime.scene);
-                        hemiLight.name = node.name;
+                        hemiLight.name = node.name || "";
                         if (ambienLight.color) {
                             hemiLight.diffuse = BABYLON.Color3.FromArray(ambienLight.color);
                         }
@@ -1017,7 +1017,7 @@ var BABYLON;
                     else if (light.type === "directional") {
                         var directionalLight = light[light.type];
                         var dirLight = new BABYLON.DirectionalLight(node.light, BABYLON.Vector3.Zero(), gltfRuntime.scene);
-                        dirLight.name = node.name;
+                        dirLight.name = node.name || "";
                         if (directionalLight.color) {
                             dirLight.diffuse = BABYLON.Color3.FromArray(directionalLight.color);
                         }
@@ -1026,7 +1026,7 @@ var BABYLON;
                     else if (light.type === "point") {
                         var pointLight = light[light.type];
                         var ptLight = new BABYLON.PointLight(node.light, BABYLON.Vector3.Zero(), gltfRuntime.scene);
-                        ptLight.name = node.name;
+                        ptLight.name = node.name || "";
                         if (pointLight.color) {
                             ptLight.diffuse = BABYLON.Color3.FromArray(pointLight.color);
                         }
@@ -1035,7 +1035,7 @@ var BABYLON;
                     else if (light.type === "spot") {
                         var spotLight = light[light.type];
                         var spLight = new BABYLON.SpotLight(node.light, BABYLON.Vector3.Zero(), BABYLON.Vector3.Zero(), 0, 0, gltfRuntime.scene);
-                        spLight.name = node.name;
+                        spLight.name = node.name || "";
                         if (spotLight.color) {
                             spLight.diffuse = BABYLON.Color3.FromArray(spotLight.color);
                         }
@@ -1054,7 +1054,7 @@ var BABYLON;
                 if (camera) {
                     if (camera.type === "orthographic") {
                         var orthoCamera = new BABYLON.FreeCamera(node.camera, BABYLON.Vector3.Zero(), gltfRuntime.scene);
-                        orthoCamera.name = node.name;
+                        orthoCamera.name = node.name || "";
                         orthoCamera.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
                         orthoCamera.attachControl(gltfRuntime.scene.getEngine().getRenderingCanvas());
                         lastNode = orthoCamera;
@@ -1062,7 +1062,7 @@ var BABYLON;
                     else if (camera.type === "perspective") {
                         var perspectiveCamera = camera[camera.type];
                         var persCamera = new BABYLON.FreeCamera(node.camera, BABYLON.Vector3.Zero(), gltfRuntime.scene);
-                        persCamera.name = node.name;
+                        persCamera.name = node.name || "";
                         persCamera.attachControl(gltfRuntime.scene.getEngine().getRenderingCanvas());
                         if (!perspectiveCamera.aspectRatio) {
                             perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();
@@ -1081,7 +1081,7 @@ var BABYLON;
                     return node.babylonNode;
                 }
                 else if (lastNode === null) {
-                    var dummy = new BABYLON.Mesh(node.name, gltfRuntime.scene);
+                    var dummy = new BABYLON.Mesh(node.name || "", gltfRuntime.scene);
                     node.babylonNode = dummy;
                     lastNode = dummy;
                 }
@@ -1105,10 +1105,11 @@ var BABYLON;
         * Traverses nodes and creates them
         */
         var traverseNodes = function (gltfRuntime, id, parent, meshIncluded) {
+            if (meshIncluded === void 0) { meshIncluded = false; }
             var node = gltfRuntime.nodes[id];
             var newNode = null;
-            if (gltfRuntime.importOnlyMeshes && !meshIncluded) {
-                if (gltfRuntime.importMeshesNames.indexOf(node.name) !== -1 || gltfRuntime.importMeshesNames.length === 0) {
+            if (gltfRuntime.importOnlyMeshes && !meshIncluded && gltfRuntime.importMeshesNames) {
+                if (gltfRuntime.importMeshesNames.indexOf(node.name || "") !== -1 || gltfRuntime.importMeshesNames.length === 0) {
                     meshIncluded = true;
                 }
                 else {
@@ -1170,9 +1171,9 @@ var BABYLON;
                         GLTF1.GLTFUtils.SetMatrix(gltfRuntime.scene, mesh, uniform, unif, shaderMaterial.getEffect());
                     }
                     else if (uniform.semantic && (uniform.source || uniform.node)) {
-                        var source = gltfRuntime.scene.getNodeByName(uniform.source || uniform.node);
+                        var source = gltfRuntime.scene.getNodeByName(uniform.source || uniform.node || "");
                         if (source === null) {
-                            source = gltfRuntime.scene.getNodeByID(uniform.source || uniform.node);
+                            source = gltfRuntime.scene.getNodeByID(uniform.source || uniform.node || "");
                         }
                         if (source === null) {
                             continue;
@@ -1193,7 +1194,7 @@ var BABYLON;
                         shaderMaterial.getEffect().setTexture(unif, texture);
                     }
                     else {
-                        GLTF1.GLTFUtils.SetUniform(shaderMaterial.getEffect(), unif, value, type);
+                        GLTF1.GLTFUtils.SetUniform((shaderMaterial.getEffect()), unif, value, type);
                     }
                 }
             }
@@ -1222,7 +1223,7 @@ var BABYLON;
                 }
                 var onLoadTexture = function (uniformName) {
                     return function (texture) {
-                        if (uniform.value) {
+                        if (uniform.value && uniformName) {
                             // Static uniform
                             shaderMaterial.setTexture(uniformName, texture);
                             delete unTreatedUniforms[uniformName];
@@ -1292,7 +1293,7 @@ var BABYLON;
         /**
         * Implementation of the base glTF spec
         */
-        var GLTFLoaderBase = (function () {
+        var GLTFLoaderBase = /** @class */ (function () {
             function GLTFLoaderBase() {
             }
             GLTFLoaderBase.CreateRuntime = function (parsedData, scene, rootUrl) {
@@ -1395,15 +1396,17 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, function (request) {
-                        onError(request.status + " " + request.statusText);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, undefined, true, function (request) {
+                        if (request) {
+                            onError(request.status + " " + request.statusText);
+                        }
                     });
                 }
             };
             GLTFLoaderBase.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var texture = gltfRuntime.textures[id];
                 if (!texture || !texture.source) {
-                    onError(null);
+                    onError("");
                     return;
                 }
                 if (texture.babylonTexture) {
@@ -1415,8 +1418,10 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, function (request) {
-                        onError(request.status + " " + request.statusText);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, undefined, undefined, true, function (request) {
+                        if (request) {
+                            onError(request.status + " " + request.statusText);
+                        }
                     });
                 }
             };
@@ -1436,8 +1441,12 @@ var BABYLON;
                 var blobURL = URL.createObjectURL(blob);
                 var revokeBlobURL = function () { return URL.revokeObjectURL(blobURL); };
                 var newTexture = new BABYLON.Texture(blobURL, gltfRuntime.scene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
-                newTexture.wrapU = GLTF1.GLTFUtils.GetWrapMode(sampler.wrapS);
-                newTexture.wrapV = GLTF1.GLTFUtils.GetWrapMode(sampler.wrapT);
+                if (sampler.wrapS !== undefined) {
+                    newTexture.wrapU = GLTF1.GLTFUtils.GetWrapMode(sampler.wrapS);
+                }
+                if (sampler.wrapT !== undefined) {
+                    newTexture.wrapV = GLTF1.GLTFUtils.GetWrapMode(sampler.wrapT);
+                }
                 newTexture.name = id;
                 texture.babylonTexture = newTexture;
                 onSuccess(newTexture);
@@ -1449,13 +1458,21 @@ var BABYLON;
                     onSuccess(shaderString);
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, function (request) {
-                        onError(request.status + " " + request.statusText);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, undefined, undefined, false, function (request) {
+                        if (request) {
+                            onError(request.status + " " + request.statusText);
+                        }
                     });
                 }
             };
             GLTFLoaderBase.LoadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var material = gltfRuntime.materials[id];
+                if (!material.technique) {
+                    if (onError) {
+                        onError("No technique found.");
+                    }
+                    return;
+                }
                 var technique = gltfRuntime.techniques[material.technique];
                 if (!technique) {
                     var defaultMaterial = new BABYLON.StandardMaterial(id, gltfRuntime.scene);
@@ -1587,7 +1604,7 @@ var BABYLON;
         /**
         * glTF V1 Loader
         */
-        var GLTFLoader = (function () {
+        var GLTFLoader = /** @class */ (function () {
             function GLTFLoader() {
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -1597,6 +1614,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
@@ -1638,12 +1658,12 @@ var BABYLON;
                             importMaterials(gltfRuntime);
                             postLoad(gltfRuntime);
                             if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                                onSuccess(meshes, null, skeletons);
+                                onSuccess(meshes, [], skeletons);
                             }
                         });
                     }, onProgress);
                     if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                        onSuccess(meshes, null, skeletons);
+                        onSuccess(meshes, [], skeletons);
                     }
                 }, onError);
                 return true;
@@ -1771,7 +1791,7 @@ var BABYLON;
         /**
         * Utils functions for GLTF
         */
-        var GLTFUtils = (function () {
+        var GLTFUtils = /** @class */ (function () {
             function GLTFUtils() {
             }
             /**
@@ -1823,17 +1843,19 @@ var BABYLON;
                 else {
                     debugger;
                 }
-                switch (parameter.type) {
-                    case GLTF1.EParameterType.FLOAT_MAT2:
-                        shaderMaterial.setMatrix2x2(uniformName, BABYLON.Matrix.GetAsMatrix2x2(mat));
-                        break;
-                    case GLTF1.EParameterType.FLOAT_MAT3:
-                        shaderMaterial.setMatrix3x3(uniformName, BABYLON.Matrix.GetAsMatrix3x3(mat));
-                        break;
-                    case GLTF1.EParameterType.FLOAT_MAT4:
-                        shaderMaterial.setMatrix(uniformName, mat);
-                        break;
-                    default: break;
+                if (mat) {
+                    switch (parameter.type) {
+                        case GLTF1.EParameterType.FLOAT_MAT2:
+                            shaderMaterial.setMatrix2x2(uniformName, BABYLON.Matrix.GetAsMatrix2x2(mat));
+                            break;
+                        case GLTF1.EParameterType.FLOAT_MAT3:
+                            shaderMaterial.setMatrix3x3(uniformName, BABYLON.Matrix.GetAsMatrix3x3(mat));
+                            break;
+                        case GLTF1.EParameterType.FLOAT_MAT4:
+                            shaderMaterial.setMatrix(uniformName, mat);
+                            break;
+                        default: break;
+                    }
                 }
             };
             /**
@@ -2021,7 +2043,7 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF1;
     (function (GLTF1) {
-        var GLTFLoaderExtension = (function () {
+        var GLTFLoaderExtension = /** @class */ (function () {
             function GLTFLoaderExtension(name) {
                 this._name = name;
             }
@@ -2175,14 +2197,14 @@ var BABYLON;
         var BinaryExtensionBufferName = "binary_glTF";
         ;
         ;
-        var GLTFBinaryExtension = (function (_super) {
+        var GLTFBinaryExtension = /** @class */ (function (_super) {
             __extends(GLTFBinaryExtension, _super);
             function GLTFBinaryExtension() {
                 return _super.call(this, "KHR_binary_glTF") || this;
             }
             GLTFBinaryExtension.prototype.loadRuntimeAsync = function (scene, data, rootUrl, onSuccess, onError) {
                 var extensionsUsed = data.json.extensionsUsed;
-                if (!extensionsUsed || extensionsUsed.indexOf(this.name) === -1) {
+                if (!extensionsUsed || extensionsUsed.indexOf(this.name) === -1 || !data.bin) {
                     return false;
                 }
                 this._bin = data.bin;
@@ -2252,7 +2274,7 @@ var BABYLON;
         ;
         ;
         ;
-        var GLTFMaterialsCommonExtension = (function (_super) {
+        var GLTFMaterialsCommonExtension = /** @class */ (function (_super) {
             __extends(GLTFMaterialsCommonExtension, _super);
             function GLTFMaterialsCommonExtension() {
                 return _super.call(this, "KHR_materials_common") || this;
@@ -2272,22 +2294,30 @@ var BABYLON;
                             case "ambient":
                                 var ambientLight = new BABYLON.HemisphericLight(light.name, new BABYLON.Vector3(0, 1, 0), gltfRuntime.scene);
                                 var ambient = light.ambient;
-                                ambientLight.diffuse = BABYLON.Color3.FromArray(ambient.color || [1, 1, 1]);
+                                if (ambient) {
+                                    ambientLight.diffuse = BABYLON.Color3.FromArray(ambient.color || [1, 1, 1]);
+                                }
                                 break;
                             case "point":
                                 var pointLight = new BABYLON.PointLight(light.name, new BABYLON.Vector3(10, 10, 10), gltfRuntime.scene);
                                 var point = light.point;
-                                pointLight.diffuse = BABYLON.Color3.FromArray(point.color || [1, 1, 1]);
+                                if (point) {
+                                    pointLight.diffuse = BABYLON.Color3.FromArray(point.color || [1, 1, 1]);
+                                }
                                 break;
                             case "directional":
                                 var dirLight = new BABYLON.DirectionalLight(light.name, new BABYLON.Vector3(0, -1, 0), gltfRuntime.scene);
                                 var directional = light.directional;
-                                dirLight.diffuse = BABYLON.Color3.FromArray(directional.color || [1, 1, 1]);
+                                if (directional) {
+                                    dirLight.diffuse = BABYLON.Color3.FromArray(directional.color || [1, 1, 1]);
+                                }
                                 break;
                             case "spot":
                                 var spot = light.spot;
-                                var spotLight = new BABYLON.SpotLight(light.name, new BABYLON.Vector3(0, 10, 0), new BABYLON.Vector3(0, -1, 0), light.spot.fallOffAngle || Math.PI, light.spot.fallOffExponent || 0.0, gltfRuntime.scene);
-                                spotLight.diffuse = BABYLON.Color3.FromArray(spot.color || [1, 1, 1]);
+                                if (spot) {
+                                    var spotLight = new BABYLON.SpotLight(light.name, new BABYLON.Vector3(0, 10, 0), new BABYLON.Vector3(0, -1, 0), spot.fallOffAngle || Math.PI, spot.fallOffExponent || 0.0, gltfRuntime.scene);
+                                    spotLight.diffuse = BABYLON.Color3.FromArray(spot.color || [1, 1, 1]);
+                                }
                                 break;
                             default:
                                 BABYLON.Tools.Warn("GLTF Material Common extension: light type \"" + light.type + "\” not supported");

文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 56 - 48
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -7,13 +7,13 @@ declare module BABYLON {
     }
     interface IGLTFLoaderData {
         json: Object;
-        bin: ArrayBufferView;
+        bin: Nullable<ArrayBufferView>;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,27 +27,23 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data, onError);
-        private _getLoader(loaderData, onError);
-        private static _parseBinary(data, onError);
-        private static _parseV1(binaryReader, onError);
-        private static _parseV2(binaryReader, onError);
+        private static _parse(data);
+        private _getLoader(loaderData);
+        private static _parseBinary(data);
+        private static _parseV1(binaryReader);
+        private static _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -129,7 +125,7 @@ declare module BABYLON.GLTF2 {
         max: number[];
         min: number[];
         sparse?: IGLTFAccessorSparse;
-        index?: number;
+        index: number;
     }
     interface IGLTFAnimationChannel extends IGLTFProperty {
         sampler: number;
@@ -147,8 +143,8 @@ declare module BABYLON.GLTF2 {
     interface IGLTFAnimation extends IGLTFChildRootProperty {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
-        index?: number;
-        targets?: any[];
+        index: number;
+        targets: any[];
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;
@@ -159,7 +155,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFBuffer extends IGLTFChildRootProperty {
         uri?: string;
         byteLength: number;
-        index?: number;
+        index: number;
         loadedData?: ArrayBufferView;
         loadedObservable?: Observable<IGLTFBuffer>;
     }
@@ -168,7 +164,7 @@ declare module BABYLON.GLTF2 {
         byteOffset?: number;
         byteLength: number;
         byteStride?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFCameraOrthographic extends IGLTFProperty {
         xmag: number;
@@ -191,7 +187,7 @@ declare module BABYLON.GLTF2 {
         uri?: string;
         mimeType?: string;
         bufferView?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
         scale: number;
@@ -215,8 +211,8 @@ declare module BABYLON.GLTF2 {
         alphaMode?: string;
         alphaCutoff: number;
         doubleSided?: boolean;
-        index?: number;
-        babylonMaterial?: Material;
+        index: number;
+        babylonMaterial: Material;
     }
     interface IGLTFMeshPrimitive extends IGLTFProperty {
         attributes: {
@@ -234,7 +230,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
         weights?: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFNode extends IGLTFChildRootProperty {
         camera?: number;
@@ -246,13 +242,13 @@ declare module BABYLON.GLTF2 {
         scale?: number[];
         translation?: number[];
         weights?: number[];
-        index?: number;
+        index: number;
         parent?: IGLTFNode;
-        babylonMesh?: Mesh;
-        babylonBones?: {
+        babylonMesh: Mesh;
+        babylonBones: {
             [skin: number]: Bone;
         };
-        babylonAnimationTargets?: Node[];
+        babylonAnimationTargets: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
         magFilter?: ETextureMagFilter;
@@ -262,19 +258,19 @@ declare module BABYLON.GLTF2 {
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFSkin extends IGLTFChildRootProperty {
         inverseBindMatrices?: number;
         skeleton?: number;
         joints: number[];
-        index?: number;
-        babylonSkeleton?: Skeleton;
+        index: number;
+        babylonSkeleton: Skeleton;
     }
     interface IGLTFTexture extends IGLTFChildRootProperty {
         sampler?: number;
         source: number;
-        index?: number;
+        index: number;
         url?: string;
         dataReadyObservable?: Observable<IGLTFTexture>;
     }
@@ -305,9 +301,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -316,7 +313,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -330,7 +327,6 @@ declare module BABYLON.GLTF2 {
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
-        private _onError(message);
         private _onProgress(event);
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
@@ -345,6 +341,18 @@ declare module BABYLON.GLTF2 {
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
         private _loadAllVertexDataAsync(context, mesh, onSuccess);
+        /**
+         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4TextureCoordArray(context, data, accessor);
+        /**
+         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4ColorArray(context, data, accessor);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
         private _createMorphTargets(context, node, mesh);
         private _loadMorphTargets(context, node, mesh);
@@ -357,14 +365,14 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
         private _loadAnimations();
+        private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
         private _loadBufferAsync(context, buffer, onSuccess);
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
-        private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -376,9 +384,15 @@ declare module BABYLON.GLTF2 {
         _createPbrMaterial(material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
+        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
+        private static _AssignIndices(array?);
+        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
+        private static _GetTextureWrapMode(mode?);
+        private static _GetTextureSamplingMode(magFilter?, minFilter?);
+        private static _GetNumComponents(type);
     }
 }
 
@@ -399,12 +413,6 @@ declare module BABYLON.GLTF2 {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         static ValidateUri(uri: string): boolean;
-        static AssignIndices(array: Array<{
-            index?: number;
-        }>): void;
-        static GetArrayItem<T>(array: ArrayLike<T>, index: number): T;
-        static GetTextureWrapMode(mode: ETextureWrapMode): number;
-        static GetTextureSamplingMode(magFilter: ETextureMagFilter, minFilter: ETextureMinFilter): number;
     }
 }
 
@@ -413,12 +421,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
+        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

文件差異過大導致無法顯示
+ 612 - 469
dist/preview release/loaders/babylon.glTF2FileLoader.js


文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 59 - 50
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -7,13 +7,13 @@ declare module BABYLON {
     }
     interface IGLTFLoaderData {
         json: Object;
-        bin: ArrayBufferView;
+        bin: Nullable<ArrayBufferView>;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,27 +27,23 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data, onError);
-        private _getLoader(loaderData, onError);
-        private static _parseBinary(data, onError);
-        private static _parseV1(binaryReader, onError);
-        private static _parseV2(binaryReader, onError);
+        private static _parse(data);
+        private _getLoader(loaderData);
+        private static _parseBinary(data);
+        private static _parseV1(binaryReader);
+        private static _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -434,8 +430,8 @@ declare module BABYLON.GLTF1 {
     class GLTFLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
         static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
-        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): void;
-        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: Nullable<ArrayBufferView>) => void, onError: (message: string) => void): void;
+        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: Nullable<ArrayBufferView>, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
         static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void;
         static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
     }
@@ -447,6 +443,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
@@ -675,7 +672,7 @@ declare module BABYLON.GLTF2 {
         max: number[];
         min: number[];
         sparse?: IGLTFAccessorSparse;
-        index?: number;
+        index: number;
     }
     interface IGLTFAnimationChannel extends IGLTFProperty {
         sampler: number;
@@ -693,8 +690,8 @@ declare module BABYLON.GLTF2 {
     interface IGLTFAnimation extends IGLTFChildRootProperty {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
-        index?: number;
-        targets?: any[];
+        index: number;
+        targets: any[];
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;
@@ -705,7 +702,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFBuffer extends IGLTFChildRootProperty {
         uri?: string;
         byteLength: number;
-        index?: number;
+        index: number;
         loadedData?: ArrayBufferView;
         loadedObservable?: Observable<IGLTFBuffer>;
     }
@@ -714,7 +711,7 @@ declare module BABYLON.GLTF2 {
         byteOffset?: number;
         byteLength: number;
         byteStride?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFCameraOrthographic extends IGLTFProperty {
         xmag: number;
@@ -737,7 +734,7 @@ declare module BABYLON.GLTF2 {
         uri?: string;
         mimeType?: string;
         bufferView?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
         scale: number;
@@ -761,8 +758,8 @@ declare module BABYLON.GLTF2 {
         alphaMode?: string;
         alphaCutoff: number;
         doubleSided?: boolean;
-        index?: number;
-        babylonMaterial?: Material;
+        index: number;
+        babylonMaterial: Material;
     }
     interface IGLTFMeshPrimitive extends IGLTFProperty {
         attributes: {
@@ -780,7 +777,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
         weights?: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFNode extends IGLTFChildRootProperty {
         camera?: number;
@@ -792,13 +789,13 @@ declare module BABYLON.GLTF2 {
         scale?: number[];
         translation?: number[];
         weights?: number[];
-        index?: number;
+        index: number;
         parent?: IGLTFNode;
-        babylonMesh?: Mesh;
-        babylonBones?: {
+        babylonMesh: Mesh;
+        babylonBones: {
             [skin: number]: Bone;
         };
-        babylonAnimationTargets?: Node[];
+        babylonAnimationTargets: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
         magFilter?: ETextureMagFilter;
@@ -808,19 +805,19 @@ declare module BABYLON.GLTF2 {
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFSkin extends IGLTFChildRootProperty {
         inverseBindMatrices?: number;
         skeleton?: number;
         joints: number[];
-        index?: number;
-        babylonSkeleton?: Skeleton;
+        index: number;
+        babylonSkeleton: Skeleton;
     }
     interface IGLTFTexture extends IGLTFChildRootProperty {
         sampler?: number;
         source: number;
-        index?: number;
+        index: number;
         url?: string;
         dataReadyObservable?: Observable<IGLTFTexture>;
     }
@@ -851,9 +848,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -862,7 +860,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -876,7 +874,6 @@ declare module BABYLON.GLTF2 {
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
-        private _onError(message);
         private _onProgress(event);
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
@@ -891,6 +888,18 @@ declare module BABYLON.GLTF2 {
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
         private _loadAllVertexDataAsync(context, mesh, onSuccess);
+        /**
+         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4TextureCoordArray(context, data, accessor);
+        /**
+         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4ColorArray(context, data, accessor);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
         private _createMorphTargets(context, node, mesh);
         private _loadMorphTargets(context, node, mesh);
@@ -903,14 +912,14 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
         private _loadAnimations();
+        private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
         private _loadBufferAsync(context, buffer, onSuccess);
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
-        private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -922,9 +931,15 @@ declare module BABYLON.GLTF2 {
         _createPbrMaterial(material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
+        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
+        private static _AssignIndices(array?);
+        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
+        private static _GetTextureWrapMode(mode?);
+        private static _GetTextureSamplingMode(magFilter?, minFilter?);
+        private static _GetNumComponents(type);
     }
 }
 
@@ -945,12 +960,6 @@ declare module BABYLON.GLTF2 {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         static ValidateUri(uri: string): boolean;
-        static AssignIndices(array: Array<{
-            index?: number;
-        }>): void;
-        static GetArrayItem<T>(array: ArrayLike<T>, index: number): T;
-        static GetTextureWrapMode(mode: ETextureWrapMode): number;
-        static GetTextureSamplingMode(magFilter: ETextureMagFilter, minFilter: ETextureMinFilter): number;
     }
 }
 
@@ -959,12 +968,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
+        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

文件差異過大導致無法顯示
+ 713 - 531
dist/preview release/loaders/babylon.glTFFileLoader.js


文件差異過大導致無法顯示
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.d.ts

@@ -56,7 +56,7 @@ declare module BABYLON {
          * @private
          */
         private _loadMTL(url, rootUrl, onSuccess);
-        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean;
+        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
         /**
          * Read the OBJ file and create an Array of meshes.

+ 18 - 16
dist/preview release/loaders/babylon.objFileLoader.js

@@ -4,7 +4,7 @@ var BABYLON;
     /**
      * Class reading and parsing the MTL file bundled with the obj file.
      */
-    var MTLFileLoader = (function () {
+    var MTLFileLoader = /** @class */ (function () {
         function MTLFileLoader() {
             // All material loaded from the mtl will be set here
             this.materials = [];
@@ -27,7 +27,7 @@ var BABYLON;
             //Array with RGB colors
             var color;
             //New material
-            var material;
+            var material = null;
             //Look at each line
             for (var i = 0; i < lines.length; i++) {
                 var line = lines[i].trim();
@@ -53,7 +53,7 @@ var BABYLON;
                     // value is the name of the material read in the mtl file
                     material = new BABYLON.StandardMaterial(value, scene);
                 }
-                else if (key === "kd") {
+                else if (key === "kd" && material) {
                     // Diffuse color (color under white light) using RGB values
                     //value  = "r g b"
                     color = value.split(delimiter_pattern, 3).map(parseFloat);
@@ -61,7 +61,7 @@ var BABYLON;
                     //Set tghe color into the material
                     material.diffuseColor = BABYLON.Color3.FromArray(color);
                 }
-                else if (key === "ka") {
+                else if (key === "ka" && material) {
                     // Ambient color (color under shadow) using RGB values
                     //value = "r g b"
                     color = value.split(delimiter_pattern, 3).map(parseFloat);
@@ -69,7 +69,7 @@ var BABYLON;
                     //Set tghe color into the material
                     material.ambientColor = BABYLON.Color3.FromArray(color);
                 }
-                else if (key === "ks") {
+                else if (key === "ks" && material) {
                     // Specular color (color when light is reflected from shiny surface) using RGB values
                     //value = "r g b"
                     color = value.split(delimiter_pattern, 3).map(parseFloat);
@@ -77,31 +77,31 @@ var BABYLON;
                     //Set the color into the material
                     material.specularColor = BABYLON.Color3.FromArray(color);
                 }
-                else if (key === "ke") {
+                else if (key === "ke" && material) {
                     // Emissive color using RGB values
                     color = value.split(delimiter_pattern, 3).map(parseFloat);
                     material.emissiveColor = BABYLON.Color3.FromArray(color);
                 }
-                else if (key === "ns") {
+                else if (key === "ns" && material) {
                     //value = "Integer"
                     material.specularPower = parseFloat(value);
                 }
-                else if (key === "d") {
+                else if (key === "d" && material) {
                     //d is dissolve for current material. It mean alpha for BABYLON
                     material.alpha = parseFloat(value);
                     //Texture
                     //This part can be improved by adding the possible options of texture
                 }
-                else if (key === "map_ka") {
+                else if (key === "map_ka" && material) {
                     // ambient texture map with a loaded image
                     //We must first get the folder of the image
                     material.ambientTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
                 }
-                else if (key === "map_kd") {
+                else if (key === "map_kd" && material) {
                     // Diffuse texture map with a loaded image
                     material.diffuseTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
                 }
-                else if (key === "map_ks") {
+                else if (key === "map_ks" && material) {
                     // Specular texture map with a loaded image
                     //We must first get the folder of the image
                     material.specularTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
@@ -115,11 +115,11 @@ var BABYLON;
                     //
                     //    continue;
                 }
-                else if (key === "map_bump") {
+                else if (key === "map_bump" && material) {
                     //The bump texture
                     material.bumpTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
                 }
-                else if (key === "map_d") {
+                else if (key === "map_d" && material) {
                     // The dissolve of the material
                     material.opacityTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
                     //Options for illumination
@@ -165,7 +165,9 @@ var BABYLON;
                 }
             }
             //At the end of the file, add the last material
-            this.materials.push(material);
+            if (material) {
+                this.materials.push(material);
+            }
         };
         /**
          * Gets the texture for the material.
@@ -203,7 +205,7 @@ var BABYLON;
         return MTLFileLoader;
     }());
     BABYLON.MTLFileLoader = MTLFileLoader;
-    var OBJFileLoader = (function () {
+    var OBJFileLoader = /** @class */ (function () {
         function OBJFileLoader() {
             this.name = "obj";
             this.extensions = ".obj";
@@ -241,7 +243,7 @@ var BABYLON;
             //The complete path to the mtl file
             var pathOfFile = BABYLON.Tools.BaseUrl + rootUrl + url;
             // Loads through the babylon tools to allow fileInput search.
-            BABYLON.Tools.LoadFile(pathOfFile, onSuccess, null, null, false, function () { console.warn("Error - Unable to load " + pathOfFile); });
+            BABYLON.Tools.LoadFile(pathOfFile, onSuccess, undefined, undefined, false, function () { console.warn("Error - Unable to load " + pathOfFile); });
         };
         OBJFileLoader.prototype.importMesh = function (meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons) {
             //get the meshes from OBJ file

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.d.ts

@@ -7,7 +7,7 @@ declare module BABYLON {
         vertexPattern: RegExp;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
-        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean;
+        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
         private isBinary(data);
         private parseBinary(mesh, data);

+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.js

@@ -1,7 +1,7 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
-    var STLFileLoader = (function () {
+    var STLFileLoader = /** @class */ (function () {
         function STLFileLoader() {
             this.solidPattern = /solid (\S*)([\S\s]*)endsolid[ ]*(\S*)/g;
             this.facetsPattern = /facet([\s\S]*?)endfacet/g;

文件差異過大導致無法顯示
+ 731 - 547
dist/preview release/loaders/babylonjs.loaders.js


文件差異過大導致無法顯示
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 61 - 52
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -12,7 +12,7 @@ declare module BABYLON {
         vertexPattern: RegExp;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
-        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean;
+        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
         private isBinary(data);
         private parseBinary(mesh, data);
@@ -78,7 +78,7 @@ declare module BABYLON {
          * @private
          */
         private _loadMTL(url, rootUrl, onSuccess);
-        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean;
+        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
         /**
          * Read the OBJ file and create an Array of meshes.
@@ -105,13 +105,13 @@ declare module BABYLON {
     }
     interface IGLTFLoaderData {
         json: Object;
-        bin: ArrayBufferView;
+        bin: Nullable<ArrayBufferView>;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -125,27 +125,23 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data, onError);
-        private _getLoader(loaderData, onError);
-        private static _parseBinary(data, onError);
-        private static _parseV1(binaryReader, onError);
-        private static _parseV2(binaryReader, onError);
+        private static _parse(data);
+        private _getLoader(loaderData);
+        private static _parseBinary(data);
+        private static _parseV1(binaryReader);
+        private static _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -532,8 +528,8 @@ declare module BABYLON.GLTF1 {
     class GLTFLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
         static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
-        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): void;
-        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: Nullable<ArrayBufferView>) => void, onError: (message: string) => void): void;
+        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: Nullable<ArrayBufferView>, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
         static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void;
         static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
     }
@@ -545,6 +541,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
@@ -773,7 +770,7 @@ declare module BABYLON.GLTF2 {
         max: number[];
         min: number[];
         sparse?: IGLTFAccessorSparse;
-        index?: number;
+        index: number;
     }
     interface IGLTFAnimationChannel extends IGLTFProperty {
         sampler: number;
@@ -791,8 +788,8 @@ declare module BABYLON.GLTF2 {
     interface IGLTFAnimation extends IGLTFChildRootProperty {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
-        index?: number;
-        targets?: any[];
+        index: number;
+        targets: any[];
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;
@@ -803,7 +800,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFBuffer extends IGLTFChildRootProperty {
         uri?: string;
         byteLength: number;
-        index?: number;
+        index: number;
         loadedData?: ArrayBufferView;
         loadedObservable?: Observable<IGLTFBuffer>;
     }
@@ -812,7 +809,7 @@ declare module BABYLON.GLTF2 {
         byteOffset?: number;
         byteLength: number;
         byteStride?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFCameraOrthographic extends IGLTFProperty {
         xmag: number;
@@ -835,7 +832,7 @@ declare module BABYLON.GLTF2 {
         uri?: string;
         mimeType?: string;
         bufferView?: number;
-        index?: number;
+        index: number;
     }
     interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
         scale: number;
@@ -859,8 +856,8 @@ declare module BABYLON.GLTF2 {
         alphaMode?: string;
         alphaCutoff: number;
         doubleSided?: boolean;
-        index?: number;
-        babylonMaterial?: Material;
+        index: number;
+        babylonMaterial: Material;
     }
     interface IGLTFMeshPrimitive extends IGLTFProperty {
         attributes: {
@@ -878,7 +875,7 @@ declare module BABYLON.GLTF2 {
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
         weights?: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFNode extends IGLTFChildRootProperty {
         camera?: number;
@@ -890,13 +887,13 @@ declare module BABYLON.GLTF2 {
         scale?: number[];
         translation?: number[];
         weights?: number[];
-        index?: number;
+        index: number;
         parent?: IGLTFNode;
-        babylonMesh?: Mesh;
-        babylonBones?: {
+        babylonMesh: Mesh;
+        babylonBones: {
             [skin: number]: Bone;
         };
-        babylonAnimationTargets?: Node[];
+        babylonAnimationTargets: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
         magFilter?: ETextureMagFilter;
@@ -906,19 +903,19 @@ declare module BABYLON.GLTF2 {
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
-        index?: number;
+        index: number;
     }
     interface IGLTFSkin extends IGLTFChildRootProperty {
         inverseBindMatrices?: number;
         skeleton?: number;
         joints: number[];
-        index?: number;
-        babylonSkeleton?: Skeleton;
+        index: number;
+        babylonSkeleton: Skeleton;
     }
     interface IGLTFTexture extends IGLTFChildRootProperty {
         sampler?: number;
         source: number;
-        index?: number;
+        index: number;
         url?: string;
         dataReadyObservable?: Observable<IGLTFTexture>;
     }
@@ -949,9 +946,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -960,7 +958,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -974,7 +972,6 @@ declare module BABYLON.GLTF2 {
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
-        private _onError(message);
         private _onProgress(event);
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
@@ -989,6 +986,18 @@ declare module BABYLON.GLTF2 {
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
         private _loadAllVertexDataAsync(context, mesh, onSuccess);
+        /**
+         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4TextureCoordArray(context, data, accessor);
+        /**
+         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
+         * @param {ArrayBufferView} data
+         * @param {IGLTFAccessor} accessor
+         */
+        private _convertToFloat4ColorArray(context, data, accessor);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
         private _createMorphTargets(context, node, mesh);
         private _loadMorphTargets(context, node, mesh);
@@ -1001,14 +1010,14 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
         private _loadAnimations();
+        private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
         private _loadBufferAsync(context, buffer, onSuccess);
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
-        private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -1020,9 +1029,15 @@ declare module BABYLON.GLTF2 {
         _createPbrMaterial(material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
+        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
+        private static _AssignIndices(array?);
+        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
+        private static _GetTextureWrapMode(mode?);
+        private static _GetTextureSamplingMode(magFilter?, minFilter?);
+        private static _GetNumComponents(type);
     }
 }
 
@@ -1043,12 +1058,6 @@ declare module BABYLON.GLTF2 {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         static ValidateUri(uri: string): boolean;
-        static AssignIndices(array: Array<{
-            index?: number;
-        }>): void;
-        static GetArrayItem<T>(array: ArrayLike<T>, index: number): T;
-        static GetTextureWrapMode(mode: ETextureWrapMode): number;
-        static GetTextureSamplingMode(magFilter: ETextureMagFilter, minFilter: ETextureMinFilter): number;
     }
 }
 
@@ -1057,12 +1066,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
+        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

+ 1 - 1
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.1.0-alpha3.6",
+    "version": "3.1.0-alpha3.7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/loaders/readme.md

@@ -36,7 +36,7 @@ Afterwards it can be imported to the project using:
 
 ```
 import * as BABYLON from 'babylonjs';
-import from 'babylonjs-loaders';
+import 'babylonjs-loaders';
 ```
 
 This will extend Babylon's namespace with the loaders available.

+ 246 - 0
dist/preview release/materialsLibrary/babylon.backgroundMaterial.d.ts

@@ -0,0 +1,246 @@
+
+declare namespace BABYLON {
+    /**
+     * Background material
+     */
+    class BackgroundMaterial extends BABYLON.PushMaterial {
+        /**
+         * Key light Color (multiply against the R channel of the environement texture)
+         */
+        protected _primaryColor: Color3;
+        primaryColor: Color3;
+        /**
+         * Key light Level (allowing HDR output of the background)
+         */
+        protected _primaryLevel: float;
+        primaryLevel: float;
+        /**
+         * Secondary light Color (multiply against the G channel of the environement texture)
+         */
+        protected _secondaryColor: Color3;
+        secondaryColor: Color3;
+        /**
+         * Secondary light Level (allowing HDR output of the background)
+         */
+        protected _secondaryLevel: float;
+        secondaryLevel: float;
+        /**
+         * Tertiary light Color (multiply against the B channel of the environement texture)
+         */
+        protected _tertiaryColor: Color3;
+        tertiaryColor: Color3;
+        /**
+         * Tertiary light Level (allowing HDR output of the background)
+         */
+        protected _tertiaryLevel: float;
+        tertiaryLevel: float;
+        /**
+         * Reflection Texture used in the material.
+         * Should be author in a specific way for the best result (refer to the documentation).
+         */
+        protected _reflectionTexture: Nullable<BaseTexture>;
+        reflectionTexture: Nullable<BaseTexture>;
+        /**
+         * Reflection Texture level of blur.
+         *
+         * Can be use to reuse an existing HDR Texture and target a specific LOD to prevent authoring the
+         * texture twice.
+         */
+        protected _reflectionBlur: float;
+        reflectionBlur: float;
+        /**
+         * Diffuse Texture used in the material.
+         * Should be author in a specific way for the best result (refer to the documentation).
+         */
+        protected _diffuseTexture: Nullable<BaseTexture>;
+        diffuseTexture: Nullable<BaseTexture>;
+        /**
+         * Specify the list of lights casting shadow on the material.
+         * All scene shadow lights will be included if null.
+         */
+        protected _shadowLights: Nullable<IShadowLight[]>;
+        shadowLights: Nullable<IShadowLight[]>;
+        /**
+         * For the lights having a blurred shadow generator, this can add a second blur pass in order to reach
+         * soft lighting on the background.
+         */
+        protected _shadowBlurScale: int;
+        shadowBlurScale: int;
+        /**
+         * Helps adjusting the shadow to a softer level if required.
+         * 0 means black shadows and 1 means no shadows.
+         */
+        protected _shadowLevel: float;
+        shadowLevel: float;
+        /**
+         * This helps specifying that the material is falling off to the sky box at grazing angle.
+         * This helps ensuring a nice transition when the camera goes under the ground.
+         */
+        protected _opacityFresnel: boolean;
+        opacityFresnel: boolean;
+        /**
+         * Helps to directly use the maps channels instead of their level.
+         */
+        protected _useRGBColor: boolean;
+        useRGBColor: boolean;
+        /**
+         * Number of Simultaneous lights allowed on the material.
+         */
+        private _maxSimultaneousLights;
+        maxSimultaneousLights: int;
+        /**
+         * Default configuration related to image processing available in the Background Material.
+         */
+        protected _imageProcessingConfiguration: ImageProcessingConfiguration;
+        /**
+         * Keep track of the image processing observer to allow dispose and replace.
+         */
+        private _imageProcessingObserver;
+        /**
+         * Attaches a new image processing configuration to the PBR Material.
+         * @param configuration (if null the scene configuration will be use)
+         */
+        protected _attachImageProcessingConfiguration(configuration: Nullable<ImageProcessingConfiguration>): void;
+        /**
+         * Gets the image processing configuration used either in this material.
+         */
+        /**
+         * Sets the Default image processing configuration used either in the this material.
+         *
+         * If sets to null, the scene one is in use.
+         */
+        imageProcessingConfiguration: Nullable<ImageProcessingConfiguration>;
+        /**
+         * Gets wether the color curves effect is enabled.
+         */
+        /**
+         * Sets wether the color curves effect is enabled.
+         */
+        cameraColorCurvesEnabled: boolean;
+        /**
+         * Gets wether the color grading effect is enabled.
+         */
+        /**
+         * Gets wether the color grading effect is enabled.
+         */
+        cameraColorGradingEnabled: boolean;
+        /**
+         * Gets wether tonemapping is enabled or not.
+         */
+        /**
+         * Sets wether tonemapping is enabled or not
+         */
+        cameraToneMappingEnabled: boolean;
+        /**
+         * The camera exposure used on this material.
+         * This property is here and not in the camera to allow controlling exposure without full screen post process.
+         * This corresponds to a photographic exposure.
+         */
+        /**
+         * The camera exposure used on this material.
+         * This property is here and not in the camera to allow controlling exposure without full screen post process.
+         * This corresponds to a photographic exposure.
+         */
+        cameraExposure: float;
+        /**
+         * Gets The camera contrast used on this material.
+         */
+        /**
+         * Sets The camera contrast used on this material.
+         */
+        cameraContrast: float;
+        /**
+         * Gets the Color Grading 2D Lookup Texture.
+         */
+        /**
+         * Sets the Color Grading 2D Lookup Texture.
+         */
+        cameraColorGradingTexture: Nullable<BaseTexture>;
+        /**
+         * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT).
+         * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
+         * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image;
+         * corresponding to low luminance, medium luminance, and high luminance areas respectively.
+         */
+        /**
+         * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT).
+         * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
+         * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image;
+         * corresponding to low luminance, medium luminance, and high luminance areas respectively.
+         */
+        cameraColorCurves: Nullable<ColorCurves>;
+        private _renderTargets;
+        /**
+         * constructor
+         * @param name The name of the material
+         * @param scene The scene to add the material to
+         */
+        constructor(name: string, scene: BABYLON.Scene);
+        /**
+         * The entire material has been created in order to prevent overdraw.
+         * @returns false
+         */
+        needAlphaTesting(): boolean;
+        /**
+         * The entire material has been created in order to prevent overdraw.
+         * @returns true if blending is enable
+         */
+        needAlphaBlending(): boolean;
+        /**
+         * Checks wether the material is ready to be rendered for a given mesh.
+         * @param mesh The mesh to render
+         * @param subMesh The submesh to check against
+         * @param useInstances Specify wether or not the material is used with instances
+         */
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
+        /**
+         * Build the uniform buffer used in the material.
+         */
+        buildUniformLayout(): void;
+        /**
+         * Unbind the material.
+         */
+        unbind(): void;
+        /**
+         * Bind only the world matrix to the material.
+         * @param world The world matrix to bind.
+         */
+        bindOnlyWorldMatrix(world: Matrix): void;
+        /**
+         * Bind the material for a dedicated submeh (every used meshes will be considered opaque).
+         * @param world The world matrix to bind.
+         * @param subMesh The submesh to bind for.
+         */
+        bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void;
+        /**
+         * Dispose the material.
+         * @forceDisposeEffect Force disposal of the associated effect.
+         * @forceDisposeTextures Force disposal of the associated textures.
+         */
+        dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void;
+        /**
+         * Clones the material.
+         * @name The cloned name.
+         * @returns The cloned material.
+         */
+        clone(name: string): BackgroundMaterial;
+        /**
+         * Serializes the current material to its JSON representation.
+         * @returns The JSON representation.
+         */
+        serialize(): any;
+        /**
+         * Gets the class name of the material
+         * @returns "BackgroundMaterial"
+         */
+        getClassName(): string;
+        /**
+         * Parse a JSON input to create back a background material.
+         * @param source
+         * @param scene
+         * @param rootUrl
+         * @returns the instantiated BackgroundMaterial.
+         */
+        static Parse(source: any, scene: Scene, rootUrl: string): BackgroundMaterial;
+    }
+}

文件差異過大導致無法顯示
+ 849 - 0
dist/preview release/materialsLibrary/babylon.backgroundMaterial.js


文件差異過大導致無法顯示
+ 1 - 0
dist/preview release/materialsLibrary/babylon.backgroundMaterial.min.js


+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.d.ts

@@ -14,7 +14,7 @@ declare module BABYLON {
         constructor(name: string, scene: Scene);
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
-        getAlphaTestTexture(): BaseTexture;
+        getAlphaTestTexture(): Nullable<BaseTexture>;
         isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void;
         getAnimatables(): IAnimatable[];

+ 9 - 6
dist/preview release/materialsLibrary/babylon.cellMaterial.js

@@ -17,7 +17,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
 };
 var BABYLON;
 (function (BABYLON) {
-    var CellMaterialDefines = (function (_super) {
+    var CellMaterialDefines = /** @class */ (function (_super) {
         __extends(CellMaterialDefines, _super);
         function CellMaterialDefines() {
             var _this = _super.call(this) || this;
@@ -43,7 +43,7 @@ var BABYLON;
         }
         return CellMaterialDefines;
     }(BABYLON.MaterialDefines));
-    var CellMaterial = (function (_super) {
+    var CellMaterial = /** @class */ (function (_super) {
         __extends(CellMaterial, _super);
         function CellMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
@@ -102,7 +102,7 @@ var BABYLON;
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -163,7 +163,7 @@ var BABYLON;
                     indexParameters: { maxSimultaneousLights: this.maxSimultaneousLights - 1 }
                 }, engine), defines);
             }
-            if (!subMesh.effect.isReady()) {
+            if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
             }
             this._renderId = scene.getRenderId();
@@ -177,6 +177,9 @@ var BABYLON;
                 return;
             }
             var effect = subMesh.effect;
+            if (!effect) {
+                return;
+            }
             this._activeEffect = effect;
             // Matrices        
             this.bindOnlyWorldMatrix(world);
@@ -196,7 +199,7 @@ var BABYLON;
                 if (this.pointsCloud) {
                     this._activeEffect.setFloat("pointSize", this.pointSize);
                 }
-                this._activeEffect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
+                BABYLON.MaterialHelper.BindEyePosition(effect, scene);
             }
             this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
             // Lights
@@ -260,7 +263,7 @@ var BABYLON;
             BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
         ], CellMaterial.prototype, "diffuseTexture", void 0);
         __decorate([
-            BABYLON.serializeAsColor3("diffuseColor")
+            BABYLON.serializeAsColor3("diffuse")
         ], CellMaterial.prototype, "diffuseColor", void 0);
         __decorate([
             BABYLON.serialize("computeHighLevel")

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.min.js


+ 3 - 2
dist/preview release/materialsLibrary/babylon.customMaterial.d.ts

@@ -68,6 +68,7 @@ declare module BABYLON {
         CONTRAST: boolean;
         COLORCURVES: boolean;
         COLORGRADING: boolean;
+        COLORGRADING3D: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
@@ -174,7 +175,7 @@ declare module BABYLON {
          * Attaches a new image processing configuration to the Standard Material.
          * @param configuration
          */
-        protected _attachImageProcessingConfiguration(configuration: ImageProcessingConfiguration): void;
+        protected _attachImageProcessingConfiguration(configuration: Nullable<ImageProcessingConfiguration>): void;
         /**
          * Gets wether the color curves effect is enabled.
          */
@@ -220,7 +221,7 @@ declare module BABYLON {
         /**
          * Sets the Color Grading 2D Lookup Texture.
          */
-        cameraColorGradingTexture: BaseTexture;
+        cameraColorGradingTexture: Nullable<BaseTexture>;
         customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: StandardMaterialDefines_OldVer) => string;
         protected _renderTargets: SmartArray<RenderTargetTexture>;
         protected _worldViewProjectionMatrix: Matrix;

+ 18 - 11
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -18,7 +18,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
 var BABYLON;
 (function (BABYLON) {
     // old version of standard material updated every 3 months
-    var StandardMaterialDefines_OldVer = (function (_super) {
+    var StandardMaterialDefines_OldVer = /** @class */ (function (_super) {
         __extends(StandardMaterialDefines_OldVer, _super);
         function StandardMaterialDefines_OldVer() {
             var _this = _super.call(this) || this;
@@ -89,6 +89,7 @@ var BABYLON;
             _this.CONTRAST = false;
             _this.COLORCURVES = false;
             _this.COLORGRADING = false;
+            _this.COLORGRADING3D = false;
             _this.SAMPLER3DGREENDEPTH = false;
             _this.SAMPLER3DBGRMAP = false;
             _this.IMAGEPROCESSINGPOSTPROCESS = false;
@@ -111,7 +112,7 @@ var BABYLON;
         return StandardMaterialDefines_OldVer;
     }(BABYLON.MaterialDefines));
     BABYLON.StandardMaterialDefines_OldVer = StandardMaterialDefines_OldVer;
-    var StandardMaterial_OldVer = (function (_super) {
+    var StandardMaterial_OldVer = /** @class */ (function (_super) {
         __extends(StandardMaterial_OldVer, _super);
         function StandardMaterial_OldVer(name, scene) {
             var _this = _super.call(this, name, scene) || this;
@@ -563,7 +564,7 @@ var BABYLON;
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -670,7 +671,7 @@ var BABYLON;
                 }, engine), defines);
                 this.buildUniformLayout();
             }
-            if (!subMesh.effect.isReady()) {
+            if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
             }
             defines._renderId = scene.getRenderId();
@@ -731,6 +732,9 @@ var BABYLON;
                 return;
             }
             var effect = subMesh.effect;
+            if (!effect) {
+                return;
+            }
             this._activeEffect = effect;
             // Matrices        
             this.bindOnlyWorldMatrix(world);
@@ -869,7 +873,7 @@ var BABYLON;
                 BABYLON.MaterialHelper.BindClipPlane(effect, scene);
                 // Colors
                 scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
-                effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
+                BABYLON.MaterialHelper.BindEyePosition(effect, scene);
                 effect.setColor3("vAmbientColor", this._globalAmbientColor);
             }
             if (this._mustRebind(scene, effect) || !this.isFrozen) {
@@ -1382,19 +1386,19 @@ var BABYLON;
         return StandardMaterial_OldVer;
     }(BABYLON.PushMaterial));
     BABYLON.StandardMaterial_OldVer = StandardMaterial_OldVer;
-    var CustomShaderStructure = (function () {
+    var CustomShaderStructure = /** @class */ (function () {
         function CustomShaderStructure() {
         }
         return CustomShaderStructure;
     }());
     BABYLON.CustomShaderStructure = CustomShaderStructure;
-    var ShaderSpecialParts = (function () {
+    var ShaderSpecialParts = /** @class */ (function () {
         function ShaderSpecialParts() {
         }
         return ShaderSpecialParts;
     }());
     BABYLON.ShaderSpecialParts = ShaderSpecialParts;
-    var ShaderForVer3_0 = (function (_super) {
+    var ShaderForVer3_0 = /** @class */ (function (_super) {
         __extends(ShaderForVer3_0, _super);
         function ShaderForVer3_0() {
             var _this = _super.call(this) || this;
@@ -1895,14 +1899,14 @@ vColor=color;\n\
         return ShaderForVer3_0;
     }(CustomShaderStructure));
     BABYLON.ShaderForVer3_0 = ShaderForVer3_0;
-    var StandardShaderVersions = (function () {
+    var StandardShaderVersions = /** @class */ (function () {
         function StandardShaderVersions() {
         }
         StandardShaderVersions.Ver3_0 = "3.0.0";
         return StandardShaderVersions;
     }());
     BABYLON.StandardShaderVersions = StandardShaderVersions;
-    var CustomMaterial = (function (_super) {
+    var CustomMaterial = /** @class */ (function (_super) {
         __extends(CustomMaterial, _super);
         function CustomMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
@@ -1950,11 +1954,14 @@ vColor=color;\n\
                 return this._createdShaderName;
             this._isCreatedShader = false;
             CustomMaterial.ShaderIndexer++;
-            var name = name + "custom_" + CustomMaterial.ShaderIndexer;
+            var name = "custom_" + CustomMaterial.ShaderIndexer;
             this.ReviewUniform("uniform", uniforms);
             this.ReviewUniform("sampler", samplers);
             var fn_afterBind = this._afterBind;
             this._afterBind = function (m, e) {
+                if (!e) {
+                    return;
+                }
                 _this.AttachAfterBind(m, e);
                 try {
                     fn_afterBind(m, e);

文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 4 - 4
dist/preview release/materialsLibrary/babylon.fireMaterial.d.ts

@@ -2,11 +2,11 @@
 declare module BABYLON {
     class FireMaterial extends PushMaterial {
         private _diffuseTexture;
-        diffuseTexture: BaseTexture;
+        diffuseTexture: Nullable<BaseTexture>;
         private _distortionTexture;
-        distortionTexture: BaseTexture;
+        distortionTexture: Nullable<BaseTexture>;
         private _opacityTexture;
-        opacityTexture: BaseTexture;
+        opacityTexture: Nullable<BaseTexture>;
         diffuseColor: Color3;
         speed: number;
         private _scaledDiffuse;
@@ -15,7 +15,7 @@ declare module BABYLON {
         constructor(name: string, scene: Scene);
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
-        getAlphaTestTexture(): BaseTexture;
+        getAlphaTestTexture(): Nullable<BaseTexture>;
         isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void;
         getAnimatables(): IAnimatable[];

+ 13 - 7
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -17,7 +17,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
 };
 var BABYLON;
 (function (BABYLON) {
-    var FireMaterialDefines = (function (_super) {
+    var FireMaterialDefines = /** @class */ (function (_super) {
         __extends(FireMaterialDefines, _super);
         function FireMaterialDefines() {
             var _this = _super.call(this) || this;
@@ -38,7 +38,7 @@ var BABYLON;
         }
         return FireMaterialDefines;
     }(BABYLON.MaterialDefines));
-    var FireMaterial = (function (_super) {
+    var FireMaterial = /** @class */ (function (_super) {
         __extends(FireMaterial, _super);
         function FireMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
@@ -94,7 +94,7 @@ var BABYLON;
                 defines.FOG = (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled);
             }
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);
             // Get correct effect      
@@ -140,10 +140,13 @@ var BABYLON;
                     defines: join,
                     fallbacks: fallbacks,
                     onCompiled: this.onCompiled,
-                    onError: this.onError
+                    onError: this.onError,
+                    indexParameters: null,
+                    maxSimultaneousLights: 4,
+                    transformFeedbackVaryings: null
                 }, engine), defines);
             }
-            if (!subMesh.effect.isReady()) {
+            if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
             }
             this._renderId = scene.getRenderId();
@@ -157,6 +160,9 @@ var BABYLON;
                 return;
             }
             var effect = subMesh.effect;
+            if (!effect) {
+                return;
+            }
             this._activeEffect = effect;
             // Matrices
             this.bindOnlyWorldMatrix(world);
@@ -181,7 +187,7 @@ var BABYLON;
                 if (this.pointsCloud) {
                     this._activeEffect.setFloat("pointSize", this.pointSize);
                 }
-                this._activeEffect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
+                BABYLON.MaterialHelper.BindEyePosition(effect, scene);
             }
             this._activeEffect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
             // View
@@ -312,7 +318,7 @@ var BABYLON;
             BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
         ], FireMaterial.prototype, "opacityTexture", void 0);
         __decorate([
-            BABYLON.serialize("diffuseColor")
+            BABYLON.serializeAsColor3("diffuse")
         ], FireMaterial.prototype, "diffuseColor", void 0);
         __decorate([
             BABYLON.serialize()

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.min.js


+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.d.ts

@@ -27,7 +27,7 @@ declare module BABYLON {
         furTime: number;
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
-        getAlphaTestTexture(): BaseTexture;
+        getAlphaTestTexture(): Nullable<BaseTexture>;
         updateFur(): void;
         isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void;

+ 0 - 0
dist/preview release/materialsLibrary/babylon.furMaterial.js


部分文件因文件數量過多而無法顯示