簡體   English   中英

OpenGL ES 2 使用 i 訪問紋理時,着色器鏈接失敗

[英]OpenGL ES 2 Shader linking fails when accessing texture using i

我正在嘗試在我的着色器中添加對多個陰影貼圖的支持,當我嘗試訪問統一結構中的 sampler2D 時,它只是沒有鏈接。 我的片段着色器:

#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;

它可以正常工作,所有內容都鏈接並正確顯示。 但是如果我把它改回索引訪問,它就不再鏈接了。

為了清楚起見,我的這部分代碼中報告了鏈接錯誤:

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 ,為什么它沒有鏈接?

另外,評論中斷是因為我嘗試將 for 循環設置為執行固定次數以查看是否是問題所在,然后才for (int i = 0; i < u_present_lights; i++)

我沒有收到編譯錯誤,只是無法鏈接着色器。

這是我的頂點着色器以防萬一:

#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 節 (p108)介紹了有關索引采樣器的規則。 規則要求支持constant index expression ,這基本上意味着您可以使用硬編碼/常量索引、統一或簡單循環。 您正在使用一個簡單的循環,因此您滿足該條件。

但有一點奇怪。 您的標題提到了 OpenGLES 2,但您的着色器指定了#version 300 es ,它只能在 OpenGLES 3 或更高版本上使用,所以我不太確定那里的情況。

GLSL ES 300 的規范在這里,它對索引采樣器有更嚴格的規則。 在 ES 300 中,規則只是constant integral expressions 這排除了使用簡單循環中的索引的可能性。 引用規范:

GLSL ES 1.00 支持通過常量索引表達式對采樣器的 arrays 進行索引。 常量索引表達式是由常量表達式和某些循環索引形成的表達式,為循環結構的子集定義。 這個功能應該包含在 GLSL ES 3.00 中嗎?

解決方案:編號 Arrays 的采樣器只能由常量積分表達式索引。

您可能無法手動展開循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM