AI 协作日志

学生 Web 实验作品平台

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

# 实验一 AI协作记录

> 请记录本人真实的AI协作过程。不要只粘贴AI生成结果,应体现自己的判断、测试和核验。

## AI协作1:理解数据流

### 我的目标

刚拿到实验框架时,我不清楚整个实验要做什么、文件之间怎么配合,也不理解为什么从一段 JS 数组就能画出图形。我想先搞清楚整体目录结构和 WebGL 数据流,再动手填各个 TODO。

### 提示词

我把整个实验文件夹(index.html、task1~5.html/js、common 库、实验指导书)发给 AI,说"告诉我怎么做",请它说明:目录该怎么组织、每个任务改哪里、WebGL 从 JS 数据到屏幕像素经过哪些步骤。

### AI关键回答摘要

1. HTML 里写死引用的是 `common/xxx.js` 和 `js/taskX.js`,所以必须把散文件整理成 `common/` 和 `js/` 两个子目录,否则打开会 404、黑屏。
2. 数据流是:JS 的 Float32Array → `gl.createBuffer()` → `bindBuffer` → `bufferData`(真正拷到 GPU)→ `getAttribLocation` → `vertexAttribPointer`(规定 GPU 怎么从 Buffer 里读数据)→ `enableVertexAttribArray` → `drawArrays`。
3. WebGL 坐标范围是 [-1, 1],画布中心是 (0, 0)。
4. task1 只需改颜色和一个顶点坐标;task2 填 4 个顶点用 `TRIANGLE_STRIP`;task3 要画两次(两个 Buffer、两次 drawArrays、中间改 uniform 颜色);task4 要建两个 Buffer(位置读 2 个 float,颜色读 4 个 float);task5 复制 task2 顶点换 draw mode 观察。

### 我的判断

AI 给的步骤看起来和 task1.js 里已有的代码注释("顶点数据"/"创建并绑定Buffer"/"上传数据到GPU"等)能一一对应,但我不能直接全信,得自己对着代码走一遍。

### 验证方法

打开 task1.js,从 `window.onload` 开始逐行对照 AI 说的流程,确认每一步对应的实际代码行;再打开 task1.html 看 Shader 里 `vPosition` 是怎么声明的。

### 验证结果

1.task1.js 第 32–41 行确实是 createBuffer → bindBuffer → bufferData → getAttribLocation → vertexAttribPointer → enableVertexAttribArray,和 AI 说的顺序一致。
2.我原先以为 `bufferData` 只是"把数组传进去备用",核验后发现它才是真正把 CPU 内存拷到 GPU 显存的那一步;改了 JS 数组后必须重新调用它,GPU 才会更新。这解答了任务1思考题第4题。
3.Shader 里声明的是 `in vec4 vPosition`,但 JS 里 `vertexAttribPointer` 写的是 2,我原以为会报错。AI 解释说 WebGL 会自动补 z=0、w=1,所以正常绘制。我改了 task1 的顶点坐标后重新运行,确实画出了变形的三角形,验证了这一点。

### 修正后的结论

WebGL 绘制的本质是:JS 准备好 TypedArray,通过 Buffer 上传到 GPU,再用 `vertexAttribPointer` 告诉着色器"每个顶点从这个 Buffer 里按几个 float 读",最后 `drawArrays` 按指定图元类型把数据送进管线。修改顶点数据后必须重新 `bufferData`,因为 GPU 不会自动感知 CPU 数组的变化。

---

## AI协作2:程序调试

### 现象

任务2先用 `TRIANGLE_STRIP` 正确画出了绿色四边形。按实验要求做对照实验时,我把 drawArrays 的图元类型改成 `gl.POINTS`,刷新后画布完全空白——4个顶点一个点都看不到。

### 我的初步判断

我以为是顶点坐标写错了(可能跑到 [-1,1] 画布外面去了),或者 `drawArrays` 最后一个参数顶点数算错了。因为代码没报错,我一开始怀疑是数据问题,还试着改了几个顶点坐标,结果还是空白。

### 给AI的提示词

把 task2.js 完整代码和画布设空的截图发给 AI,问:"为什么 gl.points 看不到四个点?"

### AI给出的关键建议

AI 说点其实已经画出来了,只是太小:WebGL 里画点时如果顶点着色器没有设置 `gl_PointSize`,点的大小默认是 **1.0 像素**,在高 DPI 屏幕上几乎看不见。需要在顶点着色器的 `main()` 里加一行:

```glsl
gl_PointSize = 16.0;
```

AI 还提醒:这个值必须写在**顶点着色器**里,写在 JS 里没用。

### 我实际进行的测试

1. 先按 F12 看 Console,没有任何红色报错——说明 JS 确实运行到了 drawArrays,不是代码崩了。
2. 打开 task2.html,在顶点着色器(`<script id="vertex-shader">`)的 main() 里加上 `gl_PointSize = 16.0;`,保存。
3. Ctrl+Shift+R 强制刷新。

### 测试结果

