alexr4 / datamoshing-GLSL

Quick experiments on datamoshing effect using GPU optical flow approach
GNU General Public License v3.0
16 stars 1 forks source link

little improvement #2

Open knupel opened 5 years ago

knupel commented 5 years ago

Just a quick improvement to gain 1 or 2 fps ! It's not necessary to create a PGraphics previous. Pass directly datamoshBuffer and at the end filter the result to reverse totaly and back to normal situation.

import processing.video.*;

Movie movie;
PGraphics current, previous;
boolean type;
// String file1 = "datamosh-1";
String file1 = "datamosh3x3-5x5";
String file2 = "datamosh3x3-5x5";
PShader datamosh;
PShader flip;
PGraphics datamoshBuffer;

void settings() {
  size(1920, 752, P3D);
}

void setup() {
  movie = new Movie(this, "movieFromCoverr.mp4");
  movie.loop();

  datamosh = loadShader(file1+".glsl");
  flip = loadShader("flip.glsl");
  datamosh.set("resolution", (float)width, (float)height);

  current = createGraphics(width, height, P2D);
  previous = createGraphics(width, height, P2D);
  datamoshBuffer = createGraphics(width, height, P2D);

  frameRate(30);
}

void draw() {

  if (movie.available()) {
    movie.read(); // Read the new frame from the camera
    image(movie,0,0);
    // current.beginDraw();
    // current.image(movie, 0.0, 0.0, width, height);
    // current.endDraw();
  }

  if (current != null) {
    try {
      float threshold = noise(millis() * 0.0001, frameCount * 0.01) * 0.15;
      float offsetRGB = noise(frameCount * 0.0125, millis() * 0.005) * 0.005;

      // datamosh.set("previous", previous);
      datamosh.set("previous", datamoshBuffer);
      datamosh.set("threshold", threshold);
      datamosh.set("offsetRGB", offsetRGB);

      datamoshBuffer.beginDraw();
      datamoshBuffer.shader(datamosh);
      datamoshBuffer.image(movie, 0, 0);
      //datamoshBuffer.image(current, 0, 0);
      datamoshBuffer.endDraw();

      image(datamoshBuffer, 0, 0);
    }
    catch(Exception e) {
      e.printStackTrace();
    }

    flip.set("texture_source",g);
    flip.set("resolution_source",width,height);
    flip.set("flip_source",true,false);
    filter(flip);
/*
    previous.beginDraw();
    previous.image(datamoshBuffer, 0, 0, previous.width, previous.height);
    //previous.image(current, 0, 0, previous.width, previous.height);
    previous.endDraw();
    */
  }
}

