Положение в мировом пространстве из буфера логарифмической глубины

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

Когда у меня была написана глубина z/w OpenGL по умолчанию, я мог легко вычислить это значение путем преобразования из пространства окна в пространство NDC и затем выполнить обратное преобразование перспективы.

Я сделал все это во втором проходе фрагмента шейдера:

uniform sampler2D depth_tex;

uniform mat4 inv_view_proj_mat;

in vec2 uv_f;

vec3 reconstruct_pos(){
    float z = texture(depth_tex, uv_f).r;
    vec4 pos = vec4(uv_f, z, 1.0) * 2.0 - 1.0;
    pos = inv_view_proj_mat * pos;

    return pos.xyz / pos.w;
}

и получил результат, который выглядел довольно правильно:

Отрисовка куба с корректной реконструкцией положения в мировом пространстве

Но теперь дорога к простому z значение не так просто (не кажется, что оно должно быть слишком сложным).

Мой вершинный шейдер для моего первого прохода с глубиной записи:

#version 330 core
#extension GL_ARB_shading_language_420pack : require

layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 uv;

uniform mat4 mvp_mat;

uniform float FC;

out vec2 uv_f;
out float logz_f;
out float FC_2_f;

void main(){
    gl_Position = mvp_mat * vec4(pos, 1.0);

    logz_f = 1.0 + gl_Position.w;

    gl_Position.z = (log2(max(1e-6, logz_f)) * FC - 1.0) * gl_Position.w;

    FC_2_f = FC * 0.5;
}

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

#version 330 core
#extension GL_ARB_shading_language_420pack : require

// other uniforms and output variables

in vec2 uv_f;
in float FC_2_f;

void main(){
    gl_FragDepth = log2(logz_f) * FC_2_f;
}

Я пробовал несколько разных подходов, чтобы правильно вернуть z-положение, но все не получилось.

Если я переопределю свой reconstruct_pos во втором проходе быть:

vec3 reconstruct_pos(){
    vec4 pos = vec4(uv_f, get_depth(), 1.0) * 2.0 - 1.0;
    pos = inv_view_proj_mat * pos;

    return pos.xyz / pos.w;
}

Это моя текущая попытка восстановить Z:

uniform float FC;

float get_depth(){
    float log2logz_FC_2 = texture(depth_tex, uv_f).r;
    float logz = pow(2, log2logz_FC_2 / (FC * 0.5));
    float pos_z = log2(max(1e-6, logz)) * FC - 1.0; // pos.z
    return pos_z;
}

Разъяснение:

log2logz_FC_2: значение записывается в буфер глубины, поэтому log2(1.0 + gl_Position.w) * (FC / 2)

logzпросто 1.0 + gl_Position.w

pos_z: значение gl_Position.z перед перспективой

возвращаемое значение: gl_Position.z

Конечно, это только моя работа. Я не уверен, что эти значения на самом деле содержат в конце, потому что я думаю, что я испортил некоторые математические вычисления или неправильно понял происходящие преобразования.

Как правильно получить мою позицию Z в мировом пространстве из этого буфера логарифмической глубины?

1 ответ

Решение

В конце концов я все об этом пошла не так. Способ вернуть позицию в мировом пространстве с использованием буфера журнала:

  1. Получить глубину из текстуры
  2. Реконструировать gl_Position.w
  3. линеаризовать реконструированную глубину
  4. перевести в мировое пространство

Вот моя реализация в glsl:

in vec2 uv_f;

uniform float nearz;
uniform float farz;

uniform mat4 inv_view_proj_mat;

float linearize_depth(in float depth){
    float a = farz / (farz - nearz);
    float b = farz * nearz / (nearz - farz);
    return a + b / depth;
}

float reconstruct_depth(){
    float depth = texture(depth_tex, uv_f).r;
    return pow(2.0, depth * log2(farz + 1.0)) - 1.0;
}

vec3 reconstruct_world_pos(){
    vec4 wpos =
        inv_view_proj_mat *
        (vec4(uv_f, linearize_depth(reconstruct_depth()), 1.0) * 2.0 - 1.0);

    return wpos.xyz / wpos.w;
}

Что дает мне тот же результат (но с большей точностью), что и при использовании буфера глубины OpenGL по умолчанию.

Другие вопросы по тегам