在 Rhino 里完成一个复杂曲面之后,最容易被低估的一步是表达。曲面本身只有几何信息,没有材质、没有颜色、也没有语义;一旦需要把建筑表皮分层、产品渐变、数据可视化结果或 3D 打印样件涂上颜色,手动贴图很快就会失控。Grasshopper 参数化曲面 AI 着色提供了一条更可控的路径:把曲面 UV 参数域当作颜色映射的坐标系,把 AI 生成的色板或语义描述当作输入,再通过数据树把几何细分点与颜色值一一对应,最终形成可拖动滑杆、可批量对比、可导出到渲染或打印的自动化配色工作流。
这篇内容面向已经会用 Rhino 和 Grasshopper 基础电池、但还没系统做过曲面着色的设计师与工程师。读完你会对两个问题形成自己的判断:第一,颜色如何稳定地“贴”到参数化曲面上;第二,AI 在这个流程里到底能介入到哪一步。文中示例使用 Grasshopper 默认电池和 Python Script 组件,不依赖收费插件,Rhino 6 以上版本都能复现。
1. 先理解曲面着色到底在解决什么设计问题
1.1 从单一材质到信息可视化:为什么需要给曲面配色
给曲面配色不是“把模型变好看”这么简单。实际项目里,颜色的作用常常是信息编码:
- 建筑表皮分析:用颜色表达日照时长、风压分布、造价梯度。
- 产品设计:用渐变色区分材质分区、功能区域或装配层级。
- 数据可视化:把统计数据映射到三维模型上,形成空间热力图。
- 3D 打印与数控加工:用颜色表达打印分区、纹理贴图或工艺路线。
这些需求的共同点是:颜色不是最后一步特效,而是几何数据链路的终点。如果直接在 Rhino 里用取色器一把一把刷,曲面一旦调整,颜色就对不回去。参数化着色的价值在于把“曲面几何”和“颜色数值”绑定在同一个数据流里,几何一变,颜色自动重算。
1.2 参数化着色的核心:UV 参数域与颜色数据一一对应
在 Grasshopper 里,曲面的 UV 参数域决定了颜色映射的坐标系。每个 NURBS 曲面都有自己的 U、V 方向,曲面上的任意一点都能用一对 (u, v) 坐标表达。颜色渐变本质上就是把一个 0 到 1 的数值分配给每个点。
这里有一个容易被忽视的“重参数化技巧”:Grasshopper 中很多曲面输入,默认的 UV 域并不是 0 到 1,可能是 0 到 12.7,也可能是 5 到 20。如果直接把 U 值接到渐变的 t 输入上,颜色会集中在参数范围很窄的区域,甚至完全错位。
正确做法是先把曲面重参数化:
- 在 Grasshopper 中,找到连接曲面的输入端,右键选择 Reparameterize。
- 部分版本也可以从 Surface 面板的 Util 分组里找到 Reparameterize 电池。
- 重参数化后,曲面 UV 域会被统一到 0 到 1,颜色映射才能与曲面比例保持一致。
同时要注意,Divide Surface 输出的点列表是按照 UV 方向排列的。颜色列表也必须按同样的顺序组织,否则会出现“颜色对不上位置”的经典错误。
1.3 把 AI 放进配色流程的三种合理方式
AI 在这一流程里不是取代参数化逻辑,而是扮演输入源和辅助工具。常见介入方式有三种:
- 语义生成色板:用提示词让大模型给出成套 HEX 颜色,例如“海边日落、珊瑚橙到深海蓝、8 个渐变色阶”。
- 图片提取主色:用 Python 脚本或图像工具从参考图里提取主色,再转成 Grasshopper 可读的颜色列表。
- 代码生成辅助:用 Cursor、PyCharm AI 插件、GitHub Copilot 等工具生成 GH Python 或 C# 脚本片段,减少手写数据匹配代码的负担。
这里要提醒一点:AI 生成的色板往往“好看但不够工程”,比如对比度不足、色盲友好度差、色阶数量过多。AI 生成的代码则可能存在版本兼容问题,因为 Grasshopper 的电池名在 Rhino 6、7、8 之间有差异。落地前要做校验,不能直接拿来就用。
2. 环境准备:版本、显示模式与 AI 工具链
2.1 版本组合与插件检查清单
Grasshopper 曲面着色主要依赖内置组件,不需要太多额外插件。但版本差异会影响电池名称和菜单位置,建议先确认下表。
| 软件 | 推荐版本 | 说明 |
|---|---|---|
| Rhino | 6 / 7 / 8 | Rhino 6 使用 GH 1.0,Rhino 7/8 内置新版 GH |
| Grasshopper | 随 Rhino 安装 | Rhino 8 的 GH 2.0 部分电池命名有调整 |
| T-Splines | Rhino 6 时代的插件 | 旧项目可能使用,新项目建议改用 Rhino 7+ 的 SubD |
| Python 组件 | 内置 | 无需额外安装,注意输出类型匹配 |
| Mesh 颜色组件 | 内置 | 用于把颜色写入网格顶点再烘焙导出 |
网上流传的 grasshopper 汉化版安装包,本质是修改语言资源的非官方版本,版本往往落后于官方发布。遇到组件缺失或电池报错时,优先对比官方版本;如果只是界面习惯问题,建议以官网安装包为准,避免后续排查时多一个变量。
2.2 显示模式设置:颜色看不见时先改这里
很多人在 GH 里连好颜色节点后发现“屏幕上一片灰”,第一反应是代码写错了,其实可能是显示模式问题。
Grasshopper 的预览颜色受 Rhino 显示模式影响。推荐使用 Shaded、Artistic 或 Ghosted 这类显示模式。某些渲染模式不一定会显示 GH 的预览色,尤其是在 Rhino 8 中,不同显示管线对顶点色的支持并不一致。
检查顺序:
- 确认组件右上角的预览开关是开启状态,且没有把整个 Group 隐藏。
- 在 Rhino 中把显示模式切换到 Shaded 或 Artistic。
- 用 Custom Preview 组件显式指定颜色,而不是依赖 GH 默认预览。
- 如果目标是把颜色烘焙进 Rhino 对象,在电池输出端右键 Bake,烘焙时勾选颜色相关选项。
Custom Preview 组件位于 Display 面板的 Preview 分组,不同版本名字略有差异,基本作用是把一组颜色绑定到一组几何体上显示。
2.3 AI 辅助工具的准备
这一条工作流里常用的 AI 工具包括:
- 文本生成对话工具:用来生成色板、解释脚本逻辑、排查报错。
- 代码生成插件:Cursor、PyCharm AI 插件、IntelliJ IDEA 的 AI 插件、GitHub Copilot。
- 图像取色脚本:Python 的 Pillow 库可以快速从参考图提取主色。
- 在线取色工具:可以把 AI 输出的颜色名或截图还原成 HEX 值。
使用 AI 工具的时候,建议在提示词里明确要求“只输出 HEX 颜色列表”,并且说明用途是 Grasshopper 参数化渐变。这样能减少 AI 输出冗长描述、夹带无效颜色的概率。
3. 最小参数化着色案例:从 UV 到渐变映射
3.1 创建测试曲面并重参数化
先用最简单的平面曲面跑通流程。在 Grasshopper 中按下面结构连线:
Rectangle (宽度 10, 高度 10) → Boundary Surfaces → S 输出 → Evaluate Surface在 Boundary Surfaces 输出端的曲面参数上右键,选择 Reparameterize。这一步把 UV 域变成 0 到 1。
验证重参数化是否生效:把曲面接入 Surface Closest Point 组件,让它在曲面上取若干点,检查返回的 UV 值是否都在 0 到 1 范围内。如果不在,说明重参数化没有成功,或者你接入了另一个未重参数化的曲面分支。
3.2 用 Gradient 电池建立颜色映射
Grasshopper 的 Gradient 组件位于 Params 面板的 Input 分组,有些版本显示为 Colour Gradient。拖入后右键可以编辑渐变色标。
把 Evaluate Surface 输出的 U 值接入 Gradient 的 t 输入。由于曲面已经重参数化,U 的范围就是 0 到 1,刚好对应渐变的左端到右端。
如果曲面没有重参数化,就需要先用 Remap Numbers 把 U 缩放到 0 到 1:
U 值 → Remap Numbers → source domain: 曲面原始 U 域 → target domain: 0 到 1 → tGradient 输出的颜色列表会按输入 t 的顺序逐点生成。只要点列表和 t 列表长度一致,颜色数量就会和点的数量一致。
3.3 用 Python Script 做更自由的渐变插值
Gradient 电池适合快速预览,但要做多色板切换、方向控制、颜色校验,用 Python Script 组件更灵活。
在 GH 中双击画布,输入 Python,创建一个 Python Script 组件。设置以下输入:
S: 重参数化后的曲面。P: Divide Surface 输出的点列表,需要先 Flatten。HexList: 一组颜色字符串,例如["#FF6B35", "#FFD166", "#06D6A0"]。Alpha: 不透明度整数,默认 255。
示例脚本:
import System.Drawing def hex_to_color(hex_str, alpha=255): h = hex_str.strip().lstrip('#') r = int(h[0:2], 16) g = int(h[2:4], 16) b = int(h[4:6], 16) return System.Drawing.Color.FromArgb(alpha, r, g, b) def lerp_color(c1, c2, t): r = c1.R + (c2.R - c1.R) * t g = c1.G + (c2.G - c1.G) * t b = c1.B + (c2.B - c1.B) * t a = c1.A + (c2.A - c1.A) * t return System.Drawing.Color.FromArgb( int(round(a)), int(round(r)), int(round(g)), int(round(b)) ) palette = [hex_to_color(x, Alpha) for x in HexList] result = [] for pt in P: ok, u, v = S.ClosestPoint(pt, 0.001) if not ok: result.append(System.Drawing.Color.Gray) continue t = u if len(palette) == 1: result.append(palette[0]) continue seg = t * (len(palette) - 1) i = int(seg) if i >= len(palette) - 1: result.append(palette[-1]) else: result.append(lerp_color(palette[i], palette[i + 1], seg - i))这段脚本做了三件事:
- 把 HEX 字符串解析成颜色对象。
- 对输入点逐个求最近 UV 坐标。
- 根据 U 值在色板相邻颜色之间做线性插值。
关键点在于S.ClosestPoint(pt, 0.001)返回三个值:是否成功、U 值、V 值。因为曲面已经重参数化,U 值可以直接当渐变比例用。
脚本输出的result接到 Custom Preview 组件的颜色输入,再把曲面几何接入同一组件,就能看到颜色均匀分布在曲面上。
4. 让 AI 参与配色:色板生成、语义提取与提示词模板
4.1 AI 色板生成的三种输入方式
AI 色板生成可以按输入方式分成三类,实际项目可以混用。
文字语义输入适合设计前期。给 AI 一段描述,让它返回成套颜色:
你是一名建筑与产品配色顾问。请围绕关键词「海边日落」生成一套适合参数化曲面渐变的色板。 要求: 1. 输出 8 个 HEX 颜色。 2. 从浅色到深色排列。 3. 说明哪个颜色适合作为主色。 4. 不要输出多余解释,先给出颜色列表。图片参考输入适合有明确视觉方向的项目。把你找到的参考图交给 AI 图像工具,或者直接用 Python 脚本提取主色。
已有品牌色输入适合企业项目。把品牌标准色粘贴给 AI,要求它补充中间过渡色,使其适合渐变映射。
4.2 用 Python 把参考图提取为主色板
如果参考图是一张照片或效果图,可以用 Pillow 快速提取主色。安装 Pillow 后运行下面脚本:
from PIL import Image img = Image.open("reference.png").convert("RGB").resize((200, 200)) qimg = img.quantize(colors=6) palette = qimg.getpalette() for i in range(0, 6 * 3, 3): r, g, b = palette[i], palette[i + 1], palette[i + 2] print("#{:02X}{:02X}{:02X}".format(r, g, b))量化后得到 6 个主色,颜色数量可以根据需要调整。提取结果可以直接复制到 GH 的 HexList 输入里。
要注意,量化结果是按颜色出现频率聚类的,不代表视觉上的美学顺序。作为渐变使用前,需要自己判断排列方向,或者在 Grasshopper 里用 Python 脚本按亮度排序。
4.3 提示词模板与结果校验
AI 生成色板后,不要直接接进 Grasshopper。先做三轮校验:
- 格式校验:确认每个颜色都是标准的 6 位 HEX。
- 对比度校验:相邻两个颜色之间是否有足够区分度。
- 色板规模校验:渐变最多建议 5 到 12 个色阶,超过 12 个容易产生肉眼难辨的色带。
可以写一个简单的亮度函数辅助判断:
def luminance(hex_str): h = hex_str.lstrip('#') r, g, b = (int(h[i:i+2], 16) / 255 for i in (0, 2, 4)) return 0.2126 * r + 0.7152 * g + 0.0722 * b相邻颜色的亮度差最好大于 0.05,否则在投影或打印时很容易糊成一片。
5. 自动化工作流:脚本组件、批量导出与方案对比
5.1 让 Python 组件支持渐变方向切换
第 3 节的脚本只能按 U 方向渐变。实际项目里需要按 V 方向、按对角线、甚至按到某条曲线的距离渐变。
最简单的方式是给脚本增加一个Direction滑块,0 表示按 U,1 表示按 V:
if Direction == 0: t = u elif Direction == 1: t = v else: t = (u + v) / 2.0还可以加一个Reverse布尔值,True 时把 t 改成1 - t。这样同一组色板可以快速对比不同方向的效果,不需要重新连线。
如果希望渐变形状更可控,可以使用 Graph Mapper 组件对 t 值做曲线映射。Graph Mapper 位于 Params 面板的 Input 分组,允许你用贝塞尔曲线把线性的 0 到 1 重新塑造成先快后慢、先慢后快等节奏。
5.2 批量导出配色结果
着色结果最终要进入渲染或制造流程,导出方式取决于目标:
- 渲染:在 RHINO 里烘焙几何后,用 V-Ray 或 Enscape 加载颜色材质。GH 预览色不会自动进入渲染器,需要手动关联。
- 3D 打印:如果打印机支持全彩打印,颜色需要写入网格顶点后导出为 3MF 或 VRML 格式。Grasshopper 的 Mesh 面板里有 Mesh Colour 类组件,可以把颜色写进网格顶点颜色通道。
- 施工与加工:颜色不作为视觉输出,而是作为分区编码。把颜色值转换成面板编号,导出成表格和图纸。
批量对比方案时,可以把多套色板分别接到不同的 Python 组件,摆在同一 Rhino 场景中,用 Rhino 的 View Capture To File 命令截图对比。这样比来回切换参数更直观。
5.3 从单次着色到参数化方案对比
着色流程参数化的好处是,色板本身也可以变成“变量”。把色板列表定义为多