3

1 回目のパスから保存された (非線形の) 深度テクスチャを使用して、スクリーン空間の法線を生成したいと考えています。2 番目のパスでは、深度、拡散、ID などをレンダリングできますが、深度から法線が機能しているようには見えません。

深さから法線を取得することに関する現在の理解:

  1. texture()/texelFetch() p現在の tex 座標でp+ (1, 0) = p1, p+ (0, 1) = p2; これらからカメラ空間の位置を再構築します

  2. v1ベクトルを取得p1 - p: 現在の位置とその画面/テクスチャ空間 x 隣接間のベクトル

  3. v2ベクトルを取得p2 - p: 現在の位置とその画面/テクスチャ空間の y 近傍の間のベクトル
  4. crossこれら 2 つをnormalize()積んで、現在のテクセルでサーフェス法線を取得します。

シェーダー (2 番目のパス! フルスクリーン クワッドにレンダリング)

バーテックス:

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

結果

ここに画像の説明を入力

質問何が間違っていますか? 5 歳児に説明するように説明してください。:)

これは、SSAO と指向性照明の基礎として使用されます。

私が知る限り、フラグメントdFdxdFdyはなくテクセルで作業しているため、答えではありません。

4

1 に答える 1

4

pとviaの計算方法は確かに間違っていますp1。この関数は、深さが異なるだけで 3 つのポイントすべてに同じものを使用するため、3 つのポイントすべてが線上に配置されます。の外積は、どのピクセルでも 0 になるはずです。ここに表示されるのは数値的な不安定性であり、結果のベクトルを単位長に正規化することによって増幅されます。p2viewSpacePositionFromDepth texcoordFraggetNormal

于 2015-03-04T21:53:58.247 に答える