Blur.hx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package h3d.pass;
  2. @ignore("shader")
  3. class Blur extends ScreenFx<h3d.shader.Blur> {
  4. /**
  5. How far in pixels the blur will go.
  6. **/
  7. public var radius(default,set) : Float;
  8. /**
  9. How much the blur increases or decreases the color amount (default = 1)
  10. **/
  11. public var gain(default,set) : Float;
  12. /**
  13. Set linear blur instead of gaussian (default = 0).
  14. **/
  15. public var linear(default, set) : Float;
  16. /**
  17. Adjust how much quality/speed tradeoff we want (default = 1)
  18. **/
  19. public var quality(default,set) : Float;
  20. var values : Array<Float>;
  21. var offsets : Array<Float>;
  22. public function new( radius = 1., gain = 1., linear = 0., quality = 1. ) {
  23. super(new h3d.shader.Blur());
  24. this.radius = radius;
  25. this.quality = quality;
  26. this.gain = gain;
  27. }
  28. function set_radius(r) {
  29. if( radius == r )
  30. return r;
  31. values = null;
  32. return radius = r;
  33. }
  34. function set_quality(q) {
  35. if( quality == q )
  36. return q;
  37. values = null;
  38. return quality = q;
  39. }
  40. function set_gain(s) {
  41. if( gain == s )
  42. return s;
  43. values = null;
  44. return gain = s;
  45. }
  46. function set_linear(b) {
  47. if( linear == b )
  48. return b;
  49. values = null;
  50. return linear = b;
  51. }
  52. function gauss( x:Float, s:Float ) : Float {
  53. if( s <= 0 ) return x == 0 ? 1 : 0;
  54. var sq = s * s;
  55. var p = Math.pow(2.718281828459, -(x * x) / (2 * sq));
  56. return p / Math.sqrt(2 * Math.PI * sq);
  57. }
  58. function calcValues() {
  59. values = [];
  60. offsets = [];
  61. var tot = 0.;
  62. var qadj = hxd.Math.clamp(quality) * 0.7 + 0.3;
  63. var width = radius > 0 ? Math.ceil(hxd.Math.max(radius - 1, 1) * qadj / 2) : 0;
  64. var sigma = Math.sqrt(radius) * 2;
  65. for( i in 0...width + 1 ) {
  66. var i1 = i * 2;
  67. var i2 = i == 0 ? 0 : i * 2 - 1;
  68. var g1 = gauss(i1, sigma);
  69. var g2 = gauss(i2,sigma);
  70. var g = g1 + g2;
  71. values[i] = g;
  72. offsets[i] = i == 0 ? 0 : (g1 * i1 + g2 * i2) / (g * i * Math.sqrt(qadj));
  73. tot += g;
  74. if( i > 0 ) tot += g;
  75. }
  76. // eliminate too low contributing values
  77. var minVal = values[0] * (0.01 / qadj);
  78. while( values.length > 2 ) {
  79. var last = values[values.length-1];
  80. if( last > minVal ) break;
  81. tot -= last * 2;
  82. values.pop();
  83. }
  84. tot /= gain;
  85. for( i in 0...values.length )
  86. values[i] /= tot;
  87. if( linear > 0 ) {
  88. var m = gain / (values.length * 2 - 1);
  89. for( i in 0...values.length ) {
  90. values[i] = hxd.Math.lerp(values[i], m, linear);
  91. offsets[i] = hxd.Math.lerp(offsets[i], i == 0 ? 0 : (i * 2 - 0.5) / (i * qadj), linear);
  92. }
  93. }
  94. }
  95. public function getKernelSize() {
  96. if( values == null ) calcValues();
  97. return radius <= 0 ? 0 : values.length * 2 - 1;
  98. }
  99. public function apply( ctx : h3d.impl.RenderContext, src : h3d.mat.Texture, ?output : h3d.mat.Texture ) {
  100. if( radius <= 0 && shader.fixedColor == null ) {
  101. if( output != null ) Copy.run(src, output);
  102. return;
  103. }
  104. if( output == null ) output = src;
  105. if( values == null ) calcValues();
  106. var tmp = ctx.textures.allocTarget(src.name+"BlurTmp",src.width,src.height,false,src.format);
  107. shader.Quality = values.length;
  108. shader.values = values;
  109. shader.offsets = offsets;
  110. shader.texture = src;
  111. shader.pixel.set(1 / src.width, 0);
  112. engine.pushTarget(tmp);
  113. render();
  114. engine.popTarget();
  115. shader.texture = tmp;
  116. shader.pixel.set(0, 1 / src.height);
  117. var outDepth = output.depthBuffer;
  118. output.depthBuffer = null;
  119. engine.pushTarget(output);
  120. render();
  121. engine.popTarget();
  122. output.depthBuffer = outDepth;
  123. }
  124. }