AI 协作日志
学生 Web 实验作品平台
学号:202412211401021 · 来源:ai-log.md
# 实验三 AI协作与核验记录
AI工具:豆包(Doubao)Web版
---
## 协作1:矩阵与变换次序(Task B)
- **我的目标和预先预测:**
我想验证:把一个正方形放在世界坐标 `C=(0.5, 0.25)`,分别用 `R·T` 和 `T·R` 组合绕Z轴旋转90度,两种结果有什么区别。
我自己先算了一下:列向量约定下,右边的矩阵先作用。所以 `R·T` 应该是"先把正方形移到(0.5,0.25),再绕原点旋转",正方形会绕画布中心画圈;而 `T·R` 应该是"先在原点旋转,再平移",正方形应该在原地旋转但位置不变。
- **关键提示词(原文):**
"WebGL中4x4齐次变换矩阵,列向量约定下,M=R*T和M=T*R作用于顶点时顺序有什么区别?如果把一个正方形放在(0.5,0.25),分别用这两种矩阵绕Z轴旋转45度,最终位置和姿态有什么不同?"
- **AI建议摘要:**
AI确认了我的理解是对的:
- `M = R · T(C)`:先执行T(平移到C),再执行R(绕原点旋转),对象会绕世界原点公转,轨迹是一个圆。
- `M = T(C) · R`:先执行R(在局部原点旋转),再执行T(平移到C),对象在自身位置自转,中心不动。
原因是矩阵乘法不满足交换律,且列向量约定下最右边的矩阵最先作用于顶点。
- **我的计算或测试方法:**
我在 task-b.html 页面做了对照实验:
1. 把图形选成正方形,中心设为(0.5, 0.25),模式选旋转,角度45度。
2. pivot选"世界原点",记录正方形位置和姿态。
3. pivot选"对象自身中心",记录结果。
4. 同时对照页面上的数值测试表(probe函数输出的5项矩阵测试)。
- **实际结果与证据:**
- 世界原点旋转(R·T):正方形从(0.5, 0.25)位置移到了大约(-0.05, 0.56),确实绕画布中心转了45度,同时自身也转了45度。
- 自身中心旋转(T·R):正方形中心始终在(0.5, 0.25)不变,只有自身朝向转了45度。
- 数值测试表5项全部显示✓:平移(1.3,-0.2,0,1)、缩放(2,0,0,1)、Z轴旋转(0,1,0,1)、Y轴旋转(0,0,-1,1)、方向向量w=0不变。
- **采纳、拒绝或修正的结论:**
完全采纳AI的解释。我之前对"为什么平移作用于方向向量(w=0)不改变"还有点模糊,AI解释后明白了:平移矩阵在w分量上是1,当w=0时,平移那一行的[tx,ty,tz,0]乘以(1,0,0,0)还是(1,0,0,0),所以方向向量不受平移影响。
---
## 协作2:故障诊断与修复(Task C/D)
- **错误现象、触发步骤:**
我在做Task C动画时,发现两个问题:
1. 暂停动画2秒后再点继续,圆形和三角形会突然"跳"一大段,而不是从暂停的位置继续。
2. 三角形沿X轴往复运动,但运行十几秒后发现它的中心点在慢慢往右漂移,没有精确回到初始位置。
- **我先检查了什么:**
我先看了 tick() 函数里的时间计算逻辑,发现 dt 是用 `(ms - this.lastMs) / 1000` 算的,暂停时 `this.lastMs` 也在更新,所以恢复时dt应该很小才对……但实际还是跳了。然后我又检查了三角形的位移计算,发现我一开始写成了每帧累加 `offset += velocity * dt`。
- **关键提示词(原文):**
"WebGL动画中,requestAnimationFrame的时间戳计算dt,暂停一段时间后恢复会突然跳变,可能是什么原因?另外三角形往复运动运行久了位置会漂移,应该怎么避免?"
- **AI列出的候选原因:**
1. 暂停期间仍然在更新 `lastMs`,但 elapsed 没累加——这个其实没问题,恢复时dt应该小。
2. 真正可能的原因:如果在暂停时没有正确保存上次时间,或者dt没有做上限限制,切后台再回来时dt会非常大。
3. 三角形漂移的原因:用每帧累加位移的方式(`x += v*dt`)会有浮点误差累积,时间长了越来越偏。正确做法是用正弦函数 `x = A * sin(2π * t / T)` 直接算当前位置,永远精确回到原点。
- **我逐项测试的结果:**
1. 我加了 `if (dt > 0.1) dt = 0.1;` 限制最大帧间隔,切后台再回来确实不跳了。
2. 我把三角形位移从累加改成了 `offset = amplitude * sin(2π * elapsed / period)`,运行了30秒观察,中心点始终在初始位置附近往复,没有漂移。
- **真正原因、修改位置和复测结论:**
- 跳变原因:没有限制dt上限,切后台标签页再回来时,rAF的时间戳差了好几秒,导致dt巨大。
- 漂移原因:浮点累加误差累积。
- 修改位置:`app.js` 的 tick() 函数加了dt上限;`transforms.js` 的 modelFor() translate分支用正弦函数直接计算位移。
- 复测:暂停3秒后继续,动画从暂停位置平滑继续;运行30秒后三角形精确回到初始中心。
---
## 协作3:方案比较与实现核验(Task E)
- **待解决的具体设计问题:**
Task E需要实现PNG截图。我有两种思路:一种是用 `canvas.toDataURL('image/png')` 直接生成图片URL;另一种是用 `canvas.toBlob(callback, 'image/png')` 异步获取Blob再下载。我不确定哪种更可靠。
- **关键提示词(原文):**
"WebGL canvas保存PNG图片,用toDataURL和toBlob两种方式有什么区别?哪种在preserveDrawingBuffer:true的情况下更可靠?需要注意什么?"
- **两种方案及取舍依据:**
| 对比项 | toDataURL | toBlob |
|---|---|---|
| 返回方式 | 同步,直接返回base64字符串 | 异步,通过回调返回Blob |
| 内存占用 | base64字符串较大,占内存 | Blob对象更高效 |
| 下载触发 | 需要自己创建a标签href=dataURL | 需要URL.createObjectURL(blob) |
| 可靠性 | 高,但大图时可能卡住UI | 高,异步不阻塞UI |
| 适用场景 | 小图、快速预览 | 正式保存、大图 |
- **我最终采用的实现:**
选择了 `toBlob` 方案。因为:
1. 异步方式不会阻塞浏览器UI。
2. Blob对象内存效率更高。
3. 配合 `preserveDrawingBuffer:true`,截图前先主动调用一次 `this.draw()` 确保缓冲区有当前画面。
实现代码:
```javascript
this.draw(); // 先主动重绘
this.canvas.toBlob((blob) => {
if (!blob) { /* 错误处理 */ return; }
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '实验3_画布.png';
a.click();
URL.revokeObjectURL(url);
}, 'image/png');
```
- **测试与反思:**
测试结果:点击保存截图后,浏览器自动下载了PNG文件,打开后尺寸是800×600(和canvas内部尺寸一致),包含所有WebGL图形和背景色,不是全黑。
反思:如果不设 `preserveDrawingBuffer:true`,WebGL默认绘制完就清空缓冲区,toBlob可能拿到空白图。这个项目里Graphics构造函数已经设了这个参数,但截图前主动draw()一次是更保险的做法,不受浏览器缓冲区策略影响。
---
## 其他使用AI的记录
- **Task A:** 我问AI"WebGL中四个形状的顶点数据已经存在Buffer里了,为什么只显示圆不显示其他三种?"AI提醒我检查 `gl.drawArrays` 的count参数——原来代码里写死了只有circle的顶点数,其他三种传了0。改成都用 `mesh.vertexCount` 就好了。
- **Task D:** 鼠标点击位置换算时,我一开始把Y方向搞反了,点击画布上方结果对象出现在下方。AI提醒我注意CSS坐标Y轴向下,而世界坐标Y轴向上,需要做翻转:`yWorld = 1 - 2 * v`。