刷新后画布上出现了 4 个绿色圆点,位置正好在四边形的四个角(左上、左下、右上、右下)。把 `gl_PointSize` 改回默认(删掉这行)后点又消失,确认就是这个原因。

### 最终原因

顶点着色器只写了 `gl_Position = vPosition;`,没有设置 `gl_PointSize`。WebGL 默认点大小是 1 像素,4 个点确实被绘制了,但肉眼看不见。这不是 JS 数据或 drawArrays 参数错误,而是我之前不知道"画点必须在顶点着色器里显式指定点大小"这个 WebGL 行为。我一开始怀疑坐标跑出去了,方向完全错了。

> 补充:任务2最开始我还遇到过另一个小问题——第一次填 drawArrays 时把图元位置留成了注释 `gl.drawArrays(/* TODO: mode */, 0, vertexCount);`,实际传进去的第一个参数是 `undefined`,WebGL 报 INVALID_ENUM,什么都不画。改成 `gl.TRIANGLE_STRIP` 后才正常。这两个问题让我总结出:不显示时先看 Console 有没有报错,没报错再怀疑是不是画了但太小/颜色太接近背景。

### 是否采纳AI建议及理由

采纳。AI 没有让我改顶点数据,而是先让我确认"有没有报错",再指出 `gl_PointSize` 这个我完全不知道的默认行为。这个建议解释了为什么 Console 干净却看不到图形——点画了但只有 1 像素。我自己加了 `gl_PointSize` 后点确实出现了,对照实验(删掉就消失)也验证了结论。

---

## AI协作3:顶点属性与颜色

### 我的目标

任务4要求三角形每个顶点有自己的颜色(红绿蓝),内部出现渐变。我不理解为什么位置 Buffer 每个顶点读 2 个 float、颜色 Buffer 要读 4 个 float,也想知道为什么三角形内部是连续渐变色而不是三块纯色。

### 提示词

我问 AI:"位置属性 vPosition 每个顶点提供 2 个 float,颜色属性 vColor 每个顶点提供 4 个 float。请从 GPU 怎样按 vertexAttribPointer 的参数连续读取 Buffer 数据的角度解释两者区别。"

### AI关键回答摘要

1. `vertexAttribPointer` 的第二个参数(size)决定 GPU 每读完一个顶点后在 Buffer 里跳几个 float。位置是二维 (x, y) 所以 size=2;颜色是 RGBA 四通道所以 size=4。两个 Buffer 各自独立绑定、各自调用一次 `vertexAttribPointer`,分别对应着色器里的 `vPosition` 和 `vColor` 两个 `in` 变量。
2. 顶点颜色通过 Vertex Shader 里的 `out` 变量 `aColor` 传给 Fragment Shader,光栅化阶段会在三角形内部对三个顶点的颜色做插值——Fragment Shader 拿到的是插值后的值,不是顶点原始颜色,所以内部是连续渐变。
3. 如果把颜色的 size 从 4 改成 3,GPU 会按每 3 个 float 一组去读原本每 4 个 float 一组的数据,导致颜色整体错位,渐变会错乱。

### 对照实验

按实验要求,我把颜色 Buffer 对应的 `vertexAttribPointer` 第二个参数从 4 临时改成 3:

```javascript
gl.vertexAttribPointer(vColor, 3, gl.FLOAT, false, 0, 0);
```

刷新观察后再改回 4。

### 实际现象

改成 3 后,三角形仍然是彩色的,但颜色明显不对:原本该红的顶点偏色,渐变过渡错乱,不是预期的红→绿→蓝平滑过渡。改回 4 后恢复正常的三色渐变。

### 我的解释

`colors` 数组每个顶点写了 4 个 float(R,G,B,A)。当 size=3 时,GPU 从 Buffer 里连续读:顶点1读 R1,G1,B1,顶点2接着读 A1,R2,G2——也就是把顶点1的 alpha 当成了顶点2的红色,顶点2的绿色当成了顶点2的蓝色……数据整体错位一个 float,所以颜色全乱。这验证了 AI 说的"GPU 按 size 连续顺序读 Buffer"。

### 最终结论

1.一个程序可以有多个 Buffer,每个 Buffer 绑定后调用一次 `vertexAttribPointer`,把它映射到着色器里对应的 `in` 属性。
2.size 参数必须和数据数组里每个顶点实际存放的 float 个数一致,否则数据错位。
3.顶点颜色在光栅化阶段被插值,Fragment Shader 收到的是插值后逐片元的颜色,这就是三角形内部出现连续渐变的原因。

---

## AI协作4:任务5图元对照实验记录

### 我修改了什么

在 `js/task5.js` 中复制了任务2的4个顶点数据(坐标与顺序不变),只把 `gl.drawArrays()` 的绘制模式从任务2的 `TRIANGLE_STRIP` 改为 `gl.TRIANGLES`,其余代码不动。

### 我原先预测

4个顶点用 `TRIANGLES` 绘制,应该每3个顶点组成一个独立三角形:前3个顶点组成1个三角形,第4个顶点凑不齐一组,会被忽略,所以画面上应该是1个三角形,而不是完整四边形。

### 实际结果

刷新页面后画布上确实只出现了1个三角形(由前3个顶点组成),第4个顶点没有参与绘制,四边形没有被填满。对照任务2用 `TRIANGLE_STRIP` 时同样4个顶点能画满整个四边形,结果差异非常明显。

### 原因解释

`gl.TRIANGLES` 把顶点序列按每3个一组解释成独立三角形,4个顶点只有一组完整的3个顶点,剩下的1个顶点不足一组,被直接丢弃;而 `TRIANGLE_STRIP` 从第3个顶点开始,每个新顶点都与前两个顶点组成一个新三角形,所以4个顶点能生成2个三角形拼成完整四边形。相同顶点数据,只改变图元解释方式,绘制结果就完全不同——这验证了"图元组装"是数据流中独立的一环。

> 补充:任务2对照实验时我还依次试过 `POINTS`(点太小看不见,需在顶点着色器加 `gl_PointSize`)和 `LINE_STRIP`(只连线不填充),都是"数据不变、图元类型变、结果变"。

---

## AI协作5:挑战任务(索引绘制四边形)

### 我做了什么

选做挑战2:新建 `challenge.html` 和 `js/challenge.js`,用 `ELEMENT_ARRAY_BUFFER` + `gl.drawElements()` 绘制四边形,并在 `index.html` 的任务导航中增加了挑战链接。挑战1(交互改色)未做,按指导书"任选一项"的要求完成挑战2。

### 实现要点

1. 顶点数组只存 4 个不重复顶点:v0 左上、v1 左下、v2 右上、v3 右下。
2. 索引数组存 6 个索引:`(0,1,2)` 和 `(1,3,2)`,两个三角形共用 v1、v2 两个顶点。
3. 索引数据用 `Uint16Array` 上传到 `ELEMENT_ARRAY_BUFFER`,绘制时调用 `gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)`——第二个参数 6 是索引数量,不是顶点数量。

### 与 drawArrays() 方案的比较(我的理解)

- **drawArrays() 方案**:四边形需要把顶点数组写成 6 个顶点(两个三角形各 3 个,其中 v1、v2 要重复出现),GPU 按顺序读顶点,每个顶点都要经过一次顶点着色器,重复的顶点会被重复处理。
- **drawElements() 方案**:顶点数组只存 4 个不重复顶点,GPU 先按索引取出顶点,共享顶点(v1、v2)在显存里只存一份、通过索引反复引用,顶点着色器实际只执行 4 次。
- 类比:drawArrays 像把同一个点抄两份交给 GPU;drawElements 像告诉 GPU"第1个三角形用顶点 0、1、2,第2个三角形用顶点 1、3、2"。后者省存储、避免重复计算,图形复杂(如大量共享顶点的网格)时优势更明显。

### 验证

渲染 `challenge.html`,画布出现一个紫色四边形,与任务2用 `TRIANGLE_STRIP` 画出的形状一致,说明索引方案正确;把索引数量从 6 改成 4 会只画一个三角形(第4个索引起被忽略),反向验证了 drawElements 的 count 参数含义。

---

## AI协作6:挑战任务1(交互改色)

### 我做了什么

把挑战1也做了:新建 `challenge1.html` 和 `js/challenge1.js`,在任务3的三角形 + 四边形基础上增加两个颜色控件和一个"重置颜色"按钮,用户选色后立即更新对应对象颜色并重绘;同时在 `index.html` 中补充挑战1链接。

### 说明(对应挑战任务的三个要求)

1. **哪个 JavaScript 变量发生改变**:`triangleColor` / `quadColor` 这两个保存当前颜色的对象。颜色控件触发 `input` 事件后,`hexToRgb()` 把 "#RRGGBB" 转成 0~1 的 RGB 分量并更新对应变量;点"重置颜色"则把它们恢复为默认值。
2. **哪个 uniform 被更新**:Fragment Shader 里的 `uColor`。每次重绘前调用 `gl.uniform4f(uColor, r, g, b, 1.0)`,把新的颜色分量传入 GPU,着色器输出 `fColor = uColor`。
3. **为什么几何 Buffer 不需要重新创建**:Buffer 里存的是顶点坐标(几何数据),颜色并不在 Buffer 中,而是通过 uniform 在运行时传入。改变颜色时顶点数据没有任何变化,所以只需更新 uniform 并再次调用 `gl.drawArrays()`,两个几何 Buffer(tBuffer、qBuffer)在初始化时创建一次后全程复用,无需重建。

### 验证

渲染 `challenge1.html` 初始状态:红色三角形 + 蓝色四边形与任务3一致;拖动颜色控件(或点重置按钮)后 `status` 显示的颜色值随之更新,图形颜色即时变化,说明"改变量 → 更新 uniform → 重绘"的链路正确;整个过程中没有重新调用 `createBuffer()`/`bufferData()`。