浏览代码

Videos textures and Normal maps

Deltakosh 12 年之前
父节点
当前提交
4efba21937

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

@@ -14,6 +14,7 @@
         this.reflectionTexture = null;
         this.emissiveTexture = null;
         this.specularTexture = null;
+        this.bumpTexture = null;
 
         this.ambientColor = new BABYLON.Color3(0, 0, 0);
         this.diffuseColor = new BABYLON.Color3(1, 1, 1);
@@ -63,6 +64,10 @@
         if (this.specularTexture && !this.specularTexture.isReady()) {
             return false;
         }
+        
+        if (this.bumpTexture && !this.bumpTexture.isReady()) {
+            return false;
+        }
 
         // Effect
         var defines = [];
@@ -89,6 +94,10 @@
         if (this.specularTexture) {
             defines.push("#define SPECULAR");
         }
+        
+        if (this.bumpTexture && this._scene.getEngine().getCaps().standardDerivatives) {
+            defines.push("#define BUMP");
+        }
 
         if (BABYLON.clipPlane) {
             defines.push("#define CLIPPLANE");
@@ -154,9 +163,9 @@
                  "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"],
+                 "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos",
+                 "vMisc", "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix"],
+                ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler"],
                 join);
         }
         if (!this._effect.isReady()) {
@@ -264,6 +273,13 @@
             this._effect.setVector2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
             this._effect.setMatrix("specularMatrix", this.specularTexture._computeTextureMatrix());
         }
+        
+        if (this.bumpTexture && this._scene.getEngine().getCaps().standardDerivatives) {
+            this._effect.setTexture("bumpSampler", this.bumpTexture);
+
+            this._effect.setVector2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
+            this._effect.setMatrix("bumpMatrix", this.bumpTexture._computeTextureMatrix());
+        }
 
         this._effect.setMatrix("world", world);
         this._effect.setMatrix("worldViewProjection", world.multiply(this._scene.getTransformMatrix()));
@@ -368,6 +384,10 @@
         if (this.specularTexture) {
             this.specularTexture.dispose();
         }
+        
+        if (this.bumpTexture) {
+            this.bumpTexture.dispose();
+        }
 
         // Remove from scene
         var index = this._scene.materials.indexOf(this);

+ 3 - 3
Babylon/Materials/textures/babylon.dynamicTexture.js

@@ -11,11 +11,11 @@
         this.wrapV = false;
 
         this._texture = scene.getEngine().createDynamicTexture(size, generateMipMaps);
-        var size = this.getSize();
+        var textureSize = this.getSize();
 
         this._canvas = document.createElement("canvas");
-        this._canvas.width = size.width;
-        this._canvas.height = size.height;
+        this._canvas.width = textureSize.width;
+        this._canvas.height = textureSize.height;
         this._context = this._canvas.getContext("2d");
     };
 

+ 50 - 0
Babylon/Materials/textures/babylon.videoTexture.js

@@ -0,0 +1,50 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.VideoTexture = function (name, urls, size, scene, generateMipMaps) {
+        this._scene = scene;
+        this._scene.textures.push(this);
+
+        this.name = name;
+
+        this.wrapU = false;
+        this.wrapV = false;
+
+        this._texture = scene.getEngine().createDynamicTexture(size, generateMipMaps);
+        var textureSize = this.getSize();
+
+        this.video = document.createElement("video");
+        this.video.width = textureSize.width;
+        this.video.height = textureSize.height;
+        this.video.autoplay = true;
+        this.video.loop = true;
+
+        var that = this;
+        this.video.addEventListener("canplaythrough", function () {
+            that._texture.isReady = true;
+        });
+
+        this.video.preload = true;
+        urls.forEach(function (url) {
+            var source = document.createElement("source");
+            source.src = url;
+            that.video.appendChild(source);
+        });
+       
+        this._lastUpdate = new Date();
+    };
+
+    BABYLON.VideoTexture.prototype = Object.create(BABYLON.Texture.prototype);
+
+    BABYLON.VideoTexture.prototype._update = function () {
+        var now = new Date();
+
+        if (now - this._lastUpdate < 15) {
+            return false;
+        }
+
+        this._lastUpdate = now;
+        this._scene.getEngine().updateVideoTexture(this._texture, this.video);
+        return true;
+    };
+})();

+ 4 - 4
Babylon/Mesh/babylon.mesh.js

@@ -681,10 +681,10 @@
 
         // Vertices
         var halfSize = size / 2.0;
-        vertices.push(-halfSize, -halfSize, 0, 0, 1.0, 0, 0.0, 0.0);
-        vertices.push(halfSize, -halfSize, 0, 0, 1.0, 0, 1.0, 0.0);
-        vertices.push(halfSize, halfSize, 0, 0, 1.0, 0, 1.0, 1.0);
-        vertices.push(-halfSize, halfSize, 0, 0, 1.0, 0, 0.0, 1.0);
+        vertices.push(-halfSize, -halfSize, 0, 0, 0, -1.0, 0.0, 0.0);
+        vertices.push(halfSize, -halfSize, 0, 0, 0, -1.0, 1.0, 0.0);
+        vertices.push(halfSize, halfSize, 0, 0, 0, -1.0, 1.0, 1.0);
+        vertices.push(-halfSize, halfSize, 0, 0, 0, -1.0, 0.0, 1.0);
 
         // Indices
         indices.push(0);

+ 67 - 22
Babylon/Shaders/default.fragment.fx

@@ -99,6 +99,13 @@ uniform vec2 vSpecularInfos;
 uniform sampler2D specularSampler;
 #endif
 
+#ifdef BUMP
+#extension GL_OES_standard_derivatives : enable
+varying vec2 vBumpUV;
+uniform vec2 vBumpInfos;
+uniform sampler2D bumpSampler;
+#endif
+
 // Input
 varying vec3 vPositionW;
 varying vec3 vNormalW;
@@ -107,6 +114,37 @@ varying vec3 vNormalW;
 varying float fClipDistance;
 #endif
 
+#ifdef BUMP
+// Bump
+// Thanks to http://www.thetenthplanet.de/archives/1180
+mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
+{
+	// get edge vectors of the pixel triangle
+	vec3 dp1 = dFdx(p);
+	vec3 dp2 = dFdy(p);
+	vec2 duv1 = dFdx(uv);
+	vec2 duv2 = dFdy(uv);
+
+	// solve the linear system
+	vec3 dp2perp = cross(dp2, N);
+	vec3 dp1perp = cross(N, dp1);
+	vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
+	vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
+
+	// construct a scale-invariant frame 
+	float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
+	return mat3(T * invmax, B * invmax, N);
+}
+
+vec3 perturbNormal(vec3 viewDir)
+{
+	vec3 map = texture2D(bumpSampler, vBumpUV).xyz * vBumpInfos.y;
+	map = map * 255. / 127. - 128. / 127.;
+	mat3 TBN = cotangent_frame(vNormalW, -viewDir, vBumpUV);
+	return normalize(TBN * map);
+}
+#endif
+
 // Light Computing
 struct lightingInfo
 {
@@ -114,7 +152,7 @@ struct lightingInfo
 	vec3 specular;
 };
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseColor, vec3 specularColor) {
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor) {
 	lightingInfo result;
 
 	vec3 lightVectorW;
@@ -128,11 +166,11 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseCo
 	}
 
 	// diffuse
-	float ndl = max(0., dot(vNormalW, lightVectorW));
+	float ndl = max(0., dot(vNormal, lightVectorW));
 
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightVectorW);
-	float specComp = max(0., dot(normalize(vNormalW), angleW));
+	float specComp = max(0., dot(normalize(vNormal), angleW));
 	specComp = pow(specComp, vSpecularColor.a);
 
 	result.diffuse = ndl * diffuseColor;
@@ -141,7 +179,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseCo
 	return result;
 }
 
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor) {
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor) {
 	lightingInfo result;
 
 	vec3 lightVectorW = normalize(lightData.xyz - vPositionW);
@@ -153,14 +191,14 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec4 lightData, vec4 light
 	if (cosAngle >= lightDirection.w)
 	{
 		cosAngle = max(0., pow(cosAngle, lightData.w));
-		spotAtten = (cosAngle - lightDirection.w) / (1. - cosAngle);
+		spotAtten = max(0., (cosAngle - lightDirection.w) / (1. - cosAngle));
 
 		// Diffuse
-		float ndl = max(0., dot(vNormalW, -lightDirection.xyz));
+		float ndl = max(0., dot(vNormal, -lightDirection.xyz));
 
 		// Specular
 		vec3 angleW = normalize(viewDirectionW - lightDirection.xyz);
-		float specComp = max(0., dot(normalize(vNormalW), angleW));
+		float specComp = max(0., dot(normalize(vNormal), angleW));
 		specComp = pow(specComp, vSpecularColor.a);
 
 		result.diffuse = ndl * spotAtten * diffuseColor;
@@ -175,15 +213,15 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec4 lightData, vec4 light
 	return result;
 }
 
-lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor) {
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor) {
 	lightingInfo result;
 
 	// Diffuse
-	float ndl = dot(vNormalW, lightData.xyz) * 0.5 + 0.5;
+	float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
 
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightData.xyz);
-	float specComp = max(0., dot(normalize(vNormalW), angleW));
+	float specComp = max(0., dot(normalize(vNormal), angleW));
 	specComp = pow(specComp, vSpecularColor.a);
 
 	result.diffuse = mix(groundColor, diffuseColor, ndl);
