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);
  buffer1.noSmooth();
  buffer1.beginDraw();
  buffer1.blendMode(REPLACE);
  buffer1.endDraw();
  
  buffer2 = createGraphics(width, height, P2D);
  buffer2.noSmooth();
  buffer2.beginDraw();
  buffer2.blendMode(REPLACE);
  buffer2.endDraw();
  
  buffer3 = createGraphics(width, height, P2D);
  buffer3.noSmooth();
  buffer3.beginDraw();
  buffer3.blendMode(REPLACE);
  buffer3.endDraw();
  
  
  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];
  
  looping++;
  
  //println((looping+1)%loopSize);

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

  if(mousePressed)
  {
    BufferAShader.set("mouseInput", (float)mouseX, (float)height-mouseY);
  }
  else 
  {
    BufferAShader.set("mouseInput", -1, (float)height-mouseY);
  }
  
  BufferAShader.set("iChannel0", buffLast); 
  buffLast.beginDraw();
  buffLast.shader(BufferAShader); 
  buffLast.rect(0, 0, width, height);
  buffLast.endDraw();
  
  
  BufferBShader.set("iChannel0", buffLast);
  buffLast2.beginDraw();
  buffLast2.shader(BufferBShader);
  buffLast2.rect(0, 0, width, height);
  buffLast2.endDraw();


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

}

FiniteWater_Binding.glsl:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

#define PROCESSING_COLOR_SHADER

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));
}

FiniteWater_BufferA.glsl:

#ifdef GL_ES
precision highp float;
#endif

#define PROCESSING_COLOR_SHADER

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);
    return;
  }
  
  // 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);
    return;  
  }
  
  // just copy
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  //gl_FragColor = texture2D(iChannel0, uv);
  gl_FragColor = clamp(texture2D(iChannel0, uv), 0.0, 0.998);

}

FiniteWater_BufferB.glsl:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

// Type of shader expected by Processing
#define PROCESSING_COLOR_SHADER

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);



}