3.2 散布与分布算法


3.2 散布与分布算法

本节摘要:散布(Scattering)把"点"撒到表面,再用 Copy to Points 实例化成万物。质量的分水岭在密度控制:用属性图与规则掩码决定"哪里多哪里少",用蓝噪声保证"匀而不齐"。本节搭一个完整的属性驱动散布系统,并对比随机、抖动网格与最近点避让三种分布算法。

实验:属性驱动的散布系统

接着山体做。目标:石头集中在山腰陡坡,山顶稀疏,山脚几乎不放。整条链四步:

  1. 造密度值——在山面几何上写一个 density 点属性(Wrangle,Run Over Points):
float slope = degrees(acos(clamp(dot(v@N, {0,1,0}), -1, 1))); float h = relbbox(0, @P).y; // 山腰最密:带通 + 缓冲 f@density = smooth(0.05, 0.25, h) * (1 - smooth(0.6, 0.85, h)); f@density *= fit(slope, 10, 40, 0, 1); f@density *= 0.5 + 0.5 * noise(@P * 1.7); // 簇状变化,避免均匀抹开
  1. Scatter 读取密度:勾选 Density Attribute 填 density,目标点数给 20000。注意 Scatter 的 Force Total Count 与密度属性相乘决定最终分布——密度是相对权重,不是绝对值
  2. Copy to Points 接石头模型,2.1 写的 pscale 规则继续生效;
  3. 打散规整感:Scatter 勾选蓝噪声相关选项或在前置网格上做抖动(下文对比)。

图 3.2-1 散布系统数据流

三种分布算法对比

密度解决"哪里多",分布算法解决"怎么摆"。同一密度下三种算法的质感差异显著:

算法 做法 视觉特征 代价
纯随机 每点独立掷骰 有聚块和空洞,真实但偶有"扎堆" 最便宜
抖动网格 规则网格+格内随机偏移 均匀中带随机,最常用 便宜
泊松盘/最小间距 拒绝过近样本 严格不重叠(树、岩石) 较贵,点数大时明显

Houdini 的 Scatter 自带思路二的网格抖动与思路三的最小间距参数;要完全控制时也可以用 Point Relax 节点把已撒的点推开到最小距离——它就是迭代式的最近点排斥,2.1 的邻域代码手写版即其原理。

💡 关键直觉:自然界的分布几乎都是簇状的(种子落在哪里,哪里就长出一片)。纯均匀反而假,纯随机偶尔扎堆。密度场乘一层噪声(实验第 3 行)是性价比最高的"簇感"来源。

避让与优先级

真实散布还要处理"打架":大树不许长在路上,营火周围要有空地。两层手段:

  • 掩码相减:道路先算成一张 mask(按距离曲线的远近,第 4 章会展开),density *= 1 - roadmask; 一行解决;
  • 优先级复制:先复制大树,再用 Attribute Transfer 把已有树的位置烙成"排斥场",第二次散布读它降密度——生态学里的"演替"就这么程序化了。
// 第二轮散布前的排斥:离大树越近密度越低 int near[] = nearpoints(1, @P, 2.0); // 输入1=大树点云 if (len(near) > 0) f@density *= 0.05;

性能与落点

2 万个点直接 Copy 真模型会很重。两条正路:Copy 到低模代理,渲染时换回高模;或直接输出实例化属性(取向量乘 pscale 打包成 instance 矩阵),交给渲染器/引擎实例化——第 7 章与引擎对接时这是标准出口。

⚠️ 常见坑:Scatter 在三角面上撒点时,长条三角形会比正三角形"吸"更多点(按面积加权对随机是公平的,但视觉上长条区域密度失真)。先 Remesh 匀化网格再散布,分布才可信。

本节要点回顾

  • 密度是属性:slope/height/mask/noise 相乘合成 density,Scatter 读它;
  • 分布三档:纯随机(真但扎堆)、抖动网格(匀而活)、最小间距(硬不重叠);
  • 簇状比均匀更自然:密度乘噪声一层即得;
  • 避让两法:掩码相减(便宜)与排斥场(有优先级语义);
  • 散布前先匀化网格,长三角形会造成密度失真;
  • 出口是实例化,不是复制真模型。

散布系统里反复出现的 noise 到底是什么?下一节把它讲透。

延伸:泊松盘散布的手工实现与验证

高级散布的关键约束是"既随机又不重叠",泊松盘是标准答案。Scatter SOP 内置(Relax 选项即是),但手工实现一遍能让你获得修改它的能力,核心是拒绝采样加松弛:

// Attribute Wrangle (Run Over: Detail) —— 迭代式松弛散点 int pts[] = expandpointgroup(0, ""); for (int iter = 0; iter < chi("iters"); iter++) { foreach (int p; pts) { vector pos = point(0, "P", p); int nbs[] = nearpoints(0, pos, ch("min_dist") * 2); vector push = {0,0,0}; foreach (int nb; nbs) { if (nb == p) continue; vector d = pos - point(0, "P", nb); float len = length(d); if (len < ch("min_dist") && len > 1e-5) push += normalize(d) * (ch("min_dist") - len); } setpointattrib(0, "P", p, pos + push * 0.5, "set"); } }

验证标准:最小点间距直方图(measure 出 min distance 属性后画 histogram)应紧贴 min_dist 而无长尾。同样的松弛框架换个"力"就是曲面上的颗粒堆积、苔藓群聚——散布算法的通用骨架比具体节点更值钱。

延伸:密度图的合成管线

密度场合成清单 坡度图(slope) + 海拔带(fit@P.y) + 噪声扰动(偏差) + 艺术遮罩(画笔mask) => 乘法合成: 只有多因子相乘才能制造"同时满足"的 AND 语义 => 验证: Scatter 的密度可视化 + 数量统计随参数单调 陷阱: 各因子未归一化到0-1就相乘, 密度会坍缩为0

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U