Explorar o código

StandardMaterial.useGlossinessFromSpecularMapAlpha to use specular map alpha as glossiness level
Added mesh.computeBonesUsingShaders to allow developers to disable HW skinning for low end devices

David catuhe %!s(int64=10) %!d(string=hai) anos
pai
achega
cf35254fe7

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 671 - 655
dist/preview release - alpha/babylon.2.2.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 29 - 32
dist/preview release - alpha/babylon.2.2.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 135 - 14
dist/preview release - alpha/babylon.2.2.max.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 28 - 31
dist/preview release - alpha/babylon.2.2.noworker.js


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

@@ -3,8 +3,10 @@
     - Meshes can now be attached to bones. See [documentation here](http://babylondoc.azurewebsites.net/page.php?p=22421) and [sample here](http://www.babylonjs-playground.com/#11BH6Z#18) [deltakosh](https://github.com/deltakosh)
     - HDR Rendering pipeline. See [demo here]() [julien-moreau](https://github.com/julien-moreau)
     - New rewored StandardMaterial.isReady for better memory usage and performance [deltakosh](https://github.com/deltakosh)
-    - Revamping of FBX exporter. Now supports animations and bones Simon Ferquel, [deltakosh](https://github.com/deltakosh)
+    - Revamping of FBX exporter. Now supports animations and bones [simonferquel](http://www.github.com/simonferquel), [deltakosh](https://github.com/deltakosh)
+    - StandardMaterial.useGlossinessFromSpecularMapAlpha to use specular map alpha as glossiness level [deltakosh](https://github.com/deltakosh)
   - **Updates**
+    - Added mesh.computeBonesUsingShaders to allow developers to disable HW skinning for low end devices [deltakosh](https://github.com/deltakosh)
     - Added material.disableDepthWrite (default is off) [deltakosh](https://github.com/deltakosh)
     - Added material.alphaMode (default is BABYLON.Engine.ALPHA_COMBINE, can be set to BABYLON.Engine.ALPHA_ADD, *_SUBTRACT, *_MULTIPLY or *_MAXIMIZED ) [deltakosh](https://github.com/deltakosh), [jahow](https://github.com/jahow)
     - Added Animatable.reset() function [deltakosh](https://github.com/deltakosh)

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

@@ -53,7 +53,7 @@
                     bone.getWorldMatrix().copyFrom(bone.getLocalMatrix());
                 }
 
-                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), this._transformMatrices, index * 16);
+                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), this._transformMatrices, index * 16);                
             }
 
             this._identity.copyToArray(this._transformMatrices, this.bones.length * 16);

+ 2 - 2
src/Lights/Shadows/babylon.shadowGenerator.js

@@ -68,7 +68,7 @@ var BABYLON;
                         _this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                     }
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         _this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
                     // Draw
@@ -236,7 +236,7 @@ var BABYLON;
                 }
             }
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 2 - 2
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -192,7 +192,7 @@
                     }
 
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
 
@@ -258,7 +258,7 @@
             }
 
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(VertexBuffer.MatricesIndicesKind);
                 attribs.push(VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 2 - 2
src/Materials/babylon.shaderMaterial.js

@@ -95,7 +95,7 @@ var BABYLON;
                 defines.push("#define INSTANCES");
             }
             // Bones
-            if (mesh && mesh.useBones) {
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 defines.push("#define BONES");
                 defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
                 defines.push("#define BONES4");
@@ -144,7 +144,7 @@ var BABYLON;
                     this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
                 }
                 // Bones
-                if (mesh && mesh.useBones) {
+                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                     this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                 }
                 // Texture

+ 2 - 2
src/Materials/babylon.shaderMaterial.ts

@@ -116,7 +116,7 @@
             }
 
             // Bones
-            if (mesh && mesh.useBones) {
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 defines.push("#define BONES");
                 defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
                 defines.push("#define BONES4");
@@ -185,7 +185,7 @@
                 }
 
                 // Bones
-                if (mesh && mesh.useBones) {
+                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                     this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                 }
 

+ 5 - 2
src/Materials/babylon.standardMaterial.js

