C++ Сравнение матрицы карты теней с матрицей рисования не создает теней

Я пытаюсь реализовать отображение теней. Я могу визуализировать карту глубины на текстуру кадрового буфера. и отправьте его в шейдер, а также в ортографическую матрицу источников света, чтобы проверить, находится ли фрагмент в тени. Но результаты не верны. Вместо создания теней все фрагменты просто раскрашиваются, если они находятся "внутри" световой матрицы, на которую это похоже.

IMG

Как вы можете видеть слева внизу, сгенерированная текстура глубины верна.

Я перепробовал много уроков, но ни в одной из них не упоминалось о подобных проблемах. Возможно, потому что направление света и ортографическая проекция неверны, но я не могу найти рабочее направление света, которое создает тени.

Вот как я генерирую буфер кадра и текстуру (в заголовке класса создаются экземпляры frameBuffer и framebufferTexture):

glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

//texture buffer for frame buffer
glGenTextures(1, &framebufferTexture);
glBindTexture(GL_TEXTURE_2D, framebufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 896, 504, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);


//Set framebufferTexture as our color attachment #0
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    GL_TEXTURE_2D, framebufferTexture, 0);

glDrawBuffer(GL_NONE);

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

glCullFace(GL_BACK);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer);
//Setup depth texture framebuffer rendering
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(2.0f, 2.0f);
glViewport(0, 0, 896, 504);
glClear(GL_DEPTH_BUFFER_BIT);

glUniform1i(glGetUniformLocation(shaderProgram, "fragmentTypeTarget"), -1);


glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
//Calculate the matrix for drawing the framebuffer
//Make it an orthographic that takes the whole screen
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
glm::mat4 depthViewMatrix = glm::lookAt(
    lightInvDir,
    glm::vec3(0, 0, 0),
    glm::vec3(0, 1, 0));
glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix;

//Render the objects
for (int i = 0; i < objectPool.size(); i++) {
    objectPool[i]->draw(lightSpaceMatrix);
}

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

glm::mat4 Model = glm::translate(glm::mat4(1.0), glm::vec3(x, y, z));
glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
    //Calculate the matrix for drawing the framebuffer
    //Make it an orthographic that takes the whole screen
    glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
    glm::mat4 depthViewMatrix = glm::lookAt(
        lightInvDir,
        glm::vec3(0, 0, 0),
        glm::vec3(0, 1, 0));
    glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix * Model;
glUniformMatrix4fv(glGetUniformLocation(shader, "shadowMatrix"), 1, GL_FALSE, &lightSpaceMatrix[0][0]);

Мой фрагмент шейдера:

#version 330 core
layout(location = 0) out vec4 outColor;
in vec2 UV;
in vec4 ShadowCoord;
uniform sampler2D textureSampler;
uniform sampler2D shadowMap;
uniform int fragmentTypeTarget;


// 'colorImage' is a sampler2D with the depth image
// read from the current depth buffer bound to it.
float LinearizeDepth(in vec2 uv, sampler2D t)
{
    float zNear = 1.0;    
    float zFar  = 5.0; 
    float depth = texture2D(t, uv).x;
    return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
}

void main(){
if(fragmentTypeTarget == -1){//draw frame buffer

}else if(fragmentTypeTarget == 0){//Draw everything normal
    vec4 tex = texture2D(textureSampler, UV);
    outColor = vec4(tex.rgb, tex.a);
}else if(fragmentTypeTarget == 1){//Draw depth texture
    //vec2 res = gl_FragCoord.xy / vec2(1024, 1024);
    outColor = texture(textureSampler, UV);
    float c = LinearizeDepth(UV, textureSampler);
    outColor = vec4(c, c, c, 1.0);
}else if(fragmentTypeTarget == 2){//Draw everything but apply the shadow
    float visibility = 1.0;
    float bias = 0.0039;

    if(texture(shadowMap, ShadowCoord.xy).z < ShadowCoord.z){
        visibility = 0.3;
    }
    vec4 tex = texture2D(textureSampler, UV);
    outColor = visibility * vec4(tex.rgb, tex.a);
}
}

Мой вершинный шейдер:

#version 330 core
in vec2 UVsIn;
out vec2 UV;
in vec3 position;
in vec3 vertexColor;
out vec3 fragmentColor;
uniform mat4 mvp;
uniform mat4 shadowMatrix;
out vec4 ShadowCoord;

void main(){
gl_Position = mvp * vec4(position, 1.0);
fragmentColor = vertexColor;
UV = UVsIn;

ShadowCoord = shadowMatrix * vec4(position, 1.0);
}

Результат должен выглядеть примерно так:

IMG

РЕДАКТИРОВАТЬ:

Думаю, я получил его на работу. При создании текстуры кадрового буфера я использовал неправильную функцию сравнения. Должно быть: "GL_COMPARE_R_TO_TEXTURE" вместо "GL_COMPARE_REF_TO_TEXTURE".

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

Документация openGl гласит: GL_COMPARE_R_TO_TEXTURE: указывает, что интерполированную и фиксированную координату текстуры r следует сравнивать со значением в текущей привязанной текстуре глубины

Что именно то, что я хочу.

Я также узнал, что координаты текстуры находятся в (s, t, r) вместо (x, y, z).

так как я хочу сравнить глубину матриц и текстуры, мне нужно использовать r вместо z. поэтому фрагментный шейдер должен был быть написан так:

float visibility = 1.0;

vec2 mapUV = ShadowCoord.xy * 0.5 + 0.5;
float depthFrag = ShadowCoord.z * 0.5 + 0.5;

float depthMap = texture(shadowMap, mapUV).r;//r instead of z since its (s, t, r)

if(depthMap < depthFrag){
    visibility = 0.3;
}

vec4 tex = texture2D(textureSampler, UV);
outColor = visibility * vec4(tex.rgb, tex.a);

"* 0,5 + 0,5" также необходимо было добавить из ответа Rabbid76.

1 ответ

Решение

Содержимое карты теней представляет собой значение глубины в диапазоне глубины [0.0, 1.0] (за исключением того, что вы изменили бы диапазон глубины на glDepthRange)

ShadowCoord координата пространства клипа Координата пространства клипа может быть преобразована в нормализованную координату пространства устройства делением перспективы (ShadowCoord.xyz/ShadowCoord.w). Так как теневая проекция является орфографической, это можно пропустить, потому что ShadowCoord.w == 1.0, Нормализованные координаты пространства устройства находятся в диапазоне [-1.0, 1.0].

Так и должно быть:

vec2  mapUV     = ShadowCoord.xy * 0.5 + 0.5; // [-1.0, 1.0] -> [0.0, 1.0]
float depthFrag = ShadowCoord.z  * 0.5 + 0.5; // [-1.0, 1.0] -> [0.0, 1.0]

float depthMap  = texture(shadowMap, mapUV).r;

if(depthMap < depthFrag) {
    visibility = 0.3;
}
Другие вопросы по тегам