使用 i 访问纹理时 OpenGL ES 2 着色器链接失败
OpenGL ES 2 Shader linking fails when accessing texture using i
我正在尝试在我的着色器中添加对多个阴影贴图的支持,但当我尝试访问统一结构内的 sampler2D 时,它没有 linking。我的片段着色器:
#version 300 es
precision highp float;
precision highp int;
const int MAX_LIGHTS = 3;
#ifndef LIGHTINFO_STRUCT_H
#define LIGHTINFO_STRUCT_H
struct LightInfo {
sampler2D shadow_map;
vec3 reverse_light_direction;
vec4 color;
vec3 position;
float intensity;
mat4 texture_matrix;
};
#endif
in vec2 vtf_tex_coord;
in vec4 vtf_projected_tex_coords[MAX_LIGHTS];
in vec3 vtf_normal;
in vec3 vtf_frag_pos;
uniform sampler2D u_map_albedo;
uniform sampler2D u_map_normal;
uniform LightInfo u_lights[MAX_LIGHTS];
uniform int u_present_lights;
out vec4 out_color;
const vec4 AMBIENT_LIGHT = 0.1 * vec4(0.8, 0.8, 1, 1);
const float BIAS = -0.006;
float calculateLightIncidence(vec3 position, vec3 lightPosition, float intensity) {
float d = distance(position, lightPosition);
return intensity / (1.0 + d * d);
}
bool isInRange(vec2 tex_coord) {
return tex_coord.x >= 0.0 && tex_coord.x <= 1.0 && tex_coord.y >= 0.0 && tex_coord.y <= 1.0;
}
void main() {
vec3 testNormal = texture(u_map_normal, vtf_tex_coord).rgb;
vec3 normal = normalize(vtf_normal);
float fragmentDirectLight = 0.0;
float fragmentLightMultiplier = 1.0;
// calculate for all light sources
for (int i = 0; i < 3; i++) {
// if (i >= u_present_lights) break;
fragmentDirectLight += dot(normal, u_lights[i].reverse_light_direction);
// shadow map coords
vec3 projectedShadowMapCoords = vtf_projected_tex_coords[i].xyz / vtf_projected_tex_coords[i].w;
float projectedCurrentDepth = projectedShadowMapCoords.z + BIAS;
float projectedDepth = texture(u_lights[i].shadow_map, projectedShadowMapCoords.xy).r;
float projectedShadowLight = projectedCurrentDepth < projectedDepth ? 1.0 : 0.0;
float shadowMultiplier = isInRange(projectedShadowMapCoords.xy) ? clamp(projectedShadowLight, 0.3, 1.0) : 1.0;
fragmentLightMultiplier *= shadowMultiplier;
}
fragmentDirectLight = clamp(fragmentDirectLight, 0.1, 1.0);
float at = calculateLightIncidence(vtf_frag_pos, u_lights[0].position, u_lights[0].intensity);
vec4 tex_color = texture(u_map_albedo, vtf_tex_coord);
vec3 col = mix(tex_color.rgb, u_lights[0].color.rgb, at);
out_color = vec4(col * fragmentLightMultiplier * clamp(fragmentDirectLight, 0.3, 1.0), 1.0);
}
不要介意颜色的混乱,我正在努力让阴影贴图先起作用。
问题是:如果我换行
float projectedDepth = texture(u_lights[i].shadow_map, projectedShadowMapCoords.xy).r;
至
float projectedDepth = texture(u_lights[0].shadow_map, projectedShadowMapCoords.xy).r;
一切正常,link一切正常,显示正确。但是,如果我将其改回索引访问,它就不再 link。
需要说明的是,我的这部分代码报告了 link 错误:
static createProgram(gl: WebGL2RenderingContext, vertexShader: string, fragmentShader: string): WebGLProgram {
const program = gl.createProgram();
if (!program) throw `Failed to create shader program with shaders: ${vertexShader} and ${fragmentShader}`;
gl.attachShader(program, this.createShader(gl, gl.VERTEX_SHADER, vertexShader));
gl.attachShader(program, this.createShader(gl, gl.FRAGMENT_SHADER, fragmentShader));
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success)
return program;
gl.deleteProgram(program);
throw `Failed to link shader program with shaders: \n\n${vertexShader}\n\n and \n\n${fragmentShader}\n\nError: ${gl.getError()}`
}
并打印错误代码 0。
所有制服都设置正确,为什么我将其更改为访问 u_lights[i].shadow_map
却没有 link?
还有那个评论的 break 是因为我试图将 for 循环设置为执行固定次数以查看是否是问题所在,然后才 for (int i = 0; i < u_present_lights; i++)
。
我没有遇到任何编译错误,只是 link 着色器失败了。
这是我的顶点着色器以防万一:
#version 300 es
precision highp float;
precision highp int;
const int MAX_LIGHTS = 3;
#ifndef LIGHTINFO_STRUCT_H
#define LIGHTINFO_STRUCT_H
struct LightInfo {
sampler2D shadow_map;
vec3 reverse_light_direction;
vec4 color;
vec3 position;
int casts_shadows;
float intensity;
mat4 texture_matrix;
};
#endif
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;
out vec2 vtf_tex_coord;
out vec4 vtf_projected_tex_coords[MAX_LIGHTS];
out vec3 vtf_normal;
out vec3 vtf_frag_pos;
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform LightInfo u_lights[MAX_LIGHTS];
uniform int u_present_lights;
void main() {
vec4 world_pos = u_model * vec4(a_pos, 1.0);
gl_Position = u_projection * u_view * world_pos;
vtf_tex_coord = a_uv;
for (int i = 0; i < u_present_lights; i++) {
vtf_projected_tex_coords[i] = u_lights[i].texture_matrix * world_pos;
}
vtf_normal = mat3(u_model) * a_normal;
vtf_frag_pos = world_pos.xyz / world_pos.w;
}
OpenGLES 2 使用 GLSL ES 100。附录 A 第 4 节和第 5 节 here (p108) 涵盖了有关索引采样器的规则。规则强制支持 constant index expression
,这基本上意味着您可以使用 hardcoded/constant 索引、统一或简单循环。您正在使用一个简单的循环,因此您满足了该条件。
但有些事情有点奇怪。你的标题提到了 OpenGLES 2,但是你的着色器指定了 #version 300 es
,它只能在 OpenGLES 3 或更高版本上使用,所以我不太确定那里的情况。
GLSL ES 300 的规范是 here,它对索引采样器有更严格的规则。在 ES 300 中,规则仅为 constant integral expressions
。这排除了在您执行操作时使用来自简单循环的索引。引用自规范:
Indexing of arrays of samplers by constant-index-expressions is supported in GLSL ES 1.00. A constant-
index-expression is an expression formed from constant-expressions and certain loop indices, defined for
a subset of loop constructs. Should this functionality be included in GLSL ES 3.00?
RESOLUTION: No. Arrays of samplers may only be indexed by constant-integral-expressions.
您可能无法手动展开循环。
我正在尝试在我的着色器中添加对多个阴影贴图的支持,但当我尝试访问统一结构内的 sampler2D 时,它没有 linking。我的片段着色器:
#version 300 es
precision highp float;
precision highp int;
const int MAX_LIGHTS = 3;
#ifndef LIGHTINFO_STRUCT_H
#define LIGHTINFO_STRUCT_H
struct LightInfo {
sampler2D shadow_map;
vec3 reverse_light_direction;
vec4 color;
vec3 position;
float intensity;
mat4 texture_matrix;
};
#endif
in vec2 vtf_tex_coord;
in vec4 vtf_projected_tex_coords[MAX_LIGHTS];
in vec3 vtf_normal;
in vec3 vtf_frag_pos;
uniform sampler2D u_map_albedo;
uniform sampler2D u_map_normal;
uniform LightInfo u_lights[MAX_LIGHTS];
uniform int u_present_lights;
out vec4 out_color;
const vec4 AMBIENT_LIGHT = 0.1 * vec4(0.8, 0.8, 1, 1);
const float BIAS = -0.006;
float calculateLightIncidence(vec3 position, vec3 lightPosition, float intensity) {
float d = distance(position, lightPosition);
return intensity / (1.0 + d * d);
}
bool isInRange(vec2 tex_coord) {
return tex_coord.x >= 0.0 && tex_coord.x <= 1.0 && tex_coord.y >= 0.0 && tex_coord.y <= 1.0;
}
void main() {
vec3 testNormal = texture(u_map_normal, vtf_tex_coord).rgb;
vec3 normal = normalize(vtf_normal);
float fragmentDirectLight = 0.0;
float fragmentLightMultiplier = 1.0;
// calculate for all light sources
for (int i = 0; i < 3; i++) {
// if (i >= u_present_lights) break;
fragmentDirectLight += dot(normal, u_lights[i].reverse_light_direction);
// shadow map coords
vec3 projectedShadowMapCoords = vtf_projected_tex_coords[i].xyz / vtf_projected_tex_coords[i].w;
float projectedCurrentDepth = projectedShadowMapCoords.z + BIAS;
float projectedDepth = texture(u_lights[i].shadow_map, projectedShadowMapCoords.xy).r;
float projectedShadowLight = projectedCurrentDepth < projectedDepth ? 1.0 : 0.0;
float shadowMultiplier = isInRange(projectedShadowMapCoords.xy) ? clamp(projectedShadowLight, 0.3, 1.0) : 1.0;
fragmentLightMultiplier *= shadowMultiplier;
}
fragmentDirectLight = clamp(fragmentDirectLight, 0.1, 1.0);
float at = calculateLightIncidence(vtf_frag_pos, u_lights[0].position, u_lights[0].intensity);
vec4 tex_color = texture(u_map_albedo, vtf_tex_coord);
vec3 col = mix(tex_color.rgb, u_lights[0].color.rgb, at);
out_color = vec4(col * fragmentLightMultiplier * clamp(fragmentDirectLight, 0.3, 1.0), 1.0);
}
不要介意颜色的混乱,我正在努力让阴影贴图先起作用。
问题是:如果我换行
float projectedDepth = texture(u_lights[i].shadow_map, projectedShadowMapCoords.xy).r;
至
float projectedDepth = texture(u_lights[0].shadow_map, projectedShadowMapCoords.xy).r;
一切正常,link一切正常,显示正确。但是,如果我将其改回索引访问,它就不再 link。
需要说明的是,我的这部分代码报告了 link 错误:
static createProgram(gl: WebGL2RenderingContext, vertexShader: string, fragmentShader: string): WebGLProgram {
const program = gl.createProgram();
if (!program) throw `Failed to create shader program with shaders: ${vertexShader} and ${fragmentShader}`;
gl.attachShader(program, this.createShader(gl, gl.VERTEX_SHADER, vertexShader));
gl.attachShader(program, this.createShader(gl, gl.FRAGMENT_SHADER, fragmentShader));
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success)
return program;
gl.deleteProgram(program);
throw `Failed to link shader program with shaders: \n\n${vertexShader}\n\n and \n\n${fragmentShader}\n\nError: ${gl.getError()}`
}
并打印错误代码 0。
所有制服都设置正确,为什么我将其更改为访问 u_lights[i].shadow_map
却没有 link?
还有那个评论的 break 是因为我试图将 for 循环设置为执行固定次数以查看是否是问题所在,然后才 for (int i = 0; i < u_present_lights; i++)
。
我没有遇到任何编译错误,只是 link 着色器失败了。
这是我的顶点着色器以防万一:
#version 300 es
precision highp float;
precision highp int;
const int MAX_LIGHTS = 3;
#ifndef LIGHTINFO_STRUCT_H
#define LIGHTINFO_STRUCT_H
struct LightInfo {
sampler2D shadow_map;
vec3 reverse_light_direction;
vec4 color;
vec3 position;
int casts_shadows;
float intensity;
mat4 texture_matrix;
};
#endif
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;
out vec2 vtf_tex_coord;
out vec4 vtf_projected_tex_coords[MAX_LIGHTS];
out vec3 vtf_normal;
out vec3 vtf_frag_pos;
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform LightInfo u_lights[MAX_LIGHTS];
uniform int u_present_lights;
void main() {
vec4 world_pos = u_model * vec4(a_pos, 1.0);
gl_Position = u_projection * u_view * world_pos;
vtf_tex_coord = a_uv;
for (int i = 0; i < u_present_lights; i++) {
vtf_projected_tex_coords[i] = u_lights[i].texture_matrix * world_pos;
}
vtf_normal = mat3(u_model) * a_normal;
vtf_frag_pos = world_pos.xyz / world_pos.w;
}
OpenGLES 2 使用 GLSL ES 100。附录 A 第 4 节和第 5 节 here (p108) 涵盖了有关索引采样器的规则。规则强制支持 constant index expression
,这基本上意味着您可以使用 hardcoded/constant 索引、统一或简单循环。您正在使用一个简单的循环,因此您满足了该条件。
但有些事情有点奇怪。你的标题提到了 OpenGLES 2,但是你的着色器指定了 #version 300 es
,它只能在 OpenGLES 3 或更高版本上使用,所以我不太确定那里的情况。
GLSL ES 300 的规范是 here,它对索引采样器有更严格的规则。在 ES 300 中,规则仅为 constant integral expressions
。这排除了在您执行操作时使用来自简单循环的索引。引用自规范:
Indexing of arrays of samplers by constant-index-expressions is supported in GLSL ES 1.00. A constant- index-expression is an expression formed from constant-expressions and certain loop indices, defined for a subset of loop constructs. Should this functionality be included in GLSL ES 3.00?
RESOLUTION: No. Arrays of samplers may only be indexed by constant-integral-expressions.
您可能无法手动展开循环。