用Python和Pygame寫遊戲從入門到精通(18)

發表於2015-12-18

3D是非常酷的技術,同時也就意味著更多的工作,上次的簡單介紹之後,這次還要講更多2D到3D的新概念。

基於時間的三維移動

我們使用Vector3類來進行3D上的移動,與2D非常類似,看下面一個例子:

直升機A在(-6, 2, 2)的位置上,目標是直升機B(7, 5, 10),A想摧毀B,所以發射了一枚火箭AB,現在我們得把火箭的運動軌跡過程給畫出來,否則一點發射敵機就炸了,多沒意思啊~~ 通過計算出兩者之間的向量為(13, 3, 8),然後單位化這個向量,這樣就可以在運動中用到了,下面的程式碼做了這些事情。

 

然後不停的重繪火箭的位置,用這個語句:
rocket_location += heading * time_passed_seconds * speed

不過我們還不能直接在pygame中繪製3D物體,得先學習一下下面講的,“如何把3D轉換為2D”。

3D透視

如果您初中美術認真學了的話,應該會知道這裡要講什麼,還記得當初我們是如何在紙上畫立方體的?

忘了?OK,從頭開始說起吧,儲存、計算3D座標是非常容易的,但是要把它展現到螢幕上就不那麼簡單了,因為pygame中所有的繪圖函式都只接受2D座標,因此,我們必須把這些3D的座標投影到2D的圖面上。

平行投影

最簡單的投影方法是——把第三個座標z座標給丟棄,用這樣的一個簡單的函式就可以做到:

儘管這樣的轉換簡單又快速,我們卻不能用它。為什麼?效果太糟糕了,我們甚至無法在最終的畫面上感受到一點立體的影子,這個世界看起來還是平的,沒有那個物體看起來比其他物體更遠或更近。就好像我下邊這幅圖一樣。

立體投影

在3D遊戲中使用的更為廣泛且合理的技術是立體投影,因為它的結果更為真實。立體投影把遠處的物體縮小了,也就是使用透視法(foreshortening),如下圖所示,然後下面是我們的轉換函式,看起來也很簡單:

 

與上一個轉換函式不同的是,這個轉換函式還接受一個d引數(後面討論),然後所有的x、y座標都會接受這個d的洗禮,同時z也會插一腳,把原本的座標進行縮放。

d的意思是視距(viewing distance),也就是攝像頭到3D世界物體在螢幕上的畫素體現之間的距離。比如說,一個在(10, 5, 100)的物體移動到了(11, 5, 100),視距是100的時候,它在螢幕上就剛好移動了1個畫素,但如果它的z不是100,或者視距不是100,那麼可能移動距離就不再是1個畫素的距離。有些抽象,不過玩過3D遊戲的話(這裡指國外的3D大作),都有一種滾輪調節遠近的功能,這就是視距(當然調的時候視野也會變化,這個下面說)。

在我們玩遊戲的時候,視距就為我們的眼睛到螢幕的直線距離(以畫素為單位)。

視野

那麼我們怎麼選取一個好的d呢?我們當然可以不斷調整實驗來得到一個,不過我們還可以通過視野(field of view)來計算一個出來。視野也就是在一個時刻能看到的角度。看一下左圖的視野和視距的關係,可以看到兩者是有制約關係,當視野角度(fov)增大的時候,d就會減小;而d增加的話,視野角度就會減小,能看到的東西也就變少了。

視野是決定在3D畫面上展現多少東西的絕好武器,然後我們還需要一個d來決定透視深度,使用一點點三角只是,我們就可以從fov計算出d,寫一下下面的程式碼學習學習:
在Internet上,你總是能找到99%以上的需要的別人寫好的程式碼。不過偶爾還是要自己寫一下的,不用擔心自己的數學是不及格的,這個很簡單~ 很多時候實際動手試一下,你就能明白更多。

fov角度可能取45~60°比較合適,這樣看起來很自然。當然每個人每個遊戲都有特別的地方,比如FPS的話,fov可能比較大;而策略性遊戲的fov角度會比較小,這樣可以看到更多的東西。很多時候還需要不停的變化fov,最明顯的CS中的狙擊槍(從沒玩過,不過聽過),開出來和關掉是完全不同的效果,改的就是視野角度。

今天又是補充了一大堆知識,等不及了吧~我們下一章就能看到一個用pygame畫就的3D世界了!

 

相關文章