Отображение теней OpenGL тень не всегда рисует и рисует там, где находится источник света.

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

Я отлаживал эту ошибку около двух недель, исследовал Интернет и даже пытался разобраться в этом, но все, что я могу сказать, это то, что тень почти никогда не появляется, а когда она появляется, то там, где свет. термины x и z. Я пытался сделать все точно так же, как в учебнике около 10 раз, я также пытался проверить этот сайт на наличие похожих вопросов, но каждый способ, который я нашел, был не моим случаем.

результаты

На этом изображении (1) видно, что тень не видна, когда свет находится поверх него, но затем он виден на этом изображении (2), когда переменная lightPos.x составляет около -4,5 или 4,5, то же самое относится и к переменной lightPos.z. Тень при появлении рисуется там, где есть lightPos, где на картинках она обведена красной линией.

Я использую несколько шейдеров, один для расчета света и тени (ShadowMapping), один для базового отображения глубины (ShadowMapGen). Вот мой шейдер ShadowMapping:

Вершина отображения теней

version 460
in vec3 vertexIn;
in vec3 normalIn;
in vec2 textureIn;

out vec3 FragPos;
out vec3 normalOut;
out vec2 textureOut;

out vec4 FragPosLightSpace;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightSpaceMatrix;

void main()
{
    textureOut = textureIn;

    FragPos = vec3(model * vec4(vertexIn, 1.0));
    normalOut = mat3(transpose(inverse(model))) * normalIn;  
    FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);    

    gl_Position = projection * view * model * vec4(vertexIn, 1.0);
}

Фрагмент карты теней

out vec4 FragColor;

in vec3 FragPos;
in vec3 normalOut;
in vec2 textureOut;

in vec4 FragPosLightSpace;

uniform sampler2D diffuseTexture;
uniform sampler2D shadowMap;

uniform vec3 lightPos;
uniform vec3 viewPos;

float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightdir)
{
    // perform perspective divide
    vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
    // transform to [0,1] range
    projCoords = projCoords * 0.5 + 0.5;
    // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
    float closestDepth = texture(shadowMap, projCoords.xy).r; 
    // get depth of current fragment from light's perspective
    float currentDepth = projCoords.z;
    // check whether current frag pos is in shadow
    float bias = max(0.05 * (1.0 - dot(normalOut, lightdir)), 0.005);

    // check whether current frag pos is in shadow
//    float shadow = currentDepth - bias > closestDepth  ? 1.0 : 0.0;
//    // PCF
    float shadow = 0.0;

    vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
    for(int x = -1; x <= 1; ++x)
    {
        for(int y = -1; y <= 1; ++y)
        {
            float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; 
            shadow += currentDepth - bias > pcfDepth  ? 1.0 : 0.0;        
        }    
    }

    shadow /= 9.0;

    // keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
        if(projCoords.z > 1.0)
        shadow = 0.0;

    return shadow;
}

void main()
{           
    vec3 color = texture(diffuseTexture, textureOut).rgb;
    vec3 normal = normalize(normalOut);
    vec3 lightColor = vec3(1.0f);
    // ambient
    vec3 ambient = 0.30 * color;
    // diffuse
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * lightColor;
    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
    vec3 specular = spec * lightColor;    
    // calculate shadow
    float shadow = ShadowCalculation(FragPosLightSpace, lightDir);                      
    vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;    

    FragColor = vec4(lighting, 1.0);
}

ShadowMapGen Vertex

Фрагментный шейдер пуст для этого шейдера

version 460

in vec3 vertexIn;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;

void main()
{
    gl_Position =  model * lightSpaceMatrix * vec4(vertexIn, 1.0);
}

Инициализация переменных

lightPos = glm::vec3(-2.0f, 4.0f, -1.0f);
near_plane = 1.0f;
far_plane = 7.5f;

//SAMPLE 2D Uniform binding
TheShader::Instance()->SendUniformData("ShadowMapping_diffuseTexture", 0);
TheShader::Instance()->SendUniformData("ShadowMapping_shadowMap", 1);

Генерация кадрового буфера карты глубины

Вот как я генерирую текстуру карты глубины/карты теней в конструкторе моей сцены:

glGenFramebuffers(1, &depthMapFBO);
//Create depth texture
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); // Height and Width = 1024
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

float borderColor[] = { 1.0, 1.0, 1.0, 1.0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

//Attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

Затем в функции Update(), которая запускается в цикле While движка, я сначала делаю:

Рендеринг объектов с точки зрения света

//Light Projection and view Matrix 
m_lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
m_lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
//Calculate light matrix and send it.
m_lightSpaceMatrix = m_lightProjection * m_lightView;
TheShader::Instance()->SendUniformData("ShadowMapGen_lightSpaceMatrix", 1, GL_FALSE, m_lightSpaceMatrix);

//Render to Framebuffer depth Map
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);

//Set current Shader to ShadowMapGen
m_floor.SetShader("ShadowMapGen");
m_moon.SetShader("ShadowMapGen");
//Send model Matrix to current Shader
m_floor.Draw();
m_moon.Draw();
//Set current Shader back to ShadowMapping
m_moon.SetShader("ShadowMapping");
m_floor.SetShader("ShadowMapping");

glBindFramebuffer(GL_FRAMEBUFFER, 0);

Рендеринг объектов с точки зрения камеры

glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Update Camera and Send the view and projection matrices to the ShadowMapping shader
m_freeCamera->Update();
m_freeCamera->Draw();

//Send Light Pos 
TheShader::Instance()->SendUniformData("ShadowMapping_lightPos", lightPos);
//Send LightSpaceMatrix
TheShader::Instance()->SendUniformData("ShadowMapping_lightSpaceMatrix", 1, GL_FALSE, m_lightSpaceMatrix);

//Activate Shadow Mapping texture
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap);

//Send model Matrix to ShadowMapping shaders
m_moon.Draw();  
m_floor.Draw();

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


person MrAbnox    schedule 15.03.2020    source источник


Ответы (1)


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

Ну, вы, похоже, упустили как минимум одну очевидную вещь:

m_lightSpaceMatrix = m_lightProjection * m_lightView; 

Пока все хорошо, но в своем вершинном шейдере "ShadowMapGen" вы написали:

gl_Position =  model * lightSpaceMatrix * vec4(vertexIn, 1.0);

Таким образом, вы получите порядок умножения model * projection * view, который не имеет смысла независимо от того, каких соглашений вы придерживаетесь. Поскольку в учебнике используются соглашения GL по умолчанию, вам всегда нужен порядок умножения projection * view * model * vertex, который также правильно используется в учебнике.

person derhass    schedule 15.03.2020
comment
Только что проверил, работает. Да, вы правы, я не могу поверить, что упустил из виду эту маленькую деталь. Спасибо за ваше время. - person MrAbnox; 15.03.2020
comment
Это не стоило мне много времени, это было самое первое, на что я посмотрел... :) - person derhass; 15.03.2020