A / 老虎窗被自身遮住
原始首轮外观图 → 最终外观图老虎窗看起来像白色实体装饰,部分下缘被屋面埋住,玻璃不清晰。
初版老虎窗使用整块墙体;窗户前后位置与陡坡屋面发生遮挡。
把整块墙改成两侧窗壁与上部过梁,并向室外移动老虎窗。最终画面可见窗框与玻璃。
初始外观 PNG 保留完好。初始版本脚本未完整归档;旧值来自当时的修改记录与初版工程,最终代码可在第 06 节核对。
这里展开的不只是最终效果。你可以看到尺寸如何被选定,窗框如何计算位置,几万个构件怎样写入 Blender,以及哪些问题是在真实渲染之后才被发现。
开始拆解模型 ↗bpy 生成模型。没有使用摄影测量、自动三维重建或逐像素尺寸标定。二维图中看不见的尺寸与构造,是建模假设。以下规划根据实际脚本、当时的进度说明和 trace 重建为可读的决策摘要。它解释做了什么、采用了什么依据,以及哪些地方属于推定。
| 可观察的关系 | 选定的建模规则 | 代码如何实现 | 证据与局限 |
|---|---|---|---|
| 中央突出、左右对称 | 1 + 3 + 3 + 3 + 1,共 11 开间 | 轴线数组 + 分段坐标变换 | 从图中解释;没有像素标定 |
| 拱窗细长、上下窗对齐 | 底层 1.60 × 3.65 m;上层 1.55 × 3.25 m | window(x,z,w,h,arched) | 数值为选定参数,不是实测 |
| 深色折线屋顶与老虎窗 | 陡坡下段 + 缓坡上段 | 多圈四边形连接;坡面插值排瓦 | 瓦片和窗为几何;未做完整防水构造 |
| 门厅通高、楼梯弯曲 | 楼板留空;30 级弧形踏步 | 半径、角度和高度同步递增 | 空间关系推定,未作结构校核 |
| 装饰丰富、重复较多 | 建立少量可复用的几何函数 | 旋转体、管线、叶饰、曲面 | 雕刻为抽象近似,非数字雕塑复原 |
同一层窗户只有少量参数不同。如果每扇窗都单独摆放,很容易出现高低不齐、窗套厚度变化。把重复规律写成函数后,位置来自统一轴线,尺寸来自同一组参数。
工程使用米作为单位。墙体、地面、屋顶与室内先建立关系,再添加石材分缝、栏杆、家具和庭院。四个重点室内空间放在建筑内部,其他空间保留为框架。
点击阶段查看从楼板、立面到屋顶与庭院的组合。画面来自最终工程的集合开关复现,不是历史时刻截图;“室内剖开”是解释视图,不是实际施工剖面。
“创建一块石材”最终会变成一组顶点坐标和面索引。下面用脚本中的同一种长方体拓扑,演示从 8 个点到 6 个四边形面,再到世界坐标的过程。
c=(x,y,z) 与尺寸 s=(宽,深,高)。(4,5,6,7) 是顶面。O 与旋转 A。前面的函数大多只往 Python 列表里追加几何数据。flush() 遍历每个批次,调用 from_pydata(vs, [], fs) 建立网格,再创建对象、绑定材质、放入集合、添加部分倒角和平滑着色。第一轮实现约 53 万面,细化后约 72 万面。
tube() 先估计路径切线,再构造两个与切线垂直的方向。在每个路径点周围放一圈顶点,相邻圆环连成四边形。扶手、卷草、吊灯枝臂和水线都复用这套方法。
lathe() 接收一串“半径、高度”。每个截面绕竖直轴转一圈,相邻截面连接,便成为旋转体。改变截面曲线,就能得到不同器形。
调节参数,观察底层拱窗的组成。原模型底层参数是 w=1.60 m、h=3.65 m、窗底 z=0.90 m。图中示意对应脚本的计算规则,石材线脚进行了简化绘制。
| 零件 | 本次选定尺寸 |
|---|---|
| 左右边框 / 中央框 | 55 mm |
| 内部细竖棂 | 22 mm |
| 水平横框 | 45 mm |
| 半圆内部放射棂 | 7 根 |
| 玻璃位置 | 局部 Y=0.21 m |
立面图表达外形与分格,未指定窗型厂商。这些厚度都是视觉参数,不是经过计算的型材规格。
底层直段被横框分成五个高度区间。拱顶部分另外生成半圆框和放射棂;上层矩形高窗不使用圆弧。
外墙为局部 Y=0,正 Y 指向室内。窗框中心约 0.12–0.13 m,玻璃约 0.21 m,墙体内侧约 0.64 m。玻璃是表面网格,没有多层中空玻璃构造。
先确定窗轴线,再围绕窗洞填充墙体。下面的轴线来自脚本中的实际分组坐标,不是均匀撒点;点击任意窗位可查看该窗的中心和所属分段。
脚本将每个窗洞的左右边界加入 cuts。相邻窗洞之间建立窗间墙;窗底以下补窗下墙,窗顶以上补过梁区。拱顶上方根据圆的关系计算墙体下边界:
因此没有一整面实墙挡在玻璃后面。前后与侧面通过变换重复生成,中央和端部使用不同的 Y 值制造凸出。
| 立面分段 | 前立面外表面 Y |
|---|---|
| 中央三开间 | −8.55 m |
| 左右中段 | −8.00 m |
| 端部楼亭 | −8.85 m |
| 左右侧立面 | X=±17.70 m,旋转 ±90° |
示意中的开间划分准确对应轴线。屋顶老虎窗的轴线来自另一组手动参数,并未全部与下层严格协调。
复杂外观由几种基础算法叠加而成:截面连接、沿坡面排布、曲线管线与叶片曲面。
柱础和柱身采用旋转体;竖向附加几何表现柱身细部;柱头用叶片和卷涡组合。三角山花是实体三角形场,边缘有多层斜向线脚,中央放置盾饰,两侧重复卷草。
这不是古典柱式的严格比例推导,也不是把图中人物雕塑逐一重建。重复叶饰可传达风格,但细节还原有限。
叶片沿高度分段,宽度由正弦函数收放,局部起伏形成锯齿,Y 方向的弯曲让表面翘起。卷涡则是半径逐渐缩小的螺旋路径。
底层门厅居中、餐厅与会客厅分居两翼,主卧放在二层一侧。下图用于解释布局,未表达所有隔墙、门洞及施工尺寸。
上方为花园侧,下方为到达庭院。尺寸方向与模型坐标一致;该图为代码布局的简化示意。
视图通过集合显隐制作,因此会出现悬浮部件。它展示室内对象在建筑中的位置,不代表真实的建造先后或可施工剖面。
每级踏步用内外半径和两端角度得到四个角点,再加入上下高度形成实体。扶手沿同一弧线连续上升。初版把踏步一直延伸到地面,后改为每级厚约 0.23 m 的薄体。
几何连续不等于楼梯设计已通过验证。这里没有检查净高、扶手安全间距、平台衔接或结构承载。
初版使用椭球,软垫呈圆鼓形。细化后采用超椭球:对三角函数的绝对值取小于 1 的幂,让截面接近圆角矩形。床品另用起伏网格表达褶皱;没有运行布料物理模拟。
窗帘沿横向使用余弦起伏,再沿高度下垂,形成褶皱。木地板由分块底板、边框和对角条组成;视觉检查后把条带压薄,避免出现格栅效果。
chair()、sofa()、table()、fireplace()、vase()。在末尾完整代码中可直接搜索它们,不需要依赖外部模型资源。40 个自定义材质使用 Blender 节点生成。基础色、粗糙度、金属度和透射控制表面;噪声参与颜色与凹凸。没有调用扫描材质库。
Base RGB .69 / .61 / .47
Roughness .70 · Noise .18
Transmission 1.00
Roughness .025 · Metallic 0
Metallic .78
Roughness .27
Roughness .86
Noise scale 150
花坛是平面和低矮长方体,卷草绿篱沿螺旋线生成。喷泉池壁是旋转截面,水面是圆盘,喷射水线沿抛物线形成细管。树木由枝干、冠层和大量叶片组成,仍带有明显的程序化外观。
使用太阳光、天空环境、室内面光和吊灯补光。先低采样检查,再以 64 采样输出 8 张最终图,并使用降噪。保存工程的默认采样是 32;最终输出脚本覆盖为 64。
拖动对照滑杆查看检查前后。不同轮次还同时改变了灯光、玻璃和采样,不能把整张图的变化都归因于某一个修正。每个案例标明图像来源。
老虎窗看起来像白色实体装饰,部分下缘被屋面埋住,玻璃不清晰。
初版老虎窗使用整块墙体;窗户前后位置与陡坡屋面发生遮挡。
把整块墙改成两侧窗壁与上部过梁,并向室外移动老虎窗。最终画面可见窗框与玻璃。
初始外观 PNG 保留完好。初始版本脚本未完整归档;旧值来自当时的修改记录与初版工程,最终代码可在第 06 节核对。
楼梯下方成为厚重实体,上层墙面装饰不明显,通高空间显得空白。
每级踏步都从地面向上拉伸;部分护墙板朝向墙内,上层两侧缺少同样的饰面。
踏步下表面从固定地面改为随踏步上升;调整墙面朝向并补上上层护墙板。
旧室内 PNG 已被覆盖。左图来自保留的 initial-untraced/Louvre_Residence.blend 的复现渲染,不是历史截图。
木地板对角条带明显凸起;窗帘埋在墙内;玻璃偏浑浊,软垫过于圆鼓。
条带厚度与偏移过大;窗帘的位置超过墙体内侧;玻璃粗糙度较高,软垫采用普通椭球。
压薄条带、移动窗帘、提高玻璃透射并降低粗糙度;部分靠垫改为超椭球。
最后一次检查发现画面左侧被窗帘与挂杆挡住;模型本身不需要重做。
新增窗帘后,原主卧相机位于其附近。应调整取景,而非删去窗帘。
相机从 (6.10,7.10,7.05) 移到 (7.05,6.30,7.05),保持目标点,保存后重新渲染。
Blender 5.2 不再接受脚本中的旧枚举 NISHITA,构建在保存前中断。
读取错误提示,并在本机查询 ShaderNodeTexSky 可用字段,单独测试新的枚举与属性。
使用本机支持的 MULTIPLE_SCATTERING。重跑带 trace 的构建,随后重新打开文件验证。
这里展示真实日志的时间线与代表性调用。为保持 HTML 可离线打开,没有把约 999 MB 的全部原始 trace 塞进页面;内嵌的是原始事件摘录,完整文件保留在原项目中。
时间显示为北京时间(UTC+8)。原始记录使用 UTC。同一时间可有构建、验证或渲染进程重叠,列表按运行开始时间排列。
| 记录函数调用 | 138,451 |
| 扣除 sp() 后的函数调用 | 79,651,仍包含嵌套调用 |
| Blender 相关源码行事件 | 634,491,不等于不同 API 数量 |
| 最终主体运行 | run_complete,无未完成函数调用 |
| StopIteration 记录 | 106 次,迭代控制信号,不是建模失败 |
记录器使用 sys.settrace:函数进入记录参数,退出记录结果,异常记录类型;命中筛选条件的源码行记录为 blender_statement。它不是 Blender 内部每个 C/C++ 操作的录像,也不记录所有鼠标或操作系统动作。
最后用独立后台进程重新打开保存的工程,再检查场景、依赖与渲染文件。下面数据来自 verification.json 和 delivery_verification.json。
主建模代码采用最终成功主体运行时的快照。快照中主卧仍是旧相机位置;最后的相机修正由 refine_camera.py 单独记录。可选择文件、搜索关键字、复制或下载内嵌源代码。