David Catuhe 8 lat temu
rodzic
commit
543b17a9ac

Plik diff jest za duży
+ 25 - 24
dist/preview release/babylon.core.js


Plik diff jest za duży
+ 2050 - 2048
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 30 - 29
dist/preview release/babylon.js


Plik diff jest za duży
+ 16 - 5
dist/preview release/babylon.max.js


Plik diff jest za duży
+ 20 - 19
dist/preview release/babylon.noworker.js


+ 191 - 0
src/Bones/babylon.bone.js

@@ -15,6 +15,8 @@ var BABYLON;
             this._worldTransform = new BABYLON.Matrix();
             this._absoluteTransform = new BABYLON.Matrix();
             this._invertedAbsoluteTransform = new BABYLON.Matrix();
+            this._scaleMatrix = BABYLON.Matrix.Identity();
+            this._scaleVector = new BABYLON.Vector3(1, 1, 1);
             this._skeleton = skeleton;
             this._matrix = matrix;
             this._baseMatrix = matrix;
@@ -138,6 +140,195 @@ var BABYLON;
             this.animations[0].createRange(rangeName, from + frameOffset, to + frameOffset);
             return true;
         };
+        Bone.prototype.scale = function (x, y, z, scaleChildren) {
+            if (scaleChildren === void 0) { scaleChildren = false; }
+            var locMat = this.getLocalMatrix();
+            var origLocMat = BABYLON.Tmp.Matrix[0];
+            origLocMat.copyFrom(locMat);
+            var origLocMatInv = BABYLON.Tmp.Matrix[1];
+            origLocMatInv.copyFrom(origLocMat);
+            origLocMatInv.invert();
+            var scaleMat = BABYLON.Tmp.Matrix[2];
+            BABYLON.Matrix.FromValuesToRef(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1, scaleMat);
+            this._scaleMatrix.multiplyToRef(scaleMat, this._scaleMatrix);
+            this._scaleVector.x *= x;
+            this._scaleVector.y *= y;
+            this._scaleVector.z *= z;
+            locMat.multiplyToRef(origLocMatInv, locMat);
+            locMat.multiplyToRef(scaleMat, locMat);
+            locMat.multiplyToRef(origLocMat, locMat);
+            var parent = this.getParent();
+            if (parent) {
+                locMat.multiplyToRef(parent.getAbsoluteTransform(), this.getAbsoluteTransform());
+            }
+            else {
+                this.getAbsoluteTransform().copyFrom(locMat);
+            }
+            var len = this.children.length;
+            for (var i = 0; i < len; i++) {
+                var parentAbsMat = this.children[i]._parent.getAbsoluteTransform();
+                this.children[i].getLocalMatrix().multiplyToRef(parentAbsMat, this.children[i].getAbsoluteTransform());
+            }
+            scaleMat.invert();
+            if (this.children[0]) {
+                var child = this.children[0];
+                var cm = child.getLocalMatrix();
+                cm.multiplyToRef(scaleMat, cm);
+                var lm = child.getLocalMatrix();
+                lm.m[12] *= x;
+                lm.m[13] *= y;
+                lm.m[14] *= z;
+            }
+            if (scaleChildren) {
+                for (var i = 0; i < len; i++) {
+                    this.children[i].scale(x, y, z, scaleChildren);
+                }
+            }
+            this.markAsDirty();
+        };
+        Bone.prototype.setYawPitchRoll = function (yaw, pitch, roll, space, mesh) {
+            if (space === void 0) { space = BABYLON.Space.LOCAL; }
+            if (mesh === void 0) { mesh = null; }
+            var rotMat = BABYLON.Tmp.Matrix[0];
+            BABYLON.Matrix.RotationYawPitchRollToRef(yaw, pitch, roll, rotMat);
+            var rotMatInv = BABYLON.Tmp.Matrix[1];
+            if (space == BABYLON.Space.WORLD) {
+                rotMatInv.copyFrom(this.getAbsoluteTransform());
+                if (mesh) {
+                    rotMatInv.multiplyToRef(mesh.getWorldMatrix(), rotMatInv);
+                }
+                rotMatInv.invert();
+                var scaleMatrix = BABYLON.Tmp.Matrix[2];
+                scaleMatrix.copyFrom(this._scaleMatrix);
+                scaleMatrix.m[0] *= -1;
+                rotMatInv.multiplyToRef(scaleMatrix, rotMatInv);
+                rotMatInv.multiplyToRef(rotMat, rotMat);
+            }
+            else {
+                rotMatInv.copyFrom(this.getLocalMatrix());
+                rotMatInv.invert();
+                var scaleMatrix = BABYLON.Tmp.Matrix[2];
+                scaleMatrix.copyFrom(this._scaleMatrix);
+                if (this._parent) {
+                    var pscaleMatrix = BABYLON.Tmp.Matrix[3];
+                    pscaleMatrix.copyFrom(this._parent._scaleMatrix);
+                    pscaleMatrix.invert();
+                    pscaleMatrix.multiplyToRef(rotMatInv, rotMatInv);
+                }
+                rotMatInv.multiplyToRef(scaleMatrix, rotMatInv);
+                rotMatInv.multiplyToRef(rotMat, rotMat);
+            }
+            this._rotateWithMatrix(rotMat, space, mesh);
+        };
+        Bone.prototype.rotate = function (axis, amount, space, mesh) {
+            if (space === void 0) { space = BABYLON.Space.LOCAL; }
+            if (mesh === void 0) { mesh = null; }
+            var rmat = BABYLON.Tmp.Matrix[0];
+            rmat.m[12] = 0;
+            rmat.m[13] = 0;
+            rmat.m[14] = 0;
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rmat);
+            this._rotateWithMatrix(rmat, space, mesh);
+        };
+        Bone.prototype._rotateWithMatrix = function (rmat, space, mesh) {
+            if (space === void 0) { space = BABYLON.Space.LOCAL; }
+            if (mesh === void 0) { mesh = null; }
+            var lmat = this.getLocalMatrix();
+            var lx = lmat.m[12];
+            var ly = lmat.m[13];
+            var lz = lmat.m[14];
+            var parent = this.getParent();
+            var parentScale = BABYLON.Tmp.Matrix[3];
+            var parentScaleInv = BABYLON.Tmp.Matrix[4];
+            if (parent) {
+                if (space == BABYLON.Space.WORLD) {
+                    if (mesh) {
+                        parentScale.copyFrom(mesh.getWorldMatrix());
+                        parent.getAbsoluteTransform().multiplyToRef(parentScale, parentScale);
+                    }
+                    else {
+                        parentScale.copyFrom(parent.getAbsoluteTransform());
+                    }
+                }
+                else {
+                    parentScale = parent._scaleMatrix;
+                }
+                parentScaleInv.copyFrom(parentScale);
+                parentScaleInv.invert();
+                lmat.multiplyToRef(parentScale, lmat);
+                lmat.multiplyToRef(rmat, lmat);
+                lmat.multiplyToRef(parentScaleInv, lmat);
+            }
+            else {
+                if (space == BABYLON.Space.WORLD && mesh) {
+                    parentScale.copyFrom(mesh.getWorldMatrix());
+                    parentScaleInv.copyFrom(parentScale);
+                    parentScaleInv.invert();
+                    lmat.multiplyToRef(parentScale, lmat);
+                    lmat.multiplyToRef(rmat, lmat);
+                    lmat.multiplyToRef(parentScaleInv, lmat);
+                }
+                else {
+                    lmat.multiplyToRef(rmat, lmat);
+                }
+            }
+            lmat.m[12] = lx;
+            lmat.m[13] = ly;
+            lmat.m[14] = lz;
+            if (parent) {
+                var parentAbsMat = this._parent.getAbsoluteTransform();
+                lmat.multiplyToRef(parentAbsMat, this.getAbsoluteTransform());
+            }
+            else {
+                this.getAbsoluteTransform().copyFrom(lmat);
+            }
+            var len = this.children.length;
+            for (var i = 0; i < len; i++) {
+                var parentAbsMat = this.children[i]._parent.getAbsoluteTransform();
+                this.children[i].getLocalMatrix().multiplyToRef(parentAbsMat, this.children[i].getAbsoluteTransform());
+            }
+            this.markAsDirty();
+        };
+        Bone.prototype.getScale = function () {
+            return this._scaleVector.clone();
+        };
+        Bone.prototype.getScaleToRef = function (result) {
+            result.copyFrom(this._scaleVector);
+        };
+        Bone.prototype.getAbsolutePosition = function (mesh) {
+            if (mesh === void 0) { mesh = null; }
+            var pos = BABYLON.Vector3.Zero();
+            this.getAbsolutePositionToRef(mesh, pos);
+            return pos;
+        };
+        Bone.prototype.getAbsolutePositionToRef = function (mesh, result) {
+            if (mesh === void 0) { mesh = null; }
+            this._skeleton.computeAbsoluteTransforms();
+            var tmat = BABYLON.Tmp.Matrix[0];
+            if (mesh) {
+                tmat.copyFrom(this.getAbsoluteTransform());
+                tmat.multiplyToRef(mesh.getWorldMatrix(), tmat);
+            }
+            else {
+                tmat = this.getAbsoluteTransform();
+            }
+            result.x = tmat.m[12];
+            result.y = tmat.m[13];
+            result.z = tmat.m[14];
+        };
+        Bone.prototype.computeAbsoluteTransforms = function () {
+            if (this._parent) {
+                this._matrix.multiplyToRef(this._parent._absoluteTransform, this._absoluteTransform);
+            }
+            else {
+                this._absoluteTransform.copyFrom(this._matrix);
+            }
+            var children = this.children;
+            var len = children.length;
+            for (var i = 0; i < len; i++) {
+                children[i].computeAbsoluteTransforms();
+            }
+        };
         return Bone;
     }(BABYLON.Node));
     BABYLON.Bone = Bone;

