# 赛博朋克雨夜街区 —— Blender 4.5 纯程序化场景说明

> 全部几何体、材质、夜空、雨、雾均由 Python（bpy / bmesh / 着色器节点 / 几何节点）在 Blender 内生成；**没有下载任何模型、HDRI 或贴图**。唯一使用的外部资源是系统自带字体 `NotoSansCJK-Bold.ttc`（用于 3D 文字，字体不是模型/贴图）。
> 软件：Blender 4.5.14 LTS 官方 Linux 包（安装于 `/opt/blender-4.5.14-linux-x64`），渲染引擎 Cycles（纯 CPU，8 核 Xeon，无 GPU）。

## 1. 交付物路径

| 交付物 | 路径 |
|---|---|
| .blend 工程 | `/workspace/blender-cyberpunk/cyberpunk_street.blend` |
| 主生成脚本（空场景运行即可重建全部场景、动画、渲染设置） | `/workspace/blender-cyberpunk/scripts/build_scene.py` |
| 静帧 1：街道低角度（1920×1080） | `/workspace/blender-cyberpunk/renders/still1_street_lowangle.png` |
| 静帧 2：站台特写（1920×1080） | `/workspace/blender-cyberpunk/renders/still2_station_closeup.png` |
| 静帧 3：高空全景（1920×1080） | `/workspace/blender-cyberpunk/renders/still3_aerial_panorama.png` |
| 动画 mp4（1280×720，240 帧，24fps，H.264 yuv420p） | `/workspace/blender-cyberpunk/video/cyberpunk_street.mp4` |
| 动画 PNG 序列（可断点续渲） | `/workspace/blender-cyberpunk/video/frames/frame_0001.png … frame_0240.png` |
| 动画预览拼图 / 预览帧 | `/workspace/blender-cyberpunk/video/contact_sheet.png`、`video/preview_frame0060.png`、`video/preview_frame0230.png` |
| 辅助脚本 | `scripts/render_still.py`（静帧）、`scripts/render_anim_setup.py`（动画设置）、`scripts/render_final.sh`（批量渲染+编码）、`scripts/render_resume.sh`（相机修正后续渲 160–240 帧并重渲站台静帧）、`scripts/render_rerender_s1s3.sh`（用最终工程重渲静帧 1、3）、`scripts/scene_stats.py`（统计）、`scripts/preview_frames.py` |
| 场景统计 JSON | `/workspace/blender-cyberpunk/renders/scene_stats.json` |

重建命令：
```bash
blender -b -P scripts/build_scene.py            # 生成并保存 cyberpunk_street.blend（约 2~3 秒）
blender -b cyberpunk_street.blend -P scripts/render_still.py -- Cam_Still1_StreetLow 40 1920 1080 128 out.png
blender -b cyberpunk_street.blend -P scripts/render_anim_setup.py -a   # 渲染 240 帧 PNG 序列
```
脚本固定随机种子 `SEED = 20260930`，重复运行结果一致（已验证两次构建的窗户数/亮灯数完全相同）。

## 2. 场景统计（由 `scripts/scene_stats.py` 在第 1 帧从 evaluated depsgraph 统计）

| 项目 | 数值 |
|---|---|
| 物体总数 | 217（网格 155、曲线 6〔电线/飞行路径〕、灯光 51、相机 4、空物体 1） |
| 面数（各物体求值后网格，不含雨滴实例） | 87,254 面 / 172,948 三角面 |
| 雨滴实例（几何节点） | 约 70,300 个实例（75,000 个点，站台顶棚下方的被删除），共 215,520 面 |
| 渲染总面数（含实例） | 约 302,800 面 |
| 材质数 | 61 个（其中 25 个带自发光） |
| 灯光对象 | 51 个：聚光灯 29（24 个路灯灯头 + 5 个飞行车前灯）、点光 15（招牌补光 + 飞行车尾灯）、面光 7（顶棚/站台底/横幅/广告屏补光） |
| 另计自发光 | 霓虹灯管与文字、1,331 扇窗户（591 扇亮）、广告屏、导轨灯带、列车推进器等（均为发光材质，不计入灯光对象数） |
| 世界 | `World_ProceduralNightSky`（节点自制夜空，无 HDRI） |
| 集合分层 | Buildings 16 / Signs 39 / Station 4 / Train 5 / Street 5 / Props 71 / Rain 1 / People 9 / Vehicles 10 / Lights 51 / Cameras 4 / Atmosphere 1 / Background 1 |

命名规范示例：`Bldg_L03`、`Sign05_Blade_HOTEL_Flicker`、`Station_Canopy`、`Train_Car1_Lead`、`Prop_StreetLamp_07`、`Person06_Crossing_Umbrella`、`FlyingCar02_Black`、`Rain_GeoNodes_Streaks`、`Cam_Still2_StationClose`，材质统一 `M_` 前缀。

