Przeglądaj źródła

Fresnel support step 1

David Catuhe 11 lat temu
rodzic
commit
0f1c1e1329

+ 22 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -85,6 +85,16 @@
             return skeleton;
         };
 
+        var parseFresnelParameters = function (parsedFresnelParameters) {
+            var fresnelParameters = new BABYLON.FresnelParameters();
+
+            fresnelParameters.isEnabled = parsedFresnelParameters.isEnabled;
+            fresnelParameters.leftColor = BABYLON.Color3.FromArray(parsedFresnelParameters.leftColor);
+            fresnelParameters.rightColor = BABYLON.Color3.FromArray(parsedFresnelParameters.rightColor);
+
+            return fresnelParameters;
+        };
+
         var parseMaterial = function (parsedMaterial, scene, rootUrl) {
             var material;
             material = new BABYLON.StandardMaterial(parsedMaterial.name, scene);
@@ -107,6 +117,10 @@
                 material.diffuseTexture = loadTexture(rootUrl, parsedMaterial.diffuseTexture, scene);
             }
 
+            if (parsedMaterial.diffuseFresnelParameters) {
+                material.diffuseFresnelParameters = parseFresnelParameters(parsedMaterial.diffuseFresnelParameters);
+            }
+
             if (parsedMaterial.ambientTexture) {
                 material.ambientTexture = loadTexture(rootUrl, parsedMaterial.ambientTexture, scene);
             }
@@ -115,10 +129,18 @@
                 material.opacityTexture = loadTexture(rootUrl, parsedMaterial.opacityTexture, scene);
             }
 
+            if (parsedMaterial.opacityFresnelParameters) {
+                material.opacityFresnelParameters = parseFresnelParameters(parsedMaterial.opacityFresnelParameters);
+            }
+
             if (parsedMaterial.reflectionTexture) {
                 material.reflectionTexture = loadTexture(rootUrl, parsedMaterial.reflectionTexture, scene);
             }
 
+            if (parsedMaterial.reflectionFresnelParameters) {
+                material.reflectionFresnelParameters = parseFresnelParameters(parsedMaterial.reflectionFresnelParameters);
+            }
+
             if (parsedMaterial.emissiveTexture) {
                 material.emissiveTexture = loadTexture(rootUrl, parsedMaterial.emissiveTexture, scene);
             }

+ 22 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -84,6 +84,16 @@
         return skeleton;
     };
 
+    var parseFresnelParameters = (parsedFresnelParameters) => {
+        var fresnelParameters = new BABYLON.FresnelParameters();
+
+        fresnelParameters.isEnabled = parsedFresnelParameters.isEnabled;
+        fresnelParameters.leftColor = BABYLON.Color3.FromArray(parsedFresnelParameters.leftColor);
+        fresnelParameters.rightColor = BABYLON.Color3.FromArray(parsedFresnelParameters.rightColor);
+
+        return fresnelParameters;
+    }
+
     var parseMaterial = (parsedMaterial, scene, rootUrl) => {
         var material;
         material = new BABYLON.StandardMaterial(parsedMaterial.name, scene);
@@ -106,6 +116,10 @@
             material.diffuseTexture = loadTexture(rootUrl, parsedMaterial.diffuseTexture, scene);
         }
 
+        if (parsedMaterial.diffuseFresnelParameters) {
+            material.diffuseFresnelParameters = parseFresnelParameters(parsedMaterial.diffuseFresnelParameters);
+        }
+
         if (parsedMaterial.ambientTexture) {
             material.ambientTexture = loadTexture(rootUrl, parsedMaterial.ambientTexture, scene);
         }
@@ -114,10 +128,18 @@
             material.opacityTexture = loadTexture(rootUrl, parsedMaterial.opacityTexture, scene);
         }
 
+        if (parsedMaterial.opacityFresnelParameters) {
+            material.opacityFresnelParameters = parseFresnelParameters(parsedMaterial.opacityFresnelParameters);
+        }
+
         if (parsedMaterial.reflectionTexture) {
             material.reflectionTexture = loadTexture(rootUrl, parsedMaterial.reflectionTexture, scene);
         }
 
+        if (parsedMaterial.reflectionFresnelParameters) {
+            material.reflectionFresnelParameters = parseFresnelParameters(parsedMaterial.reflectionFresnelParameters);
+        }
+
         if (parsedMaterial.emissiveTexture) {
             material.emissiveTexture = loadTexture(rootUrl, parsedMaterial.emissiveTexture, scene);
         }

+ 18 - 7
Babylon/Loading/babylon.sceneLoader.js

@@ -15,6 +15,18 @@
         });
 
 
