AI 协作日志

学生 Web 实验作品平台

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

# 实验一 AI协作记录

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

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

### 我的目标

理解实验一的整体操作流程,并弄清楚 JavaScript 中定义的顶点数据是如何经过 WebGL2 最终显示到 Canvas 上的。

### 提示词

学习一下这些内容,告诉我从头的操作,代码可以使用vscode

### AI关键回答摘要

AI首先介绍了使用 VS Code 完成实验的基本流程,包括解压实验文件、使用 VS Code 打开实验目录、通过 Live Server 运行 `index.html`,然后按照 `task1` 到 `task5` 的顺序完成实验。

对于 WebGL 的数据流,AI解释了顶点数据首先使用 `Float32Array` 保存在 JavaScript 中,然后通过 `gl.bufferData()` 上传到 GPU Buffer。之后通过 `gl.vertexAttribPointer()` 规定 GPU 如何读取 Buffer 中的数据,并将数据传递给 Vertex Shader。顶点经过图元组装和光栅化后,再由 Fragment Shader 决定最终显示的颜色。

### 我的判断

开始时我主要把 Buffer 理解成普通的 JavaScript 数组,没有注意到 JavaScript 中的数据和 GPU 中的数据并不是同一部分。

根据 AI 的解释,我认为 `gl.bufferData()` 是将 CPU 端的数据上传到 GPU,而 `gl.vertexAttribPointer()` 是建立 GPU Buffer 与 Shader 顶点属性之间联系的重要步骤。

### 验证方法

我在 `task1.js` 中按照程序执行顺序查看:

```javascript
gl.createBuffer();
gl.bindBuffer();
gl.bufferData();
gl.getAttribLocation();
gl.vertexAttribPointer();
gl.enableVertexAttribArray();
gl.drawArrays();
```

同时查看 `task1.html` 中 Vertex Shader 的:

```glsl
in vec4 vPosition;
```

并与 JavaScript 中获取 `vPosition` 的代码进行对应。

之后修改三角形的一个顶点坐标和颜色并重新运行程序。

### 验证结果

修改顶点坐标后,三角形的形状发生了变化;修改 `uColor` 后,三角形的颜色也发生变化。

程序中的代码顺序与 AI 对数据流的解释一致,说明顶点数据确实需要先进入 GPU Buffer,再通过顶点属性传递给 Shader。

### 修正后的结论

WebGL2 中,Shader 不能直接读取 JavaScript 中的 `Float32Array`。顶点数据需要先上传到 GPU Buffer,再使用 `vertexAttribPointer()` 指定数据的读取方式。

整个过程可以概括为:

```text
JavaScript顶点数据
→ Float32Array
→ GPU Buffer
→ 顶点属性
→ Vertex Shader
→ 图元组装
→ 光栅化
→ Fragment Shader
→ Canvas像素
```

---

## AI协作2:程序调试

### 现象

完成任务3后,左侧三角形和右侧四边形都能够正常显示。

为了进行调试测试,我将四边形原来的:

```javascript
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
```

临时修改为:

```javascript
gl.drawArrays(gl.TRIANGLES, 0, 4);
```

重新运行后,左侧三角形仍然正常,但是右侧四边形不能完整显示,只显示出了一个三角形区域。

### 我的初步判断

因为我没有修改四边形的4个顶点坐标,所以我认为问题应该不是顶点数据导致的。

我怀疑是修改了 `gl.drawArrays()` 中的图元类型,使 GPU 对相同顶点采用了不同的组合方式。

### 给AI的提示词

任务3中第一个三角形能够正常显示,但是第二个四边形显示不完整。四边形的顶点数据没有修改,只修改了 `gl.drawArrays()` 中的 draw mode。请不要重新写完整程序,告诉我可能的原因以及应该如何验证。

### AI给出的关键建议

AI建议依次检查:

1. 四边形的 draw mode 是否仍然为 `gl.TRIANGLE_STRIP`;
2. `gl.drawArrays()` 中的顶点数量是否正确;
3. 绘制四边形之前是否正确绑定了对应 Buffer;
4. 更换 Buffer 后是否重新设置了 `vertexAttribPointer()`。