+ 9 - 0
src/Bones/babylon.skeleton.js

@@ -10,6 +10,7 @@ var BABYLON;
             this._meshesWithPoseMatrix = new Array();
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
+            this._lastAbsoluteTransformsUpdateId = -1;
             this.bones = [];
             this._scene = scene;
             scene.skeletons.push(this);
@@ -333,6 +334,14 @@ var BABYLON;
             }
             return skeleton;
         };
+        Skeleton.prototype.computeAbsoluteTransforms = function (forceUpdate) {
+            if (forceUpdate === void 0) { forceUpdate = false; }
+            var renderId = this._scene.getRenderId();
+            if (this._lastAbsoluteTransformsUpdateId != renderId || forceUpdate) {
+                this.bones[0].computeAbsoluteTransforms();
+                this._lastAbsoluteTransformsUpdateId = renderId;
+            }
+        };
         return Skeleton;
     }());
     BABYLON.Skeleton = Skeleton;

+ 9 - 1
src/Cameras/babylon.camera.js

@@ -35,6 +35,7 @@ var BABYLON;
             // Cache
             this._computedViewMatrix = BABYLON.Matrix.Identity();
             this._projectionMatrix = new BABYLON.Matrix();
+            this._doNotComputeProjectionMatrix = false;
             this._postProcesses = new Array();
             this._transformMatrix = BABYLON.Matrix.Zero();
             this._webvrViewMatrix = BABYLON.Matrix.Identity();
