☰
3ds Max流体模拟:从瀑布到杯中溢出的尺度、体素与时间步
2026/10/28 2:37:26 网站建设 项目流程

1. 先把“水”分类:方案选型与场景拆解

做3ds Max流体模拟,最容易翻车的地方不是参数不会调,而是一开始就没想清楚这摊水到底是哪一种水。瀑布和杯中溢出的饮料,在现实世界里是同一种物质,在解算器眼里却是两个完全不同的物种。瀑布是重力主导、惯性巨大、跨越几十米尺度、以“破碎与泡沫”为主要视觉特征的大流体;杯中溢出是表面张力主导、黏性明显、尺度只有几厘米、靠“贴合与张力”取胜的小流体。用同一套参数去跑这两件事,结果一定是瀑布糊成一坨、饮料像在倒胶水。

我在项目里见过太多这种情况:有人拿一个跑瀑布的工程,把杯子模型丢进去,改了个发射源就开始算,然后困惑为什么水“粘”在杯口不掉下来,或者干脆变成一颗一颗的球。原因很朴素——物理尺度变了,主导力就变了。流体解算里有个无量纲数叫邦德数,简单说就是重力与表面张力的比值,尺度越小,表面张力占比越大。你在几十米尺度下可以忽略的东西,在几厘米尺度下就是主角。

所以这篇内容我按“先选型、再搭场景、再分案例、最后排错”的顺序来写,中间会给具体的参数区间、时间步计算和几个能直接抄的设置。适合刚上手Phoenix FD或者从其他流体软件转过来的人,也适合已经会跑但总觉得“差一口气”的中级用户。

1.1 三种液体的物理尺度差异

我习惯把要做的液体先分成三类,分完类,工具和参数基本就定了一半。

第一类是大尺度重力流:瀑布、泄洪、冲垮堤坝、船首破浪。特征是速度高、跨越距离长、破碎剧烈,视觉重点是水体形态的连贯性和大量白水泡沫。这类东西最怕分辨率不够导致“糖浆感”,也最怕子步不足导致体积凭空消失。

第二类是中尺度容器流:倒酒、倒咖啡、水龙头冲杯子、饮料溢出。尺度在5到30厘米之间,速度不高,但液体与容器壁的接触面积极大,表面张力和接触角的表现直接决定像不像。这类场景里,网格精度要求比第一类还苛刻,因为你必须让水“贴”在杯壁上形成薄薄的一层膜。

第三类是小尺度液滴与飞溅:水滴落水、雨打地面、果汁溅开。这类东西往往不值得用体素解算,用粒子加表面重构(比如Blob Mesh或者实例化球体)反而更快更好看。判断标准很简单:如果镜头里液滴直径小于画面高度的百分之一,解算出来的东西大概率是一堆方块。

注意:分类不是学术行为,是为了让你在打开解算器之前就知道该把预算花在哪。分辨率、子步、缓存体积这三样,永远是一起涨的。

1.2 主流解算管线横向对比

在3ds Max生态里能做的液体路线其实就那么几条,我按实际项目里用到的频率排一下,顺便说清楚各自适合干什么。

方案底层方法适合场景优势短板
Phoenix FD 液体混合网格/粒子(FLIP类)瀑布、溢出、容器流与Max集成好、白水系统完整、VDB缓存通用小尺度表面张力需要精细调,内存吃紧
Fume FX 液体模块网格法为主中大型水体、风格化烟雾液体同一套流程、渲染成熟白水与泡沫系统不如前者顺手
粒子+表面重构粒子法(SPH思路或纯几何)液滴、小飞溅、风格化水极快、可控、几乎不吃内存连续性差,做不了大片水体
外部解算导入VDB独立流体软件超高精度镜头、复杂交互精度上限高流程长、迭代慢、返工成本高

我个人的经验是:主水体走第一条,飞溅和白水走第三条,两者在渲染层合并。这个组合能吃掉九成以上的商业镜头需求。纯靠一套解算把主水体和高频飞溅同时做到位,成本会失控,因为飞溅需要的时间步精度远高于主水体。

