瀏覽代碼

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 8 年之前
父節點
當前提交
7366ffa081
共有 59 個文件被更改,包括 7311 次插入5836 次删除
  1. 12 0
      .vscode/launch.json
  2. 1 0
      .vscode/settings.json
  3. 3 1
      Playground/debug.html
  4. 3 1
      Playground/index-local.html
  5. 3 2
      Playground/index.html
  6. 44 9
      Playground/index.js
  7. 23 0
      Playground/index2_5.html
  8. 3 1
      Tools/Gulp/config.json
  9. 3 1
      Tools/Gulp/custom.config.json
  10. 1 1
      Tools/Npm/package.json
  11. 24 24
      dist/preview release/babylon.core.js
  12. 2861 2797
      dist/preview release/babylon.d.ts
  13. 39 39
      dist/preview release/babylon.js
  14. 335 53
      dist/preview release/babylon.max.js
  15. 2861 2797
      dist/preview release/babylon.module.d.ts
  16. 33 33
      dist/preview release/babylon.noworker.js
  17. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  18. 2 2
      dist/preview release/inspector/babylon.inspector.css
  19. 1 1
      dist/preview release/inspector/babylon.inspector.js
  20. 1 1
      dist/preview release/inspector/babylon.inspector.min.js
  21. 1 0
      dist/preview release/what's new.md
  22. 1 1
      inspector/sass/defines.scss
  23. 1 1
      inspector/src/Inspector.ts
  24. 113 1
      localDev/src/index.js
  25. 二進制
      sandbox/Assets/BtnDragdrop.png
  26. 二進制
      sandbox/Assets/BtnFullscreen.png
  27. 二進制
      sandbox/Assets/BtnPerf.png
  28. 二進制
      sandbox/Assets/FlecheDown.png
  29. 二進制
      sandbox/Assets/FlecheTuto.png
  30. 二進制
      sandbox/Assets/Interface-Sandbox.jpg
  31. 二進制
      sandbox/Assets/LogoSandbox.png
  32. 二進制
      sandbox/Assets/WideLogo.png
  33. 二進制
      sandbox/Assets/arrow.png
  34. 二進制
      sandbox/Assets/down.png
  35. 二進制
      sandbox/Assets/sep.png
  36. 二進制
      sandbox/Assets/up.png
  37. 二進制
      sandbox/Assets/video.png
  38. 56 0
      sandbox/index-local.html
  39. 264 0
      sandbox/index.css
  40. 49 0
      sandbox/index.html
  41. 115 0
      sandbox/index.js
  42. 36 31
      src/Bones/babylon.bone.ts
  43. 2 1
      src/Debug/babylon.debugLayer.ts
  44. 1 1
      src/Materials/babylon.effect.ts
  45. 52 2
      src/Materials/babylon.materialHelper.ts
  46. 18 1
      src/Materials/babylon.pbrMaterial.ts
  47. 11 2
      src/Materials/babylon.standardMaterial.ts
  48. 7 0
      src/Mesh/babylon.geometry.ts
  49. 56 0
      src/Mesh/babylon.mesh.ts
  50. 85 0
      src/Morph/babylon.morphTarget.ts
  51. 122 0
      src/Morph/babylon.morphTargetManager.ts
  52. 7 0
      src/Shaders/ShadersInclude/morphTargetsVertex.fx
  53. 7 0
      src/Shaders/ShadersInclude/morphTargetsVertexDeclaration.fx
  54. 3 0
      src/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration.fx
  55. 15 5
      src/Shaders/default.vertex.fx
  56. 15 5
      src/Shaders/pbr.vertex.fx
  57. 5 12
      src/Tools/babylon.filesInput.ts
  58. 3 3
      src/Tools/babylon.tools.ts
  59. 9 3
      src/babylon.scene.ts

+ 12 - 0
.vscode/launch.json

@@ -2,6 +2,18 @@
     "version": "0.1.0",
     "configurations": [
         {
+            "name": "Launch sandbox (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/sandbox/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis" 
+            ]
+        },         
+        {
             "name": "Launch playground (Chrome)",
             "type": "chrome",
             "request": "launch",

+ 1 - 0
.vscode/settings.json

@@ -9,6 +9,7 @@
         "**/.vs": true,        
         "**/.tempChromeProfileForDebug": true,
         "**/node_modules": true,
+        "**/dist": true,
         "**/temp": true,
         "**/.temp": true,
         "**/*.d.ts": true,

+ 3 - 1
Playground/debug.html

@@ -82,6 +82,7 @@
                 <label class="btn btn-sm active">
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
                 </label>
+                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
                 <button class="btn btn-sm" id="editorButton">-Editor</button>
                 <button class="btn btn-sm" id="debugButton">+Debug layer</button>
             </div>
@@ -124,6 +125,7 @@
                 <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
                 <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
                 <li><a href="https://doc.babylonjs.com">Documentation</a></li>
+                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
             </ul>
         </div>
     </div>
@@ -139,7 +141,7 @@
             <label for="saveFormTags">TAGS (separated by comma)</label>
             <div class="separator"></div>
             <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-            <div class="save-form-buttons">
+            <div class="save-form-buttons" id="saveFormButtons">
                 <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
                 <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
             </div>

+ 3 - 1
Playground/index-local.html

@@ -51,6 +51,7 @@
                 <label class="btn btn-sm active">
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
                 </label>
+                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
                 <button class="btn btn-sm" id="editorButton">-Editor</button>
                 <button class="btn btn-sm" id="debugButton">+Debug layer</button>
             </div>
@@ -93,6 +94,7 @@
                 <li><a href="http://www.babylonjs.com/sandbox">Sandbox</a></li>
                 <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
                 <li><a href="https://doc.babylonjs.com">Documentation</a></li>
+                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
             </ul>
         </div>
     </div>
@@ -108,7 +110,7 @@
             <label for="saveFormTags">TAGS (separated by comma)</label>
             <div class="separator"></div>
             <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-            <div class="save-form-buttons">
+            <div class="save-form-buttons" id="saveFormButtons">
                 <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
                 <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
             </div>

+ 3 - 2
Playground/index.html

@@ -3,7 +3,6 @@
 <head>
     <title>Babylon.js Playground</title>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
     <!--x-tag-->
     <script src="xtag.min.js"></script>
@@ -93,6 +92,7 @@
                 <label class="btn btn-sm active">
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
                 </label>
+                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
                 <button class="btn btn-sm" id="editorButton">-Editor</button>
                 <button class="btn btn-sm" id="debugButton">+Debug layer</button>
             </div>
@@ -135,6 +135,7 @@
                 <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
                 <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
                 <li><a href="https://doc.babylonjs.com">Documentation</a></li>
+                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
             </ul>
         </div>
     </div>
@@ -150,7 +151,7 @@
             <label for="saveFormTags">TAGS (separated by comma)</label>
             <div class="separator"></div>
             <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-            <div class="save-form-buttons">
+            <div class="save-form-buttons" id="saveFormButtons">
                 <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
                 <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
             </div>

文件差異過大導致無法顯示
+ 44 - 9
Playground/index.js


+ 23 - 0
Playground/index2_5.html

@@ -90,6 +90,7 @@
                 <label class="btn btn-sm active">
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
                 </label>
+                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
                 <button class="btn btn-sm" id="editorButton">-Editor</button>
                 <button class="btn btn-sm" id="debugButton">+Debug layer</button>
             </div>
@@ -103,6 +104,9 @@
                 </a>
                 <ul class="dropdown-menu" id="scriptsList"></ul>
             </div>
+            <div class="save-message" id="saveMessage">
+                Be the first to fill this playground metadata!
+            </div>
         </div>
     </div>
 
@@ -129,10 +133,29 @@
                 <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
                 <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
                 <li><a href="https://doc.babylonjs.com">Documentation</a></li>
+                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
             </ul>
         </div>
     </div>
 
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+            <div class="save-form-buttons" id="saveFormButtons">
+                <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
+                <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
+            </div>
+        </div>
+    </div>
+
     <script src="https://code.jquery.com/jquery.js"></script>
     <script src="bootstrap/js/bootstrap.min.js"></script>
     <script src="index.js"></script>

+ 3 - 1
Tools/Gulp/config.json

@@ -228,7 +228,9 @@
             "../../src/Materials/babylon.colorCurves.js",
             "../../src/Materials/babylon.pbrMaterial.js",
             "../../src/Debug/babylon.debugLayer.js",
-            "../../src/PostProcess/babylon.standardRenderingPipeline.js"
+            "../../src/PostProcess/babylon.standardRenderingPipeline.js",
+            "../../src/Morph/babylon.morphTarget.js",
+            "../../src/Morph/babylon.morphTargetManager.js"
         ]
     },
     "modules": [

+ 3 - 1
Tools/Gulp/custom.config.json

@@ -197,7 +197,9 @@
             "../../src/Materials/babylon.colorCurves.js",
             "../../src/Materials/babylon.pbrMaterial.js",
             "../../src/Debug/babylon.debugLayer.js",
-            "../../src/PostProcess/babylon.standardRenderingPipeline.js"
+            "../../src/PostProcess/babylon.standardRenderingPipeline.js",
+            "../../src/Morph/babylon.morphTarget.js",
+            "../../src/Morph/babylon.morphTargetManager.js"
     ]
   }
 }

