Shadow Mapping OpenGL тень не всегда рисует, а рисует там, где находится положение света - PullRequest
1 голос
/ 15 марта 2020

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

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

выводы

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

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

Вершина 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);
}

Фрагмент ShadowMapping

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

Фрагмент Шейдер для этого шейдера пуст Конструктор моей сцены:

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 l oop, я сначала делаю:

Визуализация объектов с точки зрения света

//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();

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

1 Ответ

2 голосов
/ 15 марта 2020

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

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

m_lightSpaceMatrix = m_lightProjection * m_lightView; 

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

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

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

...