2012年2月16日 星期四

從Depth map取得Eye-Space空間座標



如何從Screen-space反推三為空間座標呢?有以下幾個步驟:

STEP 1:
在Depth pass中,使用F32格式的Render target,儲存線性空間的Z值資訊,但什麼是線性
空間的Z值資訊呢?簡單說就是空間座標轉換到世界座標後的Z值,而非線性的Z值指的是轉換
到世界座標後,在經由Projection matrix傳換過後的Z值

STEP 2:
要在Screen-space下工作,可以想像成Image process一樣,對一張圖片做濾鏡的處哩,但三
維空間都是三角形怎麼模擬二維空間做影像處裡呢?說穿了就是畫兩個三角形拼成矩形暫滿整
各畫面,那要怎麼畫兩個三角形剛剛好暫滿畫面呢?

在Clipping Space中,整各會出現在畫面上的空間座標在範圍:[-1,-1,-1] ~ [1,1,1]中,比較簡
單的做法是,直接給予兩個三角形的Pos分別為:
Tri 0: (-1.0f, 1.0f,0.0f), (1.0f,1.0f,0.0f), (-1.0f,-1.0f,0.0f)
Tri 1:
(1.0f, 1.0f,0.0f), (-1.0f,-1.0f,0.0f), (1.0f,-1.0f,0.0f)
然後在Vertex shader中完全不做座標轉換!!

struct OUT
{
    float4 pos : POSITION;
    float2 uv : TEXCOORD0;
};

OUT vs_main( float3 pos : POSITION, float2 uv : TEXCOORD0 )
{
    OUT out;
    out.pos = float4( pos.x, pos.y, pos.z, 1.0f );
    out.uv = uv;
    return out;
}


STEP 3:

當完成step 2之後,我們進入Pixel shader的每一點都可以看作是圖片上的Pixel,如次就可以在
Screen-space上工作啦!!接下來就是使用texcoord去取出step 1中F32 Render-target的Z值來
反推每一點的空間座標(世界座標),反推的過程需要一點數學,簡單的說你怎麼推算出projection-matrix的,就反向帶回去即可,概念如下:

R: width/height


clipping sapce =
x' = x * 1/(z*R*tan(a/2))
y' = y * 1/(z*tan(a/2))

so, 反推回x, y等於

x = x' *
(z*R*tan(a/2))
y = y' *
(z*tan(a/2))

NVIDIA:

const float fovy = 40.0 * 3.14159265 / 180.0;   //40 deg in radian
const float invFocalLenX = tan(fovy * 0.5) * width / height;
const float invFocalLenY = tan(fovy * 0.5);

vec3 uv_to_eye(vec2 uv, float eye_z)
{
   uv = (uv * vec2(2.0, -2.0) - vec2(1.0, -1.0));
   return vec3(uv * vec2(invFocalLenX, invFocalLenY) * eye_z, eye_z);
}

vec3 fetch_eye_pos(vec2 uv)
{
   float z = texture2D(tex1, uv).a; // Depth/Normal buffer
   return uv_to_eye(uv, z);
}

沒有留言:

張貼留言

LinkWithin

Related Posts Plugin for WordPress, Blogger...