AI 协作日志

学生 Web 实验作品平台

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

# 实验三 AI协作记录(请学生在实际完成实验后填写)

> 教师参考代码包不包含虚构的AI协作过程。学生提交时需填写真实工具、提示词、独立测试与结论。

## AI协作1:矩阵和变换次序
- 我自己的预测:
  Task B 要能区分"绕世界原点旋转"和"绕自身中心旋转"这两种变换。我的预判是:正方形中心在 (0.50, 0.25),想让它绕世界原点转,相当于先把图形搬到这个位置、再让整个图形绕原点转一圈,所以矩阵应该写成 M = Rz(θ) · T(C),结果是绕画布中心公转;想让它绕自己中心转,应该先让图形绕原点把姿态转好、再平移回自己的中心,写成 M = T(C) · Rz(θ),结果是原地自转。这里我对"到底哪边先乘"是凭直觉猜的,并不确定写反了会是什么现象,更没把握怎么用矩阵数值去验证。
- AI工具与原始提示词:
  豆包(AI对话助手)。提示词原文大致是:"正方形绕世界原点转和绕自身中心转,模型矩阵的乘法顺序到底该怎么写?R·T 和 T·R 哪个是公转哪个是自转?"
- AI的建议:
  它先强调这个库是列向量存储、矩阵乘法是右边先执行,然后说明:R·T(C) 是把局部顶点先平移到 (0.5, 0.25)、再整体绕世界原点旋转,所以是公转;T(C)·R 是先绕原点把图形自身转好、再平移过去,所以是自转。它还提醒我别只凭动画判断,可以在页面里直接读出矩阵的平移列数值来核对,这样能确认乘法次序确实按我说的那样生效。
- 本人计算、运行与证据:
  我在 task-b.html 里把正方形中心设成 (0.50, 0.25)、角度 45°,先切到"世界原点"模式,页面显示的 Model 矩阵平移列是 (0.177, 0.530)。我自己手算验证:cos45°=sin45°=0.707,平移列 x = 0.707×0.5 − 0.707×0.25 = 0.3535 − 0.1768 = 0.1767 ≈ 0.177,y = 0.707×0.5 + 0.707×0.25 = 0.3535 + 0.1768 = 0.5303 ≈ 0.530,跟页面完全对得上,说明这个分支确实是 R·T。再把旋转中心切到"对象自身中心",平移列变回 (0.500, 0.250),图形从公转变成立地自转。另外页面底部的 5 项数值测试(平移、均匀缩放、Z轴90°、Y轴90°、w=0方向向量)全部显示通过。
- 采纳或修正结论:
  采纳。确认了列向量"右侧先执行"、R·T 是公转 / T·R 是自转,与我的预测一致,并且我是用手算的矩阵数值和运行现象双重验证的,不是只看动画方向就下结论。

## AI协作2:实际故障排查
  - 错误现象与重现步骤:
  完成 Task C 动画循环后,先跑起来能动了,但发现两个问题:一是点击"暂停动画"停 2 秒再"继续",图形会瞬间跳到后面一大截;二是切到别的标签页几秒再切回来,图形位置会突然瞬移。这两类都是"恢复时动画时间突跳"。
- 我先检查了什么:
  按从外到内排查:先看 Console 没有报错;确认 requestAnimationFrame 只在构造函数启动一次、没有重复循环;再深入看 tick(),发现两处隐患——① 算帧间隔的 dt 一开始是框架占位 0,改成 dt=(ms−lastMs)/1000 后才开始动;② 直接这样改后,暂停时如果还继续累加 elapsed、以及切后台回来 dt 会变得非常大,就会造成上面的突跳。
- AI工具与原始提示词:
  豆包。提示词原文大致是:"requestAnimationFrame 里怎么根据时间戳 ms 正确计算帧间隔 dt?为什么暂停恢复或切后台回来动画会突然跳一大段?暂停的时候时间要怎么处理?"
- AI建议的候选原因与测试:
  AI 列了 4 个常见原因让我逐个排除:① dt 没真正算出来(占位 0);② 每帧重复启动新 rAF 循环;③ 暂停时 elapsed 仍在累加,恢复时跳变;④ 切后台回来两帧间 dt 过大导致瞬移。我按顺序测:① 改成 dt=(ms−lastMs)/1000 后动画能动,属必要条件;② 确认只有一条循环,排除;③ 在累加条件里加 this.running 判断,暂停时不再累加,恢复不再跳;④ 用 Math.min(dt, 0.05) 限制最大帧间隔,切后台回来不再瞬移。
- 实测结果、修复与复测:
  真正原因组合是:dt 计算方式(占位/未限幅)+ 暂停未拦住 elapsed。修复集中在 tick():先算 dt、用 Math.min(dt,0.05) 限幅,再在 this.running && this.globalSpeed>0 时才给每个 obj.elapsed 累加。复测:暂停 2 秒后继续不突跳;切到别的标签页几秒再回来不瞬移;全局速度从 1 拉到 2 明显变快。

## AI协作3:设计方案比较
- 我考虑的两种实现:
  方案A(采用):对象数据用"参数快照"组织——每个对象保存 {id, type, center, mode, 各运动参数, elapsed},每帧遍历 objects 数组按当前时间算 Model 矩阵,只调一次 uniformMatrix4fv 上传;截图用 canvas.toBlob 导出当前帧。
  方案B(放弃):每帧在 CPU 重算每个对象全部顶点坐标、用 bufferData 重新上传几何 Buffer 再画;截图用直接读 canvas(依赖缓冲保留)。
- AI工具与原始提示词:
  豆包。提示词原文大致是:"画布里多个对象各自运动,是每帧在 CPU 改顶点再重新上传 Buffer,还是保存参数每帧算 Model 矩阵传 uniform 更合适?PNG 截图用 toBlob 还是直接读 canvas?"
- 对比、取舍与原因:
  方案B 时间成本高:圆有 48 段、每三角形 3 顶点,每帧全部重算重传,顶点多、带宽浪费;而且它把"局部顶点"和"变换结果"混在一起,改一次参数就得改顶点,正确性难保证、可维护性差,也无法让旧对象保持创建时参数。方案A 顶点只在初始化上传一次,之后换矩阵即可,时间成本集中在每帧算一个 4×4 矩阵、开销极小;每对象保存创建时快照,新菜单只影响之后的对象;截图配合 preserveDrawingBuffer:true + toBlob,能稳定导出含图形和背景色的 PNG。综合时间成本、正确性、可维护性,方案A 明显更优。
- 实际实现及核验:
  采用方案A。Task E 里点击时 selectOptions() 存参数快照进 objects 数组,每帧 tick() 推进 elapsed、draw() 算矩阵上传;清屏只清空 objects 数组并重绘;截图先 this.draw() 再 canvas.toBlob 下载。实际验证:先加 4 个圆再切三角形加 2 个,旧圆仍按自己参数缩放、不被覆盖也不跟新菜单变;把画布改 960×540 后旧对象保留且圆不变椭圆;保存的 PNG 打开后能看到图形和背景色、尺寸与画布一致。