Ponteiros no moderno cubemapping de sombras OpenGL?

fundo

Eu estou trabalhando em um jogo 3D usando C ++ e OpenGL moderno (3.3). Agora estou trabalhando na iluminação e renderização de sombras, e implementei com êxito o mapeamento de sombra direcional. Depois de ler os requisitos para o jogo, decidi que precisaria de um mapeamento de sombras leves. Depois de fazer algumas pesquisas, descobri que, para fazer o mapeamento de sombra omnidirecional, farei algo semelhante ao mapeamento de sombra direcional, mas com um cubemap em vez disso.

Eu não tenho nenhum conhecimento prévio de cubemaps, mas o meu entendimento deles é que um cubemap tem seis texturas, perfeitamente ligadas. Eu fiz alguns olhando ao redor, mas infelizmente eu me esforcei para encontrar um "tutorial" definitivo sobre o assunto para o OpenGL moderno. Eu procuro primeiro tutoriais que explicam do início ao fim, porque eu me esforcei muito para aprender com trechos de código-fonte ou apenas conceitos, mas eu tentei.

Entendimentos atuais

Aqui está o meu entendimento geral da ideia, menos os aspectos técnicos. Por favor me corrija.

Para cada luz de ponto, um framebuffer é configurado, como mapeamento de sombra direcionalUma textura de cubemap única é então gerada e ligada comglBindTexture(GL_TEXTURE_CUBE_MAP, shadowmap).

O cubemap é configurado com os seguintes atributos:

glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

(isso também é semelhante ao shadowmapping direcional)

AgoraglTexImage2D() é iterado por seis vezes, uma vez para cada face. Eu faço assim:

 for (int face = 0; face < 6; face++) // Fill each face of the shadow cubemap
     glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT32F , 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

A textura é anexada ao framebuffer com uma chamada para

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowmap, 0);

Quando a cena é renderizada, ela é renderizada em duas passagens, como mapeamento de sombra direcional.

Primeiro de tudo, o framebuffer sombra é ligado, a viewport é ajustada para o tamanho do mapa de sombra (1024 por 1024, neste caso).O abate é definido para as faces frontais comglCullFace(GL_FRONT)O programa ativo do shader é comutado para os sombreamentos de sombreamento de vértice e fragmento que fornecerão as fontes de mais baixo

As matrizes de visualização de luz para todas as seis visualizações são calculadas. Eu faço isso criando um vetor de glm :: mat4 epush_back() as matrizes, assim:

// Create the six view matrices for all six sides
for (int i = 0; i < renderedObjects.size(); i++) // Iterate through all rendered objects
{
    renderedObjects[i]->bindBuffers(); // Bind buffers for rendering with it

    glm::mat4 depthModelMatrix = renderedObjects[i]->getModelMatrix(); // Set up model matrix

    for (int i = 0; i < 6; i++) // Draw for each side of the light
    {
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, shadowmap, 0);
        glClear(GL_DEPTH_BUFFER_BIT); // Clear depth buffer

        // Send MVP for shadow map
        glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrices[i] * depthModelMatrix;
        glUniformMatrix4fv(glGetUniformLocation(shadowMappingProgram, "depthMVP"), 1, GL_FALSE, glm::value_ptr(depthMVP));

        glUniformMatrix4fv(glGetUniformLocation(shadowMappingProgram, "lightViewMatrix"), 1, GL_FALSE, glm::value_ptr(depthViewMatrices[i]));
        glUniformMatrix4fv(glGetUniformLocation(shadowMappingProgram, "lightProjectionMatrix"), 1, GL_FALSE, glm::value_ptr(depthProjectionMatrix));
        glDrawElements(renderedObjects[i]->getDrawType(), renderedObjects[i]->getElementSize(), GL_UNSIGNED_INT, 0);
    }
}

O framebuffer padrão é ligado e a cena é desenhada normalmente.

Questão

Agora, para os shaders. É aqui que meu entendimento fica seco. Estou completamente inseguro sobre o que devo fazer, minha pesquisa parece entrar em conflito uma com a outra, porque é para versões diferentes. Acabei copiando e colando palavras de fontes aleatórias, e esperando conseguir algo diferente de uma tela preta. Eu sei que isso é terrível, mas não parece haver nenhuma definição clara sobre o que fazer. Em quais espaços eu trabalho? Eu preciso mesmo de um sombreamento de sombra separado, como eu usei na iluminação de ponto direcional? O que diabos eu uso como o tipo para um cubemap de sombra? samplerCube? samplerCubeShadow? Como faço para amostrar o cubemap corretamente? Espero que alguém possa esclarecer isso para mim e fornecer uma boa explicação. Meu entendimento atual da parte do shader é: - Quando a cena está sendo renderizada no cubemap, o shader de vértice simplesmente pega o depthMVP uniforme que calculei no meu código C ++ e transforma os vértices de entrada por eles. - O shader de fragmento do passe do mapa de cubos simplesmente atribui o valor de saídagl_FragCoord.z. (Esta parte é inalterada desde quando eu implementei mapeamento de sombra direcional. Eu assumi que seria o mesmo para cubemapping porque os shaders nem sequer interagem com o cubemap - OpenGL simplesmente renderiza a saída deles para o cubemap, certo? Porque é um Suavizador de quadros?)