至于第四条,只在镜头要求“水必须精确地贴着某个复杂曲面流动”时才会考虑。日常项目里,迭代速度比极限精度重要得多,一个能在一晚上改五版的方案,胜过一版要算三天的完美解。

1.3 体素尺寸决定了你钱包的厚度

体素尺寸(Cell Size)是流体模拟里最贵的那个参数,没有之一。它的影响不是线性的:体素边长缩小一半,体素总数涨八倍,内存和单帧耗时基本同比例甚至更糟。

给个能直接用的估算方法。假设你要算一个长宽高各2米的水域,体素边长取2厘米,那么每一维是100格,总格子数就是100的三次方,一百万格。这个量级在普通工作站上还算轻松。如果体素边长取1厘米,每维200格,总格子数八百万,内存直接翻八倍,单帧时间也差不多。这就是为什么很多人第一次跑瀑布就爆内存——他们对着一个30米落差的场景,把体素设成了5厘米,算下来是600×600×600,两个多亿的格子。

实用的做法是自适应网格加局部精算:整体用一个粗体素把大形体跑顺,等形态满意了,再把镜头焦点区域(比如水砸进潭水的那个位置)单独加密重算,其余部分保持粗分辨率。Phoenix FD的自适应网格就是干这个的,它会跟着液体实际占据的空间扩张,不预设一个巨大的空盒子。

再补一个换算:体素尺寸和你能看到的最小细节大致是两到三倍关系。也就是说,2厘米的体素,最小能分辨的水花结构大概在4到6厘米。如果你要看到杯口边缘那圈薄薄的水膜,体素必须小于水膜厚度的一半,也就是毫米级。这就是小尺度场景格外吃资源的原因。

2. 场景准备:单位、容器与碰撞体

场景准备这一步,做得好后面一路顺,做得不好后面所有参数都是在跟错误的物理尺度搏斗。我见过最多的两个错误,一是单位乱,二是碰撞体是单面片。这两个问题有一个没解决,后面的调参基本都是白费。

2.1 单位设置是一切的地基

3ds Max默认单位是“通用单位”,这个设置在流体模拟里是个陷阱。解算器的所有物理参数——重力、黏度、表面张力——都默认你用的是米。如果你的杯子里,杯高是10个单位,解算器会认为这个杯子有10米高,然后按照10米高物体的物理规律去算表面张力,结果就是水根本不贴壁。

标准做法是两步。第一步,把系统单位和显示单位都设成米,并把模型按真实尺寸缩放:一个马克杯高10厘米,那就做成0.1。第二步,如果模型不方便改(比如从客户那里拿来的模型是毫米制),就在解算器里找到场景尺度(Scene Scale)参数,按比例填。杯子实际10厘米,场景里是10个单位,那场景尺度填0.1。

提示:场景尺度不是“视觉缩放”,它改的是解算器内部使用的长度。填错了,表面张力、黏度、重力全都跟着错,症状是水要么像胶水要么像空气。

我的习惯是,凡是涉及液体的工程,建个空场景先把单位调好再导入模型,从来不直接打开别人的模型开始干活。这一步花两分钟,能省掉后面两小时的困惑。

2.2 碰撞体:别让单面片坑了你

液体穿模是流体模拟里最常见的“玄学”问题,十次里有八次是碰撞体的问题,跟解算参数没关系。

首先,解算器判断的是几何体的体积,不是面。单面片在解算器眼里没有内外之分,液体可以从“里面”穿到“外面”去,看起来就是水从杯壁里渗出来。所以杯子、碗、水池这类容器,必须是封闭的实体网格,或者至少是给了厚度的壳体,厚度要明显大于体素尺寸——小于体素的薄壁会被解算器直接忽略掉。

其次,碰撞体的面数不是越多越好。高模杯子的曲面细分会让碰撞检测变慢,而且细小褶皱容易产生错误的法线方向。理想的做法是用一个简化的低模作为碰撞体,法线统一朝外,网格尽量均匀。视觉渲染用高模,碰撞用低模,两套分开。

再一个坑是碰撞体的运动。如果杯子里有水,杯子在动,那么杯子是不是被设成了动态碰撞体、有没有勾选“影响液体”的选项,会直接决定水是跟着杯子晃还是穿过去。运动的碰撞体还会引入额外的边界条件,速度变化太剧烈时会出现液体被“弹飞”的现象,这时候需要降低碰撞体的运动速度,或者提高子步。

