瀏覽代碼

Adding cascade shadow mapping on forward rendering.

clementlandrin 1 年之前
父節點
當前提交
a767f511fd
共有 4 個文件被更改,包括 100 次插入13 次删除
  1. 2 1
      h3d/pass/CascadeShadowMap.hx
  2. 48 7
      h3d/scene/pbr/LightBuffer.hx
  3. 3 3
      h3d/shader/CascadeShadow.hx
  4. 47 2
      h3d/shader/pbr/DefaultForward.hx

+ 2 - 1
h3d/pass/CascadeShadowMap.hx

@@ -95,7 +95,8 @@ class CascadeShadowMap extends DirShadowMap {
 		lightCameras[cascade - 1].orthoBounds = lightCamera.orthoBounds.clone();
 	}
 
-	function getCascadeProj(i:Int) {
+	public function getCascadeProj(i:Int) {
+		var i = hxd.Math.imin(i, lightCameras.length - 1);
 		return lightCameras[i].m;
 	}
 

+ 48 - 7
h3d/scene/pbr/LightBuffer.hx

@@ -1,5 +1,7 @@
 package h3d.scene.pbr;
 
+import h3d.pass.CascadeShadowMap;
+
 class LightBuffer {
 
 	public var defaultForwardShader = new h3d.shader.pbr.DefaultForward();
@@ -10,10 +12,12 @@ class LightBuffer {
 	var MAX_DIR_SHADOW = 1;
 	var MAX_SPOT_SHADOW = 2;
 	var MAX_POINT_SHADOW = 2;
+	var MAX_CASCADE_COUNT = 4;
 
 	var pointLightsShadow : Array<PointLight> = [];
 	var spotLightsShadow : Array<SpotLight> = [];
 	var dirLightsShadow : Array<DirLight> = [];
+	var cascadeLight : DirLight;
 	var pointLights : Array<PointLight> = [];
 	var spotLights : Array<SpotLight> = [];
 	var dirLights : Array<DirLight> = [];
@@ -22,6 +26,7 @@ class LightBuffer {
 	final POINT_LIGHT_INFO_SIZE = 3;
 	final SPOT_LIGHT_INFO_SIZE = 8;
 	final DIR_LIGHT_INFO_SIZE = 5;
+	final CASCADE_SHADOW_INFO_SIZE = 15;
 
 
 	public function new() {
@@ -34,18 +39,21 @@ class LightBuffer {
 		size += MAX_DIR_LIGHT * DIR_LIGHT_INFO_SIZE;
 		size += MAX_POINT_LIGHT * POINT_LIGHT_INFO_SIZE;
 		size += MAX_SPOT_LIGHT * SPOT_LIGHT_INFO_SIZE;
+		size += CASCADE_SHADOW_INFO_SIZE;
 		size = hxd.Math.imax(1, size); // Avoid empty buffer
 		lightInfos = new hxd.FloatBuffer(size * stride);
 		defaultForwardShader.lightInfos = new h3d.Buffer(size, hxd.BufferFormat.make([{ name : "uniformData", type : DVec4 }]), [UniformBuffer, Dynamic]);
 		defaultForwardShader.BUFFER_SIZE = size;
 		defaultForwardShader.dirLightStride = DIR_LIGHT_INFO_SIZE * MAX_DIR_LIGHT;
 		defaultForwardShader.pointLightStride = POINT_LIGHT_INFO_SIZE * MAX_POINT_LIGHT;
+		defaultForwardShader.spotLightStride = SPOT_LIGHT_INFO_SIZE * MAX_SPOT_LIGHT;
 	}
 
 	public function setBuffers( s : h3d.shader.pbr.DefaultForward ) {
 		s.lightInfos = defaultForwardShader.lightInfos;
 		s.dirLightStride = defaultForwardShader.dirLightStride;
 		s.pointLightStride = defaultForwardShader.pointLightStride;
+		s.spotLightStride = defaultForwardShader.spotLightStride;
 		s.cameraPosition = defaultForwardShader.cameraPosition;
 		s.emissivePower = defaultForwardShader.emissivePower;
 		s.BUFFER_SIZE = defaultForwardShader.BUFFER_SIZE;
@@ -56,6 +64,7 @@ class LightBuffer {
 		s.DIR_SHADOW_COUNT = defaultForwardShader.DIR_SHADOW_COUNT;
 		s.POINT_SHADOW_COUNT = defaultForwardShader.POINT_SHADOW_COUNT;
 		s.SPOT_SHADOW_COUNT = defaultForwardShader.SPOT_SHADOW_COUNT;
+		s.CASCADE_COUNT = defaultForwardShader.CASCADE_COUNT;
 
 		for( i in 0 ... defaultForwardShader.POINT_SHADOW_COUNT )
 			s.pointShadowMaps[i] = defaultForwardShader.pointShadowMaps[i];
@@ -63,6 +72,8 @@ class LightBuffer {
 			s.spotShadowMaps[i] = defaultForwardShader.spotShadowMaps[i];
 		for( i in 0 ... defaultForwardShader.DIR_SHADOW_COUNT )
 			s.dirShadowMaps[i] = defaultForwardShader.dirShadowMaps[i];
+		for ( i in 0... defaultForwardShader.CASCADE_COUNT )
+			s.cascadeShadowMaps[i] = defaultForwardShader.cascadeShadowMaps[i];
 
 		s.USE_INDIRECT = defaultForwardShader.USE_INDIRECT;
 		if( s.USE_INDIRECT ) {
@@ -75,14 +86,14 @@ class LightBuffer {
 		}
 	}
 
-	inline function fillFloats( b : hxd.FloatBuffer, f1 : Float, f2 : Float, f3 : Float, f4 : Float, i : Int ) {
+	function fillFloats( b : hxd.FloatBuffer, f1 : Float, f2 : Float, f3 : Float, f4 : Float, i : Int ) {
 		b[i+0] = f1;
 		b[i+1] = f2;
 		b[i+2] = f3;
 		b[i+3] = f4;
 	}
 
-	inline function fillVector( b : hxd.FloatBuffer, v : h3d.Vector, i : Int ) {
+	function fillVector( b : hxd.FloatBuffer, v : h3d.Vector, i : Int ) {
 		b[i+0] = v.r;
 		b[i+1] = v.g;
 		b[i+2] = v.b;
@@ -116,6 +127,7 @@ class LightBuffer {
 		pointLightsShadow = [];
 		spotLightsShadow = [];
 		dirLightsShadow = [];
+		cascadeLight = null;
 		pointLights = [];
 		spotLights = [];
 		dirLights = [];
@@ -134,14 +146,17 @@ class LightBuffer {
 				if (dirLightCount + dirShadowCount < MAX_DIR_LIGHT) {
 					var hasShadow = dl.shadows != null && dl.shadows.enabled && dl.shadows.mode != None && shadows;
 					if (hasShadow && dirShadowCount < MAX_DIR_SHADOW) {
-						dirLightsShadow.push(dl);
+						var cascade = Std.downcast(dl.shadows, CascadeShadowMap);
+						if ( cascade != null )
+							cascadeLight = dl;
+						else
+							dirLightsShadow.push(dl);
 						dirShadowCount++;
 					} else {
 						dirLights.push(dl);
 						dirLightCount++;
 					}
 				}
-
 			}
 
 			var pl = Std.downcast(l, PointLight);
@@ -186,13 +201,13 @@ class LightBuffer {
 		var p : h3d.scene.pbr.Renderer.RenderProps = pbrRenderer.props;
 		var s = defaultForwardShader;
 
-
 		s.cameraPosition = ctx.camera.pos;
 		s.emissivePower = p.emissive * p.emissive;
 
 		s.pointLightCount = 0;
 		s.spotLightCount = 0;
 		s.dirLightCount = 0;
+		s.CASCADE_COUNT = 0;
 
 		// Safe Reset
 		for( i in 0 ... lightInfos.length )
@@ -207,8 +222,8 @@ class LightBuffer {
 			var i = li * DIR_LIGHT_INFO_SIZE * 4;
 			var pbr = @:privateAccess dl.pbr;
 			fillVector(lightInfos, pbr.lightColor, i);
-			fillVector(lightInfos, pbr.lightDir, i+4);
 			lightInfos[i+3] = 1.0;
+			fillVector(lightInfos, pbr.lightDir, i+4);
 			lightInfos[i+7] = dl.shadows.bias;
 			s.dirShadowMaps[li] = dl.shadows.getShadowTex();
 			var mat = dl.shadows.getShadowProj();
@@ -223,8 +238,8 @@ class LightBuffer {
 			var i = (li + dirLightsShadow.length) * DIR_LIGHT_INFO_SIZE * 4;
 			var pbr = @:privateAccess dl.pbr;
 			fillVector(lightInfos, pbr.lightColor, i);
-			fillVector(lightInfos, pbr.lightDir, i+4);
 			lightInfos[i+3] = -1.0;
+			fillVector(lightInfos, pbr.lightDir, i+4);
 		}
 
 		// Point Light With Shadows
@@ -296,6 +311,31 @@ class LightBuffer {
 			lightInfos[i+14] = -1.0;
 		}
 
+		// Cascade shadows
+		if ( cascadeLight != null ) {
+			var offset = (MAX_DIR_LIGHT * DIR_LIGHT_INFO_SIZE + MAX_POINT_LIGHT * POINT_LIGHT_INFO_SIZE + MAX_SPOT_LIGHT * SPOT_LIGHT_INFO_SIZE) * 4 ;
+			var i = offset;
+			var pbr = @:privateAccess cascadeLight.pbr;
+			fillVector(lightInfos, pbr.lightColor, i);
+			lightInfos[i+3] = 0.0;
+			fillVector(lightInfos, pbr.lightDir, i+4);
+			lightInfos[i+7] = 0.0;
+			var cascadeShadow = cast(cascadeLight.shadows, CascadeShadowMap);
+			var shadowMaps = cascadeShadow.getShadowTextures();
+			s.CASCADE_COUNT = cascadeShadow.cascade;
+			var bias = [];
+			for ( index in 0...cascadeShadow.cascade ) {
+				s.cascadeShadowMaps[index] = shadowMaps[index];
+				var mat = cascadeShadow.getCascadeProj(cascadeShadow.cascade - 1 - index);
+				var i = offset + 8 + index * 12;
+				fillFloats(lightInfos, mat._11, mat._21, mat._31, mat._41, i);
+				fillFloats(lightInfos, mat._12, mat._22, mat._32, mat._42, i+4);
+				fillFloats(lightInfos, mat._13, mat._23, mat._33, mat._43, i+8);
+				bias.push(cascadeShadow.params[index].bias);
+			}
+			fillFloats(lightInfos, bias[0], bias[1], bias[2], bias[3], offset + 8 + MAX_CASCADE_COUNT * 12);
+		}
+
 		s.dirLightCount = dirLights.length;
 		s.pointLightCount = pointLights.length;
 		s.spotLightCount = spotLights.length;
@@ -309,6 +349,7 @@ class LightBuffer {
 		pointLightsShadow = [];
 		spotLightsShadow = [];
 		dirLightsShadow = [];
+		cascadeLight = null;
 
 		var pbrIndirect = @:privateAccess pbrRenderer.pbrIndirect;
 		s.USE_INDIRECT = pbrRenderer.env != null && pbrIndirect.irrLut != null;

+ 3 - 3
h3d/shader/CascadeShadow.hx

@@ -27,7 +27,7 @@ class CascadeShadow extends DirShadow {
 				var texelSize = 1.0/shadowRes;
 				@unroll for ( c in 0...CASCADE_COUNT ) {
 					var shadowPos = transformedPosition * cascadeProjs[c];
-					
+
 					if ( inside(shadowPos) ) {
 						shadow = 1.0;
 						var zMax = shadowPos.z.saturate();
@@ -43,13 +43,13 @@ class CascadeShadow extends DirShadow {
 								var offset = poissonDisk[i].xy * offScale;
 								offset = vec2(cosR * offset.x - sinR * offset.y, cosR * offset.y + sinR * offset.x);
 								var depth = cascadeShadowMaps[c].getLod(shadowUv + offset, 0).r;
-								shadow  -= (zMax - bias > depth) ? sampleStrength : 0.0;
+								shadow -= (zMax - bias > depth) ? sampleStrength : 0.0;
 							}
 						}
 						else if( USE_ESM ) {
 							var depth = cascadeShadowMaps[c].get(shadowUv).r;
 							var delta = (depth + bias).min(zMax) - zMax;
-							shadow = exp(shadowPower * delta).saturate();		
+							shadow = exp(shadowPower * delta).saturate();
 						}
 						else {
 							var depth = cascadeShadowMaps[c].get(shadowUv).r;

+ 47 - 2
h3d/shader/pbr/DefaultForward.hx

@@ -4,7 +4,8 @@ class DefaultForward extends hxsl.Shader {
 
 	static var SRC = {
 
-		@const(16) var DIR_SHADOW_COUNT:Int;
+		@const(4) var CASCADE_COUNT:Int;
+		@const(2) var DIR_SHADOW_COUNT:Int;
 		@const(16) var POINT_SHADOW_COUNT:Int;
 		@const(16) var SPOT_SHADOW_COUNT:Int;
 
@@ -23,8 +24,10 @@ class DefaultForward extends hxsl.Shader {
 		@param var spotLightCount : Int;
 		@param var dirLightStride : Int;
 		@param var pointLightStride : Int;
+		@param var spotLightStride : Int;
 
 		// ShadowMaps
+		@param var cascadeShadowMaps : Array<Sampler2D, CASCADE_COUNT>;
 		@param var dirShadowMaps : Array<Sampler2D, DIR_SHADOW_COUNT>;
 		@param var pointShadowMaps : Array<SamplerCube, POINT_SHADOW_COUNT>;
 		@param var spotShadowMaps : Array<Sampler2D, SPOT_SHADOW_COUNT>;
@@ -191,6 +194,41 @@ class DefaultForward extends hxsl.Shader {
 			return directLighting(fallOff * lightColor * fallOffInfoAngle, delta.normalize());
 		}
 
+		function evaluateCascadeLight() : Vec3 {
+			var i = dirLightStride + pointLightStride + spotLightStride;
+			var lightColor = lightInfos[i].rgb;
+			var lightDir = lightInfos[i+1].xyz;
+
+			return directLighting(lightColor, lightDir);
+		}
+
+		function inside(pos : Vec3) : Bool {
+			if ( abs(pos.x) < 1.0 && abs(pos.y) < 1.0 && abs(pos.z) < 1.0 )
+				return true;
+			else
+				return false;
+		}
+
+		function evaluateCascadeShadow() : Float {
+			var i = dirLightStride + pointLightStride + spotLightStride;
+			var bias = lightInfos[i + 2 + 3 * 4];
+			var bias = [bias.x, bias.y, bias.z, bias.w];
+			var shadow = 1.0;
+			@unroll for ( c in 0...CASCADE_COUNT ) {
+				var offset = i + 2 + 3 * c;
+				var shadowProj = mat3x4(lightInfos[offset], lightInfos[offset+1], lightInfos[offset+2]);
+				var shadowPos = transformedPosition * shadowProj;
+				if ( inside(shadowPos) ) {
+					shadow = 1.0;
+					var zMax = saturate(shadowPos.z);
+					var shadowUv = screenToUv(shadowPos.xy);
+					var depth = cascadeShadowMaps[c].get(shadowUv.xy).r;
+					shadow -= (zMax - bias[c] > depth) ? 1.0 : 0.0;
+				}
+			}
+			return saturate(shadow);
+		}
+
 		function evaluateLighting() : Vec3 {
 
 			var lightAccumulation = vec3(0);
@@ -201,7 +239,10 @@ class DefaultForward extends hxsl.Shader {
 			@unroll for( l in 0 ... DIR_SHADOW_COUNT )
 				lightAccumulation += evaluateDirLight(l) * evaluateDirShadow(l);
 			// Dir Light
-			@unroll for( l in DIR_SHADOW_COUNT ... dirLightCount + DIR_SHADOW_COUNT )
+			var start = DIR_SHADOW_COUNT;
+			if ( CASCADE_COUNT > 0 )
+				start++;
+			@unroll for( l in start ... dirLightCount + DIR_SHADOW_COUNT )
 				lightAccumulation += evaluateDirLight(l);
 
 			// Point Light With Shadow
@@ -218,6 +259,10 @@ class DefaultForward extends hxsl.Shader {
 			@unroll for( l in SPOT_SHADOW_COUNT ... spotLightCount + SPOT_SHADOW_COUNT )
 				lightAccumulation += evaluateSpotLight(l);
 
+			// Cascade shadows
+			if ( CASCADE_COUNT > 0 )
+				lightAccumulation += evaluateCascadeLight() * evaluateCascadeShadow();
+
 			// Indirect only support the main env from the scene at the moment
 			if( USE_INDIRECT )
 				lightAccumulation += indirectLighting();