فهرست منبع

added autoZPlanes for top down camera optimization

Nicolas Cannasse 4 سال پیش
والد
کامیت
ee94d882fc
1فایلهای تغییر یافته به همراه69 افزوده شده و 11 حذف شده
  1. 69 11
      h3d/pass/DirShadowMap.hx

+ 69 - 11
h3d/pass/DirShadowMap.hx

@@ -8,11 +8,21 @@ class DirShadowMap extends Shadows {
 	var border : Border;
 	var mergePass = new h3d.pass.ScreenFx(new h3d.shader.MinMaxShader());
 
-	// Shrink the frustum of the light to the bounds containing all visible objects
+	/**
+		Shrink the frustum of the light to the bounds containing all visible objects
+	**/
 	public var autoShrink = true;
-	// Clamp the zFar of the frustum of the camera for bounds calculation
+	/**
+		For top down lights and cameras, use scene Z min/max to optimize shadowmap. Requires autoShrink
+	**/
+	public var autoZPlanes = false;
+	/**
+		Clamp the zFar of the frustum of the camera for bounds calculation
+	**/
 	public var maxDist = -1.0;
-	// Clamp the zNear of the frustum of the camera for bounds calculation
+	/**
+		Clamp the zNear of the frustum of the camera for bounds calculation
+	**/
 	public var minDist = -1.0;
 
 	public function new( light : h3d.scene.Light ) {
@@ -55,15 +65,25 @@ class DirShadowMap extends Shadows {
 
 	public dynamic function calcShadowBounds( camera : h3d.Camera ) {
 		var bounds = camera.orthoBounds;
-
+		var zMax = -1e9, zMin = 1e9;
 		if( autoShrink ) {
 			// add visible casters in light camera position
 			var mtmp = new h3d.Matrix();
+			var btmp = autoZPlanes ? new h3d.col.Bounds() : null;
 			ctx.scene.iterVisibleMeshes(function(m) {
 				if( m.primitive == null || !m.material.castShadows ) return;
 				var b = m.primitive.getBounds();
 				if( b.xMin > b.xMax ) return;
-				mtmp.multiply3x4(m.getAbsPos(), camera.mcam);
+
+				var absPos = m.getAbsPos();
+				if( autoZPlanes ) {
+					btmp.load(b);
+					btmp.transform(absPos);
+					if( btmp.zMax > zMax ) zMax = btmp.zMax;
+					if( btmp.zMin < zMin ) zMin = btmp.zMin;
+				}
+
+				mtmp.multiply3x4(absPos, camera.mcam);
 
 				var p = new h3d.col.Point(b.xMin, b.yMin, b.zMin);
 				p.transform(mtmp);
@@ -98,8 +118,7 @@ class DirShadowMap extends Shadows {
 				bounds.addPoint(p);
 
 			});
-		}
-		else {
+		} else {
 			if( mode == Dynamic )
 				bounds.all();
 		}
@@ -108,23 +127,62 @@ class DirShadowMap extends Shadows {
 
 			// Intersect with frustum bounds
 			var cameraBounds = new h3d.col.Bounds();
-			var zMin = minDist < 0 ? 0.0 : ctx.camera.distanceToDepth(minDist);
-			var zMax = maxDist < 0 ? 1.0 : ctx.camera.distanceToDepth(maxDist);
-			for( pt in ctx.camera.getFrustumCorners(zMax, zMin) ) {
+			var minDist = minDist < 0 ? ctx.camera.zNear : minDist;
+			var maxDist = maxDist < 0 ? ctx.camera.zFar : maxDist;
+
+			inline function addCorner(x,y,d) {
+				var dist = d?minDist:maxDist;
+				var pt = ctx.camera.unproject(x,y,ctx.camera.distanceToDepth(dist)).toPoint();
+				if( autoShrink && autoZPlanes ) {
+					// let's auto limit our frustrum to our zMin/Max planes
+					var r = h3d.col.Ray.fromPoints(ctx.camera.pos.toPoint(), pt);
+					var d2 = r.distance(h3d.col.Plane.Z(d?zMax:zMin));
+					var k = d ? 1 : -1;
+					if( d2 > 0 && d2*k > dist*k )
+						pt.load(r.getPoint(d2));
+				}
 				pt.transform(camera.mcam);
 				cameraBounds.addPos(pt.x, pt.y, pt.z);
 			}
 
+			inline function addCorners(d) {
+				addCorner(-1,-1,d);
+				addCorner(-1,1,d);
+				addCorner(1,-1,d);
+				addCorner(1,1,d);
+			}
+
+			addCorners(true);
+			addCorners(false);
+
 			if( autoShrink ) {
 				// Keep the zMin from the bounds of visible objects
 				// Prevent shadows inside frustum from objects outside frustum being clipped
 				cameraBounds.zMin = bounds.zMin;
 				bounds.intersection(bounds, cameraBounds);
+				if( autoZPlanes ) {
+					/*
+						Let's intersect again our light camera bounds with our scene zMax plane
+						so we can tighten the zMin, which will give us better precision
+						for our depth map.
+					*/
+					var v = camera.target.sub(camera.pos).normalized();
+					var dMin = 1e9;
+					for( dx in 0...2 )
+						for( dy in 0...2 ) {
+							var px = dx > 0 ? bounds.xMax : bounds.xMin;
+							var py = dy > 0 ? bounds.yMax : bounds.yMin;
+							var r0 = new h3d.col.Point(px,py,bounds.zMin).transformed(camera.getInverseView());
+							var r = h3d.col.Ray.fromValues(r0.x, r0.y, r0.z, v.x, v.y, v.z);
+							var d = r.distance(h3d.col.Plane.Z(zMax));
+							if( d < dMin ) dMin = d;
+						}
+					bounds.zMin += dMin;
+				}
 			}
 			else
 				bounds.load( cameraBounds );
 		}
-
 		bounds.scaleCenter(1.01);
 	}