2.3 发射源的做法与取舍

发射源决定了液体从哪来、以什么速度来。常见的几种做法各有适用场景。

几何体发射是最常用的:给一个平面、一个环形、或者一个样条拉伸出来的曲面,设置为液体源,液体从这个面的法线方向流出。这种方式的好处是形态可控,比如做瀑布,用一条弯曲的带状面作为源头,就可以控制水帘的宽窄和翻转。速度可以给初始速度,也可以只给重力让它自由下落。

初始填充适合容器场景。杯子里的水不需要从水龙头流进去,直接在杯子内部生成一个液体体积作为初始状态,然后让它在重力下稳定下来,再开始真正的模拟。这样做省掉了前面几秒的“注水”时间,也避免了注水过程产生的大量无用数据。

粒子转液体适合从已有动画继承运动。比如一个角色把水泼出去,先用粒子把运动轨迹做出来,再让粒子作为液体的发射源,解算器会根据粒子密度生成液体体积。这种方式出来的形态比较“松”,需要额外的压缩和稳定化处理。

还有一个容易被忽略的点:发射源的面法线方向要和预期流向一致,而且发射源最好不要和碰撞体重合。我遇到过一次水从杯底往上冒的情况,查了半天发现是发射平面被放在了杯底内部,法线朝上,液体直接从杯底“喷”了出来。

3. 瀑布:分层策略与白水处理

瀑布是大多数人做流体的第一个大场景,也是最容易做到“能看但不像”的场景。不像的原因通常不是主水体的问题,而是缺少白水、水雾和分层细节。真实的瀑布,视觉重心有一半在那些翻滚的白色泡沫和水雾上,主水体反而是最“安静”的部分。

3.1 主水体:低分辨率跑长距离

做瀑布的第一条原则:主水体不要追求高分辨率。一条落差20米的瀑布,如果你想把每一朵水花都算出来,那是渲染农场的活。正确的做法是把主水体当成“骨架”,用相对粗的体素把水流的大形态、撞击点、扩散范围跑出来。

我的常规配置是:落差10米左右的瀑布,体素边长给8到12厘米,场景尺度按米制。这个精度下,水体整体形态是准的,但表面会很“肉”。没关系,后面靠白水粒子和表面细节去补。

模拟长度要留够。瀑布从顶部到底部再进入潭水,通常需要至少4到6秒的模拟时间才能进入稳定状态。前两秒基本是“建立流动”,形态很丑,不要看。真正能用的帧在第三秒之后。为了省时间,可以先用很粗的体素跑8秒,把稳定段的形态确认下来,再决定加密后重跑哪一段。

还有一个关键设置是开放边界。瀑布的顶部和底部都应该允许液体流出解算区域,否则水会在底部堆积、往上反涌,把整个形态毁掉。同时要保证底部的潭水区域有足够的空间容纳撞击后的扩散。

3.2 泡沫、飞溅与水雾的分离

白水这件事,我一直主张分层做,不要指望一个参数全包。

泡沫(Foam)通常分两种:水面漂浮的浮沫和液体内部的起泡。瀑布场景里主要是前者。生成逻辑一般基于速度阈值、曲率阈值和压力变化,解算器会在液体表面速度剧烈变化的地方“生”出泡沫粒子。这里的关键是阈值不要设太低,否则整个水面糊成一片白色,比没有还难看。我一般先把阈值调高,只让撞击点附近生成泡沫,再逐步下调,观察泡沫的扩散范围是否符合物理直觉。

飞溅(Splash)是独立的粒子系统,由液体表面的高速运动触发。它的参数核心是速度阈值和粒子寿命。瀑布砸进潭水的位置是飞溅最密集的地方,向外围逐渐稀疏。我习惯把飞溅粒子的尺寸做得比实际物理尺寸略大一点,因为在运动模糊下太小的粒子会闪烁。

