AI 协作日志

学生 Web 实验作品平台

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

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

## AI协作1:理解数据流
### 我的目标
搞清楚从JavaScript的Float32Array顶点数据,到浏览器屏幕画出三角形的完整WebGL2流水线,理解Buffer、vertexAttribPointer、顶点着色器、光栅化、片元着色器各自的分工,不直接复制代码。
### 提示词
从JavaScript Float32Array到屏幕上出现一个三角形,中间发生了哪些关键步骤?请结合WebGL2解释Buffer、vertexAttribPointer、Vertex Shader、光栅化和Fragment Shader各自负责什么,不要直接修改我的代码。
### AI关键回答摘要
1. Float32Array存放在CPU内存,保存原始顶点数值;
2. Buffer是GPU显存对象,`bufferData()`把CPU的数据拷贝上传到GPU显存;
3. `vertexAttribPointer`规定GPU如何从Buffer的字节流里读出每一个顶点的属性数据;
4. 顶点着色器对每一个顶点执行,输出裁剪空间坐标`gl_Position`;
5. 图元组装后进入**光栅化**:把几何三角形拆解成大量片元(像素候选);
6. 光栅化会对out/in变量做插值;片元着色器逐个片元计算颜色,最终输出到canvas像素。
7. JS数组和GPU Buffer是两块独立内存,修改JS数组不会自动更新GPU,必须重新bufferData。
### 我的判断
一开始我以为修改JS里vertices数组,图形就会自动变化,不需要额外调用上传函数。
### 验证方法
1. 对照task1.html、js/task1.js代码,找到数据流每一步对应的代码;
2. 修改JS顶点数组,**不执行bufferData**,观察画面是否改变。
### 验证结果
修改JS的vertices数组之后,不调用bufferData,浏览器画面三角形完全没有变化。只有执行bufferData,图形才会更新。
### 修正后的结论
JavaScript的TypedArray位于CPU内存,Buffer在GPU显存,二者互相隔离。修改CPU侧数组,必须调用`bufferData()`重新把数据拷贝到GPU,渲染结果才会更新。

---

## AI协作2:程序调试
### 现象
task3任务,画布只能画出左侧三角形,右侧四边形完全看不到。
### 我的初步判断
猜测是四边形的uniform颜色和背景白色一样,导致看不见图形。
### 给AI的提示词
下面是一段 WebGL2 代码。第一个图形正常,第二个图形没有显示。请不要重写完整程序,只列出最可能的3个原因,并告诉我应该通过什么现象、Console 信息或代码检查逐一验证。
### AI给出的关键建议
1. 切换新Buffer之后,忘记重新调用`vertexAttribPointer`;该函数绑定的是**当前绑定的ARRAY_BUFFER**,换buffer后映射关系失效;
2. drawArrays传入的顶点数量写错;
3. 顶点坐标超出`[-1,1]`裁剪空间,图形跑到画布可视区域之外。
### 我实际进行的测试
1. 打印检查四边形顶点坐标,坐标在‑1~1之间,排除坐标越界;
2. 核对drawArrays的顶点参数,四边形4个顶点参数写的是4,数量正确;
3. 人为复现bug:注释掉第二个Buffer后的`vertexAttribPointer`,四边形消失;把该语句恢复。
### 测试结果
补上切换buffer后的`vertexAttribPointer`语句,右侧四边形正常渲染出来。
### 最终原因
WebGL是状态机。`vertexAttribPointer`建立的是「当前绑定的Buffer」和着色器attribute的映射。当bindBuffer绑定新缓冲区后,旧的映射失效,必须再次执行vertexAttribPointer配置读取规则。
### 是否采纳AI建议及理由
采纳。AI给出的三条假设帮助我定位WebGL状态机特性,实际测试验证了第一条就是真实问题,加深对多Buffer绘制的理解。

---

## AI协作3:顶点属性与颜色
### 我的目标
理解task4中位置属性vPosition每个顶点读2个float,颜色vColor每个顶点读4个float;从GPU读取Buffer字节流角度理解`vertexAttribPointer`size参数的作用。
### 提示词
在 WebGL2 中,位置属性 vPosition 每个顶点提供2个 float,而颜色属性 vColor 每个顶点提供4个 float。请从“GPU怎样按 vertexAttribPointer 的参数读取 Buffer 中连续数据”的角度解释两个属性的区别,不要只列参数定义。
### AI关键回答摘要
`vertexAttribPointer`第二个参数size代表**该属性单个顶点占用多少个浮点数**。
- 位置属性只需要x、y二维坐标,size=2;GPU每读取2个float作为一个顶点的位置;
- 颜色属性是RGBA四个通道,size=4;GPU每读取4个float作为一个顶点的颜色;
不同Buffer绑定后调用vertexAttribPointer,就把该Buffer数据与对应in属性绑定。size设置错误会造成数据读取错位,画面花屏。
### 对照实验
将task4中颜色的`gl.vertexAttribPointer(vColorLoc,4,gl.FLOAT,false,0,0)`,临时把size参数从4改为3,运行页面,观察画面,之后恢复为4。
### 实际现象
size改为3之后,三角形颜色完全错乱,出现奇怪杂色,没有正常红‑绿‑蓝渐变。恢复size=4之后渐变正常。
### 我的解释
颜色Buffer数组每4个浮点数代表一个顶点RGBA;size=3时,GPU每次只取3个float当作颜色,读取指针发生错位,读错下一组数据,颜色全部错乱。
### 最终结论
vertexAttribPointer的size必须严格匹配单个顶点该属性实际占用float数量;size参数控制GPU从缓冲区连续数据流的读取步长,设置错误会数据错位渲染异常。

