compositor for 2d shader
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // FM - frequency modulator
  2. // 2016 Tomasz Sulej, generateme.blog@gmail.com, http://generateme.tumblr.com
  3. // Licence: http://unlicense.org/
  4. // Frequency modulation and demodulation of the image
  5. // process goes in following way:
  6. // - convert RGB into desired colorspace (GS - grayscale)
  7. // For every channel
  8. // - modulate signal
  9. // - quantize and dequantize signal (if quantval > 0)
  10. // - demodulate signal using derivative method
  11. // - apply 3 lowpass filters in a chain to remove carrier (if possible)
  12. // Combine channels and convert back to RGB
  13. // Usage:
  14. // * move mouse X axis - change the carrier wave frequency
  15. // * move mouse Y axis - change bandwidth
  16. // * click mouse to fix setup (click again to release)
  17. // * press N to negate image
  18. // * press SPACE to save
  19. class FM extends Shader {
  20. // configuration
  21. int colorspace = RGB;
  22. final static boolean first_channel_only = false; // for L.. or Y.. colorspaces set true to modulate only luma;
  23. final static int quantval = 30; // 0 - off, less - more glitch, more - more precision
  24. final static boolean lowpass1_on = true; // on/off of first low pass filter
  25. final static boolean lowpass2_on = true; // on/off of second low pass filter
  26. final static boolean lowpass3_on = true; // on/off of third low pass filter
  27. // better don't touch it, lowpass filters are run in cascade
  28. float lowpass1_cutoff = 0.25; // percentage of rate
  29. float lowpass2_cutoff = 0.1;
  30. float lowpass3_cutoff = 0.05;
  31. boolean do_blend = true; // blend image after process
  32. int blend_mode = OVERLAY; // blend type
  33. // working buffer
  34. PGraphics buffer;
  35. // image
  36. //PImage img;
  37. // local variables
  38. float min_omega, max_omega;
  39. float min_phase_mult=0.05;
  40. float max_phase_mult=50.0;
  41. LowpassFilter lpf1, lpf2, lpf3;
  42. int[][] pxls;
  43. boolean negate = false;
  44. FM() {
  45. name = "fxFM";
  46. //img = loadImage(foldername+filename+fileext);
  47. params.add(new Param ("blend_mode", 11, new int[]{RANDOM}));
  48. params.add(new Param ("omega", 0, 1, new int[]{SIN, LINE}));
  49. params.add(new Param ("phase", 0, 1, new int[]{LINE, SIN, TAN, RAMPUPDOWN, RAMP}));
  50. params.get(0).randomize();
  51. params.get(1).randomize();
  52. params.get(2).randomize();
  53. buffer = createGraphics(renderer.width, renderer.height);
  54. buffer.beginDraw();
  55. buffer.noStroke();
  56. //buffer.smooth(8);
  57. //buffer.background(0);
  58. // buffer.image(renderer, 0, 0);
  59. buffer.endDraw();
  60. //img.loadPixels();
  61. min_omega = TWO_PI/(0.05*renderer.width);
  62. max_omega = TWO_PI/(300.0*renderer.width);
  63. float rate = 100000.0;
  64. lpf1 = new LowpassFilter(rate, lowpass1_cutoff*rate);
  65. lpf2 = new LowpassFilter(rate, lowpass2_cutoff*rate);
  66. lpf3 = new LowpassFilter(rate, lowpass3_cutoff*rate);
  67. rw = renderer.width;
  68. prepareData();
  69. }
  70. //float inc1, inc2;
  71. //float playSpeed = 4;
  72. /*
  73. void animate() {
  74. blend_mode = (int)params.get(0).value + 2;
  75. inc1+=playSpeed/400;
  76. inc2+=playSpeed/300;
  77. if ((frameCount % int(map(playSpeed, 0, 4, 15, 120))) == 0) {
  78. for (int i = 0; i < params.size(); i++)
  79. params.get(i).randomize();
  80. }
  81. params.get(1).setValue((sin(inc1)+1)/2);
  82. params.get(2).setValue((sin(inc2)+1)/2);
  83. }
  84. */
  85. void prepareData() {
  86. pxls = new int[3][renderer.pixels.length];
  87. for (int i=0; i<renderer.pixels.length; i++) {
  88. int cl = toColorspace(renderer.pixels[i], colorspace);
  89. pxls[0][i] = (cl >> 16) & 0xff;
  90. pxls[1][i] = (cl >> 8) & 0xff;
  91. pxls[2][i] = (cl) & 0xff;
  92. }
  93. }
  94. float omega, min_phase, max_phase;
  95. int rw, rh;
  96. void apply() {
  97. if (rw != renderer.width || rh != renderer.height) {
  98. rw = renderer.width;
  99. rh = renderer.height;
  100. min_omega = TWO_PI/(0.05*renderer.width);
  101. max_omega = TWO_PI/(300.0*renderer.width);
  102. prepareData();
  103. }
  104. buffer.setSize(renderer.width, renderer.height);
  105. omega = map(sqrt(params.get(1).value), 0, 1, min_omega, max_omega);
  106. float phase = map(sq(params.get(2).value), 0, 1, min_phase_mult, max_phase_mult);
  107. max_phase = phase * omega;
  108. min_phase = -max_phase;
  109. processImage();
  110. }
  111. void processImage() {
  112. buffer.beginDraw();
  113. buffer.loadPixels();
  114. int [][] dest_pxls = new int[3][renderer.pixels.length];
  115. if (first_channel_only) {
  116. arrayCopy(pxls[1], dest_pxls[1]);
  117. arrayCopy(pxls[2], dest_pxls[2]);
  118. }
  119. for (int i=0; i< (first_channel_only?1:3); i++) {
  120. for (int y=0; y<renderer.height; y++) {
  121. int off = y * renderer.width;
  122. //reset filters each line
  123. lpf1.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  124. lpf2.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  125. lpf3.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  126. float sig_int = 0; // integral of the signal
  127. float pre_m = 0; // previous value of modulated signal
  128. for (int x=0; x<renderer.width; x++) {
  129. /////////////////////////
  130. // FM part starts here
  131. /////////////////////////
  132. float sig = map(pxls[i][x+off], 0, 255, min_phase, max_phase); // current signal value
  133. sig_int += sig; // current value of signal integral
  134. float m = cos(omega * x + sig_int); // modulate signal
  135. if ( quantval > 0) {
  136. m = map((int)map(m, -1, 1, 0, quantval), 0, quantval, -1, 1); // quantize
  137. }
  138. float dem = abs(m-pre_m); // demodulate signal, derivative
  139. pre_m = m; // remember current value
  140. // lowpass filter chain
  141. if (lowpass1_on) dem = lpf1.lowpass(dem);
  142. if (lowpass2_on) dem = lpf2.lowpass(dem);
  143. if (lowpass3_on) dem = lpf3.lowpass(dem);
  144. // remap signal back to channel value
  145. int v = constrain( (int)map(2*(dem-omega), min_phase, max_phase, 0, 255), 0, 255);
  146. //////////////////////
  147. // FM part ends here
  148. //////////////////////
  149. dest_pxls[i][x+off] = negate?255-v:v;
  150. }
  151. }
  152. }
  153. for (int i=0; i<buffer.pixels.length; i++) {
  154. buffer.pixels[i] = fromColorspace(0xff000000 | (dest_pxls[0][i] << 16) | (dest_pxls[1][i] << 8) | (dest_pxls[2][i]), colorspace);
  155. }
  156. buffer.updatePixels();
  157. if (do_blend)
  158. buffer.blend(renderer, 0, 0, renderer.width, renderer.height, 0, 0, buffer.width, buffer.height, blend_mode);
  159. buffer.endDraw();
  160. renderer.beginDraw();
  161. renderer.image(buffer, 0, 0, renderer.width, renderer.height);
  162. renderer.endDraw();
  163. }
  164. //
  165. final int[] blends = {
  166. ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
  167. };
  168. class LowpassFilter {
  169. float alpha;
  170. float prev;
  171. public LowpassFilter(float rate, float hz) {
  172. alpha = 0.0;
  173. prev = 0.0;
  174. setFilter(rate, hz);
  175. }
  176. void setFilter(float rate, float hz) {
  177. float timeInterval = 1.0/rate;
  178. float tau = 1.0 / (hz * TWO_PI);
  179. alpha = timeInterval / (tau + timeInterval);
  180. }
  181. void resetFilter(float val) {
  182. prev = val;
  183. }
  184. void resetFilter() {
  185. resetFilter(0);
  186. }
  187. float lowpass(float sample) {
  188. float stage1 = sample * alpha;
  189. float stage2 = prev - (prev * alpha);
  190. prev = (stage1 + stage2);
  191. return prev;
  192. }
  193. float highpass(float sample) {
  194. return sample - lowpass(sample);
  195. }
  196. }
  197. }