@@ -346,8 +347,15 @@ var BABYLON;
             this._currentRenderId = this.getScene().getRenderId();
             return this._computedViewMatrix;
         };
+        Camera.prototype.freezeProjectionMatrix = function (projection) {
+            this._doNotComputeProjectionMatrix = true;
+            if (projection !== undefined) {
+                this._projectionMatrix = projection;
+            }
+        };
+        ;
         Camera.prototype.getProjectionMatrix = function (force) {
-            if (!force && this._isSynchronizedProjectionMatrix()) {
+            if ((!force && this._isSynchronizedProjectionMatrix()) || this._doNotComputeProjectionMatrix) {
                 return this._projectionMatrix;
             }
             this._refreshFrustumPlanes = true;

+ 186 - 18
src/Materials/Textures/babylon.fontTexture.js

@@ -25,10 +25,11 @@ var BABYLON;
          * @param samplingMode the texture sampling mode
          * @param superSample if true the FontTexture will be created with a font of a size twice bigger than the given one but all properties (lineHeight, charWidth, etc.) will be according to the original size. This is made to improve the text quality.
          */
-        function FontTexture(name, font, scene, maxCharCount, samplingMode, superSample) {
+        function FontTexture(name, font, scene, maxCharCount, samplingMode, superSample, signedDistanceField) {
             if (maxCharCount === void 0) { maxCharCount = 200; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
             if (superSample === void 0) { superSample = false; }
+            if (signedDistanceField === void 0) { signedDistanceField = false; }
             _super.call(this, null, scene, true, false, samplingMode);
             this._charInfos = {};
             this._curCharCount = 0;
@@ -37,8 +38,11 @@ var BABYLON;
             this.name = name;
             this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this._sdfScale = 8;
+            this._signedDistanceField = signedDistanceField;
             this._superSample = false;
-            if (superSample) {
+            // SDF will use supersample no matter what, the resolution is otherwise too poor to produce correct result
+            if (superSample || signedDistanceField) {
                 var sfont = this.getSuperSampleFont(font);
                 if (sfont) {
                     this._superSample = true;
@@ -52,20 +56,22 @@ var BABYLON;
             this._context.fillStyle = "white";
             this._cachedFontId = null;
             var res = this.getFontHeight(font);
-            this._lineHeightSuper = res.height;
-            this._lineHeight = this._superSample ? (this._lineHeightSuper / 2) : this._lineHeightSuper;
+            this._lineHeightSuper = res.height + 4;
+            this._lineHeight = this._superSample ? (Math.ceil(this._lineHeightSuper / 2)) : this._lineHeightSuper;
             this._offset = res.offset - 1;
+            this._xMargin = 1 + Math.ceil(this._lineHeightSuper / 15); // Right now this empiric formula seems to work...
+            this._yMargin = this._xMargin;
             var maxCharWidth = this._context.measureText("W").width;
             this._spaceWidthSuper = this._context.measureText(" ").width;
             this._spaceWidth = this._superSample ? (this._spaceWidthSuper / 2) : this._spaceWidthSuper;
             // This is an approximate size, but should always be able to fit at least the maxCharCount
-            var totalEstSurface = this._lineHeightSuper * maxCharWidth * maxCharCount;
+            var totalEstSurface = (this._lineHeightSuper + this._yMargin) * (maxCharWidth + this._xMargin) * maxCharCount;
             var edge = Math.sqrt(totalEstSurface);
             var textSize = Math.pow(2, Math.ceil(Math.log(edge) / Math.log(2)));
             // Create the texture that will store the font characters
             this._texture = scene.getEngine().createDynamicTexture(textSize, textSize, false, samplingMode);
             var textureSize = this.getSize();
-            this.hasAlpha = true;
+            this.hasAlpha = this._signedDistanceField === false;
             // Recreate a new canvas with the final size: the one matching the texture (resizing the previous one doesn't work as one would expect...)
             this._canvas = document.createElement("canvas");
             this._canvas.width = textureSize.width;
@@ -75,6 +81,24 @@ var BABYLON;
             this._context.font = font;
             this._context.fillStyle = "white";
             this._context.imageSmoothingEnabled = false;
+            this._context.clearRect(0, 0, textureSize.width, textureSize.height);
+            // Create a canvas for the signed distance field mode, we only have to store one char, the purpose is to render a char scaled _sdfScale times
+            //  into this 2D context, then get the bitmap data, create the sdf char and push the result in the _context (which hold the whole Font Texture content)
+            // So you can see this context as an intermediate one, because it is.
+            if (this._signedDistanceField) {
+                var sdfC = document.createElement("canvas");
+                var s = this._sdfScale;
+                sdfC.width = maxCharWidth * s;
+                sdfC.height = this._lineHeightSuper * s;
+                var sdfCtx = sdfC.getContext("2d");
+                sdfCtx.scale(s, s);
+                sdfCtx.textBaseline = "top";
+                sdfCtx.font = font;
+                sdfCtx.fillStyle = "white";
+                sdfCtx.imageSmoothingEnabled = false;
+                this._sdfCanvas = sdfC;
+                this._sdfContext = sdfCtx;
+            }
             this._currentFreePosition = BABYLON.Vector2.Zero();
             // Add the basic ASCII based characters
             for (var i = 0x20; i < 0x7F; i++) {
@@ -90,6 +114,13 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(FontTexture.prototype, "isSignedDistanceField", {
+            get: function () {
+                return this._signedDistanceField;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(FontTexture.prototype, "spaceWidth", {
             get: function () {
                 return this._spaceWidth;
@@ -104,32 +135,34 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        FontTexture.GetCachedFontTexture = function (scene, fontName, supersample) {
+        FontTexture.GetCachedFontTexture = function (scene, fontName, supersample, signedDistanceField) {
             if (supersample === void 0) { supersample = false; }
+            if (signedDistanceField === void 0) { signedDistanceField = false; }
             var s = scene;
             if (!s.__fontTextureCache__) {
                 s.__fontTextureCache__ = new BABYLON.StringDictionary();
             }
             var dic = s.__fontTextureCache__;
-            var lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS");
+            var lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF");
             var ft = dic.get(lfn);
             if (ft) {
                 ++ft._usedCounter;
                 return ft;
             }
-            ft = new FontTexture(null, fontName, scene, supersample ? 100 : 200, BABYLON.Texture.BILINEAR_SAMPLINGMODE, supersample);
+            ft = new FontTexture(null, fontName, scene, supersample ? 100 : 200, BABYLON.Texture.BILINEAR_SAMPLINGMODE, supersample, signedDistanceField);
             ft._cachedFontId = lfn;
             dic.add(lfn, ft);
             return ft;
         };
-        FontTexture.ReleaseCachedFontTexture = function (scene, fontName, supersample) {
+        FontTexture.ReleaseCachedFontTexture = function (scene, fontName, supersample, signedDistanceField) {
             if (supersample === void 0) { supersample = false; }
+            if (signedDistanceField === void 0) { signedDistanceField = false; }
             var s = scene;
             var dic = s.__fontTextureCache__;
             if (!dic) {
                 return;
             }
-            var lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS");
+            var lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF");
             var font = dic.get(lfn);
             if (--font._usedCounter === 0) {
                 dic.remove(lfn);
@@ -154,29 +187,164 @@ var BABYLON;
             var textureSize = this.getSize();
             // we reached the end of the current line?
             var width = Math.round(measure.width);
-            var xMargin = 1 + Math.ceil(this._lineHeightSuper / 15); // Right now this empiric formula seems to work...
-            var yMargin = xMargin;
-            if (this._currentFreePosition.x + width + xMargin > textureSize.width) {
+            if (this._currentFreePosition.x + width + this._xMargin > textureSize.width) {
                 this._currentFreePosition.x = 0;
-                this._currentFreePosition.y += this._lineHeightSuper + yMargin;
+                this._currentFreePosition.y += this._lineHeightSuper + this._yMargin;
                 // No more room?
                 if (this._currentFreePosition.y > textureSize.height) {
                     return this.getChar("!");
                 }
             }
-            // Draw the character in the texture
-            this._context.fillText(char, this._currentFreePosition.x, this._currentFreePosition.y - this._offset);
+            // In sdf mode we render the character in an intermediate 2D context which scale the character this._sdfScale times (which is required to compute the sdf map accurately)
+            if (this._signedDistanceField) {
+                this._sdfContext.clearRect(0, 0, this._sdfCanvas.width, this._sdfCanvas.height);
+                this._sdfContext.fillText(char, 0, 0);
+                var data = this._sdfContext.getImageData(0, 0, width * this._sdfScale, this._sdfCanvas.height);
+                var res = this._computeSDFChar(data);
+                this._context.putImageData(res, this._currentFreePosition.x, this._currentFreePosition.y);
+            }
+            else {
+                // Draw the character in the HTML canvas
+                this._context.fillText(char, this._currentFreePosition.x, this._currentFreePosition.y - this._offset);
+            }
             // Fill the CharInfo object
             info.topLeftUV = new BABYLON.Vector2(this._currentFreePosition.x / textureSize.width, this._currentFreePosition.y / textureSize.height);
             info.bottomRightUV = new BABYLON.Vector2((this._currentFreePosition.x + width) / textureSize.width, info.topLeftUV.y + ((this._lineHeightSuper + 2) / textureSize.height));
+            if (this._signedDistanceField) {
+                var off = 1 / textureSize.width;
+                info.topLeftUV.addInPlace(new BABYLON.Vector2(off, off));
+                info.bottomRightUV.addInPlace(new BABYLON.Vector2(off, off));
+            }
             info.charWidth = this._superSample ? (width / 2) : width;
             // Add the info structure
             this._charInfos[char] = info;
             this._curCharCount++;
             // Set the next position
-            this._currentFreePosition.x += width + xMargin;
+            this._currentFreePosition.x += width + this._xMargin;
             return info;
         };
+        FontTexture.prototype._computeSDFChar = function (source) {
+            var scl = this._sdfScale;
+            var sw = source.width;
+            var sh = source.height;
+            var dw = sw / scl;
+            var dh = sh / scl;
+            var roffx = 0;
+            var roffy = 0;
+            // We shouldn't look beyond half of the biggest between width and height
+            var radius = scl;
+            var br = radius - 1;
+            var lookupSrc = function (dx, dy, offX, offY, lookVis) {
+                var sx = dx * scl;
+                var sy = dy * scl;
+                // Looking out of the area? return true to make the test going on
+                if (((sx + offX) < 0) || ((sx + offX) >= sw) || ((sy + offY) < 0) || ((sy + offY) >= sh)) {
+                    return true;
+                }
+                // Get the pixel we want
+                var val = source.data[(((sy + offY) * sw) + (sx + offX)) * 4];
+                var res = (val > 0) === lookVis;
+                if (!res) {
+                    roffx = offX;
+                    roffy = offY;
+                }
+                return res;
+            };
+            var lookupArea = function (dx, dy, lookVis) {
+                // Fast rejection test, if we have the same result in N, S, W, E at a distance which is the radius-1 then it means the data will be consistent in this area. That's because we've scale the rendering of the letter "radius" times, so a letter's pixel will be at least radius wide
+                if (lookupSrc(dx, dy, 0, br, lookVis) &&
+                    lookupSrc(dx, dy, 0, -br, lookVis) &&
+                    lookupSrc(dx, dy, -br, 0, lookVis) &&
+                    lookupSrc(dx, dy, br, 0, lookVis)) {
+                    return 0;
+                }
+                for (var i = 1; i <= radius; i++) {
+                    // Quick test N, S, W, E
+                    if (!lookupSrc(dx, dy, 0, i, lookVis) || !lookupSrc(dx, dy, 0, -i, lookVis) || !lookupSrc(dx, dy, -i, 0, lookVis) || !lookupSrc(dx, dy, i, 0, lookVis)) {
+                        return i * i; // Squared Distance is simple to compute in this case
+                    }
+                    // Test the frame area (except the N, S, W, E spots) from the nearest point from the center to the further one
+                    for (var j = 1; j <= i; j++) {
+                        if (!lookupSrc(dx, dy, -j, i, lookVis) || !lookupSrc(dx, dy, j, i, lookVis) ||
+                            !lookupSrc(dx, dy, i, -j, lookVis) || !lookupSrc(dx, dy, i, j, lookVis) ||
+                            !lookupSrc(dx, dy, -j, -i, lookVis) || !lookupSrc(dx, dy, j, -i, lookVis) ||
+                            !lookupSrc(dx, dy, -i, -j, lookVis) || !lookupSrc(dx, dy, -i, j, lookVis)) {
+                            // We found the nearest texel having and opposite state, store the squared length
+                            var res_1 = (i * i) + (j * j);
+                            var count = 1;
+                            // To improve quality we will  sample the texels around this one, so it's 8 samples, we consider only the one having an opposite state, add them to the current res and will will compute the average at the end
+                            if (!lookupSrc(dx, dy, roffx - 1, roffy, lookVis)) {
+                                res_1 += (roffx - 1) * (roffx - 1) + roffy * roffy;
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx + 1, roffy, lookVis)) {
+                                res_1 += (roffx + 1) * (roffx + 1) + roffy * roffy;
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx, roffy - 1, lookVis)) {
+                                res_1 += roffx * roffx + (roffy - 1) * (roffy - 1);
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx, roffy + 1, lookVis)) {
+                                res_1 += roffx * roffx + (roffy + 1) * (roffy + 1);
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx - 1, roffy - 1, lookVis)) {
+                                res_1 += (roffx - 1) * (roffx - 1) + (roffy - 1) * (roffy - 1);
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx + 1, roffy + 1, lookVis)) {
+                                res_1 += (roffx + 1) * (roffx + 1) + (roffy + 1) * (roffy + 1);
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx + 1, roffy - 1, lookVis)) {
+                                res_1 += (roffx + 1) * (roffx + 1) + (roffy - 1) * (roffy - 1);
+                                ++count;
+                            }
+                            if (!lookupSrc(dx, dy, roffx - 1, roffy + 1, lookVis)) {
+                                res_1 += (roffx - 1) * (roffx - 1) + (roffy + 1) * (roffy + 1);
+                                ++count;
+                            }
+                            // Compute the average based on the accumulated distance
+                            return res_1 / count;
+                        }
+                    }
+                }
+                return 0;
+            };
+            var tmp = new Array(dw * dh);
+            for (var y = 0; y < dh; y++) {
+                for (var x = 0; x < dw; x++) {
+                    var curState = lookupSrc(x, y, 0, 0, true);
+                    var d = lookupArea(x, y, curState);
+                    if (d === 0) {
+                        d = radius * radius * 2;
+                    }
+                    tmp[(y * dw) + x] = curState ? d : -d;
+                }
+            }
+            var res = this._context.createImageData(dw, dh);
+            var size = dw * dh;
+            for (var j = 0; j < size; j++) {
+                var d = tmp[j];
+                var sign = (d < 0) ? -1 : 1;
+                d = Math.sqrt(Math.abs(d)) * sign;
+                d *= 127.5 / radius;
+                d += 127.5;
+                if (d < 0) {
+                    d = 0;
+                }
+                else if (d > 255) {
+                    d = 255;
+                }
+                d += 0.5;
+                res.data[j * 4 + 0] = d;
+                res.data[j * 4 + 1] = d;
+                res.data[j * 4 + 2] = d;
+                res.data[j * 4 + 3] = 255;
+            }
+            return res;
+        };
         FontTexture.prototype.measureText = function (text, tabulationSize) {
             if (tabulationSize === void 0) { tabulationSize = 4; }
             var maxWidth = 0;

+ 6 - 3
src/Math/babylon.math.js

@@ -856,9 +856,12 @@ var BABYLON;
             return result;
         };
         Vector3.TransformNormalToRef = function (vector, transformation, result) {
-            result.x = (vector.x * transformation.m[0]) + (vector.y * transformation.m[4]) + (vector.z * transformation.m[8]);
-            result.y = (vector.x * transformation.m[1]) + (vector.y * transformation.m[5]) + (vector.z * transformation.m[9]);
-            result.z = (vector.x * transformation.m[2]) + (vector.y * transformation.m[6]) + (vector.z * transformation.m[10]);
+            var x = (vector.x * transformation.m[0]) + (vector.y * transformation.m[4]) + (vector.z * transformation.m[8]);
+            var y = (vector.x * transformation.m[1]) + (vector.y * transformation.m[5]) + (vector.z * transformation.m[9]);
+            var z = (vector.x * transformation.m[2]) + (vector.y * transformation.m[6]) + (vector.z * transformation.m[10]);
+            result.x = x;
+            result.y = y;
+            result.z = z;
         };
         Vector3.TransformNormalFromFloatsToRef = function (x, y, z, transformation, result) {
             result.x = (x * transformation.m[0]) + (y * transformation.m[4]) + (z * transformation.m[8]);

+ 6 - 3
src/Sprites/babylon.spriteManager.js

@@ -2,6 +2,7 @@ var BABYLON;
 (function (BABYLON) {
     var SpriteManager = (function () {
         function SpriteManager(name, imgUrl, capacity, cellSize, scene, epsilon, samplingMode) {
+            if (epsilon === void 0) { epsilon = 0.01; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
             this.name = name;
             this.sprites = new Array();
@@ -19,15 +20,17 @@ var BABYLON;
             this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._spriteTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-            this._epsilon = epsilon === undefined ? 0.01 : epsilon;
-            if (cellSize.width) {
+            if (cellSize.width && cellSize.height) {
                 this.cellWidth = cellSize.width;
                 this.cellHeight = cellSize.height;
             }
-            else {
+            else if (cellSize !== undefined) {
                 this.cellWidth = cellSize;
                 this.cellHeight = cellSize;
             }
+            else {
+                return;
+            }
             this._scene = scene;
             this._scene.spriteManagers.push(this);
             var indices = [];