# 漫游效果图 · 说明

本目录的 37 张静帧，全部由 `打开真实材质漫游.html` **同一套场景、同一套材质与光照**实时渲染，
使用页面内置机位逐一定位后抓帧，**未经后期修饰**。分辨率 2560x1440。

## 出图方式（含一处必须知道的问题）

原始 `打开真实材质漫游.html` 是 **213 MB 的自包含页面**：three.js r160、GLTFLoader、
HDR 环境贴图和 153 MB 的 GLB 全部以 base64 内联在 HTML 里。

实测在浏览器中打开该页会**卡死主线程、无法出图**。定位到根因是页面内的解码函数：

```js
const bytes = s => Uint8Array.from(atob(s), c => c.charCodeAt(0));
```

它对 204 MB 的 base64 串先 `atob` 成 153 MB 字符串，再逐字符映射为 `Uint8Array`，
这一步在 WebKit 中基本等于挂起。因此本次出图**没有改用它**，而是：

1. `_render/build.py` 把原页拆成 `three.js` / `loaders.js` / 应用三段，
   把两段 base64 换成 `fetch` 外部文件，其余代码与显隐逻辑**一字未改**；
2. 产物 `_render/漫游出图.html` 仅 **0.88 MB**（原 213 MB），打开即用，机位、按钮、
   分层显隐、天窗开合、遮阳收放等行为与原页一致；
3. `_render/server.py` 提供静态服务与 `/save` 抓帧端点；
4. `_render/qa.py` 做逐张质检，`_render/album.py` 生成索引图与相册页。

**这意味着原页的加载问题有解**：把内联资源外链化即可，无需重新建模或重新渲染。

## 质检方法

因为出图量大，除了人工抽查，每张都做了两项客观检查：

- **像素统计**：亮度均值、对比度（标准差）、等于渲染器背景色的像素占比（即天空/空白）。
  空白或黑屏会表现为「背景占比接近 100%」或「标准差接近 0」——本次 33 张**均未触发**。
- **射线探针**：从相机沿视锥五个方向发射射线，量到最近几何体的距离。
  用于排除「相机埋在墙里／贴着构件」。本次全部机位的最近命中在 0.85 m 以上。
- **软装差异检查**：关闭「家具与软装／吊顶」再渲一次，逐像素比对，
  用来判断画面里究竟有没有室内内容。一层各房间差异达 30% 以上（内容饱满）；
  露台与阁楼偏低（2%~5%）属**正常**，与该轮设计「移除厚地台、寝具改收叠存放」一致。

据此修正了两张：
- `T22` 原机位朝向天空（背景占比 56%、软装差异 0.00），重新俯仰后降至 30%、对比度提升至 51.5；
- `T28`/`T29` 远景下遮阳收放差异仅 0.8%（等于重复图），改为二层南阳台近景后差异 8.2%。

另补拍 4 张水平剖切鸟瞰（`T30`~`T33`，剖切高度 1.5 / 5.1 / 8.1 / 13.5 m），用于核对各层平面。

## 怎么打开（预览入口）

| 入口 | 位置 | 说明 |
|---|---|---|
| **预览入口页** | 项目根目录 `查看漫游效果图.html` | 双击即可浏览全部 37 张，按室外/各层/阁楼/屋顶/农田/剖切分组；点图看原图 |
| **33 张索引图** | `00_索引图.png` | 一页看全，适合打印或发人 |
| **相册页** | `漫游效果图集.html` | 逐张说明 + 亮度/对比度/天空占比统计 |
| **实时漫游** | 双击根目录 `启动漫游预览.command` | 自动起本地服务并打开 |

**为什么实时漫游要单独启动服务**：浏览器同源策略会阻止 `file://` 页面读取 153MB 的 GLB 模型，
所以漫游页必须经 http 打开。入口页会自动检测：若你是双击（`file://`）打开的，
页面会给出提示并暂时禁用漫游链接。停止服务：`pkill -f '_render/server.py'`。

## 索引

- `查看漫游效果图.html` —— 预览入口（根目录）
- `00_索引图.png` —— 37 张缩略图编号总览
- `漫游效果图集.html` —— 相册页，含逐张说明与统计
- `缩略图/` —— 880px JPEG，供入口页与相册页快速加载（合计 1.5MB）
- `T34`~`T37` 本轮修订专项（阁楼楼梯口防护墙、洞口俯视、檐口通圈特写、天窗与洞口对位）
- `T01`~`T09` 室外与场地；`T10`~`T14` 一层；`T15`~`T16` 二层；`T17`~`T18` 三层；
  `T19`~`T20` 阁楼；`T21`~`T24` 屋顶与光伏；`T25`~`T27` 花园与农田；
  `T28`~`T29` 遮阳对比；`T30`~`T33` 剖切鸟瞰

