CubeShadowMap.hx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package h3d.pass;
  2. enum CubeFaceFlag {
  3. Right;
  4. Left;
  5. Back;
  6. Front;
  7. Top;
  8. Bottom;
  9. }
  10. class CubeShadowMap extends Shadows {
  11. var depth : h3d.mat.Texture;
  12. var mergePass = new h3d.pass.ScreenFx(new h3d.shader.MinMaxShader.CubeMinMaxShader());
  13. public var faceMask(default, null) : haxe.EnumFlags<CubeFaceFlag>;
  14. var cubeDir = [ h3d.Matrix.L([0,0,-1,0, 0,-1,0,0, 1,0,0,0]),
  15. h3d.Matrix.L([0,0,1,0, 0,-1,0,0, -1,0,0,0]),
  16. h3d.Matrix.L([1,0,0,0, 0,0,1,0, 0,1,0,0]),
  17. h3d.Matrix.L([1,0,0,0, 0,0,-1,0, 0,-1,0,0]),
  18. h3d.Matrix.L([1,0,0,0, 0,-1,0,0, 0,0,1,0]),
  19. h3d.Matrix.L([-1,0,0,0, 0,-1,0,0, 0,0,-1,0]) ];
  20. public function new( light : h3d.scene.Light, useWorldDist : Bool ) {
  21. super(light);
  22. lightCamera = new h3d.Camera();
  23. lightCamera.screenRatio = 1.0;
  24. lightCamera.fovY = 90;
  25. faceMask.set(Front);
  26. faceMask.set(Back);
  27. faceMask.set(Top);
  28. faceMask.set(Bottom);
  29. faceMask.set(Left);
  30. faceMask.set(Right);
  31. }
  32. override function set_size(s) {
  33. return super.set_size(s);
  34. }
  35. override function dispose() {
  36. super.dispose();
  37. if( depth != null ) depth.dispose();
  38. if( tmpTex != null) tmpTex.dispose();
  39. }
  40. override function isUsingWorldDist(){
  41. return true;
  42. }
  43. override function saveStaticData() {
  44. if( mode != Mixed && mode != Static )
  45. return null;
  46. if( staticTexture == null )
  47. throw "Data not computed";
  48. var buffer = new haxe.io.BytesBuffer();
  49. buffer.addInt32(staticTexture.width);
  50. for(i in 0 ... 6){
  51. var bytes = haxe.zip.Compress.run(staticTexture.capturePixels(i).bytes,9);
  52. buffer.addInt32(bytes.length);
  53. buffer.add(bytes);
  54. }
  55. return buffer.getBytes();
  56. }
  57. function createStaticTexture() : h3d.mat.Texture {
  58. if( staticTexture != null && staticTexture.width == size && staticTexture.width == size && staticTexture.format == format )
  59. return staticTexture;
  60. if( staticTexture != null )
  61. staticTexture.dispose();
  62. staticTexture = new h3d.mat.Texture(size, size, [Target, Cube], format);
  63. staticTexture.name = "staticTexture";
  64. staticTexture.preventAutoDispose();
  65. staticTexture.realloc = function () {
  66. if( pixelsForRealloc != null && pixelsForRealloc.length == 6 ) {
  67. for( i in 0 ... 6 ) {
  68. var pixels = pixelsForRealloc[i];
  69. staticTexture.uploadPixels(pixels, 0, i);
  70. }
  71. }
  72. }
  73. return staticTexture;
  74. }
  75. var pixelsForRealloc : Array<hxd.Pixels> = null;
  76. override function loadStaticData( bytes : haxe.io.Bytes ) {
  77. if( (mode != Mixed && mode != Static) || bytes == null || bytes.length == 0 )
  78. return false;
  79. var buffer = new haxe.io.BytesInput(bytes);
  80. var size = buffer.readInt32();
  81. if( size != this.size )
  82. return false;
  83. createStaticTexture();
  84. pixelsForRealloc = [];
  85. for( i in 0 ... 6 ) {
  86. var len = buffer.readInt32();
  87. var pixels = new hxd.Pixels(size, size, haxe.zip.Uncompress.run(buffer.read(len)), format);
  88. pixelsForRealloc.push(pixels);
  89. staticTexture.uploadPixels(pixels, 0, i);
  90. }
  91. syncShader(staticTexture);
  92. return true;
  93. }
  94. var tmpTex : h3d.mat.Texture;
  95. override function createDefaultShadowMap() {
  96. if( tmpTex != null)
  97. return tmpTex;
  98. tmpTex = new h3d.mat.Texture(1,1, [Target,Cube], format);
  99. tmpTex.name = "defaultCubeShadowMap";
  100. tmpTex.realloc = function() clear(tmpTex);
  101. clear(tmpTex);
  102. return tmpTex;
  103. }
  104. inline function clear( t : h3d.mat.Texture, ?layer = -1 ) {
  105. if( format == RGBA )
  106. t.clear(0xFFFFFF, layer);
  107. else
  108. t.clearF(1, 1, 1, 1, layer);
  109. }
  110. function updateLightCameraNearFar(light : h3d.scene.Light) {
  111. }
  112. function createCollider(light : h3d.scene.Light) : h3d.col.Collider {
  113. return null;
  114. }
  115. function cull(lightCollider : h3d.col.Collider, col : h3d.col.Collider) {
  116. return false;
  117. }
  118. var clearDepthColor = new h3d.Vector4(1,1,1,1);
  119. override function draw( passes : h3d.pass.PassList, ?sort ) {
  120. if( !enabled )
  121. return;
  122. if( !filterPasses(passes) )
  123. return;
  124. if( passes.isEmpty() ) {
  125. syncEarlyExit();
  126. return;
  127. }
  128. var lightCollider = createCollider(light);
  129. cullPasses(passes,function(col) return cull(lightCollider, col));
  130. if( passes.isEmpty() ) {
  131. syncEarlyExit();
  132. return;
  133. }
  134. var computingStatic = ctx.computingStatic || updateStatic;
  135. var texture = computingStatic ? createStaticTexture() : ctx.textures.allocTarget("pointShadowMap", size, size, false, format, [Cube]);
  136. if( depth == null || depth.width != texture.width || depth.height != texture.height || depth.isDisposed() ) {
  137. if( depth != null ) depth.dispose();
  138. depth = new h3d.mat.Texture(texture.width, texture.height, Depth24Stencil8);
  139. }
  140. texture.depthBuffer = depth;
  141. var absPos = light.getAbsPos();
  142. lightCamera.pos.set(absPos.tx, absPos.ty, absPos.tz);
  143. updateLightCameraNearFar(light);
  144. var prevFar = @:privateAccess ctx.cameraFar;
  145. var prevPos = @:privateAccess ctx.cameraPos;
  146. var prevViewProj = @:privateAccess ctx.cameraViewProj;
  147. for( i in 0...6 ) {
  148. // Shadows on the current face is disabled
  149. if( !faceMask.has(CubeFaceFlag.createByIndex(i)) ) {
  150. clear(texture, i);
  151. continue;
  152. }
  153. lightCamera.setCubeMap(i);
  154. lightCamera.update();
  155. var save = passes.save();
  156. cullPasses(passes, function(col) return col.inFrustum(lightCamera.frustum));
  157. if( passes.isEmpty() ) {
  158. passes.load(save);
  159. clear(texture, i);
  160. continue;
  161. }
  162. ctx.engine.pushTarget(texture, i);
  163. format == RGBA ? ctx.engine.clear(0xFFFFFF, i) : ctx.engine.clearF(clearDepthColor, 1);
  164. @:privateAccess ctx.cameraViewProj = getShadowProj();
  165. @:privateAccess ctx.cameraFar = lightCamera.zFar;
  166. @:privateAccess ctx.cameraPos = lightCamera.pos;
  167. super.draw(passes,sort);
  168. passes.load(save);
  169. ctx.engine.popTarget();
  170. }
  171. @:privateAccess ctx.cameraFar = prevFar;
  172. @:privateAccess ctx.cameraPos = prevPos;
  173. @:privateAccess ctx.cameraViewProj = prevViewProj;
  174. // Blur is applied even if there's no shadows - TO DO : remove the useless blur pass
  175. if( blur.radius > 0 )
  176. blur.apply(ctx, texture);
  177. if( mode == Mixed && !computingStatic )
  178. syncShader(merge(texture));
  179. else
  180. syncShader(texture);
  181. updateStatic = false;
  182. }
  183. function merge( dynamicTex : h3d.mat.Texture ) : h3d.mat.Texture{
  184. if ( staticTexture == null || staticTexture.isDisposed() )
  185. return dynamicTex;
  186. if ( staticTexture.width != dynamicTex.width )
  187. throw "Static shadow map doesnt match dynamic shadow map";
  188. var merge = ctx.textures.allocTarget("mergedPointShadowMap", size, size, false, format, [Cube]);
  189. for( i in 0 ... 6 ) {
  190. if( !faceMask.has(CubeFaceFlag.createByIndex(i)) ) continue;
  191. mergePass.shader.texA = dynamicTex;
  192. mergePass.shader.texB = staticTexture;
  193. mergePass.shader.mat = cubeDir[i];
  194. ctx.engine.pushTarget(merge, i);
  195. mergePass.render();
  196. ctx.engine.popTarget();
  197. }
  198. return merge;
  199. }
  200. override function computeStatic( passes : h3d.pass.PassList ) {
  201. if( mode != Static && mode != Mixed )
  202. return;
  203. draw(passes);
  204. }
  205. }