Bläddra i källkod

Multiple fixes + simplematerial for material library

David Catuhe 8 år sedan
förälder
incheckning
4d7d9045cb
29 ändrade filer med 13677 tillägg och 14209 borttagningar
  1. 1 0
      Tools/Gulp/config.json
  2. 1 0
      Tools/Gulp/custom.config.json
  3. 27 27
      dist/preview release/babylon.core.js
  4. 6468 6458
      dist/preview release/babylon.d.ts
  5. 36 36
      dist/preview release/babylon.js
  6. 266 573
      dist/preview release/babylon.max.js
  7. 6468 6458
      dist/preview release/babylon.module.d.ts
  8. 35 35
      dist/preview release/babylon.noworker.js
  9. 1 1
      materialsLibrary/src/fire/babylon.fireMaterial.ts
  10. 1 1
      materialsLibrary/src/fur/babylon.furMaterial.ts
  11. 1 1
      materialsLibrary/src/gradient/babylon.gradientMaterial.ts
  12. 1 1
      materialsLibrary/src/grid/babylon.gridmaterial.ts
  13. 1 1
      materialsLibrary/src/lava/babylon.lavaMaterial.ts
  14. 1 1
      materialsLibrary/src/normal/babylon.normalMaterial.ts
  15. 1 1
      materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts
  16. 94 128
      materialsLibrary/src/simple/babylon.simpleMaterial.ts
  17. 4 1
      materialsLibrary/src/simple/simple.fragment.fx
  18. 1 1
      materialsLibrary/src/sky/babylon.skyMaterial.ts
  19. 1 1
      materialsLibrary/src/terrain/babylon.terrainMaterial.ts
  20. 1 1
      materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts
  21. 1 1
      materialsLibrary/src/water/babylon.waterMaterial.ts
  22. 23 3
      src/Lights/babylon.light.ts
  23. 16 7
      src/Materials/babylon.material.ts
  24. 14 33
      src/Materials/babylon.materialHelper.ts
  25. 1 1
      src/Materials/babylon.pbrMaterial.ts
  26. 105 0
      src/Materials/babylon.pushMaterial.ts
  27. 1 1
      src/Materials/babylon.shaderMaterial.ts
  28. 80 437
      src/Materials/babylon.standardMaterial.ts
  29. 26 0
      src/Tools/babylon.decorators.ts

+ 1 - 0
Tools/Gulp/config.json

@@ -87,6 +87,7 @@
             "../../src/Materials/babylon.materialHelper.js",
             "../../src/Materials/babylon.fresnelParameters.js",
             "../../src/Materials/babylon.material.js",
+            "../../src/Materials/babylon.pushMaterial.js",
             "../../src/Materials/babylon.standardMaterial.js",
             "../../src/Materials/babylon.multiMaterial.js",
             "../../src/Loading/babylon.sceneLoader.js",

+ 1 - 0
Tools/Gulp/custom.config.json

@@ -81,6 +81,7 @@
       "../../src/Materials/babylon.effect.js",
       "../../src/Materials/babylon.materialHelper.js",
       "../../src/Materials/babylon.fresnelParameters.js",
+      "../../src/Materials/babylon.pushMaterial.js",
       "../../src/Materials/babylon.material.js",
       "../../src/Materials/babylon.standardMaterial.js",
       "../../src/Materials/babylon.multiMaterial.js",

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 27 - 27
dist/preview release/babylon.core.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6468 - 6458
dist/preview release/babylon.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 36 - 36
dist/preview release/babylon.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 266 - 573
dist/preview release/babylon.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6468 - 6458
dist/preview release/babylon.module.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 35 - 35
dist/preview release/babylon.noworker.js


+ 1 - 1
materialsLibrary/src/fire/babylon.fireMaterial.ts

