AI 协作日志

学生 Web 实验作品平台

学号:202412211401023 · 来源:ai-log.md

# 实验五 AI 协作与核验记录

学号:202412211401023  姓名:    日期:2026-11-09

> 说明:本记录里的“AI 建议”均指我在实现过程中向 AI 提出的问题与得到的回复摘要;参数、数值与结论都来自我自己跑出的结果(Node 数值核验脚本 `verify.js` 与浏览器截图),不是直接抄 AI 的说法。

## 协作一:观察与投影概念核验(Task B / C,3 分)

**1. 我的问题和事先预测**

我要分清三件事:移动物体、移动相机、换投影,画面都会变,但变的原因不同。我的预测是:

- 只改 M(平移模型):画面里的模型会移动,状态栏“世界中心”数值跟着变;
- 只改 V(把 eye 从 (0,0,8) 换到 (8,0,0)):画面从正面变成侧面,但“世界中心”数值一个字都不该变;
- 只改 P(正交↔透视):模型的屏幕位置和大小会变,M、V、世界中心都不变;正交下两个等尺寸立方体一样大,透视下近的大。

**2. 我实际输入给 AI 的提示词**

> 在 WebGL2 右手坐标系、列向量和 P·V·M 的顺序下,我想比较移动物体与移动相机、正交与透视投影。请给我三组能区分原因的控制变量实验,指出应改变 M/V/P 中的哪项,说明可以打印哪些坐标数值进行核验,不要直接生成整套代码。

**3. AI 建议摘要**

- 第一组固定 V、P,只改 M 的 tx:打印 `world = M·N·center`(归一化后中心必为 0,所以 world 就等于 T 的平移量)与同一个顶点的 NDC;M 变、V 不变。
- 第二组固定 M、P,只改 eye/target:打印 `world` 与 `V` 的前三行(相机右/上/后基向量);world 必须恒定,V 必须变。
- 第三组固定 M、V,只换 P:打印 `P[0]`、`P[5]`、`P[10]`、`P[11]`、`P[14]`;透视的 `P[0]/P[5]` 应等于 `1/aspect`,正交的 `P[10]` 与 `P[14]` 由 near/far 决定;再用“等尺寸立方体的 NDC 高度”判断近大远小。
- AI 特别提醒:判断表观大小不能拿“单个点的 NDC y”比,因为相机俯视时远处点沿视线方向反而更靠画面上方,必须比两个等尺寸物体的投影高度。

**4. 我的判断和采纳/拒绝理由**

全部采纳,但第三组我补了一项:把 `P·V` 一起乘起来再验证,而不是只拿 `P` 乘世界坐标。因为相机在 (0,1.8,8.5),只乘 P 等于把相机搬到原点,结论会失真(这一点我在测试里真踩到了,见协作二第 4 步)。

**5. 我的测试参数、操作与结果**

(截图见 `04-B-正面视角.png`、`05-B-侧面视角.png`、`06-B-顶部视角.png`、`08-C-透视投影对照.png`、`09-C-正交投影对照.png`)

- M 变化:`tx: 0 → 0.15`(按 D 一次),世界中心 (0.00, 0.00, 0.00) → (0.15, 0.00, 0.00),eye 仍为 (0.00, 1.80, 8.50)。
- V 变化:正面 eye (0,0,8) → 顶部 eye (0,8,0),世界中心两次都是 (0.00, 0.00, 0.00)(模型归一化后中心确为 0,故 `M·N·center` 只受 T 影响)。
- P 变化(固定 M、V、camera=(0,1.8,8.5)):

| 量 | 透视(FOV 50°, near/far 0.1/100) | 正交(正交高度 5.5, near/far 0.1/100) |
|---|---|---|
| 近立方体(z=0)NDC 高 | 0.182 | 0.277 |
| 远立方体(z=−3)NDC 高 | 0.139 | 0.277 |
| 近/远比值 | 1.31 | 1.00 |

