Przeglądaj źródła

Merge pull request #4331 from julien-moreau/master

Adding MixMaterial to MaterialsLibrary
David Catuhe 7 lat temu
rodzic
commit
6033f3f73b

BIN
Playground/textures/mixMap_2.png


+ 10 - 0
Tools/Gulp/config.json

@@ -1319,6 +1319,16 @@
             },
             {
                 "files": [
+                    "../../materialsLibrary/src/mix/babylon.mixMaterial.ts"
+                ],
+                "shaderFiles": [
+                    "../../materialsLibrary/src/mix/mix.vertex.fx",
+                    "../../materialsLibrary/src/mix/mix.fragment.fx"
+                ],
+                "output": "babylon.mixMaterial.js"
+            },
+            {
+                "files": [
                     "../../materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts"
                 ],
                 "shaderFiles": [

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

@@ -3,6 +3,7 @@
 ## Major updates
 
 - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style ([DevChris](https://github.com/yovanoc))
+- Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 
 ## Updates
 

+ 7 - 1
materialsLibrary/index.html

@@ -53,6 +53,7 @@
 	<script src="test/addpbrspecularglossiness.js"></script>
 	<script src="test/addCell.js"></script>
 	<script src="test/addbackground.js"></script>
+	<script src="test/addMix.js"></script>
 	
 	<script>
 	var backgroundSkybox = null;
@@ -215,13 +216,15 @@
 				var shadowOnly = new BABYLON.ShadowOnlyMaterial();
 
 				var cell = prepareCell();
+
+				var mix = prepareMix();
 				
 				// Default to std
 				var currentMaterial = std;
 				sphere.material = std;				
 				sphere.receiveShadows = true;
 
-				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'pbrmetallicroughness', 'pbrspecularglossiness', 'fur', 'triPlanar', 'gradient', 'sky', 'grid', 'shadowOnly', 'cell', 'background']).onFinishChange(function () {
+				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'pbrmetallicroughness', 'pbrspecularglossiness', 'fur', 'triPlanar', 'gradient', 'sky', 'grid', 'shadowOnly', 'cell', 'background', 'mix']).onFinishChange(function () {
 					water.enableRenderTargets(false);
 					skybox.material = skyboxMaterial;
 					currentMesh.isVisible = true;
@@ -287,6 +290,9 @@
 							currentMaterial = back;
 							backgroundSkybox.setEnabled(true);
 							break;
+						case "mix":
+							currentMaterial = mix;
+							break;
 						default:
 							currentMaterial = std;
 							break;

+ 517 - 0
materialsLibrary/src/mix/babylon.mixMaterial.ts

@@ -0,0 +1,517 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    class MixMaterialDefines extends MaterialDefines {
+        public DIFFUSE = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public DEPTHPREPASS = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public SPECULARTERM = false;
+        public NORMAL = false;
+        public UV1 = false;
+        public UV2 = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public NUM_BONE_INFLUENCERS = 0;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+        public MIXMAP2 = false;
+
+        constructor() {
+            super();
+            this.rebuild();
+        }
+    }
+
+    export class MixMaterial extends PushMaterial {
+        /**
+         * Mix textures
+         */
+
+        @serializeAsTexture("mixTexture1")
+        private _mixTexture1: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public mixTexture1: BaseTexture;
+
+        @serializeAsTexture("mixTexture2")
+        private _mixTexture2: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public mixTexture2: BaseTexture;
+
+        /**
+         * Diffuse textures
+         */
+
+        @serializeAsTexture("diffuseTexture1")
+        private _diffuseTexture1: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture1: Texture;
+
+        @serializeAsTexture("diffuseTexture2")
+        private _diffuseTexture2: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture2: Texture;
+
+        @serializeAsTexture("diffuseTexture3")
+        private _diffuseTexture3: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture3: Texture;
+
+        @serializeAsTexture("diffuseTexture4")
+        private _diffuseTexture4: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture4: Texture;
+
+        @serializeAsTexture("diffuseTexture1")
+        private _diffuseTexture5: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture5: Texture;
+
+        @serializeAsTexture("diffuseTexture2")
+        private _diffuseTexture6: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture6: Texture;
+
+        @serializeAsTexture("diffuseTexture3")
+        private _diffuseTexture7: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture7: Texture;
+
+        @serializeAsTexture("diffuseTexture4")
+        private _diffuseTexture8: Texture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture8: Texture;
+
+        /**
+         * Uniforms
+         */
+
+        @serializeAsColor3()
+        public diffuseColor = new Color3(1, 1, 1);
+
+        @serializeAsColor3()
+        public specularColor = new Color3(0, 0, 0);
+
+        @serialize()
+        public specularPower = 64;
+
+        @serialize("disableLighting")
+        private _disableLighting = false;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public disableLighting: boolean;
+
+        @serialize("maxSimultaneousLights")
+        private _maxSimultaneousLights = 4;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public maxSimultaneousLights: number;
+
+        private _renderId: number;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+        }
+
+        public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): Nullable<BaseTexture> {
+            return null;
+        }
+
+        // Methods   
+        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 MixMaterialDefines();
+            }
+
+            var defines = <MixMaterialDefines>subMesh._materialDefines;
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall && subMesh.effect) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            var engine = scene.getEngine();
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (StandardMaterial.DiffuseTextureEnabled) {
+                    if (this._mixTexture1) {
+                        if (!this._mixTexture1.isReady()) {
+                            return false;
+                        } else {
+                            defines._needUVs = true;
+                            defines.DIFFUSE = true;
+                        }
+                    }
+                    if (this._mixTexture2) {
+                        if (!this._mixTexture2.isReady()) {
+                            return false;
+                        } else {
+                            defines.MIXMAP2 = true;
+                        }
+                    }
+                }
+            }
+
+            // Misc.
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
+
+            // Lights
+            defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
+
+            // Values that need to be evaluated on every frame
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+
+            // Attribs
+            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
+
+            // Get correct effect      
+            if (defines.isDirty) {
+                defines.markAsProcessed();
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();
+                if (defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this.maxSimultaneousLights);
+
+                if (defines.NUM_BONE_INFLUENCERS > 0) {
+                    fallbacks.addCPUSkinningFallback(0, mesh);
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (defines.UV2) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                }
+
+                if (defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
+                MaterialHelper.PrepareAttributesForInstances(attribs, defines);
+
+                // Legacy browser patch
+                var shaderName = "mix";
+                var join = defines.toString();
+                var uniforms = [
+                    "world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor", "vSpecularColor",
+                    "vFogInfos", "vFogColor", "pointSize",
+                    "vTextureInfos",
+                    "mBones",
+                    "vClipPlane", "textureMatrix",
+                    "diffuse1Infos", "diffuse2Infos", "diffuse3Infos", "diffuse4Infos",
+                    "diffuse5Infos", "diffuse6Infos", "diffuse7Infos", "diffuse8Infos"
+                ];
+                var samplers = [
+                    "mixMap1Sampler", "mixMap2Sampler",
+                    "diffuse1Sampler", "diffuse2Sampler", "diffuse3Sampler", "diffuse4Sampler",
+                    "diffuse5Sampler", "diffuse6Sampler", "diffuse7Sampler", "diffuse8Sampler"
+                ];
+
+                var uniformBuffers = new Array<string>()
+
+                MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
+                    uniformsNames: uniforms,
+                    uniformBuffersNames: uniformBuffers,
+                    samplers: samplers,
+                    defines: defines,
+                    maxSimultaneousLights: this.maxSimultaneousLights
+                });
+
+                subMesh.setEffect(scene.getEngine().createEffect(shaderName,
+                    <EffectCreationOptions>{
+                        attributes: attribs,
+                        uniformsNames: uniforms,
+                        uniformBuffersNames: uniformBuffers,
+                        samplers: samplers,
+                        defines: join,
+                        fallbacks: fallbacks,
+                        onCompiled: this.onCompiled,
+                        onError: this.onError,
+                        indexParameters: { maxSimultaneousLights: this.maxSimultaneousLights }
+                    }, engine), defines);
+            }
+            if (!subMesh.effect || !subMesh.effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            return true;
+        }
+
+        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
+            var scene = this.getScene();
+
+            var defines = <MixMaterialDefines>subMesh._materialDefines;
+            if (!defines) {
+                return;
+            }
+
+            var effect = subMesh.effect;
+            if (!effect) {
+                return;
+            }
+            this._activeEffect = effect;
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
+
+            if (this._mustRebind(scene, effect)) {
+                // Textures        
+                if (this._mixTexture1) {
+                    this._activeEffect.setTexture("mixMap1Sampler", this._mixTexture1);
+                    this._activeEffect.setFloat2("vTextureInfos", this._mixTexture1.coordinatesIndex, this._mixTexture1.level);
+                    this._activeEffect.setMatrix("textureMatrix", this._mixTexture1.getTextureMatrix());
+
+                    if (StandardMaterial.DiffuseTextureEnabled) {
+                        if (this._diffuseTexture1) {
+                            this._activeEffect.setTexture("diffuse1Sampler", this._diffuseTexture1);
+                            this._activeEffect.setFloat2("diffuse1Infos", this._diffuseTexture1.uScale, this._diffuseTexture1.vScale);
+                        }
+                        if (this._diffuseTexture2) {
+                            this._activeEffect.setTexture("diffuse2Sampler", this._diffuseTexture2);
+                            this._activeEffect.setFloat2("diffuse2Infos", this._diffuseTexture2.uScale, this._diffuseTexture2.vScale);
+                        }
+                        if (this._diffuseTexture3) {
+                            this._activeEffect.setTexture("diffuse3Sampler", this._diffuseTexture3);
+                            this._activeEffect.setFloat2("diffuse3Infos", this._diffuseTexture3.uScale, this._diffuseTexture3.vScale);
+                        }
+                        if (this._diffuseTexture4) {
+                            this._activeEffect.setTexture("diffuse4Sampler", this._diffuseTexture4);
+                            this._activeEffect.setFloat2("diffuse4Infos", this._diffuseTexture4.uScale, this._diffuseTexture4.vScale);
+                        }
+                    }
+                }
+
+                if (this.mixTexture2) {
+                    this._activeEffect.setTexture("mixMap2Sampler", this._mixTexture2);
+
+                    if (StandardMaterial.DiffuseTextureEnabled) {
+                        if (this._diffuseTexture5) {
+                            this._activeEffect.setTexture("diffuse5Sampler", this._diffuseTexture5);
+                            this._activeEffect.setFloat2("diffuse5Infos", this._diffuseTexture5.uScale, this._diffuseTexture5.vScale);
+                        }
+                        if (this._diffuseTexture6) {
+                            this._activeEffect.setTexture("diffuse6Sampler", this._diffuseTexture6);
+                            this._activeEffect.setFloat2("diffuse6Infos", this._diffuseTexture6.uScale, this._diffuseTexture6.vScale);
+                        }
+                        if (this._diffuseTexture7) {
+                            this._activeEffect.setTexture("diffuse7Sampler", this._diffuseTexture7);
+                            this._activeEffect.setFloat2("diffuse7Infos", this._diffuseTexture7.uScale, this._diffuseTexture7.vScale);
+                        }
+                        if (this._diffuseTexture8) {
+                            this._activeEffect.setTexture("diffuse8Sampler", this._diffuseTexture8);
+                            this._activeEffect.setFloat2("diffuse8Infos", this._diffuseTexture8.uScale, this._diffuseTexture8.vScale);
+                        }
+                    }
+                }
+
+                // Clip plane
+                MaterialHelper.BindClipPlane(this._activeEffect, scene);
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._activeEffect.setFloat("pointSize", this.pointSize);
+                }
+
+                MaterialHelper.BindEyePosition(effect, scene);
+            }
+
+            this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
+
+            if (defines.SPECULARTERM) {
+                this._activeEffect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
+            }
+
+            if (scene.lightsEnabled && !this.disableLighting) {
+                MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this.maxSimultaneousLights);
+            }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._activeEffect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);
+
+            this._afterBind(mesh, this._activeEffect);
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this._mixTexture1 && this._mixTexture1.animations && this._mixTexture1.animations.length > 0) {
+                results.push(this._mixTexture1);
+            }
+
+            if (this._mixTexture2 && this._mixTexture2.animations && this._mixTexture2.animations.length > 0) {
+                results.push(this._mixTexture2);
+            }
+
+            return results;
+        }
+
+        public getActiveTextures(): BaseTexture[] {
+            var activeTextures = super.getActiveTextures();
+
+            // Mix map 1
+            if (this._mixTexture1) {
+                activeTextures.push(this._mixTexture1);
+            }
+
+            if (this._diffuseTexture1) {
+                activeTextures.push(this._diffuseTexture1);
+            }
+
+            if (this._diffuseTexture2) {
+                activeTextures.push(this._diffuseTexture2);
+            }
+
+            if (this._diffuseTexture3) {
+                activeTextures.push(this._diffuseTexture3);
+            }
+
+            if (this._diffuseTexture4) {
+                activeTextures.push(this._diffuseTexture4);
+            }
+
+            // Mix map 2
+            if (this._mixTexture2) {
+                activeTextures.push(this._mixTexture2);
+            }
+
+            if (this._diffuseTexture5) {
+                activeTextures.push(this._diffuseTexture5);
+            }
+
+            if (this._diffuseTexture6) {
+                activeTextures.push(this._diffuseTexture6);
+            }
+
+            if (this._diffuseTexture7) {
+                activeTextures.push(this._diffuseTexture7);
+            }
+
+            if (this._diffuseTexture8) {
+                activeTextures.push(this._diffuseTexture8);
+            }
+
+            return activeTextures;
+        }
+
+        public hasTexture(texture: BaseTexture): boolean {
+            if (super.hasTexture(texture)) {
+                return true;
+            }
+
+            // Mix map 1
+            if (this._mixTexture1 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture1 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture2 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture3 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture4 === texture) {
+                return true;
+            }
+
+            // Mix map 2
+            if (this._mixTexture2 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture5 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture6 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture7 === texture) {
+                return true;
+            }
+
+            if (this._diffuseTexture8 === texture) {
+                return true;
+            }
+
+            return false;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this._mixTexture1) {
+                this._mixTexture1.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): MixMaterial {
+            return SerializationHelper.Clone(() => new MixMaterial(name, this.getScene()), this);
+        }
+
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "BABYLON.MixMaterial";
+            return serializationObject;
+        }
+
+        public getClassName(): string {
+            return "MixMaterial";
+        }
+
+        // Statics
+        public static Parse(source: any, scene: Scene, rootUrl: string): MixMaterial {
+            return SerializationHelper.Parse(() => new MixMaterial(source.name, scene), source, scene, rootUrl);
+        }
+    }
+}
+