+        Object.defineProperty(SceneLoader, "ShowLoadingScreen", {
+            get: function () {
+                return SceneLoader._ShowLoadingScreen;
+            },
+            set: function (value) {
+                SceneLoader._ShowLoadingScreen = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
         SceneLoader._getPluginForFilename = function (sceneFilename) {
             var dotPosition = sceneFilename.lastIndexOf(".");
             var extension = sceneFilename.substring(dotPosition).toLowerCase();
@@ -91,9 +103,8 @@
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
         * @param engine is the instance of BABYLON.Engine to use to create the scene
         */
-        SceneLoader.Load = function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror, showLoadingScreen) {
-            if (typeof showLoadingScreen === "undefined") { showLoadingScreen = true; }
-            SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onsuccess, progressCallBack, onerror, showLoadingScreen);
+        SceneLoader.Load = function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror) {
+            SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onsuccess, progressCallBack, onerror);
         };
 
         /**
@@ -102,12 +113,11 @@
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
         * @param scene is the instance of BABYLON.Scene to append to
         */
-        SceneLoader.Append = function (rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror, showLoadingScreen) {
-            if (typeof showLoadingScreen === "undefined") { showLoadingScreen = true; }
+        SceneLoader.Append = function (rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror) {
             var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
             var database;
 
-            if (showLoadingScreen) {
+            if (SceneLoader.ShowLoadingScreen) {
                 scene.getEngine().displayLoadingUI();
             }
 
@@ -127,7 +137,7 @@
                     onsuccess(scene);
                 }
 
-                if (showLoadingScreen) {
+                if (SceneLoader.ShowLoadingScreen) {
                     scene.executeWhenReady(function () {
                         scene.getEngine().hideLoadingUI();
                     });
@@ -152,6 +162,7 @@
             }
         };
         SceneLoader._ForceFullSceneLoadingForIncremental = false;
+        SceneLoader._ShowLoadingScreen = true;
 
         SceneLoader._registeredPlugins = new Array();
         return SceneLoader;

+ 22 - 3
Babylon/Materials/babylon.standardMaterial.js

@@ -8,6 +8,16 @@ var BABYLON;
 (function (BABYLON) {
     var maxSimultaneousLights = 4;
 
+    var FresnelParameters = (function () {
+        function FresnelParameters() {
+            this.isEnabled = true;
+            this.leftColor = BABYLON.Color3.Black();
+            this.rightColor = BABYLON.Color3.White();
+        }
+        return FresnelParameters;
+    })();
+    BABYLON.FresnelParameters = FresnelParameters;
+
     var StandardMaterial = (function (_super) {
         __extends(StandardMaterial, _super);
         function StandardMaterial(name, scene) {
@@ -19,7 +29,6 @@ var BABYLON;
             this.specularPower = 64;
             this.emissiveColor = new BABYLON.Color3(0, 0, 0);
             this.useAlphaFromDiffuseTexture = false;
-            this.useFresnelForDiffuse = false;
             this._cachedDefines = null;
             this._renderTargets = new BABYLON.SmartArray(16);
             this._worldViewProjectionMatrix = BABYLON.Matrix.Zero();
@@ -251,13 +260,15 @@ var BABYLON;
                 }
             }
 
-            if (this.useFresnelForDiffuse) {
+            // Fresnel
+            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
                 defines.push("#define FRESNEL");
                 defines.push("#define DIFFUSEFRESNEL");
                 fallbacks.addFallback(1, "FRESNEL");
                 fallbacks.addFallback(1, "DIFFUSEFRESNEL");
             }
 
+            // Attribs
             var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind];
             if (mesh) {
                 if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
@@ -312,7 +323,9 @@ var BABYLON;
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos",
                     "mBones",
                     "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix",
-                    "darkness0", "darkness1", "darkness2", "darkness3"], [
+                    "darkness0", "darkness1", "darkness2", "darkness3",
+                    "diffuseLeftColor", "diffuseRightColor"
+                ], [
                     "diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler",
                     "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3"
                 ], join, fallbacks, this.onCompiled, this.onError);
@@ -349,6 +362,12 @@ var BABYLON;
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 
+            // Fresnel
+            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                this._effect.setColor3("diffuseLeftColor", this.diffuseFresnelParameters.leftColor);
+                this._effect.setColor3("diffuseRightColor", this.diffuseFresnelParameters.rightColor);
+            }
+
             // Textures
             if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
                 this._effect.setTexture("diffuseSampler", this.diffuseTexture);

+ 22 - 3
Babylon/Materials/babylon.standardMaterial.ts

@@ -1,6 +1,12 @@
 module BABYLON {
     var maxSimultaneousLights = 4;
 
+    export class FresnelParameters {
+        public isEnabled = true;
+        public leftColor = Color3.Black();
+        public rightColor = Color3.White();
+    }
+
     export class StandardMaterial extends Material {
         public diffuseTexture: BaseTexture;
         public ambientTexture: BaseTexture;
@@ -17,7 +23,9 @@
         public emissiveColor = new BABYLON.Color3(0, 0, 0);
         public useAlphaFromDiffuseTexture = false;
 
-        public useFresnelForDiffuse = false;
+        public diffuseFresnelParameters: FresnelParameters;
+        public opacityFresnelParameters: FresnelParameters;
+        public reflectionFresnelParameters: FresnelParameters;
 
         private _cachedDefines = null;
         private _renderTargets = new BABYLON.SmartArray<RenderTargetTexture>(16);
@@ -255,13 +263,16 @@
                 }
             }
 
-            if (this.useFresnelForDiffuse) {
+            // Fresnel
+            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
                 defines.push("#define FRESNEL");
                 defines.push("#define DIFFUSEFRESNEL");
                 fallbacks.addFallback(1, "FRESNEL");
                 fallbacks.addFallback(1, "DIFFUSEFRESNEL");
             }
 
+
+            // Attribs
             var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind];
             if (mesh) {
                 if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
@@ -317,7 +328,9 @@
                         "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos",
                         "mBones",
                         "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix",
-                        "darkness0", "darkness1", "darkness2", "darkness3"],
+                        "darkness0", "darkness1", "darkness2", "darkness3",
+                        "diffuseLeftColor", "diffuseRightColor"
+                    ],
                     ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler",
                         "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3"
                     ],
