2016-11-02 43 views
7

Po zmianie mojego bieżącego rendereru odroczonego na użycie logarithmic depth buffer, nie mogę wyłuskać, na życie mnie, jak zrekonstruować głębokość przestrzeni świata z wartości bufora głębi.Pozycja w przestrzeni globalnej z logarytmicznego bufora głębi

Gdy miałem domyślną głębokość Z/W OpenGL, mogłem łatwo obliczyć tę wartość poprzez przekształcenie z przestrzeni okna na przestrzeń NDC, a następnie wykonać odwrotną transformację perspektywy.

Zrobiłem wszystko to w drugim przejściu fragment shadera:

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; 
} 

i dostałem wynik, który wyglądał całkiem poprawne:

Cube rendered with correct world-space position reconstruction

Ale teraz droga do prostego z wartości jest nie tak łatwo (nie wydaje się, że powinno być tak trudno).

Moja vertex shader dla mojego pierwszego przejścia z głębi dziennika:

#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; 
} 

A mój fragment shader:

#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; 
} 

Próbowałem kilka różnych podejść, aby wrócić z-pozycji poprawnie, wszystko zawiedzie.

Gdybym przedefiniować mój reconstruct_pos w drugim przejściu być:

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; 
} 

To moja obecna próba rekonstrukcji 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; 
} 

wyjaśnił:

log2logz_FC_2: wartość napisane do bufora głębokości, więc log2(1.0 + gl_Position.w) * (FC/2)

logz: wystarczy 1.0 + gl_Position.w

pos_z: wartość gl_Position.z przed perspektywicznym podzielić

Wartość zwracana: gl_Position.z

Oczywiście, to tylko moja robocza. Nie jestem pewien, co te wartości faktycznie trzymają w końcu, ponieważ myślę, że spieprzyłem trochę matematyki lub nie zrozumiałem poprawnie transformacji.

Jaki jest poprawny sposób na uzyskanie mojej pozycji w przestrzeni światowej z tego logarytmicznego bufora głębi?

Odpowiedz

0

W końcu chciałem to wszystko zepsuć. Sposób, aby uzyskać pozycję światowej przestrzeni powrotem stosując bufor dziennika jest:

  1. Odzyskaj od głębokości tekstury
  2. Rekonstrukc gl_Position.W
  3. zlinearyzować zrekonstruowanej głębokości
  4. przekłada się na przestrzeni światowej

Oto moja implementacja w 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; 
} 

co daje mi ten sam wynik (ale z lepszą dokładnością), a kiedy używałem domyślny bufor głębi OpenGL.