---

## 任务5图元探究实验记录
我修改了什么:保持task2的4个顶点的坐标、顶点顺序、颜色全部不变,只修改`gl.drawArrays()`的图元mode参数。

我原先预测:更换图元只是渲染效果细微变化,顶点不变图形大体形态接近。

实际结果:
1. `gl.POINTS`:只渲染4个顶点小圆点,没有连线没有填充;
2. `gl.LINE_STRIP`:4个点连成折线,首尾不闭合;
3. `gl.LINE_LOOP`:4个点连成闭合空心方框,无填充;
4. `gl.TRIANGLE_STRIP`:生成两个三角形,得到实心填充四边形;
5. `gl.TRIANGLES`:只使用前3个顶点绘制一个三角形,第4个顶点被忽略。

原因解释:顶点数据只提供原始顶点集合;**图元mode定义GPU如何把一堆顶点组装成几何图元**。相同顶点,组装规则不同,输出图形完全不一样。

---

## 挑战任务2:索引绘制 drawElements
### 实现说明
使用`gl.ELEMENT_ARRAY_BUFFER`存放索引数组,调用`gl.drawElements()`绘制四边形。顶点数组只保存4个四边形角点,索引数组`[0,1,2,1,3,2]`组装两个三角形,实现顶点复用。

### drawArrays 与 drawElements对比
1. drawArrays:按顺序直接读取顶点缓冲区;如果顶点被多次使用,顶点数组中必须重复书写,造成数据冗余。
2. drawElements:顶点只存储一份原始数据,依靠索引编号重复引用顶点;适合复杂模型,节省显存。

---

## 各任务思考题参考答案
### 任务1
1. Float32Array中连续两个数为什么可以表示一个二维顶点?
> 二维顶点包含x、y两个分量。数组按`x0,y0,x1,y1,x2,y2……`紧凑排列,每连续两个float对应一个顶点的x与y。

2. Shader声明`in vec4 vPosition`,JS中vertexAttribPointer传入2,为什么可以正常绘制?
> WebGL自动对缺少分量做填充:z=0.0,w=1.0,把vec2扩充为vec4送入顶点着色器。

3. `gl.drawArrays(gl.TRIANGLES,0,3)`最后的3表示什么?
> 代表要处理**顶点的数量**,不是Float数组元素个数。

4. 修改JS顶点数据后,为什么要重新执行`gl.bufferData()`才能改变GPU中的数据?
> JS数组保存在CPU内存,Buffer在GPU显存;修改CPU数组不会自动同步,bufferData完成数据拷贝上传。

### 任务2
1. 相同顶点数据为什么会得到不同图形?
> 顶点只是原始点集合;绘制mode决定GPU如何把顶点组装为点、线、三角形图元,组装规则不同结果不同。

2. TRIANGLE_STRIP中顶点顺序为什么重要?
> 三角条带每新增一个顶点,和条带最后两个顶点组成新三角形;顶点颠倒会导致三角形翻转、图形错乱。

3. 4个顶点通过TRIANGLE_STRIP实际组成了几个三角形?
> 2个三角形,拼接成四边形。

### 任务3
1. 为什么改变uniform后不需要重新编译Shader?
> uniform是着色器程序运行时的全局只读变量,CPU可以运行时直接更新它的值,不需要重新编译链接程序。

2. 如果只设置一次uColor,随后绘制两个对象,会发生什么?
> 两个对象全部使用这同一个uniform颜色。

3. 为什么绑定新的Buffer后需要再次正确设置顶点属性读取方式?
> vertexAttribPointer配置绑定的是**当前绑定的ARRAY_BUFFER**;更换Buffer后映射关系失效,必须重新配置。

4. “当前WebGL状态会影响后续绘制”在本任务中体现在哪里?
> 当前绑定Buffer、vertexAttribPointer映射、uniform颜色、绘制模式都是全局状态;绘制完第一个物体之后这些状态保留,会直接影响第二次绘制。

### 任务4
1. 为什么位置Buffer每个顶点读取2个float,而颜色Buffer每个顶点读取4个float?
> 二维位置只需要x,y两个分量;颜色RGBA包含红、绿、蓝、Alpha共4个分量。

2. 两个Buffer如何分别对应到`vPosition`和`vColor`?
> bindBuffer绑定位置Buffer,调用vertexAttribPointer,将该Buffer与vPosition绑定;再bindBuffer绑定颜色Buffer,调用vertexAttribPointer将该Buffer与vColor绑定。

3. 三角形内部为什么出现连续渐变色,而不是只有红、绿、蓝三个区域?
> 光栅化阶段会对顶点输出的out变量做平滑插值,三角形内部每一个片元都会得到介于顶点颜色之间的混合颜色。

4. 顶点颜色插值主要发生在哪个阶段?Fragment Shader得到的是顶点原始颜色还是插值后的颜色?
> 插值发生在**光栅化阶段**;片元着色器拿到的是插值之后的颜色,不是原始顶点颜色。