C ++ Сравнение матрицы карты теней с матрицей рисования не создает теней - PullRequest
0 голосов
/ 09 января 2019

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

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

EDIT:

Думаю, я получил его на работу. При создании текстуры кадрового буфера я использовал неправильную функцию сравнения. Должно быть: «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 голосов
/ 09 января 2019

Содержимое карты теней - это значение глубины в диапазоне глубины [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;
}
...