nockawa пре 9 година
родитељ
комит
2c641e2c2d
32 измењених фајлова са 14068 додато и 14121 уклоњено
  1. 23 23
      dist/preview release/babylon.core.js
  2. 1600 1601
      dist/preview release/babylon.d.ts
  3. 36 36
      dist/preview release/babylon.js
  4. 47 28
      dist/preview release/babylon.max.js
  5. 36 36
      dist/preview release/babylon.noworker.js
  6. 5 1
      dist/preview release/what's new.md
  7. 339 340
      src/Bones/babylon.skeleton.js
  8. 1 1
      src/Bones/babylon.skeleton.ts
  9. 262 275
      src/Cameras/babylon.targetCamera.js
  10. 0 23
      src/Cameras/babylon.targetCamera.ts
  11. 918 1049
      src/Canvas2d/babylon.canvas2d.js
  12. 741 735
      src/Canvas2d/babylon.group2d.js
  13. 752 743
      src/Canvas2d/babylon.renderablePrim2d.js
  14. 93 94
      src/Materials/Textures/babylon.dynamicTexture.js
  15. 1 1
      src/Materials/Textures/babylon.dynamicTexture.ts
  16. 83 84
      src/Materials/Textures/babylon.videoTexture.js
  17. 1 1
      src/Materials/Textures/babylon.videoTexture.ts
  18. 3124 3128
      src/Math/babylon.math.js
  19. 14 14
      src/Math/babylon.math.ts
  20. 2376 2377
      src/Mesh/babylon.mesh.js
  21. 1 1
      src/Mesh/babylon.mesh.ts
  22. 1 1
      src/Mesh/babylon.subMesh.ts
  23. 335 335
      src/Physics/Plugins/babylon.oimoJSPlugin.js
  24. 1 0
      src/Physics/Plugins/babylon.oimoJSPlugin.ts
  25. 2 13
      src/Shaders/ShadersInclude/pbrFunctions.fx
  26. 70 43
      src/Shaders/ShadersInclude/pbrLightFunctions.fx
  27. 3 3
      src/Shaders/ShadersInclude/pbrLightFunctionsCall.fx
  28. 10 4
      src/Shaders/pbr.fragment.fx
  29. 1012 1012
      src/Tools/babylon.tools.js
  30. 1 0
      src/Tools/babylon.tools.ts
  31. 2137 2111
      src/babylon.engine.js
  32. 43 8
      src/babylon.engine.ts

Разлика између датотеке није приказан због своје велике величине
+ 23 - 23
dist/preview release/babylon.core.js


Разлика између датотеке није приказан због своје велике величине
+ 1600 - 1601
dist/preview release/babylon.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 36 - 36
dist/preview release/babylon.js


Разлика између датотеке није приказан због своје велике величине
+ 47 - 28
dist/preview release/babylon.max.js


Разлика између датотеке није приказан због своје велике величине
+ 36 - 36
dist/preview release/babylon.noworker.js


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