## 逐张统计

| 编号 | 文件 | 大小 | 亮度均值 | 对比度 | 天空/背景占比 |
|---|---|---|---|---|---|
| T01 | T01_室外全景_东北鸟瞰.png | 3.9 MB | 160 | 48.9 | 9% |
| T02 | T02_南向正立面_大门侧.png | 3.0 MB | 161 | 53.3 | 17% |
| T03 | T03_东南鸟瞰.png | 3.1 MB | 159 | 50.7 | 7% |
| T04 | T04_东向立面_农田侧.png | 3.0 MB | 168 | 51.6 | 18% |
| T05 | T05_北向立面_后花园侧.png | 3.5 MB | 174 | 47.3 | 18% |
| T06 | T06_西向立面.png | 3.8 MB | 168 | 46.8 | 17% |
| T07 | T07_南向低视点_入户.png | 2.8 MB | 167 | 55.7 | 23% |
| T08 | T08_布局俯视.png | 4.9 MB | 158 | 50.0 | 0% |
| T09 | T09_整栋分层展开.png | 2.7 MB | 163 | 42.3 | 4% |
| T10 | T10_一层_入户.png | 1.1 MB | 214 | 48.6 | 0% |
| T11 | T11_一层_客厅.png | 1.5 MB | 208 | 52.4 | 0% |
| T12 | T12_一层_餐厨.png | 1.4 MB | 196 | 57.4 | 0% |
| T13 | T13_一层_灶间.png | 0.6 MB | 209 | 24.5 | 0% |
| T14 | T14_一层_后左卧室.png | 1.4 MB | 225 | 20.5 | 0% |
| T15 | T15_二层_楼梯厅.png | 1.0 MB | 226 | 35.1 | 0% |
| T16 | T16_二层_前露台.png | 0.5 MB | 223 | 28.8 | 0% |
| T17 | T17_三层_楼梯厅.png | 0.5 MB | 234 | 22.3 | 0% |
| T18 | T18_三层_右露台.png | 0.8 MB | 231 | 30.0 | 0% |
| T19 | T19_阁楼_薄榻榻米.png | 0.8 MB | 229 | 22.9 | 0% |
| T20 | T20_阁楼_储物与地铺.png | 0.6 MB | 228 | 22.0 | 0% |
| T21 | T21_屋顶_天窗出口与检修通道.png | 2.1 MB | 176 | 48.3 | 25% |
| T22 | T22_屋顶_边沿格栅护栏集水槽.png | 2.2 MB | 172 | 53.6 | 29% |
| T23 | T23_屋面光伏布置.png | 2.4 MB | 161 | 41.7 | 1% |
| T24 | T24_光伏喷淋示意.png | 2.3 MB | 166 | 45.7 | 10% |
| T25 | T25_北侧花园.png | 3.6 MB | 150 | 45.9 | 0% |
| T26 | T26_东田_80厘米石板路.png | 2.4 MB | 181 | 52.9 | 41% |
| T27 | T27_农田总览.png | 1.2 MB | 171 | 29.9 | 0% |
| T28 | T28_伸缩遮阳_展开.png | 0.9 MB | 191 | 29.4 | 1% |
| T29 | T29_伸缩遮阳_收起.png | 0.9 MB | 193 | 28.3 | 1% |
| T30 | T30_剖切鸟瞰_一层.png | 4.3 MB | 147 | 44.4 | 0% |
| T31 | T31_剖切鸟瞰_二层.png | 4.7 MB | 148 | 50.1 | 0% |
| T32 | T32_剖切鸟瞰_三层.png | 4.6 MB | 150 | 49.6 | 0% |
| T33 | T33_剖切鸟瞰_阁楼与屋面.png | 4.8 MB | 133 | 54.4 | 0% |



## 各层布局图（本轮补齐）

原漫游页的「查看布局」按钮把参数写死了：

```js
$('topview').onclick=()=>{outside();$('roof').checked=false;$('ceilings').checked=false;
  $('cut').value=3.15;$('floor').value='0';
  $('top').textContent='一层家具与通道布局';};
```

剖切高度 `3.15`、楼层 `'0'`、标题三处都固定成一层，所以**它永远只能出一层平面**。
根目录的 `布局01_1层 / 02_2层 / 03_3层` 三张二维图虽然一直存在，但新旧两个入口页都没有链接，
等于看不到。两头都补了：

