瀏覽代碼

WebGLDeferredRenderer: merged @MPanknin's area lights.

To be continued ...

todo:
- optimize vectors that don't need to be computed in shaders
- use material albedo
- add specular term
- wrapAround lighting (if possible)
- make attenuation parameters uniforms or defines instead of hardcoding them
- this is not using surface normal anywhere, this can't be right?
- maybe some box proxy instead of full-screen quad

See #2624
alteredq 12 年之前
父節點
當前提交
cd92495139

+ 19 - 0
build/three.js

@@ -7957,6 +7957,25 @@ THREE.AmbientLight = function ( hex ) {
 };
 
 THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
+/**
+ * @author MPanknin / http://www.redplant.de/
+ */
+
+THREE.AreaLight = function ( hex ) {
+
+	THREE.Light.call( this, hex );
+
+	this.normal = new THREE.Vector3( 0, -1, 0 );
+	this.right = new THREE.Vector3( 1, 0, 0 );
+
+	this.intensity = 1.0;
+	this.width = 1.0;
+	this.height = 1.0;
+
+};
+
+THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
+
 /**
  * @author mrdoob / http://mrdoob.com/
  * @author alteredq / http://alteredqualia.com/

+ 1 - 1
build/three.min.js

@@ -162,7 +162,7 @@ this.attributes.uv)console.warn("Missing required attributes (index, position, n
 var n,p,m,r,s,l,q,u,B,x,t,F,C,z,A,f=new THREE.Vector3,g=new THREE.Vector3,H,G,I,$,D,L,y,K=this.offsets;I=0;for($=K.length;I<$;++I){G=K[I].start;D=K[I].count;var J=K[I].index;H=G;for(G+=D;H<G;H+=3)D=J+b[H],L=J+b[H+1],y=J+b[H+2],n=c[3*D],p=c[3*D+1],m=c[3*D+2],r=c[3*L],s=c[3*L+1],l=c[3*L+2],q=c[3*y],u=c[3*y+1],B=c[3*y+2],x=e[2*D],t=e[2*D+1],F=e[2*L],C=e[2*L+1],z=e[2*y],A=e[2*y+1],r-=n,n=q-n,s-=p,p=u-p,l-=m,m=B-m,F-=x,x=z-x,C-=t,t=A-t,A=1/(F*t-x*C),f.set((t*r-C*n)*A,(t*s-C*p)*A,(t*l-C*m)*A),g.set((F*
 n-x*r)*A,(F*p-x*s)*A,(F*m-x*l)*A),i[D].addSelf(f),i[L].addSelf(f),i[y].addSelf(f),k[D].addSelf(g),k[L].addSelf(g),k[y].addSelf(g)}var R=new THREE.Vector3,P=new THREE.Vector3,ca=new THREE.Vector3,xa=new THREE.Vector3,M,pa,ya;I=0;for($=K.length;I<$;++I){G=K[I].start;D=K[I].count;J=K[I].index;H=G;for(G+=D;H<G;H+=3)D=J+b[H],L=J+b[H+1],y=J+b[H+2],a(D),a(L),a(y)}this.tangentsNeedUpdate=this.hasTangents=!0}},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.Camera=function(){THREE.Object3D.call(this);this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4;this.projectionMatrixInverse=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.lookAt=function(a){this.matrix.lookAt(this.position,a,this.up);!0===this.rotationAutoUpdate&&(!1===this.useQuaternion?this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder):this.quaternion.copy(this.matrix.decompose()[1]))};THREE.OrthographicCamera=function(a,b,c,d,e,f){THREE.Camera.call(this);this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:0.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=Object.create(THREE.Camera.prototype);THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix.makeOrthographic(this.left,this.right,this.top,this.bottom,this.near,this.far)};THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:0.1;this.far=void 0!==d?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=Object.create(THREE.Camera.prototype);THREE.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);this.fov=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.updateProjectionMatrix()};
 THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=e;this.height=f;this.updateProjectionMatrix()};
-THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(THREE.Math.degToRad(0.5*this.fov))*this.near,c=-b,d=a*c,a=Math.abs(a*b-d),c=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*a/this.fullWidth,d+(this.x+this.width)*a/this.fullWidth,b-(this.y+this.height)*c/this.fullHeight,b-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far)};THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=!1;this.shadowCascadeOffset=
+THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(THREE.Math.degToRad(0.5*this.fov))*this.near,c=-b,d=a*c,a=Math.abs(a*b-d),c=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*a/this.fullWidth,d+(this.x+this.width)*a/this.fullWidth,b-(this.y+this.height)*c/this.fullHeight,b-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far)};THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.AreaLight=function(a){THREE.Light.call(this,a);this.normal=new THREE.Vector3(0,-1,0);this.right=new THREE.Vector3(1,0,0);this.height=this.width=this.intensity=1};THREE.AreaLight.prototype=Object.create(THREE.Light.prototype);THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=!1;this.shadowCascadeOffset=
 new THREE.Vector3(0,0,-1E3);this.shadowCascadeCount=2;this.shadowCascadeBias=[0,0,0];this.shadowCascadeWidth=[512,512,512];this.shadowCascadeHeight=[512,512,512];this.shadowCascadeNearZ=[-1,0.99,0.998];this.shadowCascadeFarZ=[0.99,0.998,1];this.shadowCascadeArray=[];this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.DirectionalLight.prototype=Object.create(THREE.Light.prototype);THREE.HemisphereLight=function(a,b,c){THREE.Light.call(this,a);this.groundColor=new THREE.Color(b);this.position=new THREE.Vector3(0,100,0);this.intensity=void 0!==c?c:1};THREE.HemisphereLight.prototype=Object.create(THREE.Light.prototype);THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,0,0);this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0};THREE.PointLight.prototype=Object.create(THREE.Light.prototype);THREE.SpotLight=function(a,b,c,d,e){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/2;this.exponent=void 0!==e?e:10;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowMatrix=this.shadowCamera=
 this.shadowMapSize=this.shadowMap=null};THREE.SpotLight.prototype=Object.create(THREE.Light.prototype);THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}};
 THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:"anonymous",addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/

+ 142 - 2
examples/js/ShaderDeferred.js

@@ -583,8 +583,8 @@ THREE.ShaderDeferred = {
 			"uniform float viewHeight;",
 			"uniform float viewWidth;",
 
-		    "uniform float lightAngle;"+
-			"uniform float lightIntensity;"+
+			"uniform float lightAngle;",
+			"uniform float lightIntensity;",
 			"uniform vec3 lightColor;",
 
 			"uniform mat4 matProjInverse;",
@@ -824,6 +824,146 @@ THREE.ShaderDeferred = {
 
 	},
 
+	"areaLight" : {
+
+		uniforms: {
+
+			samplerNormalDepth: { type: "t", value: null },
+			samplerColor: 		{ type: "t", value: null },
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+			matView: 		{ type: "m4", value: new THREE.Matrix4() },
+			viewWidth: 		{ type: "f", value: 800 },
+			viewHeight: 	{ type: "f", value: 600 },
+
+			lightPosition:  { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightColor: 	{ type: "c", value: new THREE.Color( 0x000000 ) },
+			lightIntensity: { type: "f", value: 1.0 },
+
+			lightRight:  { type: "v3", value: new THREE.Vector3( 1, 0, 0 ) },
+			lightNormal: { type: "v3", value: new THREE.Vector3( 0, -1, 0 ) },
+
+			lightWidth: { type: "f", value: 1.0 },
+			lightHeight: { type: "f", value: 1.0 }
+
+		},
+
+		fragmentShader : [
+
+			"varying vec3 lightPosVS;",
+			"varying vec3 lightNormalVS;",
+			"varying vec3 lightRightVS;",
+
+			"uniform sampler2D samplerColor;",
+			"uniform sampler2D samplerNormalDepth;",
+
+			"uniform float lightWidth;",
+			"uniform float lightHeight;",
+
+			"uniform float lightIntensity;",
+			"uniform vec3 lightColor;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"vec3 projectOnPlane( vec3 point, vec3 planeCenter, vec3 planeNorm ) {",
+
+				"return point - dot( point - planeCenter, planeNorm ) * planeNorm;",
+
+			"}",
+
+			"bool sideOfPlane( vec3 point, vec3 planeCenter, vec3 planeNorm ) {",
+
+				"return ( dot( point - planeCenter, planeNorm ) >= 0.0 );",
+
+			"}",
+
+			"vec3 linePlaneIntersect( vec3 lp, vec3 lv, vec3 pc, vec3 pn ) {",
+
+				"return lp + lv * ( dot( pn, pc - lp ) / dot( pn, lv ) );",
+
+			"}",
+
+			"float calculateAttenuation( float dist ) {",
+
+				"float constAtten = 1.5;",
+				"float linAtten = 0.5;",
+				"float quadAtten = 0.1;",
+				"return ( 1.0 / ( constAtten + linAtten * dist + quadAtten * dist * dist ) );",
+
+			"}",
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+				THREE.DeferredShaderChunk[ "computeNormal" ],
+				THREE.DeferredShaderChunk[ "unpackColorMap" ],
+
+				"float w = lightWidth;",
+				"float h = lightHeight;",
+
+				"vec3 lightUpVS = normalize( cross( lightRightVS, lightNormalVS ) );",
+				"vec3 proj = projectOnPlane( vertexPositionVS.xyz, lightPosVS, lightNormalVS );",
+				"vec3 dir = proj - lightPosVS;",
+
+				"vec2 diagonal = vec2( dot( dir, lightRightVS ), dot( dir, lightUpVS ) );",
+				"vec2 nearest2D = vec2( clamp( diagonal.x, -w, w ), clamp( diagonal.y, -h, h ) );",
+				"vec3 nearestPointInside = vec3( lightPosVS ) + ( lightRightVS * nearest2D.x + lightUpVS * nearest2D.y );",
+
+				"float dist = distance( vertexPositionVS.xyz, nearestPointInside );",
+				"float attenuation = calculateAttenuation( dist );",
+
+				"vec3 lightDir = normalize( nearestPointInside - vertexPositionVS.xyz );",
+				"vec3 color = vec3( 0.0 );",
+
+				"float NdotL = dot( lightNormalVS, -lightDir );",
+
+				"if ( NdotL != 0.0 && sideOfPlane( vertexPositionVS.xyz, lightPosVS, lightNormalVS ) ) {",
+
+					"color.xyz = vec3( lightColor * attenuation * NdotL * 1.5 );",
+
+				"} else {",
+
+					"color.xyz = vec3( 0.0 );",
+
+				"}",
+
+				"gl_FragColor = vec4( color, 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+		"varying vec3 lightPosVS;",
+		"varying vec3 lightNormalVS;",
+		"varying vec3 lightRightVS;",
+
+		"uniform vec3 lightPosition;",
+		"uniform vec3 lightNormal;",
+		"uniform vec3 lightRight;",
+
+		"uniform mat4 matView;",
+
+		"void main() {",
+
+			"vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );",
+			"gl_Position = pos;",
+
+			"lightNormalVS = normalize( mat3( matView ) * lightNormal );",
+			"lightRightVS = normalize( mat3( matView ) * lightRight ); ",
+			"lightPosVS = vec3( matView * vec4( lightPosition, 1.0 ) );",
+
+		 "}"
+
+		].join("\n")
+
+	},
+
 	"emissiveLight" : {
 
 		uniforms: {

+ 108 - 21
examples/js/renderers/WebGLDeferredRenderer.js

@@ -40,6 +40,9 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	var positionVS = new THREE.Vector3();
 	var directionVS = new THREE.Vector3();
 
+	var right = new THREE.Vector3();
+	var normal = new THREE.Vector3();
+
 	//
 
 	var geometryLightSphere = new THREE.SphereGeometry( 1, 16, 8 );
@@ -57,6 +60,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	var spotLightShader = THREE.ShaderDeferred[ "spotLight" ];
 	var directionalLightShader = THREE.ShaderDeferred[ "directionalLight" ];
 	var hemisphereLightShader = THREE.ShaderDeferred[ "hemisphereLight" ];
+	var areaLightShader = THREE.ShaderDeferred[ "areaLight" ];
 
 	var compositeShader = THREE.ShaderDeferred[ "composite" ];
 
@@ -612,6 +616,80 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	};
 
+	var updateAreaLightProxy = function ( lightProxy ) {
+
+		var light = lightProxy.properties.originalLight;
+		var uniforms = lightProxy.material.uniforms;
+
+		uniforms[ "lightPosition" ].value.copy( light.matrixWorld.getPosition() );
+
+		var matrix = light.matrixWorld;
+
+		right.copy( light.right );
+		normal.copy( light.normal );
+		matrix.rotateAxis( right );
+		matrix.rotateAxis( normal );
+
+		uniforms[ "lightRight" ].value.copy( right );
+		uniforms[ "lightNormal" ].value.copy( normal );
+
+		uniforms[ "lightWidth" ].value = light.width;
+		uniforms[ "lightHeight" ].value = light.height;
+
+		// linear space colors
+
+		var intensity = light.intensity * light.intensity;
+
+		uniforms[ "lightIntensity" ].value = intensity;
+		uniforms[ "lightColor" ].value.copyGammaToLinear( light.color );
+
+	};
+
+	var createDeferredAreaLight = function ( light ) {
+
+		// setup light material
+
+		var uniforms = THREE.UniformsUtils.clone( areaLightShader.uniforms );
+
+		var materialLight = new THREE.ShaderMaterial( {
+
+			uniforms:       uniforms,
+			vertexShader:   areaLightShader.vertexShader,
+			fragmentShader: areaLightShader.fragmentShader,
+
+			blending:		THREE.AdditiveBlending,
+			depthWrite:		false,
+			depthTest:		false,
+			transparent:	true
+
+		} );
+
+		uniforms[ "viewWidth" ].value = scaledWidth;
+		uniforms[ "viewHeight" ].value = scaledHeight;
+
+		uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
+		uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
+
+		// create light proxy mesh
+
+		var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
+
+		// keep reference for color and intensity updates
+
+		meshLight.properties.originalLight = light;
+
+		// keep reference for size reset
+
+		resizableMaterials.push( materialLight );
+
+		// sync proxy uniforms to the original light
+
+		updateAreaLightProxy( meshLight );
+
+		return meshLight;
+
+	};
+
 	var createDeferredEmissiveLight = function () {
 
 		// setup light material
@@ -652,32 +730,37 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		if ( object instanceof THREE.PointLight ) {
 
-			var meshLight = createDeferredPointLight( object );
+			var proxy = createDeferredPointLight( object );
 
 			if ( object.distance > 0 ) {
 
-				lightSceneProxy.add( meshLight );
+				lightSceneProxy.add( proxy );
 
 			} else {
 
-				lightSceneFullscreen.add( meshLight );
+				lightSceneFullscreen.add( proxy );
 
 			}
 
 		} else if ( object instanceof THREE.SpotLight ) {
 
-			var meshLight = createDeferredSpotLight( object );
-			lightSceneFullscreen.add( meshLight );
+			var proxy = createDeferredSpotLight( object );
+			lightSceneFullscreen.add( proxy );
 
 		} else if ( object instanceof THREE.DirectionalLight ) {
 
-			var meshLight = createDeferredDirectionalLight( object );
-			lightSceneFullscreen.add( meshLight );
+			var proxy = createDeferredDirectionalLight( object );
+			lightSceneFullscreen.add( proxy );
 
 		} else if ( object instanceof THREE.HemisphereLight ) {
 
-			var meshLight = createDeferredHemisphereLight( object );
-			lightSceneFullscreen.add( meshLight );
+			var proxy = createDeferredHemisphereLight( object );
+			lightSceneFullscreen.add( proxy );
+
+		} else if ( object instanceof THREE.AreaLight ) {
+
+			var proxy = createDeferredAreaLight( object );
+			lightSceneFullscreen.add( proxy );
 
 		}
 
@@ -794,34 +877,38 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	//
 
-	function updateLightProxy ( lightProxy, camera ) {
+	function updateLightProxy ( proxy, camera ) {
 
-		var uniforms = lightProxy.material.uniforms;
+		var uniforms = proxy.material.uniforms;
 
 		if ( uniforms[ "matProjInverse" ] ) uniforms[ "matProjInverse" ].value = camera.projectionMatrixInverse;
 		if ( uniforms[ "matView" ] ) uniforms[ "matView" ].value = camera.matrixWorldInverse;
 
-		var originalLight = lightProxy.properties.originalLight;
+		var originalLight = proxy.properties.originalLight;
 
 		if ( originalLight ) {
 
-			lightProxy.visible = originalLight.visible;
+			proxy.visible = originalLight.visible;
 
 			if ( originalLight instanceof THREE.PointLight ) {
 
-				updatePointLightProxy( lightProxy );
+				updatePointLightProxy( proxy );
 
 			} else if ( originalLight instanceof THREE.SpotLight ) {
 
-				updateSpotLightProxy( lightProxy );
+				updateSpotLightProxy( proxy );
 
 			} else if ( originalLight instanceof THREE.DirectionalLight ) {
 
-				updateDirectionalLightProxy( lightProxy );
+				updateDirectionalLightProxy( proxy );
 
 			} else if ( originalLight instanceof THREE.HemisphereLight ) {
 
-				updateHemisphereLightProxy( lightProxy );
+				updateHemisphereLightProxy( proxy );
+
+			} else if ( originalLight instanceof THREE.AreaLight ) {
+
+				updateAreaLightProxy( proxy );
 
 			}
 
@@ -918,15 +1005,15 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		for ( var i = 0, il = lightSceneProxy.children.length; i < il; i ++ ) {
 
-			var lightProxy = lightSceneProxy.children[ i ];
-			updateLightProxy( lightProxy, camera );
+			var proxy = lightSceneProxy.children[ i ];
+			updateLightProxy( proxy, camera );
 
 		}
 
 		for ( var i = 0, il = lightSceneFullscreen.children.length; i < il; i ++ ) {
 
-			var lightProxy = lightSceneFullscreen.children[ i ];
-			updateLightProxy( lightProxy, camera );
+			var proxy = lightSceneFullscreen.children[ i ];
+			updateLightProxy( proxy, camera );
 
 		}
 

二進制
examples/obj/box/box.bin


+ 29 - 0
examples/obj/box/box.js

@@ -0,0 +1,29 @@
+{
+
+    "metadata" :
+    {
+        "formatVersion" : 3.1,
+        "sourceFile"    : "box.obj",
+        "generatedBy"   : "OBJConverter",
+        "vertices"      : 36,
+        "faces"         : 25,
+        "normals"       : 8,
+        "uvs"           : 0,
+        "materials"     : 1
+    },
+
+    "materials": [	{
+	"DbgColor" : 15658734,
+	"DbgIndex" : 0,
+	"DbgName" : "",
+	"colorAmbient" : [0.0, 0.0, 0.0],
+	"colorDiffuse" : [0.8, 0.8, 0.8],
+	"colorSpecular" : [0.8, 0.8, 0.8],
+	"illumination" : 2,
+	"specularCoef" : 0.0,
+	"transparency" : 1.0
+	}],
+
+    "buffers": "box.bin"
+
+}

+ 302 - 0
examples/webgl_lights_deferred_arealights.html

@@ -0,0 +1,302 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js webgl - deferred rendering</title>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background-color: #000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 20px; width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+			}
+
+			a {
+				color: #ff0080;
+				text-decoration: none;
+			}
+
+			a:hover {
+				color: #0080ff;
+			}
+
+			#stats { position: absolute; top:10px; left: 5px }
+			#stats #fps { background: transparent !important }
+			#stats #fps #fpsText { color: #aaa !important }
+			#stats #fps #fpsGraph { display: none }
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> - deferred area lights WebGL demo by <a href="http://de.redplant.de" target=_blank>redPlant</a> -
+			based on <a href="http://www.gamedev.net/topic/552315-glsl-area-light-implementation/" target=_blank>ArKano22's</a> glsl implementation
+		</div>
+		<div id="container"></div>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script src="js/renderers/WebGLDeferredRenderer.js"></script>
+		<script src="js/ShaderDeferred.js"></script>
+
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/FXAAShader.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var SCALE = 1;
+			var MARGIN = 100;
+
+			var WIDTH = window.innerWidth;
+			var HEIGHT = window.innerHeight - 2 * MARGIN;
+
+			var NEAR = 1.0, FAR = 350.0;
+			var VIEW_ANGLE = 40;
+
+			// controls
+
+			var mouseX = 0;
+			var mouseY = 0;
+
+			var targetX = 0, targetY = 0;
+			var angle = 0;
+			var target = new THREE.Vector3( 0, 0, 0 );
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			// core
+
+			var renderer, camera, scene, stats, clock;
+
+			// lights
+
+			var numLights = 50;
+			var lights = [];
+
+			//
+
+			init();
+			animate();
+
+			// -----------------------------
+
+			function init() {
+
+				// renderer
+
+				renderer = new THREE.WebGLDeferredRenderer( { width: WIDTH, height: HEIGHT, scale: SCALE, antialias: true } );
+
+				renderer.domElement.style.position = "absolute";
+				renderer.domElement.style.top = MARGIN + "px";
+				renderer.domElement.style.left = "0px";
+
+				var container = document.getElementById( 'container' );
+				container.appendChild( renderer.domElement );
+
+				// camera
+
+				camera = new THREE.PerspectiveCamera( VIEW_ANGLE, WIDTH / HEIGHT, NEAR, FAR );
+				camera.position.y = 40;
+
+				// scene
+
+				scene = new THREE.Scene();
+				scene.add( camera );
+
+				// stats
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '8px';
+				stats.domElement.style.zIndex = 100;
+				container.appendChild( stats.domElement );
+
+				// clock
+
+				clock = new THREE.Clock();
+
+				// add lights
+
+				initLights();
+
+				// add objects
+
+				initObjects();
+
+				// events
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			// -----------------------------
+
+			function createAreaEmitter( light ) {
+
+				var geometry = new THREE.CubeGeometry( 1, 1, 1 );
+				var material = new THREE.MeshBasicMaterial( { color: light.color.getHex() } );
+
+				var emitter = new THREE.Mesh( geometry, material );
+
+				emitter.position = light.position;
+				emitter.rotation = light.rotation;
+				emitter.scale.set( light.width * 2, 0.2, light.height * 2 );
+
+				return emitter;
+
+			}
+
+			function setupAreaLight( light ) {
+
+				var matrix = light.matrixWorld;
+
+				light.right.set( 1, 0, 0 );
+				light.normal.set( 0, -1, 0 );
+				light.right = matrix.multiplyVector3( light.right );
+				light.normal = matrix.multiplyVector3( light.normal );
+
+			}
+
+			function initLights() {
+
+				var areaLight1 = new THREE.AreaLight( 0xffffff );
+				areaLight1.position.set( 0.0001, 10.0001, -19.5001 );
+				areaLight1.rotation.set( -0.74719, 0.0001, 0.0001 );
+				areaLight1.width = 10;
+				areaLight1.height = 1;
+
+				scene.add( areaLight1 );
+
+				var meshEmitter = createAreaEmitter( areaLight1 );
+				scene.add( meshEmitter );
+
+				//
+
+				var areaLight2 = new THREE.AreaLight( 0x00ff00 );
+				areaLight2.position.set( -19.0001, 3.0001, 0.0001 );
+				areaLight2.rotation.set( -1.5707, 0.0001, 1.5707 );
+				areaLight2.width = 8;
+				areaLight2.height = 1;
+
+				scene.add( areaLight2 );
+
+				var meshEmitter = createAreaEmitter( areaLight2 );
+				scene.add( meshEmitter );
+
+				//
+
+				var areaLight3 = new THREE.AreaLight( 0x0000ff );
+				areaLight3.position.set( 19.0001, 3.0001, 0.0001 );
+				areaLight3.rotation.set( 1.5707, 0.0001, -1.5707 );
+				areaLight3.width = 8;
+				areaLight3.height = 1;
+
+				scene.add( areaLight3 );
+
+				var meshEmitter = createAreaEmitter( areaLight3 );
+				scene.add( meshEmitter );
+
+			}
+
+			// -----------------------------
+
+			function initObjects() {
+
+				var loader = new THREE.BinaryLoader();
+				loader.load( "obj/box/box.js", function( geometry, materials ) {
+
+					var object = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( ) );
+					object.position.x = 0;
+					object.position.y = 0;
+					object.scale.multiplyScalar( 2 );
+					scene.add( object );
+
+				} );
+
+			}
+
+
+			// -----------------------------
+
+			function onWindowResize( event ) {
+
+				windowHalfX = window.innerWidth / 2;
+				windowHalfY = window.innerHeight / 2;
+
+				WIDTH = window.innerWidth;
+				HEIGHT = window.innerHeight - 2 * MARGIN;
+
+				renderer.setSize( WIDTH, HEIGHT );
+
+				camera.aspect = WIDTH / HEIGHT;
+				camera.updateProjectionMatrix();
+
+			}
+
+			function onDocumentMouseMove( event ) {
+
+				mouseX = ( event.clientX - windowHalfX ) * 1;
+				mouseY = ( event.clientY - windowHalfY ) * 1;
+
+			}
+
+			// -----------------------------
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				// update camera
+
+				var delta = clock.getDelta();
+
+				targetX = mouseX * .001;
+				targetY = mouseY * .001;
+
+				angle += 0.05 * ( targetX - angle );
+
+				camera.position.x = -Math.sin( angle ) * 40;
+				camera.position.z =  Math.cos( angle ) * 40;
+
+				camera.lookAt( target );
+
+				// render
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+
+</html>

+ 1 - 0
utils/includes/common.json

@@ -32,6 +32,7 @@
 	"../src/cameras/PerspectiveCamera.js",
 	"../src/lights/Light.js",
 	"../src/lights/AmbientLight.js",
+	"../src/lights/AreaLight.js",
 	"../src/lights/DirectionalLight.js",
 	"../src/lights/HemisphereLight.js",
 	"../src/lights/PointLight.js",