做Blender建模这么多年,我一直有个别扭的点:传统编辑模式里每一下操作都是破坏性的,Ctrl+Z能救一时,但关掉文件基本就回不去了;几何节点倒是强大,可默认逻辑是从零“生成”几何体,想直接把一块已有网格拿过来精修,总得绕好几个弯。直到我在节点编辑器里点开建模模式,这两个世界才算真正被缝到了一起。这一篇(系列第37期)就围绕建模模式工具集、动态网格编辑和Geometry Script联动,把Mesh Editing在Geometry Nodes里的正确打开方式聊透。
如果你是那种想保留“Ctrl+Z自由”却又嫌纯节点生成太绕的建模师,或者你已经在用几何节点做程序化资产、但苦于无法对已有模型做原位编辑,这篇内容应该能解决你手头那些“就差这一口气”的问题。
1. 建模模式到底改了什么:从“生成”到“原位编辑”的机制差异
1.1 传统节点图与建模模式的数据流对比
普通几何节点修改器的工作方式,本质上是一个“生成器”。无论你给它的输入是什么,它都在创造一个独立的几何体流。哪怕你把输入几何体直接连到输出,视口里看到的也是“这份数据通过节点重算后的结果”,而不是“原网格本体被修改了”。对于做纯程序化生成的人来说这没问题,可一旦你要改的是场景里已经摆好的高模、要保留各面材质、要维持顶点组关系,这套生成逻辑就会显得很笨重。
建模模式(Modeling Mode)的思路完全反过来。进入这个模式后,节点组的输入接口拿到的是对象当前的真实网格数据,输出接口返回的则是对这份数据完成编辑后的结果。直接把结果覆盖回原来的网格显示位置。所以你的视口里看到的不再是一个“节点生成的新物体”,而是“原来的那个物体被节点图加工了一遍”。这个机制上的差异,是建模模式所有优势的根源。
1.2 进入建模模式后的接口变化
在Blender 4.1及以上版本中,选中一个带几何节点修改器的网格对象,打开节点编辑器,在模式切换区域就能看到建模模式入口。点进去后你会发现两个关键变化:
- 节点树里默认多出一对输入输出接口,输入侧只有一个Geometry(原始网格),输出侧也只有一个Geometry(编辑结果)。
- 节点组里后续出现的任何Named Attribute(命名属性)、顶点组、材质索引操作,都直接对应原网格上真实存在的数据,不再是凭空生成的新属性。
这一点很关键。普通生成式节点里,你经常要手动“捕获属性”才能在后续节点里使用某个属性;建模模式下,原网格的顶点组、UV、材质、边折痕这些数据天然就在那里,只要你按名称读取即可。我常用的做法是:先给原网格分好顶点组,比如把要开口的区域命名为holes,然后在建模模式里用Named Boolean节点读取这个组,直接作为删除或挤出的Selection输入。
1.3 什么时候该用建模模式,什么时候别用
建模模式不是万能钥匙,它最适合两类场景:
- 已经存在的基础网格需要做参数化编辑,例如产品外壳打孔、建筑立面开窗、装甲板切角。
- 需要保留原对象身份(名称、变换、材质槽位)的修改,不希望每次改动都生成一个“新对象”。
反过来,如果你要从零做一个纯程序化生成的东西,比如随机散布岩石、按曲线生长藤蔓,那普通生成式几何节点反而更顺手。建模模式要求你有一个“底子”可改,没有底子,它就只剩一个空空的输入接口。
提示:建模模式下修改器本身依然保留着“不应用则不改动原始数据”的特性。只要不点Apply,网格数据就一直存在,节点图随时可以回退、重连、微调。这种安全感是传统编辑模式给不了的。
2. 建模模式下的Mesh Editing实操:先把这套工具映射吃透
2.1 Selection:用顶点组、材质、位置精准锁定操作范围
建模模式下的所有编辑操作,几乎都要经过Selection输入。你选不中,后面再多节点都白搭。传统建模里你靠鼠标框选,节点建模里你靠数据选。我总结出三个最靠谱的选区来源:
- 顶点组:在编辑模式里分好组,建模模式中用Named Boolean节点读取。稳定、直观,适合人工预选。
- 材质槽:用Named Attribute读取材质索引,再用Compare节点比较,适合按已分配材质区隔操作。
- 位置/法向条件:用Position或Normal节点接一个Compare,适合规则化的批量选择,例如只选顶面、只选Z轴正方向的面。
举个例子,给一块面板上所有“朝上的面”增加厚度,我一般这样搭:输入Geometry进Extrude Mesh节点,Selection接一个法向判断——Normal节点取出每个面的法向,通过Compare的Dot Product比较Z分量是否大于0.5。这样无论面板怎么旋转,朝上的面始终会被选中。这种动态选区是传统建模里做不到的,也是建模模式最值得花时间掌握的部分。
2.2 挤出、删除、合并、倒角:四个高频操作的真实表现
把这几个核心操作从传统工具映射到节点上,一开始会有轻微不适,但摸清规律后就非常顺手。我做了一张对照表,方便你快速建立对应关系:
| 传统建模操作 | 几何节点等效方案 | 关键注意点 |
|---|---|---|
| 挤出(E) | Extrude Mesh节点 | Offset默认沿法向,需要沿固定轴时把Vector改为具体的轴向值 |
| 删除面(Delete) | Delete Geometry节点 | Domain选Face才会删面且不留下孤立点;想连点一起删要再处理点域 |
| 合并顶点(M) | Merge by Distance节点 | Distance值按场景尺寸调,太大容易误焊相邻结构 |
| 倒角(Ctrl+B) | Bevel节点 | Radius滑动即时反馈,适合在建模模式下逐步调参数 |
| 移动顶点(G) | Set Position节点 | 通过Offset或Position修改坐标,适合做整体位移和形变 |
| 分离(P) | Separate Geometry节点或Split Edges | 需要明确是“分对象”还是“断开边”,两种语义不同 |
这里特别想提醒一下挤出的选择。传统建模里你按E拖出来就完事,但Extrude Mesh节点会一次性输出两组几何体:主体Mesh和挤出侧面Side,以及顶盖Top。如果你的目的是“在原有面上长出一截”,那直接把输出Mesh连到下一级即可;如果要单独处理挤出的顶面(比如再倒角),就必须用Top输出。很多新手在这里少连了一条线,结果后面所有的操作都作用在了错误的数据流上,排查半天才发现是Top和Mesh混用了。
2.3 一个可直接复用的参数化切角面板案例
这部分我建议你直接照做一遍。基础场景:一个2x1x0.1米的面板网格,要求在四个角做半径可调的切角,并且切角后边沿带轻微倒角。
节点结构从左到右大概是:
- Group Input接出原始Geometry。
- 用Position和Compare构建四角选区:判断X方向绝对值接近边缘、Y方向绝对值接近边缘,用布尔与组合出四个角。
- 把选区作为Selection输入到Delete Geometry,Domain选Face,删掉四个角的面。
- 用Mesh Boolean节点,以四个圆柱体做差集,切出圆弧角。圆柱体的Radius由Group Input里的Float参数控制。
- 对整体执行Merge by Distance,距离设0.001,把布尔运算产生的重合点清理掉。
- 最后接一个Bevel节点,Radius设为0.01,勾选边域,生成切角边沿的倒角。
这套流程看着不复杂,但真正在建模模式下跑起来,你会有一种“原网格被一点一点修整”的真实感触。参数Radius改动时,四个角同步响应、倒角同步重算,所有操作都留在节点图里,回头要改成直角,把Delete和Boolean断开即可。传统做法遇到这种需求,要么手动修点线面修到崩溃,要么用修改器傻堆一通,最后乱得根本不敢动。
3. 动态网格编辑案例:把一张平面改成参数化台阶
3.1 目标与准备工作
动态网格编辑这个说法,在这个例子里体现得最直观。我找了一个很常见的需求:把一块32x20的网格平面,改造成一个带平台和踏步的台阶模型,踏步高度、平台宽度全部参数化。用传统建模做这种修改,得先加线、再逐排移动,调整一次参数就够呛;用建模模式,一切都在节点图里解决。
准备工作很简单:
- 新建Plane,Subdivision设为30x18左右,让网格足够密。
- 进入建模模式,确认Group Input的Geometry接口拿到的确实是这块平面数据。
这里关键点是平面网格的朝向。默认Plane在XY平面、法线朝Z,这方便我们用Y方向做踏步划分。如果你用的是自己导入的网格,先手动确认一下轴向,别到后面才发现选区全部错位。
3.2 节点图搭建过程:每一步的意图
我按从左到右的顺序写一下完整节点流,顺便解释每一步为什么这么做:
- 建立X轴分区:用Position节点的X分量,经过Map Range节点,从网格的实际宽度映射成0到1的进度值。这个进度值后面用来控制“整个台阶长度的占用比例”。
- 建立踏步阶梯高度:这一步是核心。把上一步算出的进度值乘以台阶总数,取整,再乘以每级高度,就得到了每个位置对应的台阶高度。这个计算过程在传统建模里可以用“逐级叠放方块”来理解,但在节点里,它是以函数方式同时作用于所有顶点的。
- 应用Set Position:把第2步算出的高度作为Position的Offset,沿Z轴写入顶点坐标。到这一步为止,原来平坦的平面已经变成锯齿状的阶梯轮廓。
- 平台区域拉平:用Map Range的曲线控制,让阶梯顶端某一段进度值保持不变,从而形成平台。具体做法是给Map Range加一个阶梯状的截断逻辑——当进度值在平台区间内时,输出固定值,不再继续上升。
- 厚度挤出:给阶梯状网格接Extrude Mesh,沿Z轴向下挤出一个厚度,形成台阶的实体感。这里Offset的Z值设为负的台阶级高即可。
- 封底和封边:用Extrude生成的Side面已经包含侧边,底部再用一个Grid补上或直接使用Grid + Merge,保证模型侧面不会漏光。
- 清理合并:最后接Merge by Distance,把平台边缘和阶梯交界处的重复点合并。
这套流程跑通后,你拖动Group Input里“台阶总数”这个参数,视口里的台阶会瞬间加高或降低,同时平台仍保持原位。这种实时性就是“动态网格编辑”最令人上瘾的地方。
3.3 实时调参的注意事项
动态调参看着爽,但有几个习惯最好早点养成。首先,参数别乱起名。给Group Input接口上的每个输入起一个可读性强的名字,比如stair_count、platform_position、thickness,否则节点多了以后你自己都分不清哪个是哪个。其次,起步阶段先把“台阶总数”放在一个较小的值,比如3到5,方便看结构;确认逻辑无误后再拉高到20到50,避免一开始就大运算量导致卡顿。
还有一点很实际:建模模式下,视口刷新频率和节点复杂度直接挂钩。节点图里如果放了多个Boolean或高精度Bevel,拖动参数时会有明显延迟。我通常的做法是,先建低精度版本调通逻辑,最后再切回高精度网格应用。这个顺序能省下大量等待时间。
4. Geometry Script联动:用Python把重复编辑流程沉淀成资产
4.1 关于Geometry Script的现状说明
先说实话,Geometry Script这个名字在Blender社区里,目前更多是官方提案和早期试验的代名词。它希望提供一种用类Python脚本描述几何操作的方式,让人不用拖拽一堆节点也能构建程序化逻辑。但在当前正式版里,你很难直接把一段“Geometry Script”塞进几何节点修改器运行。
不过这不代表脚本和建模模式没法联动。实际上,通过bpy这个官方Python API,完全可以用脚本创建、修改、参数化驱动一套几何节点组,再让这套节点组在建模模式下接管原网格。我称这个工作流为“脚本生成节点图、节点图驱动网格编辑”,它和Geometry Script的长期目标其实是一致的:把重复劳动沉淀成可复用逻辑。
4.2 用bpy创建建模模式节点组的脚本骨架
下面这段脚本是我在Blender 4.1上验证过的写法,作用是为当前对象创建一套建模模式节点组,并在组件里搭好“输入原网格—挤出Z轴—输出结果”的基础流程:
import bpy def create_modeling_group(obj, group_name="MG_StdEdit"): mod = obj.modifiers.new(name="ModelingEdit", type='NODES') ng = bpy.data.node_groups.new(group_name, type='GeometryNodeTree') mod.node_group = ng # 定义输入输出接口 ng.interface.new_socket(name="Geometry", in_out='INPUT', socket_type='NodeSocketGeometry') ng.interface.new_socket(name="Geometry", in_out='OUTPUT', socket_type='NodeSocketGeometry') ng.interface.new_socket(name="Extrude Height", in_out='INPUT', socket_type='NodeSocketFloat') ng.interface.new_socket(name="Extrude Height", in_out='OUTPUT', socket_type='NodeSocketFloat') # 创建节点 grp_in = ng.nodes.new("NodeGroupInput") grp_out = ng.nodes.new("NodeGroupOutput") extrude = ng.nodes.new("GeometryNodeExtrudeMesh") extrude.inputs["Offset"].default_value = (0.0, 0.0, 0.5) # 连接 ng.links.new(grp_in.outputs["Geometry"], extrude.inputs["Mesh"]) ng.links.new(extrude.outputs["Mesh"], grp_out.inputs["Geometry"]) ng.links.new(grp_in.outputs["Extrude Height"], extrude.inputs["Offset"]) return ng这里有个细节:建模模式下的Group Input,输入插座里的第一个Geometry会被系统识别为“原网格来源”,所以脚本里将输入输出都命名为Geometry是安全的。Extrude Height参数我特意暴露到Group Input上,是为了下一步用脚本批量调参。
4.3 用脚本批量驱动参数实现快速变体
参数驱动的好处,在做批量变体时体现得最明显。假设你要生成5个不同挤出高度的台阶模型,传统方式得手动进去改5次参数,有了脚本就完全不同:
def drive_extrude_height(group_name, height_values): ng = bpy.data.node_groups[group_name] for i, h in enumerate(height_values): # 每个变体复制一份对象和节点组 obj_data = bpy.context.object.data.copy() obj = bpy.data.objects.new(f"variant_{i}", obj_data) bpy.context.collection.objects.link(obj) mod = obj.modifiers.new("ModelingEdit", type='NODES') mod.node_group = ng # 直接改写节点组的默认参数 ng.interface.update() for item in ng.interface.items_tree: if item.name == "Extrude Height": ng.interface.items_tree.remove(item) ng.interface.new_socket(name="Extrude Height", in_out='INPUT', socket_type='NodeSocketFloat') # 将高度作为默认值写入 if h != 0.5: ng.nodes["Group Input"].outputs["Extrude Height"].default_value = h这段脚本省去了逐个修改的成本,配合循环可以一口气产出几十个变体。它本质上是把“节点图逻辑”和“参数配置”解耦,这种思路和Geometry Script想要的表达力方向完全一致。
4.4 脚本、节点图、建模模式之间的边界
我用下来最大的感受是,脚本适合做“生成节点图”和“批量调参”这两件事,而真正精细的编辑手感仍然属于节点图本身。两者不是替代关系,是接力关系:
- 脚本负责把重复、机械、批量化的部分自动化。
- 节点图负责把灵活的、交互性的编辑逻辑保留下来。
- 建模模式负责提供“原网格注入”和“结果覆盖”的桥梁。
日常流程里,我通常先写脚本把几个基础编辑管线建好,保存成blend资产文件;需要新变体时复制一份,进入建模模式微调Selection条件和Offset方向;最后再通过脚本批量导出或生成多版本。这套组合拳用顺了以后,你的建模效率会有一种“别人在点鼠标、你在写编译参数”的落差感。
注意:不同Blender版本对bpy中节点接口(interface.new_socket等)的封装细节略有差异。如果你在4.0以下版本运行,可能需要改用node_group.inputs.new这类旧写法;建议先在一个临时对象上跑通,再铺开应用。
5. 建模模式踩坑清单:选域、修改器栈和数据量
5.1 选区域不一致导致的诡异形变
建模模式里最容易翻车的,就是Selection输入的数据域和操作节点期望的域不一致。比如你用Position节点生成了一个按顶点计算的布尔选区,却把它接到了Delete Geometry的Face Selection上。这时候节点不会报错,但结果会非常诡异——有时候整个面都被删掉,有时候只删一半。
排查方法其实很朴素:先临时断开Selection,确认基础操作无异常;再用Viewer节点分别看Position和Compare的输出,确认你选中的到底是点、边还是面。养成“每个选区先过一遍Viewer”的习惯,能省掉三分之二的排查时间。
另外一个很隐蔽的问题是,当你对Extrude Mesh的输出接了Set Position时,默认处理的域是点,而Extrude输出的Side部分可能包含老点和新点两组数据。如果只打算移动新挤出的顶点,却忘了排除原有点,整个面都会跟着跑飞。解决办法是在Set Position前把Selection接到Extrude的Top输出或Side输出对应的点上,明确“只改新生成的顶点”。
5.2 修改器栈顺序和应用时机的坑
建模模式修改器在修改器栈里的位置,决定了它拿到的是“哪个版本的网格”。这个坑我用一次踩一次,后来才彻底想明白。
如果建模模式修改器前面还挂了细分修改器,那么建模模式的输入其实是细分后的结果,而不是原始基础网格。这意味着你在节点图里做的一切选择、删除、挤出,都会被细分影响。多数情况下这未必是你想要的。反过来,如果你希望建模模式编辑完后整体加细分,应该把细分修改器放在建模模式后面。这个顺序观念和传统建模里“堆修改器”的逻辑完全一致,只是建模模式本身也是一个修改器,很多人会忘了它的“栈位置身份”。
应用时机上,我建议在以下三种情况下才点Apply:模型结构最终确定、需要导出给其他软件、需要把节点图去掉以简化场景。其余时间,保留修改器反而是一种财富——谁也不知道下一秒客户会不会让你“切角半径翻倍”。
5.3 大网格性能与卡顿的排查方向
建模模式处理几万面的网格很轻松,但到了几十万面以上,特别是同时挂着Boolean和Bevel时,视口就明显开始吃力。这时候别急着怪Blender,先按顺序排查:
- 预览精度是否过高:把Bevel的Segments降低,或用Simplify修改器临时减面。
- 是否有多余Boolean:布尔是最吃性能的节点之一,能用Selection和Delete搞定的区域不要上Boolean。
- 视口精简模式:进入节点编辑器的“Proxies”或“简化”显示模式,临时只显示最简网格。
- Merge by Distance的距离是否过大:过大的合并距离会导致大量顶点重算,卡顿加剧。
- 是否在循环区域里塞了高精度计算:如果有重复区域,尽量用较小的迭代次数。
还有一个偏门但有效的技巧:大网格调试时,把Group Input输出接口临时接一个简化Subdivision来观察整体比例,确认形态无误后再把简化节点断开。这套“先看影子再看实形”的做法,能让你在大模型上依然保持流畅的调参体验。
6. 最后分享一点我的真实使用习惯
写了这么多,其实最想告诉你的是:建模模式不是传统建模的替代品,它是一张安全网和一个加速器。我现在做产品级的硬表面模型,流程通常是先快速推敲出基础网格,进入建模模式搭一套参数化编辑管线,然后在这个管线上反复调整比例和细节;确认设计师那边的方向后,再考虑是否应用修改器、进入传统布线精修。这样一来,前期的反复改动永远不会污染原始网格,改十版和改一版的成本差距被压到极小。
一个小建议:给自己建一个“建模模式起步模板”资产文件,里面放好常用的输入输出结构、几个核心节点组合和命名规范的Float参数。每次新项目直接追加这个模板再复制修改,比从零开始拖拽节点快得多。等你形成了自己的节点素材库,建模模式的威力才会真正完整释放。