Deltakosh 12 lat temu
rodzic
commit
b32951e642

+ 0 - 2
Babylon/Lights/babylon.light.js

@@ -4,8 +4,6 @@
     BABYLON.Light = function (name, scene) {
         this.name = name;
         this.id = name;
-        this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
 
         this._scene = scene;
 

+ 30 - 8
Babylon/Materials/babylon.standardMaterial.js

@@ -106,8 +106,17 @@
                 continue;
             }
 
-            defines.push("#define LIGHT" + lightIndex++);
+            defines.push("#define LIGHT" + lightIndex);
+            
+            if (light instanceof BABYLON.SpotLight) {
+                defines.push("#define SPOTLIGHT" + lightIndex);
+            } else if (light instanceof BABYLON.HemisphericLight) {
+                defines.push("#define HEMILIGHT" + lightIndex);
+            } else {
+                defines.push("#define POINTDIRLIGHT" + lightIndex);
+            }
 
+            lightIndex++;
             if (lightIndex == 4)
                 break;
         }
@@ -141,10 +150,10 @@
             this._effect = this._scene.getEngine().createEffect(shaderName,
                 attribs,
                 ["world", "view", "worldViewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
-                 "vLightData0", "vLightDiffuse0", "vLightSpecular0",
-                 "vLightData1", "vLightDiffuse1", "vLightSpecular1",
-                 "vLightData2", "vLightDiffuse2", "vLightSpecular2",
-                 "vLightData3", "vLightDiffuse3", "vLightSpecular3",
+                 "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0",
+                 "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1",
+                 "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2",
+                 "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3",
                  "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos",
                  "vMisc", "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix"],
                 ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler"],
@@ -271,14 +280,27 @@
             if (!light.isEnabled) {
                 continue;
             }
-            
-            if (light.position) {
+                        
+            if (light instanceof BABYLON.PointLight) {
+                // Point Light
                 this._effect.setVector4("vLightData" + lightIndex, light.position.x, light.position.y, light.position.z, 0);
-            } else {
+            } else if (light instanceof BABYLON.DirectionalLight) {
+                // Directional Light
                 this._effect.setVector4("vLightData" + lightIndex, light.direction.x, light.direction.y, light.direction.z, 1);
+            } else if (light instanceof BABYLON.SpotLight) {
+                // Spot Light
+                this._effect.setVector4("vLightData" + lightIndex, light.position.x, light.position.y, light.position.z, light.exponent);
+                var normalizeDirection = BABYLON.Vector3.Normalize(light.direction);
+                this._effect.setVector4("vLightDirection" + lightIndex, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(light.angle * 0.5));
+            } else if (light instanceof BABYLON.HemisphericLight) {
+                // Hemispheric Light
+                var normalizeDirection = BABYLON.Vector3.Normalize(light.direction);
+                this._effect.setVector4("vLightData" + lightIndex, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
+                this._effect.setColor3("vLightGround" + lightIndex, light.groundColor.scale(light.intensity));
             }
             this._effect.setColor3("vLightDiffuse" + lightIndex, light.diffuse.scale(light.intensity));
             this._effect.setColor3("vLightSpecular" + lightIndex, light.specular.scale(light.intensity));
+
             lightIndex++;
 
             if (lightIndex == 4)

+ 1 - 1
Babylon/Materials/textures/babylon.cubeTexture.js

@@ -12,7 +12,7 @@
         this._texture = this._getFromCache(rootUrl);
         
         if (!this._texture) {
-            this._texture = scene.getEngine().createCubeTexture(rootUrl);
+            this._texture = scene.getEngine().createCubeTexture(rootUrl, scene);
         }
         
         this.isCube = true;

+ 1 - 1
Babylon/Materials/textures/babylon.texture.js

@@ -10,7 +10,7 @@
         this._texture = this._getFromCache(url, noMipmap);
         
         if (!this._texture) {
-            this._texture = scene.getEngine().createTexture(url, noMipmap, invertY);
+            this._texture = scene.getEngine().createTexture(url, noMipmap, invertY, scene);
         }
         
         // Animations

+ 123 - 10
Babylon/Shaders/default.fragment.fx

@@ -17,21 +17,48 @@ uniform vec4 vMisc;
 uniform vec4 vLightData0;
 uniform vec3 vLightDiffuse0;
 uniform vec3 vLightSpecular0;
+#ifdef SPOTLIGHT0
+uniform vec4 vLightDirection0;
 #endif
+#ifdef HEMILIGHT0
+uniform vec3 vLightGround0;
+#endif
+#endif
+
 #ifdef LIGHT1
 uniform vec4 vLightData1;
 uniform vec3 vLightDiffuse1;
 uniform vec3 vLightSpecular1;
+#ifdef SPOTLIGHT1
+uniform vec4 vLightDirection1;
+#endif
+#ifdef HEMILIGHT1
+uniform vec3 vLightGround1;
 #endif
+#endif
+
 #ifdef LIGHT2
 uniform vec4 vLightData2;
 uniform vec3 vLightDiffuse2;
 uniform vec3 vLightSpecular2;
+#ifdef SPOTLIGHT2
+uniform vec4 vLightDirection2;
+#endif
+#ifdef HEMILIGHT2
+uniform vec3 vLightGround2;
 #endif
+#endif
+
 #ifdef LIGHT3
 uniform vec4 vLightData3;
 uniform vec3 vLightDiffuse3;
 uniform vec3 vLightSpecular3;
+#ifdef SPOTLIGHT3
+uniform vec4 vLightDirection3;
+#endif
+#ifdef HEMILIGHT3
+uniform vec3 vLightGround3;
+#endif
 #endif
 
 // Samplers
@@ -82,12 +109,12 @@ varying float fClipDistance;
 
 // Light Computing
 struct lightingInfo
-{ 
-	vec3 diffuse; 
-	vec3 specular; 
-}; 
+{
+	vec3 diffuse;
+	vec3 specular;
+};
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseColor, vec3 specularColor) {	
+lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseColor, vec3 specularColor) {
 	lightingInfo result;
 
 	vec3 lightVectorW;
@@ -95,7 +122,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseCo
 	{
 		lightVectorW = normalize(lightData.xyz - vPositionW);
 	}
-	else 
+	else
 	{
 		lightVectorW = normalize(-lightData.xyz);
 	}
@@ -105,7 +132,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseCo
 
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightVectorW);
-	float specComp = dot(normalize(vNormalW), angleW);
+	float specComp = max(0., dot(normalize(vNormalW), angleW));
 	specComp = pow(specComp, vSpecularColor.a);
 
 	result.diffuse = ndl * diffuseColor;
@@ -114,6 +141,57 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseCo
 	return result;
 }
 
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor) {
+	lightingInfo result;
+
+	vec3 lightVectorW = normalize(lightData.xyz - vPositionW);
+
+	// diffuse
+	float cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW));
+	float spotAtten = 0.0;
+
+	if (cosAngle >= lightDirection.w)
+	{
+		cosAngle = max(0., pow(cosAngle, lightData.w));
+		spotAtten = (cosAngle - lightDirection.w) / (1. - cosAngle);
+
+		// Diffuse
+		float ndl = max(0., dot(vNormalW, -lightDirection.xyz));
+
+		// Specular
+		vec3 angleW = normalize(viewDirectionW - lightDirection.xyz);
+		float specComp = max(0., dot(normalize(vNormalW), angleW));
+		specComp = pow(specComp, vSpecularColor.a);
+
+		result.diffuse = ndl * spotAtten * diffuseColor;
+		result.specular = specComp * specularColor * spotAtten;
+
+		return result;
+	}
+
+	result.diffuse = vec3(0.);
+	result.specular = vec3(0.);
+
+	return result;
+}
+
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor) {
+	lightingInfo result;
+
+	// Diffuse
+	float ndl = dot(vNormalW, lightData.xyz) * 0.5 + 0.5;
+
+	// Specular
+	vec3 angleW = normalize(viewDirectionW + lightData.xyz);
+	float specComp = max(0., dot(normalize(vNormalW), angleW));
+	specComp = pow(specComp, vSpecularColor.a);
+
+	result.diffuse = mix(groundColor, diffuseColor, ndl);
+	result.specular = specComp * specularColor;
+
+	return result;
+}
+
 void main(void) {
 	// Clip plane
 #ifdef CLIPPLANE
@@ -150,22 +228,57 @@ void main(void) {
 	vec3 specularBase = vec3(0., 0., 0.);
 
 #ifdef LIGHT0
+#ifdef SPOTLIGHT0
+	lightingInfo info = computeSpotLighting(viewDirectionW, vLightData0, vLightDirection0, vLightDiffuse0, vLightSpecular0);
+#endif
+#ifdef HEMILIGHT0
+	lightingInfo info = computeHemisphericLighting(viewDirectionW, vLightData0, vLightDiffuse0, vLightSpecular0, vLightGround0);
+#endif
+#ifdef POINTDIRLIGHT0
 	lightingInfo info = computeLighting(viewDirectionW, vLightData0, vLightDiffuse0, vLightSpecular0);
+#endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
 #endif
+
 #ifdef LIGHT1
+#ifdef SPOTLIGHT1
+	info = computeSpotLighting(viewDirectionW, vLightData1, vLightDirection1, vLightDiffuse1, vLightSpecular1);
+#endif
+#ifdef HEMILIGHT1
+	info = computeHemisphericLighting(viewDirectionW, vLightData1, vLightDiffuse1, vLightSpecular1, vLightGround1);
+#endif
+#ifdef POINTDIRLIGHT1
 	info = computeLighting(viewDirectionW, vLightData1, vLightDiffuse1, vLightSpecular1);
+#endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
 #endif
+
 #ifdef LIGHT2
+#ifdef SPOTLIGHT2
+	info = computeSpotLighting(viewDirectionW, vLightData2, vLightDirection2, vLightDiffuse2, vLightSpecular2);
+#endif
+#ifdef HEMILIGHT2
+	info = computeHemisphericLighting(viewDirectionW, vLightData2, vLightDiffuse2, vLightSpecular2, vLightGround2);
+#endif
+#ifdef POINTDIRLIGHT2
 	info = computeLighting(viewDirectionW, vLightData2, vLightDiffuse2, vLightSpecular2);
+#endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
 #endif
+
 #ifdef LIGHT3
+#ifdef SPOTLIGHT3
+	info = computeSpotLighting(viewDirectionW, vLightData3, vLightDirection3, vLightDiffuse3, vLightSpecular3);
+#endif
+#ifdef HEMILIGHT3
+	info = computeHemisphericLighting(viewDirectionW, vLightData3, vLightDiffuse3, vLightSpecular3, vLightGround3);
+#endif
+#ifdef POINTDIRLIGHT3
 	info = computeLighting(viewDirectionW, vLightData3, vLightDiffuse3, vLightSpecular3);
+#endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
 #endif
@@ -190,7 +303,7 @@ void main(void) {
 		coords.y = 1.0 - coords.y;
 
 		reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.y;
-	}	
+	}
 #endif
 
 	// Alpha
@@ -198,7 +311,7 @@ void main(void) {
 
 #ifdef OPACITY
 	vec3 opacityMap = texture2D(opacitySampler, vOpacityUV).rgb * vec3(0.3, 0.59, 0.11);
-	alpha *= (opacityMap.x + opacityMap.y + opacityMap.z )* vOpacityInfos.y;
+	alpha *= (opacityMap.x + opacityMap.y + opacityMap.z)* vOpacityInfos.y;
 #endif
 
 	// Emissive
@@ -210,7 +323,7 @@ void main(void) {
 	// Specular map
 	vec3 specularColor = vSpecularColor.rgb;
 #ifdef SPECULAR
-	specularColor = texture2D(specularSampler, vSpecularUV).rgb * vSpecularInfos.y;	
+	specularColor = texture2D(specularSampler, vSpecularUV).rgb * vSpecularInfos.y;
 #endif
 
 	// Composition

+ 29 - 13
Babylon/Tools/babylon.sceneLoader.js

@@ -201,6 +201,34 @@
         return animation;
     };
 
+    var parseLight = function(parsedLight, scene) {
+        var light;
+
+        switch (parsedLight.type) {
+            case 0:
+                light = new BABYLON.PointLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), scene);
+                break;
+            case 1:
+                light = new BABYLON.DirectionalLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), scene);
+                break;
+            case 2:
+                light = new BABYLON.SpotLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), BABYLON.Vector3.FromArray(parsedLight.direction), parsedLight.angle, parsedLight.exponent, scene);
+                break;
+            case 3:
+                light = new BABYLON.HemisphericLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), scene);
+                light.groundColor = BABYLON.Color3.FromArray(parsedLight.groundColor);
+                break;
+        }
+
+        light.id = parsedLight.id;
+
+        if (parsedLight.intensity) {
+            light.intensity = parsedLight.intensity;
+        }
+        light.diffuse = BABYLON.Color3.FromArray(parsedLight.diffuse);
+        light.specular = BABYLON.Color3.FromArray(parsedLight.specular);
+    };
+
     var parseMesh = function (parsedMesh, scene) {
         var declaration = null;
         
@@ -361,19 +389,7 @@
                 // Lights
                 for (var index = 0; index < parsedData.lights.length; index++) {
                     var parsedLight = parsedData.lights[index];
-                    var light;
-                    if (parsedLight.type === 0) {
-                        light = new BABYLON.PointLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), scene);
-                    } else {
-                        light = new BABYLON.DirectionalLight(parsedLight.name, BABYLON.Vector3.FromArray(parsedLight.data), scene);
-                    }
-                    light.diffuse = BABYLON.Color3.FromArray(parsedLight.diffuse);
-                    light.specular = BABYLON.Color3.FromArray(parsedLight.specular);
-                    light.id = parsedLight.id;
-
-                    if (parsedLight.intensity) {
-                        light.intensity = parsedLight.intensity;
-                    }
+                    parseLight(parsedLight, scene);
                 }
 
                 // Cameras