@@ -272,7 +272,7 @@ module BABYLON {
             // Speed
             this._effect.setFloat("speed", this.speed);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/fur/babylon.furMaterial.ts

@@ -382,7 +382,7 @@ module BABYLON {
                 this._effect.setTexture("furTexture", this.furTexture);
             }
  
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/gradient/babylon.gradientMaterial.ts

@@ -320,7 +320,7 @@ module BABYLON {
             this._effect.setFloat("offset", this.offset);
             this._effect.setFloat("smoothness", this.smoothness);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/grid/babylon.gridmaterial.ts

@@ -182,7 +182,7 @@ module BABYLON {
             // Fog
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public dispose(forceDisposeEffect?: boolean): void {

+ 1 - 1
materialsLibrary/src/lava/babylon.lavaMaterial.ts

@@ -353,7 +353,7 @@ module BABYLON {
             this._effect.setFloat("movingSpeed", this.movingSpeed);
 
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/normal/babylon.normalMaterial.ts

@@ -311,7 +311,7 @@ module BABYLON {
             // Fog
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts

@@ -206,7 +206,7 @@ module BABYLON {
             // Fog
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public clone(name: string): ShadowOnlyMaterial {

+ 94 - 128
materialsLibrary/src/simple/babylon.simpleMaterial.ts

@@ -22,30 +22,31 @@ module BABYLON {
         }
     }
 
-    export class SimpleMaterial extends Material {
-        @serializeAsTexture()
+    export class SimpleMaterial extends PushMaterial {
+        @serializeAsTexture("diffuseTexture")
+        private _diffuseTexture: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public diffuseTexture: BaseTexture;
 
         @serializeAsColor3("diffuseColor")
         public diffuseColor = new Color3(1, 1, 1);
         
-        @serialize()
-        public disableLighting = false;        
+        @serialize("disableLighting")
+        private _disableLighting = false;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public disableLighting: boolean;   
         
-        @serialize()
-        public maxSimultaneousLights = 4;
+        @serialize("maxSimultaneousLights")
+        private _maxSimultaneousLights = 4;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public maxSimultaneousLights: number; 
 
         private _worldViewProjectionMatrix = Matrix.Zero();
         private _scaledDiffuse = new Color3();
         private _renderId: number;
 
-        private _defines = new SimpleMaterialDefines();
-        private _cachedDefines = new SimpleMaterialDefines();
-
         constructor(name: string, scene: Scene) {
             super(name, scene);
-
-            this._cachedDefines.BonesPerMesh = -1;
         }
 
         public needAlphaBlending(): boolean {
@@ -61,149 +62,106 @@ module BABYLON {
         }
 
         // Methods   
-        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            if (!mesh) {
-                return true;
-            }
-
-            if (this._defines.INSTANCES !== useInstances) {
-                return false;
-            }
-            
-            return false;
-        }
-
-        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            if (this.checkReadyOnlyOnce) {
-                if (this._wasPreviouslyReady) {
+        public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {   
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady && subMesh.effect) {
                     return true;
                 }
             }
 
+            if (!subMesh._materialDefines) {
+                subMesh._materialDefines = new SimpleMaterialDefines();
+            }
+
+            var defines = <SimpleMaterialDefines>subMesh._materialDefines;
             var scene = this.getScene();
 
             if (!this.checkReadyOnEveryCall) {
                 if (this._renderId === scene.getRenderId()) {
-                    if (this._checkCache(scene, mesh, useInstances)) {
-                        return true;
-                    }
+                    return true;
                 }
             }
 
             var engine = scene.getEngine();
-            var needNormals = false;
-            var needUVs = false;
-
-            this._defines.reset();
 
             // Textures
-            if (scene.texturesEnabled) {
-                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
-                    if (!this.diffuseTexture.isReady()) {
-                        return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.DIFFUSE = true;
-                    }
-                }                
-            }
-
-            // Effect
-            if (scene.clipPlane) {
-                this._defines.CLIPPLANE = true;
+            if (defines._areTexturesDirty) {
+                defines._needUVs = false;
+                if (scene.texturesEnabled) {
+                    if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                        if (!this._diffuseTexture.isReady()) {
+                            return false;
+                        } else {
+                            defines._needUVs = true;
+                            defines.DIFFUSE = true;
+                        }
+                    }                
+                }
+                defines._areTexturesDirty = false;
             }
 
-            if (engine.getAlphaTesting()) {
-                this._defines.ALPHATEST = true;
-            }
+            // Misc.
+            if (defines._areMiscDirty) {
+                defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);
+                defines.FOG = (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled);
 
-            // Point size
-            if (this.pointsCloud || scene.forcePointsCloud) {
-                this._defines.POINTSIZE = true;
+                defines._areMiscDirty = false;
             }
 
-            // Fog
-            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
-                this._defines.FOG = true;
-            }
-
-            if (scene.lightsEnabled && !this.disableLighting) {
-                needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, this.maxSimultaneousLights);
-            }
+            // Lights
+            defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, this._maxSimultaneousLights, this._disableLighting);
+            defines._areLightsDirty = false;
 
+            // Values that need to be evaluated on every frame
+            defines.CLIPPLANE = (scene.clipPlane !== undefined && scene.clipPlane !== null);
+            defines.ALPHATEST = engine.getAlphaTesting();
+            defines.INSTANCES = useInstances;
+            
             // Attribs
-            if (mesh) {
-                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-                    this._defines.NORMAL = true;
-                }
-                if (needUVs) {
-                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                        this._defines.UV1 = true;
-                    }
-                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
-                        this._defines.UV2 = true;
-                    }
-                }
-                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
-                    this._defines.VERTEXCOLOR = true;
-
-                    if (mesh.hasVertexAlpha) {
-                        this._defines.VERTEXALPHA = true;
-                    }
-                }
-                if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._defines.NUM_BONE_INFLUENCERS = mesh.numBoneInfluencers;
-                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
-                }
-
-                // Instances
-                if (useInstances) {
-                    this._defines.INSTANCES = true;
-                }
-            }
+            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, useInstances);
+            defines._areAttributesDirty = false;
 
             // Get correct effect      
-            if (!this._defines.isEqual(this._cachedDefines)) {
-                this._defines.cloneTo(this._cachedDefines);
-
+            if (defines._isDirty) {
+                defines._isDirty = false;
                 scene.resetCachedMaterial();
 
                 // Fallbacks
                 var fallbacks = new EffectFallbacks();             
-                if (this._defines.FOG) {
+                if (defines.FOG) {
                     fallbacks.addFallback(1, "FOG");
                 }
 
-                MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, this.maxSimultaneousLights);
+                MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this.maxSimultaneousLights);
                 
-                if (this._defines.NUM_BONE_INFLUENCERS > 0) {
+                if (defines.NUM_BONE_INFLUENCERS > 0) {
                     fallbacks.addCPUSkinningFallback(0, mesh);
                 }
 
                 //Attributes
                 var attribs = [VertexBuffer.PositionKind];
 
-                if (this._defines.NORMAL) {
+                if (defines.NORMAL) {
                     attribs.push(VertexBuffer.NormalKind);
                 }
 
-                if (this._defines.UV1) {
+                if (defines.UV1) {
                     attribs.push(VertexBuffer.UVKind);
                 }
 
-                if (this._defines.UV2) {
+                if (defines.UV2) {
                     attribs.push(VertexBuffer.UV2Kind);
                 }
 
-                if (this._defines.VERTEXCOLOR) {
+                if (defines.VERTEXCOLOR) {
                     attribs.push(VertexBuffer.ColorKind);
                 }
 
-                MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
-                MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+                MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
+                MaterialHelper.PrepareAttributesForInstances(attribs, defines);
 
                 var shaderName = "simple";
-                var join = this._defines.toString();
+                var join = defines.toString();
                 var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor",
                                 "vFogInfos", "vFogColor", "pointSize",
                                 "vDiffuseInfos", 
@@ -212,13 +170,13 @@ module BABYLON {
                 ];
                 var samplers = ["diffuseSampler"];
                     
-                MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, this.maxSimultaneousLights);
+                MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, defines, this.maxSimultaneousLights);
                 
-                this._effect = scene.getEngine().createEffect(shaderName,
+                subMesh.setEffect(scene.getEngine().createEffect(shaderName,
                     attribs, uniforms, samplers,
-                    join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: this.maxSimultaneousLights});
+                    join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this._maxSimultaneousLights - 1 }), defines);
             }
-            if (!this._effect.isReady()) {
+            if (!subMesh.effect.isReady()) {
                 return false;
             }
 
@@ -229,70 +187,78 @@ module BABYLON {
         }
 
         public bindOnlyWorldMatrix(world: Matrix): void {
-            this._effect.setMatrix("world", world);
+            this._activeEffect.setMatrix("world", world);
         }
 
-        public bind(world: Matrix, mesh?: Mesh): void {
+        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
             var scene = this.getScene();
 
+            var defines = <SimpleMaterialDefines>subMesh._materialDefines;
+            if (!defines) {
+                return;
+            }
+
+            var effect = subMesh.effect;
+            this._activeEffect = effect;
+
             // Matrices        
             this.bindOnlyWorldMatrix(world);
-            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+            this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            MaterialHelper.BindBonesParameters(mesh, this._effect);
+            MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
 
-            if (scene.getCachedMaterial() !== this) {
+            if (this._mustRebind(scene, effect)) {
                 // Textures        
-                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
-                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+                if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._activeEffect.setTexture("diffuseSampler", this._diffuseTexture);
 
-                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                    this._activeEffect.setFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
+                    this._activeEffect.setMatrix("diffuseMatrix", this._diffuseTexture.getTextureMatrix());
                 }
                 
                 // Clip plane
-                MaterialHelper.BindClipPlane(this._effect, scene);
+                MaterialHelper.BindClipPlane(this._activeEffect, scene);
 
                 // Point size
                 if (this.pointsCloud) {
-                    this._effect.setFloat("pointSize", this.pointSize);
+                    this._activeEffect.setFloat("pointSize", this.pointSize);
                 }
 
-                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+                this._activeEffect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
             }
 
-            this._effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
+            this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
 
             // Lights
             if (scene.lightsEnabled && !this.disableLighting) {
-                MaterialHelper.BindLights(scene, mesh, this._effect, this._defines, this.maxSimultaneousLights);          
+                MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this.maxSimultaneousLights);          
             }
 
             // View
             if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
-                this._effect.setMatrix("view", scene.getViewMatrix());
+                this._activeEffect.setMatrix("view", scene.getViewMatrix());
             }
 
             // Fog
-            MaterialHelper.BindFogParameters(scene, mesh, this._effect);
+            MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh, this._activeEffect);
         }
 
         public getAnimatables(): IAnimatable[] {
             var results = [];
 
-            if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) {
-                results.push(this.diffuseTexture);
+            if (this._diffuseTexture && this._diffuseTexture.animations && this._diffuseTexture.animations.length > 0) {
+                results.push(this._diffuseTexture);
             }
 
             return results;
         }
 
         public dispose(forceDisposeEffect?: boolean): void {
-            if (this.diffuseTexture) {
-                this.diffuseTexture.dispose();
+            if (this._diffuseTexture) {
+                this._diffuseTexture.dispose();
             }
 
             super.dispose(forceDisposeEffect);

+ 4 - 1
materialsLibrary/src/simple/simple.fragment.fx

@@ -73,7 +73,10 @@ void main(void) {
     lightingInfo info;
 	float shadow = 1.;
     float glossiness = 0.;
-    
+
+#ifdef SPECULARTERM
+	vec3 specularBase = vec3(0., 0., 0.);
+#endif    
 #include<lightFragment>[0..maxSimultaneousLights]
 
 

+ 1 - 1
materialsLibrary/src/sky/babylon.skyMaterial.ts

@@ -231,7 +231,7 @@ module BABYLON {
             
 			this._effect.setVector3("sunPosition", this.sunPosition);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/terrain/babylon.terrainMaterial.ts

@@ -343,7 +343,7 @@ module BABYLON {
             // Fog
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts

@@ -335,7 +335,7 @@ module BABYLON {
             // Fog
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public getAnimatables(): IAnimatable[] {

+ 1 - 1
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -480,7 +480,7 @@ module BABYLON {
             this._effect.setFloat("colorBlendFactor2", this.colorBlendFactor2);
             this._effect.setFloat("waveSpeed", this.waveSpeed);
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
 		}
 		
 		private _createRenderTargets(scene: Scene, renderTargetSize: Vector2): void {

+ 23 - 3
src/Lights/babylon.light.ts

@@ -77,7 +77,7 @@
 
         public set includedOnlyMeshes(value: AbstractMesh[]) {
             this._includedOnlyMeshes = value;
-            this._hookArray(value);
+            this._hookArrayForIncludedOnly(value);
         }
 
         private _excludedMeshes: AbstractMesh[];
@@ -86,7 +86,7 @@
         }
         public set excludedMeshes(value: AbstractMesh[]) {
             this._excludedMeshes = value;
-            this._hookArray(value);
+            this._hookArrayForExcluded(value);
         }        
 
         @serialize("excludeWithLayerMask")
@@ -380,7 +380,7 @@
             return light;
         }
 
-        private _hookArray(array: AbstractMesh[]): void {
+        private _hookArrayForExcluded(array: AbstractMesh[]): void {
             var oldPush = array.push;
             array.push = (...items: AbstractMesh[]) => {
                 var result = oldPush.apply(array, items);
@@ -404,6 +404,26 @@
             }
         }
 
+        private _hookArrayForIncludedOnly(array: AbstractMesh[]): void {
+            var oldPush = array.push;
+            array.push = (...items: AbstractMesh[]) => {
+                var result = oldPush.apply(array, items);
+
+                this._resyncMeshes();
+
+                return result;
+            }
+
+            var oldSplice = array.splice;
+            array.splice = (index: number, deleteCount?: number) => {
+                var deleted = oldSplice.apply(array, [index, deleteCount]);
+
+                this._resyncMeshes();
+
+                return deleted;
+            }
+        }
+
         private _resyncMeshes() {
             for (var mesh of this.getScene().meshes) {
                 mesh._resyncLighSource(this);

+ 16 - 7
src/Materials/babylon.material.ts

@@ -5,8 +5,13 @@
         _trackIsDirty = false;    
 
         public _renderId: number;
+
         public _areLightsDirty = true;
         public _areAttributesDirty = true;
+        public _areTexturesDirty = true;
+        public _areFresnelDirty = true;
+        public _areMiscDirty = true;    
+
         public _needNormals = false;
         public _needUVs = false;
 
@@ -57,6 +62,8 @@
 
                 this._reBind(key);
             }
+
+            this._isDirty = true;
         } 
 
         public isEqual(other: MaterialDefines): boolean {
@@ -406,6 +413,15 @@
         }
 
         public bind(world: Matrix, mesh?: Mesh): void {
+        }
+
+        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {            
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+        }
+
+        protected _afterBind(mesh: Mesh): void {
             this._scene._cachedMaterial = this;
 
             this.onBindObservable.notifyObservers(mesh);
@@ -417,13 +433,6 @@
             }
         }
 
-        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
-            this._scene._cachedEffect = subMesh.effect;
-        }
-
-        public bindOnlyWorldMatrix(world: Matrix): void {
-        }
-
         public unbind(): void {
 
             this.onUnBindObservable.notifyObservers(this);

+ 14 - 33
src/Materials/babylon.materialHelper.ts

@@ -1,5 +1,6 @@
 module BABYLON {
     export class MaterialHelper {
+
         public static PrepareDefinesForAttributes(mesh: AbstractMesh, defines: MaterialDefines, useInstances: boolean): void {
             if (!defines._areAttributesDirty) {
                 return;
@@ -36,7 +37,6 @@
             var lightIndex = 0;
             var needNormals = false;
             var needRebuild = false;
-            var needShadows = false;
             var lightmapMode = false;
             var shadowEnabled = false;
             var specularEnabled = false;
@@ -48,7 +48,13 @@
                     if (defines["LIGHT" + lightIndex] === undefined) {
                         needRebuild = true;
                     }
+
                     defines["LIGHT" + lightIndex] = true;
+                    
+                    defines["SPOTLIGHT" + lightIndex] = false;
+                    defines["HEMILIGHT" + lightIndex] = false;
+                    defines["POINTLIGHT" + lightIndex] = false;
+                    defines["DIRLIGHT" + lightIndex] = false;
 
                     var type;
                     if (light instanceof SpotLight) {
@@ -61,10 +67,6 @@
                         type = "DIRLIGHT" + lightIndex;
                     }
 
-                    if (!needRebuild && defines[type] === undefined) {
-                        needRebuild = true;
-                    }
-
                     defines[type] = true;
 
                     // Specular
@@ -73,45 +75,28 @@
                     }
 
                     // Shadows
+                    defines["SHADOW" + lightIndex] = false;
                     if (scene.shadowsEnabled) {
                         var shadowGenerator = <ShadowGenerator>light.getShadowGenerator();
                         if (mesh && mesh.receiveShadows && shadowGenerator) {
-                            if (!needRebuild && defines["SHADOW" + lightIndex] === undefined) {
-                                needRebuild = true;
-                            }
                             defines["SHADOW" + lightIndex] = true;
 
                             shadowEnabled = true;
 
-                            if (shadowGenerator.usePoissonSampling) {
-                                if (!needRebuild && defines["SHADOWPCF" + lightIndex] === undefined) {
-                                    needRebuild = true;
-                                }
+                            defines["SHADOWPCF" + lightIndex] = false;
+                            defines["SHADOWESM" + lightIndex] = false;
 
+                            if (shadowGenerator.usePoissonSampling) {
                                 defines["SHADOWPCF" + lightIndex] = true;
                             } 
                             else if (shadowGenerator.useExponentialShadowMap || shadowGenerator.useBlurExponentialShadowMap) {
-                                if (!needRebuild && defines["SHADOWESM" + lightIndex] === undefined) {
-                                    needRebuild = true;
-                                }
-
                                 defines["SHADOWESM" + lightIndex] = true;
                             }
-
-                            needShadows = true;
-                        } else {
-                            defines["SHADOW" + lightIndex] = false;
                         }
                     }
 
                     if (light.lightmapMode != Light.LIGHTMAP_DEFAULT ) {
                         lightmapMode = true;
-                        if (!needRebuild && defines["LIGHTMAPEXCLUDED" + lightIndex] === undefined) {
-                            needRebuild = true;
-                        }
-                        if (!needRebuild && defines["LIGHTMAPNOSPECULAR" + lightIndex] === undefined) {
-                            needRebuild = true;
-                        }
                         defines["LIGHTMAPEXCLUDED" + lightIndex] = true;
                         defines["LIGHTMAPNOSPECULAR" + lightIndex] = (light.lightmapMode == Light.LIGHTMAP_SHADOWSONLY);
                     } else {
@@ -136,21 +121,17 @@
             }
 
             let caps = scene.getEngine().getCaps();
-            if (!needRebuild && defines["SHADOWFULLFLOAT"] === undefined) {
-                needRebuild = true;
-            }
 
-            defines["SHADOWFULLFLOAT"] = (needShadows && caps.textureFloat && caps.textureFloatLinearFiltering && caps.textureFloatRender);
-
-            if (!needRebuild && defines["LIGHTMAPEXCLUDED"] === undefined) {
+            if (defines["SHADOWFULLFLOAT"] === undefined) {
                 needRebuild = true;
             }
 
+            defines["SHADOWFULLFLOAT"] = (shadowEnabled && caps.textureFloat && caps.textureFloatLinearFiltering && caps.textureFloatRender);
             defines["LIGHTMAPEXCLUDED"] = lightmapMode;
 
             if (needRebuild) {
                 defines.rebuild();
-            }        
+            }
 
             return needNormals;
         }

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

@@ -1392,7 +1392,7 @@
                 // Log. depth
                 MaterialHelper.BindLogDepth(this._defines, this._effect, this._myScene);
             }
-            super.bind(world, mesh);
+            this._afterBind(mesh);
 
             this._myScene = null;
         }

+ 105 - 0
src/Materials/babylon.pushMaterial.ts

@@ -0,0 +1,105 @@
+module BABYLON {
+    export class PushMaterial extends Material {
+
+        protected _activeEffect: Effect;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+            this.storeEffectOnSubMeshes = true;
+        }
+
+        public getEffect(): Effect {
+            return this._activeEffect;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return false;
+            }
+
+            if (!mesh.subMeshes || mesh.subMeshes.length === 0) {
+                return true;
+            }
+
+            return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            if (!mesh) {
+                return;
+            }
+
+            this.bindForSubMesh(world, mesh, mesh.subMeshes[0]);
+        }
+
+        protected _afterBind(mesh: Mesh, effect?: Effect): void {
+            super._afterBind(mesh);
+            this.getScene()._cachedEffect = effect;
+        }
+
+        protected _mustRebind(scene: Scene, effect: Effect) {
+            return scene.getCachedEffect() !== effect || scene.getCachedMaterial() !== this;
+        }
+
+        public markAsDirty(flag: number): void {
+            if (flag & Material.TextureDirtyFlag) {
+                this._markAllSubMeshesAsTexturesDirty();
+            }
+
+            if (flag & Material.LightDirtyFlag) {
+                this._markAllSubMeshesAsLightsDirty();
+            }
+
+            if (flag & Material.FresnelDirtyFlag) {
+                this._markAllSubMeshesAsFresnelDirty();
+            }
+
+            if (flag & Material.AttributesDirtyFlag) {
+                this._markAllSubMeshesAsAttributesDirty();
+            }
+
+            if (flag & Material.MiscDirtyFlag) {
+                this._markAllSubMeshesAsMiscDirty();
+            }
+        }
+
+        protected _markAllSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
+            for (var mesh of this.getScene().meshes) {
+                if (!mesh.subMeshes) {
+                    continue;
+                }
+                for (var subMesh of mesh.subMeshes) {
+                    if (subMesh.getMaterial() !== this) {
+                        continue;
+                    }
+
+                    if (!subMesh._materialDefines) {
+                        return;
+                    }
+
+                    func(subMesh._materialDefines);
+                }
+            }
+        }
+
+        protected _markAllSubMeshesAsTexturesDirty() {
+            this._markAllSubMeshesAsDirty(defines => defines._areTexturesDirty = true);
+        }
+
+        protected _markAllSubMeshesAsFresnelDirty() {
+            this._markAllSubMeshesAsDirty(defines => defines._areFresnelDirty = true);
+        }
+
+        protected _markAllSubMeshesAsLightsDirty() {
+            this._markAllSubMeshesAsDirty(defines => defines._areLightsDirty = true);
+        }
+
+        protected _markAllSubMeshesAsAttributesDirty() {
+            this._markAllSubMeshesAsDirty(defines => defines._areAttributesDirty = true);
+        }
+
+        protected _markAllSubMeshesAsMiscDirty() {
+            this._markAllSubMeshesAsDirty(defines => defines._areMiscDirty = true);
+        }
+    }
+} 

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

@@ -329,7 +329,7 @@
                 }
             }
 
-            super.bind(world, mesh);
+            this._afterBind(mesh);
         }
 
         public clone(name: string): ShaderMaterial {

+ 80 - 437
src/Materials/babylon.standardMaterial.ts

@@ -60,10 +60,6 @@ module BABYLON {
         public CAMERACOLORGRADING = false;
         public CAMERACOLORCURVES = false;
 
-        public _areTexturesDirty = true;
-        public _areFresnelDirty = true;
-        public _areMiscDirty = true;
-
         constructor() {
             super(true);
             this.rebuild();
@@ -83,132 +79,51 @@ module BABYLON {
         }
     }
 
-    export class StandardMaterial extends Material {
+    export class StandardMaterial extends PushMaterial {
         @serializeAsTexture("diffuseTexture")
         private _diffuseTexture: BaseTexture;
-        public set diffuseTexture(value : BaseTexture) {
-            if (this._diffuseTexture === value) {
-                return;
-            }
-            this._diffuseTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get diffuseTexture(): BaseTexture {
-            return this._diffuseTexture;
-        }
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture: BaseTexture;
 
         @serializeAsTexture("ambientTexture")
         private _ambientTexture: BaseTexture;
-        public set ambientTexture(value : BaseTexture) {
-            if (this._ambientTexture === value) {
-                return;
-            }
-            this._ambientTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get ambientTexture(): BaseTexture {
-            return this._ambientTexture;
-        }
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public ambientTexture: BaseTexture;
 
         @serializeAsTexture("opacityTexture")
-        private _opacityTexture: BaseTexture;
-        public set opacityTexture(value : BaseTexture) {
-            if (this._opacityTexture === value) {
-                return;
-            }
-            this._opacityTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get opacityTexture(): BaseTexture {
-            return this._opacityTexture;
-        }        
+        private _opacityTexture: BaseTexture;        
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public opacityTexture: BaseTexture;    
 
         @serializeAsTexture("reflectionTexture")
         private _reflectionTexture: BaseTexture;
-        public set reflectionTexture(value : BaseTexture) {
-            if (this._reflectionTexture === value) {
-                return;
-            }
-            this._reflectionTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get reflectionTexture(): BaseTexture {
-            return this._reflectionTexture;
-        }           
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionTexture: BaseTexture;        
 
         @serializeAsTexture("emissiveTexture")
         private _emissiveTexture: BaseTexture;
-        public set emissiveTexture(value : BaseTexture) {
-            if (this._emissiveTexture === value) {
-                return;
-            }
-            this._emissiveTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get emissiveTexture(): BaseTexture {
-            return this._emissiveTexture;
-        }  
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public emissiveTexture: BaseTexture;     
 
         @serializeAsTexture("specularTexture")
         private _specularTexture: BaseTexture;
-        public set specularTexture(value : BaseTexture) {
-            if (this._specularTexture === value) {
-                return;
-            }
-            this._specularTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get specularTexture(): BaseTexture {
-            return this._specularTexture;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public specularTexture: BaseTexture;             
 
         @serializeAsTexture("bumpTexture")
         private _bumpTexture: BaseTexture;
-        public set bumpTexture(value : BaseTexture) {
-            if (this._bumpTexture === value) {
-                return;
-            }
-            this._bumpTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get bumpTexture(): BaseTexture {
-            return this._bumpTexture;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public bumpTexture: BaseTexture;         
 
         @serializeAsTexture("lightmapTexture")
         private _lightmapTexture: BaseTexture;
-        public set lightmapTexture(value : BaseTexture) {
-            if (this._lightmapTexture === value) {
-                return;
-            }
-            this._lightmapTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get lightmapTexture(): BaseTexture {
-            return this._lightmapTexture;
-        }             
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public lightmapTexture: BaseTexture;            
 
         @serializeAsTexture("refractionTexture")
         private _refractionTexture: BaseTexture;
-        public set refractionTexture(value : BaseTexture) {
-            if (this._refractionTexture === value) {
-                return;
-            }
-            this._refractionTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get refractionTexture(): BaseTexture {
-            return this._refractionTexture;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public refractionTexture: BaseTexture;   
 
         @serializeAsColor3("ambient")
         public ambientColor = new Color3(0, 0, 0);
@@ -227,123 +142,52 @@ module BABYLON {
 
         @serialize("useAlphaFromDiffuseTexture")
         private _useAlphaFromDiffuseTexture = false;
-        public set useAlphaFromDiffuseTexture(value : boolean) {
-            if (this._useAlphaFromDiffuseTexture === value) {
-                return;
-            }
-            this._useAlphaFromDiffuseTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useAlphaFromDiffuseTexture(): boolean {
-            return this._useAlphaFromDiffuseTexture;
-        }           
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useAlphaFromDiffuseTexture: boolean;      
 
         @serialize("useEmissiveAsIllumination")
         private _useEmissiveAsIllumination = false;
-        public set useEmissiveAsIllumination(value : boolean) {
-            if (this._useAlphaFromDiffuseTexture === value) {
-                return;
-            }
-            this._useEmissiveAsIllumination = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useEmissiveAsIllumination(): boolean {
-            return this._useEmissiveAsIllumination;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useEmissiveAsIllumination: boolean;           
       
         @serialize("linkEmissiveWithDiffuse")
         private _linkEmissiveWithDiffuse = false;
-        public set linkEmissiveWithDiffuse(value : boolean) {
-            if (this._linkEmissiveWithDiffuse === value) {
-                return;
-            }
-            this._linkEmissiveWithDiffuse = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get linkEmissiveWithDiffuse(): boolean {
-            return this._linkEmissiveWithDiffuse;
-        }                    
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public linkEmissiveWithDiffuse: boolean;                    
 
         @serialize("useSpecularOverAlpha")
         private _useSpecularOverAlpha = false;
-        public set useSpecularOverAlpha(value : boolean) {
-            if (this._useSpecularOverAlpha === value) {
-                return;
-            }
-            this._useSpecularOverAlpha = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useSpecularOverAlpha(): boolean {
-            return this._useSpecularOverAlpha;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useSpecularOverAlpha: boolean;               
 
         @serialize("useReflectionOverAlpha")
         private _useReflectionOverAlpha = false;
-        public set useReflectionOverAlpha(value : boolean) {
-            if (this._useReflectionOverAlpha === value) {
-                return;
-            }
-            this._useReflectionOverAlpha = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useReflectionOverAlpha(): boolean {
-            return this._useReflectionOverAlpha;
-        }            
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useReflectionOverAlpha: boolean;               
 
         @serialize("disableLighting")
         private _disableLighting = false;
-        public set disableLighting(value : boolean) {
-            if (this._disableLighting === value) {
-                return;
-            }
-            this._disableLighting = value;
-            this._markAllSubMeshesAsLightsDirty();
-        }
-        public get disableLighting(): boolean {
-            return this._disableLighting;
-        }            
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public disableLighting: boolean;           
+          
 
         @serialize("useParallax")
         private _useParallax = false;
-        public set useParallax(value : boolean) {
-            if (this._useParallax === value) {
-                return;
-            }
-            this._useParallax = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useParallax(): boolean {
-            return this._useParallax;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useParallax: boolean;            
 
         @serialize("useParallaxOcclusion")
         private _useParallaxOcclusion = false;
-        public set useParallaxOcclusion(value : boolean) {
-            if (this._useParallaxOcclusion === value) {
-                return;
-            }
-            this._useParallaxOcclusion = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useParallaxOcclusion(): boolean {
-            return this._useParallaxOcclusion;
-        }         
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useParallaxOcclusion: boolean;                  
 
         @serialize()
         public parallaxScaleBias = 0.05;
 
         @serialize("roughness")
         private _roughness = 0;
-        public set roughness(value : number) {
-            if (this._roughness === value) {
-                return;
-            }
-            this._roughness = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get roughness(): number {
-            return this._roughness;
-        }         
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public roughness: number;            
 
         @serialize()
         public indexOfRefraction = 0.98;
@@ -353,189 +197,84 @@ module BABYLON {
 
         @serialize("useLightmapAsShadowmap")
         private _useLightmapAsShadowmap = false;
-        public set useLightmapAsShadowmap(value : boolean) {
-            if (this._useLightmapAsShadowmap === value) {
-                return;
-            }
-            this._useLightmapAsShadowmap = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useLightmapAsShadowmap(): boolean {
-            return this._useLightmapAsShadowmap;
-        }            
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useLightmapAsShadowmap: boolean;             
 
         // Fresnel
         @serializeAsFresnelParameters("diffuseFresnelParameters")
         private _diffuseFresnelParameters: FresnelParameters;
-        public set diffuseFresnelParameters(value : FresnelParameters) {
-            if (this._diffuseFresnelParameters === value) {
-                return;
-            }
-            this._diffuseFresnelParameters = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get diffuseFresnelParameters(): FresnelParameters {
-            return this._diffuseFresnelParameters;
-        }           
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public diffuseFresnelParameters: FresnelParameters;            
 
         @serializeAsFresnelParameters("opacityFresnelParameters")
         private _opacityFresnelParameters: FresnelParameters;
-        public set opacityFresnelParameters(value : FresnelParameters) {
-            if (this._opacityFresnelParameters === value) {
-                return;
-            }
-            this._opacityFresnelParameters = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get opacityFresnelParameters(): FresnelParameters {
-            return this._opacityFresnelParameters;
-        }             
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public opacityFresnelParameters: FresnelParameters;            
+           
 
         @serializeAsFresnelParameters("reflectionFresnelParameters")
         private _reflectionFresnelParameters: FresnelParameters;
-        public set reflectionFresnelParameters(value : FresnelParameters) {
-            if (this._reflectionFresnelParameters === value) {
-                return;
-            }
-            this._reflectionFresnelParameters = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get reflectionFresnelParameters(): FresnelParameters {
-            return this._reflectionFresnelParameters;
-        }           
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public reflectionFresnelParameters: FresnelParameters;             
 
         @serializeAsFresnelParameters("refractionFresnelParameters")
         private _refractionFresnelParameters: FresnelParameters;
-        public set refractionFresnelParameters(value : FresnelParameters) {
-            if (this._refractionFresnelParameters === value) {
-                return;
-            }
-            this._refractionFresnelParameters = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get refractionFresnelParameters(): FresnelParameters {
-            return this._refractionFresnelParameters;
-        }          
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public refractionFresnelParameters: FresnelParameters;           
 
         @serializeAsFresnelParameters("emissiveFresnelParameters")
         private _emissiveFresnelParameters: FresnelParameters;
-        public set emissiveFresnelParameters(value : FresnelParameters) {
-            if (this._emissiveFresnelParameters === value) {
-                return;
-            }
-            this._emissiveFresnelParameters = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get emissiveFresnelParameters(): FresnelParameters {
-            return this._emissiveFresnelParameters;
-        }         
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public emissiveFresnelParameters: FresnelParameters;            
 
         @serialize("useReflectionFresnelFromSpecular")
         private _useReflectionFresnelFromSpecular = false;    
-        public set useReflectionFresnelFromSpecular(value : boolean) {
-            if (this._useReflectionFresnelFromSpecular === value) {
-                return;
-            }
-            this._useReflectionFresnelFromSpecular = value;
-            this._markAllSubMeshesAsFresnelDirty();
-        }
-        public get useReflectionFresnelFromSpecular(): boolean {
-            return this._useReflectionFresnelFromSpecular;
-        }               
+        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        public useReflectionFresnelFromSpecular: boolean;                 
 
         @serialize("useGlossinessFromSpecularMapAlpha")
         private _useGlossinessFromSpecularMapAlpha = false;
-        public set useGlossinessFromSpecularMapAlpha(value : boolean) {
-            if (this._useGlossinessFromSpecularMapAlpha === value) {
-                return;
-            }
-            this._useGlossinessFromSpecularMapAlpha = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get useGlossinessFromSpecularMapAlpha(): boolean {
-            return this._useGlossinessFromSpecularMapAlpha;
-        }        
-
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useGlossinessFromSpecularMapAlpha: boolean;           
+  
         @serialize("maxSimultaneousLights")
         private _maxSimultaneousLights = 4;
-        public set maxSimultaneousLights(value : number) {
-            if (this._maxSimultaneousLights === value) {
-                return;
-            }
-            this._maxSimultaneousLights = value;
-            this._markAllSubMeshesAsLightsDirty();
-        }
-        public get maxSimultaneousLights(): number {
-            return this._maxSimultaneousLights;
-        }          
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public maxSimultaneousLights: number;                   
 
         /**
          * If sets to true, x component of normal map value will invert (x = 1.0 - x).
          */
         @serialize("invertNormalMapX")
         private _invertNormalMapX = false;
-        public set invertNormalMapX(value : boolean) {
-            if (this._invertNormalMapX === value) {
-                return;
-            }
-            this._invertNormalMapX = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get invertNormalMapX(): boolean {
-            return this._invertNormalMapX;
-        }           
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public invertNormalMapX: boolean;
 
         /**
          * If sets to true, y component of normal map value will invert (y = 1.0 - y).
          */
         @serialize("invertNormalMapY")
         private _invertNormalMapY = false;
-        public set invertNormalMapY(value : boolean) {
-            if (this._invertNormalMapY === value) {
-                return;
-            }
-            this._invertNormalMapY = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get invertNormalMapY(): boolean {
-            return this._invertNormalMapY;
-        }           
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public invertNormalMapY: boolean;
 
         /**
          * If sets to true and backfaceCulling is false, normals will be flipped on the backside.
          */
         @serialize("twoSidedLighting")
         private _twoSidedLighting = false;
-        public set twoSidedLighting(value : boolean) {
-            if (this._twoSidedLighting === value) {
-                return;
-            }
-            this._twoSidedLighting = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-        public get inverttwoSidedLightingNormalMapY(): boolean {
-            return this._twoSidedLighting;
-        }            
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public twoSidedLighting: boolean;     
 
         /**
          * Color Grading 2D Lookup Texture.
          * This allows special effects like sepia, black and white to sixties rendering style. 
          */
-        @serializeAsTexture()
+        @serializeAsTexture("cameraColorGradingTexture")
         private _cameraColorGradingTexture: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public cameraColorGradingTexture: BaseTexture;             
 
-        public set cameraColorGradingTexture(value : BaseTexture) {
-            if (this._cameraColorGradingTexture === value) {
-                return;
-            }
-            this._cameraColorGradingTexture = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get cameraColorGradingTexture(): BaseTexture {
-            return this._cameraColorGradingTexture;
-        }           
-        
         /**
          * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). 
          * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
@@ -544,17 +283,8 @@ module BABYLON {
          */
         @serializeAsColorCurves("cameraColorCurves")
         private _cameraColorCurves: ColorCurves = null;
-        public set cameraColorCurves(value : ColorCurves) {
-            if (this._cameraColorCurves === value) {
-                return;
-            }
-            this._cameraColorCurves = value;
-            this._markAllSubMeshesAsTexturesDirty();
-        }
-
-        public get cameraColorCurves(): ColorCurves {
-            return this._cameraColorCurves;
-        }          
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public cameraColorCurves: ColorCurves;             
 
         public customShaderNameResolve: (shaderName: string) => string;
 
@@ -566,7 +296,6 @@ module BABYLON {
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
-            this.storeEffectOnSubMeshes = true;
 
             this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
                 this._renderTargets.reset();
@@ -583,8 +312,6 @@ module BABYLON {
             }
         }
 
-        private _activeEffect: Effect;
-
         public getClassName(): string {
             return "StandardMaterial";
         }        
@@ -619,44 +346,6 @@ module BABYLON {
         /**
          * Child classes can use it to update shaders
          */
-        public markAsDirty(flag: number): void {
-            if (flag & Material.TextureDirtyFlag) {
-                this._markAllSubMeshesAsTexturesDirty();
-            }
-
-            if (flag & Material.LightDirtyFlag) {
-                this._markAllSubMeshesAsLightsDirty();
-            }
-
-            if (flag & Material.FresnelDirtyFlag) {
-                this._markAllSubMeshesAsFresnelDirty();
-            }
-
-            if (flag & Material.AttributesDirtyFlag) {
-                this._markAllSubMeshesAsAttributesDirty();
-            }
-
-            if (flag & Material.MiscDirtyFlag) {
-                this._markAllSubMeshesAsMiscDirty();
-            }
-        }
-
-        public getEffect(): Effect {
-            return this._activeEffect;
-        }
-
-        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            if (!mesh) {
-                return false;
-            }
-
-            if (!mesh.subMeshes || mesh.subMeshes.length === 0) {
-                return true;
-            }
-
-            return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
-        }
-
         public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {            
             if (this.isFrozen) {
                 if (this._wasPreviouslyReady && subMesh.effect) {
@@ -668,20 +357,20 @@ module BABYLON {
                 subMesh._materialDefines = new StandardMaterialDefines();
             }
 
-            var defines = <StandardMaterialDefines>subMesh._materialDefines;
             var scene = this.getScene();
-            var engine = scene.getEngine();
-
-            // Lights
-            defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, this._maxSimultaneousLights, this._disableLighting);
-            defines._areLightsDirty = false;
-
+            var defines = <StandardMaterialDefines>subMesh._materialDefines;
             if (!this.checkReadyOnEveryCall && subMesh.effect) {
                 if (defines._renderId === scene.getRenderId()) {
                     return true;
                 }
             }
 
+            var engine = scene.getEngine();
+
+            // Lights
+            defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, this._maxSimultaneousLights, this._disableLighting);
+            defines._areLightsDirty = false;
+
             // Textures
             if (defines._areTexturesDirty) {
                 defines._needUVs = false;
@@ -1073,14 +762,6 @@ module BABYLON {
             this._activeEffect.setMatrix("world", world);
         }
 
-        public bind(world: Matrix, mesh?: Mesh): void {
-            if (!mesh) {
-                return;
-            }
-
-            this.bindForSubMesh(world, mesh, mesh.subMeshes[0]);
-        }
-
         public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
             var scene = this.getScene();
 
@@ -1098,7 +779,7 @@ module BABYLON {
             // Bones
             MaterialHelper.BindBonesParameters(mesh, effect);
 
-            if (scene.getCachedEffect() !== effect || scene.getCachedMaterial() !== this) {
+            if (this._mustRebind(scene, effect)) {
                 effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
                 if (StandardMaterial.FresnelEnabled) {
@@ -1230,7 +911,7 @@ module BABYLON {
                 effect.setColor3("vEmissiveColor", this.emissiveColor);
             }
 
-            if (scene.getCachedEffect() !== effect || scene.getCachedMaterial() !== this || !this.isFrozen) {
+            if (this._mustRebind(scene, effect) || !this.isFrozen) {
                 // Diffuse
                 effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
 
@@ -1256,8 +937,7 @@ module BABYLON {
                 }
             }
 
-            super.bindForSubMesh(world, mesh, subMesh);
-            super.bind(world, mesh);
+            this._afterBind(mesh, this._activeEffect);
         }
 
         public getAnimatables(): IAnimatable[] {
@@ -1360,43 +1040,6 @@ module BABYLON {
             return SerializationHelper.Serialize(this);
         }
 
-        private _markAllSubMeshesAsDirty(func: (defines: StandardMaterialDefines) => void) {
-            for (var mesh of this.getScene().meshes) {
-                if (!mesh.subMeshes) {
-                    continue;
-                }
-                for (var subMesh of mesh.subMeshes) {
-                    if (subMesh.getMaterial() !== this) {
-                        continue;
-                    }
-                    if (!subMesh._materialDefines) {
-                        subMesh._materialDefines = new StandardMaterialDefines();
-                    }
-                    func(<StandardMaterialDefines>(subMesh._materialDefines));
-                }
-            }
-        }
-
-        private _markAllSubMeshesAsTexturesDirty() {
-            this._markAllSubMeshesAsDirty(defines => defines._areTexturesDirty = true);
-        }
-
-        private _markAllSubMeshesAsFresnelDirty() {
-            this._markAllSubMeshesAsDirty(defines => defines._areFresnelDirty = true);
-        }
-
-        private _markAllSubMeshesAsLightsDirty() {
-            this._markAllSubMeshesAsDirty(defines => defines._areLightsDirty = true);
-        }
-
-        private _markAllSubMeshesAsAttributesDirty() {
-            this._markAllSubMeshesAsDirty(defines => defines._areAttributesDirty = true);
-        }
-
-        private _markAllSubMeshesAsMiscDirty() {
-            this._markAllSubMeshesAsDirty(defines => defines._areMiscDirty = true);
-        }
-
         // Statics
         public static Parse(source: any, scene: Scene, rootUrl: string): StandardMaterial {
             return SerializationHelper.Parse(() => new StandardMaterial(source.name, scene), source, scene, rootUrl);

+ 26 - 0
src/Tools/babylon.decorators.ts

@@ -11,6 +11,32 @@
         }
     }
 
+    function generateExpandMember(setCallback: string) {
+        return (target: any, propertyKey: string) => {
+            if (setCallback) {
+                var key = "_" + propertyKey;
+                Object.defineProperty(target, propertyKey, {
+                    get: function () {
+                        return this[key];
+                    },
+                    set: function (value) {
+                        if (this[key] === value) {
+                            return;
+                        }
+                        this[key] = value;
+                        target[setCallback].apply(this);
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+            }
+        }
+    }
+
+    export function expandToProperty(callback: string) {
+        return generateExpandMember(callback);
+    }
+
     export function serialize(sourceName?: string) {
         return generateSerializableMember(0, sourceName); // value member
     }