void keyPressed() {
  if (key == 'r') {
    type = !type;
    try {
      if (type) {
        datamosh = loadShader(file2+".glsl");
      } else {
        datamosh = loadShader(file1+".glsl");
      }
      datamosh.set("resolution", (float)width, (float)height);
      println("shader reload");
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
}

reverse uv.y on the datamosh.glsl

vec2 getFlow5x5(vec2 uv) {
  flow += getFlow(uv.xy + vec2(-2.0, -2.0) * texel) * 0.125;
  .../...
}
void main() {
    vec2 uv = vertTexCoord.xy;
    uv.y = 1. -uv.y; 

    vec2 flow = getFlow5x5(uv);
    float flowMag = length(flow.xy);

    float stepper = step(threshold, flowMag);
    flow.x = clamp(flow.x, -1.0, 1.0);
    flow.y = clamp(flow.y, -1.0, 1.0);

    vec2 st;
    vec2 texel = vec2(1.0) / resolution;
    st.x = uv.x + flow.x * texel.x * intensity;
    st.y = uv.y + flow.y * texel.y * intensity;

    //shift rgb
    vec2 shift = vec2(cos(flow.x * PI + time * 0.1), sin(flow.y * PI + time * 0.1)) * offsetRGB;
    float r = texture(previous, st + shift).r;
    float g = texture(previous, st ).g;
    float b = texture(previous, st - shift).b;

    vec4 datamosh = texture(previous, st);
    datamosh.rgb = vec3(r, g, b) * stepper;

    vec4 color = texture(texture, uv.st);

    fragColor =  color * (1.0 - stepper) + datamosh * stepper;;
}

flip.glsl

/**
* flip POST FX
* @see http://stanlepunk.xyz
* @see https://github.com/StanLepunK/Shader
* v 0.0.12
* 2018-2019
*/
// Processing implementation
#ifdef GL_ES
precision highp float;
#endif
#define PROCESSING_TEXTURE_SHADER
varying vec4 vertColor;
varying vec4 vertTexCoord;
uniform vec2 resolution; // WARNING VERY IMPORTANT // need this name for unknow reason :( here your pass your resolution texture
// vec2 texOffset   = vec2(1) / resolution; // only work with uniform resolution

// Rope implementation
uniform sampler2D texture_source;
uniform vec2 resolution_source;
uniform bvec2 flip_source; // can be use to flip texture source

// UTIL TEMPLATE
vec2 set_uv(bool flip_vertical, bool flip_horizontal, vec2 res) {
  vec2 uv;
  if(all(equal(vec2(0),res))) {
    uv = vertTexCoord.st;
  } else if(all(greaterThan(res,vertTexCoord.st))) {
    uv = vertTexCoord.st;
  } else {
    uv = res;
  }
  // flip 
  if(!flip_vertical && !flip_horizontal) {
    return uv;
  } else if(flip_vertical && !flip_horizontal) {
    uv.y = 1 -uv.y;
    return uv;
  } else if(!flip_vertical && flip_horizontal) {
    uv.x = 1 -uv.x;
    return uv;
  } else if(flip_vertical && flip_horizontal) {
    return vec2(1) -uv;
  } return uv;
}

vec2 set_uv(bvec2 flip, vec2 res) {
  return set_uv(flip.x,flip.y,res);
}

vec2 set_uv() {
  return set_uv(false,false,vec2(0));
}

void main() {
  vec2 uv = set_uv(flip_source,resolution_source);
  gl_FragColor = texture2D(texture_source,uv);
}
alexr4 commented 5 years ago

Thanks for the tips but I set a previous PGraphics in order to change the source. You can get an interesting result if you set the previous texture as the current and not the datamosh buffer

Your flip.glsl can be useful to handle PGraphics/PImage UV situation but i If/Else statements be have performance issue on older GPU. I will recommend to use mathematical condition (step, min, max... operations) or preprocessor condition to avoid it.

Here some informations about it :

knupel commented 5 years ago

thanks for the info-link el professor del glsl! It's my syntax if-else from Processing... i must improve that for glsl coding for the future !!!!

alexr4 commented 5 years ago

ahaha no problem ;)

There are differents solutions. For exemple you can set a flag using a step operator :

uniform int uvflag; //0 nothing, 1 invert)

float cond = step(0.1, uvflag);
uv.y = uv.y * cond +(1.0 - uv.y) * (1.0 - cond);

Usually a test if my texture is an PImage or a PGraphics in java using :

public boolean isPImage(PImage src) {
        if(src instanceof PGraphics) {
            return false;
        }else {
            return true;
        }
    }
knupel commented 5 years ago

thx for the code, because I try to understand, but i was little lost :) now with your code is perfect. BIG UP !!!!

alexr4 commented 5 years ago

Sure no problem. I know how mathematical condition can be tricky to conceive ;)

knupel commented 5 years ago

That's work like a charm !!!! But after test it's necessary to invert the uv.y

vec2 set_uv(int flip_vertical, int flip_horizontal, vec2 res) {
  vec2 uv;
  if(all(equal(vec2(0),res))) {
    uv = vertTexCoord.st;
  } else if(all(greaterThan(res,vertTexCoord.st))) {
    uv = vertTexCoord.st;
  } else {
    uv = res;
  }
  // flip 
  float condition_y = step(0.1, flip_vertical);
  uv.y = 1.0 -(uv.y *condition_y +(1.0 -uv.y) *(1.0 -condition_y));

  float condition_x = step(0.1, flip_horizontal);
  uv.x = uv.x *condition_x +(1.0 -uv.x) *(1.0 -condition_x);

  return uv;
}

PS : what the tip to add color in your code post ?