AI 协作日志
学生 Web 实验作品平台
学号:202412211402009 · 来源:ai-log.md
# 实验四 AI协作记录
> 学号:202412211402009
> 姓名:______(请填写)
> AI工具与使用版本(如适用):豆包办公(WebGL2 实验助手),配合 gl-matrix.js(教材 common 版)做矩阵数值核验
> 说明:以下记录来自本实验真实完成过程中与 AI 的概念核验、数值测试与调试,保留关键提示词原文,不使用整段 AI 代码代替。
---
## 协作1:变换次序核验(Task B)
### 我的目标与先验预测
- 目标:验证相同平移 T(tx,0,0)、绕Y旋转 Ry(θ)、缩放 S(s) 在两种相乘次序下,局部原点 (0,0,0) 的世界坐标不同,并解释原因。
- 先验预测(tx=2、θ=90°、s=1):
- M1=T·Ry·S:右侧先作用,S、Ry 对局部原点无效,最后 T 平移到 (2,0,0)。
- M2=Ry·T·S:先 T 到 (2,0,0),再绕Y轴旋转90°,按列向量应到 (0,0,-2)。
- 因此预测两种中心分别为 (2,0,0) 与 (0,0,-2),二者不同,说明矩阵乘法不满足交换律。
### 关键提示词
> 在WebGL2的列向量约定下,局部原点为(0,0,0),平移(2,0,0),绕Y轴旋转90°。请分别分析T·R与R·T的世界中心位置和计算步骤,并建议我要打印哪些数值进行核验;不要直接重写完整程序。
### AI建议摘要
- 列向量约定下顶点按 P·V·M·position 计算,M=T·Ry·S 时“右边先执行”:顺序是 缩放→旋转→平移。
- 对 M1=T·Ry·S,局部原点 (0,0,0) 先经 S、Ry 仍是 (0,0,0),最后 T 得 (2,0,0)。
- 对 M2=Ry·T·S,先经 T 到 (2,0,0),再绕Y轴旋转90°;绕Y轴旋转将 (x,z) 变为 (x·cosθ+z·sinθ, −x·sinθ+z·cosθ),代入 (2,0,0)、θ=90° 得 (0,0,-2)。
- 建议打印:两种 Model 矩阵本身、以及 c.point(model,0,0,0) 的局部原点世界坐标,用来与手算对照;不要只凭颜色判断。
### 我的判断与手算
- 采纳。手算 M2 的 90° 旋转:
x' = 2·cos90° + 0·sin90° = 0;z' = −2·sin90° + 0·cos90° = −2 → (0,0,-2)。与 AI 分析一致。
- 特别注意:这里旋转作用在“已经被平移过的点”上,等价于把整个坐标系绕原点旋转,故位移方向随旋转而改变;而 M1 是“先旋转再平移”,位移方向始终沿世界 +X。
### 我实际测试的参数与坐标
- 在 task-b.html:tx=2、θ=90°、s=1(点击“一键设置90°测试”)。
- 用 engine 的 c.chain 与 c.point 打印:
- M1=T·Ry·S → 中心 (2.00, 0.00, 0.00)
- M2=Ry·T·S → 中心 (0.00, 0.00, -2.00)
- 另测 θ=0°:两种次序均得 (2,0,0);θ=180°:M2 得 (−2,0,0)。
### 运行现象/数值结果
- 页面出现两个立方体:暖色(T·Ry·S)在 +X 方向 (2,0,0),青色(Ry·T·S)转到 −Z 方向 (0,0,-2),两者中心明显不同;状态栏坐标与手算、AI 分析完全一致。
- θ=0° 时两立方体重合(中心同为 (2,0,0)),仅此一特例相同。
### 修正结论
- 矩阵乘法不满足交换律:T·R ≠ R·T。因为 T 改变的是平移方向在哪个坐标系里生效——M1 中旋转先作用、平移沿世界轴;M2 中平移先作用、再被旋转整体搬动。
- 仅靠“θ=0°时两序结果相同”不能证明可交换:特殊角度相合是巧合(该角度下旋转不改变平移后的位置),不等于对一般 θ 成立。必须用非零角(如90°)对照。
- 确认核验矩阵正确性的最可靠方式是“打印局部原点经 Model 矩阵后的世界坐标 + 与手算比对”,而非只看画面。
---
## 协作2:程序调试(Task C 或 D)
### 错误现象与自己的初步分析
- 在 Task D 中,我先把“肩部位姿”误写为只由自身平移与旋转构成(`shoulderPose = T(0,.55,0)·Rz(pitch)`),而没有继承 `basePose`。初步猜测是“肩关节仍与世界原点绑定”,但想验证是否真由缺少父矩阵导致。
- 另外在数值核验脚本中,我把组合函数写成了箭头函数 `chain=()=>{...arguments...}`,箭头函数没有自己的 `arguments`,导致所有矩阵乘法结果为 NaN、无法核验坐标——这也是一个真实的“测试通道自身错误”的调试点。
### 提示词
> 我的三维对象能显示,但修改父关节(基座 yaw)角度后,机械臂与探头并没有整体跟随基座旋转。请提出三个最有可能的矩阵顺序或局部坐标错误,每个错误给出一项能区分原因的测试,不要直接替我重写整份代码。
### AI提出的可能原因
1. 子关节(肩部)位姿没有用父位姿前乘:`shoulderPose = T·Rz` 而正确应为 `shoulderPose = basePose·T·Rz`。测试:固定 pitch、只改 yaw,若肩部/末端世界坐标不变,即为“未继承父矩阵”。
2. 末端用世界原点直接定位,而不是 `shoulderPose·T(0,L,0)`。测试:打印 tip 的 c.point 值,看是否随 shoulder 变化。
3. 把臂段的非均匀缩放 S(width,L,depth) 直接乘进关节位姿再传给子部件,导致形变沿父子链传递。测试:单独改变臂段缩放,看探头是否被拉长。
### 我逐项完成的测试
1. 修正为 `shoulderPose = chain(basePose, T(0,.55,0), Rz(pitch))` 后,将 yaw 从0调到90,打印肩部、末端世界坐标——末端坐标随 yaw 改变,说明已正确继承父矩阵。
2. 核对 `tipPose = chain(shoulderPose, T(0,2.2,0))`,确认末端沿肩部局部 +Y 延伸,未用世界原点。
3. 检查绘制矩阵:`armDraw = chain(shoulderPose, T(0,1.1,0), S(.38,2.2,.45))`,非均匀缩放只放在“部件绘制”最右端,不进入 pose;探头 `probeDraw = chain(tipPose, ...)` 不受臂段缩放影响,装配关系保持。
### 真实原因与修复
- 根因是第1条:肩部(以及末端)关节位姿必须由“父位姿 × 自身局部变换”级联,否则子对象与父对象的坐标系脱节,父关节运动无法带动子对象。
- 修复:将 `shoulderPose`、`tipPose` 改为继承 `basePose`(Task D/E 同此);臂段/探头的几何缩放一律放在各自“绘制矩阵”的最右端,不混入父子位姿。
- 数值核验脚本中的 NaN 则因 `chain` 用了箭头函数、`arguments` 失效;改为普通函数后,全部关键坐标核验通过(15/15)。
### AI建议是否采纳及理由
- 采纳。原因1、2 与我的调试现象完全吻合,按“固定 pitch 改 yaw”就能隔离出“未继承父矩阵”这一个变量;原因3 也通过“单改臂段缩放、观察探头是否变形”验证。修复后父运动带子、子运动不影响父,满足 D 的验收。
---
## 协作3:主题场景协商(Task E)
### 我希望实现的对象关系
- 需要 ≥3 个可区分部件、≥1 组父子关系、≥2 种复合变换机制、≥2 个独立可调参数,并支持暂停/继续、速度、重置与 PNG 截图。我希望保留一个“层次机械臂 + 独立旋转台”的整体结构,让父链与独立旋转两类机制都能被直观验证。
### 关键提示词
> 我已实现T·R·S、绕指定点旋转和两级父子变换。请提出两个可在40分钟内用简单立方体完成的三维联动场景,并比较部件关系、矩阵链、交互参数、验证难度。请复用现有WebGL2框架,不引入相机拾取、光照或外部库,也不要直接生成整套代码。
### AI提供的两个方案与比较
| 方案 | 部件关系 | 核心矩阵链 | 交互参数 | 验证难度 |
|---|---|---|---|---|
| A. 医学设备定位装置+旋转样本台 | 基座→肩部→探头(父子);样本台独立,样本自转+标记公转 | 基座= T·Ry(yaw);肩= base·T·Rz(pitch);端= shoulder·T;样本= T(P)·Ry(spin)·S;标记= T(P)·Ry(orbit)·T(r)·S | yaw、pitch、speed | 低:父链与旋转台分左右两侧,互不干扰,便于分别核验 |
| B. 行星—卫星系统 | 恒星(中心)→行星(公转,自转)→卫星(绕行星公转);三级父子 | 行星= T·Ry(公转)·S;卫星= 行星位姿·T·Ry(绕行星)·S | 公转速度、自转速度 | 中:三级链较复杂,需更多手算 |
### 我的选择理由
- 选择方案A(医学设备定位+旋转样本台)。理由:它同时包含“两级父子(基座→肩→探头)”与“独立自转/公转(样本与标记)”两类机制,符合实验考察的两种复合变换;左侧父链、右侧旋转台布局清晰,能用“固定一个参数只改另一个”的控制变量法独立核验;沿用教师示例主题便于对照验收标准,40分钟内可稳定完成并验证。
### 实际矩阵链与交互参数
- 基座:`basePose = T(-2,-1.3,0)·Ry(yaw)`
- 肩部:`shoulderPose = basePose·T(0,.55,0)·Rz(pitch)`
- 末端探头:`tipPose = shoulderPose·T(0,2.2,0)`;`probeDraw = tipPose·T(0,.32,0)·S(.73,.65,.73)`
- 样本台:`turntableDraw = T(2,-1.32,0)·S(1.9,.25,1.9)`
- 样本自转:`specimenDraw = T(P)·Ry(spinAngle)·S(.7,.78,.7)`,spinAngle=elapsed×65°
- 环绕标记公转:`orbitMarker = T(P)·Ry(orbitAngle)·T(1.16,.28,0)·S(.22)`,orbitAngle=elapsed×42°
- 交互:yaw(−180..180)、pitch(−60..60)、speed(0..3×);暂停/继续、重置、保存PNG。
### 两组对照测试
1. 固定 pitch=−20°,将 yaw 从0°调到90°:探头与机械臂随基座整体转过90°(末端世界坐标随 yaw 改变),证明父运动带动子对象;样本台与标记不受影响,保持各自旋转。
2. 固定 yaw=25°,只改 pitch:基座静止,机械臂与探头随肩部俯仰运动,末端坐标改变而基座世界坐标不变,证明子运动不影响父。
3. 样本自转:P 处中心坐标不随 spinAngle 变化(始终为样本中心);标记公转:到样本中心的距离恒为半径1.16,360°后回到初始位置——证明自转与公转是不同的矩阵机制,而非直接改顶点。
### 最终结果和反思
- 五个部件(基座、机械臂、探头、样本台、样本、环绕标记共6个可区分对象)全部按矩阵链正确显示;暂停2秒画面保持、继续无突跳;改 speed 可见样本/标记转速变化;保存的 PNG 非空白、尺寸与画布一致。
- 与教师示例相比,我补全了所有矩阵 TODO 并对样本自转采用 `T(P)·Ry(spin)·S`(绕样本自身中心),标记采用 `T(P)·Ry(orbit)·T(r)·S`(绕样本中心公转),两者轨迹不同,用矩阵机制实现而非直接修改顶点。
- 反思:父子机制与绕点旋转的区别在于“旋转作用在谁的坐标系”——父矩阵把整个局部坐标系搬走,子对象随之;绕点旋转用 T(P)·R·T(−P) 把旋转限定在指定世界点上。数值打印(c.point)比“看上去大致正确”更能确认矩阵关系。