+ 172 - 0
materialsLibrary/src/mix/mix.fragment.fx

@@ -0,0 +1,172 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+uniform vec4 vDiffuseColor;
+
+#ifdef SPECULARTERM
+uniform vec4 vSpecularColor;
+#endif
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Helper functions
+#include<helperFunctions>
+
+// Lights
+#include<__decl__lightFragment>[0..maxSimultaneousLights]
+
+// Samplers
+#ifdef DIFFUSE
+varying vec2 vTextureUV;
+uniform sampler2D mixMap1Sampler;
+uniform vec2 vTextureInfos;
+
+#ifdef MIXMAP2
+uniform sampler2D mixMap2Sampler;
+#endif
+
+uniform sampler2D diffuse1Sampler;
+uniform sampler2D diffuse2Sampler;
+uniform sampler2D diffuse3Sampler;
+uniform sampler2D diffuse4Sampler;
+
+uniform vec2 diffuse1Infos;
+uniform vec2 diffuse2Infos;
+uniform vec2 diffuse3Infos;
+uniform vec2 diffuse4Infos;
+
+#ifdef MIXMAP2
+uniform sampler2D diffuse5Sampler;
+uniform sampler2D diffuse6Sampler;
+uniform sampler2D diffuse7Sampler;
+uniform sampler2D diffuse8Sampler;
+
+uniform vec2 diffuse5Infos;
+uniform vec2 diffuse6Infos;
+uniform vec2 diffuse7Infos;
+uniform vec2 diffuse8Infos;
+#endif
+
+#endif
+
+// Shadows
+#include<lightsFragmentFunctions>
+#include<shadowsFragmentFunctions>
+#include<clipPlaneFragmentDeclaration>
+
+// Fog
+#include<fogFragmentDeclaration>
+
+void main(void) {
+	// Clip plane
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Base color
+	vec4 finalMixColor = vec4(1., 1., 1., 1.);
+	vec3 diffuseColor = vDiffuseColor.rgb;
+
+#ifdef MIXMAP2
+	vec4 mixColor2 = vec4(1., 1., 1., 1.);
+#endif
+	
+#ifdef SPECULARTERM
+	float glossiness = vSpecularColor.a;
+	vec3 specularColor = vSpecularColor.rgb;
+#else
+	float glossiness = 0.;
+#endif
+
+	// Alpha
+	float alpha = vDiffuseColor.a;
+	
+	// Normal
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+#ifdef DIFFUSE
+	vec4 mixColor = texture2D(mixMap1Sampler, vTextureUV);
+
+#include<depthPrePass>
+
+	mixColor.rgb *= vTextureInfos.y;
+	
+	vec4 diffuse1Color = texture2D(diffuse1Sampler, vTextureUV * diffuse1Infos);
+	vec4 diffuse2Color = texture2D(diffuse2Sampler, vTextureUV * diffuse2Infos);
+	vec4 diffuse3Color = texture2D(diffuse3Sampler, vTextureUV * diffuse3Infos);
+	vec4 diffuse4Color = texture2D(diffuse4Sampler, vTextureUV * diffuse4Infos);
+	
+	diffuse1Color.rgb *= mixColor.r;
+   	diffuse2Color.rgb = mix(diffuse1Color.rgb, diffuse2Color.rgb, mixColor.g);
+   	diffuse3Color.rgb = mix(diffuse2Color.rgb, diffuse3Color.rgb, mixColor.b);
+	finalMixColor.rgb = mix(diffuse3Color.rgb, diffuse4Color.rgb, 1.0 - mixColor.a);
+
+#ifdef MIXMAP2
+	mixColor = texture2D(mixMap2Sampler, vTextureUV);
+	mixColor.rgb *= vTextureInfos.y;
+
+	vec4 diffuse5Color = texture2D(diffuse5Sampler, vTextureUV * diffuse5Infos);
+	vec4 diffuse6Color = texture2D(diffuse6Sampler, vTextureUV * diffuse6Infos);
+	vec4 diffuse7Color = texture2D(diffuse7Sampler, vTextureUV * diffuse7Infos);
+	vec4 diffuse8Color = texture2D(diffuse8Sampler, vTextureUV * diffuse8Infos);
+
+	diffuse5Color.rgb *= mixColor.r;
+   	diffuse6Color.rgb = mix(diffuse5Color.rgb, diffuse6Color.rgb, mixColor.g);
+   	diffuse7Color.rgb = mix(diffuse6Color.rgb, diffuse7Color.rgb, mixColor.b);
+	mixColor.rgb = mix(diffuse7Color.rgb, diffuse8Color.rgb, 1.0 - mixColor.a);
+
+	finalMixColor.rgb = mix(finalMixColor.rgb, mixColor.rgb, 0.5);
+#endif
+	
+#endif
+
+#ifdef VERTEXCOLOR
+	finalMixColor.rgb *= vColor.rgb;
+#endif
+
+	// Lighting
+	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
+	float shadow = 1.;
+	
+#ifdef SPECULARTERM
+	vec3 specularBase = vec3(0., 0., 0.);
+#endif
+	#include<lightFragment>[0..maxSimultaneousLights]
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+#ifdef SPECULARTERM
+	vec3 finalSpecular = specularBase * specularColor;
+#else
+	vec3 finalSpecular = vec3(0.0);
+#endif
+
+    vec3 finalDiffuse = clamp(diffuseBase * diffuseColor * finalMixColor.rgb, 0.0, 1.0);
+
+	// Composition
+	vec4 color = vec4(finalDiffuse + finalSpecular, alpha);
+
+#include<fogFragment>
+
+	gl_FragColor = color;
+}

