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得到的是顶点原始颜色还是插值后的颜色? > 插值发生在**光栅化阶段**;片元着色器拿到的是插值之后的颜色,不是原始顶点颜色。