Trying to convert shadertoy 'ping pong feedback' buffer(?) to Processing

Hi @scudly ,

Thanks for your helpful reply. I really learn a lot. You mention about the precision difference of the Shadertoy and Processing, which, I think, is critical to the conversion of the Shadertoy shader to Processing. I have experienced similar case and posed in here.

I assume that shadertoy uses full 32-bit floats for the buffer/channels.

Does this mean the temporary texture map to swap and be written between different passes is a 32-bit-float map, which it is something like this in some game engine such as the Unity (just to get an analogy), the Processing only supports 8-bit-float map as the temporary map to let processing’s shader to write ? but the processing temporary texture map has alpha channel, so this is a different topic?

I am not quite getting this:

That shadertoy stores a value in the red channel and a velocity in the green.

Processing always multiplies the rgb by the alpha channel, so to get data out of a shader, you have to always set alpha to 1. This implies that you can get at most 24 bits of data per pixel out of a shader.

I am a bit confused, would you give a bit more information on this or some readings? :slight_smile:

In addition, I got the Processing4 version and run the code. It seems to get a very low frame rate on my poor 5 years old surface laptop. :joy:Is this causing by the new string array feature?

This is rendering on1200x900.

This is rendering on 800x600:

This is rendering on a decent desktop, but the frame rate seems to get limiting on 30 fps:

And the spreading ripples will turn into rectangle shape from its initial circle shape , so is it the processing’s problem on executing the shader?

Inspired by your code, I am trying to run my code on the processing 3.5 with a little bit modification ( just trying not to modify much on the original shadertoy code) but it seems to get some channel issues. Is there a way to fix? :slight_smile:

The frame rate seems to be very good with the shader file loading method.

Here is my code:
the Processing code:

PShader BufferAShader;
PShader BufferBShader;
PShader BindShader;
PGraphics buffer1, buffer2, buffer3;
int looping = 0;

void setup()
  size(800, 600, P3D);
  buffer1 = createGraphics(width, height, P2D);
  buffer2 = createGraphics(width, height, P2D);
  buffer3 = createGraphics(width, height, P2D);
  BufferAShader = loadShader("FiniteWater_BufferA.glsl");
  BufferAShader.set("iResolution", float(width), float(height));

  BufferBShader = loadShader("FiniteWater_BufferB.glsl");
  BufferBShader.set("iResolution", float(width), float(height));
  BindShader = loadShader("FiniteWater_Binding.glsl");
  BindShader.set("iResolution", float(width), float(height));

void draw()
  PGraphics buffTemp = null;
  PGraphics buffLast = null;
  PGraphics buffLast2 = null;
  int loopSize = 3;
  PGraphics[] buffs = {buffer1, buffer2, buffer3};
  buffTemp = buffs[looping%loopSize];
  buffLast = buffs[(looping+1)%loopSize];
  buffLast2 = buffs[(looping+2)%loopSize];

  BufferAShader.set("iTime", millis()/1000.);

    BufferAShader.set("mouseInput", (float)mouseX, (float)height-mouseY);
    BufferAShader.set("mouseInput", -1, (float)height-mouseY);
  BufferAShader.set("iChannel0", buffLast); 
  buffLast.rect(0, 0, width, height);
  BufferBShader.set("iChannel0", buffLast);
  buffLast2.rect(0, 0, width, height);

  BindShader.set("iChannel0", buffLast2);
  //BindShader.set("iChannel0", buffLast);
  buffTemp.rect(0, 0, width, height);
  image(buffTemp, 0, 0);



#ifdef GL_ES
precision mediump float;
precision mediump int;


uniform vec2 iResolution;
uniform sampler2D iChannel0;

void main()
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  //gl_FragColor = vec4(2.0*texture2D(iChannel0, uv).x + 0.5);
  gl_FragColor = vec4(clamp(texture2D(iChannel0, uv).x, 0.0, .998));


#ifdef GL_ES
precision highp float;


uniform float iTime;
uniform vec2 iResolution;

uniform vec2 mouseInput;
//vec4 iMouse = vec4(mouseInput, 0.0, 0.0);
vec4 iMouse = vec4(mouseInput, mouseInput);
uniform sampler2D iChannel0;

void main()
  // Mouse excitation
  vec2 r = gl_FragCoord.xy - iMouse.xy;
  float d = 0.001 * dot(r, r);
  if(iMouse.z > 0.0 && d < 0.05)
    gl_FragColor = vec4(0.0, 0.2, 0.0, 0.0);
  // Periodic excitation
  r = gl_FragCoord.xy - vec2(50, 70);
  d = 0.001 * dot(r, r);
  if(mod(iTime, 0.5) < 0.1 && d < 0.05)
    gl_FragColor = vec4(0.0, 0.1, 0.0, 0.0);
  // just copy
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  //gl_FragColor = texture2D(iChannel0, uv);
  gl_FragColor = clamp(texture2D(iChannel0, uv), 0.0, 0.998);



#ifdef GL_ES
precision mediump float;
precision mediump int;

// Type of shader expected by Processing

uniform vec2 iResolution;
uniform sampler2D iChannel0;

void main()
  float dx = 1.0 / iResolution.x;
  float dy = 1.0 / iResolution.y;
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  vec2 udu = texture2D(iChannel0, uv).xy;
  // old elevation
  float u = udu.x;
  // old velocity
  float du = udu.y;
  // Finite differences
  float ux  = texture2D(iChannel0, vec2(uv.x + dx, uv.y)).x;
  float umx = texture2D(iChannel0, vec2(uv.x - dx, uv.y)).x;
  float uy  = texture2D(iChannel0, vec2(uv.x, uv.y + dy)).x;
  float umy = texture2D(iChannel0, vec2(uv.x, uv.y - dy)).x;
  // new elevation
  float nu = u + du + 0.5*(umx+ux+umy+uy-4.0*u);
  nu = 0.99*nu;

  nu = clamp(nu, 0.0, 1.0);
  // store elevation and velocity
  gl_FragColor = vec4((1.0-nu)*0.998, (1.0-(nu-u))*0.998, 0.0, 1.0);
  //gl_FragColor = vec4((1.0-nu)*0.998, (1.0-(nu-u))*0.998, 0.0, 0.0);
  //gl_FragColor = vec4(nu, nu-u, 0.0, 0.0);