## 3. 逐项需求完成情况

### 一、总体
- 街道沿 +Y 方向：核心街区两侧楼房覆盖 y = −36 … +36（约 72 m，含 60 m 核心段），车道 12 m 宽（x ∈ [−6, 6]），两侧人行道；两端为十字路口，远处有低细节延伸街区与天际线（`BG_Skyline`，着色器窗户）。
- 街道中部（y = −14 … +14）是跨街的高架悬浮列车站台。

### 二-1 建筑
- **16 栋**主体楼（左右各 8 栋），高度 10.9–66 m、宽度 4.7–10.2 m、层高 3.0–3.9 m、2–19 层，5 种立面风格（混凝土、涂料、金属板、瓷砖、深色玻璃幕墙），部分为两段退台式塔楼，屋顶有女儿墙、空调机组、水箱、带红色航空灯的天线。
- **窗户阵列全部程序生成**：按楼宽/层高/窗距计算列数与层数，每扇窗是独立四边形，并写入面属性 `lit / tint / bright`；每栋楼随机亮灯比例 0.17–0.78，每层再随机浮动，总计 **1,331 扇窗，591 扇亮**；亮灯颜色（暖黄、白、冷蓝、少量品红/青）与亮度随机，材质 `M_Window` 读取属性渲染。底层为发光店面或卷帘门。
- **外挂细节 6 栋**（要求 ≥3）：`Bldg_L02` 消防梯+管道、`Bldg_L04` 管道+空调、`Bldg_R01` 消防梯+空调、`Bldg_R04` 消防梯、`Bldg_R05` 空调、`Bldg_R06` 管道+空调。消防梯含每层平台、栏杆立柱、之字形楼梯及底部爬梯；空调外机含风扇与托架；管道含卡箍和水平支管。

### 二-2 霓虹招牌
- 发光招牌共 **17 块**（要求 ≥8）：9 块双面立体刀片招牌（霓虹、拉面、酒吧、电玩、HOTEL、NEON、24H、寿司、CYBER）、跨街横幅「新九龙 NEON CITY」、站台两端站名「中央站 / CENTRAL」（2 处）、药房绿十字、双色霓虹圆环、霓虹箭头、2 块动态广告屏。
- **3D 文字**：11 处招牌文字由 Text 对象生成后转换为网格（`bpy.data.meshes.new_from_object`，挤出 3 cm，含中文「霓虹」「拉面」「酒吧」「电玩」「寿司」「新九龙」「中央站」），静帧中清晰可读。
- 颜色：品红、青、琥珀、绿、红、紫、蓝、白共 8 种。

### 二-3 悬浮列车站台
- 两侧站台板（x = ±1.5 … ±6.8，顶面 z = 6.9 m），4 对立柱 + 横梁，带黄色盲道、站台边缘灯带、座椅、信息屏。
- **顶棚**：拱形磨砂玻璃 + 11 道钢拱肋 + 纵梁 + 10 根支柱 + LED 灯带（顶面有霓虹描边，航拍可见）。
- **栏杆**：立柱 + 镀铬扶手 + 玻璃挡板；右侧有通往人行道的 36 级楼梯与平台。
- **列车**：3 节车厢（头车、中车、尾车），截面为超椭圆放样的流线型车体（头/尾车有 4 m 长的子弹头），车身按面分配材质：暖光车窗、驾驶室挡风玻璃、**车门缝**（门框四边+中缝的深色缝线）、青色腰线灯带、车顶品红灯带、前照灯/尾灯；车厢之间有风挡；**车底每节 4–6 个发光推进器**（青蓝色自发光）。导轨两侧有发光磁浮轨。

### 二-4 街道细节
- 人行道（抬高 15 cm，瓷砖纹理）与车道分离，**路沿石**、车道虚线、黄色双实线、边线、**两处斑马线**+停止线、**7 个井盖**、路边雨水箅子。
- **散布道具共 69 个物体**（要求 ≥20），由脚本以固定种子随机生成、带防重叠检测：路灯 18 盏（3 种造型，高度/臂长/色温随机，每盏带聚光灯）、电线杆 8 根 + 51 根下垂电线（曲线，含跨街线和楼间高空线）+ 2 串灯笼、垃圾桶 9 个（圆桶/方桶/大型垃圾箱，尺寸/颜色/朝向随机，一个被推倒）、自动售货机 6 台（6 种发光颜色）、施工路障 4 个 + 锥桶 6 个（随机位置/角度/缩放，一个倒地）、发光护柱 8 个、消防栓 3 个、长椅 3 张、纸箱堆 4 组。外形通过尺寸、颜色（Object Color 驱动材质）、朝向随机化，不是完全相同的复制品。

