I’m writing a reaction diffusion simulation with p5js based on a video and this tutorial. The code so far is this:
var vertSrc = `
#ifdef GL_ES
precision mediump float;
#endif
attribute vec3 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
varying vec2 vTexCoord;
void main() {
vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
gl_Position = uProjectionMatrix * viewModelPosition;
vTexCoord = aTexCoord;
}
`;
var fragSrc = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D uTexture;
uniform vec2 uTexSize;
uniform float uDiffuRateA;
uniform float uDiffuRateB;
uniform float uFeedRate;
uniform float uKillRate;
varying vec2 vTexCoord;
vec2 laplacian(vec2 coord) {
vec2 sum = vec2(0.0);
mat3 kernel = mat3(
0.05, 0.20, 0.05,
0.20, -1.0, 0.20,
0.05, 0.20, 0.05
);
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
vec2 offset = vec2(float(i), float(j)) / uTexSize;
sum += texture2D(uTexture, coord + offset).rg * kernel[i+1][j+1];
}
}
return sum;
}
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
float A = color.r;
float B = color.g;
vec2 laplacianAB = laplacian(vTexCoord);
float reaction = A * B * B;
float feed = uFeedRate * (1.0 - A);
float kill = (uKillRate + uFeedRate) * B;
float dA = A + (uDiffuRateA * laplacianAB.r) - reaction + feed;
float dB = B + (uDiffuRateB * laplacianAB.g) + reaction - kill;
dA = clamp(dA, 0.0, 1.0);
dB = clamp(dB, 0.0, 1.0);
gl_FragColor = vec4(dA, dB, 0.0, 1.0);
}
`
var default_shader;
var cur_texture;
var buffer;
function preload() {
default_shader = createShader(vertSrc, fragSrc);
}
function setup() {
createCanvas(window.innerWidth, window.innerHeight, WEBGL);
cur_texture = createFramebuffer({ channels: RGB, depth: false, textureFiltering: LINEAR });
buffer = createFramebuffer({ channels: RGB, depth: false, textureFiltering: LINEAR });
cur_texture.begin();
background("#f00");
fill("#0f0");
circle(0, 0, 100);
cur_texture.end();
shader(default_shader);
default_shader.setUniform("uTexSize", [cur_texture.width, cur_texture.height]);
default_shader.setUniform("uDiffuRateA", 1.0);
default_shader.setUniform("uDiffuRateB", 0.5);
default_shader.setUniform("uFeedRate", 0.055);
default_shader.setUniform("uKillRate", 0.062);
noStroke();
}
function draw() {
buffer.begin();
background(0);
default_shader.setUniform("uTexture", cur_texture);
plane(width, height);
buffer.end();
let temp = cur_texture;
cur_texture = buffer;
buffer = temp;
default_shader.setUniform("uTexture", cur_texture);
plane(width, height);
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
</head>
</html>
Insted of interesting patterns I get a green ring. The result is similar to this other question, but I don’t think p5js has a RGBA32F
format for the buffers.
Changing the parameters does produce different effects but none similar to what I was expecting. For example, setting uDiffuRateA
to 2 eventually fills the screen with green.