CascadeShadowMap.hx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package h3d.pass;
  2. typedef CascadeParams = {
  3. var bias : Float;
  4. }
  5. class CascadeShadowMap extends DirShadowMap {
  6. var cshader : h3d.shader.CascadeShadow;
  7. var lightCameras : Array<h3d.Camera> = [];
  8. var currentCascadeIndex = 0;
  9. public var params : Array<CascadeParams> = [];
  10. public var pow : Float = 1.0;
  11. public var firstCascadeSize : Float = 10.0;
  12. public var castingMaxDist : Float = 0.0;
  13. public var cascade(default, set) = 1;
  14. public function set_cascade(v) {
  15. cascade = v;
  16. lightCameras = [];
  17. for ( i in 0...cascade ) {
  18. lightCameras.push(new h3d.Camera());
  19. lightCameras[i].orthoBounds = new h3d.col.Bounds();
  20. }
  21. return cascade;
  22. }
  23. public var debugShader : Bool = false;
  24. static var debugColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xff00ff, 0x000000];
  25. public function new( light : h3d.scene.Light ) {
  26. super(light);
  27. format = R32F;
  28. shader = dshader = cshader = new h3d.shader.CascadeShadow();
  29. }
  30. public override function getShadowTex() {
  31. return cshader.shadowMap;
  32. }
  33. public function getShadowTextures() {
  34. return cshader.cascadeShadowMaps;
  35. }
  36. function computeNearFar( i : Int ) {
  37. var min = minDist < 0.0 ? ctx.camera.zNear : minDist;
  38. var max = maxDist < 0.0 ? ctx.camera.zFar : maxDist;
  39. if ( i == 0 ) {
  40. return {near : min, far : min + firstCascadeSize};
  41. }
  42. var step = (max - min - firstCascadeSize) / (cascade - 1);
  43. var near = min + firstCascadeSize + hxd.Math.pow((i - 1) / (cascade - 1), pow) * step;
  44. var far = min + firstCascadeSize + hxd.Math.pow(i / (cascade - 1), pow) * step;
  45. return {near : near, far : far};
  46. }
  47. public function updateCascadeBounds( camera : h3d.Camera ) {
  48. var bounds = camera.orthoBounds;
  49. var shadowNear = hxd.Math.POSITIVE_INFINITY;
  50. var shadowFar = hxd.Math.NEGATIVE_INFINITY;
  51. var corners = lightCamera.getFrustumCorners();
  52. for ( corner in corners ) {
  53. corner.transform(ctx.camera.mcam);
  54. shadowNear = hxd.Math.min(shadowNear, corner.z / corner.w);
  55. shadowFar = hxd.Math.max(shadowFar, corner.z / corner.w);
  56. }
  57. for ( i in 0...cascade - 1 ) {
  58. var cascadeBounds = new h3d.col.Bounds();
  59. function addCorner(x,y,d) {
  60. var pt = ctx.camera.unproject(x,y,ctx.camera.distanceToDepth(d)).toPoint();
  61. pt.transform(camera.mcam);
  62. cascadeBounds.addPos(pt.x, pt.y, pt.z);
  63. }
  64. function addCorners(d) {
  65. addCorner(-1,-1,d);
  66. addCorner(-1,1,d);
  67. addCorner(1,-1,d);
  68. addCorner(1,1,d);
  69. }
  70. var nearFar = computeNearFar(i);
  71. addCorners(nearFar.near);
  72. addCorners(nearFar.far);
  73. // Increasing z range has no effect on resolution, only on depth precision.
  74. cascadeBounds.zMax = lightCamera.orthoBounds.zMax;
  75. cascadeBounds.zMin = lightCamera.orthoBounds.zMin;
  76. lightCameras[i].orthoBounds = cascadeBounds;
  77. }
  78. lightCameras[cascade - 1].orthoBounds = lightCamera.orthoBounds.clone();
  79. }
  80. override function setGlobals() {
  81. super.setGlobals();
  82. cameraViewProj = getCascadeProj(currentCascadeIndex);
  83. }
  84. function getCascadeProj(i:Int) {
  85. return lightCameras[i].m;
  86. }
  87. function syncCascadeShader(textures : Array<h3d.mat.Texture>) {
  88. cshader.DEBUG = debugShader;
  89. for ( i in 0...cascade ) {
  90. var c = cascade - 1 - i;
  91. cshader.cascadeShadowMaps[c] = textures[i];
  92. cshader.cascadeProjs[c] = lightCameras[i].m;
  93. if ( debugShader )
  94. cshader.cascadeDebugs[c] = h3d.Vector.fromColor(debugColors[i]);
  95. cshader.cascadeBias[c] = params[c] != null ? params[c].bias : 0.001;
  96. }
  97. cshader.CASCADE_COUNT = cascade;
  98. cshader.shadowBias = bias;
  99. cshader.shadowPower = power;
  100. cshader.shadowProj = getShadowProj();
  101. //ESM
  102. cshader.USE_ESM = samplingKind == ESM;
  103. cshader.shadowPower = power;
  104. // PCF
  105. cshader.USE_PCF = samplingKind == PCF;
  106. cshader.shadowRes.set(textures[0].width,textures[0].height);
  107. cshader.pcfScale = pcfScale;
  108. cshader.pcfQuality = pcfQuality;
  109. }
  110. override function draw( passes, ?sort ) {
  111. if( !enabled )
  112. return;
  113. if( !filterPasses(passes) )
  114. return;
  115. if( mode != Mixed || ctx.computingStatic ) {
  116. var ct = ctx.camera.target;
  117. var slight = light == null ? ctx.lightSystem.shadowLight : light;
  118. var ldir = slight == null ? null : @:privateAccess slight.getShadowDirection();
  119. if( ldir == null )
  120. lightCamera.target.set(0, 0, -1);
  121. else {
  122. lightCamera.target.set(ldir.x, ldir.y, ldir.z);
  123. lightCamera.target.normalize();
  124. }
  125. lightCamera.target.x += ct.x;
  126. lightCamera.target.y += ct.y;
  127. lightCamera.target.z += ct.z;
  128. lightCamera.pos.load(ct);
  129. lightCamera.update();
  130. for ( i in 0...lightCameras.length) {
  131. if( ldir == null )
  132. lightCameras[i].target.set(0, 0, -1);
  133. else {
  134. lightCameras[i].target.set(ldir.x, ldir.y, ldir.z);
  135. lightCameras[i].target.normalize();
  136. }
  137. lightCameras[i].target.x += ct.x;
  138. lightCameras[i].target.y += ct.y;
  139. lightCameras[i].target.z += ct.z;
  140. lightCameras[i].pos.load(ct);
  141. lightCameras[i].update();
  142. }
  143. lightCamera.orthoBounds.empty();
  144. for ( lC in lightCameras ) lC.orthoBounds.empty();
  145. if( !passes.isEmpty() ) calcShadowBounds(lightCamera);
  146. var pt = ctx.camera.pos.clone();
  147. pt.transform(lightCamera.mcam);
  148. lightCamera.orthoBounds.zMax = pt.z + (castingMaxDist > 0.0 ? castingMaxDist : maxDist < 0.0 ? ctx.camera.zFar : maxDist);
  149. lightCamera.orthoBounds.zMin = pt.z - (castingMaxDist > 0.0 ? castingMaxDist : maxDist < 0.0 ? ctx.camera.zFar : maxDist);
  150. lightCamera.update();
  151. }
  152. cullPasses(passes,function(col) return col.inFrustum(lightCamera.frustum));
  153. updateCascadeBounds(lightCamera);
  154. for ( lC in lightCameras ) lC.update();
  155. var textures = [];
  156. for (i in 0...cascade) {
  157. #if js
  158. var texture = ctx.textures.allocTarget("cascadeShadowMap_"+i, size, size, false, format);
  159. if( depth == null || depth.width != size || depth.height != size || depth.isDisposed() ) {
  160. if( depth != null ) depth.dispose();
  161. depth = new h3d.mat.Texture(size, size, Depth24Stencil8);
  162. depth.name = "dirShadowMapDepth";
  163. }
  164. texture.depthBuffer = depth;
  165. #else
  166. var texture = ctx.textures.allocTarget("cascadeShadowMap_"+i, size, size, false, Depth24Stencil8);
  167. #end
  168. currentCascadeIndex = i;
  169. var p = passes.save();
  170. cullPasses(passes,function(col) return col.inFrustum(lightCameras[i].frustum));
  171. texture = processShadowMap( passes, texture, sort);
  172. textures.push(texture);
  173. passes.load(p);
  174. }
  175. syncCascadeShader(textures);
  176. #if editor
  177. drawDebug();
  178. #end
  179. }
  180. override function drawDebug() {
  181. super.drawDebug();
  182. if ( !debug )
  183. return;
  184. for ( i in 0...cascade ) {
  185. drawBounds(lightCameras[i], debugColors[i]);
  186. }
  187. }
  188. }