Выборка из текстуры глубины всегда дает 0

Я пытаюсь реализовать отображение теней с помощью opengl, используя направленный свет.

Я подтвердил, что текстура глубины отображается правильно, например: текстура глубины

А для визуального осмотра я также вывожу координаты мирового пространства, преобразованные в световую перспективу:

координаты тени

Что опять же, кажется, в порядке.

Однако, когда я сэмплирую текстуру глубины, используя:

vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
float depth = texture( shadowMap, coord);

Я считаю, что сравнение всегда терпит неудачу. Если я изменю uniform sampler2DShadow shadowMap; на uniform sampler2D shadowMap; и сэмплирую текстуру напрямую, используя texture( shadowMap, coord.xy).r, я обнаружу, что семплированное значение всегда равно нулю, выводя этот результат на экран.

Я создал текстуру глубины следующим образом:

glGenTextures(1, &m_DepthTexture);
glBindTexture(GL_TEXTURE_2D, m_DepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthTexture, 0);

и мой код шейдера выглядит следующим образом (вершина):

#version 430
// Some drivers require the following
precision highp float;
layout (location = 0)in vec3 MSVertex;
layout (location = 4)in vec2 MSTexCoord;

out xferBlock
{
    vec3 VSVertex;
    vec2 VSTexCoord;
} outdata;

void main()
{
    outdata.VSVertex = MSVertex;
    outdata.VSTexCoord = MSTexCoord;
    gl_Position = vec4(MSVertex,1.0);
}

и фрагментный шейдер:

#version 430 core
// Some drivers require the following
precision highp float;

layout (location = 0) uniform sampler2D positionMap;
layout (location = 1) uniform sampler2D normalMap;
layout (location = 2) uniform sampler2D colourMap;
layout (location = 3) uniform sampler2D specularMap;
layout (location = 4) uniform sampler2DShadow shadowMap;

struct DirLightData
{
    vec4 colour;
    float intensity;
    vec4 direction;
};
uniform mat4 ShadowTransform;
uniform DirLightData dirLight;
out vec4 colour;
uniform vec3 WSCamPos;
in xferBlock
{
    vec3 VSVertex;
    vec2 VSTexCoord;
} indata;

vec3 computeLight(vec3 Ldirection, vec3 Vdirection, vec3 Lcolour, vec3 normal, float Lintensity, float specular)
{
    vec3 diffCol = Lcolour * max(0.0,dot(normalize(normal),-Ldirection));
    vec3 reflectVec = normalize(reflect(Ldirection,normal));
    float specFactor = max(dot(reflectVec,Vdirection),0);
    float specPow = pow(specFactor,specular*255.0);
    vec3 specCol = Lcolour * specPow;
    return (diffCol+specCol)*Lintensity;;
}
float computeOcclusion(vec4 shadowCoords)
{
    float vis = 1.0;
    vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
    float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.05));
    if (  depth < coord.z);
    {
        vis = 0.5;
    }
    return vis;
}
void main()
{
    vec4 pcolour = texture(positionMap, indata.VSTexCoord).rgba;
    vec4 ncolour = texture(normalMap, indata.VSTexCoord).rgba;
    vec4 dcolour = texture(colourMap, indata.VSTexCoord).rgba;
    vec4 scolour = texture(specularMap, indata.VSTexCoord).rgba;

    vec4 shadowCoord = ShadowTransform * pcolour;
    float visibility = computeOcclusion( shadowCoord );
    //float depth = texture(shadowMap, shadowCoord.xy).z;
    vec3 vToEye = WSCamPos - pcolour.xyz;
    vToEye = normalize(vToEye);
    vec3 outColour = vec3(0.0,0.0,0.0);

    outColour = computeLight(dirLight.direction.xyz,vToEye,dirLight.colour.rgb,ncolour.rgb,dirLight.intensity,scolour.r);
    colour = vec4(visibility*(dcolour.rgb*outColour),1.0);

}

Может ли кто-нибудь определить, где это происходит не так?


person Ian Young    schedule 13.04.2017    source источник


Ответы (2)


Такие проблемы трудно обнаружить, поэтому вот несколько вещей, на которые вам нужно обратить внимание:

  1. Вы используете samplerShadow, который по-своему особенный, вам нужно установить COMPARE_R_TO_TEXTURE и при этом вам не нужен этот оператор if. В качестве альтернативы вы можете использовать sampler2D, но вам нужно сделать оператор if в шейдере, что-то похожее на то, что вы сделали, но координата должна быть vec2, а не vec3

  2. рассмотрите возможность использования textureProj с координатой текстуры vec4. потому что гораздо проще преобразовать положение в мире в световом пространстве, используя матричное умножение. Это та же самая матрица, которую вы используете для рендеринга карты теней. В вашем случае это значение vec4 shadowCoord = ShadowTransform * pcolour;; используйте shadowCoord напрямую с textureProj.

person Raxvan    schedule 13.04.2017
comment
О 2: Если вы используете sampler2D вместо sampler2DShadow, вы больше не будете использовать PCF. - person BDL; 13.04.2017
comment
Сработали две вещи: удаление оператора if и прямое использование выборки глубины, а также вызов glCullFace(GL_FRONT) перед рендерингом карты глубины. Похоже, у меня была очень мелкая теневая проблема с прыщами, которую было нелегко увидеть. - person Ian Young; 13.04.2017
comment
Хотя ответ был не точно правильным, он дал мне пищу для размышлений и направил меня в правильном направлении, так что спасибо. - person Ian Young; 13.04.2017
comment
@ Ян Янг, не могли бы вы рассказать нам решение, чтобы мы могли опубликовать его для дальнейшего использования? - person Raxvan; 13.04.2017
comment
@Raxvan Да, я сделаю это в своем собственном ответе. - person Ian Young; 13.04.2017

Оказалось, что моя выборка возвращала правильное значение.

Настоящая проблема заключалась в очень мелкозернистых теневых прыщах, вызванных отбраковкой задних граней геометрии при рендеринге карты глубины и неправильной обработкой возвращаемого значения при выборке текстуры глубины.

Я изменил функцию выборки на:

float computeOcclusion(vec4 shadowCoords)
{
    vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
    float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.001));
    return depth;
}

И изменил мой клиентский код глубинного рендеринга gl, включив в него:

glCullFace(GL_FRONT); 

Перед рендерингом геометрии в shadowMap.

Как только это было сделано, я получил следующий результат: окончательный рендеринг

Есть еще некоторые проблемы с Питером Пэннингом, но это то, с чем я могу разобраться отдельно.

person Ian Young    schedule 13.04.2017