@@ -216,6 +254,13 @@ void main(void) {
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 
+	// Bump
+	vec3 normalW = vNormalW;
+
+#ifdef BUMP
+	normalW = perturbNormal(viewDirectionW);
+#endif
+
 	// Ambient color
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 
@@ -229,13 +274,13 @@ void main(void) {
 
 #ifdef LIGHT0
 #ifdef SPOTLIGHT0
-	lightingInfo info = computeSpotLighting(viewDirectionW, vLightData0, vLightDirection0, vLightDiffuse0, vLightSpecular0);
+	lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0, vLightSpecular0);
 #endif
 #ifdef HEMILIGHT0
-	lightingInfo info = computeHemisphericLighting(viewDirectionW, vLightData0, vLightDiffuse0, vLightSpecular0, vLightGround0);
+	lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0, vLightSpecular0, vLightGround0);
 #endif
 #ifdef POINTDIRLIGHT0
-	lightingInfo info = computeLighting(viewDirectionW, vLightData0, vLightDiffuse0, vLightSpecular0);
+	lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0, vLightSpecular0);
 #endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
@@ -243,13 +288,13 @@ void main(void) {
 
 #ifdef LIGHT1
 #ifdef SPOTLIGHT1
-	info = computeSpotLighting(viewDirectionW, vLightData1, vLightDirection1, vLightDiffuse1, vLightSpecular1);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1, vLightSpecular1);
 #endif
 #ifdef HEMILIGHT1
-	info = computeHemisphericLighting(viewDirectionW, vLightData1, vLightDiffuse1, vLightSpecular1, vLightGround1);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1, vLightSpecular1, vLightGround1);
 #endif
 #ifdef POINTDIRLIGHT1
-	info = computeLighting(viewDirectionW, vLightData1, vLightDiffuse1, vLightSpecular1);
+	info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1, vLightSpecular1);
 #endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
@@ -257,13 +302,13 @@ void main(void) {
 
 #ifdef LIGHT2
 #ifdef SPOTLIGHT2
-	info = computeSpotLighting(viewDirectionW, vLightData2, vLightDirection2, vLightDiffuse2, vLightSpecular2);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2, vLightSpecular2);
 #endif
 #ifdef HEMILIGHT2
-	info = computeHemisphericLighting(viewDirectionW, vLightData2, vLightDiffuse2, vLightSpecular2, vLightGround2);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2, vLightSpecular2, vLightGround2);
 #endif
 #ifdef POINTDIRLIGHT2
-	info = computeLighting(viewDirectionW, vLightData2, vLightDiffuse2, vLightSpecular2);
+	info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2, vLightSpecular2);
 #endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;
@@ -271,13 +316,13 @@ void main(void) {
 
 #ifdef LIGHT3
 #ifdef SPOTLIGHT3
-	info = computeSpotLighting(viewDirectionW, vLightData3, vLightDirection3, vLightDiffuse3, vLightSpecular3);
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3, vLightSpecular3);
 #endif
 #ifdef HEMILIGHT3
-	info = computeHemisphericLighting(viewDirectionW, vLightData3, vLightDiffuse3, vLightSpecular3, vLightGround3);
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3, vLightSpecular3, vLightGround3);
 #endif
 #ifdef POINTDIRLIGHT3
-	info = computeLighting(viewDirectionW, vLightData3, vLightDiffuse3, vLightSpecular3);
+	info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3, vLightSpecular3);
 #endif
 	diffuseBase += info.diffuse;
 	specularBase += info.specular;

+ 17 - 0
Babylon/Shaders/default.vertex.fx

@@ -57,6 +57,12 @@ uniform vec2 vSpecularInfos;
 uniform mat4 specularMatrix;
 #endif
 
+#ifdef BUMP
+varying vec2 vBumpUV;
+uniform vec2 vBumpInfos;
+uniform mat4 bumpMatrix;
+#endif
+
 // Output
 varying vec3 vPositionW;
 varying vec3 vNormalW;
@@ -172,6 +178,17 @@ void main(void) {
 	}
 #endif
 
+#ifdef BUMP
+	if (vBumpInfos.x == 0.)
+	{
+		vBumpUV = vec2(bumpMatrix * vec4(uv, 1.0, 0.0));
+	}
+	else
+	{
+		vBumpUV = vec2(bumpMatrix * vec4(uv2, 1.0, 0.0));
+	}
+#endif
+
 	// Clip plane
 #ifdef CLIPPLANE
 		fClipDistance = dot(worldPos, vClipPlane);

+ 4 - 0
Babylon/Tools/babylon.sceneLoader.js

