AI 协作日志
学生 Web 实验作品平台
学号:202312211503020 · 来源:ai-log.md
# 实验一 AI协作记录 > 请记录本人真实的AI协作过程。不要只粘贴AI生成结果,应体现自己的判断、测试和核验。 ## AI协作1:理解数据流 ### 我的目标 弄清从 JavaScript 的 Float32Array 顶点数据,到屏幕上出现一个三角形的完整数据流,重点理解 Buffer、vertexAttribPointer、Vertex Shader、光栅化、Fragment Shader 各自负责什么,并能在 task1.html 和 js/task1.js 里逐项找到对应代码。 ### 提示词 从 JavaScript 的 Float32Array 到屏幕上出现一个三角形,中间发生了哪些关键步骤?请结合 WebGL2 解释 Buffer、vertexAttribPointer、Vertex Shader、光栅化和 Fragment Shader 各自负责什么,不要直接修改我的代码。 ### AI关键回答摘要 AI 给出的关键步骤大致如下: 1、JavaScript 侧组织顶点数据:用 Float32Array 在 CPU 内存中存放顶点坐标。 2、创建并绑定 Buffer:gl.createBuffer() 申请 GPU Buffer,gl.bindBuffer() 把它设为当前 ARRAY_BUFFER。 3、上传数据到 GPU:gl.bufferData() 把 CPU 端数据拷贝到 GPU 显存。 4、建立顶点属性与 Buffer 的联系:gl.vertexAttribPointer() 描述“GPU 按什么规则从 Buffer 中读数据”,gl.enableVertexAttribArray() 真正启用该属性。 5、Vertex Shader 逐顶点执行:读取 in vPosition,计算并写入 gl_Position。 6、图元组装 + 光栅化:gl.drawArrays(gl.TRIANGLES, 0, 3) 触发图元组装和光栅化,把三角形切成像素,并对顶点属性做插值。 7、Fragment Shader 逐像素执行:计算每个像素的颜色,写入自定义输出变量 fColor。 8、写入 Canvas 像素:最终结果出现在 Canvas 上。 ### 我的判断 AI 的描述与课程中“JavaScript 顶点数据 → TypedArray → GPU Buffer → 顶点属性 → Vertex Shader → 图元组装 → 光栅化 → Fragment Shader → Canvas 像素”的数据流一致。 但仅凭一段解释还不能完全确认,因为其中有些说法比较笼统,例如: “建立联系”具体对应哪几行代码? 光栅化没有显式代码,它到底在什么时机发生? Vertex Shader 和 Fragment Shader 分别执行多少次? 这些都需要逐条到代码里核验。 ### 验证方法 在 task1.html 和 js/task1.js 中逐项查找 AI 所说步骤的对应代码,形成一一对应 核验方式: 1、把 js/task1.js 从上到下逐行读一遍,确认每个关键调用都在; 2、对照 task1.html 中的 Vertex Shader 和 Fragment Shader,确认 AI 说的“逐顶点/逐像素”确实对应两个 Shader; 3、故意把 gl.drawArrays(gl.TRIANGLES, 0, 3) 的 3 改成 1,看画面是否消失;改回 3 后恢复,从而确认光栅化确实由 drawArrays 触发。 ### 验证结果 表中的每一项都能在 task1.html 或 js/task1.js 中找到对应代码; 把 drawArrays 的最后一个参数由 3 改为 1 后,Canvas 上没有三角形; 改回 3 后三角形重新出现; 说明“绘制由 drawArrays 触发、并把顶点组合成三角形”这一说法与代码行为一致; AI 描述的步骤顺序与代码执行顺序一致。 ### 修正后的结论 我原先理解不清的是 gl.vertexAttribPointer 的作用,一度以为它只是“告诉 GPU 用哪个变量”,核验代码后修正为: gl.vertexAttribPointer 本质上是在描述 Buffer 中顶点数据的内存布局,即“GPU 应该如何从连续内存中切分出一个个顶点属性”。它同时指定了: 属性位置(vPosition 的 location); 每个顶点读几个分量(这里的 2); 分量类型(gl.FLOAT); 是否归一化(false); 步长(0 表示紧密排列); 起始偏移(0)。 enableVertexAttribArray 才是“真正启用”该属性的调用。 同时进一步确认: gl.bufferData 是把 CPU 端数据拷贝到 GPU 显存的动作,JS 端数组后续再改不会自动同步到 GPU; 光栅化没有显式 JavaScript 调用,是 gl.drawArrays 触发的内部阶段; Vertex Shader 每个顶点执行一次,Fragment Shader 每个像素执行一次。 --- ## AI协作2:程序调试 ### 现象 在完成 js/task3.js 后,左侧红色三角形显示正常,但右侧四边形没有完整显示——只画出了一个小三角形,看起来像“半个四边形”,颜色还是红色,和三角形同色。 ### 我的初步判断 我怀疑问题出在四边形那一段绘制代码里,可能是: gl.drawArrays() 的顶点数量参数写错了; 或者第二次 gl.uniform4f() 忘了写,导致颜色没变; 也可能是 TRIANGLE_STRIP 的顶点顺序不对,导致拼不出完整四边形 ### 给AI的提示词 下面是一段 WebGL2 代码。第一个图形(三角形)正常,第二个图形(四边形)只画出了半个,而且颜色和第一个图形相同。请不要重写完整程序,只列出最可能的3个原因,并告诉我应该通过什么现象、Console 信息或代码检查逐一验证。 ### AI给出的关键建议 AI 给出 3 个最可能的原因: gl.drawArrays() 最后一个参数写错:四边形有 4 个顶点,如果写成 3,只会画出前 3 个顶点组成的 1 个三角形,表现为“半个四边形”。 第二次 gl.uniform4f() 没写或写在了 drawArrays 之后:uniform 是状态,不重新设置就会沿用上一次的颜色。 第二次 gl.vertexAttribPointer() 遗漏或参数错:换了 Buffer 后没重设读取方式,会按旧 Buffer 的布局读取,导致图形错乱。 验证方式: 检查第二段 gl.drawArrays 的第三个参数是否是 4; 检查第二次 gl.uniform4f 是否位于四边形 drawArrays 之前; 检查第二段 gl.bindBuffer 之后是否紧接着调用了 gl.vertexAttribPointer。 ### 我实际进行的测试 按 AI 的建议逐条核验,我先做了第一个最明显的测试: 1、把四边形那一句: gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3); 临时改成: gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 2、同时确认四边形 drawArrays 前面有: gl.uniform4f(uColor, 0.20, 0.40, 0.85, 1.0); 3、再刷新页面观察结果 ### 测试结果 把 3 改成 4 后,四边形完整显示; 颜色也变成了蓝色(因为 uniform4f 已正确写在了四边形绘制之前); Console 无红色报错。 ### 最终原因 根因是第二个 gl.drawArrays() 的顶点数量参数写成了 3,而四边形有 4 个顶点,所以只画出前三个顶点组成的一个三角形,表现为“只画了半个”。颜色问题其实是核对过程中一并检查后确认早已正确,真正需要修改的只有顶点数量。 ### 是否采纳AI建议及理由 采纳。理由: AI 给出的 3 条原因中,第 1 条“顶点数量写错”直接命中了我的实际错误; 它没有直接重写我的代码,而是给出了可验证的排查方向; 我按照它建议的顺序逐条检查,并通过“改 3 为 4 → 刷新 → 观察”的对照实验完成了验证; 最终我亲手确认了错误位置并修正,符合实验要求的“运行 → 观察 → 判断 → 验证”闭环。 --- ## AI协作3:顶点属性与颜色 ### 我的目标 理解 gl.vertexAttribPointer 的参数究竟怎样决定 GPU 从 Buffer 中读取数据的方式,特别是为什么位置属性每顶点读 2 个 float、颜色属性每顶点读 4 个 float,并通过一个对照实验验证自己对这两个属性区别的理解。 ### 提示词 在 WebGL2 中,位置属性 vPosition 每个顶点提供2个 float,而颜色属性 vColor 每个顶点提供4个 float。请从“GPU怎样按 vertexAttribPointer 的参数读取 Buffer 中连续数据”的角度解释两个属性的区别,不要只列参数定义。 ### AI关键回答摘要 AI 的回答可以概括为: gl.vertexAttribPointer(location, size, type, normalized, stride, offset) 中的关键参数是: size:每个顶点从 Buffer 中读几个分量; type:每个分量的类型(这里是 gl.FLOAT,4 字节); stride:两个相邻顶点之间的字节间隔(0 表示紧密排列); offset:从 Buffer 起始到第一个顶点数据的字节偏移。 当 stride = 0 时,GPU 会按 size × sizeof(type) 自动算出步长,从而把连续内存切成一个个顶点属性; 对位置来说,size = 2,每顶点占 8 字节,所以 Buffer 被切成 (x, y); 对颜色来说,size = 4,每顶点占 16 字节,所以 Buffer 被切成 (r, g, b, a); 两个属性虽然都来自不同 Buffer,但各自按自己的 size 独立解析,互相不影响; Shader 中 in vec4 vColor; 需要 4 个分量,所以 size 必须是 4;如果只写 3,就会与 Shader 期望的 4 个分量不匹配。 ### 对照实验 在 js/task4.js 中,把颜色 Buffer 的属性设置: gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0);、 中的 4 临时改为 3,即: gl.vertexAttribPointer(vColor, 3, gl.FLOAT, false, 0, 0); 其它代码不变,刷新页面观察,然后再改回 4。 ### 实际现象 改成 3 后,三角形颜色显示不正常: 颜色发生错位,出现明显的异常色块; 三角形内部不再是平滑的红→绿→蓝渐变; Console 中可能不会报错,但画面明显错误。 改回 4 后,恢复正常的红、绿、蓝渐变。 ### 我的解释 size = 3 时,GPU 认为每个顶点只占 12 字节(3 个 float),但实际上 Buffer 中每个顶点是 16 字节(4 个 float,含 A); 于是 GPU 会把顶点 1 的 B 当成顶点 2 的 R、顶点 1 的 A 当成顶点 2 的 G,数据整体错位; 顶点 3 的读取也会越界,取到不属于它的数据; 最终结果是颜色错乱,而不是简单的“只剩 RGB 没 A”; 改回 4 后,步长重新按 16 字节切分,每个顶点正好读到自己的 RGBA,颜色恢复正常。 这说明 AI 关于“size 决定每顶点读几个分量、stride = 0 时按 size × sizeof(type) 自动切分”的解释是对的,能够对应我观察到的现象。 ### 最终结论 gl.vertexAttribPointer 的参数不是“随便填”的,它精确描述了 GPU 该如何从连续内存中切出一个个顶点属性;位置的 size = 2 和颜色的 size = 4 分别对应 Shader 中 in vec4 vPosition 和 in vec4 vColor 的实际需要,任何一处不匹配都会造成读取错位。我之前以为 size 只是“填几个都行、GPU 会自己补齐”,经过对照实验后修正为:size 必须与 Shader 中该属性期望的分量数一致,否则数据读取就会错位,A 分量并不会被自动补上。 实验 1:gl.LINE_STRIP 我修改了什么:把 draw mode 从 gl.TRIANGLE_STRIP 改成 gl.LINE_STRIP。 我原先预测:不会出现填充四边形,而是沿着顶点顺序连出一条折线;因为 LINE_STRIP 是把相邻顶点依次连线,所以不会闭合,也不会填充。 实际结果:Canvas 上出现一条折线,依次连接“左上 → 左下 → 右上 → 右下”,首尾不相连,图形内部没有被填充。 原因解释:LINE_STRIP 把顶点序列解释为一串线段,连接 (v0,v1)、(v1,v2)、(v2,v3),因此不闭合,也不做三角形填充。 实验 2:gl.POINTS 我修改了什么:把 draw mode 改成 gl.POINTS。 我原先预测:只会看到 4 个孤立的小点,分别对应 4 个顶点,没有任何连线或填充。 实际结果:Canvas 上只出现了 4 个离散的小点,位置正好对应 4 个顶点;点与点之间没有线,也没有面。 原因解释:POINTS 把每个顶点单独解释为一个点图元,不进行任何连接或填充 实验 3:gl.LINE_LOOP 我修改了什么:把 draw mode 改成 gl.LINE_LOOP。 我原先预测:与 LINE_STRIP 类似是折线,但会首尾相连,形成一个闭合四边形轮廓;仍然不会填充。 实际结果:Canvas 上出现一个闭合的四边形轮廓,首尾相连,内部没有被填充。 原因解释:LINE_LOOP 与 LINE_STRIP 相似,但会在最后一个顶点和第一个顶点之间再连一条线段,因此图形是闭合的。 实验 4:gl.TRIANGLES 我修改了什么:把 draw mode 改成 gl.TRIANGLES。 我原先预测:4 个顶点按每 3 个一组解释成三角形,第 4 个顶点会被忽略,因此只会看到 1 个三角形。 实际结果:Canvas 上只出现 1 个三角形,由前 3 个顶点 (v0,v1,v2) 组成,第 4 个顶点没有参与绘制。 原因解释:TRIANGLES 把顶点序列按每 3 个一组解释为三角形,多余的顶点被忽略;因此 4 个顶点只能画出 1 个完整三角形。 实验 5:gl.TRIANGLE_STRIP(任务2 使用的模式) 我修改了什么:把 draw mode 改回 gl.TRIANGLE_STRIP。 我原先预测:4 个顶点会组成 2 个相邻的三角形,从而拼成一个完整的填充四边形,与任务2结果一致。 实际结果:Canvas 上重新出现一个完整的填充四边形,颜色与任务2一致。 原因解释:TRIANGLE_STRIP 把相邻顶点两两组合,依次构成 (v0,v1,v2)、(v1,v2,v3) 两个三角形,它们共享一条边,拼成一个四边形