| 文件 | 内容 | 来源 |
|---|---|---|
| `布局04_1层_三维.png` | 一层三维剖切（切高 3.15m） | 本轮按层参数化新出 |
| `布局05_2层_三维.png` | 二层三维剖切（6.15m） | 本轮新出 |
| `布局06_3层_三维.png` | 三层三维剖切（9.15m） | 本轮新出 |
| `布局07_阁楼_三维.png` | 阁楼三维剖切（11.5m） | 本轮新出 |
| `布局01~03` | 各层二维家具与通行 | 原有成果 |
| `阁楼薄榻榻米与围墙布局.png` | 榻榻米分格与围墙 | 原有成果 |

预览入口 `查看漫游效果图.html` 顶部新增「各层布局图」区块，8 张一屏直达。
四张三维布局两两差异 63%~78%，已确认层过滤真实生效、不是同一张图换个标题。



### 第 5 项：天窗洞口随天窗一起移位（师兄指出）

我先前的判断**是错的**。当时用重心法粗测屋面，得出"屋面没有洞、天窗只是贴面表达"。
师兄指出"天窗位置对了、但窗孔还在老位置"后，改用**逐点栅格化覆盖检测**重测，证实
屋面基层与瓦面**两层都真实开了洞**：

| | 进深 plan_y | 说明 |
|---|---|---|
| 原洞口 | 6.03 ~ 7.33 | 天窗南移后**留在了原位** |
| 天窗现位置 | 5.05 ~ 6.61 | 与洞口只重叠 0.49m |
| 错位 | **0.71 ~ 1.07 m** | 天窗约 0.7m 悬在实心瓦面上，老洞约 0.7m 敞通阁楼 |

**修法**：对屋面网格做矩形精确裁剪——
把与新洞口相交的三角形按矩形裁开、保留矩形外部分（322 个三角形）；
再自西侧同标高区域取同款瓦（x 平移不改变屋面标高，故能严丝合缝），
裁到取料矩形 → 平移至老洞位置 → **扣除新洞范围**（两洞有重叠，否则补瓦会盖住新洞），
共补回 488 个三角形、5 个材质段（对应瓦面的 4 种色差 + 基层）。

**验证**：13 个关键点位全部符合预期——新洞范围内为空、老洞范围内有面、两洞重叠区为空。

> 过程中修掉一个自己埋的 bug：裁剪时把进深轴写成了 `axis=1`，而三维坐标里
> `axis=1` 是**高度**、进深是 `axis=2`，导致进深判断一直在拿标高比 z 值，
> 第一版裁出的洞形完全是错的。已加注释并在代码里标明。


### 第 6、7 项：天窗检修踏步随天窗移位 / 去掉天窗出口扶手

师兄指出「天窗北面的光伏板上出现两根小柱子」。查证结果是：

| 节点 | 位置 | 高度 | 进深 |
|---|---|---|---|
| 2485 天窗出口扶手建议 | x[9.75,9.79] | 11.98→12.63 | 6.49~6.53 |
| 2486 天窗出口扶手建议.001 | x[11.11,11.15] | 11.98→12.63 | 6.49~6.53 |

这两根 0.65m 高的立柱本是**贴在天窗北缘两侧的出口扶手**。第 1 项把天窗南移 0.85m 时，
只移动了 `category='hatch'` 的节点，**漏掉了 `category='access'` 的这组**，于是它们留在原处；
而新移到天窗北面的光伏板正好占进深 7.00~7.98，立柱就从板面上戳了出来。

处理：
- **第 7 项**：按师兄意见**直接删除**这两根扶手（不再随天窗移动）。
- **第 6 项**：同组的「东侧天窗检修踏步」×3 也从进深 7.38~8.01 同步下移到 6.53~7.16，
  末级与光伏板边齐平、不再相压。
- 屋脊检修防滑格栅位于屋脊处，**不随天窗移动**（正确保留）。

> 教训记在这：改一个构件的空间位置时，必须按**功能分组**找全关联件
> （天窗 = hatch 的翻边窗扇 + access 的扶手踏步 + roof 的洞口），
> 只按 category 过滤一定会漏。第 5 项漏洞口、第 6 项漏扶手，都是同一个原因。

### 「分层查看」下拉框（本轮一并修好）

原页的「分层查看」事件处理只做过滤，不动相机：

```js
['variant','floor','walls',...].forEach(id=>$(id).oninput=()=>{ ...; display(); });
```