@@ -30,7 +30,7 @@
     - Enabled other post processes to be used when also using a 3D Rig ([jcpalmer](https://github.com/Palmer-JC))
     - Got Skeleton.copyAminationRange scaling better for different bone lengths ([jcpalmer](https://github.com/Palmer-JC))
     - Added skeleton.getBoneIndexByName(boneName: string) ([dad72](https://github.com/dad72))
-    - Added node._children to track children hierarchy ([deltakosh](https://github.com/deltakosh))
+    - Added `node._children` to track children hierarchy ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
     - Support for Layer.alphaTest ([deltakosh](https://github.com/deltakosh))
     - New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection ([deltakosh](https://github.com/deltakosh))
@@ -73,6 +73,9 @@
     - Fixed bug with OBJ Loader - All meshes were concatenated with the previous one ([Temechon](https://github.com/Temechon))
     - Fixed the device orientation cameras (both VR and non-VR cameras)  ([RaananW](https://github.com/RaananW))
     - Fixed the WebVR implementation  ([RaananW](https://github.com/RaananW))
+    - `DynamicTexture.clone()` now preserves height in addition to width  ([dahlbyk](https://github.com/dahlbyk))
+    - Fixed missing some parameter default values in `MeshBuilder.CreateGroundFromHeightMap()` and `MeshBuilder.CreateTiledGround()` ([jerome](https://github.com/jbousquie))
+    - Fixed model shape initial red vertex color set to zero not formerly being taken in account in the `SolidParticleSystem` ([jerome](https://github.com/jbousquie))
   - **Breaking changes**
     - `VertexData.CreateLines()` removed as `MeshBuilder.CreateLines()` now calls `MeshBuilder.CreateLineSystem()`
     - `scene.onNewXXXAdded` and `scene.onXXXRemoved` callbacks were removed and replaced by `scene.onNewXXXAddedObservable` and `scene.onXXXRemovedObservable`
@@ -82,3 +85,4 @@
     - `Engine.bindMultiBuffers` is now `Engine.bindBuffers` and strongly typed `{ [key: string]: VertexBuffer; }` of buffers ([benaadams](https://github.com/benaadams))
     - `Engine.createDynamicVertexBuffer` takes vertices rather than capacity, creating and initalizing in one gpu instruction ([benaadams](https://github.com/benaadams)) 
     - Internally new `Engine.bindBuffer` is used rather than `gl.bindBuffer` which only binds when the bound buffer is changing ([benaadams](https://github.com/benaadams)) 
+    - `DynamicTexture` no longer forces height/width to exponents of 2 if MIP maps are disabled ([dahlbyk](https://github.com/dahlbyk))

+ 339 - 340
src/Bones/babylon.skeleton.js

@@ -1,340 +1,339 @@
-var BABYLON;
-(function (BABYLON) {
-    var Skeleton = (function () {
-        function Skeleton(name, id, scene) {
-            this.name = name;
-            this.id = id;
-            this.bones = new Array();
-            this.needInitialSkinMatrix = false;
-            this._isDirty = true;
-            this._meshesWithPoseMatrix = new Array();
-            this._identity = BABYLON.Matrix.Identity();
-            this._ranges = {};
-            this.bones = [];
-            this._scene = scene;
-            scene.skeletons.push(this);
-            //make sure it will recalculate the matrix next time prepare is called.
-            this._isDirty = true;
-        }
-        // Members
-        Skeleton.prototype.getTransformMatrices = function (mesh) {
-            if (this.needInitialSkinMatrix && mesh._bonesTransformMatrices) {
-                return mesh._bonesTransformMatrices;
-            }
-            return this._transformMatrices;
-        };
-        Skeleton.prototype.getScene = function () {
-            return this._scene;
-        };
-        // Methods
-        /**
-         * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
-         */
-        Skeleton.prototype.toString = function (fullDetails) {
-            var ret = "Name: " + this.name + ", nBones: " + this.bones.length;
-            ret += ", nAnimationRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
-            if (fullDetails) {
-                ret += ", Ranges: {";
-                var first = true;
-                for (var name_1 in this._ranges) {
-                    if (first) {
-                        ret += ", ";
-                        first = false;
-                    }
-                    ret += name_1;
-                }
-                ret += "}";
-            }
-            return ret;
-        };
-        /**
-        * Get bone's index searching by name
-        * @param {string} name is bone's name to search for
-        * @return {number} Indice of the bone. Returns -1 if not found
-        */
-        Skeleton.prototype.getBoneIndexByName = function (name) {
-            for (var boneIndex = 0, cache = this.bones.length; boneIndex < cache; boneIndex++) {
-                if (this.bones[boneIndex].name === name) {
-                    return boneIndex;
-                }
-            }
-            return -1;
-        };
-        Skeleton.prototype.createAnimationRange = function (name, from, to) {
-            // check name not already in use
-            if (!this._ranges[name]) {
-                this._ranges[name] = new BABYLON.AnimationRange(name, from, to);
-                for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
-                    if (this.bones[i].animations[0]) {
-                        this.bones[i].animations[0].createRange(name, from, to);
-                    }
-                }
-            }
-        };
-        Skeleton.prototype.deleteAnimationRange = function (name, deleteFrames) {
-            if (deleteFrames === void 0) { deleteFrames = true; }
-            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
-                if (this.bones[i].animations[0]) {
-                    this.bones[i].animations[0].deleteRange(name, deleteFrames);
-                }
-            }
-            this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
-        };
-        Skeleton.prototype.getAnimationRange = function (name) {
-            return this._ranges[name];
-        };
-        /**
-         *  Returns as an Array, all AnimationRanges defined on this skeleton
-         */
-        Skeleton.prototype.getAnimationRanges = function () {
-            var animationRanges = [];
-            var name;
-            var i = 0;
-            for (name in this._ranges) {
-                animationRanges[i] = this._ranges[name];
-                i++;
-            }
-            return animationRanges;
-        };
-        /**
-         *  note: This is not for a complete retargeting, only between very similar skeleton's with only possible bone length differences
-         */
-        Skeleton.prototype.copyAnimationRange = function (source, name, rescaleAsRequired) {
-            if (rescaleAsRequired === void 0) { rescaleAsRequired = false; }
-            if (this._ranges[name] || !source.getAnimationRange(name)) {
-                return false;
-            }
-            var ret = true;
-            var frameOffset = this._getHighestAnimationFrame() + 1;
-            // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
-            var boneDict = {};
-            var sourceBones = source.bones;
-            var nBones;
-            var i;
-            for (i = 0, nBones = sourceBones.length; i < nBones; i++) {
-                boneDict[sourceBones[i].name] = sourceBones[i];
-            }
-            if (this.bones.length !== sourceBones.length) {
-                BABYLON.Tools.Warn("copyAnimationRange: this rig has " + this.bones.length + " bones, while source as " + sourceBones.length);
-                ret = false;
-            }
-            var skelDimensionsRatio = (rescaleAsRequired && this.dimensionsAtRest && source.dimensionsAtRest) ? this.dimensionsAtRest.divide(source.dimensionsAtRest) : null;
-            for (i = 0, nBones = this.bones.length; i < nBones; i++) {
-                var boneName = this.bones[i].name;
-                var sourceBone = boneDict[boneName];
-                if (sourceBone) {
-                    ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
-                }
-                else {
-                    BABYLON.Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
-                    ret = false;
-                }
-            }
-            // do not call createAnimationRange(), since it also is done to bones, which was already done
-            var range = source.getAnimationRange(name);
-            this._ranges[name] = new BABYLON.AnimationRange(name, range.from + frameOffset, range.to + frameOffset);
-            return ret;
-        };
-        Skeleton.prototype.returnToRest = function () {
-            for (var index = 0; index < this.bones.length; index++) {
-                this.bones[index].returnToRest();
-            }
-        };
-        Skeleton.prototype._getHighestAnimationFrame = function () {
-            var ret = 0;
-            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
-                if (this.bones[i].animations[0]) {
-                    var highest = this.bones[i].animations[0].getHighestFrame();
-                    if (ret < highest) {
-                        ret = highest;
-                    }
-                }
-            }
-            return ret;
-        };
-        Skeleton.prototype.beginAnimation = function (name, loop, speedRatio, onAnimationEnd) {
-            var range = this.getAnimationRange(name);
-            if (!range) {
-                return null;
-            }
-            return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
-        };
-        Skeleton.prototype._markAsDirty = function () {
-            this._isDirty = true;
-        };
-        Skeleton.prototype._registerMeshWithPoseMatrix = function (mesh) {
-            this._meshesWithPoseMatrix.push(mesh);
-        };
-        Skeleton.prototype._unregisterMeshWithPoseMatrix = function (mesh) {
-            var index = this._meshesWithPoseMatrix.indexOf(mesh);
-            if (index > -1) {
-                this._meshesWithPoseMatrix.splice(index, 1);
-            }
-        };
-        Skeleton.prototype._computeTransformMatrices = function (targetMatrix, initialSkinMatrix) {
-            for (var index = 0; index < this.bones.length; index++) {
-                var bone = this.bones[index];
-                var parentBone = bone.getParent();
-                if (parentBone) {
-                    bone.getLocalMatrix().multiplyToRef(parentBone.getWorldMatrix(), bone.getWorldMatrix());
-                }
-                else {
-                    if (initialSkinMatrix) {
-                        bone.getLocalMatrix().multiplyToRef(initialSkinMatrix, bone.getWorldMatrix());
-                    }
-                    else {
-                        bone.getWorldMatrix().copyFrom(bone.getLocalMatrix());
-                    }
-                }
-                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), targetMatrix, index * 16);
-            }
-            this._identity.copyToArray(targetMatrix, this.bones.length * 16);
-        };
-        Skeleton.prototype.prepare = function () {
-            if (!this._isDirty) {
-                return;
-            }
-            if (this.needInitialSkinMatrix) {
-                for (var index = 0; index < this._meshesWithPoseMatrix.length; index++) {
-                    var mesh = this._meshesWithPoseMatrix[index];
-                    if (!mesh._bonesTransformMatrices || mesh._bonesTransformMatrices.length !== 16 * (this.bones.length + 1)) {
-                        mesh._bonesTransformMatrices = new Float32Array(16 * (this.bones.length + 1));
-                    }
-                    var poseMatrix = mesh.getPoseMatrix();
-                    // Prepare bones
-                    for (var boneIndex = 0; boneIndex < this.bones.length; boneIndex++) {
-                        var bone = this.bones[boneIndex];
-                        if (!bone.getParent()) {
-                            var matrix = bone.getBaseMatrix();
-                            matrix.multiplyToRef(poseMatrix, BABYLON.Tmp.Matrix[0]);
-                            bone._updateDifferenceMatrix(BABYLON.Tmp.Matrix[0]);
-                        }
-                    }
-                    this._computeTransformMatrices(mesh._bonesTransformMatrices, poseMatrix);
-                }
-            }
-            else {
-                if (!this._transformMatrices || this._transformMatrices.length !== 16 * (this.bones.length + 1)) {
-                    this._transformMatrices = new Float32Array(16 * (this.bones.length + 1));
-                }
-                this._computeTransformMatrices(this._transformMatrices, null);
-            }
-            this._isDirty = false;
-            this._scene._activeBones += this.bones.length;
-        };
-        Skeleton.prototype.getAnimatables = function () {
-            if (!this._animatables || this._animatables.length !== this.bones.length) {
-                this._animatables = [];
-                for (var index = 0; index < this.bones.length; index++) {
-                    this._animatables.push(this.bones[index]);
-                }
-            }
-            return this._animatables;
-        };
-        Skeleton.prototype.clone = function (name, id) {
-            var result = new Skeleton(name, id || name, this._scene);
-            result.needInitialSkinMatrix = this.needInitialSkinMatrix;
-            for (var index = 0; index < this.bones.length; index++) {
-                var source = this.bones[index];
-                var parentBone = null;
-                if (source.getParent()) {
-                    var parentIndex = this.bones.indexOf(source.getParent());
-                    parentBone = result.bones[parentIndex];
-                }
-                var bone = new BABYLON.Bone(source.name, result, parentBone, source.getBaseMatrix().clone(), source.getRestPose().clone());
-                BABYLON.Tools.DeepCopy(source.animations, bone.animations);
-            }
-            if (this._ranges) {
-                result._ranges = {};
-                for (var rangeName in this._ranges) {
-                    result._ranges[rangeName] = this._ranges[rangeName].clone();
-                }
-            }
-            this._isDirty = true;
-            return result;
-        };
-        Skeleton.prototype.enableBlending = function (blendingSpeed) {
-            if (blendingSpeed === void 0) { blendingSpeed = 0.01; }
-            this.bones.forEach(function (bone) {
-                bone.animations.forEach(function (animation) {
-                    animation.enableBlending = true;
-                    animation.blendingSpeed = blendingSpeed;
-                });
-            });
-        };
-        Skeleton.prototype.dispose = function () {
-            this._meshesWithPoseMatrix = [];
-            // Animations
-            this.getScene().stopAnimation(this);
-            // Remove from scene
-            this.getScene().removeSkeleton(this);
-        };
-        Skeleton.prototype.serialize = function () {
-            var serializationObject = {};
-            serializationObject.name = this.name;
-            serializationObject.id = this.id;
-            serializationObject.dimensionsAtRest = this.dimensionsAtRest;
-            serializationObject.bones = [];
-            serializationObject.needInitialSkinMatrix = this.needInitialSkinMatrix;
-            for (var index = 0; index < this.bones.length; index++) {
-                var bone = this.bones[index];
-                var serializedBone = {
-                    parentBoneIndex: bone.getParent() ? this.bones.indexOf(bone.getParent()) : -1,
-                    name: bone.name,
-                    matrix: bone.getLocalMatrix().toArray(),
-                    rest: bone.getRestPose().toArray()
-                };
-                serializationObject.bones.push(serializedBone);
-                if (bone.length) {
-                    serializedBone.length = bone.length;
-                }
-                if (bone.animations && bone.animations.length > 0) {
-                    serializedBone.animation = bone.animations[0].serialize();
-                }
-                serializationObject.ranges = [];
-                for (var name in this._ranges) {
-                    var range = {};
-                    range.name = name;
-                    range.from = this._ranges[name].from;
-                    range.to = this._ranges[name].to;
-                    serializationObject.ranges.push(range);
-                }
-            }
-            return serializationObject;
-        };
-        Skeleton.Parse = function (parsedSkeleton, scene) {
-            var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
-            if (parsedSkeleton.dimensionsAtRest) {
-                skeleton.dimensionsAtRest = BABYLON.Vector3.FromArray(parsedSkeleton.dimensionsAtRest);
-            }
-            skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
-            var index;
-            for (index = 0; index < parsedSkeleton.bones.length; index++) {
-                var parsedBone = parsedSkeleton.bones[index];
-                var parentBone = null;
-                if (parsedBone.parentBoneIndex > -1) {
-                    parentBone = skeleton.bones[parsedBone.parentBoneIndex];
-                }
-                var rest = parsedBone.rest ? BABYLON.Matrix.FromArray(parsedBone.rest) : null;
-                var bone = new BABYLON.Bone(parsedBone.name, skeleton, parentBone, BABYLON.Matrix.FromArray(parsedBone.matrix), rest);
-                if (parsedBone.length) {
-                    bone.length = parsedBone.length;
-                }
-                if (parsedBone.animation) {
-                    bone.animations.push(BABYLON.Animation.Parse(parsedBone.animation));
-                }
-            }
-            // placed after bones, so createAnimationRange can cascade down
-            if (parsedSkeleton.ranges) {
-                for (index = 0; index < parsedSkeleton.ranges.length; index++) {
-                    var data = parsedSkeleton.ranges[index];
-                    skeleton.createAnimationRange(data.name, data.from, data.to);
-                }
-            }
-            return skeleton;
-        };
-        return Skeleton;
-    }());
-    BABYLON.Skeleton = Skeleton;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.skeleton.js.map
+var BABYLON;
+(function (BABYLON) {
+    var Skeleton = (function () {
+        function Skeleton(name, id, scene) {
+            this.name = name;
+            this.id = id;
+            this.bones = new Array();
+            this.needInitialSkinMatrix = false;
+            this._isDirty = true;
+            this._meshesWithPoseMatrix = new Array();
+            this._identity = BABYLON.Matrix.Identity();
+            this._ranges = {};
+            this.bones = [];
+            this._scene = scene;
+            scene.skeletons.push(this);
+            //make sure it will recalculate the matrix next time prepare is called.
+            this._isDirty = true;
+        }
+        // Members
+        Skeleton.prototype.getTransformMatrices = function (mesh) {
+            if (this.needInitialSkinMatrix && mesh._bonesTransformMatrices) {
+                return mesh._bonesTransformMatrices;
+            }
+            return this._transformMatrices;
+        };
+        Skeleton.prototype.getScene = function () {
+            return this._scene;
+        };
+        // Methods
+        /**
+         * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
+         */
+        Skeleton.prototype.toString = function (fullDetails) {
+            var ret = "Name: " + this.name + ", nBones: " + this.bones.length;
+            ret += ", nAnimationRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
+            if (fullDetails) {
+                ret += ", Ranges: {";
+                var first = true;
+                for (var name_1 in this._ranges) {
+                    if (first) {
+                        ret += ", ";
+                        first = false;
+                    }
+                    ret += name_1;
+                }
+                ret += "}";
+            }
+            return ret;
+        };
+        /**
+        * Get bone's index searching by name
+        * @param {string} name is bone's name to search for
+        * @return {number} Indice of the bone. Returns -1 if not found
+        */
+        Skeleton.prototype.getBoneIndexByName = function (name) {
+            for (var boneIndex = 0, cache = this.bones.length; boneIndex < cache; boneIndex++) {
+                if (this.bones[boneIndex].name === name) {
+                    return boneIndex;
+                }
+            }
+            return -1;
+        };
+        Skeleton.prototype.createAnimationRange = function (name, from, to) {
+            // check name not already in use
+            if (!this._ranges[name]) {
+                this._ranges[name] = new BABYLON.AnimationRange(name, from, to);
+                for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                    if (this.bones[i].animations[0]) {
+                        this.bones[i].animations[0].createRange(name, from, to);
+                    }
+                }
+            }
+        };
+        Skeleton.prototype.deleteAnimationRange = function (name, deleteFrames) {
+            if (deleteFrames === void 0) { deleteFrames = true; }
+            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                if (this.bones[i].animations[0]) {
+                    this.bones[i].animations[0].deleteRange(name, deleteFrames);
+                }
+            }
+            this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
+        };
+        Skeleton.prototype.getAnimationRange = function (name) {
+            return this._ranges[name];
+        };
+        /**
+         *  Returns as an Array, all AnimationRanges defined on this skeleton
+         */
+        Skeleton.prototype.getAnimationRanges = function () {
+            var animationRanges = [];
+            var name;
+            var i = 0;
+            for (name in this._ranges) {
+                animationRanges[i] = this._ranges[name];
+                i++;
+            }
+            return animationRanges;
+        };
+        /**
+         *  note: This is not for a complete retargeting, only between very similar skeleton's with only possible bone length differences
+         */
+        Skeleton.prototype.copyAnimationRange = function (source, name, rescaleAsRequired) {
+            if (rescaleAsRequired === void 0) { rescaleAsRequired = false; }
+            if (this._ranges[name] || !source.getAnimationRange(name)) {
+                return false;
+            }
+            var ret = true;
+            var frameOffset = this._getHighestAnimationFrame() + 1;
+            // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
+            var boneDict = {};
+            var sourceBones = source.bones;
+            var nBones;
+            var i;
+            for (i = 0, nBones = sourceBones.length; i < nBones; i++) {
+                boneDict[sourceBones[i].name] = sourceBones[i];
+            }
+            if (this.bones.length !== sourceBones.length) {
+                BABYLON.Tools.Warn("copyAnimationRange: this rig has " + this.bones.length + " bones, while source as " + sourceBones.length);
+                ret = false;
+            }
+            var skelDimensionsRatio = (rescaleAsRequired && this.dimensionsAtRest && source.dimensionsAtRest) ? this.dimensionsAtRest.divide(source.dimensionsAtRest) : null;
+            for (i = 0, nBones = this.bones.length; i < nBones; i++) {
+                var boneName = this.bones[i].name;
+                var sourceBone = boneDict[boneName];
+                if (sourceBone) {
+                    ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired, skelDimensionsRatio);
+                }
+                else {
+                    BABYLON.Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
+                    ret = false;
+                }
+            }
+            // do not call createAnimationRange(), since it also is done to bones, which was already done
+            var range = source.getAnimationRange(name);
+            this._ranges[name] = new BABYLON.AnimationRange(name, range.from + frameOffset, range.to + frameOffset);
+            return ret;
+        };
+        Skeleton.prototype.returnToRest = function () {
+            for (var index = 0; index < this.bones.length; index++) {
+                this.bones[index].returnToRest();
+            }
+        };
+        Skeleton.prototype._getHighestAnimationFrame = function () {
+            var ret = 0;
+            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                if (this.bones[i].animations[0]) {
+                    var highest = this.bones[i].animations[0].getHighestFrame();
+                    if (ret < highest) {
+                        ret = highest;
+                    }
+                }
+            }
+            return ret;
+        };
+        Skeleton.prototype.beginAnimation = function (name, loop, speedRatio, onAnimationEnd) {
+            var range = this.getAnimationRange(name);
+            if (!range) {
+                return null;
+            }
+            return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
+        };
+        Skeleton.prototype._markAsDirty = function () {
+            this._isDirty = true;
+        };
+        Skeleton.prototype._registerMeshWithPoseMatrix = function (mesh) {
+            this._meshesWithPoseMatrix.push(mesh);
+        };
+        Skeleton.prototype._unregisterMeshWithPoseMatrix = function (mesh) {
+            var index = this._meshesWithPoseMatrix.indexOf(mesh);
+            if (index > -1) {
+                this._meshesWithPoseMatrix.splice(index, 1);
+            }
+        };
+        Skeleton.prototype._computeTransformMatrices = function (targetMatrix, initialSkinMatrix) {
+            for (var index = 0; index < this.bones.length; index++) {
+                var bone = this.bones[index];
+                var parentBone = bone.getParent();
+                if (parentBone) {
+                    bone.getLocalMatrix().multiplyToRef(parentBone.getWorldMatrix(), bone.getWorldMatrix());
+                }
+                else {
+                    if (initialSkinMatrix) {
+                        bone.getLocalMatrix().multiplyToRef(initialSkinMatrix, bone.getWorldMatrix());
+                    }
+                    else {
+                        bone.getWorldMatrix().copyFrom(bone.getLocalMatrix());
+                    }
+                }
+                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), targetMatrix, index * 16);
+            }
+            this._identity.copyToArray(targetMatrix, this.bones.length * 16);
+        };
+        Skeleton.prototype.prepare = function () {
+            if (!this._isDirty) {
+                return;
+            }
+            if (this.needInitialSkinMatrix) {
+                for (var index = 0; index < this._meshesWithPoseMatrix.length; index++) {
+                    var mesh = this._meshesWithPoseMatrix[index];
+                    if (!mesh._bonesTransformMatrices || mesh._bonesTransformMatrices.length !== 16 * (this.bones.length + 1)) {
+                        mesh._bonesTransformMatrices = new Float32Array(16 * (this.bones.length + 1));
+                    }
+                    var poseMatrix = mesh.getPoseMatrix();
+                    // Prepare bones
+                    for (var boneIndex = 0; boneIndex < this.bones.length; boneIndex++) {
+                        var bone = this.bones[boneIndex];
+                        if (!bone.getParent()) {
+                            var matrix = bone.getBaseMatrix();
+                            matrix.multiplyToRef(poseMatrix, BABYLON.Tmp.Matrix[0]);
+                            bone._updateDifferenceMatrix(BABYLON.Tmp.Matrix[0]);
+                        }
+                    }
+                    this._computeTransformMatrices(mesh._bonesTransformMatrices, poseMatrix);
+                }
+            }
+            else {
+                if (!this._transformMatrices || this._transformMatrices.length !== 16 * (this.bones.length + 1)) {
+                    this._transformMatrices = new Float32Array(16 * (this.bones.length + 1));
+                }
+                this._computeTransformMatrices(this._transformMatrices, null);
+            }
+            this._isDirty = false;
+            this._scene._activeBones += this.bones.length;
+        };
+        Skeleton.prototype.getAnimatables = function () {
+            if (!this._animatables || this._animatables.length !== this.bones.length) {
+                this._animatables = [];
+                for (var index = 0; index < this.bones.length; index++) {
+                    this._animatables.push(this.bones[index]);
+                }
+            }
+            return this._animatables;
+        };
+        Skeleton.prototype.clone = function (name, id) {
+            var result = new Skeleton(name, id || name, this._scene);
+            result.needInitialSkinMatrix = this.needInitialSkinMatrix;
+            for (var index = 0; index < this.bones.length; index++) {
+                var source = this.bones[index];
+                var parentBone = null;
+                if (source.getParent()) {
+                    var parentIndex = this.bones.indexOf(source.getParent());
+                    parentBone = result.bones[parentIndex];
+                }
+                var bone = new BABYLON.Bone(source.name, result, parentBone, source.getBaseMatrix().clone(), source.getRestPose().clone());
+                BABYLON.Tools.DeepCopy(source.animations, bone.animations);
+            }
+            if (this._ranges) {
+                result._ranges = {};
+                for (var rangeName in this._ranges) {
+                    result._ranges[rangeName] = this._ranges[rangeName].clone();
+                }
+            }
+            this._isDirty = true;
+            return result;
+        };
+        Skeleton.prototype.enableBlending = function (blendingSpeed) {
+            if (blendingSpeed === void 0) { blendingSpeed = 0.01; }
+            this.bones.forEach(function (bone) {
+                bone.animations.forEach(function (animation) {
+                    animation.enableBlending = true;
+                    animation.blendingSpeed = blendingSpeed;
+                });
+            });
+        };
+        Skeleton.prototype.dispose = function () {
+            this._meshesWithPoseMatrix = [];
+            // Animations
+            this.getScene().stopAnimation(this);
+            // Remove from scene
+            this.getScene().removeSkeleton(this);
+        };
+        Skeleton.prototype.serialize = function () {
+            var serializationObject = {};
+            serializationObject.name = this.name;
+            serializationObject.id = this.id;
+            serializationObject.dimensionsAtRest = this.dimensionsAtRest;
+            serializationObject.bones = [];
+            serializationObject.needInitialSkinMatrix = this.needInitialSkinMatrix;
+            for (var index = 0; index < this.bones.length; index++) {
+                var bone = this.bones[index];
+                var serializedBone = {
+                    parentBoneIndex: bone.getParent() ? this.bones.indexOf(bone.getParent()) : -1,
+                    name: bone.name,
+                    matrix: bone.getLocalMatrix().toArray(),
+                    rest: bone.getRestPose().toArray()
+                };
+                serializationObject.bones.push(serializedBone);
+                if (bone.length) {
+                    serializedBone.length = bone.length;
+                }
+                if (bone.animations && bone.animations.length > 0) {
+                    serializedBone.animation = bone.animations[0].serialize();
+                }
+                serializationObject.ranges = [];
+                for (var name in this._ranges) {
+                    var range = {};
+                    range.name = name;
+                    range.from = this._ranges[name].from;
+                    range.to = this._ranges[name].to;
+                    serializationObject.ranges.push(range);
+                }
+            }
+            return serializationObject;
+        };
+        Skeleton.Parse = function (parsedSkeleton, scene) {
+            var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
+            if (parsedSkeleton.dimensionsAtRest) {
+                skeleton.dimensionsAtRest = BABYLON.Vector3.FromArray(parsedSkeleton.dimensionsAtRest);
+            }
+            skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
+            var index;
+            for (index = 0; index < parsedSkeleton.bones.length; index++) {
+                var parsedBone = parsedSkeleton.bones[index];
+                var parentBone = null;
+                if (parsedBone.parentBoneIndex > -1) {
+                    parentBone = skeleton.bones[parsedBone.parentBoneIndex];
+                }
+                var rest = parsedBone.rest ? BABYLON.Matrix.FromArray(parsedBone.rest) : null;
+                var bone = new BABYLON.Bone(parsedBone.name, skeleton, parentBone, BABYLON.Matrix.FromArray(parsedBone.matrix), rest);
+                if (parsedBone.length) {
+                    bone.length = parsedBone.length;
+                }
+                if (parsedBone.animation) {
+                    bone.animations.push(BABYLON.Animation.Parse(parsedBone.animation));
+                }
+            }
+            // placed after bones, so createAnimationRange can cascade down
+            if (parsedSkeleton.ranges) {
+                for (index = 0; index < parsedSkeleton.ranges.length; index++) {
+                    var data = parsedSkeleton.ranges[index];
+                    skeleton.createAnimationRange(data.name, data.from, data.to);
+                }
+            }
+            return skeleton;
+        };
+        return Skeleton;
+    })();
+    BABYLON.Skeleton = Skeleton;
+})(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Bones/babylon.skeleton.ts

@@ -142,7 +142,7 @@
                 var boneName = this.bones[i].name;
                 var sourceBone = boneDict[boneName];
                 if (sourceBone) {
-                    ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
+                    ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired, skelDimensionsRatio);
                 } else {
                     Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
                     ret = false;

+ 262 - 275
src/Cameras/babylon.targetCamera.js

@@ -1,275 +1,262 @@
-var __extends = (this && this.__extends) || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-    return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-var BABYLON;
-(function (BABYLON) {
-    var TargetCamera = (function (_super) {
-        __extends(TargetCamera, _super);
-        function TargetCamera(name, position, scene) {
-            _super.call(this, name, position, scene);
-            this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
-            this.cameraRotation = new BABYLON.Vector2(0, 0);
-            this.rotation = new BABYLON.Vector3(0, 0, 0);
-            this.speed = 2.0;
-            this.noRotationConstraint = false;
-            this.lockedTarget = null;
-            this._currentTarget = BABYLON.Vector3.Zero();
-            this._viewMatrix = BABYLON.Matrix.Zero();
-            this._camMatrix = BABYLON.Matrix.Zero();
-            this._cameraTransformMatrix = BABYLON.Matrix.Zero();
-            this._cameraRotationMatrix = BABYLON.Matrix.Zero();
-            this._referencePoint = new BABYLON.Vector3(0, 0, 1);
-            this._defaultUpVector = new BABYLON.Vector3(0, 1, 0);
-            this._transformedReferencePoint = BABYLON.Vector3.Zero();
-            this._lookAtTemp = BABYLON.Matrix.Zero();
-            this._tempMatrix = BABYLON.Matrix.Zero();
-        }
-        TargetCamera.prototype.getFrontPosition = function (distance) {
-            var direction = this.getTarget().subtract(this.position);
-            direction.normalize();
-            direction.scaleInPlace(distance);
-            return this.globalPosition.add(direction);
-        };
-        TargetCamera.prototype._getLockedTargetPosition = function () {
-            if (!this.lockedTarget) {
-                return null;
-            }
-            return this.lockedTarget.position || this.lockedTarget;
-        };
-        // Cache
-        TargetCamera.prototype._initCache = function () {
-            _super.prototype._initCache.call(this);
-            this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-            this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-            this._cache.rotationQuaternion = new BABYLON.Quaternion(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        };
-        TargetCamera.prototype._updateCache = function (ignoreParentClass) {
-            if (!ignoreParentClass) {
-                _super.prototype._updateCache.call(this);
-            }
-            var lockedTargetPosition = this._getLockedTargetPosition();
-            if (!lockedTargetPosition) {
-                this._cache.lockedTarget = null;
-            }
-            else {
-                if (!this._cache.lockedTarget) {
-                    this._cache.lockedTarget = lockedTargetPosition.clone();
-                }
-                else {
-                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
-                }
-            }
-            this._cache.rotation.copyFrom(this.rotation);
-            if (this.rotationQuaternion)
-                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
-        };
-        // Synchronized
-        TargetCamera.prototype._isSynchronizedViewMatrix = function () {
-            if (!_super.prototype._isSynchronizedViewMatrix.call(this)) {
-                return false;
-            }
-            var lockedTargetPosition = this._getLockedTargetPosition();
-            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
-                && (this.rotationQuaternion ? this.rotationQuaternion.equals(this._cache.rotationQuaternion) : this._cache.rotation.equals(this.rotation));
-        };
-        // Methods
-        TargetCamera.prototype._computeLocalCameraSpeed = function () {
-            var engine = this.getEngine();
-            return this.speed * ((engine.getDeltaTime() / (engine.getFps() * 10.0)));
-        };
-        // Target
-        TargetCamera.prototype.setTarget = function (target) {
-            this.upVector.normalize();
-            BABYLON.Matrix.LookAtLHToRef(this.position, target, this._defaultUpVector, this._camMatrix);
-            this._camMatrix.invert();
-            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
-            var vDir = target.subtract(this.position);
-            if (vDir.x >= 0.0) {
-                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
-            }
-            else {
-                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
-            }
-            this.rotation.z = 0;
-            if (isNaN(this.rotation.x)) {
-                this.rotation.x = 0;
-            }
-            if (isNaN(this.rotation.y)) {
-                this.rotation.y = 0;
-            }
-            if (isNaN(this.rotation.z)) {
-                this.rotation.z = 0;
-            }
-            if (this.rotationQuaternion) {
-                BABYLON.Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
-            }
-        };
-        TargetCamera.prototype.getTarget = function () {
-            return this._currentTarget;
-        };
-        TargetCamera.prototype._decideIfNeedsToMove = function () {
-            return Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
-        };
-        TargetCamera.prototype._updatePosition = function () {
-            this.position.addInPlace(this.cameraDirection);
-        };
-        TargetCamera.prototype._checkInputs = function () {
-            var needToMove = this._decideIfNeedsToMove();
-            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
-            // Move
-            if (needToMove) {
-                this._updatePosition();
-            }
-            // Rotate
-            if (needToRotate) {
-                this.rotation.x += this.cameraRotation.x;
-                this.rotation.y += this.cameraRotation.y;
-                if (!this.noRotationConstraint) {
-                    var limit = (Math.PI / 2) * 0.95;
-                    if (this.rotation.x > limit)
-                        this.rotation.x = limit;
-                    if (this.rotation.x < -limit)
-                        this.rotation.x = -limit;
-                }
-            }
-            // Inertia
-            if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < BABYLON.Epsilon) {
-                    this.cameraDirection.x = 0;
-                }
-                if (Math.abs(this.cameraDirection.y) < BABYLON.Epsilon) {
-                    this.cameraDirection.y = 0;
-                }
-                if (Math.abs(this.cameraDirection.z) < BABYLON.Epsilon) {
-                    this.cameraDirection.z = 0;
-                }
-                this.cameraDirection.scaleInPlace(this.inertia);
-            }
-            if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < BABYLON.Epsilon) {
-                    this.cameraRotation.x = 0;
-                }
-                if (Math.abs(this.cameraRotation.y) < BABYLON.Epsilon) {
-                    this.cameraRotation.y = 0;
-                }
-                this.cameraRotation.scaleInPlace(this.inertia);
-            }
-            _super.prototype._checkInputs.call(this);
-        };
-        TargetCamera.prototype._updateCameraRotationMatrix = function () {
-            if (this.rotationQuaternion) {
-                this.rotationQuaternion.toRotationMatrix(this._cameraRotationMatrix);
-                //update the up vector!
-                BABYLON.Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this.upVector);
-            }
-            else {
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-            }
-        };
-        TargetCamera.prototype._getViewMatrix = function () {
-            if (!this.lockedTarget) {
-                // Compute
-                this._updateCameraRotationMatrix();
-                BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-                // Computing target and final matrix
-                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            }
-            else {
-                this._currentTarget.copyFrom(this._getLockedTargetPosition());
-            }
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
-            return this._viewMatrix;
-        };
-        TargetCamera.prototype._getVRViewMatrix = function () {
-            this._updateCameraRotationMatrix();
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
-            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        };
-        /**
-         * @override
-         * Override Camera.createRigCamera
-         */
-        TargetCamera.prototype.createRigCamera = function (name, cameraIndex) {
-            if (this.cameraRigMode !== BABYLON.Camera.RIG_MODE_NONE) {
-                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
-                if (this.cameraRigMode === BABYLON.Camera.RIG_MODE_VR) {
-                    if (!this.rotationQuaternion) {
-                        this.rotationQuaternion = new BABYLON.Quaternion();
-                    }
-                    rigCamera._cameraRigParams = {};
-                    rigCamera._cameraRigParams.vrActualUp = new BABYLON.Vector3(0, 0, 0);
-                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
-                    rigCamera.rotationQuaternion = new BABYLON.Quaternion();
-                }
-                return rigCamera;
-            }
-            return null;
-        };
-        /**
-         * @override
-         * Override Camera._updateRigCameras
-         */
-        TargetCamera.prototype._updateRigCameras = function () {
-            var camLeft = this._rigCameras[0];
-            var camRight = this._rigCameras[1];
-            switch (this.cameraRigMode) {
-                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
-                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
-                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
-                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
-                    //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
-                    var leftSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : -1;
-                    var rightSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 : 1;
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft.position);
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
-                    camLeft.setTarget(this.getTarget());
-                    camRight.setTarget(this.getTarget());
-                    break;
-                case BABYLON.Camera.RIG_MODE_VR:
-                    camLeft.rotationQuaternion.copyFrom(this.rotationQuaternion);
-                    camRight.rotationQuaternion.copyFrom(this.rotationQuaternion);
-                    camLeft.position.copyFrom(this.position);
-                    camRight.position.copyFrom(this.position);
-                    break;
-            }
-            _super.prototype._updateRigCameras.call(this);
-        };
-        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
-            if (!this._rigCamTransformMatrix) {
-                this._rigCamTransformMatrix = new BABYLON.Matrix();
-            }
-            var target = this.getTarget();
-            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
-            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
-        };
-        TargetCamera.prototype.getTypeName = function () {
-            return "TargetCamera";
-        };
-        __decorate([
-            BABYLON.serializeAsVector3()
-        ], TargetCamera.prototype, "rotation", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], TargetCamera.prototype, "speed", void 0);
-        __decorate([
-            BABYLON.serializeAsMeshReference("lockedTargetId")
-        ], TargetCamera.prototype, "lockedTarget", void 0);
-        return TargetCamera;
-    }(BABYLON.Camera));
-    BABYLON.TargetCamera = TargetCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.targetCamera.js.map
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var TargetCamera = (function (_super) {
+        __extends(TargetCamera, _super);
+        function TargetCamera(name, position, scene) {
+            _super.call(this, name, position, scene);
+            this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
+            this.cameraRotation = new BABYLON.Vector2(0, 0);
+            this.rotation = new BABYLON.Vector3(0, 0, 0);
+            this.speed = 2.0;
+            this.noRotationConstraint = false;
+            this.lockedTarget = null;
+            this._currentTarget = BABYLON.Vector3.Zero();
+            this._viewMatrix = BABYLON.Matrix.Zero();
+            this._camMatrix = BABYLON.Matrix.Zero();
+            this._cameraTransformMatrix = BABYLON.Matrix.Zero();
+            this._cameraRotationMatrix = BABYLON.Matrix.Zero();
+            this._referencePoint = new BABYLON.Vector3(0, 0, 1);
+            this._defaultUpVector = new BABYLON.Vector3(0, 1, 0);
+            this._transformedReferencePoint = BABYLON.Vector3.Zero();
+            this._lookAtTemp = BABYLON.Matrix.Zero();
+            this._tempMatrix = BABYLON.Matrix.Zero();
+        }
+        TargetCamera.prototype.getFrontPosition = function (distance) {
+            var direction = this.getTarget().subtract(this.position);
+            direction.normalize();
+            direction.scaleInPlace(distance);
+            return this.globalPosition.add(direction);
+        };
+        TargetCamera.prototype._getLockedTargetPosition = function () {
+            if (!this.lockedTarget) {
+                return null;
+            }
+            return this.lockedTarget.position || this.lockedTarget;
+        };
+        // Cache
+        TargetCamera.prototype._initCache = function () {
+            _super.prototype._initCache.call(this);
+            this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotationQuaternion = new BABYLON.Quaternion(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+        };
+        TargetCamera.prototype._updateCache = function (ignoreParentClass) {
+            if (!ignoreParentClass) {
+                _super.prototype._updateCache.call(this);
+            }
+            var lockedTargetPosition = this._getLockedTargetPosition();
+            if (!lockedTargetPosition) {
+                this._cache.lockedTarget = null;
+            }
+            else {
+                if (!this._cache.lockedTarget) {
+                    this._cache.lockedTarget = lockedTargetPosition.clone();
+                }
+                else {
+                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
+                }
+            }
+            this._cache.rotation.copyFrom(this.rotation);
+            if (this.rotationQuaternion)
+                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
+        };
+        // Synchronized
+        TargetCamera.prototype._isSynchronizedViewMatrix = function () {
+            if (!_super.prototype._isSynchronizedViewMatrix.call(this)) {
+                return false;
+            }
+            var lockedTargetPosition = this._getLockedTargetPosition();
+            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
+                && (this.rotationQuaternion ? this.rotationQuaternion.equals(this._cache.rotationQuaternion) : this._cache.rotation.equals(this.rotation));
+        };
+        // Methods
+        TargetCamera.prototype._computeLocalCameraSpeed = function () {
+            var engine = this.getEngine();
+            return this.speed * ((engine.getDeltaTime() / (engine.getFps() * 10.0)));
+        };
+        // Target
+        TargetCamera.prototype.setTarget = function (target) {
+            this.upVector.normalize();
+            BABYLON.Matrix.LookAtLHToRef(this.position, target, this._defaultUpVector, this._camMatrix);
+            this._camMatrix.invert();
+            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
+            var vDir = target.subtract(this.position);
+            if (vDir.x >= 0.0) {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
+            }
+            else {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
+            }
+            this.rotation.z = 0;
+            if (isNaN(this.rotation.x)) {
+                this.rotation.x = 0;
+            }
+            if (isNaN(this.rotation.y)) {
+                this.rotation.y = 0;
+            }
+            if (isNaN(this.rotation.z)) {
+                this.rotation.z = 0;
+            }
+            if (this.rotationQuaternion) {
+                BABYLON.Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
+            }
+        };
+        TargetCamera.prototype.getTarget = function () {
+            return this._currentTarget;
+        };
+        TargetCamera.prototype._decideIfNeedsToMove = function () {
+            return Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
+        };
+        TargetCamera.prototype._updatePosition = function () {
+            this.position.addInPlace(this.cameraDirection);
+        };
+        TargetCamera.prototype._checkInputs = function () {
+            var needToMove = this._decideIfNeedsToMove();
+            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
+            // Move
+            if (needToMove) {
+                this._updatePosition();
+            }
+            // Rotate
+            if (needToRotate) {
+                this.rotation.x += this.cameraRotation.x;
+                this.rotation.y += this.cameraRotation.y;
+                if (!this.noRotationConstraint) {
+                    var limit = (Math.PI / 2) * 0.95;
+                    if (this.rotation.x > limit)
+                        this.rotation.x = limit;
+                    if (this.rotation.x < -limit)
+                        this.rotation.x = -limit;
+                }
+            }
+            // Inertia
+            if (needToMove) {
+                if (Math.abs(this.cameraDirection.x) < BABYLON.Epsilon) {
+                    this.cameraDirection.x = 0;
+                }
+                if (Math.abs(this.cameraDirection.y) < BABYLON.Epsilon) {
+                    this.cameraDirection.y = 0;
+                }
+                if (Math.abs(this.cameraDirection.z) < BABYLON.Epsilon) {
+                    this.cameraDirection.z = 0;
+                }
+                this.cameraDirection.scaleInPlace(this.inertia);
+            }
+            if (needToRotate) {
+                if (Math.abs(this.cameraRotation.x) < BABYLON.Epsilon) {
+                    this.cameraRotation.x = 0;
+                }
+                if (Math.abs(this.cameraRotation.y) < BABYLON.Epsilon) {
+                    this.cameraRotation.y = 0;
+                }
+                this.cameraRotation.scaleInPlace(this.inertia);
+            }
+            _super.prototype._checkInputs.call(this);
+        };
+        TargetCamera.prototype._updateCameraRotationMatrix = function () {
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.toRotationMatrix(this._cameraRotationMatrix);
+                //update the up vector!
+                BABYLON.Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this.upVector);
+            }
+            else {
+                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+            }
+        };
+        TargetCamera.prototype._getViewMatrix = function () {
+            if (!this.lockedTarget) {
+                // Compute
+                this._updateCameraRotationMatrix();
+                BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+                // Computing target and final matrix
+                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+            }
+            else {
+                this._currentTarget.copyFrom(this._getLockedTargetPosition());
+            }
+            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+            return this._viewMatrix;
+        };
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        TargetCamera.prototype.createRigCamera = function (name, cameraIndex) {
+            if (this.cameraRigMode !== BABYLON.Camera.RIG_MODE_NONE) {
+                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
+                if (this.cameraRigMode === BABYLON.Camera.RIG_MODE_VR) {
+                    if (!this.rotationQuaternion) {
+                        this.rotationQuaternion = new BABYLON.Quaternion();
+                    }
+                    rigCamera._cameraRigParams = {};
+                    rigCamera.rotationQuaternion = new BABYLON.Quaternion();
+                }
+                return rigCamera;
+            }
+            return null;
+        };
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        TargetCamera.prototype._updateRigCameras = function () {
+            var camLeft = this._rigCameras[0];
+            var camRight = this._rigCameras[1];
+            switch (this.cameraRigMode) {
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                    var leftSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : -1;
+                    var rightSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 : 1;
+                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft.position);
+                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
+                    camLeft.setTarget(this.getTarget());
+                    camRight.setTarget(this.getTarget());
+                    break;
+                case BABYLON.Camera.RIG_MODE_VR:
+                    camLeft.rotationQuaternion.copyFrom(this.rotationQuaternion);
+                    camRight.rotationQuaternion.copyFrom(this.rotationQuaternion);
+                    camLeft.position.copyFrom(this.position);
+                    camRight.position.copyFrom(this.position);
+                    break;
+            }
+            _super.prototype._updateRigCameras.call(this);
+        };
+        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
+            if (!this._rigCamTransformMatrix) {
+                this._rigCamTransformMatrix = new BABYLON.Matrix();
+            }
+            var target = this.getTarget();
+            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
+            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
+        };
+        TargetCamera.prototype.getTypeName = function () {
+            return "TargetCamera";
+        };
+        __decorate([
+            BABYLON.serializeAsVector3()
+        ], TargetCamera.prototype, "rotation", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], TargetCamera.prototype, "speed", void 0);
+        __decorate([
+            BABYLON.serializeAsMeshReference("lockedTargetId")
+        ], TargetCamera.prototype, "lockedTarget", void 0);
+        return TargetCamera;
+    })(BABYLON.Camera);
+    BABYLON.TargetCamera = TargetCamera;
+})(BABYLON || (BABYLON = {}));

+ 0 - 23
src/Cameras/babylon.targetCamera.ts

@@ -211,12 +211,6 @@
                 BABYLON.Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this.upVector);
             } else {
                 Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-                //if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
-                //    Matrix.LookAtLHToRef(Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
-                //    this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
-                //    this._lookAtTemp.invert();
-                //    this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
-                //}
             }
         }
 
@@ -237,21 +231,6 @@
             return this._viewMatrix;
         }
 
-        public _getVRViewMatrix(): Matrix {
-            this._updateCameraRotationMatrix();
-
-            Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-
-            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
-
-            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        }
-
         /**
          * @override
          * Override Camera.createRigCamera
@@ -264,8 +243,6 @@
                         this.rotationQuaternion = new Quaternion();
                     }
                     rigCamera._cameraRigParams = {};
-                    rigCamera._cameraRigParams.vrActualUp = new Vector3(0, 0, 0);
-                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
                     rigCamera.rotationQuaternion = new Quaternion();
                 }
                 return rigCamera;

Разлика између датотеке није приказан због своје велике величине
+ 918 - 1049
src/Canvas2d/babylon.canvas2d.js


Разлика између датотеке није приказан због своје велике величине
+ 741 - 735
src/Canvas2d/babylon.group2d.js


Разлика између датотеке није приказан због своје велике величине
+ 752 - 743
src/Canvas2d/babylon.renderablePrim2d.js


+ 93 - 94
src/Materials/Textures/babylon.dynamicTexture.js

@@ -1,94 +1,93 @@
-var __extends = (this && this.__extends) || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var BABYLON;
-(function (BABYLON) {
-    var DynamicTexture = (function (_super) {
-        __extends(DynamicTexture, _super);
-        function DynamicTexture(name, options, scene, generateMipMaps, samplingMode) {
-            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
-            _super.call(this, null, scene, !generateMipMaps);
-            this.name = name;
-            this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-            this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-            this._generateMipMaps = generateMipMaps;
-            if (options.getContext) {
-                this._canvas = options;
-                this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
-            }
-            else {
-                this._canvas = document.createElement("canvas");
-                if (options.width) {
-                    this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
-                }
-                else {
-                    this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
-                }
-            }
-            var textureSize = this.getSize();
-            this._canvas.width = textureSize.width;
-            this._canvas.height = textureSize.height;
-            this._context = this._canvas.getContext("2d");
-        }
-        Object.defineProperty(DynamicTexture.prototype, "canRescale", {
-            get: function () {
-                return true;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        DynamicTexture.prototype.scale = function (ratio) {
-            var textureSize = this.getSize();
-            textureSize.width *= ratio;
-            textureSize.height *= ratio;
-            this._canvas.width = textureSize.width;
-            this._canvas.height = textureSize.height;
-            this.releaseInternalTexture();
-            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
-        };
-        DynamicTexture.prototype.getContext = function () {
-            return this._context;
-        };
-        DynamicTexture.prototype.clear = function () {
-            var size = this.getSize();
-            this._context.fillRect(0, 0, size.width, size.height);
-        };
-        DynamicTexture.prototype.update = function (invertY) {
-            this.getScene().getEngine().updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY);
-        };
-        DynamicTexture.prototype.drawText = function (text, x, y, font, color, clearColor, invertY, update) {
-            if (update === void 0) { update = true; }
-            var size = this.getSize();
-            if (clearColor) {
-                this._context.fillStyle = clearColor;
-                this._context.fillRect(0, 0, size.width, size.height);
-            }
-            this._context.font = font;
-            if (x === null) {
-                var textSize = this._context.measureText(text);
-                x = (size.width - textSize.width) / 2;
-            }
-            this._context.fillStyle = color;
-            this._context.fillText(text, x, y);
-            if (update) {
-                this.update(invertY);
-            }
-        };
-        DynamicTexture.prototype.clone = function () {
-            var textureSize = this.getSize();
-            var newTexture = new DynamicTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-            // Dynamic Texture
-            newTexture.wrapU = this.wrapU;
-            newTexture.wrapV = this.wrapV;
-            return newTexture;
-        };
-        return DynamicTexture;
-    }(BABYLON.Texture));
-    BABYLON.DynamicTexture = DynamicTexture;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.dynamicTexture.js.map
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var BABYLON;
+(function (BABYLON) {
+    var DynamicTexture = (function (_super) {
+        __extends(DynamicTexture, _super);
+        function DynamicTexture(name, options, scene, generateMipMaps, samplingMode) {
+            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            _super.call(this, null, scene, !generateMipMaps);
+            this.name = name;
+            this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this._generateMipMaps = generateMipMaps;
+            if (options.getContext) {
+                this._canvas = options;
+                this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+            }
+            else {
+                this._canvas = document.createElement("canvas");
+                if (options.width) {
+                    this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                }
+                else {
+                    this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
+                }
+            }
+            var textureSize = this.getSize();
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+            this._context = this._canvas.getContext("2d");
+        }
+        Object.defineProperty(DynamicTexture.prototype, "canRescale", {
+            get: function () {
+                return true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        DynamicTexture.prototype.scale = function (ratio) {
+            var textureSize = this.getSize();
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+            this.releaseInternalTexture();
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        };
+        DynamicTexture.prototype.getContext = function () {
+            return this._context;
+        };
+        DynamicTexture.prototype.clear = function () {
+            var size = this.getSize();
+            this._context.fillRect(0, 0, size.width, size.height);
+        };
+        DynamicTexture.prototype.update = function (invertY) {
+            this.getScene().getEngine().updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY);
+        };
+        DynamicTexture.prototype.drawText = function (text, x, y, font, color, clearColor, invertY, update) {
+            if (update === void 0) { update = true; }
+            var size = this.getSize();
+            if (clearColor) {
+                this._context.fillStyle = clearColor;
+                this._context.fillRect(0, 0, size.width, size.height);
+            }
+            this._context.font = font;
+            if (x === null) {
+                var textSize = this._context.measureText(text);
+                x = (size.width - textSize.width) / 2;
+            }
+            this._context.fillStyle = color;
+            this._context.fillText(text, x, y);
+            if (update) {
+                this.update(invertY);
+            }
+        };
+        DynamicTexture.prototype.clone = function () {
+            var textureSize = this.getSize();
+            var newTexture = new DynamicTexture(this.name, textureSize, this.getScene(), this._generateMipMaps);
+            // Base texture
+            newTexture.hasAlpha = this.hasAlpha;
+            newTexture.level = this.level;
+            // Dynamic Texture
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            return newTexture;
+        };
+        return DynamicTexture;
+    })(BABYLON.Texture);
+    BABYLON.DynamicTexture = DynamicTexture;
+})(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.dynamicTexture.ts

@@ -88,7 +88,7 @@
 
         public clone(): DynamicTexture {
             var textureSize = this.getSize();
-            var newTexture = new DynamicTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+            var newTexture = new DynamicTexture(this.name, textureSize, this.getScene(), this._generateMipMaps);
 
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;

+ 83 - 84
src/Materials/Textures/babylon.videoTexture.js

@@ -1,84 +1,83 @@
-var __extends = (this && this.__extends) || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var BABYLON;
-(function (BABYLON) {
-    var VideoTexture = (function (_super) {
-        __extends(VideoTexture, _super);
-        /**
-         * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
-         * @param {BABYLON.Scene} scene is obviously the current scene.
-         * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
-         * @param {boolean} invertY is false by default but can be used to invert video on Y axis
-         * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
-         */
-        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
-            var _this = this;
-            if (generateMipMaps === void 0) { generateMipMaps = false; }
-            if (invertY === void 0) { invertY = false; }
-            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
-            _super.call(this, null, scene, !generateMipMaps, invertY);
-            this._autoLaunch = true;
-            var urls;
-            this.name = name;
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                this.video = urlsOrVideo;
-            }
-            else {
-                urls = urlsOrVideo;
-                this.video = document.createElement("video");
-                this.video.autoplay = false;
-                this.video.loop = true;
-            }
-            this._generateMipMaps = generateMipMaps;
-            this._samplingMode = samplingMode;
-            if (BABYLON.Tools.IsExponentOfTwo(this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(this.video.videoHeight)) {
-                this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-                this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-            }
-            else {
-                this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                this._generateMipMaps = false;
-            }
-            if (urls) {
-                this.video.addEventListener("canplaythrough", function () {
-                    _this._createTexture();
-                });
-                urls.forEach(function (url) {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    _this.video.appendChild(source);
-                });
-            }
-            else {
-                this._createTexture();
-            }
-            this._lastUpdate = BABYLON.Tools.Now;
-        }
-        VideoTexture.prototype._createTexture = function () {
-            this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode, false);
-            this._texture.isReady = true;
-        };
-        VideoTexture.prototype.update = function () {
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-            var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
-            }
-            this._lastUpdate = now;
-            this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
-        };
-        return VideoTexture;
-    }(BABYLON.Texture));
-    BABYLON.VideoTexture = VideoTexture;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.videoTexture.js.map
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var BABYLON;
+(function (BABYLON) {
+    var VideoTexture = (function (_super) {
+        __extends(VideoTexture, _super);
+        /**
+         * Creates a video texture.
+         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
+         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * @param {BABYLON.Scene} scene is obviously the current scene.
+         * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
+         * @param {boolean} invertY is false by default but can be used to invert video on Y axis
+         * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         */
+        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
+            var _this = this;
+            if (generateMipMaps === void 0) { generateMipMaps = false; }
+            if (invertY === void 0) { invertY = false; }
+            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            _super.call(this, null, scene, !generateMipMaps, invertY);
+            this._autoLaunch = true;
+            var urls;
+            this.name = name;
+            if (urlsOrVideo instanceof HTMLVideoElement) {
+                this.video = urlsOrVideo;
+            }
+            else {
+                urls = urlsOrVideo;
+                this.video = document.createElement("video");
+                this.video.autoplay = false;
+                this.video.loop = true;
+            }
+            this._generateMipMaps = generateMipMaps;
+            this._samplingMode = samplingMode;
+            if (BABYLON.Tools.IsExponentOfTwo(this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(this.video.videoHeight)) {
+                this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+            }
+            else {
+                this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                this._generateMipMaps = false;
+            }
+            if (urls) {
+                this.video.addEventListener("canplaythrough", function () {
+                    _this._createTexture();
+                });
+                urls.forEach(function (url) {
+                    var source = document.createElement("source");
+                    source.src = url;
+                    _this.video.appendChild(source);
+                });
+            }
+            else {
+                this._createTexture();
+            }
+            this._lastUpdate = BABYLON.Tools.Now;
+        }
+        VideoTexture.prototype._createTexture = function () {
+            this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
+            this._texture.isReady = true;
+        };
+        VideoTexture.prototype.update = function () {
+            if (this._autoLaunch) {
+                this._autoLaunch = false;
+                this.video.play();
+            }
+            var now = BABYLON.Tools.Now;
+            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
+                return false;
+            }
+            this._lastUpdate = now;
+            this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
+            return true;
+        };
+        return VideoTexture;
+    })(BABYLON.Texture);
+    BABYLON.VideoTexture = VideoTexture;
+})(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.videoTexture.ts

@@ -60,7 +60,7 @@
         }
 
         private _createTexture(): void {
-            this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode, false);
+            this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
             this._texture.isReady = true;
         }
 

Разлика између датотеке није приказан због своје велике величине
+ 3124 - 3128
src/Math/babylon.math.js


+ 14 - 14
src/Math/babylon.math.ts

@@ -304,16 +304,16 @@
 
             return this;
         }
-        
-       /**
-         * Multipy an RGBA Color4 value by another and return a new Color4 object
-         * @param color The Color4 (RGBA) value to multiply by
-         * @returns A new Color4.
-         */
+
+        /**
+          * Multipy an RGBA Color4 value by another and return a new Color4 object
+          * @param color The Color4 (RGBA) value to multiply by
+          * @returns A new Color4.
+          */
         public multiply(color: Color4): Color4 {
             return new Color4(this.r * color.r, this.g * color.g, this.b * color.b, this.a * color.a);
         }
-        
+
         /**
          * Multipy an RGBA Color4 value by another and push the result in a reference value
          * @param color The Color4 (RGBA) value to multiply by
@@ -325,10 +325,10 @@
             result.g = this.g * color.g;
             result.b = this.b * color.b;
             result.a = this.a * color.a;
-            
+
             return result;
         }
-        
+
         public toString(): string {
             return "{R: " + this.r + " G:" + this.g + " B:" + this.b + " A:" + this.a + "}";
         }
@@ -695,7 +695,7 @@
             let s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * p.x + (p0.x - p2.x) * p.y) * sign;
             let t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * p.x + (p1.x - p0.x) * p.y) * sign;
 
-            return s > 0 && t > 0 && (s + t) < 2 * a * sign;            
+            return s > 0 && t > 0 && (s + t) < 2 * a * sign;
         }
 
         public static Distance(value1: Vector2, value2: Vector2): number {
@@ -1132,9 +1132,10 @@
         }
 
         public static CrossToRef(left: Vector3, right: Vector3, result: Vector3): void {
-            result.x = left.y * right.z - left.z * right.y;
-            result.y = left.z * right.x - left.x * right.z;
-            result.z = left.x * right.y - left.y * right.x;
+            Tmp.Vector3[0].x = left.y * right.z - left.z * right.y;
+            Tmp.Vector3[0].y = left.z * right.x - left.x * right.z;
+            Tmp.Vector3[0].z = left.x * right.y - left.y * right.x;
+            result.copyFrom(Tmp.Vector3[0]);
         }
 
         public static Normalize(vector: Vector3): Vector3 {
@@ -3572,7 +3573,6 @@
             else {
                 normal0 = Vector3.Cross(vt, va);
                 Vector3.CrossToRef(normal0, vt, normal0);
-                //normal0 = Vector3.Cross(normal0, vt);
             }
             normal0.normalize();
             return normal0;

Разлика између датотеке није приказан због своје велике величине
+ 2376 - 2377
src/Mesh/babylon.mesh.js


+ 1 - 1
src/Mesh/babylon.mesh.ts

@@ -835,7 +835,7 @@
                     if (this._unIndexed) {
                         engine.drawUnIndexed(false, subMesh.verticesStart, subMesh.verticesCount, instancesCount);
                     } else {
-                        engine.draw(false, 0, subMesh.linesIndexCount, instancesCount);
+                        engine.draw(false, 0, instancesCount > 0 ? subMesh.linesIndexCount / 2 : subMesh.linesIndexCount, instancesCount);
                     }
                     break;
 

+ 1 - 1
src/Mesh/babylon.subMesh.ts

@@ -111,7 +111,7 @@
             this._renderingMesh.render(this, enableAlphaMode);
         }
 
-        public getLinesIndexBuffer(indices: number[] | Int32Array, engine): WebGLBuffer {
+        public getLinesIndexBuffer(indices: number[] | Int32Array, engine: Engine): WebGLBuffer {
             if (!this._linesIndexBuffer) {
                 var linesIndices = [];
 

+ 335 - 335
src/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -1,335 +1,335 @@
-var BABYLON;
-(function (BABYLON) {
-    var OimoJSPlugin = (function () {
-        function OimoJSPlugin(iterations) {
-            this.name = "OimoJSPlugin";
-            this._tmpImpostorsArray = [];
-            this._tmpPositionVector = BABYLON.Vector3.Zero();
-            this.world = new OIMO.World(1 / 60, 2, iterations, true);
-            this.world.clear();
-            //making sure no stats are calculated
-            this.world.isNoStat = true;
-        }
-        OimoJSPlugin.prototype.setGravity = function (gravity) {
-            this.world.gravity.copy(gravity);
-        };
-        OimoJSPlugin.prototype.setTimeStep = function (timeStep) {
-            this.world.timeStep = timeStep;
-        };
-        OimoJSPlugin.prototype.executeStep = function (delta, impostors) {
-            var _this = this;
-            impostors.forEach(function (impostor) {
-                impostor.beforeStep();
-            });
-            this.world.step();
-            impostors.forEach(function (impostor) {
-                impostor.afterStep();
-                //update the ordered impostors array
-                _this._tmpImpostorsArray[impostor.uniqueId] = impostor;
-            });
-            //check for collisions
-            var contact = this.world.contacts;
-            while (contact !== null) {
-                if (contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
-                    contact = contact.next;
-                    continue;
-                }
-                //is this body colliding with any other? get the impostor
-                var mainImpostor = this._tmpImpostorsArray[+contact.body1.name];
-                var collidingImpostor = this._tmpImpostorsArray[+contact.body2.name];
-                if (!mainImpostor || !collidingImpostor) {
-                    contact = contact.next;
-                    continue;
-                }
-                mainImpostor.onCollide({ body: collidingImpostor.physicsBody });
-                collidingImpostor.onCollide({ body: mainImpostor.physicsBody });
-                contact = contact.next;
-            }
-        };
-        OimoJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
-            var mass = impostor.physicsBody.massInfo.mass;
-            impostor.physicsBody.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
-        };
-        OimoJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
-            BABYLON.Tools.Warn("Oimo doesn't support applying force. Using impule instead.");
-            this.applyImpulse(impostor, force, contactPoint);
-        };
-        OimoJSPlugin.prototype.generatePhysicsBody = function (impostor) {
-            var _this = this;
-            //parent-child relationship. Does this impostor has a parent impostor?
-            if (impostor.parent) {
-                if (impostor.physicsBody) {
-                    this.removePhysicsBody(impostor);
-                    //TODO is that needed?
-                    impostor.forceUpdate();
-                }
-                return;
-            }
-            if (impostor.isBodyInitRequired()) {
-                var bodyConfig = {
-                    name: impostor.uniqueId,
-                    //Oimo must have mass, also for static objects.
-                    config: [impostor.getParam("mass") || 1, impostor.getParam("friction"), impostor.getParam("restitution")],
-                    size: [],
-                    type: [],
-                    pos: [],
-                    rot: [],
-                    move: impostor.getParam("mass") !== 0,
-                    //Supporting older versions of Oimo
-                    world: this.world
-                };
-                var impostors = [impostor];
-                function addToArray(parent) {
-                    if (!parent.getChildMeshes)
-                        return;
-                    parent.getChildMeshes().forEach(function (m) {
-                        if (m.physicsImpostor) {
-                            impostors.push(m.physicsImpostor);
-                            m.physicsImpostor._init();
-                        }
-                    });
-                }
-                addToArray(impostor.object);
-                function checkWithEpsilon(value) {
-                    return Math.max(value, BABYLON.PhysicsEngine.Epsilon);
-                }
-                impostors.forEach(function (i) {
-                    //get the correct bounding box
-                    var oldQuaternion = i.object.rotationQuaternion;
-                    var rot = new OIMO.Euler().setFromQuaternion({
-                        x: impostor.object.rotationQuaternion.x,
-                        y: impostor.object.rotationQuaternion.y,
-                        z: impostor.object.rotationQuaternion.z,
-                        s: impostor.object.rotationQuaternion.w
-                    });
-                    var extendSize = i.getObjectExtendSize();
-                    if (i === impostor) {
-                        var center = impostor.getObjectCenter();
-                        impostor.object.position.subtractToRef(center, _this._tmpPositionVector);
-                        //Can also use Array.prototype.push.apply
-                        bodyConfig.pos.push(center.x);
-                        bodyConfig.pos.push(center.y);
-                        bodyConfig.pos.push(center.z);
-                        //tmp solution
-                        bodyConfig.rot.push(rot.x / (OIMO.degtorad || OIMO.TO_RAD));
-                        bodyConfig.rot.push(rot.y / (OIMO.degtorad || OIMO.TO_RAD));
-                        bodyConfig.rot.push(rot.z / (OIMO.degtorad || OIMO.TO_RAD));
-                    }
-                    else {
-                        bodyConfig.pos.push(i.object.position.x);
-                        bodyConfig.pos.push(i.object.position.y);
-                        bodyConfig.pos.push(i.object.position.z);
-                        //tmp solution until https://github.com/lo-th/Oimo.js/pull/37 is merged
-                        bodyConfig.rot.push(0);
-                        bodyConfig.rot.push(0);
-                        bodyConfig.rot.push(0);
-                    }
-                    // register mesh
-                    switch (i.type) {
-                        case BABYLON.PhysicsImpostor.ParticleImpostor:
-                            BABYLON.Tools.Warn("No Particle support in Oimo.js. using SphereImpostor instead");
-                        case BABYLON.PhysicsImpostor.SphereImpostor:
-                            var radiusX = extendSize.x;
-                            var radiusY = extendSize.y;
-                            var radiusZ = extendSize.z;
-                            var size = Math.max(checkWithEpsilon(radiusX), checkWithEpsilon(radiusY), checkWithEpsilon(radiusZ)) / 2;
-                            bodyConfig.type.push('sphere');
-                            //due to the way oimo works with compounds, add 3 times
-                            bodyConfig.size.push(size);
-                            bodyConfig.size.push(size);
-                            bodyConfig.size.push(size);
-                            break;
-                        case BABYLON.PhysicsImpostor.CylinderImpostor:
-                            var sizeX = checkWithEpsilon(extendSize.x) / 2;
-                            var sizeY = checkWithEpsilon(extendSize.y);
-                            bodyConfig.type.push('cylinder');
-                            bodyConfig.size.push(sizeX);
-                            bodyConfig.size.push(sizeY);
-                            //due to the way oimo works with compounds, add one more value.
-                            bodyConfig.size.push(sizeY);
-                            break;
-                        case BABYLON.PhysicsImpostor.PlaneImpostor:
-                        case BABYLON.PhysicsImpostor.BoxImpostor:
-                        default:
-                            var sizeX = checkWithEpsilon(extendSize.x);
-                            var sizeY = checkWithEpsilon(extendSize.y);
-                            var sizeZ = checkWithEpsilon(extendSize.z);
-                            bodyConfig.type.push('box');
-                            bodyConfig.size.push(sizeX);
-                            bodyConfig.size.push(sizeY);
-                            bodyConfig.size.push(sizeZ);
-                            break;
-                    }
-                    //actually not needed, but hey...
-                    i.object.rotationQuaternion = oldQuaternion;
-                });
-                impostor.physicsBody = new OIMO.Body(bodyConfig).body; //this.world.add(bodyConfig);
-            }
-            else {
-                this._tmpPositionVector.copyFromFloats(0, 0, 0);
-            }
-            impostor.setDeltaPosition(this._tmpPositionVector);
-            //this._tmpPositionVector.addInPlace(impostor.mesh.getBoundingInfo().boundingBox.center);
-            //this.setPhysicsBodyTransformation(impostor, this._tmpPositionVector, impostor.mesh.rotationQuaternion);
-        };
-        OimoJSPlugin.prototype.removePhysicsBody = function (impostor) {
-            //impostor.physicsBody.dispose();
-            //Same as : (older oimo versions)
-            this.world.removeRigidBody(impostor.physicsBody);
-        };
-        OimoJSPlugin.prototype.generateJoint = function (impostorJoint) {
-            var mainBody = impostorJoint.mainImpostor.physicsBody;
-            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
-            if (!mainBody || !connectedBody) {
-                return;
-            }
-            var jointData = impostorJoint.joint.jointData;
-            var options = jointData.nativeParams || {};
-            var type;
-            var nativeJointData = {
-                body1: mainBody,
-                body2: connectedBody,
-                axe1: options.axe1 || (jointData.mainAxis ? jointData.mainAxis.asArray() : null),
-                axe2: options.axe2 || (jointData.connectedAxis ? jointData.connectedAxis.asArray() : null),
-                pos1: options.pos1 || (jointData.mainPivot ? jointData.mainPivot.asArray() : null),
-                pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
-                min: options.min,
-                max: options.max,
-                collision: options.collision || jointData.collision,
-                spring: options.spring,
-                //supporting older version of Oimo
-                world: this.world
-            };
-            switch (impostorJoint.joint.type) {
-                case BABYLON.PhysicsJoint.BallAndSocketJoint:
-                    type = "jointBall";
-                    break;
-                case BABYLON.PhysicsJoint.SpringJoint:
-                    BABYLON.Tools.Warn("Oimo.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
-                    var springData = jointData;
-                    nativeJointData.min = springData.length || nativeJointData.min;
-                    //Max should also be set, just make sure it is at least min
-                    nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
-                case BABYLON.PhysicsJoint.DistanceJoint:
-                    type = "jointDistance";
-                    nativeJointData.max = jointData.maxDistance;
-                    break;
-                case BABYLON.PhysicsJoint.PrismaticJoint:
-                    type = "jointPrisme";
-                    break;
-                case BABYLON.PhysicsJoint.SliderJoint:
-                    type = "jointSlide";
-                    break;
-                case BABYLON.PhysicsJoint.WheelJoint:
-                    type = "jointWheel";
-                    break;
-                case BABYLON.PhysicsJoint.HingeJoint:
-                default:
-                    type = "jointHinge";
-                    break;
-            }
-            nativeJointData.type = type;
-            impostorJoint.joint.physicsJoint = new OIMO.Link(nativeJointData).joint; //this.world.add(nativeJointData);
-        };
-        OimoJSPlugin.prototype.removeJoint = function (impostorJoint) {
-            //Bug in Oimo prevents us from disposing a joint in the playground
-            //joint.joint.physicsJoint.dispose();
-            //So we will bruteforce it!
-            try {
-                this.world.removeJoint(impostorJoint.joint.physicsJoint);
-            }
-            catch (e) {
-                BABYLON.Tools.Warn(e);
-            }
-        };
-        OimoJSPlugin.prototype.isSupported = function () {
-            return OIMO !== undefined;
-        };
-        OimoJSPlugin.prototype.setTransformationFromPhysicsBody = function (impostor) {
-            if (!impostor.physicsBody.sleeping) {
-                //TODO check that
-                if (impostor.physicsBody.shapes.next) {
-                    var parentShape = this._getLastShape(impostor.physicsBody);
-                    impostor.object.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
-                    impostor.object.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
-                    impostor.object.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
-                }
-                else {
-                    impostor.object.position.copyFrom(impostor.physicsBody.getPosition());
-                }
-                impostor.object.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
-            }
-        };
-        OimoJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
-            var body = impostor.physicsBody;
-            body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
-            body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
-            body.syncShapes();
-            body.awake();
-        };
-        OimoJSPlugin.prototype._getLastShape = function (body) {
-            var lastShape = body.shapes;
-            while (lastShape.next) {
-                lastShape = lastShape.next;
-            }
-            return lastShape;
-        };
-        OimoJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
-            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
-        };
-        OimoJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
-            impostor.physicsBody.angularVelocity.init(velocity.x, velocity.y, velocity.z);
-        };
-        OimoJSPlugin.prototype.getLinearVelocity = function (impostor) {
-            var v = impostor.physicsBody.linearVelocity;
-            if (!v)
-                return null;
-            return new BABYLON.Vector3(v.x, v.y, v.z);
-        };
-        OimoJSPlugin.prototype.getAngularVelocity = function (impostor) {
-            var v = impostor.physicsBody.angularVelocity;
-            if (!v)
-                return null;
-            return new BABYLON.Vector3(v.x, v.y, v.z);
-        };
-        OimoJSPlugin.prototype.setBodyMass = function (impostor, mass) {
-            var staticBody = mass === 0;
-            //this will actually set the body's density and not its mass.
-            //But this is how oimo treats the mass variable.
-            impostor.physicsBody.shapes.density = staticBody ? 1 : mass;
-            impostor.physicsBody.setupMass(staticBody ? 0x2 : 0x1);
-        };
-        OimoJSPlugin.prototype.sleepBody = function (impostor) {
-            impostor.physicsBody.sleep();
-        };
-        OimoJSPlugin.prototype.wakeUpBody = function (impostor) {
-            impostor.physicsBody.awake();
-        };
-        OimoJSPlugin.prototype.updateDistanceJoint = function (joint, maxDistance, minDistance) {
-            joint.physicsJoint.limitMotoe.upperLimit = maxDistance;
-            if (minDistance !== void 0) {
-                joint.physicsJoint.limitMotoe.lowerLimit = minDistance;
-            }
-        };
-        OimoJSPlugin.prototype.setMotor = function (joint, speed, maxForce, motorIndex) {
-            //TODO separate rotational and transational motors.
-            var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
-            if (motor) {
-                motor.setMotor(speed, maxForce);
-            }
-        };
-        OimoJSPlugin.prototype.setLimit = function (joint, upperLimit, lowerLimit, motorIndex) {
-            //TODO separate rotational and transational motors.
-            var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
-            if (motor) {
-                motor.setLimit(upperLimit, lowerLimit === void 0 ? -upperLimit : lowerLimit);
-            }
-        };
-        OimoJSPlugin.prototype.dispose = function () {
-            this.world.clear();
-        };
-        return OimoJSPlugin;
-    }());
-    BABYLON.OimoJSPlugin = OimoJSPlugin;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.oimoJSPlugin.js.map
+var BABYLON;
+(function (BABYLON) {
+    var OimoJSPlugin = (function () {
+        function OimoJSPlugin(iterations) {
+            this.name = "OimoJSPlugin";
+            this._tmpImpostorsArray = [];
+            this._tmpPositionVector = BABYLON.Vector3.Zero();
+            this.world = new OIMO.World(1 / 60, 2, iterations, true);
+            this.world.clear();
+            //making sure no stats are calculated
+            this.world.isNoStat = true;
+        }
+        OimoJSPlugin.prototype.setGravity = function (gravity) {
+            this.world.gravity.copy(gravity);
+        };
+        OimoJSPlugin.prototype.setTimeStep = function (timeStep) {
+            this.world.timeStep = timeStep;
+        };
+        OimoJSPlugin.prototype.executeStep = function (delta, impostors) {
+            var _this = this;
+            impostors.forEach(function (impostor) {
+                impostor.beforeStep();
+            });
+            this.world.step();
+            impostors.forEach(function (impostor) {
+                impostor.afterStep();
+                //update the ordered impostors array
+                _this._tmpImpostorsArray[impostor.uniqueId] = impostor;
+            });
+            //check for collisions
+            var contact = this.world.contacts;
+            while (contact !== null) {
+                if (contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
+                    contact = contact.next;
+                    continue;
+                }
+                //is this body colliding with any other? get the impostor
+                var mainImpostor = this._tmpImpostorsArray[+contact.body1.name];
+                var collidingImpostor = this._tmpImpostorsArray[+contact.body2.name];
+                if (!mainImpostor || !collidingImpostor) {
+                    contact = contact.next;
+                    continue;
+                }
+                mainImpostor.onCollide({ body: collidingImpostor.physicsBody });
+                collidingImpostor.onCollide({ body: mainImpostor.physicsBody });
+                contact = contact.next;
+            }
+        };
+        OimoJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
+            var mass = impostor.physicsBody.massInfo.mass;
+            impostor.physicsBody.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
+        };
+        OimoJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
+            BABYLON.Tools.Warn("Oimo doesn't support applying force. Using impule instead.");
+            this.applyImpulse(impostor, force, contactPoint);
+        };
+        OimoJSPlugin.prototype.generatePhysicsBody = function (impostor) {
+            var _this = this;
+            //parent-child relationship. Does this impostor has a parent impostor?
+            if (impostor.parent) {
+                if (impostor.physicsBody) {
+                    this.removePhysicsBody(impostor);
+                    //TODO is that needed?
+                    impostor.forceUpdate();
+                }
+                return;
+            }
+            if (impostor.isBodyInitRequired()) {
+                var bodyConfig = {
+                    name: impostor.uniqueId,
+                    //Oimo must have mass, also for static objects.
+                    config: [impostor.getParam("mass") || 1, impostor.getParam("friction"), impostor.getParam("restitution")],
+                    size: [],
+                    type: [],
+                    pos: [],
+                    rot: [],
+                    move: impostor.getParam("mass") !== 0,
+                    //Supporting older versions of Oimo
+                    world: this.world
+                };
+                var impostors = [impostor];
+                function addToArray(parent) {
+                    if (!parent.getChildMeshes)
+                        return;
+                    parent.getChildMeshes().forEach(function (m) {
+                        if (m.physicsImpostor) {
+                            impostors.push(m.physicsImpostor);
+                            m.physicsImpostor._init();
+                        }
+                    });
+                }
+                addToArray(impostor.object);
+                function checkWithEpsilon(value) {
+                    return Math.max(value, BABYLON.PhysicsEngine.Epsilon);
+                }
+                impostors.forEach(function (i) {
+                    //get the correct bounding box
+                    var oldQuaternion = i.object.rotationQuaternion;
+                    var rot = new OIMO.Euler().setFromQuaternion({
+                        x: impostor.object.rotationQuaternion.x,
+                        y: impostor.object.rotationQuaternion.y,
+                        z: impostor.object.rotationQuaternion.z,
+                        s: impostor.object.rotationQuaternion.w
+                    });
+                    var extendSize = i.getObjectExtendSize();
+                    if (i === impostor) {
+                        var center = impostor.getObjectCenter();
+                        impostor.object.position.subtractToRef(center, _this._tmpPositionVector);
+                        //Can also use Array.prototype.push.apply
+                        bodyConfig.pos.push(center.x);
+                        bodyConfig.pos.push(center.y);
+                        bodyConfig.pos.push(center.z);
+                        //tmp solution
+                        bodyConfig.rot.push(rot.x / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.y / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.z / (OIMO.degtorad || OIMO.TO_RAD));
+                    }
+                    else {
+                        bodyConfig.pos.push(i.object.position.x);
+                        bodyConfig.pos.push(i.object.position.y);
+                        bodyConfig.pos.push(i.object.position.z);
+                        //tmp solution until https://github.com/lo-th/Oimo.js/pull/37 is merged
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
+                    }
+                    // register mesh
+                    switch (i.type) {
+                        case BABYLON.PhysicsImpostor.ParticleImpostor:
+                            BABYLON.Tools.Warn("No Particle support in Oimo.js. using SphereImpostor instead");
+                        case BABYLON.PhysicsImpostor.SphereImpostor:
+                            var radiusX = extendSize.x;
+                            var radiusY = extendSize.y;
+                            var radiusZ = extendSize.z;
+                            var size = Math.max(checkWithEpsilon(radiusX), checkWithEpsilon(radiusY), checkWithEpsilon(radiusZ)) / 2;
+                            bodyConfig.type.push('sphere');
+                            //due to the way oimo works with compounds, add 3 times
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            break;
+                        case BABYLON.PhysicsImpostor.CylinderImpostor:
+                            var sizeX = checkWithEpsilon(extendSize.x) / 2;
+                            var sizeY = checkWithEpsilon(extendSize.y);
+                            bodyConfig.type.push('cylinder');
+                            bodyConfig.size.push(sizeX);
+                            bodyConfig.size.push(sizeY);
+                            //due to the way oimo works with compounds, add one more value.
+                            bodyConfig.size.push(sizeY);
+                            break;
+                        case BABYLON.PhysicsImpostor.PlaneImpostor:
+                        case BABYLON.PhysicsImpostor.BoxImpostor:
+                        default:
+                            var sizeX = checkWithEpsilon(extendSize.x);
+                            var sizeY = checkWithEpsilon(extendSize.y);
+                            var sizeZ = checkWithEpsilon(extendSize.z);
+                            bodyConfig.type.push('box');
+                            bodyConfig.size.push(sizeX);
+                            bodyConfig.size.push(sizeY);
+                            bodyConfig.size.push(sizeZ);
+                            break;
+                    }
+                    //actually not needed, but hey...
+                    i.object.rotationQuaternion = oldQuaternion;
+                });
+                impostor.physicsBody = new OIMO.Body(bodyConfig).body; //this.world.add(bodyConfig);
+            }
+            else {
+                this._tmpPositionVector.copyFromFloats(0, 0, 0);
+            }
+            impostor.setDeltaPosition(this._tmpPositionVector);
+            //this._tmpPositionVector.addInPlace(impostor.mesh.getBoundingInfo().boundingBox.center);
+            //this.setPhysicsBodyTransformation(impostor, this._tmpPositionVector, impostor.mesh.rotationQuaternion);
+        };
+        OimoJSPlugin.prototype.removePhysicsBody = function (impostor) {
+            //impostor.physicsBody.dispose();
+            //Same as : (older oimo versions)
+            this.world.removeRigidBody(impostor.physicsBody);
+        };
+        OimoJSPlugin.prototype.generateJoint = function (impostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+            if (!mainBody || !connectedBody) {
+                return;
+            }
+            var jointData = impostorJoint.joint.jointData;
+            var options = jointData.nativeParams || {};
+            var type;
+            var nativeJointData = {
+                body1: mainBody,
+                body2: connectedBody,
+                axe1: options.axe1 || (jointData.mainAxis ? jointData.mainAxis.asArray() : null),
+                axe2: options.axe2 || (jointData.connectedAxis ? jointData.connectedAxis.asArray() : null),
+                pos1: options.pos1 || (jointData.mainPivot ? jointData.mainPivot.asArray() : null),
+                pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
+                min: options.min,
+                max: options.max,
+                collision: options.collision || jointData.collision,
+                spring: options.spring,
+                //supporting older version of Oimo
+                world: this.world
+            };
+            switch (impostorJoint.joint.type) {
+                case BABYLON.PhysicsJoint.BallAndSocketJoint:
+                    type = "jointBall";
+                    break;
+                case BABYLON.PhysicsJoint.SpringJoint:
+                    BABYLON.Tools.Warn("Oimo.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
+                    var springData = jointData;
+                    nativeJointData.min = springData.length || nativeJointData.min;
+                    //Max should also be set, just make sure it is at least min
+                    nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
+                case BABYLON.PhysicsJoint.DistanceJoint:
+                    type = "jointDistance";
+                    nativeJointData.max = jointData.maxDistance;
+                    break;
+                case BABYLON.PhysicsJoint.PrismaticJoint:
+                    type = "jointPrisme";
+                    break;
+                case BABYLON.PhysicsJoint.SliderJoint:
+                    type = "jointSlide";
+                    break;
+                case BABYLON.PhysicsJoint.WheelJoint:
+                    type = "jointWheel";
+                    break;
+                case BABYLON.PhysicsJoint.HingeJoint:
+                default:
+                    type = "jointHinge";
+                    break;
+            }
+            nativeJointData.type = type;
+            impostorJoint.joint.physicsJoint = new OIMO.Link(nativeJointData).joint; //this.world.add(nativeJointData);
+        };
+        OimoJSPlugin.prototype.removeJoint = function (impostorJoint) {
+            //Bug in Oimo prevents us from disposing a joint in the playground
+            //joint.joint.physicsJoint.dispose();
+            //So we will bruteforce it!
+            try {
+                this.world.removeJoint(impostorJoint.joint.physicsJoint);
+            }
+            catch (e) {
+                BABYLON.Tools.Warn(e);
+            }
+        };
+        OimoJSPlugin.prototype.isSupported = function () {
+            return OIMO !== undefined;
+        };
+        OimoJSPlugin.prototype.setTransformationFromPhysicsBody = function (impostor) {
+            if (!impostor.physicsBody.sleeping) {
+                //TODO check that
+                if (impostor.physicsBody.shapes.next) {
+                    var parentShape = this._getLastShape(impostor.physicsBody);
+                    impostor.object.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
+                    impostor.object.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
+                    impostor.object.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
+                }
+                else {
+                    impostor.object.position.copyFrom(impostor.physicsBody.getPosition());
+                }
+                impostor.object.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
+                impostor.object.rotationQuaternion.normalize();
+            }
+        };
+        OimoJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
+            var body = impostor.physicsBody;
+            body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
+            body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
+            body.syncShapes();
+            body.awake();
+        };
+        OimoJSPlugin.prototype._getLastShape = function (body) {
+            var lastShape = body.shapes;
+            while (lastShape.next) {
+                lastShape = lastShape.next;
+            }
+            return lastShape;
+        };
+        OimoJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
+            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+        };
+        OimoJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
+            impostor.physicsBody.angularVelocity.init(velocity.x, velocity.y, velocity.z);
+        };
+        OimoJSPlugin.prototype.getLinearVelocity = function (impostor) {
+            var v = impostor.physicsBody.linearVelocity;
+            if (!v)
+                return null;
+            return new BABYLON.Vector3(v.x, v.y, v.z);
+        };
+        OimoJSPlugin.prototype.getAngularVelocity = function (impostor) {
+            var v = impostor.physicsBody.angularVelocity;
+            if (!v)
+                return null;
+            return new BABYLON.Vector3(v.x, v.y, v.z);
+        };
+        OimoJSPlugin.prototype.setBodyMass = function (impostor, mass) {
+            var staticBody = mass === 0;
+            //this will actually set the body's density and not its mass.
+            //But this is how oimo treats the mass variable.
+            impostor.physicsBody.shapes.density = staticBody ? 1 : mass;
+            impostor.physicsBody.setupMass(staticBody ? 0x2 : 0x1);
+        };
+        OimoJSPlugin.prototype.sleepBody = function (impostor) {
+            impostor.physicsBody.sleep();
+        };
+        OimoJSPlugin.prototype.wakeUpBody = function (impostor) {
+            impostor.physicsBody.awake();
+        };
+        OimoJSPlugin.prototype.updateDistanceJoint = function (joint, maxDistance, minDistance) {
+            joint.physicsJoint.limitMotoe.upperLimit = maxDistance;
+            if (minDistance !== void 0) {
+                joint.physicsJoint.limitMotoe.lowerLimit = minDistance;
+            }
+        };
+        OimoJSPlugin.prototype.setMotor = function (joint, speed, maxForce, motorIndex) {
+            //TODO separate rotational and transational motors.
+            var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
+            if (motor) {
+                motor.setMotor(speed, maxForce);
+            }
+        };
+        OimoJSPlugin.prototype.setLimit = function (joint, upperLimit, lowerLimit, motorIndex) {
+            //TODO separate rotational and transational motors.
+            var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
+            if (motor) {
+                motor.setLimit(upperLimit, lowerLimit === void 0 ? -upperLimit : lowerLimit);
+            }
+        };
+        OimoJSPlugin.prototype.dispose = function () {
+            this.world.clear();
+        };
+        return OimoJSPlugin;
+    })();
+    BABYLON.OimoJSPlugin = OimoJSPlugin;
+})(BABYLON || (BABYLON = {}));

+ 1 - 0
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -307,6 +307,7 @@ module BABYLON {
 
                 }
                 impostor.object.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
+                impostor.object.rotationQuaternion.normalize();
             }
         }
 

+ 2 - 13
src/Shaders/ShadersInclude/pbrFunctions.fx

@@ -86,14 +86,14 @@ vec3 FresnelSchlickEnvironmentGGX(float VdotN, vec3 reflectance0, vec3 reflectan
 }
 
 // Cook Torance Specular computation.
-vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 specularColor)
+vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 specularColor, vec3 reflectance90)
 {
     float alphaG = convertRoughnessToAverageSlope(roughness);
     float distribution = normalDistributionFunction_TrowbridgeReitzGGX(NdotH, alphaG);
     float visibility = smithVisibilityG_TrowbridgeReitzGGX_Walter(NdotL, NdotV, alphaG);
     visibility /= (4.0 * NdotL * NdotV); // Cook Torance Denominator  integated in viibility to avoid issues when visibility function changes.
 
-    vec3 fresnel = fresnelSchlickGGX(VdotH, specularColor, vec3(1., 1., 1.));
+    vec3 fresnel = fresnelSchlickGGX(VdotH, specularColor, reflectance90);
 
     float specTerm = max(0., visibility * distribution) * NdotL;
     return fresnel * specTerm * kPi; // TODO: audit pi constants
@@ -150,17 +150,6 @@ vec3 toGammaSpace(vec3 color)
     return vec3(pow(color.r, 1.0 / 2.2), pow(color.g, 1.0 / 2.2), pow(color.b, 1.0 / 2.2));
 }
 
-float computeLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
-{
-    #ifdef USEPHYSICALLIGHTFALLOFF
-        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
-        return lightDistanceFalloff;
-    #else
-        float lightFalloff = max(0., 1.0 - length(lightOffset) / range);
-        return lightFalloff;
-    #endif
-}
-
 #ifdef CAMERATONEMAP
     vec3 toneMaps(vec3 color)
     {

+ 70 - 43
src/Shaders/ShadersInclude/pbrLightFunctions.fx

@@ -7,7 +7,48 @@ struct lightingInfo
     #endif
 };
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
+float computeDistanceLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
+{   
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
+    #else
+        float lightDistanceFalloff = max(0., 1.0 - length(lightOffset) / range);
+    #endif
+    
+    return lightDistanceFalloff;
+}
+
+float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float lightAngle, float exponent)
+{
+    float falloff = 0.0;
+    
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        float cosHalfAngle = cos(lightAngle * 0.5);
+        const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
+
+        // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
+        // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
+        // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle) 
+        // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
+        // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
+        float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
+    
+        // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff; 
+        // not directional light type)
+        vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
+        falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
+    #else
+        float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
+        if (cosAngle >= lightAngle)
+        {
+            falloff = max(0., pow(cosAngle, exponent));
+        }
+    #endif
+    
+    return falloff;
+}
+
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     vec3 lightDirection;
@@ -19,7 +60,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
     {
         vec3 lightOffset = lightData.xyz - vPositionW;
         float lightDistanceSquared = dot(lightOffset, lightOffset);
-        attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
+        attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
         
         lightDistance = sqrt(lightDistanceSquared);
         lightDirection = normalize(lightOffset);
@@ -46,65 +87,51 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
         // Specular
         float NdotH = max(0.00000000001, dot(vNormal, H));
 
-        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
         result.specular = specTerm * attenuation;
     #endif
 
     return result;
 }
 
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     vec3 lightOffset = lightData.xyz - vPositionW;
-    vec3 lightVectorW = normalize(lightOffset);
+    vec3 directionToLightCenterW = normalize(lightOffset);
 
-    // diffuse
-    float cosAngle = max(0.000000000000001, dot(-lightDirection.xyz, lightVectorW));
+    // Distance falloff.
+    float lightDistanceSquared = dot(lightOffset, lightOffset);
+    float attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
     
-    if (cosAngle >= lightDirection.w)
-    {
-        cosAngle = max(0., pow(cosAngle, lightData.w));
-        
-        // Inverse squared falloff.
-        float lightDistanceSquared = dot(lightOffset, lightOffset);
-        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
-        
-        // Directional falloff.
-        attenuation *= cosAngle;
-        
-        // Roughness.
-        float lightDistance = sqrt(lightDistanceSquared);
-        roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
-        
-        // Diffuse
-        vec3 H = normalize(viewDirectionW - lightDirection.xyz);
-        NdotL = max(0.00000000001, dot(vNormal, -lightDirection.xyz));
-        float VdotH = clamp(dot(viewDirectionW, H), 0.00000000001, 1.0);
-
-        float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
-        result.diffuse = diffuseTerm * diffuseColor * attenuation;
-
-        #ifdef SPECULARTERM
-            // Specular
-            float NdotH = max(0.00000000001, dot(vNormal, H));
-
-            vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
-            result.specular = specTerm  * attenuation;
-        #endif
+    // Directional falloff.
+    float directionalAttenuation = computeDirectionalLightFalloff(lightDirection.xyz, directionToLightCenterW, lightDirection.w, lightData.w);
+    attenuation *= directionalAttenuation;
+    
+    // Roughness.
+    float lightDistance = sqrt(lightDistanceSquared);
+    roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
+    
+    // Diffuse
+    vec3 H = normalize(viewDirectionW - lightDirection.xyz);
+    NdotL = max(0.00000000001, dot(vNormal, -lightDirection.xyz));
+    float VdotH = clamp(dot(viewDirectionW, H), 0.00000000001, 1.0);
 
-        return result;
-    }
+    float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
+    result.diffuse = diffuseTerm * diffuseColor * attenuation;
 
-    result.diffuse = vec3(0.);
     #ifdef SPECULARTERM
-        result.specular = vec3(0.);
+        // Specular
+        float NdotH = max(0.00000000001, dot(vNormal, H));
+
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
+        result.specular = specTerm  * attenuation;
     #endif
 
     return result;
 }
 
-lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, out float NdotL) {
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     // Roughness
@@ -122,7 +149,7 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
         NdotL = max(0.00000000001, NdotL);
         float VdotH = clamp(0.00000000001, 1.0, dot(viewDirectionW, H));
 
-        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
         result.specular = specTerm;
     #endif
 

+ 3 - 3
src/Shaders/ShadersInclude/pbrLightFunctionsCall.fx

@@ -3,13 +3,13 @@
         vec3 vLightSpecular{X} = vec3(0.0);
     #endif
     #ifdef SPOTLIGHT{X}
-        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
+        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     #ifdef HEMILIGHT{X}
-        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, NdotL);
+        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
-        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
+        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     
     #ifdef SHADOW{X}

+ 10 - 4
src/Shaders/pbr.fragment.fx

@@ -293,6 +293,15 @@ void main(void) {
 	float NdotL = -1.;
 	lightingInfo info;
 
+	// Compute reflectance.
+	float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
+
+	// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+    // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+	vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
+	vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
+
 #include<pbrLightFunctionsCall>[0..maxSimultaneousLights]
 
 #ifdef SPECULARTERM
@@ -466,9 +475,7 @@ void main(void) {
 	environmentRadiance *= vLightingIntensity.z;
 	environmentIrradiance *= vLightingIntensity.z;
 
-	// Compute reflection specular fresnel
-	vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
-	vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0);
+	// Specular Environment Fresnel.
 	vec3 specularEnvironmentReflectance = FresnelSchlickEnvironmentGGX(clamp(NdotV, 0., 1.), specularEnvironmentR0, specularEnvironmentR90, sqrt(microSurface));
 
 	// Compute refractance
@@ -510,7 +517,6 @@ void main(void) {
 #endif
 
 	// Apply Energy Conservation taking in account the environment level only if the environment is present.
-	float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
 	surfaceAlbedo.rgb = (1. - reflectance) * surfaceAlbedo.rgb;
 
 	refractance *= vLightingIntensity.z;

Разлика између датотеке није приказан због своје велике величине
+ 1012 - 1012
src/Tools/babylon.tools.js


+ 1 - 0
src/Tools/babylon.tools.ts

@@ -684,6 +684,7 @@
             });
 
             scene.incrementRenderId();
+            scene.resetCachedMaterial();
             texture.render(true);
             texture.dispose();
 

Разлика између датотеке није приказан због своје велике величине
+ 2137 - 2111
src/babylon.engine.js


+ 43 - 8
src/babylon.engine.ts

@@ -162,7 +162,7 @@
         public maxCubemapTextureSize: number;
         public maxRenderTextureSize: number;
         public standardDerivatives: boolean;
-        public s3tc : WEBGL_compressed_texture_s3tc;
+        public s3tc: WEBGL_compressed_texture_s3tc;
         public textureFloat: boolean;
         public textureAnisotropicFilterExtension: EXT_texture_filter_anisotropic;
         public maxAnisotropy: number;
@@ -1452,7 +1452,7 @@
             this._gl.colorMask(enable, enable, enable, enable);
         }
 
-        public setAlphaMode(mode: number, noDepthWriteChange: boolean=false): void {
+        public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
             if (this._alphaMode === mode) {
                 return;
             }
@@ -1726,12 +1726,12 @@
             return texture;
         }
 
-        public createDynamicTexture(width: number, height: number, generateMipMaps: boolean, samplingMode: number, forceExponantOfTwo = true): WebGLTexture {
+        public createDynamicTexture(width: number, height: number, generateMipMaps: boolean, samplingMode: number): WebGLTexture {
             var texture = this._gl.createTexture();
             texture._baseWidth = width;
             texture._baseHeight = height;
 
-            if (forceExponantOfTwo) {
+            if (generateMipMaps) {
                 width = Tools.GetExponentOfTwo(width, this._caps.maxTextureSize);
                 height = Tools.GetExponentOfTwo(height, this._caps.maxTextureSize);
             }
@@ -1870,8 +1870,8 @@
                 Tools.Warn("Float textures are not supported. Render target forced to TEXTURETYPE_UNSIGNED_BYTE type");
             }
 
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);//filters.mag);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);//filters.min);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 
@@ -2147,12 +2147,47 @@
                     }
                     else {
                         // Data are known to be in +X +Y +Z -X -Y -Z
-                        for (var index = 0; index < facesIndex.length; index++) {
-                            var faceData = rgbeDataArrays[index];
+                        for (let index = 0; index < facesIndex.length; index++) {
+                            let faceData = rgbeDataArrays[index];
                             gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);
                         }
 
                         gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+
+                        // Workaround firefox bug fix https://bugzilla.mozilla.org/show_bug.cgi?id=1221822
+                        // By following the webgl standard changes from Revision 7, 2014/11/24
+                        // Firefox Removed the support for RGB32F, since it is not natively supported on all platforms where WebGL is implemented.
+                        if (textureType === gl.FLOAT && internalFormat === gl.RGB && gl.getError() === 1282) {
+                            Tools.Log("RGB32F not renderable on Firefox, trying fallback to RGBA32F.");
+
+                            // Data are known to be in +X +Y +Z -X -Y -Z
+                            for (let index = 0; index < facesIndex.length; index++) {
+                                let faceData = <Float32Array>rgbeDataArrays[index];
+
+                                // Create a new RGBA Face.
+                                let newFaceData = new Float32Array(width * height * 4);
+                                for (let x = 0; x < width; x++) {
+                                    for (let y = 0; y < height; y++) {
+                                        let index = (y * width + x) * 3;
+                                        let newIndex = (y * width + x) * 4;
+
+                                        // Map Old Value to new value.
+                                        newFaceData[newIndex + 0] = faceData[index + 0];
+                                        newFaceData[newIndex + 1] = faceData[index + 1];
+                                        newFaceData[newIndex + 2] = faceData[index + 2];
+
+                                        // Add fully opaque alpha channel.
+                                        newFaceData[newIndex + 3] = 1;
+                                    }
+                                }
+
+                                // Reupload the face.
+                                gl.texImage2D(facesIndex[index], 0, gl.RGBA, width, height, 0, gl.RGBA, textureType, newFaceData);
+                            }
+
+                            // Try to generate mipmap again.
+                            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                        }
                     }
                 }
                 else {