O sombreador de vértice para a renderização normal é inalterado.No shader de fragmento para renderização normal, a posição do vértice é transformada no espaço da luz com a projeção da luz e a matriz de visualização.Isso é de alguma forma usado na pesquisa de textura do cubemap. ???Uma vez que a profundidade tenha sido recuperada usando meios mágicos, ela é comparada à distância da luz ao vértice, muito parecido com o mapeamento de sombras direcional. Se é menos, esse ponto deve ser sombreado e vice-versa.

Não é muito de um entendimento. Eu vou em branco sobre como os vértices são transformados e usados ​​para procurar o cubemap, então eu vou colar a fonte para meus shaders, na esperança de que as pessoas possam esclarecer isso. Por favor, note que muito deste código é cópia e colagem cegas, eu não alterei nada para não comprometer qualquer entendimento.

Sombra sombreamento de vértice:
#version 150

in vec3 position;

uniform mat4 depthMVP;

void main()
{
    gl_Position = depthMVP * vec4(position, 1);
}
Shadow shader fragment:
#version 150

out float fragmentDepth;

void main()
{
    fragmentDepth = gl_FragCoord.z;
}
Shader de vértice padrão:
#version 150

in vec3 position;
in vec3 normal;
in vec2 texcoord;

uniform mat3 modelInverseTranspose;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

out vec3 fragnormal;
out vec3 fragnormaldirection;
out vec2 fragtexcoord;
out vec4 fragposition;
out vec4 fragshadowcoord;

void main()
{
    fragposition = modelMatrix * vec4(position, 1.0);
    fragtexcoord = texcoord;
    fragnormaldirection = normalize(modelInverseTranspose * normal);
    fragnormal = normalize(normal);
    fragshadowcoord = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);


    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
Shader de fragmento padrão:
#version 150

out vec4 outColour;

in vec3 fragnormaldirection;
in vec2 fragtexcoord;
in vec3 fragnormal;
in vec4 fragposition;
in vec4 fragshadowcoord;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrixInversed;

uniform mat4 lightViewMatrix;
uniform mat4 lightProjectionMatrix;

uniform sampler2D tex;
uniform samplerCubeShadow shadowmap;

float VectorToDepthValue(vec3 Vec)
{
    vec3 AbsVec = abs(Vec);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    const float f = 2048.0;
    const float n = 1.0;
    float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp;
    return (NormZComp + 1.0) * 0.5;
}

float ComputeShadowFactor(samplerCubeShadow ShadowCubeMap, vec3 VertToLightWS)
{   
    float ShadowVec = texture(ShadowCubeMap, vec4(VertToLightWS, 1.0));
    if (ShadowVec + 0.0001 > VectorToDepthValue(VertToLightWS)) // To avoid self shadowing, I guess
        return 1.0;

    return 0.7;
}

void main()
{
    vec3 light_position = vec3(0.0, 0.0, 0.0);
    vec3 VertToLightWS = light_position - fragposition.xyz;
    outColour = texture(tex, fragtexcoord) * ComputeShadowFactor(shadowmap, VertToLightWS);
}

Não me lembro de onde o código da função ComputerShadowFactor e VectorToDepthValue veio, porque eu estava pesquisando no meu laptop que eu não consigo acessar agora, mas esse é o resultado desses shaders:

É um pequeno quadrado de espaço sem sombras cercado por um espaço sombreado.

Eu obviamente estou fazendo muito errado aqui, provavelmente centrado em meus shaders, devido à falta de conhecimento sobre o assunto, porque acho difícil aprender com qualquer coisa além de tutoriais, e eu sinto muito por isso. Eu estou perdido, seria maravilhoso se alguém pudesse esclarecer isso com uma explicação clara sobre o que estou fazendo de errado, porque está errado, como posso consertar e talvez até mesmo algum código. Eu acho que o problema pode ser porque eu estou trabalhando nos espaços errados.

questionAnswers(1)

yourAnswerToTheQuestion