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