浏览代码

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

LightShadow: Add shadow map normal offset.
Mr.doob 5 年之前
父节点
当前提交
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
 		</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>
 		<p>
 			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 );',
 			'	gl_Position = projectionMatrix * mvPosition;',
 
+			'#include <beginnormal_vertex>',
+			'#include <defaultnormal_vertex>',
 			'#include <logdepthbuf_vertex>',
 			'#include <fog_vertex>',
 			'#include <shadowmap_vertex>',

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

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

+ 1 - 0
src/lights/LightShadow.js

@@ -13,6 +13,7 @@ function LightShadow( camera ) {
 	this.camera = camera;
 
 	this.bias = 0;
+	this.normalOffset = 0;
 	this.radius = 1;
 
 	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 ];
 
-	#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 ) {
 
 		directLight.color = directionalLight.color;
@@ -98,20 +85,6 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 
 	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
 	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 ];
 
-	#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
 	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 ];
 		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
 
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
@@ -13,6 +22,15 @@ export default /* glsl */`
 		uniform sampler2D spotShadowMap[ 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
 
 	#if NUM_POINT_LIGHT_SHADOWS > 0
@@ -20,6 +38,17 @@ export default /* glsl */`
 		uniform sampler2D pointShadowMap[ 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
 
 	/*

+ 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 ];
 		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
 
 	#if NUM_SPOT_LIGHT_SHADOWS > 0
@@ -13,6 +22,15 @@ export default /* glsl */`
 		uniform mat4 spotShadowMatrix[ 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
 
 	#if NUM_POINT_LIGHT_SHADOWS > 0
@@ -20,6 +38,17 @@ export default /* glsl */`
 		uniform mat4 pointShadowMatrix[ 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
 
 	/*

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

@@ -1,12 +1,21 @@
 export default /* glsl */`
 #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
 
 	#pragma unroll_loop_start
 	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
@@ -18,7 +27,8 @@ export default /* glsl */`
 	#pragma unroll_loop_start
 	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
@@ -30,7 +40,8 @@ export default /* glsl */`
 	#pragma unroll_loop_start
 	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

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

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

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

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

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

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

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

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