@@ -78,6 +78,7 @@ var BABYLON;
             this.BONES4 = false;
             this.BonesPerMesh = 0;
             this.INSTANCES = false;
+            this.GLOSSINESS = false;
             this._keys = Object.keys(this);
         }
         StandardMaterialDefines.prototype.isEqual = function (other) {
@@ -134,6 +135,7 @@ var BABYLON;
             this.useAlphaFromDiffuseTexture = false;
             this.useSpecularOverAlpha = true;
             this.fogEnabled = true;
+            this.useGlossinessFromSpecularMapAlpha = false;
             this._renderTargets = new BABYLON.SmartArray(16);
             this._worldViewProjectionMatrix = BABYLON.Matrix.Zero();
             this._globalAmbientColor = new BABYLON.Color3(0, 0, 0);
@@ -237,6 +239,7 @@ var BABYLON;
                     else {
                         needUVs = true;
                         this._defines.SPECULAR = true;
+                        this._defines.GLOSSINESS = this.useGlossinessFromSpecularMapAlpha;
                     }
                 }
             }
@@ -377,7 +380,7 @@ var BABYLON;
                         this._defines.VERTEXALPHA = true;
                     }
                 }
-                if (mesh.useBones) {
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
                     this._defines.BONES = true;
                     this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
                     this._defines.BONES4 = true;
@@ -513,7 +516,7 @@ var BABYLON;
             this.bindOnlyWorldMatrix(world);
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
             // Bones
-            if (mesh && mesh.useBones) {
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
             if (scene.getCachedMaterial() !== this) {

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

@@ -68,6 +68,7 @@
         public BONES4 = false;
         public BonesPerMesh = 0;
         public INSTANCES = false;
+        public GLOSSINESS = false;
 
         _keys: string[];
 
@@ -150,6 +151,8 @@
         public reflectionFresnelParameters: FresnelParameters;
         public emissiveFresnelParameters: FresnelParameters;
 
+        public useGlossinessFromSpecularMapAlpha = false;
+
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
         private _worldViewProjectionMatrix = Matrix.Zero();
         private _globalAmbientColor = new Color3(0, 0, 0);
@@ -272,6 +275,7 @@
                     } else {
                         needUVs = true;
                         this._defines.SPECULAR = true;
+                        this._defines.GLOSSINESS = this.useGlossinessFromSpecularMapAlpha;    
                     }
                 }
             }
@@ -441,7 +445,7 @@
                         this._defines.VERTEXALPHA = true
                     }
                 }
-                if (mesh.useBones) {
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
                     this._defines.BONES = true;
                     this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
                     this._defines.BONES4 = true;
@@ -617,7 +621,7 @@
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            if (mesh && mesh.useBones) {
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 

+ 34 - 0
src/Math/babylon.math.js

@@ -586,6 +586,12 @@ var BABYLON;
             }
             return new Vector3(array[offset], array[offset + 1], array[offset + 2]);
         };
+        Vector3.FromFloatArray = function (array, offset) {
+            if (!offset) {
+                offset = 0;
+            }
+            return new Vector3(array[offset], array[offset + 1], array[offset + 2]);
+        };
         Vector3.FromArrayToRef = function (array, offset, result) {
             result.x = array[offset];
             result.y = array[offset + 1];
@@ -1453,6 +1459,29 @@ var BABYLON;
             this.invertToRef(this);
             return this;
         };
+        Matrix.prototype.reset = function () {
+            for (var index = 0; index < 16; index++) {
+                this.m[index] = 0;
+            }
+            return this;
+        };
+        Matrix.prototype.add = function (other) {
+            var result = new Matrix();
+            this.addToRef(other, result);
+            return result;
+        };
+        Matrix.prototype.addToRef = function (other, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] + other.m[index];
+            }
+            return this;
+        };
+        Matrix.prototype.addToSelf = function (other) {
+            for (var index = 0; index < 16; index++) {
+                this.m[index] += other.m[index];
+            }
+            return this;
+        };
         Matrix.prototype.invertToRef = function (other) {
             var l1 = this.m[0];
             var l2 = this.m[1];
@@ -1758,6 +1787,11 @@ var BABYLON;
                 result.m[index] = array[index + offset];
             }
         };
