How to fix the problem on converting ShaderToy color to Processing?

38 Views Asked by At

I am trying to convert this ShaderToy shader https://www.shadertoy.com/view/XsG3z1 to the Processing, but the processing seems to have different color channel, as shown below:

In Shadertoy shader by using this section:

// Ultra simple version, minus the window dressing.
void mainImage(out vec4 fragColor, in vec2 fragCoord){
    fragColor = 1. - texture(iChannel0, fragCoord/iResolution.xy).wyyw;
}

It results black pattern and greenish background.ShaderToy ultra simple version But in the Processing shader, using the same line of code it will get a grey image without any pattern.

If in Processing it's using this line:

// Ultra simple version, minus the window dressing.
void main()
{
  gl_FragColor = texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).wyyw;
}

it will get red background and whitish pattern

If in Processing it's using this line of code:

// Ultra simple version, minus the window dressing.
void main()
{
  gl_FragColor = 1.0 - texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).zxxz;
}

it will get blue background and redish pattern

But, interestingly, if it is using the full version of the shadertoy code, the Processing rendering result will appear approximately the same as the Shadertoy result.

So would anyone like to explain a little bit how these two system color channel float precision and its range work and the differences (sorry, trying my best to use the terms with my limited knowledge, bear in mind if I am descript it wrong)? how to solve this issue in converting the Shadertoy shader?

Here is the simple version, BTW, I'm using the Processing 3.5

The Processing code:

PShader BufferAShader;
PShader ImageShader;
PGraphics buffer1, buffer2;
int looping = 0;

void setup()
{
  size(800, 450, 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();
  
  BufferAShader = loadShader("ReactionDiffusion_BufferA.glsl");
  BufferAShader.set("iResolution", float(width), float(height)); 
  
  ImageShader = loadShader("ReactionDiffusion_Image.glsl");
  ImageShader.set("iResolution", float(width), float(height)); 

}

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

  BufferAShader.set("iFrame", frameCount);
  BufferAShader.set("iTime", millis()/1000.0);
  BufferAShader.set("iChannel0", buffTemp); 
  buffLast.beginDraw();
  buffLast.shader(BufferAShader); 
  buffLast.rect(0, 0, width, height);
  buffLast.endDraw();
  
  ImageShader.set("iChannel0", buffLast);
  buffTemp.beginDraw();  
  buffTemp.shader(ImageShader);
  buffTemp.rect(0, 0, width, height);
  buffTemp.endDraw();
  
  image(buffTemp, 0, 0);

 
  
}

ReactionDiffusion_BufferA.glsl:

#ifdef GL_ES
precision highp float;
#endif

#define PROCESSING_COLOR_SHADER

uniform int iFrame;
uniform float iTime;

uniform vec2 iResolution;
uniform sampler2D iChannel0;

vec3 hash33(in vec2 p)
{
  float n = sin(dot(p, vec2(41.0, 289.0)));
  return fract(vec3(2097151.0, 262144.0, 32768.0)*n);
}

vec4 tx(in vec2 p)
{
  return texture2D(iChannel0, p);
}

// Weighted blur function. Pretty standard
float blur(in vec2 p)
{
  // Used to move to adjoining pixels. - uv + vec2(-1, 1)*px, uv + vec2(1, 0)*px, etc.
  vec3 e = vec3(1.0, 0.0, -1.0);
  vec2 px = 1.0 / iResolution.xy;
  
  // Weighted 3x3 blur, or a cheap and nasty Gaussian blur approximation.
  float res = 0.0;    
  // Four corners. Those receive the least weight.
  res += tx(p + e.xx*px).x + tx(p + e.xz*px).x + tx(p + e.zx*px).x + tx(p + e.zz*px).x;
  // Four sides, which are given a little more weight.
  res += (tx(p + e.xy*px).x + tx(p + e.yx*px).x + tx(p + e.yz*px).x + tx(p + e.zy*px).x)*2.0;
  // The center pixel, which we're giving the most weight to, as you'd expect.
  res += tx(p + e.yy*px).x*4.0;
  // Normalizing.
  return res/16.0; 
}


// The reation diffusion loop.
//
void main()
{
  vec2 uv = gl_FragCoord.xy/iResolution.xy; // Screen coordinates. Range: [0, 1]
  vec2 pw = 1.0/iResolution.xy; // Relative pixel width. Used for neightboring pixels, etc.
  
  float avgReactDiff = blur(uv);
  

  vec3 noise = hash33(uv + vec2(53.0, 43.0)*iTime)*0.6 + 0.2;  
  
  // Used to move to adjoining pixels. - uv + vec2(-1, 1)*px, uv + vec2(1, 0)*px, etc.
  vec3 e = vec3(1.0, 0.0, -1.0);
  
  // Gradient epsilon value. The "1.5" figure was trial and error, but was based on the 3x3 blur radius.
  vec2 pwr = pw*1.5;
  
  // Gradient of the blurred pixels from the previous frame.
  vec2 lap = vec2(tx(uv + e.xy*pwr).y - tx(uv - e.xy*pwr).y, tx(uv + e.yx*pwr).y - tx(uv - e.yx*pwr).y);
  
  // Add some diffusive expansion, scaled down to the order of a pixel width.
  uv = uv + lap*pw*3.0;
  
  // Stochastic decay. Ie: A differention equation, influenced by noise.
  float newReactDiff = tx(uv).x + (noise.z - 0.5)*0.0025 - 0.002;
  
  // Reaction-diffusion.
  newReactDiff += dot(tx(uv + (noise.xy - 0.5)*pw).xy, vec2(1.0, -1.0))*0.145;
  
  // be enough, but for some weird reason, it doesn't always get stored on the very first frame.
  if(iFrame>9) gl_FragColor.xy = clamp(vec2(newReactDiff, avgReactDiff/0.98), 0.0, 1.0);
  else gl_FragColor = vec4(noise, 1.0);

} 

ReactionDiffusion_Image.glsl:


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

#define PROCESSING_COLOR_SHADER

uniform vec2 iResolution;
uniform sampler2D iChannel0;


// Ultra simple version, minus the window dressing.
void main()
{
  //gl_FragColor = 1.0 - texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).wyyw;
  //gl_FragColor = texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).wyyw;
  gl_FragColor = 1.0 - texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).zxxz;

}

Here is the full version, if anyone would like to try. BTW, I'm using the Processing 3.5

The Processing code:

PShader BufferAShader;
PShader ImageShader;
PGraphics buffer1, buffer2;
int looping = 0;

void setup()
{
  size(800, 450, 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();
  
  BufferAShader = loadShader("ReactionDiffusion_BufferA.glsl");
  BufferAShader.set("iResolution", float(width), float(height)); 
  
  ImageShader = loadShader("ReactionDiffusion_Image.glsl");
  ImageShader.set("iResolution", float(width), float(height)); 

}

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

  BufferAShader.set("iFrame", frameCount);
  BufferAShader.set("iTime", millis()/1000.0);
  BufferAShader.set("iChannel0", buffTemp); 
  buffLast.beginDraw();
  buffLast.shader(BufferAShader); 
  buffLast.rect(0, 0, width, height);
  buffLast.endDraw();
  
  //image(buffLast, 0, 0);
  
  ImageShader.set("iTime", millis()/1000.0);  // warm color version uniform float variables
  ImageShader.set("iChannel0", buffLast);
  buffTemp.beginDraw();
  buffTemp.shader(ImageShader);
  buffTemp.rect(0, 0, width, height);
  buffTemp.endDraw();
  
  image(buffTemp, 0, 0);

 
  
}

ReactionDiffusion_BufferA.glsl:


#ifdef GL_ES
precision highp float;
#endif

#define PROCESSING_COLOR_SHADER

uniform int iFrame;
uniform float iTime;

uniform vec2 iResolution;
uniform sampler2D iChannel0;

// Cheap vec2 to vec3 hash. Works well enough, but there are other ways.
vec3 hash33(in vec2 p)
{
  float n = sin(dot(p, vec2(41.0, 289.0)));
  return fract(vec3(2097151.0, 262144.0, 32768.0)*n);
}

// Serves no other purpose than to save having to write this out all the time. I could write a 
// "define," but I'm pretty sure this'll be inlined.
vec4 tx(in vec2 p)
{
  return texture2D(iChannel0, p);
}

