将着色器迁移至OpenGL ES 3.0后程序链接失败,求解决
切换到OpenGL ES 3.0 GLSL后着色器程序链接失败问题
问题概述
切换至OpenGL ES 3.0 GLSL版本后,着色器程序无法完成链接(gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)未通过)。检查单个顶点/片段着色器编译状态均显示成功,且着色器日志为空,但获取到程序链接错误日志如下:
Shader Program compile failed:ERROR: 0:41: 'texture2D' : no matching overloaded function found ERROR: 0:41: '=' : dimension mismatch ERROR: 0:41: '=' : cannot convert from 'const mediump float' to 'highp 4-component vector of float'
相关代码
顶点着色器
#version 300 es in vec3 aVertexPosition; in vec3 aVertexNormal; in vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; uniform vec3 uAmbientColor; uniform vec3 uLightingDirection; uniform vec3 uDirectionalColor; uniform bool uUseLighting; out vec2 vTextureCoord; out vec3 vLightWeighting; // Spot uniform vec3 u_lightWorldPosition; out vec3 v_normal; out vec3 v_surfaceToLight; out vec3 v_surfaceToView; // spot-Shadow uniform mat4 u_textureMatrix; out vec2 v_texcoord; out vec4 v_projectedTexcoord; void main(void) { // SPOT v_normal = mat3(uNMatrix) * aVertexNormal; vec3 surfaceWorldPosition = (uNMatrix * aVertexPosition).xyz; v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition; v_surfaceToView = (uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0)).xyz - surfaceWorldPosition; // spot shadow // Multiply the position by the matrix. // vec4 worldPosition = u_world * a_position; vec4 worldPosition = vec4(0,0,0,0) * vec4( aVertexPosition, 1.0); v_texcoord = aTextureCoord; v_projectedTexcoord = u_textureMatrix * worldPosition; gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vTextureCoord = aTextureCoord; if (!uUseLighting) { vLightWeighting = vec3(1.0, 1.0, 1.0); } else { vec3 transformedNormal = uNMatrix * aVertexNormal; float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0); vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting; } }
片段着色器
#version 300 es precision mediump float; precision highp float; in vec2 vTextureCoord; in vec3 vLightWeighting; uniform float textureSamplerAmount[1]; int MixOperandString = 0; uniform sampler2D uSampler; uniform sampler2D uSampler1; uniform sampler2D uSampler2; uniform sampler2D uSampler3; uniform sampler2D uSampler4; uniform sampler2D uSampler5; uniform sampler2D uSampler6; uniform sampler2D uSampler7; in vec3 v_normal; in vec3 v_surfaceToLight; in vec3 v_surfaceToView; uniform vec4 u_color; uniform float u_shininess; uniform vec3 u_lightDirection; uniform float u_innerLimit; // in dot space uniform float u_outerLimit; // in dot space uniform mat4 u_projection; uniform mat4 u_view; uniform mat4 u_world; uniform mat4 u_textureMatrix; out vec4 outColor; void main(void) { vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); vec4 textureColor1 = texture2D(uSampler1, vec2(vTextureCoord.s, vTextureCoord.t)); vec4 textureColor2 = texture2D(uSampler2, vec2(vTextureCoord.s, vTextureCoord.t)); vec4 textureColor3 = texture2D(uSampler3, vec2(vTextureCoord.s, vTextureCoord.t)); vec4 textureColor4 = texture2D(uSampler4, vec2(vTextureCoord.s, vTextureCoord.t)); if (1 == 1) { outColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a); } vec3 normal = normalize(v_normal); vec3 surfaceToLightDirection = normalize(v_surfaceToLight); vec3 surfaceToViewDirection = normalize(v_surfaceToView); vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection); float dotFromDirection = dot(surfaceToLightDirection, -u_lightDirection); float limitRange = u_innerLimit - u_outerLimit; float inLight = clamp((dotFromDirection - u_outerLimit) / limitRange, 0.0, 1.0); float light = inLight * dot(normal, surfaceToLightDirection); float specular = inLight * pow(dot(normal, halfVector), u_shininess); outColor.rgb *= light; // Just add in the specular // outColor.rgb += specular; }
错误排查代码
var shaderProgram = gl.createProgram(); // console.log("Creating Shader fragment"); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); console.info('TEST ERROR => ' + gl.getShaderInfoLog(vertexShader)); console.info('TEST ERROR => ' + gl.getShaderInfoLog(fragmentShader));
编译状态检查代码及输出
var compiled = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS); console.log('Shader compiled successfully: ' + compiled); var compiled = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS); console.log('Shader fragmentShader compiled successfully: ' + compiled);
输出:
Shader compiled successfully: true app.js:810 Shader fragmentShader compiled successfully: true
问题原因
- API函数弃用:GLSL ES 3.0(
#version 300 es)中已移除texture2D()函数,统一使用通用的texture()函数替代。原代码中调用不存在的texture2D()导致找不到匹配函数,进而引发后续的维度不匹配、类型转换错误。 - 冗余精度声明:片段着色器中重复设置
precision mediump float;和precision highp float;,虽不影响链接,但易造成混淆。
解决方案
- 替换纹理采样函数:将片段着色器中所有
texture2D()调用替换为texture(),示例:vec4 textureColor = texture(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); vec4 textureColor1 = texture(uSampler1, vec2(vTextureCoord.s, vTextureCoord.t)); // 其余textureColor2至textureColor4同理修改 - 清理冗余精度声明:移除重复的精度设置,保留一个即可,例如保留
precision mediump float;(片段着色器常用中等精度)。 - 可选代码优化:顶点着色器中
vec4 worldPosition = vec4(0,0,0,0) * vec4( aVertexPosition, 1.0);计算结果恒为零向量,属于无效代码,建议根据实际需求修正或删除。
修改验证
完成上述修改后,重新编译并链接着色器程序,gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)应返回true,链接错误日志消失。
内容的提问来源于stack exchange,提问作者Nikola Lukic
相关产品推荐
相关产品推荐

