HTML中WebGL着色器程序基本结构解析
初学者在接触 WebGL 着色器编程时,常被几个看似简单的规则难住。实际上,核心要求虽然不多,但每一条都是硬性规定——违反则程序要么编译失败,要么静默出错。下面我们就逐一详细解析这些关键规则。 首先需要明确基础结构:一个完整的 WebGL 着色器程序必须包含两个独立的部分——顶点着色器与片元着色器。
初学者在接触 WebGL 着色器编程时,常被几个看似简单的规则难住。实际上,核心要求虽然不多,但每一条都是硬性规定——违反则程序要么编译失败,要么静默出错。下面我们就逐一详细解析这些关键规则。

首先需要明确基础结构:一个完整的 WebGL 着色器程序必须包含两个独立的部分——顶点着色器与片元着色器。它们分别编译后,最终链接成一个 program 对象。请勿认为它们是同一文件中的两个函数,实际上这是两套独立的代码单元。
顶点着色器必须输出 gl_Position
这一条是铁律。GPU 渲染管线依赖该内置变量确定顶点在裁剪空间中的最终位置。若漏写或拼写错误(如写成 gl_Postion),gl.linkProgram() 链接步骤可能仍会成功,但在执行 gl.drawArrays() 绘制时,屏幕上将一片空白,且控制台往往没有显式报错,排查起来非常棘手。
gl_Position必须为vec4类型,第四个分量(w)通常设为1.0。若涉及透视除法,w 分量不可为 0。- 新手常犯的错误是直接赋值一个
vec3变量,例如gl_Position = aPosition;,这会导致编译失败,错误信息通常是"cannot convert from 'vec3' to 'vec4'"。 - 在 WebGL2(使用
#version 300 es)中,虽然鼓励使用自定义输出变量(如out vec4 vPosition;),但gl_Position依然是强制性的输出出口,不能省略。
片元着色器必须声明精度(precision)
这是 WebGL1(基于 GLSL ES 1.0 规范)的特殊要求,与桌面版 OpenGL 不同。片元着色器中所有浮点数相关操作必须带有精度限定符,否则编译直接失败,报错信息为 "missing precision qualifier"。
- 最常用的写法是
precision mediump float;(推荐作为默认选择)。highp精度在某些移动设备的 GPU 上可能不被支持,使用时需注意。 - 若着色器中还涉及
int或uint运算,也需加上对应的精度声明,例如precision mediump int;。 - 在 WebGL2 中,虽然仍需精度声明,但使用
#version 300 es后,通常用out vec4 fragColor;等自定义输出来替代旧的gl_FragColor内置变量。
attribute、uniform、varying 的用途不能混用
这三种变量都用于传递数据,但作用域和生命周期差异很大。用错地方会导致数据无法传入,或链接直接失败。
attribute:这是顶点着色器的“专属粮草”。数据从 JavaScript 端的缓冲区(绑定到ARRAY_BUFFER)传入,每个顶点获取一份。典型用途是传递顶点坐标aPosition、纹理坐标aTexCoord。uniform:可理解为“全局常量”。由 JavaScript 通过gl.getUniformLocation()获取位置后设置,顶点着色器和片元着色器都能读取,且在一次绘制调用中保持不变。例如传递变换矩阵uMVPMatrix。varying:这是顶点到片元之间的“信使”。在顶点着色器中写入(如计算每个顶点的颜色或光照),然后在片元着色器中读取。GPU 会自动在顶点之间进行插值,为每个片元生成平滑过渡的值。在 WebGL2 中,它被in和out配对变量取代。
最后提醒一个易被忽略的细节:着色器字符串中的换行和空格通常不影响逻辑,但 #version 指令(若使用)必须位于整个源码第一行,前面不能有任何空白字符或注释。否则 WebGL 可能静默降级到 1.0 模式,导致 layout(location = x) 等高级语法失效,而开发者浑然不知。
