04.02 【遊戲開發】聊聊 2D 遊戲視差背景的實現

【遊戲開發】聊聊 2D 遊戲視差背景的實現

來indienova官網,挖掘獨立遊戲的更多樂趣

【游戏开发】聊聊 2D 游戏视差背景的实现
【游戏开发】聊聊 2D 游戏视差背景的实现

引言

這次聊什麼呢?因為我們正在實現一個橫版遊戲,咱們這次就聊聊橫版遊戲裡非常重要的技術——視差背景。

作為橫版的 2D 遊戲而言,如果想要提升畫面效果,想必很多人想到的就是做視差背景。也因此市面上大部分橫版遊戲多多少少都會使用視差背景來增強遊戲畫面的視覺效果:

【游戏开发】聊聊 2D 游戏视差背景的实现

泰拉瑞亞的視差背景,是比較簡單的平鋪背景,沒有太多特效

【游戏开发】聊聊 2D 游戏视差背景的实现

Braid 中也使用了視差背景,但要比一般遊戲的複雜很多

這裡我們主要對其中的技術細節進行介紹。

什麼是視差背景?

簡單地說,視差背景其實就是通過多層次的背景來模擬透視視差效果:就是當發生移動時,離照相機越近的背景移動越快;反之越慢。這樣,我們的背景就會形成類似於透視視差的效果。

那麼,既然需要透視效果,為何不直接使用透視投影來做呢?這個原因是如果使用透視投影來產生視差的話,我們的遠景必須真的是一個非常大的背景,你如果想模擬出一百倍於近景的遠景,那麼可能就需要相應尺寸的背景貼圖。這種做法顯然是做不到的。當然,如果是3D 背景的話有其他方式,不過對於2D 遊戲而言,最直接有效的還是多層次背景模擬出視差效果。我們這裡也主要聊聊如果通過多層次背景滾動的方式實現視差效果。

在整個視差背景實現過程中,需要完成兩個主要工作:

  1. 實現單層背景的滾動;

  2. 複合多層背景的滾動,實現視差效果;

實現單層背景的滾動

背景滾動是實現視差效果的核心也是最重要的問題。背景滾動存在橫向和縱向兩種。所有使用視差背景的遊戲都會有橫向滾動的情況,而縱向滾動則未必都會有。我們這裡以橫向滾動來介紹背景滾動。我們有四種常規方式可以實現背景的滾動:

  1. 通過移動一個四邊形頂點的 UV 移動形成滾動,之後就稱之為 UV 滾動方式;

  2. 通過滾動移動多個連續的背景精靈形成滾動,之後就稱之為精靈滾動方式;

  3. 添加背景層照相機,移動照相機形成滾動,之後就稱之為照相機移動方式;

  4. 精靈滾動方式和照相機移動方式混合使用,之後就稱之為混合滾動方式;

為了更好地解釋這幾種實現方式,需要幾張圖片用於介紹。

我們使用一個黃框精靈代表屏幕取景區域:

【游戏开发】聊聊 2D 游戏视差背景的实现

接下來是三張可拼接的背景精靈:

【游戏开发】聊聊 2D 游戏视差背景的实现【游戏开发】聊聊 2D 游戏视差背景的实现
【游戏开发】聊聊 2D 游戏视差背景的实现

UV 滾動方式:

使用 UV 座標移動形成滾動的效果看起來是這樣的:

【游戏开发】聊聊 2D 游戏视差背景的实现

在 UV 座標移動的方法中,我們只是用一個和照相機取景區域一樣大的精靈作為背景渲染區域。然後通過調整它的 UV 座標和採樣方式實現平鋪背景以及背景滾動。具體實現步驟:

  1. 準備一個覆蓋整個屏幕的四邊形頂點,並使用它顯示背景貼圖;

  2. 調整 UV 座標和紋理之間的採樣方式,以實現紋理連續顯示;

  3. 移動時,修改四個頂點的 UV 座標形成滾動;

因為我們只使用一張精靈,我們區域採樣的方式就是通過 UV 座標。因此此方式下 UV 座標存在兩個作用:

  1. UV 座標的整數部分標記了當前採樣位置使用哪一張背景貼圖;

  2. UV 座標小數部分為選中背景貼圖的採樣 UV 座標;

因此,此精靈的 UV 座標必定會大於[0,1]區間。

如果背景使用的背景貼圖只有一張的話,這個問題很容易解決。我們只要設置圖形 API(OpenGL 或 DirectX,這裡以 OpenGL 為例)的紋理包裝類型(即所謂的 wrapping 類型)即可。所謂的包裝類型即指定了當 UV 座標值在[ 0,1 ]區間之外時,如何獲取紋理。那麼這裡,我們需要讓一張紋理重複出現。在 OpenGL 中,我們需要調用此函數來完成包裝類型的設置:glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );

稍微解釋一下此函數:glTexParameteri 函數會對指定的紋理的參數進行設置。我們這裡針對2D 紋理(第一參數GL_TEXTURE_2D)的 x 方向即橫向(第二參數GL_TEXTURE_WRAP_S)的包裝模式設置為重複出現的方式(第三參數GL_REPEAT)。

不過如果背景是多張不同的紋理連續出現的話,就不能使用上面的方法解決了。這個時候我們需要編寫一個簡單的 shader 在 shader 中完成 UV 座標映射。這裡截取出演示 demo 中,獲取紋理相關的 shader 代碼(GLSL 代碼)提供大家參考:

//我們有三張背景貼圖,對 UV 座標對3取模,得到使用哪一種背景貼圖。

int _index = int( mod( v_TexCoord.x, 3.0 ));

//使用此貼圖並使用 UV 座標的小數部分進行像素採樣。

gl_FragData[0] = texture( u_BackgroundTextures[_index], fract(v_TexCoord));

UV 方式有著非常良好的性能,但是缺點就是隻能處理簡單的平鋪背景,對於有著複雜結構或是效果的滾動背景沒有辦法使用。

精靈滾動方式:

使用精靈滾動形成滾動的效果看起來是這樣的:

【游戏开发】聊聊 2D 游戏视差背景的实现

這種方式應該是比較直接的。我們首先使用背景精靈拼接出背景取景區域覆蓋到的背景區域。然後在發生背景移動時,我們依然不需要移動背景取景區域,而是通過滾動移動所有的背景精靈來實現背景移動的效果。

這種方式實現簡單直接,但缺點是發生背景移動時,需要對所有的背景精靈進行移動。對於結構複雜元素較多的背景需要佔用更多的性能。

照相機移動方式:

使用照相機移動形成滾動的效果看起來是這樣的:

【游戏开发】聊聊 2D 游戏视差背景的实现

這種方式與精靈滾動方式正好相反。在這種方式下,我們需要使用背景精靈拼接出完整的背景。同時在背景移動時,不移動背景精靈轉而移動背景取景區域來實現背景移動效果。

這種方式在移動過程中由於只需要移動背景照相機,所以有種很好的移動性能。但是為了使用此方法。我們需要預先將整個背景全部拼接。這樣導致同時存在過多的背景精靈在場景中。如果使用的遊戲引擎沒有場景管理器或是場景管理器性能不佳的情況下,此方式反而會帶來額外的性能消耗。

混合滾動方式:

使用混合滾動方式形成的滾動效果看起來是這樣的:

【游戏开发】聊聊 2D 游戏视差背景的实现

顧名思義,混合移動混合了精靈移動和照相機移動兩種方式。我們在移動背景取景區域的同時,適時地滾動背景精靈。使得背景取景區域內的背景正確。

這種方式結合了精靈滾動方式和照相機移動方式。避免了精靈滾動方式移動過程中,因為需要移動所有背景精靈帶來的額外性能開銷;也避免了照相機移動方式中,需要預先構建完整的背景而導致場景中存在過多的背景精靈帶來的額外性能開銷。當然,和照相機移動方式一樣,避免不了每一層背景都需要有一個獨立的背景照相機。同時在代碼實現良好的情況下,性能比前兩者都要好。

四種方式的優劣

平均性能:

UV 滾動方式只使用了一個四邊形並且移動時也只是單純改變了 UV 採樣方式。它的性能是最好的;其次是混合滾動方式;照相機移動方式有更多的空間開銷,同時此開銷對性能的影響與遊戲引擎的場景管理模塊密切關聯;精靈方式則有最大的移動性能消耗。

對複雜背景的支持:

即四種方式所實現的背景可以有多複雜。UV 滾動方式礙於實現只能做簡單的平鋪背景的滾動效果;精靈滾動方式和混合滾動方式可以實現更為複雜一點的背景,可以在簡單的平鋪背景之上加入一些其他背景精靈元素;而照相機移動方式對背景的構建沒有要求,它可以支持非常複雜的背景。

是否可以無限延伸:

理論上四種方式都可以實現無限延伸。但是對於照相機移動方式來說,實現起來會比較麻煩。而另外三種方式都是循環利用同一個背景,所以天然支持無限延伸的背景。

複合多層背景的滾動,實現視差效果:

有了上面的工作,這一步也是順其自然就可以完成:

我們首先要構建多層背景,多層背景可以同時只是用一種滾動方式;也可以不同層背景使用不同的滾動方式。比如最遠的背景由於基本上都是簡單的平鋪可以使用 UV 滾動方式構建;而再近一點細節較多的背景層可以考慮後幾種滾動方式構建背景。

之後是移動,我們需要根據每一層背景的距離決定其在移動過程中的移動速度。速度如何決定並沒有統一的方法或是模式。總之,這一點聽聽美術們的意見是比較合適的。

其它問題

完成以上工作,我們的視差背景就算順利建立起來了。不過,在實現中我們依舊會碰到一些其他的問題:

比如當開發者構建了一個有著複雜結構的背景,且使用了除去照相機移動方式以外的其他背景滾動方式實現了背景滾動。可能需要將背景取景區域覆蓋的背景精靈左右都擴展一個背景精靈作為緩衝。以防止建立在背景精靈之上的背景佈景(比如開發者在表示平原的背景精靈之上,放了另一個樹的精靈作為此平原背景精靈的佈景)在顯示過程中出現突然出現和突然消失的情況。

或者在有些情況下,背景本身就會移動(比如雲層背景)或者是背景之上存在一些獨立移動的背景佈景。這個時候我們也需要對上面的背景滾動方式進行相應的調整。

也可能是背景上需要支持某些特效,這種情況下我們的背景也可能需要特殊處理。

這裡就不一一列舉了。這裡描述的是一些視差背景的基本細節,具體問題還需要在具體實現中留給開發者們自己去解決。

【游戏开发】聊聊 2D 游戏视差背景的实现


分享到:


相關文章: