多年之后,我最終決定分享我的作品集。
說(shuō)實(shí)在的,我從來(lái)沒(méi)有想過(guò),也沒(méi)法說(shuō)清楚人們會(huì)如此喜歡它(作品集),但我真的很高興,能收到如此多的反饋和贊揚(yáng)。
一些開(kāi)發(fā)者請(qǐng)求我說(shuō)明如何完成了它(作品集),需要說(shuō)明的是,其實(shí)這只是一些簡(jiǎn)單的技術(shù)。
這篇文章需要你具有一定的數(shù)學(xué)知識(shí)背景,我努力使你盡可能的明白,即使你不是一個(gè)開(kāi)發(fā)者。
希望你會(huì)喜歡我作品中的“幕后花絮”!
概念:
起初,我想做一些原始的,令人愉悅的,好玩的,可理解的事情。
我是一個(gè)超級(jí)玩家,去年也大量的使用了 WebGl 開(kāi)發(fā)了游戲,用游戲內(nèi)容去實(shí)施是一個(gè)顯而易見(jiàn)的選擇。當(dāng)我還是個(gè)孩子的時(shí)候,就很喜歡遠(yuǎn)程遙控汽車,并且在游戲機(jī)上花費(fèi)了大量的時(shí)間去玩一款叫做 Micro Machine 的游戲。所以最終的結(jié)果是,我決定去構(gòu)建一片天地,在那里你可以自由自在得駕駛汽車。
我發(fā)現(xiàn)物理學(xué)在網(wǎng)頁(yè)中并沒(méi)有被很好的使用,這就是為什么構(gòu)成我宇宙的元素是“可碰撞的”。另外,我選擇不使用任何接口,這會(huì)讓體驗(yàn)更加身臨其境。
很大一部分靈感來(lái)源于我是?Gustavo Henrique?的粉絲,因此我決定嘗試這種平整的,具有圓角,多彩小巧的建筑風(fēng)格,
我希望我的作品是完全個(gè)人的,因此我決定獨(dú)自進(jìn)行全部的開(kāi)發(fā)。
我知道這個(gè)項(xiàng)目會(huì)花費(fèi)我大量的時(shí)間,因此我盡可能的讓我自己感到快樂(lè)。(相信我,我在那輛車上花費(fèi)了大量的時(shí)間埋下彩蛋。)
我相信一句話“你所能制作的最好的游戲,是你愿意花費(fèi)大量時(shí)間去玩的游戲?!?/p>
游戲開(kāi)始
游戲的開(kāi)始是空間中彈出一塊陸地,汽車從天而降并彈起,這時(shí)你會(huì)注意到物理學(xué)的設(shè)計(jì)。
唯一需要說(shuō)明的教程是,請(qǐng)用戶直接在地面上用方向鍵進(jìn)行移動(dòng)(它沒(méi)有在任何地方顯示,但你也可以按照玩家習(xí)慣的方式,使用 WQSD 或者法式鍵盤中的 ZQSD 進(jìn)行移動(dòng)。)
汽車的位置不是一個(gè)隨機(jī)的選擇:我希望確保你能在體驗(yàn)到開(kāi)始就碰到 “BRUNO SIMON” 的標(biāo)題,這可以最大限度的理解元素是可以被移動(dòng)的。
為了幫助和指導(dǎo)用戶到達(dá)正確的方向,我用了一些簡(jiǎn)單的方法,例如:
這些瓦片的作用象征著有一些線索,幫助用戶很容易的明白那個(gè)方向有更多的東西。
墻面是邊界。
標(biāo)牌是,沒(méi)錯(cuò),你懂得,那是標(biāo)牌。
有交互的區(qū)域,在那里當(dāng)你開(kāi)車經(jīng)過(guò)或者用鼠標(biāo)懸浮,它將會(huì)展開(kāi)。
最后,這片天地被分成五個(gè)區(qū)域:
? ? 介紹如何導(dǎo)航的簡(jiǎn)介
? ? 十字路口充當(dāng)和其他部分的指南和連接
? ? 在廣場(chǎng)上玩物理游戲
? ? 我一直在從事的項(xiàng)目(我們不要忘記這是一個(gè)作品集)
? ? 有關(guān)如何與我聯(lián)系的補(bǔ)充信息
我發(fā)布了這個(gè)作品集之后,被問(wèn)到最多的問(wèn)題是如何在這個(gè)廣場(chǎng)上加速。對(duì)我而言顯然是要用 shift 了,但是對(duì)非游戲玩家卻不是。所以我決定增加更多的說(shuō)明。(但為了信息過(guò)多,并不直接展示在簡(jiǎn)介中。)
調(diào)試
尋找最佳的顏色,重力,速度,質(zhì)量,等。有一個(gè)調(diào)試盤非常重要。作為一個(gè)老派的開(kāi)發(fā)者,Dat.GUI?眾所周知,我將在項(xiàng)目中一直使用它。(少數(shù)幾個(gè)選擇)
貫穿項(xiàng)目的始終,我一直在調(diào)試參數(shù),以便于獲得最佳的組合。
使用這種調(diào)試工具可能會(huì)對(duì)性能造成不良影響,因此應(yīng)確保在生產(chǎn)時(shí)完全停用它。一個(gè)不錯(cuò)的技巧是僅對(duì)特定網(wǎng)址啟用此功能https://bruno-simon.com/#debug(如果你想玩,它也可以運(yùn)行。)
渲染
我是用Three.js?對(duì) WebGl 渲染的。我用了這個(gè)庫(kù)很多年,如果沒(méi)有它,我也不可能完成這個(gè)項(xiàng)目。原生的 WebGl 已經(jīng)優(yōu)化的足夠好,但如果要實(shí)現(xiàn)相同的結(jié)果,則需要做很多額外的工作。
Samuel Honigstein (@samsyyyy) 用?VAO (Vertex Array Object) 為我提供了一個(gè)優(yōu)化版本的方案,極大地減少了 WebGl 的調(diào)用次數(shù)。
為了獲得更好的分辨率,我用了很多的方法,但有一點(diǎn)你需要明白,這個(gè)場(chǎng)景里沒(méi)有亮光和陰影。至少?zèng)]有“普遍意義”上的亮光和陰影。這只是幻覺(jué)。
Matcaps
Matcaps 是一款很古老但是很有效率的技術(shù)。Matcaps 用于對(duì)“著色”對(duì)象添加紋理。
它使用相機(jī)提供的常規(guī)關(guān)系來(lái)選擇性的提供紋理上的顏色。
該技術(shù)的缺點(diǎn)是您無(wú)法使用動(dòng)態(tài)光源,并且如果您繞轉(zhuǎn)對(duì)象,則光源總是相對(duì)于相機(jī)來(lái)自同一方向。
地板
地板由始終填充屏幕的簡(jiǎn)單平面組成。直接用 JS 指定和發(fā)送需要?jiǎng)?chuàng)造的 2X2 紋理,著色器就會(huì)用 UV 為每個(gè)角進(jìn)行著色。然后,將這些顏色自然插入整個(gè)表面。
輕輕地彈起
為了更加真實(shí)和更加清晰的效果,我想要增加一個(gè)輕輕彈起的效果,由于目前幾乎不可能獲得具有良好分辨率的真正的WebGL輕彈,因此我不得不找到一種解決方案。
由于地板是場(chǎng)景中最突出的形狀,而橙色是鮮艷的,所以我只是在偽造地板的彈跳。
我只計(jì)算了頂點(diǎn)到地面的距離,然后乘以“絕對(duì)法線”和上軸之間的點(diǎn)積。
理論的基礎(chǔ),簡(jiǎn)單來(lái)說(shuō):越靠近地面,橙色就會(huì)越多。
陰影
這里有兩種類型的陰影。
第一種是靜態(tài)陰影對(duì)于靜態(tài)的元素。
我只是簡(jiǎn)單的在 Blender 中進(jìn)行烘烤,以 PNG-8 的格式進(jìn)行保存,并對(duì)其盡可能的壓縮。
第二種是動(dòng)態(tài)的陰影對(duì)于移動(dòng)的元素。
這些實(shí)現(xiàn)起來(lái)有些棘手。
我在每個(gè)移動(dòng)元素下面添加了一個(gè)平面,并根據(jù)以下內(nèi)容更新了每個(gè)平面:
相關(guān)對(duì)象的旋轉(zhuǎn),
它的位置,
它相對(duì)地面的距離,
太陽(yáng)的方向
這些平面上有陰影紋理,并且對(duì)象越高,透明度越低。
后期處理
為了使其看起來(lái)更加美觀,我在屏幕的頂部和底部增加模糊的水平和垂直線。
我還在左側(cè)增加一個(gè)巨大的照明點(diǎn),與假定的太陽(yáng)光方向一致,使其更加真實(shí),并帶來(lái)良好和溫暖的感覺(jué)。
相機(jī)
相機(jī)是一種簡(jiǎn)單的透視圖,可以看著汽車并隨車行駛。
然后,我添加了一個(gè)簡(jiǎn)單的緩動(dòng)來(lái)平滑運(yùn)動(dòng)并讓用戶感覺(jué)到速度。
許多測(cè)試人員告訴我,“項(xiàng)目”中部分內(nèi)容的不可見(jiàn)。為了解決這個(gè)問(wèn)題,當(dāng)用戶進(jìn)入這個(gè)部分時(shí),我將相機(jī)的位置調(diào)整為從上向下看。
我還添加了用滾輪進(jìn)行放大縮小的功能,提高了可讀性。
物理
在物理方面,我決定選擇3D引擎。做到這一點(diǎn)的一種方法可能是使用2D引擎并將物體放在地板上,但我想獲得更多的真實(shí)感。
Cannon.js?是一個(gè)非常不錯(cuò)的庫(kù),非常實(shí)用,但是它缺少實(shí)例,因此我在引用庫(kù)代碼時(shí)花費(fèi)了大量的時(shí)間來(lái)理解應(yīng)該怎么做。在游戲中玩了幾分鐘后,我的分辨率下降了。這是因?yàn)槟J(rèn)情況下對(duì)象并不會(huì)被清理,這意味著,碰到的每個(gè)對(duì)象,即使它們幾乎沒(méi)有移動(dòng),也需要測(cè)試每個(gè)對(duì)象在每個(gè)像素上的影響。
為了簡(jiǎn)化物理模型,我創(chuàng)建了更詳細(xì)的模型匹配最初的外觀。Cannon.js 可以處理這些原始模型,然后我根據(jù)原始坐標(biāo)更新了每一像素的 Three.js 集成。
天線的動(dòng)畫(huà)是完全按照我的想法完成的,沒(méi)有任何物理考量。我根據(jù)汽車的反向加速度旋轉(zhuǎn)天線,然后用一個(gè)力將其推回中心。推力越大,天線越遠(yuǎn)。
建模
我用Blender?進(jìn)行建模。我已經(jīng)使用它一年了,大多數(shù)用于網(wǎng)頁(yè)項(xiàng)目,我認(rèn)為它很棒。一開(kāi)始,它并不易于上手,但你一旦開(kāi)始使用,對(duì)控制,快捷方式和界面都是非常有意義的。
我不是 3D 動(dòng)畫(huà)方面的專家,因此我覺(jué)得這是一個(gè)非常好的練習(xí)的機(jī)會(huì)。我建模了一切東西:樹(shù)木,自己,保齡球,我的狗,是的,我把它放進(jìn)了我的作品集。(順便說(shuō)一句,希望你能知道,他的名字叫做 Sudo。)
在此過(guò)程中,我分別對(duì)5個(gè)部分和一些特定對(duì)象建模。
絕大多數(shù)情況我會(huì)使用Eevee 進(jìn)行建模。Eevee 是?Blender 用于實(shí)時(shí)渲染的引擎。它使用 GPU,大多數(shù)情況下,他的運(yùn)行速度也快于?Cycles。不幸的是,它有一些限制,不過(guò)我的場(chǎng)景很簡(jiǎn)單,所以這不是問(wèn)題。
我使用了帶 Draco 壓縮功能的 GLTF 導(dǎo)出了每個(gè)部分。在這個(gè)案例中,Draco 的作用是實(shí)時(shí)游戲修改器。根據(jù)幾何圖形的不同,文件壓縮了 50% 至 70%。我用法線和碰撞圖元導(dǎo)出模型,并盡可能減少數(shù)據(jù)量。
Eevee 由于技術(shù)原因不支持烘焙。幸運(yùn)的是,Eevee和Cycles的渲染效果非常相似。我只需要切換至 Cycles 做地板陰影的烘焙,將它保存為 PNG-8 格式, 然后用?tinyPNG?進(jìn)行壓縮。
聲音
也許你已經(jīng)注意到了,我不是一個(gè)聲音的設(shè)計(jì)師。但是我完全相信,在數(shù)字產(chǎn)品中,為了獲得身臨其境的體驗(yàn),聲音是必不可少的。就像我之前說(shuō)過(guò)的,我希望這個(gè)項(xiàng)目的所有事情都是由我自己獨(dú)立來(lái)完成的。
為了增加真實(shí)感,我需要在聲音中添加一些隨機(jī)的元素。舉個(gè)例子,在實(shí)際生活中,即使你用相同的速度打擊相同的點(diǎn),發(fā)出的聲音也不是完全相同的。
據(jù)我所知,Howler.js可以根據(jù)速度的不同控制聲音的不同,所以我決定使用它。
像一塊磚頭掉下來(lái)的定時(shí)聲音是由以下幾部分組成的:
檢測(cè)物理中的碰撞,
測(cè)試它的速度,
從一組多個(gè)相似的聲音中隨機(jī)播放一個(gè),
隨機(jī)調(diào)整音量和速度,
然后,我還增加了同時(shí)播放聲音數(shù)量的的限制,防止鼓膜破裂流血。
對(duì)于引擎,我測(cè)試不同速度下引擎的多次重復(fù)音。
我根據(jù)汽車的加速度添加了速度變化時(shí)的聲音。
說(shuō)實(shí)在的,對(duì)于結(jié)果我始終不能完全滿意,但我相信,對(duì)于一個(gè)非聲音設(shè)計(jì)師來(lái)說(shuō),這是一個(gè)不錯(cuò)的開(kāi)端。
不幸的是,現(xiàn)在很多瀏覽器阻止任何聲音自動(dòng)播放,除非用戶與頁(yè)面進(jìn)行交互,而且僅限于觸碰和點(diǎn)擊。(令人難過(guò)的是,沒(méi)有鍵盤的交互指令。)這就是開(kāi)始按鈕背后的故事。但是最后我發(fā)現(xiàn),即使整個(gè)網(wǎng)站都很輕巧,這也是加載的最好時(shí)機(jī)。
顯然,我還需要找一個(gè)介紹這個(gè)世界的聲音。在尋求最佳音效的過(guò)程中,我發(fā)現(xiàn)了這種清爽的紙張翻頁(yè)的聲音。我嘗試對(duì)它進(jìn)行了一系列編輯,創(chuàng)建了一個(gè)動(dòng)畫(huà),當(dāng)聲音播放時(shí),所有的物體都從地面向上升起。我認(rèn)為這還挺酷的。
細(xì)節(jié)
我是Metal Gear Solid系列游戲的忠實(shí)粉絲,Hideo Kojima(MGS的導(dǎo)演和設(shè)計(jì)者)教會(huì)了一件事,即使并非每個(gè)用戶都會(huì)注意到這些細(xì)節(jié),也要花時(shí)間打造它。例如:
背光燈
你是否注意到汽車倒車燈是由用戶倒車或使用制動(dòng)器而亮起的?
動(dòng)畫(huà)標(biāo)題
或許你看到了,這一頁(yè)的標(biāo)題是一個(gè)動(dòng)畫(huà)。如果你向前走,動(dòng)畫(huà)就會(huì)向前走,反之亦然。不幸的是,標(biāo)題不能被頻繁更新。
磚墻
我通過(guò)簡(jiǎn)單的函數(shù)創(chuàng)建了不同形狀的墻。實(shí)際上,也正是這時(shí)候,我決定創(chuàng)建一個(gè)游樂(lè)場(chǎng)。加大油門,保持速度,全力穿過(guò)這個(gè)墻實(shí)在令人滿意。
我在積木位置上添加了一些隨機(jī)性,以獲得更多的真實(shí)感。
圖塊
地板上的圖塊用于創(chuàng)建路徑并引導(dǎo)用戶。我只創(chuàng)建了5個(gè)不同的圖塊,隨機(jī)旋轉(zhuǎn)它們,并確保彼此之間永遠(yuǎn)不會(huì)有相同的圖塊。
移動(dòng)端
當(dāng)我在移動(dòng)設(shè)備上進(jìn)行測(cè)試時(shí),我感到非常驚喜,因?yàn)榉直媛蔬€不錯(cuò)。但是,出于性能和可用性的考慮,我應(yīng)用了一些優(yōu)化措施,例如消除模糊,限制像素比率并停用了Three.js對(duì)象的矩陣自動(dòng)更新。
控件部分,我添加了簡(jiǎn)單的按鈕來(lái)控制速度,并添加了操縱桿來(lái)控制轉(zhuǎn)向。我知道,“沒(méi)有接口”,但是在手機(jī)上我實(shí)在找不到其他直接的解決方案。