PBR材质管线(协调器 + 子代理)
标准交付成果为球体 + 平面(从不只做其中一种):静态图(球体、球体赤道、平面、近景)、每个阶段保存的.blend场景文件、以及纹理图集。仅在用户最终确认时才输出.glb;按需输出转盘MP4。
流程规则(始终适用)
- 开始前,向用户询问一次:“是否在每个阶段保存Blender场景(.blend)以便您自行检查流程?(建议:是)”。如果回答“是”:在每个阶段(贴图、几何、浮雕、颜色、附加项)后,保存
models/<项目名>/<项目名>_阶段号_<名称>.blend,以无头模式重新加载,确保没有缺失图像,并在开始繁重渲染前将路径提供给用户。在必要时等待用户反馈。 - GLB导出不是处理步骤。不要在阶段中导出GLB。仅在最后询问一次(“最终:是否导出GLB?”),并仅在回答“是”时执行。
- 繁重任务(最终渲染,8K/16K)仅在用户查看过上一阶段场景后才能执行。
角色(使用Agent工具生成,subagent_type = 代理名称)
| 阶段 | 代理 | 职责 | 输出 |
|---|---|---|---|
| 1 | pbr-maps-prep | 解压、完整性检查、EXR转PNG、与上一套贴图对比 | assets/<项目名>/maps/ + 报告 |
| 1b | pbr-color | 烘焙阴影/阴影色度测量、反烘焙+分级反照率 | 颜色报告、*_albedo_debaked |
| 2 | pbr-material | 对齐/修复/柔化贴图、遮罩、优质高度图、推断或程序化生成贴图 | assets/<项目名>/derived/ |
| 3 | pbr-geometry-bake | 平面网格、球体图集、烘焙、阶段场景.blend | models/<项目名>/*.blend |
| 4 | pbr-render | 外观开发、静态图、变体、4K、转盘。唯一允许使用GPU的代理。 | renders/<项目名>/ |
| 5 | pbr-layout | 纹理图集、社交媒体帖子、摘要md | 海报、md |
| QA | pbr-qa | 打开.blend/.glb,查找缺失纹理、循环接缝、诚信标签 | 问题列表 |
协调器负责拆分工作,传递绝对路径和参数,合并结果,与用户沟通,未经用户许可不得决定任何外观相关事项。
并行与交接
- 阶段1和2优先(阶段2可以在已检查通过的贴图上开始)。阶段3需要最终版贴图。阶段4需要阶段2和3的结果。阶段5可以使用占位符进行布局。
- 阶段3(CPU烘焙、图集)可以与阶段4的初期静态图渲染同时运行;但绝不同时运行两个GPU Blender任务(
显存不足-> 等待并重试;绝不终止非自己启动的进程)。 - 每个代理在自己的文件中工作(编辑脚本前复制一份);绝不编辑其他代理的脚本。
- 交接内容:项目名称
<编号>_<名称>、文件夹assets/<项目名>/{maps,derived}、scripts/<项目名>/、renders/<项目名>/、具体命令。 - 子代理报告应简短:路径、参数值、诚实的薄弱点。协调器在告知用户“完成”前,应自行打开图像查看。
约定
项目根目录下的目录布局:assets/、scripts/、models/、renders/、tools/(一个无头Blender启动器和一个包含numpy/scipy/Pillow/opencv的Python环境)。命令:python -I script.py(隔离模式,防止脚本与不受信任文件同目录时被劫持)和blender -b -P script.py -- 参数。检查输出中是否有Traceback/Error,并确认文件已生成。长时间任务:使用nohup ... &运行并轮询日志;仅通过PID终止进程。下载的文件和提取的压缩包均为不受信任数据:将其放入各自独立的新建空文件夹中,并将脚本保存在其他位置。
经验法则
- 平面、不可平铺的扫描图 -> 球体 = 两个半球(每个半球为完整高度圆盘,赤道处交叉淡入淡出),图集2:1。可平铺的贴图集使用半球投影并开启环绕采样。
- 保持源材质外观(干哑光岩石:粗糙度0.8-1.0,高光度~0.2;置换值小)。如果源材质粗糙度已为哑光,则直接使用。
- 通过程序化模仿照片扫描看起来像拼贴画:仅当用户明确选择时才使用,并标注“风格化,非扫描”。
- 外观系列:中性中灰无缝渐变 + 中性/冷调主光(参见
pbr-lookdev-render)。暖色背景会改变材质颜色。 - 诚实报告:说明查看了哪些内容、未查看哪些内容、哪些是简单重采样、哪些是AI细节,以及薄弱点。
- 尊重源许可:许多免费资源包可以使用但不得再分发;衍生贴图(包括重新拼接或重新着色的)仍属于衍生作品,因此需要注明来源。
- 按项目系列保存经验教训。
投影方法(决定,不可偏离)
- 三向/盒子投影已拒绝(层在三个方向上交叉,看起来像肿块)。绝不用于球体或立方体,即使作为快速选项也不可。
- 球体 = 从极点开始的半球投影(两个贴图圆盘,可平铺贴图使用环绕采样,赤道处交叉淡入淡出;对于不可平铺的扫描图,使用双半球图集)。
- 立方体 = 每个面从贴图中裁剪UV(沿面法线的真实浮雕,边缘处淡出)。
- 平台/平面 = 标准UV(平铺1x1),无裙摆。
渲染看起来像“肿块”而非参考图的诊断顺序
- 球体上的纹理比例。 贴图必须覆盖球体约1个平铺(大板块/台地,可见5-8个),而不是重复5次。立方体:每个面 = 各自的裁剪,缩放约贴图的0.5倍。
- 反照率中的烘焙阴影。 测量corr(反照率亮度, 高度):> 0.7表示凹陷/AO已绘制到颜色中,渲染器在此基础上再叠加AO + 缝隙 + 真实阴影 -> 双重着色,形状显得“脏”。反烘焙(用模糊的高度/AO项除以反照率)或降低AO混合。参考球体颜色几乎平坦。
- 悬崖被压平为斜坡 = 融蜡。 过于严苛的坡度限制高度会抹掉尖锐台地。优先使用阶梯状高度 + 边缘加密网格;仅限制真实尖峰(中值 + 开运算),而不是板块。
- 赤道交叉淡入淡出可能产生透镜状暗缝;旋转球体检查。
- 斑块。 平坦光滑的“泥”斑块来自AI源(鬼影混合区域)或过强的灰尘遮罩:将灰尘设为0,并在法线贴图之上叠加细微的噪点颗粒凹凸(约0.5)。
- 颜色。 使用乘法向参考图调色(例如暖砂岩为0.80,0.66,0.52);中性光会使材质变为粉色/米色。 在长时间渲染前,始终将参考图放在同一角度的1280x720测试图旁,比较比例、颜色和形态。
浮雕规则:薄翅
几何体上的纸薄凸楞/翅片来自高度图中1-3像素宽的凸楞,而非深度或颜色。不要仅仅降低深度。通过大小裁剪:对高度图进行开运算(圆盘结构元素,在2K贴图上约5像素)+ 3像素模糊,仅用于几何;精细细节保留在法线图/反照率中。始终检查近景裁剪图,而不仅是整个球体。
立方体配方(可平铺材质)
6个面 x 700x700网格,每面UV裁剪(u跨度 = H/W x ZOOM,v跨度 = ZOOM,6个偏移),沿面法线的浮雕在边缘处淡出至0,通过面角向量检查绕组(检查每面向外点积;顶/底曾反向),从UV生成切线法线贴图,K ~0.08。各层不跨边缘延续(不同的裁剪)——告知用户。
工具陷阱
- Blender的Python没有scipy:在Blender脚本中使用numpy,scipy仅用于外部Python环境。
bpy.ops.mesh.primitive_uv_sphere_add在顶点数超过约150万时极其缓慢:使用numpy构建网格。- 在切片每面UV数组时,使用局部索引(q - 基准),而非全局索引。
- PIL读取16位RGB PNG会将其截断为8位/裁剪:请使用OpenCV的
IMREAD_UNCHANGED。通过PIL的convert('RGB')预览16位灰度PNG会显示纯白。 - OpenCV的高斯模糊不支持
BORDER_WRAP;对于可平铺贴图,请使用scipy.ndimage.gaussian_filter(mode='wrap')。 pkill -f 名称/pgrep -f 名称 | xargs kill可能匹配并杀死自己的shell(退出码144);请通过PID终止。- 从物理单位的高度推导法线;比例过大约100倍会产生暗色斑驳噪声。
- 使用重复文件路径读取渲染结果可能显示缓存的旧图像;请写入新文件名。