水雾(Mist)是最容易被忽略但最提气氛的一层。它是液体在高速运动和撞击时被“打碎”成极细颗粒的部分,视觉上是半透明的雾状云团,尤其在瀑布底部和撞击点附近。水雾不需要严格的物理精度,用粒子加体积渲染,甚至用几层噪声贴图做体积雾都能出效果,成本比真解算低一个量级。

三层的分工很清楚:泡沫负责水面的白色纹理,飞溅负责空中的离散颗粒,水雾负责整体的空气感。三者叠加之后,即使主水体的分辨率只有10厘米,画面也会显得很“细”。

3.3 时间步与CFL的算法

这一段是干货,也是很多人跳过导致模拟崩掉的地方。

流体解算的稳定性有个基本条件,专业上叫库朗条件,通俗说就是:一帧之内,流体不能跨过超过一个体素的距离,否则计算会失真甚至发散。用公式表达就是 速度 × 时间步 ÷ 体素尺寸 < 1(实际工程上常允许到2到5,取决于解算器的隐式程度)。

拿瀑布举例。落差10米,忽略空气阻力,落到底部的速度大约是 开根号(2 × 9.8 × 10),约14米每秒。体素边长0.1米。那么单个时间步的上限是 0.1 ÷ 14,约0.007秒。按24帧每秒算,一帧的时间是1/24,约0.0417秒。0.0417 ÷ 0.007 ≈ 6,也就是说每帧至少需要6个子步才能保证不崩。

再看杯中溢出。倒水速度按0.5米每秒,体素边长2毫米也就是0.002米,单步上限 0.002 ÷ 0.5 = 0.004秒,一帧0.0417秒,需要约11个子步。这就是为什么小尺度场景特别慢——不是格子多,是子步多,两个乘起来。

实际设置时,我会在这个理论值上再乘个安全系数1.5左右。子步数上去了,模拟变慢,但换来的是体积守恒和稳定性,这笔账划算。如果实在跑不动,优先降体素精度,别降子步——降子步的后果是水“漏”掉、体积莫名其妙变少、表面开始抖。

3.4 渲染:水不是蓝色的玻璃

渲染阶段最常见的错误是把水做成“蓝色透明玻璃”。真实的水在绝大多数情况下几乎是无色的,它的颜色来自吸收而不是表面染色。

基础材质思路:折射率给1.333,反射给足但不给镜面级别,颜色用极淡的青蓝色并且靠吸收距离控制浓淡。薄的水层几乎透明,厚的水体(比如瀑布主体)才会显出青色。用体积吸收或者雾颜色来控制这个“厚此薄彼”的效果,比直接调基础色准确得多。

泡沫的渲染是另一套材质。它的视觉特征是强散射、低反射、偏白的漫反射,用次表面散射或者简单的漫反射加自发光混合都能出效果。关键是泡沫和水体之间要有过渡,不能是硬边——真实的白水边缘是渐变的、撕裂状的。用一个带噪声的遮罩在两种材质之间混合,效果比纯粒子便宜得多。

反射环境也很关键。水面是镜面,会忠实反射周围的一切。如果环境里只有一盏灯,水面会显得死板。我在做瀑布时一般会加一张环境贴图,哪怕很粗糙,水面的反射也会立刻“活”起来。

4. 杯中溢出:小尺度液体的关键参数

如果说瀑布考的是资源调度和分层思维,杯中溢出考的就是对细节的耐心。这个场景的难点全在“边界”上:液体与杯壁的接触、液体与空气的表面张力、液膜在杯口的堆积与断裂。这三件事在粗体素下全部消失。

4.1 场景尺度与表面张力

前面提过场景尺度,这里展开说。一个高10厘米的杯子,在3ds Max里如果是10个单位,场景尺度必须设0.1。设对之后,你会发现表面张力参数“突然生效了”——因为解算器终于知道这是个小东西。

表面张力强度的取值没有统一标准,跟液体种类有关。清水在室温下的表面张力系数约0.072牛每米,换算到解算器里的无量纲参数,大概在中等偏上的位置。饮料因为有糖分,黏度和表面张力都比水高一点,表现出来就是挂杯更明显、断裂更慢。

我的调法是从中间值开始,先看液体在杯口能不能形成连续的弯月面——就是贴着杯壁微微上翘的那一圈。如果液体在杯口“缩”成一颗颗球,说明表面张力过大;如果液体直接摊平、边缘没有任何收拢感,说明太小。这个判断标准比看数字直观。