- FOV 50°→80°:同一物体 NDC 高度 0.207 → 0.115(比值 0.556 ≈ tan25°/tan40° = 0.556),说明 FOV 变大是“视野变宽、物体占比变小”,不是把模型缩小。
- near 从 0.1 推进到 8:z=0.8 的顶点 NDC z=−1.07(被裁掉),z=0 的顶点仍是 −0.87(还在视锥里)。

**6. AI 是否正确?我最终修正了什么认识**

建议方向正确。修正的认识有两点:

1. 「近大远小」必须用等尺寸物体的投影高度来量化,单个点的屏幕 y 不能当证据;
2. 正交下两个不同深度的立方体 NDC 高度完全相同(0.277/0.277),说明正交投影确实丢掉了深度信息,只有透视会除以 w 做透视除法。

## 协作二:程序故障诊断(Task C / D,4 分)

**1. 真实错误现象和我起初怀疑的原因**

我把 Task C 的第一版写成 `mat4.perspective(out, 50, aspect, .1, 100)`,即把 50 直接当弧度传。现象是:切到透视后模型和网格整片消失,状态栏停在上一次的画面,页面底部出现红色的「参数错误:观察或投影矩阵含无效数值。」。我起初怀疑是宽高比算错了。

**2. 向 AI 提出的诊断问题**

> 我的 OBJ 能显示,但切换透视投影后形状被拉伸/裁剪或者鼠标拖动方向异常。请从宽高比、裁剪面、矩阵顺序和观察基向量中提出至少三种假设,分别给一项最小测试,先帮助排查,不要直接重写完整程序。

**3. AI 建议的至少两个可区分原因及测试**

- 假设 A:FOV 单位错(度当弧度)。最小测试:打印 `P[5]`,透视下应等于 `1/tan(fovy/2)` 且为正;若为负或量级异常就是单位错。
- 假设 B:宽高比用了 `canvas.width/canvas.height`(含 devicePixelRatio)而不是 CSS 宽高。最小测试:打印 `P[0]/P[5]`,应严格等于 `1/aspect`。
- 假设 C:near/far 非法(near≤0 或 far<near)。最小测试:打印 `P[10]/P[11]/P[14]`,看是否出现 0 或 NaN。
- 假设 D:矩阵顺序写成 V·P。最小测试:只打印 `V` 的前三行,检查是否仍为正交单位阵。

**4. 我实际逐项测试了什么?各自结果如何**

| 测试 | 操作 | 结果 |
|---|---|---|
| A | 打印错误版 `P[0]/P[5]` | `P[0] = −4.8694`、`P[5] = −7.4892`,都为负 → 命中 |
| B | 计算 `P[0]/P[5]` | `−4.8694 / −7.4892 = 0.6503 = 1/1.538`,宽高比其实是对的 → 排除 |
| C | near=0、far=near 各试一次 | 分别提示「near 必须大于 0」「far 必须大于 near」,说明校验有效 → 排除 |
| D | 打印 `V` 前三行 | 正交单位、det=+1 → 排除 |

Node 复现输出(`verify.js` 第 0 节):

```
错误矩阵[0]=-4.8694  [5]=-7.4892  [11]=-1.0000
原点按错误 P 投影 → NDC NaN, NaN, -Infinity(w 为负,符号被翻转)
```

**5. 最终根因、修复处及修复后结果**

根因在 `js/task-c.js` 的 C3:`mat4.perspective` 的 fovy 要弧度,我传了角度。修复为 `mat4.perspective(out, fov*RAD, aspect, near, far)`。修复后 `P[0]=1.394`、`P[5]=2.145`(=2.145/1.538=1.394 ✓),原点 NDC 回到正常的 (0.000, 0.000, −1.000),模型恢复显示。

排查中我还犯了一个更隐蔽的错:做“近大远小”的数值验证时,我把 `P` 直接乘世界坐标点,得到 `w = 0`、NDC 全是 NaN。用调试脚本打印齐次坐标才看到 `w` 为 0——因为相机在 z=8.5,世界 z=0 的点正好落在“原点相机”的视平面上。改成 `P·V` 后数值正常。这条也写进了第 3 节的注释,避免以后再用单点 NDC 下结论。

