2015-03-01 2 views
2

Я хочу использовать сохраненную (нелинейную) глубину с 1-го прохода для получения нормалей экранного пространства. Во 2-м проходе я могу отображать глубину, диффузность, идентификатор и т. Д., Но я не могу получить нормали от глубины.Камерное пространство Нормали из глубинной текстуры

Современного понимания получать нормали из глубины:

  1. texture()/texelFetch()p при текущем тексе коорде, p + (1, 0) = p1 и p + (0, 1) = p2; реконструировать камеры космические позиции из этих

  2. Получить v1 вектор p1 - p: вектор между текущим положением и это экран/текстура-пространство х сосед

  3. Получить v2 вектор p2 - p: вектор между текущим положением, и это экран/текстуры пространства y сосед
  4. cross продукт этих двух и normalize(), чтобы получить нормальную поверхность в текущем текселе.

шейдеры (второй проход рендеринга в полноэкранный квад!)

Vertex:

#version 330 core 

layout (location = 0) in vec2 position; 
layout (location = 2) in vec2 texcoord; 

out vec2 texcoordFrag; 

void main() 
{ 
    gl_Position = vec4(position.x, position.y, 0, 1); 
    texcoordFrag = texcoord; 
} 

Фрагмент:

#version 330 core 

uniform sampler2D tex; 
uniform mat4 vpInv; 

in vec2 texcoordFrag; 
layout(location = 0) out vec4 fragmentColor; 


float near = 0.1; 
float far = 100.0; 

float linearizeDepth(float depth) 
{ 
    float nearToFarDistance = far - near; 
    return (2.0 * near)/(far + near - depth * nearToFarDistance); 
    //http://www.ozone3d.net/blogs/lab/20090206/how-to-linearize-the-depth-value/ 
    //http://www.geeks3d.com/20091216/geexlab-how-to-visualize-the-depth-buffer-in-glsl/ 
} 

vec3 worldSpacePositionFromDepth(in float depth) 
{ 
    vec4 clipSpacePos; 
    clipSpacePos.xy = texcoordFrag * 2.0 - 1.0; 
    clipSpacePos.z = texture(tex, texcoordFrag).r * 2.0 - 1.0; 
    clipSpacePos.w = 1.0; 
    vec4 homogenousPos = vpInv * clipSpacePos; 
    return homogenousPos.xyz/homogenousPos.w; 
} 

vec3 viewSpacePositionFromDepth(in float depth) //PositionFromDepth_DarkPhoton(): https://www.opengl.org/discussion_boards/showthread.php/176040-Render-depth-to-texture-issue 
{ 
    vec2 ndc;    // Reconstructed NDC-space position 
    vec3 eye;    // Reconstructed EYE-space position 

    float top = 0.05463024898; //per 1 radianm FoV & distance of 0.1 
    float bottom = -top; 

    float right = top * 1024.0/768.0; 
    float left = -right; 

    float width = 1024.0; 
    float height = 768.0; 
    float widthInv = 1.0/width; 
    float heightInv = 1.0/height; 

    ndc.x = (texcoordFrag.x - 0.5) * 2.0; 
    ndc.y = (texcoordFrag.y - 0.5) * 2.0; 

    eye.z = linearizeDepth(depth); //eye.z = near * far/((depth * (far - near)) - far); //original 
    eye.x = (-ndc.x * eye.z) * right/near; 
    eye.y = (-ndc.y * eye.z) * top/near; 

    return eye; 
} 

vec3 getNormal(vec3 p1, vec3 p2) 
{ 
    vec3 normal = cross(p2, p1); 
    normal.z = -normal.z; 
    return normalize(normal) * 0.5 + 0.5; 
} 

void main() 
{ 
    float depth = texture(tex, texcoordFrag.st).r; 
    float depth1 = texture(tex, texcoordFrag.st + vec2(1.0/1024.0, 0)).r; 
    float depth2 = texture(tex, texcoordFrag.st + vec2(1.0/768.0 , 0)).r; 
    float depthLinear = linearizeDepth(depth); 

    if (depthLinear > 1.0) discard; 
    //fragmentColor = vec4(depth, depth, depth, 1.0f); 
    fragmentColor = vec4(depthLinear, depthLinear, depthLinear, 1.0); 

    //vec3 w = worldSpacePositionFromDepth(depth); 
    //fragmentColor = vec4(w, 1.0); 

    vec3 p = viewSpacePositionFromDepth(depth); 
    vec3 p1 = viewSpacePositionFromDepth(depth1); 
    vec3 p2 = viewSpacePositionFromDepth(depth2); 

    vec3 v1 = (p1-p); 
    vec3 v2 = (p2-p); 
    vec3 normal = getNormal(v1, v2); 
    fragmentColor = vec4(normal, 1.0); 
} 

Результат

enter image description here

Вопрос Что я делаю неправильно? Объясните это, как и вы, пятилетнему. :)

Это будет использоваться в качестве основы для SSAO и направленного освещения.

Насколько я знаю, dFdx и dFdy не являются ответом, поскольку я работаю с текселями, а не фрагментами.

+0

... потому что хранение нормалей в другой текстуре слишком просто. – Luca

ответ

4

Способы расчета p, p1 и p2 через viewSpacePositionFromDepth, безусловно, ошибочны. Эта функция использует то же самое:texcoordFrag для всех трех точек, только с разной глубиной, поэтому все три точки будут лежать на линии. Перекрестное произведение в getNormal должно просто дать 0 для любого пикселя - то, что вы видите здесь, - это просто численная неустойчивость, которая усиливается путем нормализации полученного вектора до единицы длины.

+0

Thanks; мне кажется, мне нужен был обзор кода! Я был слеп к такой очевидной проблеме. Сейчас _apparently_ работает, независимо от того, использовал ли dFdx/dFdy или ручную разницу. Я награду щедростью, как только у меня будет SSAO на этой основе. Я просто хочу быть уверенным, что нормали теперь правильны с точки зрения направления. Это, безусловно, так кажется. –