能跑的GLSL着色器核心三点:版本声明匹配上下文(如WebGL1用#version 100)、in/out变量名与类型严格配对、gl_Position和gl_FragColor(或modern版out vec4 frag_color)必须存在且赋值;纹理坐标需顶点着色器读入attribute再out传递,片段着色器in接收并texture采样,注意精度声明和Y轴翻转。

直接写能跑的 GLSL 着色器,核心就三点:版本声明必须对、输入输出语义要配对、gl_Position 和 gl_FragColor(或现代版 frag_color)不能漏。其他全是围绕这三点展开的细节。
顶点着色器里怎么传纹理坐标给片段着色器
顶点着色器负责把纹理坐标从 attribute 读进来,再通过 out 变量传出去;片段着色器用 in 接收,中间经过光栅化插值。常见错误是类型不一致或变量名没对上。
-
out变量在顶点着色器中必须显式声明,比如out vec2 vTexCoord; - 对应片段着色器里得写
in vec2 vTexCoord;,名字和类型必须完全一致 - WebGL 或 OpenGL 3.3+ 中,
attribute和varying已废弃,只用in/out配对 - 纹理坐标的 Y 轴常需翻转:
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);,否则贴图上下颠倒
片段着色器里怎么正确采样纹理
采样前要确保 sampler2D uniform 已绑定、纹理单元已激活、texture 函数参数类型匹配。最容易被忽略的是精度声明和采样坐标范围。
- 必须加精度限定符,WebGL 必须写
precision mediump float;,否则编译失败 -
uniform sampler2D uTexture;声明后,在 JS 中要用gl.uniform1i(gl.getUniformLocation(prog, "uTexture"), 0);指定纹理单元 -
texture(uTexture, vTexCoord)的第二个参数必须是vec2,传vec3或标量会报错 - 如果
vTexCoord超出 [0,1] 范围且没设好 wrap mode,可能显示黑块或重复拉伸
#version 写多少才不会报错
不是越高越好,必须和你的 OpenGL / WebGL 上下文版本严格匹配。错配会导致编译器直接拒绝,连错误详情都不给。
- WebGL 1 对应
#version 100(ES 版本),用attribute/varying,无 layout - WebGL 2 或 OpenGL 3.3+ 推荐
#version 330 core,用in/out,支持layout(location = N) - OpenGL 4.6 开发可选
#version 460 core,但驱动支持度参差,调试工具如 RenderDoc 对它更友好 - 写了
#version 460却用 OpenGL 4.5 上下文创建 context,着色器根本不会编译——不是警告,是静默失败
为什么 gl_FragColor 改成 frag_color 就不亮了
这是 GLSL 版本升级带来的输出变量变更。旧版隐式提供 gl_FragColor,新版要求你显式声明 out 变量并赋值,否则 GPU 不知道往哪写颜色。
-
#version 100或120:直接写gl_FragColor = vec4(1.0); -
#version 330及以上:必须声明out vec4 frag_color;,然后写frag_color = vec4(1.0); - 漏掉
out声明、拼错变量名、或忘记赋值,都会导致黑屏——没有默认输出,GPU 不会猜 - 多个输出(如 MRT)时,
layout(location = 0)等修饰符必须明确,否则顺序不确定
真正卡住人的往往不是语法本身,而是上下文版本、API 绑定顺序、精度声明这三者之间的隐性耦合。写完着色器别急着调逻辑,先确认 gl.getShaderInfoLog 和 gl.getProgramInfoLog 有没有隐藏的编译/链接失败信息——很多“不生效”其实是停在了第一步。

















