AI 协作日志

学生 Web 实验作品平台

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

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

AI工具:Doubao(豆包)Web助手,浏览器打开各 task-*.html 页面实测

## 协作1:矩阵与变换次序(Task B)
- 我的目标和预先预测:对象初始中心 C=(0.50,0.25),对点 p=C(局部原点),我预测 `Rz(90°)·T(C)` 把 p 先平移到 C 再绕世界原点旋转,结果应落到约 (-0.25, 0.50);而 `T(C)·Rz(90°)` 先把局部原点 (0,0) 旋转(仍为 (0,0)),再平移到 C,结果应停在 (0.50,0.25)。即前者公转、后者自转。
- 关键提示词(原文):"列向量下 Model=T·R 与 R·T 对一个位于 C=(0.5,0.25) 的正方形有什么区别?Rz(90°) 作用于 (0.5,0.25) 的结果是多少?"
- AI建议摘要:列向量右侧先作用;R·T 等价于先平移后旋转,p=C 被绕原点旋转到 R(C);T·R 时局部原点旋转后仍在原点,再平移到 C,故中心不动。给出 Rz(90°)·(0.5,0.25)=(-0.25,0.5)。
- 我的计算或测试方法:在 Node 中用本工程 `common/gl-matrix.js` 与 `js/transforms.js` 的 `modelFor()` 直接验证:对象 elapsed=2s(45°/s×2s=90°),pivot='world' 时 Model 矩阵第 12/13 元素(局部原点变换结果)为 (-0.320, 0.530)(对应 C=(0.53,0.32)),pivot='self' 时仍为 (0.530,0.320)。同时在 task-b.html 页面上切换"世界原点/对象中心"单选观察轨迹。
- 实际结果与证据:headless 输出 `orbit 90deg center = -0.320, 0.530`、`self 90deg center = 0.530, 0.320`,与预测一致;页面上世界原点模式下正方形绕画布中心画圈,自身模式下原地转动。
- 采纳、拒绝或修正的结论:完全采纳。代码中 world 公转写为 `multiply(R, T)`,self 自转写为 `multiply(T, R)`,与 AI 建议一致。

## 协作2:故障诊断与修复(Task C/D 暂停突跳 + 鼠标 Y 翻转)
- 错误现象、触发步骤:①第一次把 dt 写成 `(ms-this.lastMs)/1000` 但在暂停时仍更新 `this.lastMs`,恢复动画的瞬间 dt 正常;但早期版本暂停时不更新 lastMs,恢复第一帧 dt≈暂停时长,对象瞬间跳一大段。②鼠标点击画布正中央时对象出现在正确位置,但点击画布上半部分(期望 Y>0)对象却出现在下方。
- 我先检查了什么:先看 Console 无报错;再检查 task-d.html 点击处理,发现占位代码直接用 u=v=0.5;按指导书坐标公式手算 clientY 与世界 Y 的关系:canvas 顶部 clientY 小,而世界 Y 向上,故必须 `y=1-2v`。
- 关键提示词(原文):"WebGL 正交投影 Y 轴向上,canvas getBoundingClientRect 的 clientY 向下,如何把鼠标点击映射到世界坐标?为什么暂停后 requestAnimationFrame 恢复第一帧对象会突跳?"
- AI列出的候选原因:①Y 未翻转:clientY 越小越靠上,应做 `1-2*(clientY-top)/rect.height`;②暂停突跳:暂停期间仍应更新 lastMs,或直接不在暂停分支累加 elapsed,但必须每帧更新 lastMs 时间戳;③切换后台标签 dt 过大,应 clamp(如 ≤0.1s)。
- 我逐项测试的结果:①按 `x=(2u-1)*aspect, y=1-2v` 修改后,点击画布左上 (200,150)(800×600)得到 x=(2*0.25-1)*1.333=-0.667、y=1-2*0.25=0.5,与指导书验收数据 (-0.667,+0.5) 完全一致;②暂停 2 秒后画面冻结、继续时无突跳;③后台标签切回时 dt 被 clamp 到 0.1s,不跳变。
- 真正原因、修改位置和复测结论:原因是 Y 轴方向未翻转 + 暂停时 lastMs 未推进。修改位于 `js/app.js` 的 `addFromMouse()` 与 `tick()`,复测通过。

## 协作3:方案比较与实现核验(Task E 截图与对象组织)
- 待解决的具体设计问题:PNG 截图应如何避免得到空白/黑色图片;对象数据该如何组织才能让多对象独立运动。
- 关键提示词(原文):"WebGL canvas.toBlob 截图为什么常常是黑色?preserveDrawingBuffer 的作用是什么?对象状态应该每帧重算顶点还是保存 elapsed 参数每帧重算 Model 矩阵?"
- 两种方案及取舍依据:
  1. 截图方案A:依赖浏览器自动保存的绘制缓冲,直接 toBlob。缺点:未开启 preserveDrawingBuffer 时合成后缓冲被清空,toBlob 得到黑图。方案B:构造函数已设置 `preserveDrawingBuffer:true`,且 toBlob 前先主动调用一次 `this.draw()`,再用临时 `<a download>` 触发下载。
  2. 对象组织方案A:每帧把位移累加到对象中心坐标上。缺点:浮点累计漂移、暂停恢复需额外处理、周期往返端点误差累积。方案B:对象只保存初始 center 与 elapsed,每帧由 `modelFor(obj)` 用 `sin(2π·elapsed/period)` 解析算出当前位置。无漂移、暂停时停止累加 elapsed 即可、速度倍率直接乘在 dt 上。
- 我最终采用的实现:方案B。对象记录 {id,type,center,motion,elapsed,speed,...};截图走 `this.draw() → canvas.toBlob(cb,'image/png') → URL.createObjectURL → a.download 触发 → revokeObjectURL`。
- 测试与反思:在 task-e.html 添加 6 个对象(圆、X三角形、30°三角形、公转正方形、自转正方形、Y轴自转四面体),点击保存PNG,打开后尺寸为 800×600、含背景色与全部图形;清空后对象计数归零且可继续添加。认识到截图必须先重绘、对象状态必须与 GPU Buffer 解耦——顶点只上传一次,动画全部由 uniform Model 矩阵完成。

## 其他使用AI的记录
- 三角波函数:提示词"周期 1→2→1 往复缩放的连续周期函数",AI建议 `1-|2f-1|`(f=t-floor(t)),Node 自测 t=0/0.25/0.5/0.75/1 输出 0/0.5/1/0.5/0,与预期一致,采纳。
- 数值探针:`probe()` 的 5 项测试(平移点、缩放、Rz90、Ry90、平移对 w=0 向量)在 Node 中全部 PASS,页面 task-b.html 显示全部 ✓。