// Weighted blur function. Pretty standard
float blur(in vec2 p)
{
  // Used to move to adjoining pixels. - uv + vec2(-1, 1)*px, uv + vec2(1, 0)*px, etc.
  vec3 e = vec3(1.0, 0.0, -1.0);
  vec2 px = 1.0 / iResolution.xy;
  
  // Weighted 3x3 blur, or a cheap and nasty Gaussian blur approximation.
  float res = 0.0;    
  // Four corners. Those receive the least weight.
  res += tx(p + e.xx*px).x + tx(p + e.xz*px).x + tx(p + e.zx*px).x + tx(p + e.zz*px).x;
  // Four sides, which are given a little more weight.
  res += (tx(p + e.xy*px).x + tx(p + e.yx*px).x + tx(p + e.yz*px).x + tx(p + e.zy*px).x)*2.0;
  // The center pixel, which we're giving the most weight to, as you'd expect.
  res += tx(p + e.yy*px).x*4.0;
  // Normalizing.
  return res/16.0; 
}


// The reation diffusion loop.
//
void main()
{
  vec2 uv = gl_FragCoord.xy/iResolution.xy; // Screen coordinates. Range: [0, 1]
  vec2 pw = 1.0/iResolution.xy; // Relative pixel width. Used for neightboring pixels, etc.
  
  float avgReactDiff = blur(uv);

  vec3 noise = hash33(uv + vec2(53.0, 43.0)*iTime)*0.6 + 0.2;  
  
  // Used to move to adjoining pixels. - uv + vec2(-1, 1)*px, uv + vec2(1, 0)*px, etc.
  vec3 e = vec3(1.0, 0.0, -1.0);
  
  // Gradient epsilon value. The "1.5" figure was trial and error, but was based on the 3x3 blur radius.
  vec2 pwr = pw*1.5;
  
  // Gradient of the blurred pixels from the previous frame.
  vec2 lap = vec2(tx(uv + e.xy*pwr).y - tx(uv - e.xy*pwr).y, tx(uv + e.yx*pwr).y - tx(uv - e.yx*pwr).y);
  
  // Add some diffusive expansion, scaled down to the order of a pixel width.
  uv = uv + lap*pw*3.0;
  
  float newReactDiff = tx(uv).x + (noise.z - 0.5)*0.0025 - 0.002;
  
  // Reaction-diffusion.
  newReactDiff += dot(tx(uv + (noise.xy - 0.5)*pw).xy, vec2(1.0, -1.0))*0.145;
  
  // be enough, but for some weird reason, it doesn't always get stored on the very first frame.
  if(iFrame>9) gl_FragColor.xy = clamp(vec2(newReactDiff, avgReactDiff/0.98), 0.0, 1.0);
  else gl_FragColor = vec4(noise, 1.0);

}

ReactionDiffusion_Image.glsl:

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

#define PROCESSING_COLOR_SHADER

uniform vec2 iResolution;
uniform sampler2D iChannel0;

/*
// Ultra simple version, minus the window dressing.
void main()
{
  //gl_FragColor = texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).wyyw;
  gl_FragColor = 1.0 - texture2D(iChannel0, gl_FragCoord.xy/iResolution.xy).zxxz;

}
*/


// warm color version
uniform float iTime;

void main()
{
  // screen coordinates
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  

  float c = 1. - texture2D(iChannel0, uv).y;

  float c2 = 1.0 - texture(iChannel0, uv + 0.5 / iResolution.xy).y; 
  
  

  float pattern = -cos(uv.x*0.75*3.14159 - 0.9)*cos(uv.y*1.5*3.14159 - 0.75)*0.5 + 0.5;

  vec3 col = pow(vec3(1.5, 1.0, 1.0)*c, vec3(1.0, 2.25, 6.0));
  col = mix(col, col.zyx, clamp(pattern - 0.2, 0.0, 1.0));
  
 
  col += vec3(0.6, 0.85, 1.0)*max(c2*c2 - c*c, 0.0)*12.0;
  

  col *= pow(16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.125)*1.15;
  

  col *= smoothstep(0.0, 1.0, iTime/2.0);
  

  gl_FragColor = vec4(min(col, 1.0), 1.0);
  

}

So would anyone like to explain a little bit how these two system color channel float precision and its range work and the differences (sorry, trying my best to use the terms with my limited knowledge, bear in mind if I am descript it wrong)? how to solve this issue in converting the Shadertoy shader?

0

There are 0 best solutions below