@@ -356,6 +369,12 @@
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 
+            // Fresnel
+            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                this._effect.setColor3("diffuseLeftColor", this.diffuseFresnelParameters.leftColor);
+                this._effect.setColor3("diffuseRightColor", this.diffuseFresnelParameters.rightColor);
+            }
+
             // Textures        
             if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
                 this._effect.setTexture("diffuseSampler", this.diffuseTexture);

+ 27 - 7
Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -29,9 +29,22 @@
                     continue;
                 }
 
-                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
-                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
-                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
+                // Body position
+                var bodyX = registeredMesh.body.position.x,
+                    bodyY = registeredMesh.body.position.y,
+                    bodyZ = registeredMesh.body.position.z;
+
+                var deltaPos = registeredMesh.delta;
+                if (deltaPos) {
+                    registeredMesh.mesh.position.x = bodyX + deltaPos.x;
+                    registeredMesh.mesh.position.y = bodyZ + deltaPos.y;
+                    registeredMesh.mesh.position.z = bodyY + deltaPos.z;
+                } else {
+                    registeredMesh.mesh.position.x = bodyX;
+                    registeredMesh.mesh.position.y = bodyZ;
+                    registeredMesh.mesh.position.z = bodyY;
+                }
+
 
                 if (!registeredMesh.mesh.rotationQuaternion) {
                     registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
@@ -174,6 +187,10 @@
                 mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
             }
 
+            // The delta between the mesh position and the mesh bounding box center
+            var bbox = mesh.getBoundingInfo().boundingBox;
+            var deltaPosition = mesh.position.subtract(bbox.center);
+
             var material = this._addMaterial(friction, restitution);
             var body = new CANNON.RigidBody(mass, shape, material);
 
@@ -184,10 +201,10 @@
                 body.quaternion.w = -initialRotation.w;
             }
 
-            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+            body.position.set(bbox.center.x, bbox.center.z, bbox.center.y);
             this._world.add(body);
 
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition });
 
             return body;
         }
@@ -221,6 +238,7 @@
 
                 if (registeredMesh.body === body) {
                     registeredMesh.body = null;
+                    registeredMesh.delta = 0;
                 }
             }
         }
@@ -262,7 +280,9 @@
                 var registeredMesh = this._registeredMeshes[index];
                 if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
                     var body = registeredMesh.body.body;
-                    body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+
+                    var center = mesh.getBoundingInfo().boundingBox.center;
+                    body.position.set(center.x, center.z, center.y);
 
                     body.quaternion.x = mesh.rotationQuaternion.x;
                     body.quaternion.z = mesh.rotationQuaternion.y;
@@ -305,4 +325,4 @@
             return window.CANNON !== undefined;
         }
     }
-}
+}

+ 1 - 1
Babylon/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -345,4 +345,4 @@ module BABYLON {
             }
         }
     }
-}
+}

+ 8 - 2
Babylon/Shaders/default.fragment.fx

@@ -128,11 +128,16 @@ uniform sampler2D specularSampler;
 #ifdef FRESNEL
 float computeFresnelTerm(vec3 viewDirection, vec3 worldNormal)
 {
-	float fresnelTerm = dot(viewDirection, worldNormal);
+	float fresnelTerm = dot(viewDirection, worldNormal);
 	return clamp(1.0 - fresnelTerm, 0., 1.);
 }
 #endif
 
+#ifdef DIFFUSEFRESNEL
+uniform vec3 diffuseLeftColor;
+uniform vec3 diffuseRightColor;
+#endif
+
 // Reflection
 #ifdef REFLECTION
 varying vec3 vPositionUVW;