+        Matrix.FromFloat32ArrayToRefScaled = function (array, offset, scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = array[index + offset] * scale;
+            }
+        };
         Matrix.FromValuesToRef = function (initialM11, initialM12, initialM13, initialM14, initialM21, initialM22, initialM23, initialM24, initialM31, initialM32, initialM33, initialM34, initialM41, initialM42, initialM43, initialM44, result) {
             result.m[0] = initialM11;
             result.m[1] = initialM12;

+ 46 - 1
src/Math/babylon.math.ts

@@ -739,6 +739,14 @@
             return new Vector3(array[offset], array[offset + 1], array[offset + 2]);
         }
 
+        public static FromFloatArray(array: Float32Array, offset?: number): Vector3 {
+            if (!offset) {
+                offset = 0;
+            }
+
+            return new Vector3(array[offset], array[offset + 1], array[offset + 2]);
+        }
+
         public static FromArrayToRef(array: number[], offset: number, result: Vector3): void {
             result.x = array[offset];
             result.y = array[offset + 1];
@@ -1791,6 +1799,38 @@
             return this;
         }
 
+        public reset(): Matrix {
+            for (var index = 0; index < 16; index++) {
+                this.m[index] = 0;
+            }
+
+            return this;
+        }
+
+        public add(other: Matrix): Matrix {
+            var result = new Matrix();
+
+            this.addToRef(other, result);
+
+            return result;
+        }
+
+        public addToRef(other: Matrix, result: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] + other.m[index];
+            }
+
+            return this;
+        }
+
+        public addToSelf(other: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                this.m[index] += other.m[index];
+            }
+
+            return this;
+        }
+
         public invertToRef(other: Matrix): Matrix {
             var l1 = this.m[0];
             var l2 = this.m[1];
@@ -2179,12 +2219,17 @@
         }
 
         public static FromArrayToRef(array: number[], offset: number, result: Matrix) {
-
             for (var index = 0; index < 16; index++) {
                 result.m[index] = array[index + offset];
             }
         }
 
+        public static FromFloat32ArrayToRefScaled(array: Float32Array, offset: number, scale: number, result: Matrix) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = array[index + offset] * scale;
+            }
+        }
+
         public static FromValuesToRef(initialM11: number, initialM12: number, initialM13: number, initialM14: number,
             initialM21: number, initialM22: number, initialM23: number, initialM24: number,
             initialM31: number, initialM32: number, initialM33: number, initialM34: number,

+ 1 - 0
src/Mesh/babylon.abstractMesh.js

@@ -37,6 +37,7 @@ var BABYLON;
             this.hasVertexAlpha = false;
             this.useVertexColors = true;
             this.applyFog = true;
+            this.computeBonesUsingShaders = true;
             this.useOctreeForRenderingSelection = true;
             this.useOctreeForPicking = true;
             this.useOctreeForCollisions = true;

+ 1 - 0
src/Mesh/babylon.abstractMesh.ts

@@ -57,6 +57,7 @@
         public hasVertexAlpha = false;
         public useVertexColors = true;
         public applyFog = true;
+        public computeBonesUsingShaders = true;
 
         public useOctreeForRenderingSelection = true;
         public useOctreeForPicking = true;

+ 73 - 0
src/Mesh/babylon.mesh.js

@@ -1674,6 +1674,79 @@ var BABYLON;
             decal.rotation = new BABYLON.Vector3(pitch, yaw, angle);
             return decal;
         };
