Browse Source

merged with master

Benjamin Guignabert 8 years ago
parent
commit
cc4d3bd7e5

+ 4 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonTexture.cs

@@ -71,6 +71,9 @@ namespace BabylonExport.Entities
         [DataMember]
         public string[] extensions { get; set; }
 
+        [DataMember]
+        public int samplingMode { get; set; }
+
         public BabylonTexture()
         {
             level = 1.0f;
@@ -85,6 +88,7 @@ namespace BabylonExport.Entities
             wrapV = 1;
             hasAlpha = false;
             coordinatesIndex = 0;
+            samplingMode = 3;
         }
     }
 }

+ 13 - 8
Playground/frame.js

@@ -1,5 +1,5 @@
 (function () {
-    var snippetUrl = "https://babylonjs-api.azurewebsites.net/api/snippet";
+    var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
     var currentSnippetToken;
     var engine;
     var fpsLabel = document.getElementById("fpsLabel");
@@ -15,6 +15,7 @@
             if (xhr.readyState === 4) {
                 if (xhr.status === 200) {
                     blockEditorChange = true;
+                    console.log(xhr.responseText);
                     jsEditor.setValue(xhr.responseText);
                     jsEditor.setPosition({ lineNumber: 0, column: 0 });
                     blockEditorChange = false;
@@ -30,6 +31,10 @@
         xhr.send(null);
     };
 
+    var showError = function(error) {
+        console.warn(error);
+    };
+
     compileAndRun = function (code) {
         try {
 
@@ -103,7 +108,7 @@
             }
 
         } catch (e) {
-            showError(e.message);
+            // showError(e.message);
         }
     };
     window.addEventListener("resize", function () {
@@ -122,7 +127,7 @@
         }
 
         location.hash = splits.join("#");
-    }
+    };
 
     var checkHash = function () {
         if (location.hash) {
@@ -133,15 +138,15 @@
                 xmlHttp.onreadystatechange = function () {
                     if (xmlHttp.readyState === 4) {
                         if (xmlHttp.status === 200) {
-                            var snippet = JSON.parse(xmlHttp.responseText);
-                            compileAndRun(snippet.code.toString());
+                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText)[0].jsonPayload).code;
+                            compileAndRun(snippetCode);
 
                             document.getElementById("refresh").addEventListener("click", function () {
-                                compileAndRun(snippet.code.toString());
+                                compileAndRun(snippetCode);
                             });
                         }
                     }
-                }
+                };
 
                 var hash = location.hash.substr(1);
                 currentSnippetToken = hash.split("#")[0];
@@ -154,7 +159,7 @@
 
             }
         }
-    }
+    };
 
     checkHash();
 

+ 3 - 1
Tools/Gulp/config.json

@@ -229,7 +229,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",

File diff suppressed because it is too large
+ 17 - 17
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 3147 - 3146
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 39 - 39
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 328 - 39
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 3147 - 3146
dist/preview release/babylon.module.d.ts


File diff suppressed because it is too large
+ 26 - 26
dist/preview release/babylon.noworker.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/inspector/babylon.inspector.bundle.js


File diff suppressed because it is too large
+ 3 - 3
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))

+ 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;
+
+};

+ 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());
             

+ 16 - 1
src/Materials/Textures/babylon.texture.ts

@@ -273,7 +273,14 @@
         public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): BaseTexture {
             if (parsedTexture.customType) { 
                 var customTexture = Tools.Instantiate(parsedTexture.customType);
-                return customTexture.Parse(parsedTexture, scene, rootUrl);
+                // Update Sampling Mode
+                var parsedCustomTexture:any = customTexture.Parse(parsedTexture, scene, rootUrl);
+                if (parsedTexture.samplingMode && parsedCustomTexture.updateSamplingMode && parsedCustomTexture._samplingMode) {
+                    if (parsedCustomTexture._samplingMode !== parsedTexture.samplingMode) {
+                        parsedCustomTexture.updateSamplingMode(parsedTexture.samplingMode);
+                    }
+                }
+                return parsedCustomTexture;
             }
 
             if (parsedTexture.isCube) {
@@ -308,6 +315,14 @@
                 }
             }, parsedTexture, scene);
 
+            // Update Sampling Mode
+            if (parsedTexture.samplingMode) {
+                var sampling:number = parsedTexture.samplingMode;
+                if (texture._samplingMode !== sampling) {
+                    texture.updateSamplingMode(sampling);
+                }
+            }
+
             // Animations
             if (parsedTexture.animations) {
                 for (var animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {

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

@@ -368,7 +368,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);
@@ -308,6 +350,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";
 
@@ -725,7 +729,7 @@ module BABYLON {
 
                 subMesh.setEffect(scene.getEngine().createEffect(shaderName,
                     attribs, uniforms, samplers,
-                    join, fallbacks, onCompiled, this.onError, { maxSimultaneousLights: this._maxSimultaneousLights - 1 }), defines);
+                    join, fallbacks, onCompiled, this.onError, { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }), defines);
 
                 this.buildUniformLayout();
 
@@ -985,6 +989,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

@@ -112,6 +112,9 @@ varying vec4 vColor;
 #include<fogVertexDeclaration>
 #include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
 
+#include<morphTargetsVertexGlobalDeclaration>
+#include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
+
 #ifdef REFLECTIONMAP_SKYBOX
 varying vec3 vPositionUVW;
 #endif
@@ -123,24 +126,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 = uScene.viewProjection * finalWorld * vec4(position, 1.0);
+	gl_Position = uScene.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

+ 9 - 3
src/babylon.scene.ts

@@ -1681,8 +1681,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
@@ -1750,13 +1756,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);
         }