+ 102 - 0
materialsLibrary/src/mix/mix.vertex.fx

@@ -0,0 +1,102 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+
+#include<bonesDeclaration>
+
+// Uniforms
+#include<instancesDeclaration>
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef DIFFUSE
+varying vec2 vTextureUV;
+uniform mat4 textureMatrix;
+uniform vec2 vTextureInfos;
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#include<clipPlaneVertexDeclaration>
+#include<fogVertexDeclaration>
+#include<__decl__lightFragment>[0..maxSimultaneousLights]
+
+void main(void) {
+	#include<instancesVertex>
+    #include<bonesVertex>
+	
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef DIFFUSE
+	if (vTextureInfos.x == 0.)
+	{
+		vTextureUV = vec2(textureMatrix * vec4(uv, 1.0, 0.0));
+	}
+	else
+	{
+		vTextureUV = vec2(textureMatrix * vec4(uv2, 1.0, 0.0));
+	}
+#endif
+
+	// Clip plane
+#ifdef CLIPPLANE
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif
+
+	// Fog
+	#include<fogVertex>
+	
+	// Shadows
+    #include<shadowsVertex>[0..maxSimultaneousLights]
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+}

+ 29 - 0
materialsLibrary/test/addMix.js

@@ -0,0 +1,29 @@
+window.prepareMix = function() {
+    var mix = new BABYLON.MixMaterial("mix", scene);
+    mix.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+    mix.specularPower = 64;
+    mix.mixTexture1 = new BABYLON.Texture("/playground/textures/mixMap.png", scene);
+    mix.mixTexture2 = new BABYLON.Texture("/playground/textures/mixMap_2.png", scene);
+
+    mix.diffuseTexture1 = new BABYLON.Texture("/playground/textures/floor.png", scene);
+    mix.diffuseTexture2 = new BABYLON.Texture("/playground/textures/rock.png", scene);
+    mix.diffuseTexture3 = new BABYLON.Texture("/playground/textures/grass.png", scene);
+    mix.diffuseTexture4 = new BABYLON.Texture("/playground/textures/floor.png", scene);
+
+    mix.diffuseTexture1.uScale = mix.diffuseTexture1.vScale = 10;
+    mix.diffuseTexture2.uScale = mix.diffuseTexture2.vScale = 10;
+    mix.diffuseTexture3.uScale = mix.diffuseTexture3.vScale = 10;
+    mix.diffuseTexture4.uScale = mix.diffuseTexture4.vScale = 10;
+
+    mix.diffuseTexture5 = new BABYLON.Texture("/playground/textures/leopard_fur.jpg", scene);
+    mix.diffuseTexture6 = new BABYLON.Texture("/playground/textures/fur.jpg", scene);
+    mix.diffuseTexture7 = new BABYLON.Texture("/playground/textures/sand.jpg", scene);
+    mix.diffuseTexture8 = new BABYLON.Texture("/playground/textures/crate.png", scene);
+
+    mix.diffuseTexture5.uScale = mix.diffuseTexture5.vScale = 10;
+    mix.diffuseTexture6.uScale = mix.diffuseTexture6.vScale = 10;
+    mix.diffuseTexture7.uScale = mix.diffuseTexture7.vScale = 5;
+    mix.diffuseTexture8.uScale = mix.diffuseTexture8.vScale = 10;
+    
+    return mix;
+};