@@ -651,7 +656,8 @@ void main(void) {
 
 	// Fresnel
 #ifdef DIFFUSEFRESNEL
-	diffuseBase *= computeFresnelTerm(viewDirectionW, normalW);
+	float diffuseFresnelTerm = computeFresnelTerm(viewDirectionW, normalW);
+	diffuseBase *= diffuseLeftColor * (1.0 - diffuseFresnelTerm) + diffuseFresnelTerm * diffuseRightColor;
 #endif
 
 	// Composition

+ 3 - 2
Babylon/Tools/babylon.database.js

@@ -1,4 +1,4 @@
-var BABYLON;
+var BABYLON;
 (function (BABYLON) {
     var Database = (function () {
         function Database(urlToScene, callbackManifestChecked) {
@@ -513,7 +513,8 @@ var BABYLON;
         Database.parseURL = function (url) {
             var a = document.createElement('a');
             a.href = url;
-            var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
+            var urlWithoutHash = url.substring(0, url.lastIndexOf("#"));
+            var fileName = url.substring(urlWithoutHash.lastIndexOf("/") + 1, url.length);
             var absLocation = url.substring(0, url.indexOf(fileName, 0));
             return absLocation;
         };

+ 4 - 4
Babylon/Tools/babylon.database.ts

@@ -27,16 +27,16 @@ module BABYLON {
             this.checkManifestFile();
         }
 
-        static parseURL = function(url: string) {
+        static parseURL = (url: string) => {
             var a = document.createElement('a');
             a.href = url;
-            var urlWithoutHash = url.substring(0, url.lastIndexOf("#"));
-            var fileName = url.substring(urlWithoutHash.lastIndexOf("/") + 1, url.length);
+            var urlWithoutHash = url.substring(0, url.lastIndexOf("#")); 
+            var fileName = url.substring(urlWithoutHash.lastIndexOf("/") + 1, url.length); 
             var absLocation = url.substring(0, url.indexOf(fileName, 0));
             return absLocation;
         }
 
-        static ReturnFullUrlLocation = function (url: string): string {
+        static ReturnFullUrlLocation = (url: string): string => {
             if (url.indexOf("http:/") === -1) {
                 return (BABYLON.Database.parseURL(window.location.href) + url);
             }

+ 295 - 29
Babylon/babylon.engine.js

@@ -1,5 +1,250 @@
 var BABYLON;
 (function (BABYLON) {
+    var _DepthCullingState = (function () {
+        function _DepthCullingState() {
+            this._isDepthTestDirty = false;
+            this._isDepthMaskDirty = false;
+            this._isDepthFuncDirty = false;
+            this._isCullFaceDirty = false;
+            this._isCullDirty = false;
+        }
+        Object.defineProperty(_DepthCullingState.prototype, "isDirty", {
+            get: function () {
+                return this._isDepthTestDirty || this._isDepthMaskDirty || this._isCullFaceDirty || this._isCullDirty;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(_DepthCullingState.prototype, "cullFace", {
+            get: function () {
+                return this._cullFace;
+            },
+            set: function (value) {
+                if (this._cullFace === value) {
+                    return;
+                }
+
+                this._cullFace = value;
+                this._isCullFaceDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(_DepthCullingState.prototype, "cull", {
+            get: function () {
+                return this._cull;
+            },
+            set: function (value) {
+                if (this._cull === value) {
+                    return;
+                }
+
+                this._cull = value;
+                this._isCullDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(_DepthCullingState.prototype, "depthFunc", {
+            get: function () {
+                return this._depthFunc;
+            },
+            set: function (value) {
+                if (this._depthFunc === value) {
+                    return;
+                }
+
+                this._depthFunc = value;
+                this._isDepthFuncDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(_DepthCullingState.prototype, "depthMask", {
+            get: function () {
+                return this._depthMask;
+            },
+            set: function (value) {
+                if (this._depthMask === value) {
+                    return;
+                }
+
+                this._depthMask = value;
+                this._isDepthMaskDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(_DepthCullingState.prototype, "depthTest", {
+            get: function () {
+                return this._depthTest;
+            },
+            set: function (value) {
+                if (this._depthTest === value) {
+                    return;
+                }
+
+                this._depthTest = value;
+                this._isDepthTestDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        _DepthCullingState.prototype.reset = function () {
+            this._depthMask = true;
+            this._depthTest = true;
+            this._depthFunc = null;
+            this._cull = null;
+            this._cullFace = null;
+
+            this._isDepthTestDirty = true;
+            this._isDepthMaskDirty = true;
+            this._isDepthFuncDirty = false;
+            this._isCullFaceDirty = false;
+            this._isCullDirty = false;
+        };
+
+        _DepthCullingState.prototype.apply = function (gl) {
+            if (!this.isDirty) {
+                return;
+            }
+
+            // Cull
+            if (this._isCullDirty) {
+                if (this.cull === true) {
+                    gl.enable(gl.CULL_FACE);
+                } else if (this.cull === false) {
+                    gl.disable(gl.CULL_FACE);
+                }
+
+                this._isCullDirty = false;
+            }
+
+            // Cull face
+            if (this._isCullFaceDirty) {
+                gl.cullFace(this.cullFace);
+                this._isCullFaceDirty = false;
+            }
+
+            // Depth mask
+            if (this._isDepthMaskDirty) {
+                gl.depthMask(this.depthMask);
+                this._isDepthMaskDirty = false;
+            }
+
+            // Depth test
+            if (this._isDepthTestDirty) {
+                if (this.depthTest === true) {
+                    gl.enable(gl.DEPTH_TEST);
+                } else if (this.depthTest === false) {
+                    gl.disable(gl.DEPTH_TEST);
+                }
+                this._isDepthTestDirty = false;
+            }
+
+            // Depth func
+            if (this._isDepthFuncDirty) {
+                gl.depthFunc(this.depthFunc);
+                this._isDepthFuncDirty = false;
+            }
+        };
+        return _DepthCullingState;
+    })();
+    BABYLON._DepthCullingState = _DepthCullingState;
+
+    var _AlphaState = (function () {
+        function _AlphaState() {
+            this._isAlphaBlendDirty = false;
+            this._isBlendFunctionParametersDirty = false;
+            this._alphaBlend = false;
+            this._blendFunctionParameters = new Array(4);
+        }
+        Object.defineProperty(_AlphaState.prototype, "isDirty", {
+            get: function () {
+                return this._isAlphaBlendDirty || this._isBlendFunctionParametersDirty;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(_AlphaState.prototype, "alphaBlend", {
+            get: function () {
+                return this._alphaBlend;
+            },
+            set: function (value) {
+                if (this._alphaBlend === value) {
+                    return;
+                }
+
+                this._alphaBlend = value;
+                this._isAlphaBlendDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        _AlphaState.prototype.setAlphaBlendFunctionParameters = function (value0, value1, value2, value3) {
+            if (this._blendFunctionParameters[0] === value0 && this._blendFunctionParameters[1] === value1 && this._blendFunctionParameters[2] === value2 && this._blendFunctionParameters[3] === value3) {
+                return;
+            }
+
+            this._blendFunctionParameters[0] = value0;
+            this._blendFunctionParameters[1] = value1;
+            this._blendFunctionParameters[2] = value2;
+            this._blendFunctionParameters[3] = value3;
+
+            this._isBlendFunctionParametersDirty = true;
+        };
+
+        _AlphaState.prototype.reset = function () {
+            this._alphaBlend = false;
+            this._blendFunctionParameters[0] = null;
+            this._blendFunctionParameters[1] = null;
+            this._blendFunctionParameters[2] = null;
+            this._blendFunctionParameters[3] = null;
+
+            this._isAlphaBlendDirty = true;
+            this._isBlendFunctionParametersDirty = false;
+        };
+
+        _AlphaState.prototype.apply = function (gl) {
+            if (!this.isDirty) {
+                return;
+            }
+
+            // Alpha blend
+            if (this._isAlphaBlendDirty) {
+                if (this._alphaBlend === true) {
+                    gl.enable(gl.BLEND);
+                } else if (this._alphaBlend === false) {
+                    gl.disable(gl.BLEND);
+                }
+
+                this._isAlphaBlendDirty = false;
+            }
+
+            // Alpha function
+            if (this._isBlendFunctionParametersDirty) {
+                gl.blendFuncSeparate(this._blendFunctionParameters[0], this._blendFunctionParameters[1], this._blendFunctionParameters[2], this._blendFunctionParameters[3]);
+                this._isBlendFunctionParametersDirty = false;
+            }
+        };
+        return _AlphaState;
+    })();
+    BABYLON._AlphaState = _AlphaState;
+
     var compileShader = function (gl, source, type, defines) {
         var shader = gl.createShader(type === "vertex" ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
 
@@ -131,11 +376,14 @@
             this.scenes = new Array();
             this._windowIsBackground = false;
             this._runningLoop = false;
+            this._loadingDivBackgroundColor = "black";
+            // States
+            this._depthCullingState = new _DepthCullingState();
+            this._alphaState = new _AlphaState();
             // Cache
             this._loadedTexturesCache = new Array();
             this._activeTexturesCache = new Array();
             this._compiledEffects = {};
-            this._depthMask = true;
             this._renderingCanvas = canvas;
             this._canvasClientRect = this._renderingCanvas.getBoundingClientRect();
 
@@ -340,19 +588,19 @@
 
         // Methods
         Engine.prototype.setDepthFunctionToGreater = function () {
-            this._gl.depthFunc(this._gl.GREATER);
+            this._depthCullingState.depthFunc = this._gl.GREATER;
         };
 
         Engine.prototype.setDepthFunctionToGreaterOrEqual = function () {
-            this._gl.depthFunc(this._gl.GEQUAL);
+            this._depthCullingState.depthFunc = this._gl.GEQUAL;
         };
 
         Engine.prototype.setDepthFunctionToLess = function () {
-            this._gl.depthFunc(this._gl.LESS);
+            this._depthCullingState.depthFunc = this._gl.LESS;
         };
 
         Engine.prototype.setDepthFunctionToLessOrEqual = function () {
-            this._gl.depthFunc(this._gl.LEQUAL);
+            this._depthCullingState.depthFunc = this._gl.LEQUAL;
         };
 
         Engine.prototype.stopRenderLoop = function () {
@@ -409,7 +657,7 @@
 
         Engine.prototype.clear = function (color, backBuffer, depthStencil) {
             this._gl.clearColor(color.r, color.g, color.b, color.a !== undefined ? color.a : 1.0);
-            if (this._depthMask) {
+            if (this._depthCullingState.depthMask) {
                 this._gl.clearDepth(1.0);
             }
             var mode = 0;
@@ -417,7 +665,7 @@
             if (backBuffer)
                 mode |= this._gl.COLOR_BUFFER_BIT;
 
-            if (depthStencil && this._depthMask)
+            if (depthStencil && this._depthCullingState.depthMask)
                 mode |= this._gl.DEPTH_BUFFER_BIT;
 
             this._gl.clear(mode);
@@ -642,6 +890,11 @@
         };
 
         Engine.prototype.draw = function (useTriangles, indexStart, indexCount, instancesCount) {
+            // Apply states
+            this._depthCullingState.apply(this._gl);
+            this._alphaState.apply(this._gl);
+
+            // Render
             if (instancesCount) {
                 this._caps.instancedArrays.drawElementsInstancedANGLE(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, this._gl.UNSIGNED_SHORT, indexStart * 2, instancesCount);
                 return;
@@ -829,33 +1082,26 @@
         // States
         Engine.prototype.setState = function (culling, force) {
             // Culling
-            if (this._cullingState !== culling || force) {
+            if (this._depthCullingState.cull !== culling || force) {
                 if (culling) {
-                    this._gl.cullFace(this.cullBackFaces ? this._gl.BACK : this._gl.FRONT);
-                    this._gl.enable(this._gl.CULL_FACE);
+                    this._depthCullingState.cullFace = this.cullBackFaces ? this._gl.BACK : this._gl.FRONT;
+                    this._depthCullingState.cull = true;
                 } else {
-                    this._gl.disable(this._gl.CULL_FACE);
+                    this._depthCullingState.cull = false;
                 }
-
-                this._cullingState = culling;
             }
         };
 
         Engine.prototype.setDepthBuffer = function (enable) {
-            if (enable) {
-                this._gl.enable(this._gl.DEPTH_TEST);
-            } else {
-                this._gl.disable(this._gl.DEPTH_TEST);
-            }
+            this._depthCullingState.depthTest = enable;
         };
 
         Engine.prototype.getDepthWrite = function () {
-            return this._depthMask;
+            return this._depthCullingState.depthMask;
         };
 
         Engine.prototype.setDepthWrite = function (enable) {
-            this._gl.depthMask(enable);
-            this._depthMask = enable;
+            this._depthCullingState.depthMask = enable;
         };
 
         Engine.prototype.setColorWrite = function (enable) {
@@ -866,17 +1112,17 @@
             switch (mode) {
                 case BABYLON.Engine.ALPHA_DISABLE:
                     this.setDepthWrite(true);
-                    this._gl.disable(this._gl.BLEND);
+                    this._alphaState.alphaBlend = false;
                     break;
                 case BABYLON.Engine.ALPHA_COMBINE:
                     this.setDepthWrite(false);
-                    this._gl.blendFuncSeparate(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
-                    this._gl.enable(this._gl.BLEND);
+                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
+                    this._alphaState.alphaBlend = true;
                     break;
                 case BABYLON.Engine.ALPHA_ADD:
                     this.setDepthWrite(false);
-                    this._gl.blendFuncSeparate(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
-                    this._gl.enable(this._gl.BLEND);
+                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
+                    this._alphaState.alphaBlend = true;
                     break;
             }
         };
@@ -893,7 +1139,9 @@
         Engine.prototype.wipeCaches = function () {
             this._activeTexturesCache = [];
             this._currentEffect = null;
-            this._cullingState = null;
+
+            this._depthCullingState.reset();
+            this._alphaState.reset();
 
             this._cachedVertexBuffers = null;
             this._cachedIndexBuffer = null;
@@ -1453,7 +1701,7 @@
 
             window.addEventListener("resize", this._resizeLoadingUI);
 
-            this._loadingDiv.style.backgroundColor = "black";
+            this._loadingDiv.style.backgroundColor = this._loadingDivBackgroundColor;
             document.body.appendChild(this._loadingDiv);
 
             setTimeout(function () {
@@ -1462,7 +1710,7 @@
             }, 0);
         };
 
-        Object.defineProperty(Engine.prototype, "loadingUiText", {
+        Object.defineProperty(Engine.prototype, "loadingUIText", {
             set: function (text) {
                 if (!this._loadingDiv) {
                     return;
@@ -1474,6 +1722,24 @@
             configurable: true
         });
 
+        Object.defineProperty(Engine.prototype, "loadingUIBackgroundColor", {
+            get: function () {
+                return this._loadingDivBackgroundColor;
+            },
+            set: function (color) {
+                this._loadingDivBackgroundColor = color;
+
+                if (!this._loadingDiv) {
+                    return;
+                }
+
+                this._loadingDiv.style.backgroundColor = this._loadingDivBackgroundColor;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
         Engine.prototype.hideLoadingUI = function () {
             var _this = this;
             if (!this._loadingDiv) {

+ 268 - 30
Babylon/babylon.engine.ts

@@ -1,4 +1,225 @@
 module BABYLON {
+    export class _DepthCullingState {
+        private _isDepthTestDirty = false;
+        private _isDepthMaskDirty = false;
+        private _isDepthFuncDirty = false;
+        private _isCullFaceDirty = false;
+        private _isCullDirty = false;
+
+        private _depthTest: boolean;
+        private _depthMask: boolean;
+        private _depthFunc: number;
+        private _cull: boolean;
+        private _cullFace: number;
+        
+
+        public get isDirty(): boolean {
+            return this._isDepthTestDirty || this._isDepthMaskDirty || this._isCullFaceDirty || this._isCullDirty;
+        }
+
+        public get cullFace(): number {
+            return this._cullFace;
+        }
+
+        public set cullFace(value: number) {
+            if (this._cullFace === value) {
+                return;
+            }
+
+            this._cullFace = value;
+            this._isCullFaceDirty = true;
+        }
+
+        public get cull() {
+            return this._cull;
+        }
+
+        public set cull(value: boolean) {
+            if (this._cull === value) {
+                return;
+            }
+
+            this._cull = value;
+            this._isCullDirty = true;
+        }
+
+        public get depthFunc(): number {
+            return this._depthFunc;
+        }
+
+        public set depthFunc(value: number) {
+            if (this._depthFunc === value) {
+                return;
+            }
+
+            this._depthFunc = value;
+            this._isDepthFuncDirty = true;
+        }
+
+        public get depthMask(): boolean {
+            return this._depthMask;
+        }
+
+        public set depthMask(value: boolean) {
+            if (this._depthMask === value) {
+                return;
+            }
+
+            this._depthMask = value;
+            this._isDepthMaskDirty = true;
+        }
+
+        public get depthTest(): boolean {
+            return this._depthTest;
+        }
+
+        public set depthTest(value: boolean) {
+            if (this._depthTest === value) {
+                return;
+            }
+
+            this._depthTest = value;
+            this._isDepthTestDirty = true;
+        }
+
+        public reset() {
+            this._depthMask = true;
+            this._depthTest = true;
+            this._depthFunc = null;
+            this._cull = null;
+            this._cullFace = null;
+
+            this._isDepthTestDirty = true;
+            this._isDepthMaskDirty = true;
+            this._isDepthFuncDirty = false;
+            this._isCullFaceDirty = false;
+            this._isCullDirty = false;
+        }
+
+        public apply(gl: WebGLRenderingContext) {
+
+            if (!this.isDirty) {
+                return;
+            }
+
+            // Cull
+            if (this._isCullDirty) {
+                if (this.cull === true) {
+                    gl.enable(gl.CULL_FACE);
+                } else if (this.cull === false) {
+                    gl.disable(gl.CULL_FACE);
+                }
+
+                this._isCullDirty = false;
+            }
+
+            // Cull face
+            if (this._isCullFaceDirty) {
+                gl.cullFace(this.cullFace);
+                this._isCullFaceDirty = false;
+            }
+
+            // Depth mask
+            if (this._isDepthMaskDirty) {
+                gl.depthMask(this.depthMask);
+                this._isDepthMaskDirty = false;
+            }
+
+            // Depth test
+            if (this._isDepthTestDirty) {
+                if (this.depthTest === true) {
+                    gl.enable(gl.DEPTH_TEST);
+                } else if (this.depthTest === false) {
+                    gl.disable(gl.DEPTH_TEST);
+                }
+                this._isDepthTestDirty = false;
+            }
+
+            // Depth func
+            if (this._isDepthFuncDirty) {
+                gl.depthFunc(this.depthFunc);
+                this._isDepthFuncDirty = false;
+            }
+        }
+    }
+
+    export class _AlphaState {
+        private _isAlphaBlendDirty = false;
+        private _isBlendFunctionParametersDirty = false;
+        private _alphaBlend = false;
+        private _blendFunctionParameters = new Array<number>(4);
+
+        public get isDirty(): boolean {
+            return this._isAlphaBlendDirty || this._isBlendFunctionParametersDirty;
+        }
+
+        public get alphaBlend(): boolean {
+            return this._alphaBlend;
+        }
+
+        public set alphaBlend(value: boolean) {
+            if (this._alphaBlend === value) {
+                return;
+            }
+
+            this._alphaBlend = value;
+            this._isAlphaBlendDirty = true;
+        }
+
+        public setAlphaBlendFunctionParameters(value0: number, value1: number, value2: number, value3: number): void {
+            if (
+                this._blendFunctionParameters[0] === value0 &&
+                this._blendFunctionParameters[1] === value1 &&
+                this._blendFunctionParameters[2] === value2 &&
+                this._blendFunctionParameters[3] === value3
+            ) {
+                return;
+            }
+
+            this._blendFunctionParameters[0] = value0;                
+            this._blendFunctionParameters[1] = value1;                
+            this._blendFunctionParameters[2] = value2;                
+            this._blendFunctionParameters[3] = value3;                
+
+            this._isBlendFunctionParametersDirty = true;
+        }
+
+        public reset() {
+            this._alphaBlend = false;
+            this._blendFunctionParameters[0] = null;
+            this._blendFunctionParameters[1] = null;
+            this._blendFunctionParameters[2] = null;
+            this._blendFunctionParameters[3] = null;   
+
+            this._isAlphaBlendDirty = true;
+            this._isBlendFunctionParametersDirty = false;
+        }
+
+        public apply(gl: WebGLRenderingContext) {
+
+            if (!this.isDirty) {
+                return;
+            }
+
+            // Alpha blend
+            if (this._isAlphaBlendDirty) {
+                if (this._alphaBlend === true) {
+                    gl.enable(gl.BLEND);
+                } else if (this._alphaBlend === false) {
+                    gl.disable(gl.BLEND);
+                }
+
+                this._isAlphaBlendDirty = false;
+            }
+
+            // Alpha function
+            if (this._isBlendFunctionParametersDirty) {
+                gl.blendFuncSeparate(this._blendFunctionParameters[0], this._blendFunctionParameters[1], this._blendFunctionParameters[2], this._blendFunctionParameters[3]);
+                this._isBlendFunctionParametersDirty = false;
+            }
+        }
+    }
+
     var compileShader = (gl: WebGLRenderingContext, source: string, type: string, defines: string): WebGLShader => {
         var shader = gl.createShader(type === "vertex" ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
 
@@ -203,15 +424,18 @@
         private _resizeLoadingUI: () => void;
         private _loadingDiv: HTMLDivElement;
         private _loadingTextDiv: HTMLDivElement;
+        private _loadingDivBackgroundColor = "black";
+
+        // States
+        private _depthCullingState = new _DepthCullingState();
+        private _alphaState = new _AlphaState();
 
         // Cache
         private _loadedTexturesCache = new Array<WebGLTexture>();
         public _activeTexturesCache = new Array<BaseTexture>();
         private _currentEffect: Effect;
-        private _cullingState: boolean;
         private _compiledEffects = {};
         private _vertexAttribArrays: boolean[];
-        private _depthMask = true;
         private _cachedViewport: Viewport;
         private _cachedVertexBuffers: any;
         private _cachedIndexBuffer: WebGLBuffer;
@@ -373,19 +597,19 @@
 
         // Methods
         public setDepthFunctionToGreater(): void {
-            this._gl.depthFunc(this._gl.GREATER);
+            this._depthCullingState.depthFunc = this._gl.GREATER;
         }
 
         public setDepthFunctionToGreaterOrEqual(): void {
-            this._gl.depthFunc(this._gl.GEQUAL);
+            this._depthCullingState.depthFunc = this._gl.GEQUAL;
         }
 
         public setDepthFunctionToLess(): void {
-            this._gl.depthFunc(this._gl.LESS);
+            this._depthCullingState.depthFunc = this._gl.LESS;
         }
 
         public setDepthFunctionToLessOrEqual(): void {
-            this._gl.depthFunc(this._gl.LEQUAL);
+            this._depthCullingState.depthFunc = this._gl.LEQUAL;
         }
 
         public stopRenderLoop(): void {
@@ -440,7 +664,7 @@
 
         public clear(color: any, backBuffer: boolean, depthStencil: boolean): void {
             this._gl.clearColor(color.r, color.g, color.b, color.a !== undefined ? color.a : 1.0);
-            if (this._depthMask) {
+            if (this._depthCullingState.depthMask) {
                 this._gl.clearDepth(1.0);
             }
             var mode = 0;
@@ -448,7 +672,7 @@
             if (backBuffer)
                 mode |= this._gl.COLOR_BUFFER_BIT;
 
-            if (depthStencil && this._depthMask)
+            if (depthStencil && this._depthCullingState.depthMask)
                 mode |= this._gl.DEPTH_BUFFER_BIT;
 
             this._gl.clear(mode);
@@ -673,6 +897,11 @@
         }
 
         public draw(useTriangles: boolean, indexStart: number, indexCount: number, instancesCount?: number): void {
+            // Apply states
+            this._depthCullingState.apply(this._gl);
+            this._alphaState.apply(this._gl);
+            
+            // Render
             if (instancesCount) {
                 this._caps.instancedArrays.drawElementsInstancedANGLE(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, this._gl.UNSIGNED_SHORT, indexStart * 2, instancesCount);
                 return;
@@ -861,33 +1090,26 @@
         // States
         public setState(culling: boolean, force?: boolean): void {
             // Culling        
-            if (this._cullingState !== culling || force) {
+            if (this._depthCullingState.cull !== culling || force) {
                 if (culling) {
-                    this._gl.cullFace(this.cullBackFaces ? this._gl.BACK : this._gl.FRONT);
-                    this._gl.enable(this._gl.CULL_FACE);
+                    this._depthCullingState.cullFace = this.cullBackFaces ? this._gl.BACK : this._gl.FRONT;
+                    this._depthCullingState.cull = true;
                 } else {
-                    this._gl.disable(this._gl.CULL_FACE);
+                    this._depthCullingState.cull = false;
                 }
-
-                this._cullingState = culling;
             }
         }
 
         public setDepthBuffer(enable: boolean): void {
-            if (enable) {
-                this._gl.enable(this._gl.DEPTH_TEST);
-            } else {
-                this._gl.disable(this._gl.DEPTH_TEST);
-            }
+            this._depthCullingState.depthTest = enable;
         }
 
         public getDepthWrite(): boolean {
-            return this._depthMask;
+            return this._depthCullingState.depthMask;
         }
 
         public setDepthWrite(enable: boolean): void {
-            this._gl.depthMask(enable);
-            this._depthMask = enable;
+            this._depthCullingState.depthMask = enable;
         }
 
         public setColorWrite(enable: boolean): void {
@@ -899,17 +1121,17 @@
             switch (mode) {
                 case BABYLON.Engine.ALPHA_DISABLE:
                     this.setDepthWrite(true);
-                    this._gl.disable(this._gl.BLEND);
+                    this._alphaState.alphaBlend = false;
                     break;
                 case BABYLON.Engine.ALPHA_COMBINE:
                     this.setDepthWrite(false);
-                    this._gl.blendFuncSeparate(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
-                    this._gl.enable(this._gl.BLEND);
+                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
+                    this._alphaState.alphaBlend = true;
                     break;
                 case BABYLON.Engine.ALPHA_ADD:
                     this.setDepthWrite(false);
-                    this._gl.blendFuncSeparate(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
-                    this._gl.enable(this._gl.BLEND);
+                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
+                    this._alphaState.alphaBlend = true;
                     break;
             }
         }
@@ -926,7 +1148,9 @@
         public wipeCaches(): void {
             this._activeTexturesCache = [];
             this._currentEffect = null;
-            this._cullingState = null;
+
+            this._depthCullingState.reset();
+            this._alphaState.reset();
 
             this._cachedVertexBuffers = null;
             this._cachedIndexBuffer = null;
@@ -1485,7 +1709,7 @@
 
             window.addEventListener("resize", this._resizeLoadingUI);
 
-            this._loadingDiv.style.backgroundColor = "black";
+            this._loadingDiv.style.backgroundColor = this._loadingDivBackgroundColor;
             document.body.appendChild(this._loadingDiv);
 
             setTimeout(() => {
@@ -1494,7 +1718,7 @@
             }, 0);
         }
 
-        public set loadingUiText(text: string) {
+        public set loadingUIText(text: string) {
             if (!this._loadingDiv) {
                 return;
             }
@@ -1502,6 +1726,20 @@
             this._loadingTextDiv.innerHTML = text;
         }
 
+        public get loadingUIBackgroundColor(): string {
+            return this._loadingDivBackgroundColor;
+        }
+
+        public set loadingUIBackgroundColor(color: string) {
+            this._loadingDivBackgroundColor = color;
+
+            if (!this._loadingDiv) {
+                return;
+            }
+
+            this._loadingDiv.style.backgroundColor = this._loadingDivBackgroundColor;
+        }
+
         public hideLoadingUI(): void {
             if (!this._loadingDiv) {
                 return;

Plik diff jest za duży
+ 3 - 3
babylon.1.14-beta-debug.js


Plik diff jest za duży
+ 13 - 13
babylon.1.14-beta.js