还有一个易错点:表面张力生效的前提是体素足够细。体素大于液膜厚度时,表面张力在数学上起作用,但视觉上完全看不出来,因为根本没有足够的格子去表达那个弯曲的表面。杯口液膜厚度通常在1毫米以内,所以体素给到0.5毫米才比较稳,这个精度对内存要求不低,通常只对杯口局部加密。

4.2 三种触发溢出的做法

溢出这个动作,实现方式有三种,我按可控性排个序。

第一种是倾斜杯体。把杯子作为动态碰撞体,用关键帧慢慢倾斜,液体在重力下自然流向杯口并溢出。这种方式最物理,也最考验解算稳定性和子步。倾斜速度必须慢,一帧转超过两三度,液体会因为边界条件突变而炸开。我的经验是倾斜角度控制在15到20度之间,持续1到2秒,出来的溢出形态最自然。

第二种是注水溢出。杯子里先有半杯液体作为初始状态,然后从上方持续注入液体,靠体积增加把水顶出来。这种方式的好处是溢出量可控,注入速度决定溢出速度。缺点是注入源的位置和速度如果给得不好,会在杯内激起不自然的波浪。

第三种是初始状态直接给过量。在杯内生成一个超过杯口容量的液体体积,让它自己在重力下落、扩散、溢出。这种方式最快,但形态最不可控,容易出“爆炸式”的喷涌。适合风格化或者远景,需要精确控制的特写不建议用。

不管哪种方式,杯口的几何形态都很关键。真实杯子杯口有厚度、有圆角,液体溢出时会沿着外壁爬一段再滴落。如果你的杯子杯口是一圈锐利的零厚度边,液体会直接从边缘“切”断,看着非常假。给杯口加个0.5毫米的圆角,效果立刻不一样。

4.3 气泡、折射与焦散

杯中的饮料如果完全没有气泡,会像一块塑料。气泡的加入让液体有了“内部结构”。

解算器一般有独立的起泡通道,需要开启并在液体内部生成。生成条件是压力变化或者卷吸空气,参数核心是气泡密度和尺寸范围。气泡尺寸要和体素匹配,太小会表现为噪点。我一般让气泡直径在3到6毫米,正好是肉眼能看清、渲染也能表现的范围。

气泡上升速度受浮力控制,黏度高的饮料里气泡上升慢、会变形。这个细节很多人不做,但在特写镜头里,气泡缓慢上升并轻轻晃动,是判断“像不像”的重要依据。

折射是饮料质感的另一个关键。液体的折射率在1.33到1.36之间,饮料因为含糖更高一点。透过液体看杯后的物体会有明显的放大和位移,这个效果必须靠真实的折射计算,用贴图是模拟不出来的。渲染时记得开启折射的最大光线深度,否则透过两层液体和一层玻璃就会变黑。

焦散是加分项。光线穿过液体在桌面上形成明亮的光斑纹路,这个效果需要开启渲染器的焦散计算,非常吃时间。我的做法是只在特写镜头开启,而且降低光子数量换速度,画面的氛围感提升明显。如果是远景或者运动镜头,直接跳过。

4.4 缓存与渲染采样

小尺度流体的缓存体积比想象中大。一个杯子的液体,体素0.5毫米,杯子直径8厘米,那就是160×160×160的常驻网格,四百多万格,每帧的液体通道加泡沫通道加压力通道,一帧轻轻松松上百兆。模拟5秒就是一百多帧,十几个G。

实际做法是用VDB格式缓存,它只存有液体的区域,能省掉大量空白空间。缓存时只勾选需要渲染的通道,压力和速度通道在调完之后就可以关掉了。另外一定要分段缓存,不要一口气跑到底,跑二十帧看一眼,确认没有崩的趋势再继续。

渲染采样方面,液体表面的高光反射和折射都很吃采样。运动中的液体表面噪点尤其明显,因为反射方向每帧都在变。我的常规设置是反射和折射的采样比漫反射高一档,配合降噪。降噪器开太猛会把泡沫的细节一起抹平,所以泡沫层通常单独渲染再合成,这样降噪可以分开设置。

