Browse Source

Merge pull request #18915 from higharc/shadow-normal-offset

LightShadow: Add shadow map normal offset.
Mr.doob 5 years ago
parent
commit
2640a19341

+ 4 - 0
docs/api/en/lights/shadows/LightShadow.html

@@ -40,6 +40,10 @@
 			The default is 0. Very tiny adjustments here (in the order of 0.0001) may help reduce artefacts in shadows
 			The default is 0. Very tiny adjustments here (in the order of 0.0001) may help reduce artefacts in shadows
 		</p>
 		</p>
 
 
+		<h3>[property:Float normalOffset]</h3>
+		<p>Defines how much the position used to query the shadow map is offset along the object normal.</p>
+		<p>The default is 0. Increasing this value can be used to reduce shadow acne especially in large scenes where light shines onto geometry at a shallow angle. The cost is that shadows may appear distorted.</p>
+
 		<h3>[property:WebGLRenderTarget map]</h3>
 		<h3>[property:WebGLRenderTarget map]</h3>
 		<p>
 		<p>
 			The depth map generated using the internal camera; a location beyond a pixel's depth is
 			The depth map generated using the internal camera; a location beyond a pixel's depth is

+ 2 - 0
examples/jsm/objects/Water.js

@@ -122,6 +122,8 @@ var Water = function ( geometry, options ) {
 			'	vec4 mvPosition =  modelViewMatrix * vec4( position, 1.0 );',
 			'	vec4 mvPosition =  modelViewMatrix * vec4( position, 1.0 );',
 			'	gl_Position = projectionMatrix * mvPosition;',
 			'	gl_Position = projectionMatrix * mvPosition;',
 
 
+			'#include <beginnormal_vertex>',
+			'#include <defaultnormal_vertex>',
 			'#include <logdepthbuf_vertex>',
 			'#include <logdepthbuf_vertex>',
 			'#include <fog_vertex>',
 			'#include <fog_vertex>',
 			'#include <shadowmap_vertex>',
 			'#include <shadowmap_vertex>',

+ 1 - 0
src/lights/LightShadow.d.ts

@@ -11,6 +11,7 @@ export class LightShadow {
 
 
 	camera: Camera;
 	camera: Camera;
 	bias: number;
 	bias: number;
+	normalOffset: number;
 	radius: number;
 	radius: number;
 	mapSize: Vector2;
 	mapSize: Vector2;
 	map: RenderTarget;
 	map: RenderTarget;

+ 1 - 0
src/lights/LightShadow.js

@@ -13,6 +13,7 @@ function LightShadow( camera ) {
 	this.camera = camera;
 	this.camera = camera;
 
 
 	this.bias = 0;
 	this.bias = 0;
+	this.normalOffset = 0;
 	this.radius = 1;
 	this.radius = 1;
 
 
 	this.mapSize = new Vector2( 512, 512 );
 	this.mapSize = new Vector2( 512, 512 );

+ 0 - 39
src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js

@@ -63,19 +63,6 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 
 
 	uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
 	uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
 
 
-	#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0
-
-		struct DirectionalLightShadow {
-			float shadowBias;
-			float shadowRadius;
-			vec2 shadowMapSize;
-		};
-
-		uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];
-
-	#endif
-
-
 	void getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {
 	void getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {
 
 
 		directLight.color = directionalLight.color;
 		directLight.color = directionalLight.color;
@@ -98,20 +85,6 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 
 
 	uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
 	uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
 
 
-	#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0
-
-		struct PointLightShadow {
-			float shadowBias;
-			float shadowRadius;
-			vec2 shadowMapSize;
-			float shadowCameraNear;
-			float shadowCameraFar;
-		};
-
-		uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];
-
-	#endif
-
 	// directLight is an out parameter as having it as a return value caused compiler errors on some devices
 	// directLight is an out parameter as having it as a return value caused compiler errors on some devices
 	void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {
 	void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {
 
 
@@ -143,18 +116,6 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 
 
 	uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];
 	uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];
 
 
-	#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0
-
-		struct SpotLightShadow {
-			float shadowBias;
-			float shadowRadius;
-			vec2 shadowMapSize;
-		};
-
-		uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];
-
-	#endif
-
 	// directLight is an out parameter as having it as a return value caused compiler errors on some devices
 	// directLight is an out parameter as having it as a return value caused compiler errors on some devices
 	void getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {
 	void getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {
 
 

+ 29 - 0
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js

@@ -6,6 +6,15 @@ export default /* glsl */`
 		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];
 		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];
 		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 
+		struct DirectionalLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+		};
+
+		uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
@@ -13,6 +22,15 @@ export default /* glsl */`
 		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
 		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
 		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 
+		struct SpotLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+		};
+
+		uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	#if NUM_POINT_LIGHT_SHADOWS > 0
 	#if NUM_POINT_LIGHT_SHADOWS > 0
@@ -20,6 +38,17 @@ export default /* glsl */`
 		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];
 		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];
 		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 
+		struct PointLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+			float shadowCameraNear;
+			float shadowCameraFar;
+		};
+
+		uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	/*
 	/*

+ 29 - 0
src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js

@@ -6,6 +6,15 @@ export default /* glsl */`
 		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];
 		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];
 		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 
+		struct DirectionalLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+		};
+
+		uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
@@ -13,6 +22,15 @@ export default /* glsl */`
 		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
 		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
 		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 
+		struct SpotLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+		};
+
+		uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	#if NUM_POINT_LIGHT_SHADOWS > 0
 	#if NUM_POINT_LIGHT_SHADOWS > 0
@@ -20,6 +38,17 @@ export default /* glsl */`
 		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];
 		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];
 		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 
+		struct PointLightShadow {
+			float shadowBias;
+			float shadowNormalOffset;
+			float shadowRadius;
+			vec2 shadowMapSize;
+			float shadowCameraNear;
+			float shadowCameraFar;
+		};
+
+		uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];
+
 	#endif
 	#endif
 
 
 	/*
 	/*

+ 14 - 3
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js

@@ -1,12 +1,21 @@
 export default /* glsl */`
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 #ifdef USE_SHADOWMAP
 
 
+	#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0
+
+		// Offsetting the position used for querying occlusion along the world normal can be used to reduce shadow acne.
+		vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
+		vec4 shadowWorldPosition;
+
+	#endif
+
 	#if NUM_DIR_LIGHT_SHADOWS > 0
 	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 
 	#pragma unroll_loop_start
 	#pragma unroll_loop_start
 	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 
 
-		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
+		shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalOffset, 0 );
+		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;
 
 
 	}
 	}
 	#pragma unroll_loop_end
 	#pragma unroll_loop_end
@@ -18,7 +27,8 @@ export default /* glsl */`
 	#pragma unroll_loop_start
 	#pragma unroll_loop_start
 	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 
 
-		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
+		shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalOffset, 0 );
+		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;
 
 
 	}
 	}
 	#pragma unroll_loop_end
 	#pragma unroll_loop_end
