feat(ai-art): 路径C窗户字汇表(含阳台标准件修正)及首图验证
- 修正阳台标准件prompt:两扇→三对6扇+物理依据(正投影/轴测两件) - 重生成阳台2件并核验;4标准件(卧室窗/厨卫窄窗/阳台正投影/阳台轴测)全合格 - 新增窗户字汇表(_build_parts_sheet.py 拼接3正投影件+中英标签) - 路径C组装prompt + codex完整prompt + codex Mac指南 - 工具:_gen_standard_parts.py / _run_pathc_fuse.py - 路径C首图(apiyi三图融合,阳台6扇一次对,风格统一无割裂)
This commit is contained in:
@@ -0,0 +1,134 @@
|
|||||||
|
# 路径 C 组装 · codex 通道指南(Mac 尝试)
|
||||||
|
|
||||||
|
> 用 Codex CLI 内置 `image_gen` 跑「路径 C:风格图 + 外立面图 + 窗户字汇表 + 文字布局 → 单元南立面」。
|
||||||
|
> 三图融合是 codex 通道的强项:最多 5 张参考图、融合稳定、走 ChatGPT Plus 订阅额度(不按张计费)。
|
||||||
|
> 创建:2026-06-23
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 为什么有这篇 + 通道选择
|
||||||
|
|
||||||
|
路径 C 组装是**三图融合**(风格 + 外立面 + 窗户字汇表)。
|
||||||
|
|
||||||
|
| 通道 | 三图融合 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| **codex**(本文) | ✅ 稳定 | 最多 5 图、融合可靠、免费(Plus 额度)。**但需人在终端跑**(Claude 的安全分类器硬拦 `--dangerously-bypass-approvals-and-sandbox`,不可配置放行) |
|
||||||
|
| apiyi 兜底 | ⚠️ 不稳 | `images.edit` 多图支持差,失败会降级到"单图 + 文字",**丢掉窗户字汇表 → 路径 C 破功** |
|
||||||
|
|
||||||
|
**Windows 实测结论(2026-06-23)**:本机 Windows 上 codex 内部 `image_gen` 工具调用失败,整条 codex 路径跑不通。已改用 apiyi 兜底先出图验证窗户准确度;**codex 三图融合留待 Mac 上验证**(Mac 环境下 codex 调用 image_gen 的成功率更高)。
|
||||||
|
|
||||||
|
> 通用 codex 通道说明见 [`codex生图工作规范.md`](./codex生图工作规范.md)。本文只聚焦「路径 C 组装」这一具体场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 前置自检(Mac)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CODEX="$HOME/.codex/packages/standalone/current/bin/codex" # standalone 安装路径
|
||||||
|
"$CODEX" --version # 验证可执行
|
||||||
|
"$CODEX" login status # 应 "Logged in using ChatGpt"(走订阅,非 API 计费)
|
||||||
|
"$CODEX" features list | grep image_generation # image_generation stable true
|
||||||
|
grep auth_mode ~/.codex/auth.json # "auth_mode": "chatgpt"
|
||||||
|
```
|
||||||
|
|
||||||
|
- `auth_mode=chatgpt` = 走订阅额度;若显示 `api_key` 则按张计费,需 `codex login` 用 ChatGPT 重新登录。
|
||||||
|
- codex 不在默认 PATH,必须用绝对路径或先加 PATH。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 素材清单(都在 `ai-art-research/` 下)
|
||||||
|
|
||||||
|
| 角色 | 文件 |
|
||||||
|
|------|------|
|
||||||
|
| 图1 风格参考 | `参考图/游戏截图/深夏时光/深夏时光-下午-街景.png` |
|
||||||
|
| 图2 外立面参考 | `参考图/真实场景/东井村/QQ20260616-174350.png` |
|
||||||
|
| 图3 窗户字汇表 | `生成结果/窗户标准件/标准件合集图.png` |
|
||||||
|
| 完整 codex prompt(自包含) | `prompts/_codex_路径C组装完整prompt.txt` |
|
||||||
|
|
||||||
|
> 窗户字汇表由 `tools/_build_parts_sheet.py` 把 3 个正投影标准件(卧室普通窗 / 厨卫窄窗 / 阳台正面)拼成,生成方法见该脚本。
|
||||||
|
> 组装正文(不带 codex 约束语、不带图引用的纯净版)存档于 `prompts/居民楼-单元南立面-路径C-窗户字汇表-v1.txt`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 一条命令跑(Mac bash)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CODEX="$HOME/.codex/packages/standalone/current/bin/codex"
|
||||||
|
RESEARCH="/绝对路径/ai-art-research" # ← 改成 Mac 上的实际路径
|
||||||
|
|
||||||
|
cd "$RESEARCH"
|
||||||
|
|
||||||
|
"$CODEX" exec \
|
||||||
|
--enable image_generation \
|
||||||
|
--dangerously-bypass-approvals-and-sandbox \
|
||||||
|
--skip-git-repo-check \
|
||||||
|
-C "$RESEARCH" \
|
||||||
|
-o "$RESEARCH/.codex_lastmsg.txt" \
|
||||||
|
"$(cat prompts/_codex_路径C组装完整prompt.txt)"
|
||||||
|
```
|
||||||
|
|
||||||
|
**四个不可省的 flag**:
|
||||||
|
1. `--enable image_generation` —— `codex exec` 默认不启用生图工具,会话里没有 `image_gen`。
|
||||||
|
2. `--dangerously-bypass-approvals-and-sandbox` —— 不加会被默认沙箱断网。
|
||||||
|
3. `-C "$RESEARCH"` —— 工作目录设为 `ai-art-research`,让 `./参考图/...` 相对路径能找到。
|
||||||
|
4. `--skip-git-repo-check` —— 该目录非 git 仓库根。
|
||||||
|
|
||||||
|
`-o` 把 codex 最后一条消息(含生成图路径)写到 `.codex_lastmsg.txt`,比从 stdout 捞可靠。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 跑完收尾(命名 + meta)
|
||||||
|
|
||||||
|
codex 把生成图存到默认目录(`~/.codex/generated_images/<session>/ig_*.png`),路径也写进 `.codex_lastmsg.txt`。按现有规则落盘到:
|
||||||
|
|
||||||
|
```
|
||||||
|
生成结果/路径C组装/<时间戳>_gpt-image-2_fusion.png
|
||||||
|
```
|
||||||
|
|
||||||
|
同名 `.meta.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"model": "gpt-image-2",
|
||||||
|
"backend": "codex",
|
||||||
|
"mode": "multi_reference_fusion",
|
||||||
|
"style_reference": "参考图/游戏截图/深夏时光/深夏时光-下午-街景.png",
|
||||||
|
"content_references": [
|
||||||
|
"参考图/真实场景/东井村/QQ20260616-174350.png",
|
||||||
|
"生成结果/窗户标准件/标准件合集图.png"
|
||||||
|
],
|
||||||
|
"prompt": "<prompts/_codex_路径C组装完整prompt.txt 全文>",
|
||||||
|
"size": "1536x1024",
|
||||||
|
"quality": "medium",
|
||||||
|
"timestamp": "<ISO>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> `.codex_lastmsg.txt` 是临时文件,读完可删(`ai-art-research/` 整目录已被 `.ignore` 屏蔽,不进 git)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 验证(路径 C vs 路径 B / v4 基线)
|
||||||
|
|
||||||
|
路径 C 的核心假设是「窗户从字汇表复用结构」比 v4「文字钉死结构」更准。重点核对:
|
||||||
|
|
||||||
|
- **卧室段**:两扇推拉、每扇宽高比 1:2、把手在两端、两个卧室的窗独立不合并。
|
||||||
|
- **阳台段**:**三对共 6 扇**、每扇 1:2、横向均匀填满阳台宽度、是外凸全高阳台(不是飘窗、不是两扇大窗)。
|
||||||
|
- **风格统一**:窗户用 cel-shaded 暖色渲染、与墙面融为一体(**没有**灰平涂工程图贴在暖色立面上的割裂感——这是路径 C 最大风险点)。
|
||||||
|
- 与 `prompts/居民楼-单元南立面-户型图推导-v4.txt` 的产物正面对比窗户准确度。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 已知坑
|
||||||
|
|
||||||
|
| 现象 | 处理 |
|
||||||
|
|------|------|
|
||||||
|
| 融合没用到图 3(窗户表) | codex agent 偶尔不 view_image。把 `标准件合集图.png` 复制进 `-C` 目录、用相对路径 + 明确 `Image 1/2/3` 引用重试 |
|
||||||
|
| 429 / 限额 | Plus 约 40–50 张/3h。撞限额切 apiyi(但 apiyi 三图不稳,见第 0 节) |
|
||||||
|
| codex 自己写起 Python/Node 脚本 | prompt 开头"用内置工具、不要写脚本"约束语已防;若仍跑偏,重申该约束 |
|
||||||
|
| Windows 下 codex image_gen 调用失败 | 已知(本文第 0 节)。Mac 上重试;或暂用 apiyi 兜底 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 后续:三立面 → 单元模型
|
||||||
|
|
||||||
|
路径 C 验证通过(窗户准确度优于 v4)后,下一步用同一户型推导该单元的**南 / 北 / 山墙**三个立面,喂给建模 AI 生成一个单元的完整 3D 模型,再实例拼接成整楼——呼应 Issue #44 的最终目标。
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
用 Codex 内置的 image_gen 工具(gpt-image-2)直接生成 1 张图,不要写任何 Python/Node 脚本,不要使用 OPENAI_API_KEY 或外部 Images API。
|
||||||
|
|
||||||
|
参考图(已在工作目录下,请先用 view_image 逐张加载,再融合生成):
|
||||||
|
- Image 1(风格参考·《深夏时光》截图): ./参考图/游戏截图/深夏时光/深夏时光-下午-街景.png —— 只取画法与色调
|
||||||
|
- Image 2(外立面参考·中国城郊居民楼真实照片): ./参考图/真实场景/东井村/QQ20260616-174350.png —— 取材质质感与年代感,不要照搬它具体的窗户形态和布局
|
||||||
|
- Image 3(窗户字汇表·平涂结构示意图): ./生成结果/窗户标准件/标准件合集图.png —— 窗户的几何模具,只取每种窗的结构
|
||||||
|
|
||||||
|
图1是我的风格参考(《深夏时光》游戏截图)——只用它的画法与色调,不要它的内容。
|
||||||
|
图2是我的外立面参考(中国城郊居民楼的真实照片)——取它的材质质感、年代感、色调倾向,【不要照搬它具体的窗户形态和布局】。
|
||||||
|
图3是我的【窗户字汇表】——里面纵向列了3种窗户样式(卧室普通窗 / 厨卫窄窗 / 阳台正面),每种都是正投影、平涂色块的【结构示意图】。这是窗户的"几何模具"。
|
||||||
|
|
||||||
|
任务:用图1的画法、图2的质感,画【一个单元】的【南立面正投影图】(正对南墙、无透视)。每个位置的窗户要从图3字汇表里【选用对应窗型的几何结构】。
|
||||||
|
|
||||||
|
【⚠️ 图3字汇表怎么用——成败关键】
|
||||||
|
- 字汇表只提供窗户的【几何结构】(几扇、宽高比、把手、开法),【绝不照搬它的灰平涂工程图外观】
|
||||||
|
- 必须用图1的 cel-shaded 画法,把选中的窗户【重新渲染】成有玻璃质感、暖色调、与墙面融为一体的样子——窗户和墙面风格必须统一,【严禁出现灰平涂的工程图窗户贴在暖色立面上的割裂感】
|
||||||
|
|
||||||
|
【南侧房间构成——文字布局】
|
||||||
|
- 一梯两户,左右镜像
|
||||||
|
- 每户南侧从左到右依次为:卧室1 + 卧室2 + 客厅;客厅外侧(南面)接一个外凸阳台
|
||||||
|
- 各位置选窗型(对照图3字汇表):
|
||||||
|
· 卧室1、卧室2 → 用图3的【卧室普通窗】
|
||||||
|
· 客厅外侧的阳台 → 用图3的【阳台正面】
|
||||||
|
|
||||||
|
【阳台与客厅的立体关系——本次重点】
|
||||||
|
- 客厅南墙与两个卧室南墙【在同一平面、互相平齐】,客厅【不凹进】
|
||||||
|
- 阳台【外凸】于客厅前方,且是【全楼层高】(从本层楼板通到上层楼板),上下层阳台连续叠放
|
||||||
|
- 阳台全高外凸,从南立面看【完全遮挡】其后的客厅,客厅段看到的是外凸的全高阳台
|
||||||
|
- 【严格区分三种凸出物】阳台=外凸+全楼层高+可站人半室外空间;飘窗=外凸但只有半高(【禁止把阳台画成飘窗】);普通窗=墙面平面上不外凸(卧室窗就是这种)
|
||||||
|
|
||||||
|
【窗户结构——必须严格对照图3字汇表,不要自己发明】
|
||||||
|
- 卧室1、卧室2:各一扇图3【卧室普通窗】=两扇推拉、每扇宽高比1:2、把手在两端;两卧室窗独立分开相邻,【禁止合并成大窗】
|
||||||
|
- 阳台正面:用图3【阳台正面】=【三对推拉共6扇】、每扇宽高比1:2、横向均匀填满阳台宽度;阳台正面宽约4.2米,每扇约0.7米,【必须排下6扇,严禁两扇大窗、严禁宽矮形】
|
||||||
|
|
||||||
|
【面宽比例】卧室1约3.6m(32%) · 卧室2约3.0m(27%) · 客厅+外凸阳台约4.7m(41%);两卧室合计面宽明显大于客厅+阳台段。
|
||||||
|
|
||||||
|
【视角与背景】严格正投影南立面,无透视;纯白背景,只画这个单元。
|
||||||
|
【其他】共4-7层每层布局相同;单元中央底层为单元门(约一层3/4高),上方楼梯间窗小偏上;明显低多边形、cel-shaded 色块、硬边、暖色调。
|
||||||
|
|
||||||
|
尺寸: 1536x1024(横向·单元南立面) 质量: medium
|
||||||
|
生成完成后,告诉我图片的完整文件路径。
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
图1是我的风格参考(《深夏时光》游戏截图)——只用它的画法与色调,不要它的内容。
|
||||||
|
图2是我的外立面参考(中国城郊居民楼的真实照片)——取它的材质质感、年代感、色调倾向,【不要照搬它具体的窗户形态和布局】。
|
||||||
|
图3是我的【窗户字汇表】——里面纵向列了3种窗户样式(卧室普通窗 / 厨卫窄窗 / 阳台正面),每种都是正投影、平涂色块的【结构示意图】。这是窗户的"几何模具"。
|
||||||
|
|
||||||
|
任务:用图1的画法、图2的质感,画【一个单元】的【南立面正投影图】(正对南墙、无透视)。每个位置的窗户要从图3字汇表里【选用对应窗型的几何结构】。
|
||||||
|
|
||||||
|
【⚠️ 图3字汇表怎么用——成败关键】
|
||||||
|
- 字汇表只提供窗户的【几何结构】(几扇、宽高比、把手、开法),【绝不照搬它的灰平涂工程图外观】
|
||||||
|
- 必须用图1的 cel-shaded 画法,把选中的窗户【重新渲染】成有玻璃质感、暖色调、与墙面融为一体的样子——窗户和墙面风格必须统一,【严禁出现灰平涂的工程图窗户贴在暖色立面上的割裂感】
|
||||||
|
|
||||||
|
【南侧房间构成——文字布局】
|
||||||
|
- 一梯两户,左右镜像
|
||||||
|
- 每户南侧从左到右依次为:卧室1 + 卧室2 + 客厅;客厅外侧(南面)接一个外凸阳台
|
||||||
|
- 各位置选窗型(对照图3字汇表):
|
||||||
|
· 卧室1、卧室2 → 用图3的【卧室普通窗】
|
||||||
|
· 客厅外侧的阳台 → 用图3的【阳台正面】
|
||||||
|
|
||||||
|
【阳台与客厅的立体关系——本次重点】
|
||||||
|
- 客厅的南墙与两个卧室的南墙【在同一平面、互相平齐】,客厅【不凹进】
|
||||||
|
- 阳台【外凸】于客厅前方(向室外凸出),且阳台是【全楼层高】的:从本层楼板一直通到上层楼板,占据完整一层高度,上下层的阳台连续叠放
|
||||||
|
- 由于阳台全高且外凸,从南立面看阳台【完全遮挡】其后的客厅,所以客厅这一段看到的是外凸的全高阳台
|
||||||
|
- 【严格区分三种凸出物】
|
||||||
|
· 阳台=外凸 + 全楼层高(整层高)+ 可站人的半室外空间,正面是大开面窗
|
||||||
|
· 飘窗=外凸但只有半高——【禁止把阳台画成飘窗】
|
||||||
|
· 普通窗=在墙面平面上的窗,不外凸
|
||||||
|
|
||||||
|
【窗户结构——必须严格对照图3字汇表,不要自己发明】
|
||||||
|
- 卧室1、卧室2:各用一扇图3【卧室普通窗】=两扇推拉、每扇宽高比1:2(竖长方形)、把手在两端。两个卧室的窗独立分开、相邻,【禁止合并成大窗】
|
||||||
|
- 阳台正面:用图3【阳台正面】=【三对推拉共6扇】、每扇宽高比1:2、横向均匀排列填满整个阳台宽度。【严禁画成两扇大窗、严禁宽矮形】——阳台正面宽约4.2米,每扇约0.7米,必须排下6扇
|
||||||
|
|
||||||
|
【面宽比例——还原布局】
|
||||||
|
- 卧室1约3.6m(32%) · 卧室2约3.0m(27%) · 客厅+外凸阳台约4.7m(41%)
|
||||||
|
- 两个卧室的合计面宽明显大于客厅+阳台段
|
||||||
|
|
||||||
|
【视角与背景】
|
||||||
|
- 严格正投影南立面,正对南墙,无透视
|
||||||
|
- 纯白背景,无环境,只画这个单元
|
||||||
|
|
||||||
|
【其他】
|
||||||
|
- 共4-7层,每层布局相同
|
||||||
|
- 单元中央底层为单元门(约一层3/4高),上方楼梯间(窗小、偏上)
|
||||||
|
- 风格:明显低多边形、cel-shaded 色块、硬边、暖色调
|
||||||
|
|
||||||
|
游戏概念艺术,干净剪影,模块化资产
|
||||||
@@ -6,15 +6,21 @@
|
|||||||
- 整体风格像建筑立面结构图(architectural elevation diagram),扁平、干净、无立体渲染感
|
- 整体风格像建筑立面结构图(architectural elevation diagram),扁平、干净、无立体渲染感
|
||||||
- 纯白背景,画面里只有阳台正面这一个部件
|
- 纯白背景,画面里只有阳台正面这一个部件
|
||||||
|
|
||||||
|
【阳台正面尺度——物理依据,必须画对】
|
||||||
|
- 一个外凸阳台正面宽约3-4米(占满一个客厅的开间),层高约2.8-3米
|
||||||
|
- 真实住宅每扇窗宽约0.7米,所以3-4米宽的阳台正面【绝不是一两扇窗】,必须画出多扇窗来填满整个宽度
|
||||||
|
|
||||||
【阳台正面结构·从下到上】
|
【阳台正面结构·从下到上】
|
||||||
- 底部约1/3高:实心矮墙(浅灰色块)
|
- 底部约1/3高:实心矮墙(浅灰色块)
|
||||||
- 中部约1/2高:推拉窗组(浅灰蓝玻璃 + 中灰窗框)
|
- 中部约1/2高:推拉窗组(浅灰蓝玻璃 + 中灰窗框)
|
||||||
- 顶部约1/6高:实墙(浅灰色块)
|
- 顶部约1/6高:实墙(浅灰色块)
|
||||||
|
|
||||||
【推拉窗组——结构关键,必须画对】
|
【推拉窗组——结构关键,必须画对】
|
||||||
- 窗组由【两扇推拉窗】左右并排组成,中间一条竖向窗框分界
|
- 窗组由【三对推拉窗】组成,共【6扇】,左右排列均匀填满整个阳台宽度
|
||||||
- 【每扇推拉窗的宽高比为1:2】(竖长方形:宽是高的一半)
|
- 每对推拉窗=2扇左右推拉,两扇在中间竖框(闭合轨道)处交叠
|
||||||
- 【把手位置——本次重点】:两扇各一个把手,分别位于整组窗的【最左端和最右端】——左扇的把手在最左竖框上、右扇的把手在最右竖框上,左右对称;【严禁把两个把手画在同一侧】
|
- 三对之间由竖向承重梃分隔,整体呈“6扇竖长窗+5道竖框”的均匀网格
|
||||||
|
- 【每扇窗宽高比为1:2】(竖长方形:宽约0.7米、高约1.5米)——【严禁画成宽矮形、严禁只画一两扇大窗凑数】
|
||||||
|
- 【把手位置】:每对推拉窗内部,左扇把手在该对最左竖框、右扇把手在该对最右竖框,三对逐一对称;【严禁把两个把手画在同一侧】
|
||||||
|
|
||||||
【禁止】
|
【禁止】
|
||||||
- 阳台内部不得画任何物品(不要植物、不要家具、不要杂物、不要地面贴砖)
|
- 阳台内部不得画任何物品(不要植物、不要家具、不要杂物、不要地面贴砖)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
【立体结构——必须画清楚】
|
【立体结构——必须画清楚】
|
||||||
- 阳台向室外凸出约1.2米(必须能看出明显的外凸体量,不是贴墙平面的窗)
|
- 阳台向室外凸出约1.2米(必须能看出明显的外凸体量,不是贴墙平面的窗)
|
||||||
- 正面:下部矮墙 + 上部【两扇推拉窗】(每扇宽高比1:2竖长方形;把手在窗组的最左端和最右端,对称)
|
- 阳台正面宽约3-4米(占满客厅开间),故正面是多扇连续窗
|
||||||
|
- 正面:下部矮墙 + 上部【三对推拉窗(共6扇)】左右排列填满宽度(每扇宽高比1:2竖长方形,宽约0.7米;每对把手在该对最左与最右端,左右对称)
|
||||||
- 一侧侧面:因外凸露出的窄侧面(下部矮墙 + 上部窗)
|
- 一侧侧面:因外凸露出的窄侧面(下部矮墙 + 上部窗)
|
||||||
- 顶部:可见阳台顶板
|
- 顶部:可见阳台顶板
|
||||||
- 整个阳台占满一层楼高,是可站人的外凸阳台(不是只凸半高的飘窗)
|
- 整个阳台占满一层楼高,是可站人的外凸阳台(不是只凸半高的飘窗)
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
拼「窗户标准件合集图」(windows spec sheet) = 路径C组装prompt的【图3:窗户字汇表】。
|
||||||
|
纵向排列 3 个正投影标准件,每件下方加中英标签 + 尺度注释。
|
||||||
|
轴测件不进合集(它表达立体关系,最小闭环靠文字描述)。
|
||||||
|
|
||||||
|
需要 Pillow: pip install Pillow
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Windows 控制台 UTF-8(避免 print emoji/中文时 GBK 崩溃)
|
||||||
|
if sys.platform == "win32":
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
RESEARCH = Path(__file__).resolve().parent.parent
|
||||||
|
PARTS_DIR = RESEARCH / "生成结果" / "窗户标准件"
|
||||||
|
OUT = PARTS_DIR / "标准件合集图.png"
|
||||||
|
|
||||||
|
# (文件名, 中文, 英文, 尺度注释)
|
||||||
|
ITEMS = [
|
||||||
|
("标准件-普通窗-卧室.png", "卧室普通窗", "Bedroom window — 2-panel sliding", "约1.4m宽 · 两扇推拉 · 每扇宽高比1:2 · 把手在两端"),
|
||||||
|
("标准件-窄窗-厨卫-新版.png", "厨卫窄窗", "Kitchen/bath narrow window", "约0.7m宽 · 单扇外开 · 宽高比1:2"),
|
||||||
|
("260623-160342_gpt-image-2_gen.png", "阳台正面", "Balcony front — 6-panel sliding", "约4.2m宽 · 三对推拉共6扇 · 每扇宽高比1:2"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def font(size):
|
||||||
|
for f in ["C:/Windows/Fonts/msyh.ttc", "C:/Windows/Fonts/simhei.ttf",
|
||||||
|
"C:/Windows/Fonts/arial.ttf"]:
|
||||||
|
if Path(f).exists():
|
||||||
|
try:
|
||||||
|
return ImageFont.truetype(f, size)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return ImageFont.load_default()
|
||||||
|
|
||||||
|
|
||||||
|
ROW_H = 820
|
||||||
|
LABEL_H = 170
|
||||||
|
PAD = 50
|
||||||
|
CANVAS_W = 1700
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for fn, zh, en, note in ITEMS:
|
||||||
|
p = PARTS_DIR / fn
|
||||||
|
if not p.exists():
|
||||||
|
print(f"⚠️ 缺文件,跳过: {fn}")
|
||||||
|
continue
|
||||||
|
img = Image.open(p).convert("RGB")
|
||||||
|
w, h = img.size
|
||||||
|
scale = ROW_H / h
|
||||||
|
nw, nh = int(w * scale), ROW_H
|
||||||
|
maxw = CANVAS_W - 2 * PAD
|
||||||
|
if nw > maxw:
|
||||||
|
s2 = maxw / nw
|
||||||
|
nw, nh = int(nw * s2), int(nh * s2)
|
||||||
|
rows.append((img.resize((nw, nh), Image.LANCZOS), zh, en, note, nw))
|
||||||
|
|
||||||
|
n = len(rows)
|
||||||
|
unit = ROW_H + LABEL_H
|
||||||
|
canvas_h = unit * n + PAD * 2 + 30 * (n - 1) + 70 # +70 给顶部标题
|
||||||
|
canvas = Image.new("RGB", (CANVAS_W, canvas_h), "white")
|
||||||
|
draw = ImageDraw.Draw(canvas)
|
||||||
|
|
||||||
|
# 顶部标题:强调"尺寸仅供识别窗型,非真实比例"
|
||||||
|
draw.text((PAD, 18),
|
||||||
|
"窗户标准件字汇表 Windows Spec Sheet",
|
||||||
|
fill="black", font=font(34))
|
||||||
|
draw.text((PAD, 58),
|
||||||
|
"正投影·平涂结构图。图中窗的视觉大小仅供识别窗型,不代表真实比例;真实面宽见组装prompt的文字布局。",
|
||||||
|
fill="#666", font=font(24))
|
||||||
|
|
||||||
|
y = 100
|
||||||
|
for img2, zh, en, note, nw in rows:
|
||||||
|
x = (CANVAS_W - nw) // 2
|
||||||
|
canvas.paste(img2, (x, y))
|
||||||
|
ly = y + ROW_H + 6
|
||||||
|
draw.text((PAD, ly), zh, fill="black", font=font(46))
|
||||||
|
draw.text((PAD, ly + 58), en, fill="#555", font=font(28))
|
||||||
|
draw.text((PAD, ly + 96), note, fill="#555", font=font(26))
|
||||||
|
y += unit + 30
|
||||||
|
|
||||||
|
canvas.save(OUT)
|
||||||
|
print(f"✅ 合集图已生成: {OUT}")
|
||||||
|
print(f" 尺寸: {canvas.size}")
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
标准件生图辅助(apiyi 通道,无风格前缀)。
|
||||||
|
从 prompts/标准件/<名>.txt 读 UTF-8 prompt,生成纯结构示意图到 生成结果/窗户标准件/。
|
||||||
|
|
||||||
|
为什么需要它:
|
||||||
|
- 避开 Windows shell 传中文 prompt 给 Python argv 的 GBK/UTF-8 乱码坑;
|
||||||
|
- 标准件是工程结构图(平涂色块、无光照),【不加】STYLE_SEED_EN(那是 cel-shaded 游戏风格,会冲突)。
|
||||||
|
|
||||||
|
Usage(用英文 key,避免中文 argv):
|
||||||
|
python _gen_standard_parts.py # 默认:front + axo(阳台两件)
|
||||||
|
python _gen_standard_parts.py front # 仅阳台正投影
|
||||||
|
python _gen_standard_parts.py axo # 仅阳台轴测
|
||||||
|
python _gen_standard_parts.py bedroom narrow # 卧室窗 + 厨卫窄窗
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
HERE = Path(__file__).resolve().parent # ai-art-research/tools/
|
||||||
|
RESEARCH = HERE.parent # ai-art-research/
|
||||||
|
sys.path.insert(0, str(HERE))
|
||||||
|
from image_gen import get_client, cmd_generate
|
||||||
|
|
||||||
|
# 英文 key → (prompt 文件名, 尺寸)
|
||||||
|
# 横向构图(宽立面/阳台)用 1536x1024;单个竖窗用 1024x1024
|
||||||
|
PARTS = {
|
||||||
|
"front": ("阳台窗-正投影", "1536x1024"),
|
||||||
|
"axo": ("阳台窗-轴测", "1536x1024"),
|
||||||
|
"bedroom": ("普通窗-卧室", "1024x1024"),
|
||||||
|
"narrow": ("窄窗-厨卫", "1024x1024"),
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = sys.argv[1:] or ["front", "axo"]
|
||||||
|
client = get_client()
|
||||||
|
for k in keys:
|
||||||
|
if k not in PARTS:
|
||||||
|
print(f"❌ 未知标准件 key: {k} (可用: {' '.join(PARTS)})")
|
||||||
|
continue
|
||||||
|
name, size = PARTS[k]
|
||||||
|
pf = RESEARCH / "prompts" / "标准件" / f"{name}.txt"
|
||||||
|
if not pf.exists():
|
||||||
|
print(f"❌ prompt 文件不存在: {pf}")
|
||||||
|
continue
|
||||||
|
prompt = pf.read_text(encoding="utf-8")
|
||||||
|
print(f"\n{'='*60}\n=== 标准件 [{k}] {name} 尺寸 {size} ===\n{'='*60}")
|
||||||
|
cmd_generate(client, prompt, use_style=False, size=size,
|
||||||
|
quality="medium", model=None, subdir="窗户标准件")
|
||||||
|
print("\n✅ 全部完成")
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
路径C组装:apiyi 三图融合(风格 + 外立面 + 窗户字汇表)→ 单元南立面。
|
||||||
|
在 Python 内部用绝对路径调 cmd_fuse,避开 Windows shell 传中文路径给 Python argv 的 GBK 乱码坑。
|
||||||
|
|
||||||
|
注意:image_gen.py 的 cmd_fuse 当前硬编码 size=1024x1024(方图)。
|
||||||
|
路径C首图先用方图验证「三图融合能否成功 + 窗户准确度」;
|
||||||
|
若窗户对、只是横向比例挤,再改 cmd_fuse 支持 size 出 1536x1024 横图。
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 注意:不在这里重定向 stdout/stderr —— image_gen.py 开头已做 TextIOWrapper(UTF-8) 重定向,
|
||||||
|
# 重复包装同一个 buffer 会导致底层文件被提前关闭("I/O operation on closed file")。
|
||||||
|
|
||||||
|
HERE = Path(__file__).resolve().parent # tools/
|
||||||
|
RESEARCH = HERE.parent # ai-art-research/
|
||||||
|
sys.path.insert(0, str(HERE))
|
||||||
|
from image_gen import get_client, cmd_fuse
|
||||||
|
|
||||||
|
STYLE = RESEARCH / "参考图" / "游戏截图" / "深夏时光" / "深夏时光-下午-街景.png"
|
||||||
|
CONTENT = [
|
||||||
|
RESEARCH / "参考图" / "真实场景" / "东井村" / "QQ20260616-174350.png",
|
||||||
|
RESEARCH / "生成结果" / "窗户标准件" / "标准件合集图.png",
|
||||||
|
]
|
||||||
|
PROMPT_FILE = RESEARCH / "prompts" / "居民楼-单元南立面-路径C-窗户字汇表-v1.txt"
|
||||||
|
|
||||||
|
for p in [STYLE] + CONTENT + [PROMPT_FILE]:
|
||||||
|
if not p.exists():
|
||||||
|
print(f"❌ 缺失: {p}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
prompt = PROMPT_FILE.read_text(encoding="utf-8")
|
||||||
|
client = get_client()
|
||||||
|
|
||||||
|
# cmd_fuse 上传顺序 = [style, *content],与 prompt 里 图1=风格/图2=外立面/图3=窗户表 的编号一致
|
||||||
|
cmd_fuse(
|
||||||
|
client,
|
||||||
|
style_path=str(STYLE),
|
||||||
|
content_paths=[str(c) for c in CONTENT],
|
||||||
|
prompt=prompt,
|
||||||
|
model=None,
|
||||||
|
subdir="路径C组装",
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"model": "gpt-image-2",
|
||||||
|
"prompt": "【任务】画一个外凸阳台正面的【正交立面结构示意图】——只表达阳台正面的几何结构(几段、几扇窗、把手位置、比例),不表达材质质感与光照。\n\n【严格正交·平涂色块·无渲染——必须严格遵守】\n- 严格正交投影正面(orthographic front elevation):完全正对阳台正面;【绝对无透视、无消失点——墙面四边是纯直线直角,不向内收、不带任何立体转角效果】\n- 平涂纯色填充(flat solid color):窗框用中灰色、玻璃用浅灰蓝色、矮墙用浅灰色,各自为均匀纯色块;【严禁任何光照、阴影、投影、环境光遮蔽、渐变、材质纹理、lowpoly块面】\n- 整体风格像建筑立面结构图(architectural elevation diagram),扁平、干净、无立体渲染感\n- 纯白背景,画面里只有阳台正面这一个部件\n\n【阳台正面尺度——物理依据,必须画对】\n- 一个外凸阳台正面宽约3-4米(占满一个客厅的开间),层高约2.8-3米\n- 真实住宅每扇窗宽约0.7米,所以3-4米宽的阳台正面【绝不是一两扇窗】,必须画出多扇窗来填满整个宽度\n\n【阳台正面结构·从下到上】\n- 底部约1/3高:实心矮墙(浅灰色块)\n- 中部约1/2高:推拉窗组(浅灰蓝玻璃 + 中灰窗框)\n- 顶部约1/6高:实墙(浅灰色块)\n\n【推拉窗组——结构关键,必须画对】\n- 窗组由【三对推拉窗】组成,共【6扇】,左右排列均匀填满整个阳台宽度\n- 每对推拉窗=2扇左右推拉,两扇在中间竖框(闭合轨道)处交叠\n- 三对之间由竖向承重梃分隔,整体呈“6扇竖长窗+5道竖框”的均匀网格\n- 【每扇窗宽高比为1:2】(竖长方形:宽约0.7米、高约1.5米)——【严禁画成宽矮形、严禁只画一两扇大窗凑数】\n- 【把手位置】:每对推拉窗内部,左扇把手在该对最左竖框、右扇把手在该对最右竖框,三对逐一对称;【严禁把两个把手画在同一侧】\n\n【禁止】\n- 阳台内部不得画任何物品(不要植物、不要家具、不要杂物、不要地面贴砖)\n- 本图只画正面正投影,不要画侧面、不要俯视\n",
|
||||||
|
"mode": "text_to_image",
|
||||||
|
"style_prefix_used": false,
|
||||||
|
"size": "1536x1024",
|
||||||
|
"quality": "medium",
|
||||||
|
"timestamp": "2026-06-23T16:03:42.663242"
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"model": "gpt-image-2",
|
||||||
|
"prompt": "【任务】画外凸阳台的【正交轴测结构示意图】——目的是显示阳台外凸的立体几何关系(只表达结构,不表达材质光照)。\n\n【正交轴测·平涂色块·无渲染】\n- 正交轴测视图(axonometric parallel projection,平行投影、无消失点、非透视):能同时看到阳台的正面 + 一侧侧面 + 顶部\n- 平涂纯色填充:窗框中灰、玻璃浅灰蓝、矮墙浅灰,均匀纯色块;【严禁光照、阴影、投影、渐变、材质纹理、lowpoly块面】\n- 像建筑轴测结构图,扁平干净\n- 纯白背景,画面里只有这一个阳台\n\n【立体结构——必须画清楚】\n- 阳台向室外凸出约1.2米(必须能看出明显的外凸体量,不是贴墙平面的窗)\n- 阳台正面宽约3-4米(占满客厅开间),故正面是多扇连续窗\n- 正面:下部矮墙 + 上部【三对推拉窗(共6扇)】左右排列填满宽度(每扇宽高比1:2竖长方形,宽约0.7米;每对把手在该对最左与最右端,左右对称)\n- 一侧侧面:因外凸露出的窄侧面(下部矮墙 + 上部窗)\n- 顶部:可见阳台顶板\n- 整个阳台占满一层楼高,是可站人的外凸阳台(不是只凸半高的飘窗)\n\n【禁止】阳台内部清空,不要任何物品(无植物、家具、杂物)。\n",
|
||||||
|
"mode": "text_to_image",
|
||||||
|
"style_prefix_used": false,
|
||||||
|
"size": "1536x1024",
|
||||||
|
"quality": "medium",
|
||||||
|
"timestamp": "2026-06-23T16:05:34.947320"
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"model": "gpt-image-2",
|
||||||
|
"backend": "apiyi",
|
||||||
|
"prompt": "图1是我的风格参考(《深夏时光》游戏截图)——只用它的画法与色调,不要它的内容。\n图2是我的外立面参考(中国城郊居民楼的真实照片)——取它的材质质感、年代感、色调倾向,【不要照搬它具体的窗户形态和布局】。\n图3是我的【窗户字汇表】——里面纵向列了3种窗户样式(卧室普通窗 / 厨卫窄窗 / 阳台正面),每种都是正投影、平涂色块的【结构示意图】。这是窗户的\"几何模具\"。\n\n任务:用图1的画法、图2的质感,画【一个单元】的【南立面正投影图】(正对南墙、无透视)。每个位置的窗户要从图3字汇表里【选用对应窗型的几何结构】。\n\n【⚠️ 图3字汇表怎么用——成败关键】\n- 字汇表只提供窗户的【几何结构】(几扇、宽高比、把手、开法),【绝不照搬它的灰平涂工程图外观】\n- 必须用图1的 cel-shaded 画法,把选中的窗户【重新渲染】成有玻璃质感、暖色调、与墙面融为一体的样子——窗户和墙面风格必须统一,【严禁出现灰平涂的工程图窗户贴在暖色立面上的割裂感】\n\n【南侧房间构成——文字布局】\n- 一梯两户,左右镜像\n- 每户南侧从左到右依次为:卧室1 + 卧室2 + 客厅;客厅外侧(南面)接一个外凸阳台\n- 各位置选窗型(对照图3字汇表):\n · 卧室1、卧室2 → 用图3的【卧室普通窗】\n · 客厅外侧的阳台 → 用图3的【阳台正面】\n\n【阳台与客厅的立体关系——本次重点】\n- 客厅的南墙与两个卧室的南墙【在同一平面、互相平齐】,客厅【不凹进】\n- 阳台【外凸】于客厅前方(向室外凸出),且阳台是【全楼层高】的:从本层楼板一直通到上层楼板,占据完整一层高度,上下层的阳台连续叠放\n- 由于阳台全高且外凸,从南立面看阳台【完全遮挡】其后的客厅,所以客厅这一段看到的是外凸的全高阳台\n- 【严格区分三种凸出物】\n · 阳台=外凸 + 全楼层高(整层高)+ 可站人的半室外空间,正面是大开面窗\n · 飘窗=外凸但只有半高——【禁止把阳台画成飘窗】\n · 普通窗=在墙面平面上的窗,不外凸\n\n【窗户结构——必须严格对照图3字汇表,不要自己发明】\n- 卧室1、卧室2:各用一扇图3【卧室普通窗】=两扇推拉、每扇宽高比1:2(竖长方形)、把手在两端。两个卧室的窗独立分开、相邻,【禁止合并成大窗】\n- 阳台正面:用图3【阳台正面】=【三对推拉共6扇】、每扇宽高比1:2、横向均匀排列填满整个阳台宽度。【严禁画成两扇大窗、严禁宽矮形】——阳台正面宽约4.2米,每扇约0.7米,必须排下6扇\n\n【面宽比例——还原布局】\n- 卧室1约3.6m(32%) · 卧室2约3.0m(27%) · 客厅+外凸阳台约4.7m(41%)\n- 两个卧室的合计面宽明显大于客厅+阳台段\n\n【视角与背景】\n- 严格正投影南立面,正对南墙,无透视\n- 纯白背景,无环境,只画这个单元\n\n【其他】\n- 共4-7层,每层布局相同\n- 单元中央底层为单元门(约一层3/4高),上方楼梯间(窗小、偏上)\n- 风格:明显低多边形、cel-shaded 色块、硬边、暖色调\n\n游戏概念艺术,干净剪影,模块化资产\n",
|
||||||
|
"mode": "multi_reference_fusion",
|
||||||
|
"style_reference": "C:\\MiceCola\\Indi\\ChildHood\\ai-art-research\\参考图\\游戏截图\\深夏时光\\深夏时光-下午-街景.png",
|
||||||
|
"content_references": [
|
||||||
|
"C:\\MiceCola\\Indi\\ChildHood\\ai-art-research\\参考图\\真实场景\\东井村\\QQ20260616-174350.png",
|
||||||
|
"C:\\MiceCola\\Indi\\ChildHood\\ai-art-research\\生成结果\\窗户标准件\\标准件合集图.png"
|
||||||
|
],
|
||||||
|
"size": "1024x1024",
|
||||||
|
"timestamp": "2026-06-23T16:36:36.251035"
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user