前言

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

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

此篇文章只說明第2題。

推導

首先,已知Camera的世界座標。並根據代碼,得知投影平面位於Camera的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

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