@@ -30,7 +40,8 @@ export default /* glsl */`
 	#pragma unroll_loop_start
 	#pragma unroll_loop_start
 	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
 
-		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;
+		shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalOffset, 0 );
+		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;
 
 
 	}
 	}
 	#pragma unroll_loop_end
 	#pragma unroll_loop_end

+ 7 - 0
src/renderers/shaders/ShaderLib/shadow_vert.glsl.js

@@ -7,6 +7,13 @@ void main() {
 	#include <begin_vertex>
 	#include <begin_vertex>
 	#include <project_vertex>
 	#include <project_vertex>
 	#include <worldpos_vertex>
 	#include <worldpos_vertex>
+
+	#include <beginnormal_vertex>
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+
 	#include <shadowmap_vertex>
 	#include <shadowmap_vertex>
 	#include <fog_vertex>
 	#include <fog_vertex>
 
 

+ 3 - 0
src/renderers/shaders/UniformsLib.d.ts

@@ -73,6 +73,7 @@ export let UniformsLib: {
 			value: any[];
 			value: any[];
 			properties: {
 			properties: {
 				shadowBias: {};
 				shadowBias: {};
+				shadowNormalOffset: {};
 				shadowRadius: {};
 				shadowRadius: {};
 				shadowMapSize: {};
 				shadowMapSize: {};
 			};
 			};
@@ -95,6 +96,7 @@ export let UniformsLib: {
 			value: any[];
 			value: any[];
 			properties: {
 			properties: {
 				shadowBias: {};
 				shadowBias: {};
+				shadowNormalOffset: {};
 				shadowRadius: {};
 				shadowRadius: {};
 				shadowMapSize: {};
 				shadowMapSize: {};
 			};
 			};
@@ -114,6 +116,7 @@ export let UniformsLib: {
 			value: any[];
 			value: any[];
 			properties: {
 			properties: {
 				shadowBias: {};
 				shadowBias: {};
+				shadowNormalOffset: {};
 				shadowRadius: {};
 				shadowRadius: {};
 				shadowMapSize: {};
 				shadowMapSize: {};
 			};
 			};

+ 3 - 0
src/renderers/shaders/UniformsLib.js

@@ -119,6 +119,7 @@ const UniformsLib = {
 
 
 		directionalLightShadows: { value: [], properties: {
 		directionalLightShadows: { value: [], properties: {
 			shadowBias: {},
 			shadowBias: {},
+			shadowNormalOffset: {},
 			shadowRadius: {},
 			shadowRadius: {},
 			shadowMapSize: {}
 			shadowMapSize: {}
 		} },
 		} },
@@ -138,6 +139,7 @@ const UniformsLib = {
 
 
 		spotLightShadows: { value: [], properties: {
 		spotLightShadows: { value: [], properties: {
 			shadowBias: {},
 			shadowBias: {},
+			shadowNormalOffset: {},
 			shadowRadius: {},
 			shadowRadius: {},
 			shadowMapSize: {}
 			shadowMapSize: {}
 		} },
 		} },
@@ -154,6 +156,7 @@ const UniformsLib = {
 
 
 		pointLightShadows: { value: [], properties: {
 		pointLightShadows: { value: [], properties: {
 			shadowBias: {},
 			shadowBias: {},
+			shadowNormalOffset: {},
 			shadowRadius: {},
 			shadowRadius: {},
 			shadowMapSize: {},
 			shadowMapSize: {},
 			shadowCameraNear: {},
 			shadowCameraNear: {},

+ 6 - 0
src/renderers/webgl/WebGLLights.js

@@ -103,6 +103,7 @@ function ShadowUniformsCache() {
 				case 'DirectionalLight':
 				case 'DirectionalLight':
 					uniforms = {
 					uniforms = {
 						shadowBias: 0,
 						shadowBias: 0,
+						shadowNormalOffset: 0,
 						shadowRadius: 1,
 						shadowRadius: 1,
 						shadowMapSize: new Vector2()
 						shadowMapSize: new Vector2()
 					};
 					};
@@ -111,6 +112,7 @@ function ShadowUniformsCache() {
 				case 'SpotLight':
 				case 'SpotLight':
 					uniforms = {
 					uniforms = {
 						shadowBias: 0,
 						shadowBias: 0,
+						shadowNormalOffset: 0,
 						shadowRadius: 1,
 						shadowRadius: 1,
 						shadowMapSize: new Vector2()
 						shadowMapSize: new Vector2()
 					};
 					};
@@ -119,6 +121,7 @@ function ShadowUniformsCache() {
 				case 'PointLight':
 				case 'PointLight':
 					uniforms = {
 					uniforms = {
 						shadowBias: 0,
 						shadowBias: 0,
+						shadowNormalOffset: 0,
 						shadowRadius: 1,
 						shadowRadius: 1,
 						shadowMapSize: new Vector2(),
 						shadowMapSize: new Vector2(),
 						shadowCameraNear: 1,
 						shadowCameraNear: 1,
@@ -258,6 +261,7 @@ function WebGLLights() {
 					const shadowUniforms = shadowCache.get( light );
 					const shadowUniforms = shadowCache.get( light );
 
 
 					shadowUniforms.shadowBias = shadow.bias;
 					shadowUniforms.shadowBias = shadow.bias;
+					shadowUniforms.shadowNormalOffset = shadow.normalOffset;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 
 
@@ -299,6 +303,7 @@ function WebGLLights() {
 					const shadowUniforms = shadowCache.get( light );
 					const shadowUniforms = shadowCache.get( light );
 
 
 					shadowUniforms.shadowBias = shadow.bias;
 					shadowUniforms.shadowBias = shadow.bias;
+					shadowUniforms.shadowNormalOffset = shadow.normalOffset;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 
 
@@ -364,6 +369,7 @@ function WebGLLights() {
 					const shadowUniforms = shadowCache.get( light );
 					const shadowUniforms = shadowCache.get( light );
 
 
 					shadowUniforms.shadowBias = shadow.bias;
 					shadowUniforms.shadowBias = shadow.bias;
+					shadowUniforms.shadowNormalOffset = shadow.normalOffset;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowRadius = shadow.radius;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 					shadowUniforms.shadowMapSize = shadow.mapSize;
 					shadowUniforms.shadowCameraNear = shadow.camera.near;
 					shadowUniforms.shadowCameraNear = shadow.camera.near;