@@ -101,6 +101,10 @@
         if (parsedMaterial.specularTexture) {
             material.specularTexture = loadTexture(rootUrl, parsedMaterial.specularTexture, scene);
         }
+        
+        if (parsedMaterial.bumpTexture) {
+            material.bumpTexture = loadTexture(rootUrl, parsedMaterial.bumpTexture, scene);
+        }
 
         return material;
     };

+ 25 - 3
Babylon/babylon.engine.js

@@ -37,6 +37,10 @@
         this._caps.maxCubemapTextureSize = this._gl.getParameter(this._gl.MAX_CUBE_MAP_TEXTURE_SIZE);
         this._caps.maxRenderTextureSize = this._gl.getParameter(this._gl.MAX_RENDERBUFFER_SIZE);
 
+        // Extensions
+        var derivatives = this._gl.getExtension('OES_standard_derivatives');
+        this._caps.standardDerivatives = (derivatives !== undefined);
+
         // Cache
         this._loadedTexturesCache = [];
         this._activeTexturesCache = [];
@@ -326,9 +330,9 @@
         for (var index = 0; index < attributesNames.length; index++) {
             try {
                 results.push(this._gl.getAttribLocation(shaderProgram, attributesNames[index]));
-            } catch(e) {
+            } catch (e) {
                 results.push(-1);
-            } 
+            }
         }
 
         return results;
@@ -418,7 +422,7 @@
             this._currentState.culling = culling;
         }
     };
-    
+
     BABYLON.Engine.prototype.setDepthBuffer = function (enable) {
         if (enable) {
             this._gl.enable(this._gl.DEPTH_TEST);
@@ -579,6 +583,18 @@
         texture.isReady = true;
     };
 
+    BABYLON.Engine.prototype.updateVideoTexture = function (texture, video) {
+        this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
+        this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, false);
+        this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, video);
+        if (!texture.noMipmap) {
+            this._gl.generateMipmap(this._gl.TEXTURE_2D);
+        }
+        this._gl.bindTexture(this._gl.TEXTURE_2D, null);
+        this._activeTexturesCache = [];
+        texture.isReady = true;
+    };
+
     BABYLON.Engine.prototype.createRenderTargetTexture = function (size, generateMipMaps) {
         var gl = this._gl;
 
@@ -735,6 +751,12 @@
             return;
         }
 
+        if (texture instanceof BABYLON.VideoTexture) {
+            if (texture._update()) {
+                this._activeTexturesCache[channel] = null;
+            }
+        }
+
         if (this._activeTexturesCache[channel] == texture) {
             return;
         }

+ 4 - 1
Exporters/Blender/io_export_babylon.py

@@ -227,7 +227,10 @@ class Export_babylon(bpy.types.Operator, ExportHelper):
 						Export_babylon.export_texture("reflectionTexture", mtex.diffuse_color_factor, mtex, scene, file_handler, filepath)
 					if mtex.use_map_emit:
 						# Emissive
-						Export_babylon.export_texture("emissiveTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)						
+						Export_babylon.export_texture("emissiveTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)		
+					if mtex.use_map_normal:
+						# Bump
+						Export_babylon.export_texture("bumpTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)							
 		
 		file_handler.write("}")			
 	

+ 6 - 2
readme.md

@@ -4,7 +4,8 @@
 
 Babylon.js is a webgl / javascript 3D engine. It supports the following features: 
 - Complete scene graph with lights, cameras, materials and meshes
-- Standard material is a per pixel material that supports: ◦Diffuse lightning and texture
+- Standard material is a per pixel material that supports:
+ - Diffuse lightning and texture
  - Ambient lightning and texture
  - Specular lightning
  - Opacity texture
@@ -12,9 +13,11 @@ Babylon.js is a webgl / javascript 3D engine. It supports the following features
  - Mirror texture
  - Emissive texture
  - Specular texture
+ - Bump texture (Normal map)
  - Up to 4 lights (points, directionals, spots, hemispherics)
 - Render target textures
 - Dynamic textures (canvas)
+- Video textures
 - Custom materials
 - Alpha blending
 - Alpha testing
@@ -28,7 +31,8 @@ Babylon.js is a webgl / javascript 3D engine. It supports the following features
 - Frustum clipping
 - Sub-meshes clipping
 - Fullscreen mode
-- Babylon file format is a JSON file that can be produced from: ◦.OBJ
+- Babylon file format is a JSON file that can be produced from:
+ - .OBJ
  - .FBX
  - .MXB
  - Blender

+ 3 - 0
what's new.txt

@@ -1,3 +1,6 @@
+1.0.3:
+ - Video textures
+ - Normal map (bump) 
 1.0.2:
  - Spot lights
  - Hemispheric lights