透視投影


在 p5.js 中繪製 3D 物件,若物件很大,你會發現 z 正方向那面看來較大,負方向那面看來較小,構成一種遠近感,例如:

這是因為 p5.js 預設套用透視投影(Perspective projection),這跟在紙面上繪畫時會採用透視法是相同的原理,為描繪的對象找個消失點,邊繪製時往消失點方向進行,這會使得近面看來較大,遠面看來較小:

透視投影

在紙面上繪畫運用透視技法時,實際上觀察點在哪呢?其實是與消失點相反的方向:

透視投影

在上圖中,若中間的軸線代表畫面,離觀察點較遠的頂點投射至畫面時,是會低於離觀察點較近的頂點,因此才會造成近面看來較大,遠面看來較小的視覺效果。

計算時就可以基於觀察點,而在自定義空間時,〈正交投影〉 會是個立方體,然而透視投影時,會是個錐形體,或稱為視體(Viewing frustum),也就是觀察範圍:

透視投影

觀察點的近面距離(near)、遠面距離(far),以及觀察點的視場角(fov)、近面寬高比(aspect)(也就是畫布寬高比例),決定了要觀察的範圍,也就是模型必須位於圖中藍色部份,才會被繪製出來,計算時視場角,可以使用近面上下兩個邊的角度(fovy):

透視投影

p5.js 提供了 perspective,可以讓你指定 fovyaspectnearfar 等參數,p5.js 預設會使用 PI / 3.0, width / height, eyeZ / 10.0, eyeZ * 10.0eyeZ(height / 2.0) / tan(PI * 60.0 / 360.0)

增加 fovy、減少 near、增加 far 等,都會讓觀察範圍變大:

透視投影

觀察的範圍變大,然而還是要畫進同尺寸畫布,最後看到的 3D 物件就會變小。例如:

perspective 也可以跟 camera 結合使用(底層也是兩個轉換矩陣的運算),同樣地,這時可以想像,相機與觀察範圍的近面是連動的:

透視投影

如果你移動相機,觀察範圍也會跟著一起動:

透視投影

除了透過 perspective 來進行透視投影之外,p5.js 也提供了 frustum,可指定 leftrightbottomtopnearfar 來定義視體,其中 leftrightbottomtop 是近面的邊界:

透視投影

使用哪個,就看你的需求,底下是個 frustum 示範: