소스 검색

adopt attenuation equation discussed here: https://github.com/mrdoob/three.js/pull/5787#issuecomment-68066541 Also apply attenuation formula to example shaders.

Ben Houston 10 년 전
부모
커밋
b323f3bd7d

+ 18 - 17
examples/js/ShaderSkin.js

@@ -105,11 +105,13 @@ THREE.ShaderSkin = {
 				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];",
 
 			"#endif",
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
@@ -201,11 +203,8 @@ THREE.ShaderSkin = {
 						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
 
 						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+	
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );",
 
 						"lVector = normalize( lVector );",
 
@@ -215,8 +214,8 @@ THREE.ShaderSkin = {
 
 						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
 
-						"pointTotal    += lDistance * diffuse * pointLightColor[ i ] * pointDiffuseWeight;",
-						"specularTotal += lDistance * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
+						"pointTotal    += attenuation * diffuse * pointLightColor[ i ] * pointDiffuseWeight;",
+						"specularTotal += attenuation * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
 
 					"}",
 
@@ -314,6 +313,7 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
 
 			"void main() {",
@@ -430,6 +430,7 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 
 			"float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",
@@ -632,6 +633,7 @@ THREE.ShaderSkin = {
 
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];",
 
 				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
 
@@ -639,6 +641,8 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
+
 			"void main() {",
 
 				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
@@ -668,14 +672,11 @@ THREE.ShaderSkin = {
 
 						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
 
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );",
 
 						"lVector = normalize( lVector );",
 
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
+						"vPointLight[ i ] = vec4( lVector, attenuation );",
 
 					"}",
 
@@ -721,6 +722,7 @@ THREE.ShaderSkin = {
 
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];",
 
 				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
 
@@ -728,6 +730,8 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
+
 			"void main() {",
 
 				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
@@ -757,14 +761,11 @@ THREE.ShaderSkin = {
 
 						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
 
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );",
 
 						"lVector = normalize( lVector );",
 
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
+						"vPointLight[ i ] = vec4( lVector, attenuation );",
 
 					"}",
 

+ 4 - 6
examples/js/ShaderTerrain.js

@@ -108,6 +108,7 @@ THREE.ShaderTerrain = {
 				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];",
 
 			"#endif",
 
@@ -174,22 +175,19 @@ THREE.ShaderTerrain = {
 						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
 						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
 
-						"float lDistance = 1.0;",
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );"
 
 						"lVector = normalize( lVector );",
 
 						"vec3 pointHalfVector = normalize( lVector + viewPosition );",
-						"float pointDistance = lDistance;",
 
 						"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
 						"float pointDiffuseWeight = max( dot( normal, lVector ), 0.0 );",
 
 						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
 
-						"pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
-						"pointSpecular += pointDistance * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
+						"pointDiffuse += attenuation * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
+						"pointSpecular += attenuation * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
 
 					"}",
 

+ 3 - 2
src/renderers/WebGLRenderer.js

@@ -5304,8 +5304,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 				pointPositions[ pointOffset + 1 ] = _vector3.y;
 				pointPositions[ pointOffset + 2 ] = _vector3.z;
 
+				// distance is 0 if decayExponent is 0, because there is no attenuation at all.
 				pointDistances[ pointLength ] = distance;
-				pointDecayExponents[ pointLength ] = light.decayExponent;
+				pointDecayExponents[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decayExponent;
 
 				pointLength += 1;
 
@@ -5345,7 +5346,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				spotAnglesCos[ spotLength ] = Math.cos( light.angle );
 				spotExponents[ spotLength ] = light.exponent;
-				spotDecayExponents[ pointLength ] = light.decayExponent;
+				spotDecayExponents[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decayExponent;
 
 				spotLength += 1;
 

+ 12 - 9
src/renderers/shaders/ShaderChunk/common.glsl

@@ -14,14 +14,18 @@ vec3  saturate( in vec3 a )  { return clamp( a, 0.0, 1.0 ); }
 vec4  saturate( in vec4 a )  { return clamp( a, 0.0, 1.0 ); }
 float average( in float a ) { return a; }
 float average( in vec2 a )  { return ( a.x + a.y) * 0.5; }
-float average( in vec3 a )  { return ( a.x + a.y + a.z) * 0.3333333333; }
+float average( in vec3 a )  { return ( a.x + a.y + a.z) / 3.0; }
 float average( in vec4 a )  { return ( a.x + a.y + a.z + a.w) * 0.25; }
 float whiteCompliment( in float a ) { return saturate( 1.0 - a ); }
 vec2  whiteCompliment( in vec2 a )  { return saturate( vec2(1.0) - a ); }
 vec3  whiteCompliment( in vec3 a )  { return saturate( vec3(1.0) - a ); }
 vec4  whiteCompliment( in vec4 a )  { return saturate( vec4(1.0) - a ); }
-vec3 transformNormal( in vec3 normal, in mat4 matrix ) {
-	return normalize( ( viewMatrix * vec4( normal, 0.0 ) ).xyz );
+vec3 transformDirection( in vec3 normal, in mat4 matrix ) {
+	return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );
+}
+// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations
+vec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {
+	return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );
 }
 vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {
 	float distance = dot( planeNormal, point-pointOnPlane );
@@ -33,11 +37,10 @@ float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
 vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {
 	return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );
 }
-// standard exponential distance attenuation multiplied by a linear distance cutoff, if cutoffDistance > 0.
 float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {
-	float distanceAttenuation = 1.0 / pow( lightDistance, decayExponent );
-	if ( cutoffDistance > 0.0 ) {
-		distanceAttenuation *= 1.0 - min( lightDistance / cutoffDistance, 1.0 );
+	if ( decayExponent > 0.0 ) {
+	  return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );
 	}
-	return distanceAttenuation;
-}
+	return 1.0;
+}
+

+ 2 - 4
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl

@@ -4,10 +4,8 @@
 
 		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );
 