### 二-5 雨与湿地面
- **积水反射**：`M_WetAsphalt` 用两层噪波生成积水遮罩，积水区粗糙度 0.015、干区 0.32–0.72 并带凹凸，积水区更深色；人行道 `M_SidewalkTiles` 同样有积水遮罩。静帧中可以看到霓虹在积水和斑马线上的倒影。
- **下雨**：几何节点 `GN_RainStreaks`：75,000 个随机点 → 用场景帧号做下落（约 10.8 m/s）+取模循环 → 实例化三棱柱细长雨丝（长 0.35–0.85 m，半径 5 mm，微倾斜）；雨丝材质为半透明自发光，并按相机距离渐隐（太近/太远都会淡出，避免糊镜头和远处噪点）；雨滴不投射阴影；站台顶棚下的雨滴被 Delete Geometry 删除。
- **薄雾/体积光**：覆盖整条街的体积立方体（Principled Volume，均匀密度 0.0055，各向异性 0.35），路灯/招牌补光在雾中形成光晕；另在合成器中用 Mist 通道叠加深度雾色。

### 二-6 角色剪影
- **9 个**简化人形（要求 ≥5）：头、颈、躯干、髋、分段四肢、鞋，部分穿长风衣/兜帽，身高 1.62–1.82 m，站立/行走两种姿态；**4 个打伞**（2 把黑伞、2 把带青色 LED 伞沿的透明伞）；3 人有行走位移动画（沿人行道/斑马线移动 + 轻微上下起伏）；站台上有 3 人候车。

### 二-7 飞行器
- **5 架**飞行车（要求 ≥2）：放样流线车身、玻璃座舱、侧推进器（发光尾喷口）、尾翼、**红色尾灯**（自发光灯条 + 红色点光）、前照灯（自发光 + 聚光灯）、车底品红灯带；各自沿贝塞尔路径用 Follow Path 约束飞行，速度与高度不同（9–40 m）。

### 三、灯光与材质
- 光源类型：① 霓虹/窗户/屏幕等自发光；② 路灯聚光灯（24 个灯头）、招牌点光补光、面光；③ 世界节点自制夜空（渐变 + 城市光污染地平线辉光 + 噪波云层，**无外部 HDRI**）。
- 材质 61 个，包括金属（`M_DarkSteel`、`M_Chrome`、`M_RustyMetal`、`M_PaintedMetal`、金属板立面）、玻璃（`M_Glass`、`M_GlassFrosted`、挡风玻璃）、湿沥青（`M_WetAsphalt`）、混凝土（`M_BldgConcrete`、`M_CurbConcrete`、`M_StationConcrete`）、发光体（8 色霓虹、窗户、屏幕、推进器、车灯）、瓷砖、人行道砖、警示条纹、井盖、车漆、布料等，全部为节点程序化材质。

### 四、10 秒镜头动画（240 帧 / 24 fps）
- 相机（`Cam_Anim_Flythrough`）：由 8 个关键位姿做 Catmull-Rom 插值后**逐帧烘焙**（位置 + 朝向，保证平滑无翻转）。从街道南端路口约 1.25 m 高度出发，越过斑马线低空推进 → 约第 60–150 帧从站台正下方穿过 → 驶出站台后在横幅下方经过 → 第 160–240 帧边前进边抬升到约 34 m，同时向左转 180°，最后回望俯瞰整条街全景（焦距 22→24 mm）。
- **列车**：第 1–110 帧从北端减速驶入站台（初速约 160 km/h），停靠到 140 帧，然后加速驶出向南（240 帧时已驶出约 38 m），「驶入」和「驶出」都有。
- **飞行车**：5 架全程沿路径移动。
- **闪烁招牌**：`Sign05_Blade_HOTEL_Flicker` 的发光强度及其补光能量用常量插值关键帧做不规则闪烁（约 10 次熄灭/变暗）；另有 2 块广告屏的图案在滚动；行人走动。

## 4. 渲染设置
- **静帧**：Cycles CPU，1920×1080，128 采样 + 自适应采样（阈值 0.03）+ OpenImageDenoise（albedo+normal），最大反弹 6（漫反射 2 / 光泽 3 / 透射 4 / 体积 0），关闭焦散，Light Tree 开启，间接光 clamp 6，AgX（Medium High Contrast）。合成器：Mist 深度雾色 → Bloom 辉光 → 轻微色散。最终单张耗时：街道 479 s、站台 552 s、航拍 394 s（三张最终静帧均由最终版 `cyberpunk_street.blend` 渲染；第一版静帧耗时 497 / 587 / 403 s，已移到 `test/` 备查）。
- **动画**：1280×720，16 采样 + 自适应（0.05）+ OIDN，最大反弹 4（漫反射 1 / 光泽 2），Persistent Data，保留体积雾与合成器效果；逐帧输出 PNG（占位文件 + 不覆盖，可断点续渲），ffmpeg 编码 H.264（CRF 17，yuv420p，24 fps）。实测平均约 28 s/帧（第一段 1–159 帧约 29 s/帧，续渲 160–240 帧约 26 s/帧）。有效渲染时间约 1 小时 53 分（12:05:30–13:22:36 渲 1–159 帧，13:35:44–14:11:24 渲 160–240 帧）；另有 28 帧（160–187）因相机问题作废重渲，浪费约 13 分钟。
- 峰值内存：960×540 测试渲染时 Blender 进程峰值常驻内存约 0.9 GB，16 GB 机器上很宽裕。