+ 18 - 5
Babylon/babylon.engine.js

@@ -489,7 +489,7 @@
         return count;
     };
 
-    BABYLON.Engine.prototype.createTexture = function (url, noMipmap, invertY) {
+    BABYLON.Engine.prototype.createTexture = function (url, noMipmap, invertY, scene) {
         var texture = this._gl.createTexture();
         var that = this;
         var img = new Image();
@@ -519,8 +519,14 @@
             texture._width = that._workingCanvas.width;
             texture._height = that._workingCanvas.height;
             texture.isReady = true;
+            scene._removePendingData(img);
         };
 
+        img.onerror = function () {
+            scene._removePendingData(img);
+        };
+
+        scene._addPendingData(img);
         img.src = url;
 
         texture.url = url;
@@ -616,22 +622,29 @@
 
     var extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
 
-    var cascadeLoad = function (rootUrl, index, loadedImages, onfinish) {
+    var cascadeLoad = function (rootUrl, index, loadedImages, scene, onfinish) {
         var img = new Image();
         img.onload = function () {
             loadedImages.push(this);
 
+            scene._removePendingData(img);
+
             if (index != extensions.length - 1) {
-                cascadeLoad(rootUrl, index + 1, loadedImages, onfinish);
+                cascadeLoad(rootUrl, index + 1, loadedImages, scene, onfinish);
             } else {
                 onfinish(loadedImages);
             }
         };
 
+        img.onerrror = function () {
+            scene._removePendingData(img);
+        };
+
+        scene._addPendingData(img);
         img.src = rootUrl + extensions[index];
     };
 
-    BABYLON.Engine.prototype.createCubeTexture = function (rootUrl) {
+    BABYLON.Engine.prototype.createCubeTexture = function (rootUrl, scene) {
         var gl = this._gl;
 
         var texture = gl.createTexture();
@@ -641,7 +654,7 @@
         this._loadedTexturesCache.push(texture);
 
         var that = this;
-        cascadeLoad(rootUrl, 0, [], function (imgs) {
+        cascadeLoad(rootUrl, 0, [], scene, function (imgs) {
             var width = getExponantOfTwo(imgs[0].width);
             var height = width;
 

+ 47 - 30
Babylon/babylon.scene.js

@@ -19,6 +19,9 @@
 
         this._toBeDisposed = [];
 
+        this._onReadyCallbacks = [];
+        this._pendingData = [];
+
         // Lights
         this.lights = [];
 
@@ -43,14 +46,14 @@
 
         // Sprites
         this.spriteManagers = [];
-        
+
         // Layers
         this.layers = [];
 
         // Collisions
         this.collisionsEnabled = true;
         this.gravity = new BABYLON.Vector3(0, 0, -9);
-        
+
         // Animations
         this._activeAnimatables = [];
     };
@@ -96,15 +99,15 @@
     BABYLON.Scene.prototype.getParticlesDuration = function () {
         return this._particlesDuration;
     };
-    
+
     BABYLON.Scene.prototype.getSpritesDuration = function () {
         return this._spritesDuration;
     };
-    
+
     BABYLON.Scene.prototype.getAnimationRatio = function () {
         return this._animationRatio;
     };
-    
+
     // Ready
     BABYLON.Scene.prototype.isReady = function () {
         for (var index = 0; index < this.materials.length; index++) {
@@ -116,25 +119,39 @@
         return true;
     };
 
-    BABYLON.Scene.prototype.executeWhenReady = function(func) {
+    BABYLON.Scene.prototype.executeWhenReady = function (func) {
         if (this.isReady()) {
             func();
             return;
         }
-        
-        var that = this;
-        var checkState = function() {
-            if (that.isReady()) {
-                func();
-                return;
-            }            
 
-            setTimeout(checkState, 150);
-        };
+        if (this._pendingData.length === 0) {
+            func();
+            return;
+        }
+        this._onReadyCallbacks.push(func);
+    };
+
+    BABYLON.Scene.prototype._addPendingData = function (data) {
+        this._pendingData.push(data);
+    };
+
+    BABYLON.Scene.prototype._removePendingData = function (data) {
+        var index = this._pendingData.indexOf(data);
+
+        if (index !== -1) {
+            this._pendingData.splice(index, 1);
 
-        setTimeout(checkState, 150);
+            if (this._pendingData.length === 0) {
+                this._onReadyCallbacks.forEach(function (func) {
+                    func();
+                });
+
+                this._onReadyCallbacks = [];
+            }
+        }
     };
-    
+
     // Animations
     BABYLON.Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio) {
         if (speedRatio === undefined) {
@@ -144,12 +161,12 @@
         // Local animations
         if (target.animations) {
             this.stopAnimation(target);
-            
+
             var animatable = new BABYLON._Animatable(target, from, to, loop, speedRatio);
 
             this._activeAnimatables.push(animatable);
         }
-        
+
         // Children animations
         if (target.getAnimatables) {
             var animatables = target.getAnimatables();
@@ -159,7 +176,7 @@
         }
     };
 
-    BABYLON.Scene.prototype.stopAnimation = function(target) {
+    BABYLON.Scene.prototype.stopAnimation = function (target) {
         for (var index = 0; index < this._activeAnimatables.length; index++) {
             if (this._activeAnimatables[index].target === target) {
                 this._activeAnimatables.splice(index, 1);
@@ -176,7 +193,7 @@
             }
         }
     };
-    
+
     // Matrix
     BABYLON.Scene.prototype.getViewMatrix = function () {
         return this._viewMatrix;
@@ -237,7 +254,7 @@
 
         return result;
     };
-    
+
     BABYLON.Scene.prototype.getMeshByName = function (name) {
         for (var index = 0; index < this.meshes.length; index++) {
             if (this.meshes[index].name == name) {
@@ -330,7 +347,7 @@
             var submesh = opaqueSubMeshes[subIndex];
 
             this._activeVertices += submesh.verticesCount;
-            
+
             submesh.render();
         }
 
@@ -355,14 +372,14 @@
             }
             this._spritesDuration = new Date() - beforeSpritessDate;
         }
-        
+
         // Transparent
         engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
         for (var subIndex = 0; subIndex < transparentSubMeshes.length; subIndex++) {
             var submesh = transparentSubMeshes[subIndex];
 
             this._activeVertices += submesh.verticesCount;
-            
+
             submesh.render();
         }
         engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
@@ -446,7 +463,7 @@
             }
         }
         engine.setDepthBuffer(true);
-        
+
         this._renderDuration = new Date() - beforeRenderDate;
 
         // Update camera
@@ -496,7 +513,7 @@
         while (this.spriteManagers.length) {
             this.spriteManagers[0].dispose();
         }
-        
+
         // Release layers
         while (this.layers.length) {
             this.layers[0].dispose();
@@ -565,9 +582,9 @@
     };
 
     // Picking
-    BABYLON.Scene.prototype.createPickingRay = function(x, y, world) {        
+    BABYLON.Scene.prototype.createPickingRay = function (x, y, world) {
         var engine = this._engine;
-        
+
         if (!this._viewMatrix) {
             if (!this.activeCamera)
                 throw new Error("Active camera not set");
@@ -589,7 +606,7 @@
             if (!mesh.isEnabled() || !mesh.isVisible) {
                 continue;
             }
-            
+
             var world = mesh.getWorldMatrix();
             var ray = this.createPickingRay(x, y, world);
 

+ 1 - 1
readme.md

@@ -12,7 +12,7 @@ Babylon.js is a webgl / javascript 3D engine. It supports the following features
  - Mirror texture
  - Emissive texture
  - Specular texture
- - Up to 4 lights (point or directional)
+ - Up to 4 lights (points, directionals, spots, hemispherics)
 - Render target textures
 - Dynamic textures (canvas)
 - Custom materials