我对 WEBGL 的工作方式不熟悉,所以我不明白为什么热方程不能像预期的那样工作。在我的片段着色器中,我使用了 2D 采样器 prevState 和纹理坐标 uv。使用具有公式的热方程,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),我把这个公式放在我的片段着色器中:
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);
但是,当我运行下面提到的 HTML + JavaScript 代码时,随着时间的推移,我没有得到一个扩散解决方案,热方程应该如何工作。相反,该函数会爆炸并扩散,形成菱形。
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>
我究竟做错了什么?