嗨,

我正在开发的游戏里将会包含一个披萨构建器。为此我一直在研究如何创建风格一致的素材。

我先通过 GPT Images 2.0 制作了参考素材。并计划在 Inkscape 中重新绘制它们。目前我只在 Inkscape 里画好了我的萨拉米香肠片,并且有点不想继续在那里做了。

在我看来这个方案是可行的。让我知道你的想法。每个素材大约消耗 Pro Lite 每周配额的 1-2%。

https://i.imgur.com/z8i0EI5.png

https://i.imgur.com/5rsyE5q.png

以下是 Asta 对工作流的描述:

asset_pipeline/
├── shared/
│   ├── geometry.py       # 网格创建、曲线、边界、父子关系
│   ├── style.py          # 材质、着色节点、轮廓合成器
│   └── export.py         # 相机、构图、渲染、场景保存
├── ingredients/
│   └── example/
│       ├── build.py      # 该原料的几何体及变体
│       ├── sheet.py      # PNG 检查及对比表合成
│       └── render.ps1    # 运行 Blender,然后运行常规 Python
└── output/
    ├── ingredient.blend
    ├── inspection/
    ├── pieces/
    └── manifest.json

可重用模块对应我们的 blender_common.py 和 blender_family.py;每种原料都有自己的 build.py。

  1. 将风格母版转换为显式设置。

母版可以是生成的图像、绘画、精灵或渲染图。有人先解释其视觉效果并记录决策,例如:

json { "nominal_canvas": [64, 64], "export_scale": 4, "supersample": 3, "outline_px_at_nominal": 1.0, "projection": "orthographic_top_down", "shading": "two_tone" }

原料调色板定义材质角色(如外皮、果肉和种子),每种角色包含基础色和阴影色。

向下传递风格意味着将相同的着色器和导出代码导入每个原料构建器。母版图像本身不必嵌入到素材中。

  1. 在原料的 build.py 中生成实际网格。

Blender 的 Python API 接受顶点坐标和面:

```python
import bpy

mesh = bpy.data.meshes.new("IngredientMesh")
mesh.from_pydata(vertices, [], faces)
mesh.update()

obj = bpy.data.objects.new("Ingredient", mesh)
bpy.context.collection.objects.link(obj)
obj.data.materials.append(material)
```

原料特定的工作是计算顶点和面。

对于圆环,定义一个包含外壁、顶面和内壁的横截面。将每个横截面点围绕一个角度扫描:

x = radius * math.cos(angle) y = radius * math.sin(angle) z = height

用四边形面连接相邻样本。完整旋转产生一个圆环;受限角度范围产生一个扇形,其两端需要闭合面。

其他形状使用不同的构造方法:切割片的挤出轮廓、茎的带厚度曲线、以及种子的扁平化小网格。倒角和细分修改器可软化选中的边。

  1. 通过 Python 构建共享着色系统。

style.py 创建一个 Blender 材质节点组。我们的处理方式根据空间边界在两种颜色之间进行选择。

为进行通用演示,将片的投影坐标归一化为 u、v(介于 0 和 1 之间),然后使用:

boundary = 0.35 + 0.30 × (3u² − 2u³) colour = shade_colour when v > boundary, otherwise base_colour

这提供了一个简单的曲线划分,而不暴露母版的实际路径。

在 Blender 中,这变成了坐标、数学运算、比较和颜色混合节点,输入到自发光着色器。自发光提供对纯色的直接控制。我们的实现还使用表面朝向,使转向背面的侧面用相同的阴影色着色。

属于同一片的所有组件引用一个共享坐标的空物体。因此外皮、果肉和种子使用同一个连续的着色边界。

  1. 构建并摆放明确的变体。

每个原料脚本都包含其变体的显式参数:厚度、开口大小、曲率、切割角度、种子位置和朝向。

脚本构建每个变体,将其组件作为子级挂载到一个空物体,应用姿态,然后建立其着色坐标。这个顺序确保当几何体改变朝向时,着色一致对齐。

参数是可重复的。如果使用随机变化,应记录种子。视觉修正变为对这些参数或构造函数的修改。

  1. 在合成器中生成轮廓。

我们的轮廓来自渲染的剪影:

渲染 alpha → 扩展蒙版 → 用轮廓色给扩展蒙版上色 → 将原始渲染放在上面

在 Blender 中,相关节点是渲染层、膨胀/侵蚀、设置 Alpha 和 Alpha 叠加。

这使得轮廓宽度在渲染像素中可控。对于上述通用配置:

检查轮廓 = 1 个标称像素 × 4 倍导出缩放 × 3 倍超采样 = 12 像素

相机取景必须为这种向外扩展预留空间。

  1. 一次渲染一个孤立的片。

导出脚本配置场景:

python scene = bpy.context.scene scene.render.engine = "BLENDER_EEVEE" scene.render.film_transparent = True scene.render.image_settings.file_format = "PNG" scene.render.image_settings.color_mode = "RGBA" scene.view_settings.view_transform = "Standard" camera.data.type = "ORTHO"

然后它隐藏其他变体,评估当前片的几何体(包括修改器),并计算其边界。这些边界决定相机中心点和正交缩放。

对于标称 64×64 的画布,使用示例设置:

标称画布: 64 × 64
导出的 PNG: 256 × 256
检查渲染: 768 × 768

使用 bpy.ops.render.render(write_still=True) 渲染,然后下采样。使用 bpy.ops.wm.save_as_mainfile(...) 保存可编辑场景。

  1. 在 Blender 外部运行图像检查并合成审核表。

使用 Pillow 的常规 Python 打开导出的 PNG,检查尺寸、透明度、剪影边界和居中。原料特定检查可以确认圆环仍有一个透明中心。

表格脚本会调整大小并放置完成后的图像。它会生成放大的检查视图和使用明确放置尺寸的视图。一个 256 像素的源文件可能代表一个 16 像素的骰子或一个 90 像素的圆环;这种关系属于放置元数据。

JSON 清单记录变体 ID、尺寸、枢轴点、预期尺寸和源哈希。自动检查确保技术正确性;视觉检查则确认识别度和一致性。

启动器连接这些阶段:

$blenderExe = 'C:\Program Files\Blender Foundation\Blender 5.2\blender.exe'

& $blenderExe --background --factory-startup --python-exit-code 1 `
    --python .\ingredients\example\build.py
if ($LASTEXITCODE -ne 0) { throw 'Blender build failed.' }

python .\ingredients\example\sheet.py
if ($LASTEXITCODE -ne 0) { throw 'Sheet generation or checks failed.' }

Blender 运行 build.py;普通 Python 运行 sheet.py。.blend 文件存储生成的可编辑网格、材质和场景。脚本保留了构建配方,因此可以重新生成修订版;仅保存在场景中的手动编辑需要传回该配方,才能在重建后保留。