AI指出 `gl.TRIANGLES` 和 `gl.TRIANGLE_STRIP` 对同一组顶点的组织方式不同,因此即使顶点坐标完全一样,最终得到的图形也可能不同。

### 我实际进行的测试

我首先确认四边形仍然包含4个顶点,并检查绘制前的 Buffer 绑定和 `vertexAttribPointer()`,这些代码均没有改变。

随后只把:

```javascript
gl.TRIANGLES
```

恢复为:

```javascript
gl.TRIANGLE_STRIP
```

其他代码保持不变,再次运行程序。

### 测试结果

恢复 `gl.TRIANGLE_STRIP` 后,右侧四边形重新完整显示,左侧三角形也保持正常。

### 最终原因

`gl.TRIANGLES` 每3个顶点组成一个独立的三角形。

四边形只有4个顶点,因此前三个顶点可以构成一个三角形,但是剩余的一个顶点无法单独构成第二个三角形。

`gl.TRIANGLE_STRIP` 可以利用4个连续顶点组成两个相邻三角形,因此能够绘制完整四边形。

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

采纳了 AI 关于检查 draw mode 的建议。

我通过只改变一个变量进行对照测试,发现恢复 `gl.TRIANGLE_STRIP` 后图形立即恢复正常,因此能够确认问题确实来自图元类型,而不是顶点坐标或 Buffer。

这次调试也让我理解了,相同的顶点数据使用不同的 draw mode 会产生不同的绘制结果。

---

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

### 我的目标

理解任务4中位置属性 `vPosition` 和颜色属性 `vColor` 为什么需要使用不同的 `vertexAttribPointer()` 参数,以及三角形内部为什么会出现连续的渐变颜色。

### 提示词

在 WebGL2 中,位置属性 `vPosition` 每个顶点提供2个 float,而颜色属性 `vColor` 每个顶点提供4个 float。请从 GPU 怎样通过 `vertexAttribPointer()` 读取 Buffer 中连续数据的角度解释它们的区别。

### AI关键回答摘要

AI解释了 `vertexAttribPointer()` 的第二个参数表示每个顶点属性包含多少个数据分量。

位置数据的形式为:

```text
x, y
```

因此每个顶点读取2个 `float`。

颜色数据的形式为:

```text
R, G, B, A
```

因此每个顶点读取4个 `float`。

位置数据和颜色数据分别存放在不同的 Buffer 中,通过 `vPosition` 和 `vColor` 两个不同的 Shader 属性进行对应。

三角形内部的渐变颜色则是在光栅化过程中,根据三个顶点的颜色进行插值得到的。

### 对照实验

正确的颜色属性代码为:

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

按照实验要求,我将其中的:

```javascript
4
```

临时修改为:

```javascript
3
```

运行程序并观察颜色变化,之后再恢复为正确的 `4`。

### 实际现象

当参数为 `4` 时,三个顶点分别显示红、绿、蓝三种颜色,并且三角形内部形成连续的渐变。

将参数修改为 `3` 后,颜色显示发生异常,三个顶点的颜色与原来设置的红、绿、蓝不再正确对应。

恢复为 `4` 后,颜色显示重新正常。

### 我的解释

颜色数组原来的存储方式是:

```text
R G B A | R G B A | R G B A
```

每4个 `float` 对应一个顶点。

当 `vertexAttribPointer()` 的参数为 `4` 时,GPU能够按照正确的数据边界读取每个顶点颜色。

如果修改为 `3`,GPU会按照:

```text
R G B | A R G | B A R | ...
```

的方式重新划分数据,因此原来的颜色数据被错误分组,最终导致颜色显示异常。

另外,三角形内部并没有单独定义大量颜色,而是 GPU 在光栅化过程中根据三个顶点的颜色进行插值,因此会看到连续的渐变效果。

### 最终结论

`vertexAttribPointer()` 中设置的分量数量必须与 Buffer 中实际的数据组织方式一致。

位置属性:

```text
x, y
```

所以每个顶点读取2个 `float`。

颜色属性:

```text
R, G, B, A
```

所以每个顶点读取4个 `float`。

不同顶点的颜色经过光栅化阶段插值后,再传递给 Fragment Shader,因此最终能够在三角形内部形成连续的渐变颜色。