Просмотр исходного кода

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 10 лет назад
Родитель
Сommit
cf35254fe7

Разница между файлами не показана из-за своего большого размера
+ 671 - 655
dist/preview release - alpha/babylon.2.2.d.ts


Разница между файлами не показана из-за своего большого размера
+ 29 - 32
dist/preview release - alpha/babylon.2.2.js


Разница между файлами не показана из-за своего большого размера
+ 135 - 14
dist/preview release - alpha/babylon.2.2.max.js


Разница между файлами не показана из-за своего большого размера
+ 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) {