+ 1 - 1
Tools/Npm/package.json

@@ -12,7 +12,7 @@
     "type": "git",
     "url": "https://github.com/BabylonJS/Babylon.js.git"
   },
-  "main": "babylon.js",
+  "main": "babylon.max.js",
   "files": [
     "babylon.d.ts",
     "babylon.module.d.ts",

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


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


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


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


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


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


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


+ 2 - 2
dist/preview release/inspector/babylon.inspector.css

@@ -1,8 +1,8 @@
 @import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);
-@import url(http://fonts.googleapis.com/css?family=Inconsolata);
+@import url(https://fonts.googleapis.com/css?family=Inconsolata);
 
 @import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);
-@import url(http://fonts.googleapis.com/css?family=Inconsolata);
+@import url(https://fonts.googleapis.com/css?family=Inconsolata);
 .insp-wrapper {
   user-select: none;
   display: flex;

+ 1 - 1
dist/preview release/inspector/babylon.inspector.js

@@ -20,7 +20,7 @@ var INSPECTOR;
             Inspector.WINDOW = window;
             // Load the Canvas2D library if it's not already done
             if (!BABYLON.Canvas2D) {
-                BABYLON.Tools.LoadScript("http://www.babylonjs.com/babylon.canvas2d.js", function () { });
+                BABYLON.Tools.LoadScript("https://www.babylonjs.com/babylon.canvas2d.js", function () { });
             }
             // POPUP MODE
             if (popup) {

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


+ 1 - 0
dist/preview release/what's new.md

@@ -5,6 +5,7 @@
 ### Major updates
  - WebGL2 context support. WebGL2 is now used instead of WebGL 1 when available. [More info here](http://doc.babylonjs.com/overviews/webgl2) ([deltakosh](https://github.com/deltakosh))
  - Complete WebVR 1.1 support including controllers for HTC Vive and Occulus. [More info here](http://doc.babylonjs.com/overviews/webvr_camera) ([raanan](https://github.com/raananw))
+ - Support for Morph Targets. [More info here](http://doc.babylonjs.com/tutorials/how_to_use_morphtargets) ([deltakosh](https://github.com/deltakosh))
  - Added support for Exponential Shadow maps to replace Variance Shadow maps. [more info here](http://www.babylonjs-playground.com/debug.html#1CXNXC#3) - [Demo](http://www.babylonjs.com/Demos/AdvancedShadows/) - [Demo](http://www.babylonjs-playground.com/#1CXNXC#4) ([deltakosh](https://github.com/deltakosh))
  - Support for [Vertex Array Objects](https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt) ([deltakosh](https://github.com/deltakosh))
  - Support for multisample render targets. [Demo](http://www.babylonjs-playground.com/#12MKMN) ([deltakosh](https://github.com/deltakosh))

+ 1 - 1
inspector/sass/defines.scss

@@ -1,5 +1,5 @@
 @import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);
-@import url(http://fonts.googleapis.com/css?family=Inconsolata);
+@import url(https://fonts.googleapis.com/css?family=Inconsolata);
 
 $font               : 'Inconsolata', sans-serif;
 

+ 1 - 1
inspector/src/Inspector.ts

@@ -55,7 +55,7 @@ module INSPECTOR {
 
             // Load the Canvas2D library if it's not already done
             if (!BABYLON.Canvas2D) {
-                BABYLON.Tools.LoadScript("http://www.babylonjs.com/babylon.canvas2d.js", () => { });
+                BABYLON.Tools.LoadScript("https://www.babylonjs.com/babylon.canvas2d.js", () => { });
             }
 
             // POPUP MODE

+ 113 - 1
localDev/src/index.js

@@ -1,5 +1,117 @@
 /// <reference path="../../dist/preview release/babylon.d.ts"/>
 
+var scramble = function(data) {
+    for (index = 0; index < data.length; index ++) {
+        data[index] += 0.1 * Math.random();
+    }
+}
+
 // Playground like creation of the scene
 var createScene = function () {
-}
+
+    // This creates a basic Babylon Scene object (non-mesh)
+    var scene = new BABYLON.Scene(engine);
+
+    // This creates and positions a free camera (non-mesh)
+    var camera = new BABYLON.ArcRotateCamera("camera1", 1.14, 1.13, 10, BABYLON.Vector3.Zero(), scene);
+
+    // This targets the camera to scene origin
+    camera.setTarget(BABYLON.Vector3.Zero());
+
+    // This attaches the camera to the canvas
+    camera.attachControl(canvas, true);
+
+    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
+    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
+
+    // Default intensity is 1. Let's dim the light a small amount
+    light.intensity = 0.7;
+
+    // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
+    var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
+
+    var sphere2 = BABYLON.Mesh.CreateSphere("sphere2", 16, 2, scene);
+    sphere2.setEnabled(false);
+    sphere2.updateMeshPositions(scramble);
+
+    var sphere3 = BABYLON.Mesh.CreateSphere("sphere3", 16, 2, scene);
+    sphere3.setEnabled(false);
+
+    sphere3.scaling = new BABYLON.Vector3(2.1, 3.5, 1.0);
+    sphere3.bakeCurrentTransformIntoVertices();
+
+    var sphere4 = BABYLON.Mesh.CreateSphere("sphere4", 16, 2, scene);
+    sphere4.setEnabled(false);
+    sphere4.updateMeshPositions(scramble);
+
+    var sphere5 = BABYLON.Mesh.CreateSphere("sphere5", 16, 2, scene);
+    sphere5.setEnabled(false);
+
+    sphere5.scaling = new BABYLON.Vector3(1.0, 0.1, 1.0);
+    sphere5.bakeCurrentTransformIntoVertices();    
+
+    var manager = new BABYLON.MorphTargetManager();
+    sphere.morphTargetManager = manager;
+
+    var target0 = BABYLON.MorphTarget.FromMesh(sphere2, "sphere2", 0.25);
+    manager.addTarget(target0);
+
+    var target1 = BABYLON.MorphTarget.FromMesh(sphere3, "sphere3", 0.25);
+    manager.addTarget(target1);
+
+    var target2 = BABYLON.MorphTarget.FromMesh(sphere4, "sphere4", 0.25);
+    manager.addTarget(target2);   
+
+    var target3 = BABYLON.MorphTarget.FromMesh(sphere5, "sphere5", 0.25);
+    manager.addTarget(target3);       
+
+    var gui = new dat.GUI();
+    var options = {
+	    influence0: 0.25,
+        influence1: 0.25,
+        influence2: 0.25,
+        influence3: 0.25,
+    }
+
+    gui.add(options, "influence0", 0, 1).onChange(function(value) {
+		target0.influence = value;
+    });
+
+    gui.add(options, "influence1", 0, 1).onChange(function(value) {
+		target1.influence = value;
+    });
+
+    gui.add(options, "influence2", 0, 1).onChange(function(value) {
+		target2.influence = value;
+    });  
+
+    gui.add(options, "influence3", 0, 1).onChange(function(value) {
+		target3.influence = value;
+    });        
+
+    var button = { switch:function(){
+         if (sphere.morphTargetManager) {
+             sphere.morphTargetManager = null;
+         } else {
+             sphere.morphTargetManager = manager;
+         }
+    }};
+
+    gui.add(button,'switch');
+
+    var disposeButton = { dispose:function(){
+         sphere.dispose();
+    }};
+
+    gui.add(disposeButton,'dispose');
+
+    var removeButton = { removeLast:function(){
+         manager.removeTarget(target3);   
+    }};
+
+    gui.add(removeButton,'removeLast');
+
+
+    return scene;
+
+};

二進制
sandbox/Assets/BtnDragdrop.png


二進制
sandbox/Assets/BtnFullscreen.png


二進制
sandbox/Assets/BtnPerf.png


二進制
sandbox/Assets/FlecheDown.png


二進制
sandbox/Assets/FlecheTuto.png


二進制
sandbox/Assets/Interface-Sandbox.jpg


二進制
sandbox/Assets/LogoSandbox.png


二進制
sandbox/Assets/WideLogo.png


二進制
sandbox/Assets/arrow.png


二進制
sandbox/Assets/down.png


二進制
sandbox/Assets/sep.png


二進制
sandbox/Assets/up.png


二進制
sandbox/Assets/video.png


+ 56 - 0
sandbox/index-local.html

@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BabylonJS - Sandbox</title>
+    <link href="index.css" rel="stylesheet" />
+    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
+	<script src="../Tools/DevLoader/BabylonLoader.js"></script>
+</head>
+<body>
+    <canvas id="renderCanvas"></canvas>
+    <div id="logo">
+    </div>
+    <div id="help01" class="help">
+        <span class="helpText">Press this button to open your assets' files</span>
+        <img id="helpArrow" src="./Assets/FlecheTuto.png" />
+    </div>
+    <div id="help02" class="help2">
+        <span class="helpText">Or directly drag'n'drop your files in the browser</span>
+    </div>
+    <div id="perf" class="perffooter">
+        <div class="footerLeft">
+            <div id="miscCounters"></div>
+        </div>
+        <div class="footerRight">
+            <div id="fps"></div>
+            <img id="btnDownArrow" src="./Assets/FlecheDown.png" />
+        </div>
+    </div>
+    <div class="footer">
+        <div class="footerLeft">
+            Powered by <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a><br />
+        </div>
+        <div class="footerRight">
+            <ul>
+                <li id="btnFullscreen">
+                    <img src="./Assets/BtnFullscreen.png" alt="Switch the scene to full screen" title="Switch the scene to full screen" />
+                </li>
+                <li id="btnPerf">
+                    <img src="./Assets/BtnPerf.png" alt="Display inspector" title="Display inspector" />
+                </li>
+                <li id="btnFiles">
+                    <div class="custom-upload" title="Open your .babylon scene from your hard drive">
+                        <input type="file" id="files" multiple />
+                    </div>
+                </li>
+            </ul>
+        </div>
+    </div>
+    <div id="loadingText" class="loadingText"></div>
+    <script>
+        BABYLONDEVTOOLS.Loader.require('index.js')
+            .load();
+    </script>	
+</body>
+</html>

+ 264 - 0
sandbox/index.css

@@ -0,0 +1,264 @@
+html, body {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+    overflow: hidden;
+    font-family: "Segoe WP", "Segoe UI", "Verdana", "Arial";
+}
+
+#DebugLayerLogs {
+    height: 100px !important;   
+}
+
+    #DebugLayerLogs > div:first-child {
+        background-color: #988DB5 !important;
+    }
+
+#DebugLayerStats {
+    margin-top: 2px !important;
+}
+
+#DebugLayerStats div:nth-child(2) {
+    max-height: 180px !important;
+}
+
+    #DebugLayerStats > div:first-child {
+        background-color: #988DB5 !important;
+    }
+
+#DebugLayerOptions {
+    overflow-y: hidden !important;
+}
+
+#DebugLayerOptions > div:first-child {
+    background-color: #988DB5 !important;
+}
+
+#DebugLayerTree > div:first-child {
+    background-color: #988DB5 !important;
+}
+
+a {
+    color: white;
+}
+
+    a:visited {
+        color: white;
+    }
+
+.hidden {
+    display: none;
+}
+
+#renderCanvas {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    margin-bottom: 70px;
+    touch-action: none;
+    -ms-touch-action: none;
+}
+
+.help {
+    position: absolute;
+    background-color: #988DB5;
+    right: 0;
+    bottom: 70px;
+    color: white;
+    padding-right: 10px;
+    width: 360px;
+    height: 30px;
+    transition: all 0.5s ease;
+    -webkit-transition: all 0.5s ease;
+    transform: translateX(400px);
+    -webkit-transform: translateX(400px);
+        text-align: center;
+}
+
+    .help.shown {
+        transform: translateX(-100px);
+        -webkit-transform: translateX(-100px);
+    }
+
+ .help2 {
+    position: absolute;
+    background-color: #988DB5;
+    right: 0;
+    bottom: 70px;
+    color: white;
+    padding-right: 10px;
+    width: 360px;
+    height: 30px;
+    transition: all 0.5s ease;
+    -webkit-transition: all 0.5s ease;
+    transform: translateX(400px);
+    -webkit-transform: translateX(400px);
+        text-align: center;
+}
+
+    .help2.shown {
+        transform: translateX(0px);
+        -webkit-transform: translateX(0px);
+    }
+
+#helpArrow {
+    position: absolute;
+    right: -65px;
+    bottom: 10px;
+}
+
+#fps {
+    position: absolute;
+    font-size: 30px;
+    color: white;
+    bottom: 15px;
+    right: 85px;
+    width: 85px;
+}
+
+.footer {
+    position: absolute;
+    width: 100%;
+    height: 60px;
+    bottom: 0;
+    background-color: #59448F;
+    padding-top: 5px;
+    padding-left: 15px;
+}
+
+.perffooter {
+    position: absolute;
+    width: 100%;
+    height: 60px;
+    bottom: 0px;
+    background-color: #988DB5;
+    padding-top: 5px;
+    padding-left: 15px;
+        transition: all 0.5s ease;
+    -webkit-transition: all 0.5s ease;
+}
+
+    .perffooter.shown {
+        transform: translateY(-65px);
+        -webkit-transform: translateY(-65px);
+    }
+
+.footerRight {
+    display: inline;
+    position: absolute;
+    bottom: 0;
+    right: 10px;
+}
+
+.footerLeft {
+    position: absolute;
+    bottom: 20px;
+    left: 15px;
+    color: white;
+}
+
+.custom-upload {
+    position: relative;
+    background:url(./Assets/BtnDragdrop.png) center right no-repeat;
+    height: 56px;
+    width: 56px;
+    margin: 10px 20px 5px 5px;
+}
+
+.custom-upload input[type=file]
+{
+    outline:none;
+    position: relative;
+    text-align: right;    
+    -moz-opacity:0 ;
+    filter:alpha(opacity: 0);
+    opacity: 0;
+    z-index: 2;
+    width:100%;
+    height:100%;
+    
+}
+
+#logo {
+    width: 100%;
+    height: 100%;
+    background: url('./Assets/LogoSandbox.png') no-repeat 0 0;
+    background-position: center;
+}
+
+#btnFullscreen {
+}
+
+#btnFullscreen {
+    margin-top: 10px;
+    margin-right: 25px;
+}
+
+#btnPerf {
+    margin-top: 10px;
+    margin-right: 15px;
+}
+
+ul {
+ padding:0;
+ margin:0;
+ list-style-type:none;
+ }
+
+li {
+ float:left;
+ }
+
+#btnDownArrow {
+    position: absolute;
+    bottom: 35px;
+    right: 30px;
+}
+
+#miscCounters {
+    position: relative;
+    top: 18px;
+    height: 60px;
+    -webkit-column-width: 150px;
+    -moz-column-width: 150px;
+    -ms-column-width: 150px;
+    -o-column-width: 150px;
+    column-width: 150px;
+
+    font-size: 14px;
+}
+
+#loadingText {
+    width: 100%;
+    height: 60px;
+    position: absolute;
+    top: 50%;
+    left: 0;
+    margin-top: -30px;
+    color: white;
+    text-align: center;
+    padding-top: 10px;
+    font-size: 30px;
+    transition: transform 0.25s ease-in-out;
+    -webkit-transition: -webkit-transform 0.25s ease-in-out;
+    z-index: 3;
+    cursor: default;
+    background-color: #988DB5;
+}
+
+.loadingText {
+    transform: translateX(120%);
+    -webkit-transform: translateX(120%);
+}
+
+#btnFullscreen, #btnPerf, #btnFiles {
+     -webkit-transition: -webkit-transform 0.15s ease-in-out;
+     transition: transform 0.15s ease-in-out;
+}
+
+#btnFullscreen:hover, #btnPerf:hover, #btnFiles:hover {
+    -webkit-transform: scale(0.9);
+    transform: scale(0.9);
+}

