AI 协作日志
学生 Web 实验作品平台
学号:202412211402004 · 来源:ai-log.md
# 实验一 AI协作记录 > 请记录本人真实的AI协作过程。不要只粘贴AI生成结果,应体现自己的判断、测试和核验。 ## AI协作1:理解数据流 ### 我的目标 理解一组JavaScript顶点数据如何经过WebGL2的各个阶段,最终显示为Canvas中的三角形。 ### 提示词 从 JavaScript 的 Float32Array 到屏幕上出现一个三角形,中间发生了哪些关键步骤?请结合 WebGL2 解释 Buffer、vertexAttribPointer、Vertex Shader、光栅化和 Fragment Shader 各自负责什么,不要直接修改我的代码。 ### AI关键回答摘要 `Float32Array`在CPU端保存连续的顶点数据;`gl.bufferData()`把数据上传到GPU Buffer;`gl.vertexAttribPointer()`规定GPU如何分组、解释Buffer中的数据,并将其关联到Vertex Shader的输入属性;Vertex Shader逐顶点计算`gl_Position`;图元组装阶段每三个顶点组成三角形;光栅化把三角形覆盖区域转换为片元并插值属性;Fragment Shader计算各片元的颜色,最后写入Canvas。 ### 我的判断 我最初只理解连续两个数分别表示x、y坐标,没有意识到`Float32Array`本身并不知道如何划分顶点。真正决定“每两个float为一个顶点”的是`vertexAttribPointer()`的第二个参数`2`。 ### 验证方法 逐项对照`task1.html`和`js/task1.js`:在JavaScript中找到`Float32Array`、`createBuffer()`、`bufferData()`、`vertexAttribPointer()`和`drawArrays()`;在HTML中找到Vertex Shader、Fragment Shader及`gl_Position`、`fColor`。同时修改第一个顶点坐标并重新运行页面,观察三角形形状是否改变。 ### 验证结果 修改第一个顶点坐标并重新上传后,三角形形状随之改变;`vertexAttribPointer(vPosition, 2, ...)`确实使GPU按两个float读取一个位置。Shader中的`vPosition`虽然是`vec4`,但只提供x、y时,缺少的z、w会补为0和1,因此仍能正常绘制。 ### 修正后的结论 Buffer负责保存上传到GPU的数据,`vertexAttribPointer()`负责说明这些数据的读取方法,两者不是同一个作用。完整流程为:顶点数组→GPU Buffer→顶点属性→Vertex Shader→图元组装→光栅化→Fragment Shader→Canvas像素。 --- ## AI协作2:程序调试 ### 现象 任务3正确版本能够显示左侧红色三角形和右侧蓝色四边形。为了完成真实排错,我在AI协助下临时把四边形的绘制顶点数从4改为3,结果右侧四边形只剩下一个蓝色三角形。 ### 我的初步判断 第一个对象正常,说明WebGL2上下文、Shader Program和页面加载基本正常;第二个对象有颜色但形状不完整,问题更可能出在第二次绘制的图元类型或顶点数量,而不是Shader编译失败。 ### 给AI的提示词 任务3原本可以正常运行,但AI协作点B尚未完成。请通过一个可恢复的小错误完成真实调试,不要重写整个程序,并说明应根据什么现象定位原因。 ### AI给出的关键建议 先检查第二次`drawArrays()`的mode和count;再检查四边形Buffer是否已绑定并上传;确认绑定新Buffer后是否重新调用`vertexAttribPointer()`;最后检查第二次绘制前是否更新`uColor`。使用控制变量法,每次只改一项并观察画面。 ### 我实际进行的测试 保持顶点数据、Buffer、顶点属性和颜色不变,只把四边形绘制调用的count临时设为`3`。运行并截图观察后,将count恢复为`quad.length / 2`,即4个顶点。 ### 测试结果 count为3时,`TRIANGLE_FAN`只读取前三个顶点,只能组成一个三角形;恢复为4后,右侧重新显示完整四边形。左侧三角形在整个过程中始终正常。 ### 最终原因 `drawArrays()`的最后一个参数是顶点数量。四边形需要读取4个顶点,错误地设置为3会少读取一个顶点,因此只能形成一个三角形。 ### 是否采纳AI建议及理由 采纳了先检查绘制参数并采用控制变量法的建议,因为画面现象与预测一致,恢复正确顶点数量后问题立即消失,形成了完整的“假设—测试—结果—恢复”闭环。 --- ## AI协作3:顶点属性与颜色 ### 我的目标 理解位置Buffer和颜色Buffer为何采用不同的分组大小,以及GPU如何把两个Buffer分别交给`vPosition`和`vColor`。 ### 提示词 在 WebGL2 中,位置属性 vPosition 每个顶点提供2个 float,而颜色属性 vColor 每个顶点提供4个 float。请从“GPU怎样按 vertexAttribPointer 的参数读取 Buffer 中连续数据”的角度解释两个属性的区别,不要只列参数定义。 ### AI关键回答摘要 调用`vertexAttribPointer()`时,当前绑定的`ARRAY_BUFFER`会成为对应属性的数据来源。位置属性每两个float构成一个二维坐标;颜色属性每四个float构成RGBA。两个属性位置不同,各自保存自己的Buffer来源和读取格式,因此可以同时向Vertex Shader提供位置和颜色。 ### 对照实验 把颜色属性中的`gl.vertexAttribPointer(vColor, 4, ...)`临时改成`gl.vertexAttribPointer(vColor, 3, ...)`,其余代码保持不变,运行并观察后再恢复为4。 ### 实际现象 正确值4时,三角形三个顶点分别为红、绿、蓝,内部出现连续渐变。改成3后,顶部仍为红色,左下角变为品红色,右下角变为绿色,原来的蓝色顶点消失。 ### 我的解释 参数改为3后,GPU改为每三个float分组:第一个顶点读取`(1,0,0)`得到红色;第二个顶点从上一个RGBA的A分量继续读取,得到`(1,0,1)`即品红色;第三个顶点得到`(0,1,0)`即绿色。每组缺少的第四分量由WebGL补为1,后面的蓝色数据没有按原来边界被读取。 ### 最终结论 `vertexAttribPointer()`的size参数决定每个顶点从当前Buffer连续读取多少个分量。size必须和数据的实际组织方式一致,否则虽然程序可能仍能绘制,但属性边界会错位,颜色也会错误。实验结束后已恢复正确值4。 --- # 各任务思考题 ## 任务1 1. `Float32Array`中的数据连续存储,`vertexAttribPointer(vPosition, 2, ...)`规定每两个float组成一个顶点位置,第一个是x,第二个是y。 2. Shader需要`vec4`,而JavaScript只提供两个分量时,WebGL会把缺少的z、w补为`0.0`、`1.0`,得到`(x,y,0,1)`。 3. `gl.drawArrays(gl.TRIANGLES, 0, 3)`最后的3表示从第0个顶点开始读取3个顶点。`TRIANGLES`每三个顶点组成一个三角形。 4. JavaScript数组在CPU内存中,GPU绘制读取的是GPU Buffer。修改CPU端数组不会自动同步,需再次调用`bufferData()`上传;局部更新也可使用`bufferSubData()`。 ## 任务2 1. draw mode决定GPU如何解释相同顶点:可以把它们当作点、折线、独立三角形或三角形条带,所以结果不同。 2. `TRIANGLE_STRIP`按`1-2-3`、`2-3-4`连续组装三角形。顺序决定公共边和覆盖区域,顺序不合理可能导致重叠、交叉或缺失。 3. 4个顶点实际组成`4-2=2`个三角形。 ## 任务3 1. uniform是已编译Shader的运行时输入。修改其值没有改变Shader源代码或结构,因此不需要重新编译。 2. uniform值会保持到下次修改。如果只设置一次`uColor`,两个对象会使用相同颜色。 3. `vertexAttribPointer()`会记录调用时绑定的Buffer及读取格式。仅绑定新Buffer不会自动修改属性来源,因此需要再次设置。 4. Shader Program、Buffer绑定、顶点属性和uniform都是持续生效的WebGL状态。绘制四边形前必须更新相应状态,否则会继续使用三角形留下的状态。 ## 任务4 1. 二维位置由x、y组成,所以每个位置读取2个float;RGBA颜色由R、G、B、A组成,所以每个颜色读取4个float。 2. 分别绑定位置Buffer和颜色Buffer,并在各自绑定后调用`vertexAttribPointer()`,将它们关联到`vPosition`和`vColor`。 3. 光栅化阶段会在三个顶点之间对颜色属性进行插值,因此三角形内部呈现连续渐变,而不是三个互相分离的纯色区域。 4. 顶点颜色插值主要发生在光栅化阶段。Fragment Shader接收到的是当前位置经过插值后的颜色,而不是某一个顶点的原始颜色。 ## 任务5 - 我修改了什么:保持任务2的顶点数量、坐标、顺序和颜色不变,只把`TRIANGLE_STRIP`改为`LINE_STRIP`。 - 我原先预测:顶点会依次连接成折线,不再形成填充四边形。 - 实际结果:页面显示三段依次连接的线段,没有内部填充。 - 原因解释:`LINE_STRIP`只连接相邻顶点,不会把顶点组装成三角形并填充内部区域。 ## 挑战任务:索引绘制四边形 - `drawArrays()`方案把两个三角形的顶点依次写入位置Buffer,共需要6个顶点,其中两个角点被重复存储。 - `drawElements()`方案只保存四边形的4个不同顶点,再用索引`[0,1,2, 1,3,2]`描述两个三角形,共使用6个索引。 - `ELEMENT_ARRAY_BUFFER`保存索引数据,`drawElements()`根据索引重复访问位置Buffer中的共享顶点。 - 两种方案绘制出的四边形外观相同,但索引绘制避免了重复存储共享顶点。模型越复杂、每个顶点的属性越多,节省效果越明显。