# Reaction Diffusion Shader Implementation (problems)

**URL:** https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879
**Category:** Coding Questions
**Created:** [February 10, 2024, 1:32pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879 "2024-02-10T13:32:30Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![JorgeRando](https://avatars.discourse-cdn.com/v4/letter/j/cdc98d/32.png) [@JorgeRando](https://discourse.processing.org/u/JorgeRando)
#### Post date: [February 10, 2024, 1:32pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/1 "2024-02-10T13:32:30Z")

</div>

Hi there! I’m working on an implementation of the well-known reaction-diffusion model with p5 shaders. However, I’m experiencing issues because the model seems to work, but after a few iterations, it gets stuck and stops progressing. I don’t think it’s a performance issue since I’ve implemented it without shaders, and it doesn’t get stuck in the same way. Does anyone have any ideas on why this might be happening? I don’t think it’s a matter of miscalculating something. I suspect it might be related to the shaders, but honestly, I have no clue. Any insights would be greatly appreciated!

 ![Screenshot from 2024-02-10 14-32-00](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/f/8fcd00097fe70f2be378b043f8e0cc8fac01d6eb.png)

--------------------------------------------------- sketch.js ---------------------------------------------------------------------

```auto
let golShader;
let prevFrame;

function preload() {
  golShader = loadShader('gol.vert', 'gol.frag');
}

function setup() {
  
  createCanvas(400, 400, WEBGL);
  pixelDensity(1);
  noSmooth();
  background(255,0,0);
  stroke(0,0,255)
  
  fill(0,0,255)
  rect(0,0,50,50);
  shader(golShader);
  golShader.setUniform("normalRes", [1.0 / width, 1.0 / height]);
  
}

function draw() {
  
  golShader.setUniform('tex', get());
  rect(-width / 2, -height / 2, width, height);

}

```

------------------------------------------------------------gol.vert-------------------------------------------------------------------

```auto
attribute vec3 aPosition;
attribute vec2 aTexCoord;

varying vec2 vTexCoord;

void main() {
  // copy the texcoords
  vTexCoord = aTexCoord;

  vec4 positionVec4 = vec4(aPosition, 1.0);
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;

  gl_Position = positionVec4;
}

```

---------------------------------------------------------gol.frag---------------------------------------------------------

```auto
#ifdef GL_ES
precision mediump float;
#endif

varying vec2 vTexCoord;
uniform sampler2D tex;
uniform vec2 normalRes;

float laPlacian(vec2 uv, float m) {
  float laplacian = 0.0;
  float mult ;
  for (float i = -1.0; i < 2.0; i++) {
    for (float j = -1.0; j < 2.0; j++) {
      
      float x = uv.x + i * normalRes.x;
      float y = uv.y + j * normalRes.y;

      if (i == 0.0 && j == 0.0) {
        mult = -1.0;
      } else if (i == j || i == -j) {
        mult = 0.05;
      } else {
        mult = 0.2;
      }
      
      if (m == 0.0) {
         laplacian += texture2D(tex, vec2(x, y)).r * mult;
      } else {
         laplacian += texture2D(tex, vec2(x, y)).b * mult;
      }  
      
    }
  }

  return laplacian;
}

void main() {
  vec2 uv = vTexCoord;
  uv.y = 1.0 - uv.y;

  
  float Da = 1.0;
  float Db = 0.5;
  float f = 0.055;
  float k = 0.062;
  
  
  vec4 col = texture2D(tex, uv); 
  float a = col.r;
  float b = col.b;
  
  float new_a = a + Da * laPlacian(uv, 0.0) - a * b * b + f * (1.0 - a);
  float new_b = b + Db * laPlacian(uv, 1.0) + a * b * b - (k + f) * b;

  gl_FragColor = vec4(new_a, 0.0, new_b, 1.0);
}

```

---

<div class="post-metadata">

### Author: ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)
#### Post date: [February 10, 2024, 6:37pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/2 "2024-02-10T18:37:32Z")

</div>

You posted your javascript code twice instead of your glsl fragment code.

Having not seen your code, let me take a guess that it’s a numerical precision issue. On the CPU, perhaps you were using floats but on the shader you’re using color values which, although they are a float vec3 on the shader, are only stored as 8-bit colors in the framebuffer. If you try to add too small of a value to an 8-bit value, anything less than 1.0/256, it’ll just disappear.

---

<div class="post-metadata">

### Author: ![JorgeRando](https://avatars.discourse-cdn.com/v4/letter/j/cdc98d/32.png) [@JorgeRando](https://discourse.processing.org/u/JorgeRando)
#### Post date: [February 11, 2024, 11:18am UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/3 "2024-02-11T11:18:33Z")

</div>

Hi, thanks for the help. I’ve already fixed the post. I’m new to shader programming, and how can I increase the numerical precision of the buffer?

---

<div class="post-metadata">

### Author: ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)
#### Post date: [February 11, 2024, 6:27pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/4 "2024-02-11T18:27:47Z")

</div>

p5 now has a [Framebuffer](https://p5js.org/reference/#/p5/createFramebuffer) that supports float datatypes. I haven’t used it so can’t give you the details.

The problem with your code might not be precision, but that the default, byte-based images only support values from 0 to 1, whereas your math functions are assuming full floats with negative values. You could try subtracting 0.5 from each texture() call and adding 0.5 to the values before writing them to the gl\_FragColor.

Using float framebuffers is more likely the better solution.

---

<div class="post-metadata">

### Author: ![JorgeRando](https://avatars.discourse-cdn.com/v4/letter/j/cdc98d/32.png) [@JorgeRando](https://discourse.processing.org/u/JorgeRando)
#### Post date: [February 11, 2024, 7:15pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/5 "2024-02-11T19:15:08Z")

</div>

I just tried subtracting and adding 0.5, and it didn’t work ☹

```auto
#ifdef GL_ES
precision mediump float;
#endif

varying vec2 vTexCoord;
uniform sampler2D tex;
uniform vec2 normalRes;

float laPlacian(vec2 uv, float m) {
  float laplacian = 0.0;
  float mult ;
  for (float i = -1.0; i < 2.0; i++) {
    for (float j = -1.0; j < 2.0; j++) {
      
      float x = uv.x + i * normalRes.x;
      float y = uv.y + j * normalRes.y;

      if (i == 0.0 && j == 0.0) {
        mult = -1.0;
      } else if (i == j || i == -j) {
        mult = 0.05;
      } else {
        mult = 0.2;
      }
      
      if (m == 0.0) {
         laplacian += texture2D(tex, vec2(x, y)).r - 0.5 * mult;
      } else {
         laplacian += texture2D(tex, vec2(x, y)).b - 0.5 * mult;
      }  
      
    }
  }

  return laplacian;
}

void main() {
  
  vec2 uv = vTexCoord;
  uv.y = 1.0 - uv.y;

  
  float Da = 1.0;
  float Db = 0.5;
  float f = 0.055;
  float k = 0.062;
  
  
  vec4 col = texture2D(tex, uv); 
  float a = col.r - 0.5 ;
  float b = col.b - 0.5 ;
  
  float new_a = a + Da * laPlacian(uv, 0.0) - a * b * b + f * (1.0 - a);
  float new_b = b + Db * laPlacian(uv, 1.0) + a * b * b - (k + f) * b;

  gl_FragColor = vec4(new_a + 0.5, 0.0, new_b + 0.5, 1.0);
  
}

```

I suppose this is what you are referring to.

---

<div class="post-metadata">

### Author: ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)
#### Post date: [February 11, 2024, 7:51pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/6 "2024-02-11T19:51:14Z")

</div>

In the laplacian, you need parentheses around the `(texture2D().r - 0.5)` (and again for .b) before the `* mult`.

And subtracting 0.5 will give you values in the range from -0.5 to 0.5. You might need a greater range than that so you would also need to multiply when reading and divide before writing to scale up/down. I don’t know what the expected range of values is for the laplacian.

---

<div class="post-metadata">

### Author: ![JorgeRando](https://avatars.discourse-cdn.com/v4/letter/j/cdc98d/32.png) [@JorgeRando](https://discourse.processing.org/u/JorgeRando)
#### Post date: [February 12, 2024, 4:02pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/7 "2024-02-12T16:02:14Z")

</div>

Mmmm, according to the tests I have conducted in the iterative implementation, the values of ‘a’ and ‘b’ should always be in the range of 0 to 1.

---

<div class="post-metadata">

### Author: ![JorgeRando](https://avatars.discourse-cdn.com/v4/letter/j/cdc98d/32.png) [@JorgeRando](https://discourse.processing.org/u/JorgeRando)
#### Post date: [February 12, 2024, 9:38pm UTC](https://discourse.processing.org/t/reaction-diffusion-shader-implementation-problems/43879/9 "2024-02-12T21:38:44Z")

</div>

Here if I set the range of new\_a and new\_b from 0 to 1. Exactly the same thing happens

```auto
void main() {

 vec2 uv = vTexCoord;
 uv.y = 1.0 - uv.y;

 float Da = 1.0;
 float Db = 0.5;
 float f = 0.055;
 float k = 0.062;
 float scale_factor = 2.0; // Adjust this value based on your needs
 
 vec4 col = texture2D(tex, uv); 
 float a = col.r ;
 float b = col.b ;
 
 float new_a = a + Da * laPlacian(uv, 0.0, scale_factor) / scale_factor - a * b * b + f * (1.0 - a);
 float new_b = b + Db * laPlacian(uv, 1.0, scale_factor) / scale_factor + a * b * b - (k + f) * b;
 
 new_a = clamp(new_a, 0.0, 1.0);
 new_b = clamp(new_b, 0.0, 1.0);

 gl_FragColor = vec4(new_a , 0.0, new_b , 1.0);

}

```