+        // Skeletons
+        /**
+         * Update the vertex buffers by applying transformation from the bones
+         * @param {skeleton} skeleton to apply
+         */
+        Mesh.prototype.applySkeleton = function (skeleton) {
+            if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                return this;
+            }
+            if (!this._sourcePositions) {
+                var source = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                this._sourcePositions = new Float32Array(source);
+                if (!this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable()) {
+                    this.setVerticesData(BABYLON.VertexBuffer.PositionKind, source, true);
+                }
+            }
+            if (!this._sourceNormals) {
+                var source = this.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+                this._sourceNormals = new Float32Array(source);
+                if (!this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable()) {
+                    this.setVerticesData(BABYLON.VertexBuffer.NormalKind, source, true);
+                }
+            }
+            var positionsData = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            var normalsData = this.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+            var skeletonMatrices = skeleton.getTransformMatrices();
+            var tempVector3 = BABYLON.Vector3.Zero();
+            var finalMatrix = new BABYLON.Matrix();
+            var tempMatrix = new BABYLON.Matrix();
+            for (var index = 0; index < positionsData.length; index += 3) {
+                var index4 = (index / 3) * 4;
+                var matricesWeight0 = matricesWeightsData[index4];
+                var matricesWeight1 = matricesWeightsData[index4 + 1];
+                var matricesWeight2 = matricesWeightsData[index4 + 2];
+                var matricesWeight3 = matricesWeightsData[index4 + 3];
+                if (matricesWeight0 > 0) {
+                    var matricesIndex0 = matricesIndicesData[index4];
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4] * 16, matricesWeight0, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+                if (matricesWeight1 > 0) {
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 1] * 16, matricesWeight1, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+                if (matricesWeight2 > 0) {
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 2] * 16, matricesWeight2, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+                if (matricesWeight3 > 0) {
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 3] * 16, matricesWeight3, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
+                tempVector3.toArray(positionsData, index);
+                BABYLON.Vector3.TransformNormalFromFloatsToRef(this._sourceNormals[index], this._sourceNormals[index + 1], this._sourceNormals[index + 2], finalMatrix, tempVector3);
+                tempVector3.toArray(normalsData, index);
+                finalMatrix.reset();
+            }
+            this.updateVerticesData(BABYLON.VertexBuffer.PositionKind, positionsData);
+            this.updateVerticesData(BABYLON.VertexBuffer.NormalKind, normalsData);
+            return this;
+        };
         // Tools
         Mesh.MinMax = function (meshes) {
             var minVector = null;

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

@@ -69,6 +69,9 @@
         private _sideOrientation: number = Mesh._DEFAULTSIDE;
         private _areNormalsFrozen: boolean = false; // Will be used by ribbons mainly
 
+        private _sourcePositions: Float32Array; // Will be used to save original positions when using software skinning
+        private _sourceNormals: Float32Array; // Will be used to save original normals when using software skinning
+
         /**
          * @constructor
          * @param {string} name - The value used by scene.getMeshByName() to do a lookup.
@@ -1953,6 +1956,99 @@
             return decal;
         }
 
+        // Skeletons
+
+        /**
+         * Update the vertex buffers by applying transformation from the bones
+         * @param {skeleton} skeleton to apply
+         */
+        public applySkeleton(skeleton: Skeleton): Mesh {
+            if (!this.isVerticesDataPresent(VertexBuffer.PositionKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind)) {
+                return this;
+            }
+            if (!this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)) {
+                return this;
+            }
+
+            if (!this._sourcePositions) {
+                var source = this.getVerticesData(VertexBuffer.PositionKind);
+                this._sourcePositions = new Float32Array(source);
+
+                if (!this.getVertexBuffer(VertexBuffer.PositionKind).isUpdatable()) {
+                    this.setVerticesData(VertexBuffer.PositionKind, source, true);
+                }
+            }
+
+            if (!this._sourceNormals) {
+                var source = this.getVerticesData(VertexBuffer.NormalKind);
+                this._sourceNormals = new Float32Array(source);
+
+                if (!this.getVertexBuffer(VertexBuffer.NormalKind).isUpdatable()) {
+                    this.setVerticesData(VertexBuffer.NormalKind, source, true);
+                }
+            }
+
+            var positionsData = this.getVerticesData(VertexBuffer.PositionKind);
+            var normalsData = this.getVerticesData(VertexBuffer.NormalKind);
+
+            var matricesIndicesData = this.getVerticesData(VertexBuffer.MatricesIndicesKind);
+            var matricesWeightsData = this.getVerticesData(VertexBuffer.MatricesWeightsKind);
+
+            var skeletonMatrices = skeleton.getTransformMatrices();
+
+            var tempVector3 = Vector3.Zero();
+            var finalMatrix = new Matrix();
+            var tempMatrix = new Matrix();
+
+            for (var index = 0; index < positionsData.length; index += 3) {
+                var index4 = (index / 3) * 4;
+                var matricesWeight0 = matricesWeightsData[index4];
+                var matricesWeight1 = matricesWeightsData[index4 + 1];
+                var matricesWeight2 = matricesWeightsData[index4 + 2];
+                var matricesWeight3 = matricesWeightsData[index4 + 3];
+                
+                if (matricesWeight0 > 0) {
+                    var matricesIndex0 = matricesIndicesData[index4];
+                    Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4] * 16, matricesWeight0, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+
+                if (matricesWeight1> 0) {
+                    Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 1] * 16, matricesWeight1, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+
+                if (matricesWeight2 > 0) {
+                    Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 2] * 16, matricesWeight2, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+
+                if (matricesWeight3 > 0) {
+                    Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, matricesIndicesData[index4 + 3] * 16, matricesWeight3, tempMatrix);
+                    finalMatrix.addToSelf(tempMatrix);
+                }
+
+                Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
+                tempVector3.toArray(positionsData, index);
+
+                Vector3.TransformNormalFromFloatsToRef(this._sourceNormals[index], this._sourceNormals[index + 1], this._sourceNormals[index + 2], finalMatrix, tempVector3);
+                tempVector3.toArray(normalsData, index);
+
+                finalMatrix.reset();
+            }
+
+            this.updateVerticesData(VertexBuffer.PositionKind, positionsData);
+            this.updateVerticesData(VertexBuffer.NormalKind, normalsData);
+
+            return this;
+        }
+
         // Tools
         public static MinMax(meshes: AbstractMesh[]): { min: Vector3; max: Vector3 } {
             var minVector: Vector3 = null;

+ 2 - 2
src/PostProcess/babylon.volumetricLightScatteringPostProcess.js

@@ -128,7 +128,7 @@ var BABYLON;
                 }
             }
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");
@@ -237,7 +237,7 @@ var BABYLON;
                         }
                     }
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         _this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
                     // Draw

