I am new to how WEBGL works so I do not understand why the Heat Equation is not working like it is supposed to. In my fragment shader, I used a sampler 2D, prevState, and a texture coordinate, uv. With the heat equation having the formula, U(i,j) += dT*(U(i,j+1)+U(i,j-1)+U(i+1,j)+U(i-1,j)-4*U(i,j))/(dX*dX), I put that formula in my fragment shader:
float u = texture2D(prevState, uv).r;
float lu = (texture2D(prevState, vec2(uv.x, uv.y + eps) ).r + texture2D(prevState, vec2(uv.x, uv.y - eps) ).r + texture2D(prevState, vec2(uv.x + eps, uv.y) ).r + texture2D(prevState, vec2(uv.x - eps, uv.y) ).r - 4.*u)/(eps * eps);
However, when I run the HTML + JavaScript code mentioned below, I do not get a diffusive solution over time, how the heat equation should work. Instead, the function blows up and spreads, forming a diamond shape.
function main(err, regl) {
const RAD = 2048
const h = 1/(RAD - 1);
var B = 0;
const pixels = new Float32Array(RAD * RAD * 4);
for(var i = 0; i < RAD; i++){
for(var j = 0; j < RAD; j++){
var x = h*(j - RAD/2), y = h*(i - RAD/2);
pixels[B++] = 30*Math.exp(-3000*(x*x + y*y));
pixels[B++] = 0;
pixels[B++] = 0;
pixels[B++] = 0;
}
}
const state = (Array(2)).fill().map(() =>
regl.framebuffer({
color: regl.texture({
radius: RAD,
data: pixels,
wrap: 'repeat'
}),
depthStencil: false
}))
const doHeatEq = regl({
frag: `
precision mediump float;
uniform sampler2D prevState;
varying vec2 uv;
const float eps = 1./2047., dt = .000001;
void main() {
float u = texture2D(prevState, uv).r;
float lu = (texture2D(prevState, vec2(uv.x, uv.y + eps) ).r + texture2D(prevState, vec2(uv.x, uv.y - eps) ).r + texture2D(prevState, vec2(uv.x + eps, uv.y) ).r + texture2D(prevState, vec2(uv.x - eps, uv.y) ).r - 4.*u)/(eps * eps);
u += dt * lu;
gl_FragColor = vec4(u, 0., 0., 0. );
}`,
framebuffer: ({tick}) => state[(tick + 1) % 2]
})
const colorset = regl({
frag: `
precision mediump float;
uniform sampler2D prevState;
varying vec2 uv;
void main() {
float val = texture2D(prevState, uv).r;
gl_FragColor = vec4(vec3(abs(val)), 1.);
}`,
vert: `
precision mediump float;
attribute vec2 position;
varying vec2 uv;
void main() {
uv = 0.5 * (position + 1.0);
gl_Position = vec4(position, 0, 1);
}`,
attributes: {
position: [ -4, -4, 4, -4, 0, 4 ]
},
uniforms: {
prevState: ({tick}) => state[tick % 2]
},
depth: { enable: false },
count: 3
})
regl.frame(() => {
colorset(() => {
regl.draw()
doHeatEq()
})
})
}
// initialize regl
createREGL({
extensions: 'OES_texture_float',
// callback when regl is initialized
onDone: main,
});
<!DOCTYPE html>
<title>Heat Equation</title>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/regl/1.3.11/regl.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
</body>
What am I doing wrong?