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