5. 稳定性排查:崩解、穿模与体积丢失

流体模拟的调试有点像个侦探活,症状明显,病因藏得深。这一节我把这些年遇到的高频问题整理成可以对照排查的形式,尽量给出“看到这个现象先查什么”的顺序。

5.1 缓存的正确管理

缓存管理听起来是流程问题,实际上直接影响你能不能在有限时间里迭代出结果。

第一条:每一版参数对应一个独立缓存目录,目录名带版本号和关键参数摘要。不要在原目录上覆盖,因为你永远会在覆盖之后想回到上一版。

第二条:先粗后细。用粗体素跑完整时长,确认整体运动和时间节奏,再加密重跑。加密后不要重跑全部时长,把前面已经稳定的部分用初始状态导入,只算后面需要的帧。这一条能把迭代时间砍掉一半以上。

第三条:缓存和工程文件分开存放。VDB文件体积大,放在网络盘上读取会拖慢整个流程,本地固态盘算完再归档。

第四条:渲染前做一次缓存完整性检查。逐帧检查有没有空帧、有没有体积突然跳变。我遇到过一次中间某一帧缓存写坏了,渲染出来是整个画面闪一下,排查了很久才发现是硬盘写满导致的截断。

5.2 常见问题速查表

现象最可能的原因排查顺序
液体穿出容器碰撞体是单面片或壁厚小于体素检查网格封闭性 → 加厚壁体 → 提高体素精度
体积莫名减少子步不足、边界开放设置错误提高每帧子步 → 检查开放边界方向 → 提高压力迭代
液体表面持续抖动子步不足、表面张力过大加倍子步 → 下调表面张力 → 检查碰撞体面法线
液体像糖浆黏度过高、场景尺度设置错误检查场景尺度 → 黏度归零测试 → 检查体素尺寸
泡沫糊成一片白泡沫生成阈值过低提高阈值 → 缩小泡沫寿命 → 检查曲率通道
溢出时液体炸开碰撞体运动突变、初始状态过压放缓碰撞体关键帧 → 降低初始体积 → 增加子步
杯壁无挂壁残留未开启湿图通道、表面张力过小开启湿图 → 上调表面张力 → 加密体素
渲染出现块状表面体素精度不足且未做表面平滑提高体素 → 开启表面重构 → 加细分修改器

这张表不是万能的,但它能覆盖八成以上的常见症状。真正麻烦的是组合症状,比如“体积减少加表面抖动”,那基本可以确定是子步和压力迭代同时不足,两个一起调才有用。

5.3 几条踩出来的经验

第一条,先用一个球体测试解算器。拿到一个新工程,别急着上复杂场景,先放一个球在水里落下去,看水花形态、看体积守恒、看表面平滑度。这个五分钟的测试能提前暴露尺度、单位、碰撞体的一大堆问题。

第二条,关掉所有花哨通道再调主水体。泡沫、飞溅、水雾全部关掉,只看纯液体。主水体的形态对了,再一层层往上加。反过来做,你会分不清是主水体不对还是白水太多遮住了问题。

第三条,用关键帧记录你的参数变化。同一个参数今天调了三次,明天忘了当时为什么这么设,这是常态。在工程里放一个文本层或者用注释记录关键参数和调整理由,返工时能救命。

第四条,别相信预览窗口。视口里的流体预览为了速度做了大量简化,表面可能很粗糙,也可能根本不显示泡沫。判断效果一定要渲染几帧,至少是低质量渲染,看真实的材质和光照下是什么样。

第五条,留出“废帧”预算。流体模拟的稳定过程通常需要一两秒的前置时间,这段画面是不能用的。排期时把这段算进去,别按“我要5秒动画就算5秒”来估时间,实际得算7秒。

最后分享一个我自己常用的小技巧:做溢出镜头时,先在杯口内侧放一圈极细的引导几何体(一圈薄环),让液体优先沿着这个环聚集,再自然溢出。这个“作弊”不会破坏物理感,但能显著提高溢出的可预测性,减少重算次数。这类小手段在实际项目里比调参数有用得多,多做几个镜头自然就有手感了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询