使用未使用的影子采样器的未定义行为

时间:2015-04-22 14:44:28

标签: opengl glsl shader

我有一个在延迟渲染器中执行光照传递的着色器。它需要各种可选功能的制服,其中一个是阴影。

我想使用相同的着色器来执行带有阴影的光照(请参阅我的其他问题here)。这很有效。

然而,当我渲染没有阴影的光时会出现问题,因此不要将任何纹理绑定到阴影采样器,而是保留一些其他纹理。在我的系统上运行NVIDIA 346.59驱动程序时,会产生以下GL错误/警告:

  

编程未定义的行为警告:采样器对象0绑定到非深度纹理0,但它与使用阴影采样器的程序一起使用。这是未定义的行为。

即使我知道在这种情况下也不会使用采样器。

有没有办法解决这个问题?似乎没有必要绑定一些未使用的占位符纹理只是为了抑制此警告。

编辑:请注意,这确实有效。唯一的问题是司机吐出的警告。

编辑:好的,这是我的着色器。与此问题相关的部分是main()函数。

#version 330
#extension GL_ARB_shading_language_420pack : enable

#include "headers/blocks/camera"
#include "headers/blocks/spotlight"
#include "headers/uniform_disks"
#include "headers/shadow/sample_spot"

in vec2 texcrd;

layout(std140, binding=0) uniform CAMERABLOCK { CameraBlock CB; };
layout(std140, binding=1) uniform SPOTLIGHTBLOCK { SpotLightBlock LB; };

uniform int mode;
uniform int shadQuality;
uniform int shadFilter;
layout(binding=0) uniform sampler2D texDiff;
layout(binding=1) uniform sampler2D texNorm;
layout(binding=2) uniform sampler2D texSurf;
layout(binding=3) uniform sampler2D texSpec;
layout(binding=4) uniform sampler2D texAmbi;
layout(binding=5) uniform sampler2D texDepth;
layout(binding=6) uniform sampler2DShadow texShad;

out vec3 fragColour;


vec3 get_view_pos(in vec2 _tc) {
    float dep = texture(texDepth, _tc).r * 2.f - 1.f;
    vec4 p_pos = vec4(_tc * 2.f - 1.f, dep, 1.f);
    vec4 v_pos = CB.invProj * p_pos;
    return v_pos.xyz / v_pos.w;
}

float get_shadow_value(vec3 _wpos, vec3 _wsurf) {
    vec3 normPos = _wpos + _wsurf*0.04f;
    vec4 sc = LB.matrix * vec4(normPos, 1.f);
    vec3 shadcrd = sc.xyz / sc.w * 0.5f + 0.5f;

    float bias = get_bias(_wsurf, normalize(normPos - LB.position));
    if (shadFilter < 2) return sample_shadow(shadcrd, bias, texShad);
    else {
        if (shadQuality == 0) return sample_shadow_x4(shadcrd, bias, texShad);
        if (shadQuality == 1) return sample_shadow_x8(shadcrd, bias, texShad);
        if (shadQuality == 2) return sample_shadow_x16(shadcrd, bias, texShad);
    }
}

vec3 get_diffuse_value(vec3 _lightDir, vec3 _normal) {
    vec3 txDiff = texture(texDiff, texcrd).rgb;
    float dotProd = max(dot(-_lightDir, _normal), 0.f);
    return LB.colour * txDiff * dotProd;
}

vec3 get_specular_value(vec3 _lightDir, vec3 _normal, vec3 _position) {
    vec3 txSpec = texture(texSpec, texcrd).rgb;
    vec3 reflection = reflect(_lightDir, _normal);
    vec3 dirFromCam = normalize(-_position);
    float factor = pow(max(dot(dirFromCam, reflection), 0.f), 50.f);
    return LB.colour * txSpec * factor;
}

void main() {
    vec3 v_pos = get_view_pos(texcrd);
    vec3 v_norm = normalize(texture(texNorm, texcrd).rgb * 2.f - 1.f);
    vec3 lightDir = normalize(v_pos - vec3(CB.view * vec4(LB.position, 1.f)));
    if (dot(-lightDir, v_norm) < -0.25f) discard;

    vec4 wp = CB.invView * vec4(v_pos, 1.f);
    vec3 w_pos = wp.xyz / wp.w;
    vec3 v_surf = normalize(texture(texSurf, texcrd).rgb * 2.f - 1.f);
    vec3 w_surf = normalize(vec3(CB.trnView * vec4(v_surf, 0.f)));

    vec3 spotDir = normalize(vec3(CB.view * vec4(LB.direction, 0.f)));
    float spotDist = distance(LB.position, w_pos);
    float angle = acos(dot(lightDir, spotDir));
    if (angle > LB.angle || spotDist > LB.intensity) discard;

    bool doShad = bool(mode & 1);
    bool doDiff = bool(mode & 2);
    bool doSpec = bool(mode & 4);

    float shad = 1.f;
    if (doShad) shad = get_shadow_value(w_pos, w_surf);
    if (shad == 0.f) discard;

    vec3 diff = vec3(0.f, 0.f, 0.f);
    if (doDiff) diff = get_diffuse_value(lightDir, v_norm);

    vec3 spec = vec3(0.f, 0.f, 0.f);
    if (doSpec) spec = get_specular_value(lightDir, v_norm, v_pos);

    float fovRolf = pow((LB.angle - angle) / (1.f - LB.angle), sqrt(LB.softness));
    float dstRolf = 1.f - spotDist / LB.intensity;
    float rolloff = fovRolf * dstRolf;

    fragColour = (diff + spec) * shad * rolloff;
}

2 个答案:

答案 0 :(得分:1)

我也读过你的其他问题。

您通常会使用所有必需/使用的采样器编译着色器,而不会暴露任何未使用的采样器。这样做可能会给你错误。

我知道你不喜欢这种方法,但是使用ifdef并创建不同版本的着色器以考虑阴影/阴影灯。您可以自己缓存它们并在CPU中在运行时切换它们。在CPU中进行分支比在GPU中进行分支更好;请记住,对于对象,您只会执行一次此操作,而在GPU中,您将为每个像素执行一次,这非常浪费。

的内容
#if defined(USE_SHADOWS)
sampler2D [...]
#endif

答案 1 :(得分:0)

在遇到这个问题并进行了一些挖掘之后,我发现了另一种不需要你使用宏的方法。因此,我们的想法是简单地解决警告问题。我创建了1x1和GL_DEPTHCOMPONENT16类型的伪纹理,并将过滤模式设置为:

glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, supportsMipMaps && getTextureInfo().mMipCount > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(mTextureTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(mTextureTarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

如果你想优化它,你可以做的是你的ShaderObject类(或代表GLShader的w / e对象),在你的着色器中反映制服时,看看你是否有shadowSampler2D类型(I我总是硬编码到15号机组,我一直在寻找它。如果您确实拥有该类型并且在渲染调用期间(在绑定着色器之前),您仍然没有绑定单元15,将伪造的纹理与过滤方法绑定在一起。

此外,您需要在清除其他任何程序之前调用glUseProgram(0)仍然会发出警告。