+ 49 - 0
sandbox/index.html

@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BabylonJS - Sandbox</title>
+    <link href="index.css" rel="stylesheet" />
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/babylon.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>    
+</head>
+<body>
+    <canvas id="renderCanvas"></canvas>
+    <div id="logo">
+    </div>
+    <div id="help01" class="help">
+        <span class="helpText">Press this button to open your assets' files</span>
+        <img id="helpArrow" src="./Assets/FlecheTuto.png" />
+    </div>
+    <div id="help02" class="help2">
+        <span class="helpText">Or directly drag'n'drop your files in the browser</span>
+    </div>
+    <div class="footer">
+        <div class="footerLeft">
+            Powered by <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a><br />
+        </div>
+        <div class="footerRight">
+            <ul>
+                <li id="btnFullscreen">
+                    <img src="./Assets/BtnFullscreen.png" alt="Switch the scene to full screen" title="Switch the scene to full screen" />
+                </li>
+                <li id="btnPerf">
+                    <img src="./Assets/BtnPerf.png" alt="Display debug & performance layer" title="Display debug & performance layer" />
+                </li>
+                <li id="btnFiles">
+                    <div class="custom-upload" title="Open your .babylon scene from your hard drive">
+                        <input type="file" id="files" multiple />
+                    </div>
+                </li>
+            </ul>
+        </div>
+    </div>
+    <div id="loadingText" class="loadingText"></div>
+    <script src="index.js"></script>
+</body>
+</html>

+ 115 - 0
sandbox/index.js

@@ -0,0 +1,115 @@
+/// <reference path="../../babylon.js" />
+
+if (BABYLON.Engine.isSupported()) {
+    var canvas = document.getElementById("renderCanvas");
+    var engine = new BABYLON.Engine(canvas, true);
+    var divFps = document.getElementById("fps");
+    var htmlInput = document.getElementById("files");
+    var btnFullScreen = document.getElementById("btnFullscreen");
+    var btnDownArrow = document.getElementById("btnDownArrow");
+    var perffooter = document.getElementById("perf");
+    var btnPerf = document.getElementById("btnPerf");
+    var miscCounters = document.getElementById("miscCounters");
+    var help01 = document.getElementById("help01");
+    var help02 = document.getElementById("help02");
+    var loadingText = document.getElementById("loadingText");
+    var filesInput;
+    var currentHelpCounter;
+    var currentScene;
+    var enableDebugLayer = false;
+
+    currentHelpCounter = localStorage.getItem("helpcounter");
+
+    BABYLON.Engine.ShadersRepository = "/src/Shaders/";
+
+    if (!currentHelpCounter) currentHelpCounter = 0;
+
+    // Resize
+    window.addEventListener("resize", function () {
+        engine.resize();
+    });
+
+    var sceneLoaded = function (sceneFile, babylonScene) {
+        function displayDebugLayerAndLogs() {
+            currentScene.debugLayer._displayLogs = true;
+            enableDebugLayer = true;
+            currentScene.debugLayer.show();
+        };
+        function hideDebugLayerAndLogs() {
+            currentScene.debugLayer._displayLogs = false;
+            enableDebugLayer = false;
+            currentScene.debugLayer.hide();
+        };
+        if (enableDebugLayer) {
+            hideDebugLayerAndLogs();
+        }
+        currentScene = babylonScene;
+        document.title = "BabylonJS - " + sceneFile.name;
+        // Fix for IE, otherwise it will change the default filter for files selection after first use
+        htmlInput.value = "";
+        // In case of error during loading, meshes will be empty and clearColor is set to red
+        if (currentScene.meshes.length === 0 && currentScene.clearColor.r === 1 && currentScene.clearColor.g === 0 && currentScene.clearColor.b === 0) {
+            document.getElementById("logo").className = "";
+            canvas.style.opacity = 0;
+            displayDebugLayerAndLogs();
+        }
+        else {
+            if (BABYLON.Tools.errorsCount > 0) {
+                displayDebugLayerAndLogs();
+            }
+            document.getElementById("logo").className = "hidden";
+            canvas.style.opacity = 1;
+            if (currentScene.activeCamera.keysUp) {
+                currentScene.activeCamera.keysUp.push(90); // Z
+                currentScene.activeCamera.keysUp.push(87); // W
+                currentScene.activeCamera.keysDown.push(83); // S
+                currentScene.activeCamera.keysLeft.push(65); // A
+                currentScene.activeCamera.keysLeft.push(81); // Q
+                currentScene.activeCamera.keysRight.push(69); // E
+                currentScene.activeCamera.keysRight.push(68); // D
+            }
+        }
+    };
+
+    filesInput = new BABYLON.FilesInput(engine, null, canvas, sceneLoaded);
+    filesInput.monitorElementForDragNDrop(canvas);
+
+    window.addEventListener("keydown", function (evt) {
+        // Press R to reload
+        if (evt.keyCode === 82) {
+            filesInput.reload();
+        }
+    });
+    htmlInput.addEventListener('change', function (event) {
+        filesInput.loadFiles(event);
+    }, false);
+    btnFullScreen.addEventListener('click', function () {
+        engine.switchFullscreen(true);
+    }, false);
+    btnPerf.addEventListener('click', function () {
+        if (currentScene) {
+            if (!enableDebugLayer) {
+                currentScene.debugLayer.show();
+                enableDebugLayer = true;
+
+            } else {
+                currentScene.debugLayer.hide();
+                enableDebugLayer = false;
+            }
+        }
+    }, false);
+
+    // The help tips will be displayed only 5 times
+    if (currentHelpCounter < 5) {
+        help01.className = "help shown";
+
+        setTimeout(function () {
+            help01.className = "help";
+            help02.className = "help2 shown";
+            setTimeout(function () {
+                help02.className = "help2";
+                localStorage.setItem("helpcounter", currentHelpCounter + 1);
+            }, 5000);
+        }, 5000);
+    }
+}

+ 36 - 31
src/Bones/babylon.bone.ts

