|
@@ -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);
|
|
|
}
|
|
|
|