+ 2 - 2
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -143,7 +143,7 @@
             }
 
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(VertexBuffer.MatricesIndicesKind);
                 attribs.push(VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");
@@ -279,7 +279,7 @@
                     }
 
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
 

+ 2 - 2
src/Rendering/babylon.depthRenderer.js

@@ -47,7 +47,7 @@ var BABYLON;
                         _this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                     }
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         _this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
                     // Draw
@@ -83,7 +83,7 @@ var BABYLON;
                 }
             }
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 2 - 2
src/Rendering/babylon.depthRenderer.ts

@@ -63,7 +63,7 @@
                     }
 
                     // Bones
-                    if (mesh.useBones) {
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
                     }
 
@@ -109,7 +109,7 @@
             }
 
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(VertexBuffer.MatricesIndicesKind);
                 attribs.push(VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 2 - 2
src/Rendering/babylon.outlineRenderer.js

@@ -20,7 +20,7 @@ var BABYLON;
             this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : 1.0);
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
             mesh._bind(subMesh, this._effect, BABYLON.Material.TriangleFillMode);
@@ -50,7 +50,7 @@ var BABYLON;
                 }
             }
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 2 - 2
src/Rendering/babylon.outlineRenderer.ts

@@ -27,7 +27,7 @@
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 
@@ -65,7 +65,7 @@
             }
 
             // Bones
-            if (mesh.useBones) {
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(VertexBuffer.MatricesIndicesKind);
                 attribs.push(VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 33 - 27
src/Shaders/default.fragment.fx

@@ -392,7 +392,7 @@ struct lightingInfo
 #endif
 };
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range) {
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
 	lightingInfo result;
 
 	vec3 lightVectorW;
@@ -417,14 +417,14 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightVectorW);
 	float specComp = max(0., dot(vNormal, angleW));