@@ -2,6 +2,11 @@
 
 module BABYLON {
     export class Bone extends Node {
+
+        private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero()];
+        private static _tmpQuat = Quaternion.Identity();
+        private static _tmpMats: Matrix[] = [Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity()];
+
         public children = new Array<Bone>();
         public animations = new Array<Animation>();
         public length: number;
@@ -211,8 +216,8 @@ module BABYLON {
                 }
 
                 this._skeleton.computeAbsoluteTransforms();
-                var tmat = Tmp.Matrix[0];
-                var tvec = Tmp.Vector3[0];
+                var tmat = Bone._tmpMats[0];
+                var tvec = Bone._tmpVecs[0];
 
                 if (mesh) {
                     tmat.copyFrom(this._parent.getAbsoluteTransform());
@@ -265,8 +270,8 @@ module BABYLON {
 
                 this._skeleton.computeAbsoluteTransforms();
 
-                var tmat = Tmp.Matrix[0];
-                var vec = Tmp.Vector3[0];
+                var tmat = Bone._tmpMats[0];
+                var vec = Bone._tmpVecs[0];
 
                 if (mesh) {
                     tmat.copyFrom(this._parent.getAbsoluteTransform());
@@ -331,14 +336,14 @@ module BABYLON {
         public scale (x: number, y: number, z: number, scaleChildren = false): void {
 	
             var locMat = this.getLocalMatrix();
-            var origLocMat = Tmp.Matrix[0];
+            var origLocMat = Bone._tmpMats[0];
             origLocMat.copyFrom(locMat);
 
-            var origLocMatInv = Tmp.Matrix[1];
+            var origLocMatInv = Bone._tmpMats[1];
             origLocMatInv.copyFrom(origLocMat);
             origLocMatInv.invert();
 
-            var scaleMat = Tmp.Matrix[2];
+            var scaleMat = Bone._tmpMats[2];
             Matrix.FromValuesToRef(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1, scaleMat);
             this._scaleMatrix.multiplyToRef(scaleMat, this._scaleMatrix);
             this._scaleVector.x *= x;
@@ -393,10 +398,10 @@ module BABYLON {
          */
         public setYawPitchRoll (yaw: number, pitch: number, roll: number, space = Space.LOCAL, mesh?: AbstractMesh): void {
 	
-            var rotMat = Tmp.Matrix[0];
+            var rotMat = Bone._tmpMats[0];
             Matrix.RotationYawPitchRollToRef(yaw, pitch, roll, rotMat);
             
-            var rotMatInv = Tmp.Matrix[1];
+            var rotMatInv = Bone._tmpMats[1];
             
             this._getNegativeRotationToRef(rotMatInv, space, mesh);
 	
@@ -415,7 +420,7 @@ module BABYLON {
          */
         public rotate (axis: Vector3, amount: number, space = Space.LOCAL, mesh?: AbstractMesh): void {
             
-            var rmat = Tmp.Matrix[0];
+            var rmat = Bone._tmpMats[0];
             rmat.m[12] = 0;
             rmat.m[13] = 0;
             rmat.m[14] = 0;
@@ -435,9 +440,9 @@ module BABYLON {
          */
         public setAxisAngle (axis: Vector3, angle: number, space = Space.LOCAL, mesh?: AbstractMesh): void {
 
-            var rotMat = Tmp.Matrix[0];
+            var rotMat = Bone._tmpMats[0];
             Matrix.RotationAxisToRef(axis, angle, rotMat);
-            var rotMatInv = Tmp.Matrix[1];
+            var rotMatInv = Bone._tmpMats[1];
             
             this._getNegativeRotationToRef(rotMatInv, space, mesh);
             
@@ -466,11 +471,11 @@ module BABYLON {
          */
         public setRotationQuaternion (quat: Quaternion, space = Space.LOCAL, mesh?: AbstractMesh): void {
 
-            var rotMatInv = Tmp.Matrix[0];
+            var rotMatInv = Bone._tmpMats[0];
 
             this._getNegativeRotationToRef(rotMatInv, space, mesh);
 
-            var rotMat = Tmp.Matrix[1];
+            var rotMat = Bone._tmpMats[1];
             Matrix.FromQuaternionToRef(quat, rotMat);
 
             rotMatInv.multiplyToRef(rotMat, rotMat);
@@ -487,11 +492,11 @@ module BABYLON {
          */
         public setRotationMatrix (rotMat: Matrix, space = Space.LOCAL, mesh?: AbstractMesh): void {
 
-            var rotMatInv = Tmp.Matrix[0];
+            var rotMatInv = Bone._tmpMats[0];
             
             this._getNegativeRotationToRef(rotMatInv, space, mesh);
 
-            var rotMat2 = Tmp.Matrix[1];
+            var rotMat2 = Bone._tmpMats[1];
             rotMat2.copyFrom(rotMat);
 
             rotMatInv.multiplyToRef(rotMat, rotMat2);
@@ -507,8 +512,8 @@ module BABYLON {
             var ly = lmat.m[13];
             var lz = lmat.m[14];
             var parent = this.getParent();
-            var parentScale = Tmp.Matrix[3];
-            var parentScaleInv = Tmp.Matrix[4];
+            var parentScale = Bone._tmpMats[3];
+            var parentScaleInv = Bone._tmpMats[4];
 
             if (parent) {
                 if (space == Space.WORLD) {
@@ -552,13 +557,13 @@ module BABYLON {
         private _getNegativeRotationToRef(rotMatInv: Matrix, space = Space.LOCAL, mesh?: AbstractMesh): void {
 
             if (space == Space.WORLD) {
-                var scaleMatrix = Tmp.Matrix[2];
+                var scaleMatrix = Bone._tmpMats[2];
                 scaleMatrix.copyFrom(this._scaleMatrix);
                 rotMatInv.copyFrom(this.getAbsoluteTransform());
                 
                 if (mesh) {
                     rotMatInv.multiplyToRef(mesh.getWorldMatrix(), rotMatInv);
-                    var meshScale = Tmp.Matrix[3];
+                    var meshScale = Bone._tmpMats[3];
                     Matrix.ScalingToRef(mesh.scaling.x, mesh.scaling.y, mesh.scaling.z, meshScale);
                     scaleMatrix.multiplyToRef(meshScale, scaleMatrix);
                 }
@@ -569,11 +574,11 @@ module BABYLON {
             } else {
                 rotMatInv.copyFrom(this.getLocalMatrix());
                 rotMatInv.invert();
-                var scaleMatrix = Tmp.Matrix[2];
+                var scaleMatrix = Bone._tmpMats[2];
                 scaleMatrix.copyFrom(this._scaleMatrix);
 
                 if (this._parent) {
-                    var pscaleMatrix = Tmp.Matrix[3];
+                    var pscaleMatrix = Bone._tmpMats[3];
                     pscaleMatrix.copyFrom(this._parent._scaleMatrix);
                     pscaleMatrix.invert();
                     pscaleMatrix.multiplyToRef(rotMatInv, rotMatInv);
@@ -649,7 +654,7 @@ module BABYLON {
                 
                 this._skeleton.computeAbsoluteTransforms();
                 
-                var tmat = Tmp.Matrix[0];
+                var tmat = Bone._tmpMats[0];
 
                 if (mesh) {
                     tmat.copyFrom(this.getAbsoluteTransform());
@@ -777,7 +782,7 @@ module BABYLON {
 
             this._skeleton.computeAbsoluteTransforms();
             
-            var mat = Tmp.Matrix[0];
+            var mat = Bone._tmpMats[0];
 
             mat.copyFrom(this.getAbsoluteTransform());
 
@@ -815,7 +820,7 @@ module BABYLON {
          */
         public getRotationToRef(space = Space.LOCAL, mesh: AbstractMesh, result: Vector3): void {
 
-            var quat = Tmp.Quaternion[0];
+            var quat = Bone._tmpQuat;
 
             this.getRotationQuaternionToRef(space, mesh, quat);
             
@@ -849,11 +854,11 @@ module BABYLON {
 
             if(space == Space.LOCAL){
 
-                this.getLocalMatrix().decompose(Tmp.Vector3[0], result, Tmp.Vector3[1]);
+                this.getLocalMatrix().decompose(Bone._tmpVecs[0], result, Bone._tmpVecs[1]);
 
             }else{
 
-                var mat = Tmp.Matrix[0];
+                var mat = Bone._tmpMats[0];
                 var amat = this.getAbsoluteTransform();
 
                 if(mesh){
@@ -866,7 +871,7 @@ module BABYLON {
                 mat.m[1] *= this._scalingDeterminant;
                 mat.m[2] *= this._scalingDeterminant;
 
-                mat.decompose(Tmp.Vector3[0], result, Tmp.Vector3[1]);
+                mat.decompose(Bone._tmpVecs[0], result, Bone._tmpVecs[1]);
 
             }
         }
@@ -901,7 +906,7 @@ module BABYLON {
 
             }else{
 
-                var mat = Tmp.Matrix[0];
+                var mat = Bone._tmpMats[0];
                 var amat = this.getAbsoluteTransform();
 
                 if(mesh){
@@ -953,7 +958,7 @@ module BABYLON {
 
             this._skeleton.computeAbsoluteTransforms();
 
-            var tmat = Tmp.Matrix[0];
+            var tmat = Bone._tmpMats[0];
             
             if (mesh) {
                 tmat.copyFrom(this.getAbsoluteTransform());
@@ -999,7 +1004,7 @@ module BABYLON {
 
             this._skeleton.computeAbsoluteTransforms();
 
-            var tmat = Tmp.Matrix[0];
+            var tmat = Bone._tmpMats[0];
 
             tmat.copyFrom(this.getAbsoluteTransform());
             

+ 2 - 1
src/Debug/babylon.debugLayer.ts

@@ -5,7 +5,8 @@ module BABYLON {
 
     export class DebugLayer {
         private _scene: Scene;
-        public static InspectorURL = 'http://www.babylonjs.com/babylon.inspector.bundle.js';
+        // Get protocol used - http or https
+        public static InspectorURL = window.location.href.split('/')[0] + '//www.babylonjs.com/babylon.inspector.bundle.js';
         // The inspector instance
         private _inspector: any;
 

+ 1 - 1
src/Materials/babylon.effect.ts

@@ -363,7 +363,7 @@
                                 maxIndex = this._indexParameters[indexSplits[1]];
                             }
 
-                            for (var i = minIndex; i <= maxIndex; i++) {
+                            for (var i = minIndex; i < maxIndex; i++) {
                                 includeContent += sourceIncludeContent.replace(/\{X\}/g, i) + "\n";
                             }
                         } else {

+ 52 - 2
src/Materials/babylon.materialHelper.ts

@@ -32,13 +32,17 @@
             }
         }
 
-        public static PrepareDefinesForAttributes(mesh: AbstractMesh, defines: MaterialDefines, useVertexColor: boolean, useBones: boolean): void {
+        public static PrepareDefinesForAttributes(mesh: AbstractMesh, defines: MaterialDefines, useVertexColor: boolean, useBones: boolean, useMorphTargets = false): void {
             if (!defines._areAttributesDirty) {
                 return;
-            }
+            }               
 
             defines["NORMAL"] = (defines._needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind));
 
+            if (defines._needNormals && mesh.isVerticesDataPresent(VertexBuffer.TangentKind)) {
+                defines["TANGENT"] = true;
+            }
+
             if (defines._needUVs) {
                 defines["UV1"] = mesh.isVerticesDataPresent(VertexBuffer.UVKind);
                 defines["UV2"] = mesh.isVerticesDataPresent(VertexBuffer.UV2Kind);
@@ -61,6 +65,19 @@
                     defines["BonesPerMesh"] = 0;
                 }           
             }
+
+            if (useMorphTargets) {
+                if ((<any>mesh).morphTargetManager) {
+                    var manager = (<Mesh>mesh).morphTargetManager;
+                    defines["MORPHTARGETS_NORMAL"] = manager.supportsNormals && defines["NORMAL"] ;
+                    defines["MORPHTARGETS"] = (manager.numInfluencers > 0);
+                    defines["NUM_MORPH_INFLUENCERS"] = manager.numInfluencers;
+                } else {
+                    defines["MORPHTARGETS_NORMAL"] = false;
+                    defines["MORPHTARGETS"] = false;
+                    defines["NUM_MORPH_INFLUENCERS"] = 0;
+                }
+            }
         }
 
         public static PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, defines: MaterialDefines, specularSupported: boolean, maxSimultaneousLights = 4, disableLighting = false): boolean {
@@ -188,6 +205,10 @@
 
                 samplersList.push("shadowSampler" + lightIndex);
             }
+
+            if (defines["NUM_MORPH_INFLUENCERS"]) {
+                uniformsList.push("morphTargetInfluences");
+            }
         }
 
         public static HandleFallbacksForShadows(defines: MaterialDefines, fallbacks: EffectFallbacks, maxSimultaneousLights = 4): void {
@@ -218,6 +239,27 @@
             }
         }
 
+        public static PrepareAttributesForMorphTargets(attribs: string[], mesh: AbstractMesh, defines: MaterialDefines): void {
+            var influencers = defines["NUM_MORPH_INFLUENCERS"];
+
+            if (influencers > 0) {
+                var maxAttributesCount = Engine.LastCreatedEngine.getCaps().maxVertexAttribs;
+                var manager = (<Mesh>mesh).morphTargetManager;
+                var normal = manager.supportsNormals && defines["NORMAL"];
+                for (var index = 0; index < influencers; index++) {
+                    attribs.push(VertexBuffer.PositionKind + index);
+
+                    if (normal) {
+                        attribs.push(VertexBuffer.NormalKind + index);
+                    }
+
+                    if (attribs.length > maxAttributesCount) {
+                        Tools.Error("Cannot add more vertex attributes for mesh " + mesh.name);
+                    }
+                }
+            }
+        }
+
         public static PrepareAttributesForBones(attribs: string[], mesh: AbstractMesh, defines: MaterialDefines, fallbacks: EffectFallbacks): void {
             if (defines["NUM_BONE_INFLUENCERS"] > 0) {
                 fallbacks.addCPUSkinningFallback(0, mesh);
@@ -319,6 +361,14 @@
             }
         }
 
+        public static BindMorphTargetParameters(abstractMesh: AbstractMesh, effect: Effect): void {
+            if (!abstractMesh || !(<Mesh>abstractMesh).morphTargetManager) {
+                return;
+            }
+
+            effect.setFloatArray("morphTargetInfluences", (<Mesh>abstractMesh).morphTargetManager.influences);
+        }
+
         public static BindLogDepth(defines: MaterialDefines, effect: Effect, scene: Scene): void {
             if (defines["LOGARITHMICDEPTH"]) {
                 effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log(scene.activeCamera.maxZ + 1.0) / Math.LN2));

+ 18 - 1
src/Materials/babylon.pbrMaterial.ts

@@ -73,6 +73,10 @@
         public METALLICROUGHNESSGSTOREINALPHA = false;
         public METALLICROUGHNESSGSTOREINGREEN = false;
 
+        public MORPHTARGETS = false;
+        public MORPHTARGETS_NORMAL = false;
+        public NUM_MORPH_INFLUENCERS = 0;
+
         constructor() {
             super();
             this.rebuild();
@@ -979,6 +983,13 @@
                 if (useInstances) {
                     this._defines.INSTANCES = true;
                 }
+
+               if ((<any>mesh).morphTargetManager) {
+                    var manager = (<Mesh>mesh).morphTargetManager;
+                    this._defines.MORPHTARGETS_NORMAL = manager.supportsNormals && this._defines.NORMAL;
+                    this._defines.MORPHTARGETS = (manager.numInfluencers > 0);
+                    this._defines.NUM_MORPH_INFLUENCERS = manager.numInfluencers;
+                }
             }
 
             // Get correct effect
@@ -1076,6 +1087,7 @@
 
                 MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
                 MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+                MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, this._defines);
 
                 // Legacy browser patch
                 var join = this._defines.toString();
@@ -1104,7 +1116,7 @@
                 
                 this._effect = scene.getEngine().createEffect("pbr",
                     attribs, uniforms, samplers,
-                    join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: this.maxSimultaneousLights});
+                    join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: this.maxSimultaneousLights, maxSimultaneousMorphTargets: this._defines.NUM_MORPH_INFLUENCERS});
             }
             if (!this._effect.isReady()) {
                 return false;
@@ -1339,6 +1351,11 @@
                 // Fog
                 MaterialHelper.BindFogParameters(this._myScene, mesh, this._effect);
 
+                // Morph targets
+                if (this._defines.NUM_MORPH_INFLUENCERS) {
+                    MaterialHelper.BindMorphTargetParameters(mesh, this._effect);                
+                }
+
                 this._lightingInfos.x = this.directIntensity;
                 this._lightingInfos.y = this.emissiveIntensity;
                 this._lightingInfos.z = this.environmentIntensity;

+ 11 - 2
src/Materials/babylon.standardMaterial.ts

@@ -59,6 +59,9 @@ module BABYLON {
         public SHADOWFULLFLOAT = false;
         public CAMERACOLORGRADING = false;
         public CAMERACOLORCURVES = false;
+        public MORPHTARGETS = false;
+        public MORPHTARGETS_NORMAL = false;
+        public NUM_MORPH_INFLUENCERS = 0;
 
         constructor() {
             super();
@@ -586,7 +589,7 @@ module BABYLON {
             MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
 
             // Attribs
-            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
+            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
 
             // Values that need to be evaluated on every frame
             MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
@@ -687,6 +690,7 @@ module BABYLON {
 
                 MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
                 MaterialHelper.PrepareAttributesForInstances(attribs, defines);
+                MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, defines);
                 
                 var shaderName = "default";
 
@@ -717,7 +721,7 @@ module BABYLON {
 
                 subMesh.setEffect(scene.getEngine().createEffect(shaderName,
                     attribs, uniforms, samplers,
-                    join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this._maxSimultaneousLights - 1 }), defines);
+                    join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }), defines);
             }
 
             if (!subMesh.effect.isReady()) {
@@ -910,6 +914,11 @@ module BABYLON {
                 // Fog
                 MaterialHelper.BindFogParameters(scene, mesh, effect);
 
+                // Morph targets
+                if (defines.NUM_MORPH_INFLUENCERS) {
+                    MaterialHelper.BindMorphTargetParameters(mesh, effect);                
+                }
+
                 // Log. depth
                 MaterialHelper.BindLogDepth(defines, effect, scene);
 

+ 7 - 0
src/Mesh/babylon.geometry.ts

@@ -112,6 +112,13 @@
             this.setVerticesBuffer(buffer);
         }
 
+        public removeVerticesData(kind: string) {
+            if (this._vertexBuffers[kind]) {
+                this._vertexBuffers[kind].dispose();
+                delete this._vertexBuffers[kind];
+            }
+        }
+
         public setVerticesBuffer(buffer: VertexBuffer): void {
             var kind = buffer.getKind();
             if (this._vertexBuffers[kind]) {

+ 56 - 0
src/Mesh/babylon.mesh.ts

@@ -100,6 +100,21 @@
         private _LODLevels = new Array<Internals.MeshLODLevel>();
         public onLODLevelSelection: (distance: number, mesh: Mesh, selectedLevel: Mesh) => void;
 
+        // Morph
+        private _morphTargetManager: MorphTargetManager;
+
+        public get morphTargetManager(): MorphTargetManager {
+            return this._morphTargetManager;
+        }
+
+        public set morphTargetManager(value: MorphTargetManager) {
+            if (this._morphTargetManager === value) {
+                return;
+            }
+            this._morphTargetManager = value;
+            this._syncGeometryWithMorphTargetManager();
+        }
+
         // Private
         public _geometry: Geometry;
         public _delayInfo; //ANY
@@ -1417,6 +1432,8 @@
          * This also frees the memory allocated under the hood to all the buffers used by WebGL.
          */
         public dispose(doNotRecurse?: boolean): void {
+            this.morphTargetManager = undefined;
+
             if (this._geometry) {
                 this._geometry.releaseForMesh(this, true);
             }
@@ -1976,6 +1993,45 @@
                 serializationObject.actions = this.actionManager.serialize(this.name);
             }
         }
+        
+        public _syncGeometryWithMorphTargetManager() {
+            if (!this.geometry) {
+                return;
+            }
+
+            this._markSubMeshesAsAttributesDirty();
+
+            if (this._morphTargetManager && this._morphTargetManager.vertexCount) {
+                if (this._morphTargetManager.vertexCount !== this.getTotalVertices()) {
+                    Tools.Error("Mesh is incompatible with morph targets. Targets and mesh must all have the same vertices count.");
+                    this.morphTargetManager = undefined;
+                    return;
+                }
+
+                for (var index = 0; index < this.morphTargetManager.numInfluencers; index++) {
+                    var morphTarget = this.morphTargetManager.getActiveTarget(index);
+                    this.geometry.setVerticesData(VertexBuffer.PositionKind + index, morphTarget.getPositions(), false, 3);
+
+                    if (morphTarget.hasNormals) {
+                        this.geometry.setVerticesData(VertexBuffer.NormalKind + index, morphTarget.getNormals(), false, 3);
+                    }
+                }
+            } else {
+                var index = 0;
+                
+                // Positions
+                while (this.geometry.isVerticesDataPresent(VertexBuffer.PositionKind + index))
+                {
+                    this.geometry.removeVerticesData(VertexBuffer.PositionKind + index);
+                    
+                    if (this.geometry.isVerticesDataPresent(VertexBuffer.NormalKind + index))
+                    {
+                        this.geometry.removeVerticesData(VertexBuffer.NormalKind + index);
+                    }
+                    index++;
+                }    
+            }
+        }
 
         // Statics
         /**

+ 85 - 0
src/Morph/babylon.morphTarget.ts

@@ -0,0 +1,85 @@
+module BABYLON {
+    export class MorphTarget {
+        private _positions: Float32Array;
+        private _normals: Float32Array;
+        private _influence: number;
+
+        public onInfluenceChanged = new Observable<boolean>();
+
+        public get influence(): number {
+            return this._influence;
+        }
+
+        public set influence(influence: number) {
+            if (this._influence === influence) {
+                return;
+            }
+
+            var previous = this._influence;
+            this._influence = influence;
+
+            if (this.onInfluenceChanged.hasObservers) {
+                this.onInfluenceChanged.notifyObservers(previous === 0 || influence === 0);
+            }
+        }
+
+        public constructor(public name: string, influence = 0) {
+            this.influence = influence;
+        }
+
+        public get hasNormals(): boolean {
+            return this._normals !== undefined;
+        }
+
+        public setPositions(data: Float32Array | number[]) {
+            this._positions = new Float32Array(data);
+        }
+
+        public getPositions(): Float32Array {
+            return this._positions;
+        }
+
+        public setNormals(data: Float32Array | number[]) {
+            this._normals = new Float32Array(data);
+        }
+
+        public getNormals(): Float32Array {
+            return this._normals;
+        }
+
+        /**
+         * Serializes the current target into a Serialization object.  
+         * Returns the serialized object.  
+         */
+        public serialize(): any {
+            var serializationObject:any = {};
+
+            serializationObject.name = this.name;
+            serializationObject.influence = this.influence;
+
+            serializationObject.positions = this.getPositions();
+            if (this.hasNormals) {
+                serializationObject.normals = this.getNormals();
+            }
+
+            return serializationObject;
+        }
+
+        // Statics
+        public static FromMesh(mesh: AbstractMesh, name?: string, influence?: number): MorphTarget {
+            if (!name) {
+                name = mesh.name;
+            }
+
+            var result = new MorphTarget(name, influence);
+
+            result.setPositions(mesh.getVerticesData(VertexBuffer.PositionKind));
+
+            if (mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                result.setNormals(mesh.getVerticesData(VertexBuffer.NormalKind));
+            }
+
+            return result;
+        }
+    }
+}

+ 122 - 0
src/Morph/babylon.morphTargetManager.ts

@@ -0,0 +1,122 @@
+module BABYLON {
+    export class MorphTargetManager {
+        private _targets = new Array<MorphTarget>();
+        private _targetObservable = new Array<Observer<boolean>>();
+        private _activeTargets = new SmartArray<MorphTarget>(16);
+        private _scene: Scene;
+        private _influences: Float32Array;
+        private _supportsNormals = false;
+        private _vertexCount = 0;
+        private _uniqueId = 0;
+
+        public constructor(scene?: Scene) {
+            if (!scene) {
+                scene = Engine.LastCreatedScene;
+            }
+
+            this._scene = scene;
+
+            this._uniqueId = scene.getUniqueId();
+        }
+
+        public get uniqueId(): number {
+            return this._uniqueId;
+        }
+
+        public get vertexCount(): number {
+            return this._vertexCount
+        }
+
+        public get supportsNormals(): boolean {
+            return this._supportsNormals;
+        }
+
+        public get numInfluencers(): number {
+            return this._activeTargets.length;
+        }
+
+        public get influences(): Float32Array {
+            return this._influences;
+        }
+
+        public getActiveTarget(index: number): MorphTarget {
+            return this._activeTargets.data[index];
+        }
+       
+        public addTarget(target: MorphTarget): void {
+            if (this._vertexCount) {
+                if (this._vertexCount !== target.getPositions().length / 3) {
+                    Tools.Error("Incompatible target. Targets must all have the same vertices count.");
+                    return;
+                }
+            }
+
+            this._targets.push(target);
+            this._targetObservable.push(target.onInfluenceChanged.add(needUpdate => {
+                this._syncActiveTargets(needUpdate);
+            }));
+            this._syncActiveTargets(true);        
+        }
+
+        public removeTarget(target: MorphTarget): void {
+            var index = this._targets.indexOf(target);
+            if (index >= 0) {
+                this._targets.splice(index, 1);
+
+                target.onInfluenceChanged.remove(this._targetObservable.splice(index, 1)[0]);
+                this._vertexCount = 0;
+                this._syncActiveTargets(true);
+            }
+        }
+
+        /**
+         * Serializes the current manager into a Serialization object.  
+         * Returns the serialized object.  
+         */
+        public serialize(): any {
+            var serializationObject:any = {};
+
+            serializationObject.id = this.uniqueId;
+
+            serializationObject.targets = [];
+            for (var target of this._targets) {
+                serializationObject.targets.push(target.serialize());
+            }
+
+            return serializationObject;
+        }
+
+        private _onInfluenceChanged(needUpdate: boolean): void {
+            this._syncActiveTargets(needUpdate);
+        }
+
+        private _syncActiveTargets(needUpdate: boolean): void {
+            this._activeTargets.reset();
+            var tempInfluences = [];
+            this._supportsNormals = true;
+            for (var target of this._targets) {
+                if (target.influence > 0) {
+                    this._activeTargets.push(target);
+                    tempInfluences.push(target.influence);
+
+                    this._supportsNormals = this._supportsNormals && target.hasNormals;
+
+                    if (this._vertexCount === 0) {
+                        this._vertexCount = target.getPositions().length / 3;
+                    }
+                }
+            }
+
+            this._influences = new Float32Array(tempInfluences);
+
+            if (needUpdate) {
+                // Flag meshes as dirty to resync with the active targets
+                for (var mesh of this._scene.meshes) {
+                    if ((<any>mesh).morphTargetManager === this) {
+                        (<Mesh>mesh)._syncGeometryWithMorphTargetManager();
+                    }
+                }
+            }
+        }
+    }
+}

+ 7 - 0
src/Shaders/ShadersInclude/morphTargetsVertex.fx

@@ -0,0 +1,7 @@
+#ifdef MORPHTARGETS
+	positionUpdated += (position{X} - position) * morphTargetInfluences[{X}];
+	
+	#ifdef MORPHTARGETS_NORMAL
+	normalUpdated += (normal{X} - normal) * morphTargetInfluences[{X}];
+	#endif	
+#endif

+ 7 - 0
src/Shaders/ShadersInclude/morphTargetsVertexDeclaration.fx

@@ -0,0 +1,7 @@
+#ifdef MORPHTARGETS
+	attribute vec3 position{X};
+
+	#ifdef MORPHTARGETS_NORMAL
+	attribute vec3 normal{X};
+	#endif
+#endif

+ 3 - 0
src/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration.fx

@@ -0,0 +1,3 @@
+#ifdef MORPHTARGETS
+	uniform float morphTargetInfluences[NUM_MORPH_INFLUENCERS];
+#endif

+ 15 - 5
src/Shaders/default.vertex.fx

@@ -85,6 +85,9 @@ varying vec4 vColor;
 #include<fogVertexDeclaration>
 #include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
 
+#include<morphTargetsVertexGlobalDeclaration>
+#include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
+
 #ifdef REFLECTIONMAP_SKYBOX
 varying vec3 vPositionUVW;
 #endif
@@ -96,24 +99,31 @@ varying vec3 vDirectionW;
 #include<logDepthDeclaration>
 
 void main(void) {
+	vec3 positionUpdated = position;
+#ifdef NORMAL	
+	vec3 normalUpdated = normal;
+#endif
+
+#include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
+
 #ifdef REFLECTIONMAP_SKYBOX
-	vPositionUVW = position;
+	vPositionUVW = positionUpdated;
 #endif 
 
 #include<instancesVertex>
 #include<bonesVertex>
 
-	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+	gl_Position = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
 
-	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
 	vPositionW = vec3(worldPos);
 
 #ifdef NORMAL
-	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+	vNormalW = normalize(vec3(finalWorld * vec4(normalUpdated, 0.0)));
 #endif
 
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-	vDirectionW = normalize(vec3(finalWorld * vec4(position, 0.0)));
+	vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0)));
 #endif
 
 	// Texture coordinates

+ 15 - 5
src/Shaders/pbr.vertex.fx

@@ -88,6 +88,9 @@ varying vec4 vColor;
 #include<fogVertexDeclaration>
 #include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
 
+#include<morphTargetsVertexGlobalDeclaration>
+#include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
+
 #ifdef REFLECTIONMAP_SKYBOX
 varying vec3 vPositionUVW;
 #endif
@@ -99,24 +102,31 @@ varying vec3 vDirectionW;
 #include<logDepthDeclaration>
 
 void main(void) {
+	vec3 positionUpdated = position;
+#ifdef NORMAL	
+	vec3 normalUpdated = normal;
+#endif
+
+#include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
+
 #ifdef REFLECTIONMAP_SKYBOX
-    vPositionUVW = position;
+    vPositionUVW = positionUpdated;
 #endif 
 
 #include<instancesVertex>
 #include<bonesVertex>
 
-    gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+    gl_Position = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
 
-    vec4 worldPos = finalWorld * vec4(position, 1.0);
+    vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
     vPositionW = vec3(worldPos);
 
 #ifdef NORMAL
-    vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+    vNormalW = normalize(vec3(finalWorld * vec4(normalUpdated, 0.0)));
 #endif
 
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-    vDirectionW = normalize(vec3(finalWorld * vec4(position, 0.0)));
+    vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0)));
 #endif
 
     // Texture coordinates

+ 5 - 12
src/Tools/babylon.filesInput.ts

@@ -9,7 +9,6 @@
         private _textureLoadingCallback;
         private _startingProcessingFilesCallback;
         private _elementToMonitor: HTMLElement;
-        public static FilesTextures: File[] = new Array();
         public static FilesToLoad: File[] = new Array();
 
         private _sceneFileToLoad: File;
@@ -86,18 +85,12 @@
                     let extension = name.split('.').pop();
                     let type = this._filesToLoad[i].type;
                     
-                    if (extension === "jpg" || extension === "png" || extension === "bmp" || extension === "jpeg" || 
-                        type === "image/jpeg" || type === "image/png" || type === "image/bmp") {
-                           FilesInput.FilesTextures[name] = this._filesToLoad[i]; 
-                        }
+                    if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb") 
+                        && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
+                        this._sceneFileToLoad = this._filesToLoad[i];
+                    }
                     else {
-                        if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb") 
-                            && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
-                            this._sceneFileToLoad = this._filesToLoad[i];
-                        }
-                        else {
-                            FilesInput.FilesToLoad[name] = this._filesToLoad[i];
-                        }
+                        FilesInput.FilesToLoad[name] = this._filesToLoad[i];
                     }
                 }
 

+ 3 - 3
src/Tools/babylon.tools.ts

@@ -368,15 +368,15 @@
                 }
                 else {
                     var textureName = url.substring(5).toLowerCase();
-                    if (FilesInput.FilesTextures[textureName]) {
+                    if (FilesInput.FilesToLoad[textureName]) {
                         try {
                             var blobURL;
                             try {
-                                blobURL = URL.createObjectURL(FilesInput.FilesTextures[textureName], { oneTimeOnly: true });
+                                blobURL = URL.createObjectURL(FilesInput.FilesToLoad[textureName], { oneTimeOnly: true });
                             }
                             catch (ex) {
                                 // Chrome doesn't support oneTimeOnly parameter
-                                blobURL = URL.createObjectURL(FilesInput.FilesTextures[textureName]);
+                                blobURL = URL.createObjectURL(FilesInput.FilesToLoad[textureName]);
                             }
                             img.src = blobURL;
                         }

+ 9 - 3
src/babylon.scene.ts

@@ -1670,8 +1670,14 @@
 
         // Methods
 
+        public getUniqueId() {
+            var result = this._uniqueIdCounter;
+            this._uniqueIdCounter++;
+            return result;
+        }
+
         public addMesh(newMesh: AbstractMesh) {
-            newMesh.uniqueId = this._uniqueIdCounter++;
+            newMesh.uniqueId = this.getUniqueId();
             var position = this.meshes.push(newMesh);
 
             //notify the collision coordinator
@@ -1739,13 +1745,13 @@
         }
 
         public addLight(newLight: Light) {
-            newLight.uniqueId = this._uniqueIdCounter++;
+            newLight.uniqueId = this.getUniqueId();
             var position = this.lights.push(newLight);
             this.onNewLightAddedObservable.notifyObservers(newLight);
         }
 
         public addCamera(newCamera: Camera) {
-            newCamera.uniqueId = this._uniqueIdCounter++;
+            newCamera.uniqueId = this.getUniqueId();
             var position = this.cameras.push(newCamera);
             this.onNewCameraAddedObservable.notifyObservers(newCamera);
         }