未定义的行为与未使用的阴影取样器

问题描述:

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

我想使用相同的着色器执行阴影照明,因为没有阴影(请参阅我的其他问题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; 
} 

我也读过你的其他问题。

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

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

沿

#if defined(USE_SHADOWS) 
sampler2D [...] 
#endif 
+0

在这一点上,对光的其他属性(漫反射和镜面反射)做同样的事情是合乎逻辑的。但是最后我得到了2 * 2 * 2不同的着色器,我不想那样做。此外,它意味着更加丑陋的C++,因为每次迭代通过灯光时都必须避免绑定不同的着色器。 – Jagoly

+0

为什么你需要不采用漫反射/镜面纹理的灯光? – RedOrav

+0

有时候为各种伪造的GI物体散射光线可能会很方便。至于镜面反射,仅仅是因为它应该没有额外的努力或时间,即使它不太可能有用。 – Jagoly

东西线运行到这个问题,并做了一些挖后,我发现,不需要你使用宏的另一种方式。所以这个想法是简单地解决警告。我创建的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),在你着色器中反射校服的过程中,看看你是否有shadowSampler2D类型(我总是用硬编码的方式将它存储到单元15中,然后查找它)。如果你确实有这种类型,并且在渲染调用期间(就在你绑定着色器之前),你仍然没有绑定单元15,绑定你的假纹理和过滤方法。

在清除其他东西之前,您还需要调用glUseProgram(0),任何带着色器的程序仍会发出警告。