关于 scenario-blender-geometry-nodes
面向 Agent 的 Blender Geometry Nodes 技能,用于构建程序化系统与模拟。内容涵盖字段和域规划、可复用修改器资产、几何数据测量、渲染检查及模拟验证。
主要功能
- 01规划字段、域与数据流
- 02使用 bx_gn.Builder 构建节点树
- 03开放可复用修改器输入
- 04测量求值后的几何体与属性
- 05验证模拟并检查渲染结果
适用场景
- 01创建表面散布系统
- 02构建曲线阵列或生长效果
- 03设置有状态的粒子模拟
- 04封装可复用的 Geometry Nodes 资产
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-blender-geometry-nodes安装后在 Claude Code 中输入/scenario-blender-geometry-nodes确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/critique.mdexpert-notes.mdprocedures.mdsources.mdscripts/bx_gn.py详细介绍
Blender 几何节点(程序化系统与模拟)
精通几何节点,意味着要把字段视为在各个域上求值的内容,让系统保持声明式(数据和指令从外部传入),并交付艺术家无需打开节点树、只需通过修改器输入即可驱动的工具。对 Agent 来说,这也意味着要用从求值后的几何体中读取的数值和渲染结果验证每个节点树,因为除非主动检查,否则无法通过 Python 看到节点编辑器中的红色连线和警告。如果此处提到的某项相关技能不在可用技能中,请让用户安装该技能(npx skills add scenario-labs/skills --skill <name>);若需无人值守地继续,则根据工具架构处理,并指出这一缺口。
必备背景: scenario-blender-expert(执行渠道、审查循环、5.2 API 变更)。 毛发节点组(Interpolate、Clump、Curl、Hair Dynamics groom):scenario-blender-hair。
核心理念(专家的关键差异)
- 字段是一个待延迟回答的问题,而不是数据。 Thommes:字段由使用它的节点在该节点的域和几何体上求值;只有在被命名或使用时,值才会存在。由此得出的结论[新增,已验证]:两个相互耦合的更新(位置和速度)必须一起在一个 Capture Attribute 中捕获,否则第二个更新会读取第一个更新后的值。
- 域变更会进行插值;所有内容都会按规则变为布尔值。 Erindale:浮点数 > 0 即为真(向量:任意非零值),因此细分后的顶点组选择会发生扩散;应通过 Float to Integer 或带 epsilon 的 Compare 来做出判定。优先使用特征选择(位置、法线、邻近度、射线投射),而非基于索引的选择,除非几何体由你生成且其顺序本身就是设计的一部分(Blender Studio 的矩阵视频通过 Index == 0 驱动堆栈)。
- 只有依赖历史时才使用模拟。 Thommes:模拟是应用于状态的规则;动画是时间的函数。如果没有任何内容依赖上一帧,就用 Scene Time 驱动,这样无需额外工作即可支持拖动时间轴和子帧。
- 循环是最后的选择。 Thommes:内置节点在所有元素上运行时会使用加速结构,而循环无法做到这一点。For-each 适用于逐个元素运行的黑盒生成器:字段在外部,单个值在内部。
- 所有内容都在对象局部空间中。 Thommes:(0, 0, -1)向量会随对象旋转。世界方向需经过 Self Object > Object Info > Invert Matrix > Transform Direction。
- 构建工具,而非节点树。 Thommes:将每个场景依赖项和可调整值都公开为组输入,绝不在可复用节点树内部硬引用对象;仅使用 Group Input 插口,通过可逆数学运算,将操纵器连接到每个数学节点的第一个输入。
- 5.2 物理采用声明式方式。 Thommes(BCON26):力、碰撞体和约束以捆绑包和闭包的形式传入黑盒求解器。首先从外部进行自定义(输入、捆绑包、Custom Effector 闭包);只有在需要编辑内置约束时,才将资产设为本地数据。每步模拟中使用的自定义属性都必须列在 Extra Sim Attributes 中;拓扑发生变化的模拟必须将新元素追加到末尾。
首先明确
| 问题 | 为什么这会改变方案 | 未说明时的默认选择 |
|---|---|---|
| 谁会使用结果:着色器、另一个修改器、导出还是物理模拟? | 跨越边界需要命名属性;导出可能需要实现几何体 | 着色器读取的内容使用命名属性;保留实例 |
| 是否依赖上一帧? | 这决定使用模拟区和烘焙,还是 Scene Time 函数 | 时间函数 |
| 是一次性的创作步骤,还是可复用资产? | 一次性步骤可以应用(Thommes 的头发噪声);资产则不能 | 可复用:公开输入,设置面板和合理的最小值/最大值 |
| 规模:元素数量、视口开销 | 实现、循环和模拟都有开销;实例开销很低 | 使用实例和字段,不用循环 |
| 方向和地面使用世界空间还是对象空间? | 可避免对象局部空间的陷阱 | 世界空间向上方向、世界空间重力 |
工作流
- 规划数据流。 明确每个值所属的组件和域、每个字段由哪个位置求值,以及适合使用哪种基本节点:先用普通字段;按组求和用 Accumulate Field;需要 N 次依赖式迭代用 repeat zone;需要为每个元素调用黑盒生成器用 for-each;需要状态用 simulation zone;需要注入行为用 closure;需要传递多个命名值用 bundle。GATE:能说清每个字段由哪个节点求值。
- 使用
bx_gn.Builder构建(无界面或实时均可,具幂等性:同名树会在原处重建)。b.node(kind, prop=..., ins={...})会先设置属性,再设置输入;连接源节点并赋值常量。b.zone(...)配对区域并添加项目;b.join([...])保留列表顺序。GATE:b.done()返回(区域已配对,且所有连接均已创建)。 - 附加并设置输入,使用
G.attach(obj, tree, inputs={...})或G.set_inputs(md, {...});"attr:NAME"会将字段输入切换为属性或顶点组。GATE:G.check(md)["ok"],资产上没有hard_refs。 - 测量。 使用
G.stats(obj)(计数、各域的属性、包含实例的世界包围盒)、G.attribute、G.instance_transforms、G.positions。然后进行两项稳健性测试:将对象旋转 90 度(世界空间效果应保持方向),并将输入分辨率加倍(按特征选择的结果会相应缩放,按索引选择的结果则会跳变)。GATE:数值符合解析预期。 - 查看效果。
G.snapshot(objs, path, views=..., frames=...)会使用材质颜色和阴影渲染当前场景状态(会显示浮动实例);对已实现的网格使用bx_review.review。打开每张图表。GATE:references/critique.md中的视觉检查项全部通过。 - 模拟。 使用
G.step(range(...))按顺序逐帧执行,或使用G.bake(obj)进行随机访问;断言边界、状态单调性、计数及无 NaN。GATE:只有烘焙后,直接跳到较晚帧的结果才会与逐帧执行的结果相同。 - 打包(资产):将输入分组到面板中,并设置默认值、最小值/最大值和子类型;设置
tree.is_modifier = True; tree.asset_mark();将其拖到另一个对象上(Thommes 的 Suzanne 测试)。GATE:无需编辑树即可在第二个对象上正常工作。
scripts/bx_gn.py 中包含已测试并渲染的配方:scatter_tree(密度 × 遮罩、世界空间坡度限制、直立或对齐、从对象和集合中选取)、curve_array_tree(沿切线对齐的阵列,交替扭转可形成链条)、growth_tree(repeat-zone 挤出)、particle_drop_tree(带发射、世界重力和地面反弹的 simulation zone)。当内置 Essentials 资产(Scatter on Surface、Array、Instance on Elements、Randomize Transforms)的输入能满足需求时,优先使用它们;需要世界空间规则、遮罩或自定义属性时,再自行构建。
数值
| 数值 | 相对于什么 | 来源 |
|---|---|---|
| 融化模拟:环境温度 300 K,热源温度 2000 K,每帧加热 0.05、冷却 0.01 | 每步混合系数;因会累积,所以数值较小 | Thommes BCON23 |
| 模糊属性权重 0.5;平滑 5 次迭代;融化蒙版范围 500 至 2000 K | 热量扩散和软化 | Thommes BCON23 |
| 每帧沿 -Z 方向滴落 0.01;法线混合 0.1(0.5“看起来像烤面包”) | 每步偏移量 | Thommes BCON23 |
| 撕裂阈值 1 = 长度一超过静止长度就会撕裂(过于敏感);加固 10;基础随机范围 1 至 1.1;Voronoi 模式 | 边长比率 | Thommes BCON26 |
| 缝合渐变:在累积的 Delta Time 达到 1 s 时,静止长度因子从 1 降至 0 | 避免突然弹开 | Thommes BCON26 |
| 撕裂处的线:约 2 cm,每条 3 个点 | 性能上限 | Thommes BCON26 |
| 布料资产默认值:Substeps 5、Constraint Steps 15、Collision Radius 0.01、Tearing Threshold 1.2 | 从 5.2.1 资产读取 | digest [verified] |
| Gizmo 位置 = 尺寸 x 0.5,用于居中网格;在 SECOND 输入上使用 0.2 至 1 的随机因子 | 让拖动始终贴合 | Thommes BCON24 |
| 堆叠:方块原点位于底部;随机缩放 XY 1 至 1.5、Z 0.05 至 0.3 | Accumulate Field Trailing | Matrix video |
| 展平区域:岛屿至少 5 个面;邻近衰减范围 0 至 0.2 m,Smoother Step;Volume to Mesh 阈值约为 0.5 | Erindale 练习 | Erindale |
| Realize Instances:关闭 Realize All,Depth 设为 1 | 展平一层层级 | Thommes BCON24 |
质量门槛
可测量(代码):
G.check(md):ok(没有无效链接、没有 ERROR 警告、区域配对正确),资产的hard_refs为空,你添加的 Warning 节点会按预期报告。- 数量符合预期:散布数量与密度 x 蒙版 x 可用区域的偏差约在 12 percent 以内 [verified test];曲线阵列数量 = floor(length / spacing);重复增长面数 = F0 + sides x selected x iterations。
- 属性存在于正确的域且类型正确,值在范围内(
G.attribute)。 - 旋转探针和分辨率探针(第 4 步)。
- 模拟:每帧数量、边界(没有任何内容低于地面)、追加内容时 ID 前缀稳定、能量或状态在需要时保持单调、烘焙跳转结果与逐步计算一致。
- 热点树使用
G.time_eval(obj);标记其中的重复或 for-each 区域。
视觉(G.snapshot、bx_review):散布密度看起来自然,没有悬浮或下沉;阵列沿曲线延伸且不会翻转;增长在底部没有自相交;模拟条带显示运动后静止;在渲染分辨率下检查由着色器驱动的属性。Gizmo 的手感仅通过 GUI 检查。
常见错误
| 错误 | 表现 | 修复方法 |
|---|---|---|
跨树使用 tree.links.new | 返回 None,没有连接,也没有报错 | Builder.link 会引发错误;切换树后,绝不要重复使用已绑定的 links.new |
仅设置 md.properties.inputs.<id>.value | 结果没有变化 | 调用 obj.update_tag()(或 G.set_inputs) |
| 在 For-Each 区域中使用带隐式 ID 的 Random Value | 连接线变红,输出悄然出错;md.node_warnings 为空 | 将区域 Index 接入 ID;G.check 会列出 invalid_links |
| 两个 Random Value 节点使用相同的 Seed | 缩放和旋转同步变化(相关性为 1.0 [已验证]) | 偏移种子(seed + k) |
| Simulation Input 未连接到 Output 的状态 | 每一帧数值都会重置 | 将每个状态项都贯通连接 |
| 在 Cloth 或 Hair Dynamics 中使用自定义属性 | 每一步都会重置,且没有警告 | 将其列入 Extra Sim Attributes |
| 资产中硬引用控制器对象 | 首次使用正常,重复使用时失效 | 在 Group Input 上使用 Object 插槽 |
| 两个节点更新耦合字段 | 速度根据已经移动后的位置计算 | 两者共用一个 Capture Attribute |
| 假定连接顺序等于链接顺序 | 新元素被优先插入,求解器或 ID 出错 | b.join([state, new]) |
| 将局部方向用于世界空间 | 效果会随对象旋转 | 使用 Self Object 矩阵转换 |
| 通过自动填充闭包签名 | ERROR "Closure does not have output" | 创建两个项目列表,并使用相同名称 |
Blender 5.2 说明
- 修改器输入:
md.properties.inputs.<Socket_N>.value(旧写法md["Socket_N"]会引发 TypeError), 然后调用obj.update_tag()。 - 菜单是输入插口:Transform Geometry 的
Mode= 'Matrix'、Resample Curve 的Mode、Custom Force 的Mode、Custom Effector 的Stage(菜单为Socket_1;名为 Stage 的字符串输入则是Socket_2)。 - 在 Mix 上,
node.inputs["A"]在 5.2.1 中会返回可用插口;名称重复且已启用的插口(Cloth 的两个Gravity) 仍需使用标识符。使用这些标识符时,bx_gn.sock会引发异常。 - Join Geometry 会将最后创建的链接排在最前面[已验证]。
- 求值后的
obj.bound_box会忽略实例;实例点云的position属性读取结果为零,请使用instance_transform[已验证]。在无界面模式下,md.execution_time始终为 0.0。 - 仿真:首帧已运行节点区域主体;跳过缓存直接跳到后续帧时会计算一步;
simulation_nodes_cache_calculate_to_frame在无界面模式下返回 PASS_THROUGH,且不进行计算;simulation_nodes_cache_bake可用(已打包)[已验证]。 - Lists(Field to List、Get List Item)、Bundles、Closures 和
GeometryNodeXPBDSolver均已存在;模态节点工具则没有(仅实验性版本提供)。 - 随附资产:
<DATAFILES>/assets/nodes/geometry_nodes_essentials.blend、geometry_nodes_dynamics_assets.blend、procedural_hair_node_assets.blend(G.append_group(name, library))。
参考资料
references/expert-notes.md:Thommes、Erindale 和 Johnny Matthews 的原则及时间戳;设计系统或资产时加载。references/procedures.md:经过测试的代码:原始 bpy 流程 A 到 H (属性管线、浮点仿真、重复扩展、逐项处理、闭包、矩阵堆叠、操纵器、布料),以及 bx_gn 配方和物理测试;编写任何节点树之前加载。references/critique.md:用于评估节点树、资产和仿真的评分标准;每个关卡都要加载。references/sources.md:八个源视频、各自最适合的用途,以及最佳时间戳。scripts/bx_gn.py:构建器、修改器、求值、仿真、快照辅助工具和配方(文档字符串列出了易踩的坑)。