-	specComp = pow(specComp, max(1., vSpecularColor.a));
+	specComp = pow(specComp, max(1., glossiness));
 
 	result.specular = specComp * specularColor * attenuation;
 #endif
 	return result;
 }
 
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range) {
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
 	lightingInfo result;
 
 	vec3 direction = lightData.xyz - vPositionW;
@@ -448,7 +448,7 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
 		// Specular
 		vec3 angleW = normalize(viewDirectionW - lightDirection.xyz);
 		float specComp = max(0., dot(vNormal, angleW));
-		specComp = pow(specComp, vSpecularColor.a);
+		specComp = pow(specComp, glossiness);
 
 		result.specular = specComp * specularColor * spotAtten * attenuation;
 #endif
@@ -464,7 +464,7 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
 	return result;
 }
 
-lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor) {
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float glossiness) {
 	lightingInfo result;
 
 	// Diffuse
@@ -475,7 +475,7 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightData.xyz);
 	float specComp = max(0., dot(vNormal, angleW));
-	specComp = pow(specComp, vSpecularColor.a);
+	specComp = pow(specComp, glossiness);
 
 	result.specular = specComp * specularColor;
 #endif
@@ -530,7 +530,6 @@ void main(void) {
 	normalW = perturbNormal(viewDirectionW);
 #endif
 
-
 	// Ambient color
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 
@@ -538,6 +537,21 @@ void main(void) {
 	baseAmbientColor = texture2D(ambientSampler, vAmbientUV).rgb * vAmbientInfos.y;
 #endif
 
+
+	// Specular map
+	float glossiness = vSpecularColor.a;
+#ifdef SPECULARTERM
+	vec3 specularColor = vSpecularColor.rgb;
+
+	#ifdef SPECULAR
+		vec4 specularMapColor = texture2D(specularSampler, vSpecularUV);
+		specularColor = specularMapColor.rgb;
+		#ifdef GLOSSINESS
+			glossiness = specularMapColor.a;
+		#endif
+	#endif
+#endif
+
 	// Lighting
 	vec3 diffuseBase = vec3(0., 0., 0.);
 #ifdef SPECULARTERM
@@ -550,13 +564,13 @@ void main(void) {
 	vec3 vLightSpecular0 = vec3(0.0);
 #endif
 #ifdef SPOTLIGHT0
-	lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a);
+	lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);
 #endif
 #ifdef HEMILIGHT0
-	lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0);
+	lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, glossiness);
 #endif
 #ifdef POINTDIRLIGHT0
-	lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a);
+	lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);
 #endif
 #ifdef SHADOW0
 #ifdef SHADOWVSM0
@@ -582,13 +596,13 @@ void main(void) {
 	vec3 vLightSpecular1 = vec3(0.0);
 #endif
 #ifdef SPOTLIGHT1
-	info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);
 #endif
 #ifdef HEMILIGHT1
-	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, glossiness);
 #endif
 #ifdef POINTDIRLIGHT1
-	info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a);
+	info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);
 #endif
 #ifdef SHADOW1
 #ifdef SHADOWVSM1
@@ -614,13 +628,13 @@ void main(void) {
 	vec3 vLightSpecular2 = vec3(0.0);
 #endif
 #ifdef SPOTLIGHT2
-	info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);
 #endif
 #ifdef HEMILIGHT2
-	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, glossiness);
 #endif
 #ifdef POINTDIRLIGHT2
-	info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a);
+	info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);
 #endif
 #ifdef SHADOW2
 #ifdef SHADOWVSM2
@@ -646,13 +660,13 @@ void main(void) {
 	vec3 vLightSpecular3 = vec3(0.0);
 #endif
 #ifdef SPOTLIGHT3
-	info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);
 #endif
 #ifdef HEMILIGHT3
-	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, glossiness);
 #endif
 #ifdef POINTDIRLIGHT3
-	info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a);
+	info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);
 #endif
 #ifdef SHADOW3
 #ifdef SHADOWVSM3
