未定义的行为与未使用的阴影取样器
我有一个着色器在延迟渲染器中执行光照传递。它需要各种可选功能的制服,其中一个是阴影。未定义的行为与未使用的阴影取样器
我想使用相同的着色器执行阴影照明,因为没有阴影(请参阅我的其他问题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
东西线运行到这个问题,并做了一些挖后,我发现,不需要你使用宏的另一种方式。所以这个想法是简单地解决警告。我创建的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),任何带着色器的程序仍会发出警告。
在这一点上,对光的其他属性(漫反射和镜面反射)做同样的事情是合乎逻辑的。但是最后我得到了2 * 2 * 2不同的着色器,我不想那样做。此外,它意味着更加丑陋的C++,因为每次迭代通过灯光时都必须避免绑定不同的着色器。 – Jagoly
为什么你需要不采用漫反射/镜面纹理的灯光? – RedOrav
有时候为各种伪造的GI物体散射光线可能会很方便。至于镜面反射,仅仅是因为它应该没有额外的努力或时间,即使它不太可能有用。 – Jagoly