前言

因為在做GAMES 101的Homework 5時,遇到Screen Space -> World Space的問題,所以將思路及其解決方法記錄在此篇文章中。在作業5中,有兩題:

  1. 判斷是否與三角形相交 (Moller-Trumbore)
  2. 得到射線的方向

此篇文章只說明第2題。

推導

首先,我們已知Camera的世界座標,而且根據代碼,得知投影平面位於Camera的z=-1的位置(一般也是在z=1的位置)。

1
Vector3f dir = Vector3f (x, y, -1);

為了得到射線,我們需要知道Camera與像素中心之間的方向,所以我們需要知道像素的世界座標,目前已知的是z=-1,還需要求出xy

假設螢幕大小為width×heightwidth \times height,起點在左下角,寬高比A=widthheightA = \frac{width}{height}。按照以下的步驟進行計算:

  1. 變換到NDC空間中,NDC空間的範圍為[0,1][0, 1]

    Xndc=Xscreen+0.5widthYndc=Yscreen+0.5height X_{ndc} = \frac{X_{screen} + 0.5}{width} \\[5px] Y_{ndc} = \frac{Y_{screen} + 0.5}{height}

  2. 起點變換至中心

    X=2×Xndc1Y=2×Yndc1 X = 2 \times X_{ndc} - 1 \\ Y = 2 \times Y_{ndc} - 1

  3. 根據寬高比拉伸

    X=X×AY=Y X = X \times A \\ Y = Y

    一般規定了高為2,所以Y不需要改變。

  4. FOV控制視野範圍
    一般FOV有水平和垂直之分,作業中的FOV只有一種,即說明水平和垂直的FOV都一樣。
    在透視投影中說明的將點投影到近平面上的算式將其逆轉過來,得

    Xfinal=X×tan(fovx2)Yfinal=Y×tan(fovy2) X_{final} = X \times tan (\frac{fov_x}{2}) \\ Y_{final} = Y \times tan (\frac{fov_y}{2})

    重溫透視投影的算式(右手座標系)

    x=xdz=xztanθ2y=ydz=yztanθ2 x' = \frac{xd}{-z} = \frac{x}{-ztan\frac{\theta}{2}} \\ y' = \frac{yd}{-z} = \frac{y}{-ztan\frac{\theta}{2}}

結論

將推導中的式子總結,得:

Xfinal=2×(Xscreen+0.5width1)×A×tan(fovx2)Yfinal=2×(Yscreen+0.5height1)×tan(fovy2) X_{final} = 2 \times (\frac{X_{screen} + 0.5}{width} - 1) \times A \times tan(\frac{fov_x}{2}) \\[5px] Y_{final} = 2 \times (\frac{Y_{screen} + 0.5}{height} - 1)\times tan(\frac{fov_y}{2})

改變觀察方向

因為作業中的視野是看著(0, 0, -1)的,如何能旋轉視角呢?其實很簡單,只需要將求得的dir乘以旋轉矩陣便可。類似於下面的偽代碼:

1
2
3
4
// 求得的dir
Vector3f dir = Vector3f (x, y, -1);
float angle = 45;
Vector3f new_dir = get_x_rotation_matrix (angle) * dir;

相當於將Camera(投影平面)旋轉了45度角。

References

  1. Ray-Tracing: Generating Camera Rays
  2. GAMES 101: 作業5解析