
用 Three.js 实现流体模拟中的液体扩散效果
来源标题:Spreading Liquid with Three.js
Three.js 通过流体模拟生成的流速图,记录屏幕上每个位置的运动方向和幅度。实现时先采样当前像素的厚度与速度,按速度计算应移走的厚度并减去,再用回溯采样完成平流步骤。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
流体模拟生成的速度图记录了屏幕上每个位置的运动方向和幅度。 首先,我对当前像素处的厚度和速度进行采样。 根据速度,我计算出应该有多少厚度移走,并从原始厚度中减去这个量。 float previousHeight = texture2D(heightMap, vUv).r; vec2 flow = texture2D(velocity, vUv).xy; float previousStrength = smoothstep( velocityThreshold.x, velocityThreshold.y, length(flow) ); float removed = min( previousHeight, previousStrength * 0.3 * previousHeight ); removed 就是从当前像素减去的厚度量。 接下来,我使用平流(advection),这在上篇流体模拟文章中也出现过。 我从当前像素沿速度反向追溯,并在来源位置采样厚度。 以下是 backtraceUv() 的实现,它根据当前 UV、速度和经过的时间计算来源 UV。 vec2 backtraceUv(vec2 uv, vec2 flow, vec2 fboSize, float dt) { vec2 ratio = max(fboSize.x, fboSize.y) / fboSize; vec2 velocityRatio = fboSize / min(fboSize.x, fboSize.y); return uv - flow * velocityRatio * dt * ratio; height.frag vec2 sourceUv = backtraceUv(vUv, flow, fboSize, dt); float sourceHeight = texture2D(heightMap, sourceUv).r; float sourceStrength = smoothstep( velocityThreshold.x, velocityThreshold.y, length(texture2D(velocity, sourceUv).xy) ); float added = min( sourceHeight, sourceStrength * 0.3 * sourceHeight ); vUv 是当前像素的位置。sourceUv 是沿速度反向追溯找到的位置。 backtraceUv() 函数利用速度和时间步长 dt 来计算该位置。 added 是从来源位置带到当前像素的厚度。 最后,我从当前厚度中减去 removed,再加上 added,以更新高度图。 float nextHeight = max(0.0, previousHeight - removed + added); gl_FragColor = vec4(nextHeight, 0.0, 0.0, 1.0); 结果写入 gl_FragColor 的 R 通道。G 和 B 通道为 0,A 通道为 1。 后续的 alpha 贴图和渲染 shader 通过 texture2D(heightMap, vUv).r 读取这个值。 这样一来,每个像素都会失去一部分厚度,同时从反向追溯的来源位置获得厚度。 我还使用了 smoothstep(),使得速度较小时厚度几乎不移动。 这可以防止静止区域不断流动,并将运动集中在受拖拽影响的区域周围。 这并不是物理上精确、体积守恒的计算。我调整它是为了实现我想要的外观。 每一帧,我采样上一帧的高度图,将结果渲染到下一张图中,并在两个 FBO 之间交替。
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。