## 协作三:综合工作台方案比较(Task E,3 分)

**1. 我准备完成的观察任务**

做一个“茶壶/兔子 + 固定参考点 + 绕点运行的小标记”的观察台,要求能改旋转中心、能看出公转与自转的区别,并在 40 分钟内接上已有的 A—D 模块。

**2. 向 AI 询问的两种设计方案**

> 我已完成 OBJ 导入、观察视角、正交/透视以及鼠标键盘变换。请提供两个能在 40 分钟内复用已有 WebGL2 模块的观察台拓展设计,对比功能、矩阵链、交互参数和验证难度。不引入 Three.js、光照、纹理或复杂模型编辑器。

**3. 两种方案的功能、矩阵链、测试难度对比**

| 项目 | 方案一:指定点旋转 + 父子标记 | 方案二:正交/透视双画布同步对照 |
|---|---|---|
| 功能 | 固定点 P、轨道半径 R、公转角 θ;子标记挂在主标记上自转 | 左右两个 canvas 同一 M/V,只差 P,拖动同步 |
| 矩阵链 | `M_orbit = T(P)·Ry(θ)·T(−P)·T(q)·S`;子件再左乘 `Ry(2θ)·T(0.45,0,0)` | 两套 `P` 共用同一个 `M·N`,各自 `P·V·M·N` |
| 交互参数 | P(3)、R、θ、父子开关 | 只需一个模式开关,但需两套 Scene |
| 验证难度 | 低:半径|中心−P|应恒为 R,可逐角度数值核验 | 高:要维护两份 GL 上下文、两个 resize 与截图 |
| 与 A—D 复用 | 完全复用(只加 `extra()`) | 需改 render 循环与布局,框架改动大 |

**4. 最终采纳的方案与理由**

AI 只提供了对比,**最终是我决定的**:先做方案一,因为它的数学机制(绕点旋转 + 父子继承)正好补上指导书要求的“至少一种额外复合机制”,而且能用 |中心−P| 恒等于 R 的数值直接验收;方案二更适合作为 Challenge,本次时间不够就没有做。

**5. 自己实现或修改的功能差异**

在教师示范的 `T(P)Ry(θ)T(−P)` 上,我自己加了三处:

1. 面板里增加旋转中心 P(px/py/pz)与轨道半径 R 两个可输入量,P 一改整组标记跟着平移;
2. 主标记的初始中心改为 `q = P + (R,0,0)`,而不是固定死的偏移,保证改 R 后仍然绕 P 转;
3. 增加“父子继承”子部件:`M_child = M_orbit·Ry(2θ)·T(0.45,0,0)·S(0.11)`,它跟随父标记公转的同时相对父再自转,能直观看出“父带子”和“各自转”的区别;面板下方增加实时读数(P、R、θ、主标记中心、|中心−P|)。

**6. 预测与实际结果对照,仍存在的局限**

| θ | 预测:|中心−P| | 实测 | 主标记中心 |
|---|---|---|
| 0° | 0.85 | 0.85 | (2.35, 0.35, 0.00) |
| 35° | 0.85 | 0.85 | (2.20, 0.35, −0.49) |
| 90° | 0.85 | 0.85 | (1.50, 0.35, −0.85) |
| 180° | 0.85 | 0.85 | (0.65, 0.35, 0.00) |
| 270° | 0.85 | 0.85 | (1.50, 0.35, 0.85) |

预测与实际一致(截图 `16-E-绕点公转默认.png`、`17-E-改P与半径.png`)。局限:辅助标记只用立方体,没有真实骨骼;轨道圆没有画出来,半径只能靠读数确认;子部件自转角固定为 2θ,不能单独调。

## 全局诚信声明

- 我提交的代码均已本人运行并核验;无法解释的 AI 输出未直接作为完成结果。
- 我明确标注了使用 AI 辅助的功能和本人自主完成的关键判断:M/V/P 三组控制变量核验、FOV 单位故障的定位与修复、E 的方案取舍与父子继承实现均由本人完成并留有数值证据。