GLSL实现Runge Kutta求解薛定谔波模拟出现数值爆炸问题
问题原因排查
- 帧计数器实现错误
你使用#define frame (u_time*60.0)作为帧计数,本质是浮点数计算,受浏览器时间精度、掉帧影响非常容易出现跳变,会直接导致frame < 10的初始化逻辑没有执行够次数、甚至完全不执行,波函数初始值为缓冲的随机垃圾值,迭代几轮就会数值爆炸。而Shadertoy的iFrame是严格每帧+1的整数,不存在这个问题。 - 缓冲更新顺序错误
RK4求解要求每帧的缓冲更新顺序严格为BUFFER_1→BUFFER_2→BUFFER_3→BUFFER_0,如果GlslCanvas的默认缓冲更新顺序不符合这个逻辑,各k值采样到的是上一帧的错误结果,会导致迭代误差快速累积发散。 - 缓冲纹理参数不匹配
你仅确认了插值为NEAREST,但没有确认另外两个关键参数:
- 纹理封装模式如果是
REPEAT而非CLAMP_TO_EDGE,边界像素采样相邻点时会取到对侧的像素,直接破坏反射边界条件 - 缓冲格式如果是默认的8位RGBA整形而非32位浮点格式,波函数的浮点值会被截断,精度损失几帧就会触发数值异常
- CFL稳定性条件不满足
如果你的运行分辨率和原Shadertoy不一致,空间步长对应的时间步长上限会变化,固定的dt=0.25可能超出稳定范围,导致RK4迭代发散。
解决思路
- 替换帧计数器实现,新增一个每帧严格+1的整数uniform变量控制初始化逻辑,确保前10帧正确输出初始波函数
psi0 - 手动指定缓冲更新顺序为
BUFFER_1→BUFFER_2→BUFFER_3→BUFFER_0,最后执行主渲染通道 - 强制设置缓冲的纹理参数:封装模式为
CLAMP_TO_EDGE,缓冲格式为RGBA32F浮点格式 - 先把
dt降低到0.1测试,如果不再爆炸再逐步调大到合适的取值 - 单独调试初始波函数阶段,关闭RK4逻辑,确认初始的psi0输出和原Shadertoy一致后再打开迭代逻辑
内容的提问来源于stack exchange,提问作者buddhabrot
相关产品推荐
相关产品推荐