@@ -738,14 +752,6 @@ void main(void) {
 	emissiveColor *= emissiveLeftColor.rgb * (1.0 - emissiveFresnelTerm) + emissiveFresnelTerm * emissiveRightColor.rgb;
 #endif
 
-	// Specular map
-#ifdef SPECULARTERM
-	vec3 specularColor = vSpecularColor.rgb;
-#ifdef SPECULAR
-	specularColor = texture2D(specularSampler, vSpecularUV).rgb * vSpecularInfos.y;
-#endif
-#endif
-
 	// Fresnel
 #ifdef DIFFUSEFRESNEL
 	float diffuseFresnelTerm = computeFresnelTerm(viewDirectionW, normalW, diffuseRightColor.a, diffuseLeftColor.a);

+ 10 - 0
src/babylon.scene.js

@@ -125,6 +125,7 @@ var BABYLON;
             this._renderTargets = new BABYLON.SmartArray(256);
             this._activeParticleSystems = new BABYLON.SmartArray(256);
             this._activeSkeletons = new BABYLON.SmartArray(32);
+            this._softwareSkinnedMeshes = new BABYLON.SmartArray(32);
             this._activeBones = 0;
             this._activeAnimatables = new Array();
             this._transformMatrix = BABYLON.Matrix.Zero();
@@ -974,6 +975,7 @@ var BABYLON;
             this._processedMaterials.reset();
             this._activeParticleSystems.reset();
             this._activeSkeletons.reset();
+            this._softwareSkinnedMeshes.reset();
             this._boundingBoxRenderer.reset();
             if (!this._frustumPlanes) {
                 this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix);
@@ -1041,6 +1043,9 @@ var BABYLON;
         Scene.prototype._activeMesh = function (mesh) {
             if (mesh.skeleton && this.skeletonsEnabled) {
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+                if (!mesh.computeBonesUsingShaders) {
+                    this._softwareSkinnedMeshes.pushNoDuplicate(mesh);
+                }
             }
             if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
@@ -1093,6 +1098,11 @@ var BABYLON;
                 var skeleton = this._activeSkeletons.data[skeletonIndex];
                 skeleton.prepare();
             }
+            // Software skinning
+            for (var softwareSkinnedMeshIndex = 0; softwareSkinnedMeshIndex < this._softwareSkinnedMeshes.length; softwareSkinnedMeshIndex++) {
+                var mesh = this._softwareSkinnedMeshes.data[softwareSkinnedMeshIndex];
+                mesh.applySkeleton(mesh.skeleton);
+            }
             // Render targets
             var beforeRenderTargetDate = BABYLON.Tools.Now;
             if (this.renderTargetsEnabled) {

+ 13 - 0
src/babylon.scene.ts

@@ -239,6 +239,7 @@
         private _renderTargets = new SmartArray<RenderTargetTexture>(256);
         public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
         private _activeSkeletons = new SmartArray<Skeleton>(32);
+        private _softwareSkinnedMeshes = new SmartArray<Mesh>(32);
         public _activeBones = 0;
 
         private _renderingManager: RenderingManager;
@@ -1253,6 +1254,7 @@
             this._processedMaterials.reset();
             this._activeParticleSystems.reset();
             this._activeSkeletons.reset();
+            this._softwareSkinnedMeshes.reset();
             this._boundingBoxRenderer.reset();
 
             if (!this._frustumPlanes) {
@@ -1336,6 +1338,10 @@
         private _activeMesh(mesh: AbstractMesh): void {
             if (mesh.skeleton && this.skeletonsEnabled) {
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+
+                if (!mesh.computeBonesUsingShaders) {
+                    this._softwareSkinnedMeshes.pushNoDuplicate(mesh);
+                }
             }
 
             if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
@@ -1405,6 +1411,13 @@
                 skeleton.prepare();
             }
 
+            // Software skinning
+            for (var softwareSkinnedMeshIndex = 0; softwareSkinnedMeshIndex < this._softwareSkinnedMeshes.length; softwareSkinnedMeshIndex++) {
+                var mesh = this._softwareSkinnedMeshes.data[softwareSkinnedMeshIndex];
+
+                mesh.applySkeleton(mesh.skeleton);
+            }
+
             // Render targets
             var beforeRenderTargetDate = Tools.Now;
             if (this.renderTargetsEnabled) {