2015-04-22 1 views
0

У меня есть шейдер, который выполняет пропуска освещения в отложенном рендерере. Он принимает униформы для различных дополнительных функций, один из которых - тени.Неопределенное поведение с неиспользуемыми пробоотборниками тени

Я хочу использовать тот же шейдер для выполнения освещения с тенями, как и без (см. Мой другой вопрос here). Это отлично работает.

Однако возникает проблема, когда я визуализирую свет без теней и, как таковой, не привязываю текстуру к теневому сэмплеру, оставляя некоторую другую связанную текстуру. На моей системе, запуск драйверов NVIDIA 346.59, это приводит к следующей ошибке GL/предупреждение:

Программа предупреждения неопределенное поведение: Sampler объект 0 обязан без глубины текстуры 0, но она используется с программой, использует теневой пробоотборник. Это неопределенное поведение.

Хотя я знаю, что сэмплер не будет использоваться, если это так.

Есть ли способ обойти это? Кажется излишним связать какую-то неиспользуемую текстуру заполнителя, чтобы подавить это предупреждение.

EDIT: Обратите внимание, что это действительно работает. Единственная проблема - это предупреждение, которое выталкивает водитель.

EDIT: Хорошо, вот мой шейдер. Часть, относящаяся к этому вопросу, является основной() функцией.

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

ответ

1

Я также прочитал ваш другой вопрос.

Что бы вы обычно делали, это скомпилировать шейдер со всеми необходимыми/использованными пробоотборниками и не выставлять неиспользуемые пробоотборники. Это может привести к ошибкам.

Я знаю, что вам не нравится этот подход, но делайте это с помощью ifdefs и создавайте разные версии вашего шейдера для учета теневых/носовых ламп. Вы можете кэшировать их самостоятельно и переключать их во время выполнения в CPU. Лучше делать ветвление в CPU, чем в GPU; имейте в виду, что вы сделаете это только один раз для объекта, тогда как в GPU вы сделаете это один раз для каждого пикселя, что очень расточительно.

Что-то вдоль линий

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

В этот момент было бы логично сделать то же самое для других свойств света, а именно диффузных и зеркальных. Но потом я получаю 2 * 2 * 2 разных шейдера, и я не хочу этого делать. Кроме того, это означает гораздо более уродливый C++, так как я должен избегать связывания разных шейдеров каждый раз, когда итерация происходит по огню. – Jagoly

+0

Зачем вам нужны огни, которые не воспринимают рассеянные/зеркальные текстуры? – RedOrav

+0

Иногда бывает удобно иметь рассеянные только огни для различных фальшивых материалов GI. Что касается только зеркальной, просто потому, что это должно быть нулевое дополнительное усилие или время, даже если это вряд ли будет полезно. – Jagoly

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), во время вашего отражения мундиров в вашем шейдере, посмотрите, есть ли у вас тип shadowSampler2D (я всегда всегда жестко закодировал мою часть 15, и я искал это). Если у вас есть этот тип и во время вызова рендеринга (прямо перед тем, как вы привязываете шейдер), у вас все еще нет привязанного блока 15, привяжите свою поддельную текстуру вместе с методами фильтрации.

Также вам нужно вызвать glUseProgram (0), прежде чем вы очистите что-либо еще, любая программа с этим шейдером все равно выдает предупреждение.

Смежные вопросы