光照与纹理贴图必须协同设计:光照依赖法线、光源和材质参数,纹理依赖UV坐标、采样器及纹理单元绑定;单独启用任一者均无法实现真实渲染效果。

光照和纹理贴图在 OpenGL 中不是“开关式”功能,而是必须协同设计的两套数据流:光照依赖法线、光源、材质参数;纹理依赖 UV 坐标、采样器、纹理单元绑定。单独启用任一者都得不到真实效果——比如只加纹理不改光照计算,material.diffuse 还是常量,纹理颜色根本进不到漫反射项里。
glGenTextures 和 glBindTexture 必须配对使用,且绑定后才能配置参数
常见错误是调用 glGenTextures 得到 textureID 后,直接调用 glTexImage2D 却没先 glBindTexture(GL_TEXTURE_2D, textureID)。GPU 会静默失败,后续 texture() 采样返回黑色或未定义值。
-
glGenTextures只生成 ID,不分配显存,也不激活任何目标 - 必须
glBindTexture(GL_TEXTURE_2D, textureID)才能对这个 ID 设置glTexParameter或上传图像 - 同一时刻只能有一个
GL_TEXTURE_2D绑定生效;多纹理需切换绑定 + 在着色器中用不同sampler2Duniform
纹理坐标必须从顶点着色器传入,不能在片段着色器里硬编码
很多初学者在片段着色器里写 vec2 uv = vec2(0.5); 试图“统一采样中心点”,结果整个物体只显示纹理左上角一个像素。UV 必须作为顶点属性(layout location = 2)传入,由顶点着色器输出,经光栅化插值得到每个片段的正确位置。
- 顶点数据里每顶点要带 2D
TexCoords,和位置、法线一样是独立 attribute - 顶点着色器必须声明
in vec2 aTexCoords并out vec2 TexCoords - 片段着色器用
in vec2 TexCoords接收插值后的坐标,再喂给texture(material.diffuse, TexCoords)
光照计算中用纹理替代材质常量时,ambient/diffuse 必须乘以采样结果
如果保留原始 struct Material { vec3 ambient; vec3 diffuse; ... };,但把 material.diffuse 改成 sampler2D,却不改光照公式,漫反射项就还是常量——纹理信息完全被忽略。
- 正确做法:把
material.diffuse换成sampler2D diffuseMap,并在片段着色器里写:vec3 sampledDiffuse = texture(material.diffuseMap, TexCoords).rgb;vec3 diffuse = light.diffuse * max(dot(normal, lightDir), 0.0) * sampledDiffuse; - ambient 项同理,否则暗部全黑,失去环境光基础亮度
- 注意:纹理 RGB 通常是非线性的(sRGB),若启用
GL_SRGB8_ALPHA8格式,OpenGL 会自动做 gamma 校正;否则需手动 pow(color, vec3(2.2)),否则光照计算失真
最容易被跳过的点是法线向量——它不参与纹理采样,但决定光照方向与表面夹角。如果模型用了法线贴图,就必须在切线空间做光照计算,而普通漫反射贴图不需要。混用这两者却不转换空间,结果就是光影“浮”在表面之上,不随视角变化。

