`display()` 只按 `floor` 值控制显隐，**既不移相机也不设剖切面**。
所以选「二层」只是把一、三层构件藏掉，视点还停在原地——站在一层或室外，
自然看不到二层那张平面。这项和上面的「查看布局」是同一个病根：**这个页面从来没做过按层布局的逻辑**。

现改为：选中某一层即切到该层布局视图（移相机到俯视、剖切面设到该层楼板下、关屋顶与室外方案、标题同步）；
选「整栋房屋」恢复室外全景与全部图层。并把选项「阁楼 / 屋顶」正名为「阁楼」。

验证方式：全部用**下拉框**逐层出图，与交付的 `布局04~07` 逐像素比对——
一层/二层/三层/阁楼四张**平均差均为 0.000**，即下拉框现在出的就是那四张图。

## 本轮七项模型修订（修订 09）

模型已按师兄意见改过，输出为 `全屋真实材质漫游_修订09.glb`，
原 `全屋真实材质漫游.glb` 未改动。逐项数值见根目录 `本轮三项修订参数.json`。

| # | 修订 | 落地情况 |
|---|---|---|
| 1 | **检修天窗移到靠近南檐** | 天窗组沿进深南移 0.85m（防水翻边由进深 5.90~7.46 → **5.05~6.61**），距南檐 4.80 留 0.25m；并随屋面坡度下降 0.437m |
| 1 | **天窗南面的光伏板移到北面** | 原「光伏_南坡_1_6」（x=10.775）移到天窗北面的「南坡_3_6」位（进深 7.49）；南坡仍 16 块、总数仍 34 块 |
| 2 | **阁楼楼梯口补墙** | 新增「阁楼楼梯口防护墙」x[5.00,6.50]、进深中心 7.80、自阁楼面 9.60 砌至屋面下 12.40。**原先此处是 1.5m 宽、约 3m 落差的敞口**（楼梯只占西侧 1.2m 宽，东侧 1.5m 无遮挡） |
| 3 | **屋顶边沿改传统檐口** | 移除金属护栏 56 个节点，原位做**通圈低瓦檐带**：宽 0.30m、高出屋面外沿 0.25m、向下包边 0.20m；东西两侧沿坡 96 段细分随坡下降，南北两檐水平，**四角同标高 11.25m 连续不折断**；脊处顶 13.03m，整体低于原有山墙压顶。材质「徽式青灰小瓦」 |
| 4 | **去掉落水管** | 移除落水管及管卡共 22 个节点（新屋面雨水立管建议×4、雨水立管建议_下游接驳待确认×4、雨水管卡示意×14）；天沟与集水槽保留 |

### 修订中必须知道的三件事

1. **屋面网格从来没有开过洞。** 局部统计：屋面板 48 个三角形中 12 个、瓦面 4918 个中 93 个正落在天窗口范围内，
   即天窗一直是**贴在瓦面上的表达**，屋面本身是实心的。移天窗不影响这一点，但"检修天窗作为屋顶出入口"
   在模型层面仍未成立——真要开洞需做网格布尔运算或回 Blender 重做（本机未装 Blender）。
2. **落水管取消后，集水槽与天沟在模型中没有排出路径**，雨水组织方式需重新确定。
3. **0.25m 高的檐带不构成防坠措施。** 原先 1.1m 的金属护栏与 1.1m 女儿墙方案都已按你的意见取消，
   现在屋面外围检修走道只有 0.25m 高的檐带挡边。若仍需上屋面作业，防坠要靠屋脊那道刚性导轨，
   或另定做法——这一条请务必与安全设计一起确认。

## 使用边界（不可省略）

- 屋面护栏、天窗至屋脊的防坠导轨、滑车、集水槽、灌溉与光伏喷淋，**都是空间方案示意**。
  它们出现在画面里，**不等于**已获得防坠安全保证、结构承载力或水力性能结论。
  必须结合结构锚固、产品选型、坠落净空与救援方案由专业人员设计验收。
- 34 块光伏为**占位排布**，组件型号、功率、支架、串并联、逆变器与线缆均未确认；
  护栏、导轨与遮阳会改变遮挡与荷载条件，最终发电量需与结构、构造一起复核。
- 农田总面积含 80 cm 田间路，**不能把总面积全部作为净种植面积**；
  北侧花园边界为方案，不是测绘确认的地界。
- 室内强电、弱电、给水、热水、排水、空调与新风的完整施工走线仍缺失，
  画面中不存在可据以施工的管线布置。
- 实时光照精度与 Cycles 离线渲染不同；文件中既有的 `05`~`16` 号效果图是离线渲染，
  两者不应互相替代。

_本目录由 `_render/` 下脚本生成，可重复执行。原始成果包未作任何修改。_