-		// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations
 		// Transforming Normal Vectors with the Inverse Transformation
-
-		vec3 worldNormal = transformNormal( normal, viewMatrix );
+		vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );
 
 		#ifdef ENVMAP_MODE_REFLECTION
 
@@ -41,7 +39,7 @@
 		vec4 envColor = texture2D( envMap, sampleUV );
 		
 	#elif defined( ENVMAP_TYPE_SPHERE )
-		vec3 reflectView = flipNormal * ( transformNormal( reflectVec, viewMatrix ) + vec3(0.0,0.0,1.0) );
+		vec3 reflectView = flipNormal * ( transformDirection( reflectVec, viewMatrix ) + vec3(0.0,0.0,1.0) );
 		vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );
 	#endif
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/envmap_vertex.glsl

@@ -1,6 +1,6 @@
 #if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )
 
-	vec3 worldNormal = transformNormal( objectNormal, modelMatrix );
+	vec3 worldNormal = transformDirection( objectNormal, modelMatrix );
 
 	vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl

@@ -24,7 +24,7 @@ uniform vec3 ambientLightColor;
 	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];
 	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];
 	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];
-	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];
+	uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];
 
 #endif
 

+ 8 - 8
src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl

@@ -12,7 +12,7 @@ transformedNormal = normalize( transformedNormal );
 
 for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
-	vec3 dirVector = transformNormal( directionalLightDirection[ i ], viewMatrix );
+	vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );
 
 	float dotProduct = dot( transformedNormal, dirVector );
 	vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );
@@ -61,7 +61,7 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );
 		vec3 lVector = lPosition.xyz - mvPosition.xyz;
 
-		float lDistance = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );
+		float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );
 
 		lVector = normalize( lVector );
 		float dotProduct = dot( transformedNormal, lVector );
@@ -93,11 +93,11 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 		#endif
 
-		vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;
+		vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;
 
 		#ifdef DOUBLE_SIDED
 
-			vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;
+			vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;
 
 		#endif
 
@@ -118,7 +118,7 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );
 
-			float lDistance = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );
+			float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );
 
 			lVector = normalize( lVector );
 
@@ -150,11 +150,11 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 			#endif
 
-			vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;
+			vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;
 
 			#ifdef DOUBLE_SIDED
 
-				vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;
+				vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;
 
 			#endif
 
@@ -168,7 +168,7 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
 
-		vec3 lVector = transformNormal( hemisphereLightDirection[ i ], viewMatrix );
+		vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );
 
 		float dotProduct = dot( transformedNormal, lVector );
 

+ 8 - 8
src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl

@@ -27,7 +27,7 @@ vec3 viewPosition = normalize( vViewPosition );
 		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );
 		vec3 lVector = lPosition.xyz + vViewPosition.xyz;
 
-		float lDistance = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );
+		float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );
 
 		lVector = normalize( lVector );
 
@@ -48,7 +48,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		#endif
 
-		pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;
+		pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * attenuation;
 
 				// specular
 
@@ -59,7 +59,7 @@ vec3 viewPosition = normalize( vViewPosition );
 		float specularNormalization = ( shininess + 2.0 ) / 8.0;
 
 		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );
-		pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;
+		pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;
 
 	}
 
@@ -75,7 +75,7 @@ vec3 viewPosition = normalize( vViewPosition );
 		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );
 		vec3 lVector = lPosition.xyz + vViewPosition.xyz;
 
-		float lDistance = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );
+		float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );
 
 		lVector = normalize( lVector );
 
@@ -102,7 +102,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 			#endif
 
-			spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;
+			spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;
 
 					// specular
 
@@ -113,7 +113,7 @@ vec3 viewPosition = normalize( vViewPosition );
 			float specularNormalization = ( shininess + 2.0 ) / 8.0;
 
 			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );
-			spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;
+			spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;
 
 		}
 
@@ -128,7 +128,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
-		vec3 dirVector = transformNormal( directionalLightDirection[ i ], viewMatrix );
+		vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );
 
 				// diffuse
 
@@ -193,7 +193,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
 
-		vec3 lVector = transformNormal( hemisphereLightDirection[ i ], viewMatrix );
+		vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );
 
 		// diffuse
 

+ 4 - 4
src/renderers/shaders/ShaderLib.js

@@ -913,7 +913,7 @@ THREE.ShaderLib = {
 
 			"		for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-			"			vec3 dirVector = transformNormal( directionalLightDirection[ i ], viewMatrix );",
+			"			vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
 
 						// diffuse
 
@@ -956,7 +956,7 @@ THREE.ShaderLib = {
 
 			"		for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
-			"			vec3 lVector = transformNormal( hemisphereLightDirection[ i ], viewMatrix );",
+			"			vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );",
 
 						// diffuse
 
@@ -1234,7 +1234,7 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	vWorldPosition = transformNormal( position, modelMatrix );",
+			"	vWorldPosition = transformDirection( position, modelMatrix );",
 
 			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
 
@@ -1284,7 +1284,7 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	vWorldPosition = transformNormal( position, modelMatrix );",
+			"	vWorldPosition = transformDirection( position, modelMatrix );",
 
 			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",