## 5. 用时
- 开始：2026-09-30 11:17 HKT；结束：2026-09-30 14:42 HKT；总用时约 3 小时 25 分钟（按 box 系统时钟统计，包含安装 Blender、编写脚本、5 轮低分辨率测试迭代、最终静帧与动画渲染）。
- 大致时间线（HKT）：11:17–11:20 安装 Blender 4.5.14 LTS；11:20–11:40 编写脚本并做 5 轮测试渲染（修正雨太亮、雾太重、航拍构图被高楼遮挡、列车改为迎面驶入/驶出、相机穿过横幅等问题）；11:40–12:05 渲染 3 张最终静帧；12:05 开始动画渲染；渲染期间逐帧检查已完成的帧，发现第 160–208 帧（抬升段）相机离导轨梁/横幅太近，于是在脚本里对这段相机路径做平滑侧移修正（第 160 帧处修正量为 0，保证与已渲染帧衔接），13:22 停止渲染、删除 160–187 帧，13:35 用修正后的工程续渲 160–240 帧；14:11 动画完成并编码 mp4；14:11–14:20 重渲站台静帧；14:26 起用最终工程重渲静帧 1、3（见妥协 1）；最后整理说明。

## 6. 妥协与诚实说明
1. **静帧/动画与工程的一致性**：第一版三张静帧（11:40–12:05）是在"删除顶棚下雨滴"和"雨丝远处渐隐距离调整"之前的工程渲染的，站台静帧里能看到雨穿过玻璃顶棚落到站台上。12:04 修复后动画才开始渲染。之后我用最终工程重渲了三张静帧（第一版保存在 `test/*_v1_*.png`）。动画 1–159 帧是用 12:04 的工程渲的，160–240 帧是用 13:32 的最终工程渲的。我用脚本逐帧比对了两个工程在第 100/159/160/200 帧的所有物体变换、物体数、材质数、网格顶点数和雨节点树，唯一差别是第 200 帧附近的相机位置（也就是这次修正的内容），所以最终 `.blend` 能复现所有交付画面。
2. **雾**：为控制 CPU 渲染时间，用的是均匀密度体积（没有噪波驱动的非均匀体积雾），再叠加合成器的 Mist 深度雾；体积光束比较柔和，不是强烈的"丁达尔光柱"。
3. **雨**：雨丝是半透明自发光细棱柱，没有运动模糊，地面没有溅水粒子和积水涟漪；从高空俯视时，楼顶上方的雨会呈颗粒感。
4. **人物**：简化人形，行走者只做了整体位移 + 轻微起伏，没有腿部骨骼动画（远看可接受，近看会有"滑行"感）。
5. **窗户**：是贴在立面前的发光平面（无室内几何），靠亮度/颜色/噪波变化区分；背景天际线的窗户由着色器程序生成，不是几何体。
6. **列车可见度**：列车在高架上、相机大部分时间在站台下方低空，所以动画中段（穿过站台底部）看不到列车，列车主要出现在开头远景（迎面驶来）、站台静帧和最后的俯瞰（驶出站台、车顶灯带可见）。
7. **街道长度**：有建筑的街区为 72 m（y −36…+36），两端之外是低细节背景街区，不是 60 m 精确裁切。
8. **动画画质**：720p、16 采样 + 降噪，暗部可能有轻微降噪涂抹/闪烁；没有开启运动模糊。
9. **道具随机化**：路灯和电线杆按行排布并加随机偏移/造型/高度/颜色；垃圾桶、售货机、消防栓、长椅、纸箱、路障、锥桶为脚本随机撒点（带防重叠），没有使用几何节点撒点（需求允许"几何节点或脚本"）。
10. 没有地面行驶的汽车（需求未要求）。
11. **动画抬升段构图**：第 ~165–200 帧相机一边抬升一边左转，画面大部分是楼立面、横幅背面和近处雨丝（见 `video/frames/frame_0185.png`），是整段镜头里最弱的一段；最后的俯瞰（约 210–240 帧）雨丝在前景比较密，稍微挡住街道。时间原因没有再重新设计这段机位。
