多年之后馏颂,我最終決定分享我的作品集。
說實(shí)在的蔑舞,我從來沒有想過入偷,也沒法說清楚人們會(huì)如此喜歡它(作品集),但我真的很高興眉枕,能收到如此多的反饋和贊揚(yáng)恶复。
一些開發(fā)者請求我說明如何完成了它(作品集)怜森,需要說明的是,其實(shí)這只是一些簡單的技術(shù)谤牡。
這篇文章需要你具有一定的數(shù)學(xué)知識(shí)背景副硅,我努力使你盡可能的明白,即使你不是一個(gè)開發(fā)者翅萤。
希望你會(huì)喜歡我作品中的“幕后花絮”恐疲!
概念:
起初,我想做一些原始的套么,令人愉悅的培己,好玩的,可理解的事情胚泌。
我是一個(gè)超級玩家省咨,去年也大量的使用了 WebGl 開發(fā)了游戲,用游戲內(nèi)容去實(shí)施是一個(gè)顯而易見的選擇玷室。當(dāng)我還是個(gè)孩子的時(shí)候零蓉,就很喜歡遠(yuǎn)程遙控汽車,并且在游戲機(jī)上花費(fèi)了大量的時(shí)間去玩一款叫做 Micro Machine 的游戲穷缤。所以最終的結(jié)果是敌蜂,我決定去構(gòu)建一片天地,在那里你可以自由自在得駕駛汽車津肛。
我發(fā)現(xiàn)物理學(xué)在網(wǎng)頁中并沒有被很好的使用章喉,這就是為什么構(gòu)成我宇宙的元素是“可碰撞的”。另外身坐,我選擇不使用任何接口囊陡,這會(huì)讓體驗(yàn)更加身臨其境。
很大一部分靈感來源于我是?Gustavo Henrique?的粉絲掀亥,因此我決定嘗試這種平整的,具有圓角妥色,多彩小巧的建筑風(fēng)格搪花,
我希望我的作品是完全個(gè)人的,因此我決定獨(dú)自進(jìn)行全部的開發(fā)嘹害。
我知道這個(gè)項(xiàng)目會(huì)花費(fèi)我大量的時(shí)間撮竿,因此我盡可能的讓我自己感到快樂。(相信我笔呀,我在那輛車上花費(fèi)了大量的時(shí)間埋下彩蛋幢踏。)
我相信一句話“你所能制作的最好的游戲,是你愿意花費(fèi)大量時(shí)間去玩的游戲许师》坎酰”
游戲開始
游戲的開始是空間中彈出一塊陸地僚匆,汽車從天而降并彈起,這時(shí)你會(huì)注意到物理學(xué)的設(shè)計(jì)搭幻。
唯一需要說明的教程是咧擂,請用戶直接在地面上用方向鍵進(jìn)行移動(dòng)(它沒有在任何地方顯示,但你也可以按照玩家習(xí)慣的方式檀蹋,使用 WQSD 或者法式鍵盤中的 ZQSD 進(jìn)行移動(dòng)松申。)
汽車的位置不是一個(gè)隨機(jī)的選擇:我希望確保你能在體驗(yàn)到開始就碰到 “BRUNO SIMON” 的標(biāo)題,這可以最大限度的理解元素是可以被移動(dòng)的俯逾。
為了幫助和指導(dǎo)用戶到達(dá)正確的方向贸桶,我用了一些簡單的方法,例如:
這些瓦片的作用象征著有一些線索桌肴,幫助用戶很容易的明白那個(gè)方向有更多的東西皇筛。
墻面是邊界。
標(biāo)牌是识脆,沒錯(cuò)设联,你懂得,那是標(biāo)牌灼捂。
有交互的區(qū)域离例,在那里當(dāng)你開車經(jīng)過或者用鼠標(biāo)懸浮,它將會(huì)展開悉稠。
最后宫蛆,這片天地被分成五個(gè)區(qū)域:
? ? 介紹如何導(dǎo)航的簡介
? ? 十字路口充當(dāng)和其他部分的指南和連接
? ? 在廣場上玩物理游戲
? ? 我一直在從事的項(xiàng)目(我們不要忘記這是一個(gè)作品集)
? ? 有關(guān)如何與我聯(lián)系的補(bǔ)充信息
我發(fā)布了這個(gè)作品集之后,被問到最多的問題是如何在這個(gè)廣場上加速的猛。對我而言顯然是要用 shift 了耀盗,但是對非游戲玩家卻不是。所以我決定增加更多的說明卦尊。(但為了信息過多叛拷,并不直接展示在簡介中。)
調(diào)試
尋找最佳的顏色岂却,重力忿薇,速度,質(zhì)量躏哩,等署浩。有一個(gè)調(diào)試盤非常重要。作為一個(gè)老派的開發(fā)者扫尺,Dat.GUI?眾所周知筋栋,我將在項(xiàng)目中一直使用它。(少數(shù)幾個(gè)選擇)
貫穿項(xiàng)目的始終正驻,我一直在調(diào)試參數(shù)弊攘,以便于獲得最佳的組合抢腐。
使用這種調(diào)試工具可能會(huì)對性能造成不良影響,因此應(yīng)確保在生產(chǎn)時(shí)完全停用它肴颊。一個(gè)不錯(cuò)的技巧是僅對特定網(wǎng)址啟用此功能https://bruno-simon.com/#debug(如果你想玩氓栈,它也可以運(yùn)行。)
渲染
我是用Three.js?對 WebGl 渲染的婿着。我用了這個(gè)庫很多年授瘦,如果沒有它,我也不可能完成這個(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è)場景里沒有亮光和陰影挪捕。至少?zèng)]有“普遍意義”上的亮光和陰影粗梭。這只是幻覺。
Matcaps
Matcaps 是一款很古老但是很有效率的技術(shù)级零。Matcaps 用于對“著色”對象添加紋理断医。
它使用相機(jī)提供的常規(guī)關(guān)系來選擇性的提供紋理上的顏色。
該技術(shù)的缺點(diǎn)是您無法使用動(dòng)態(tài)光源奏纪,并且如果您繞轉(zhuǎn)對象鉴嗤,則光源總是相對于相機(jī)來自同一方向。
地板
地板由始終填充屏幕的簡單平面組成序调。直接用 JS 指定和發(fā)送需要?jiǎng)?chuàng)造的 2X2 紋理醉锅,著色器就會(huì)用 UV 為每個(gè)角進(jìn)行著色。然后发绢,將這些顏色自然插入整個(gè)表面硬耍。
輕輕地彈起
為了更加真實(shí)和更加清晰的效果,我想要增加一個(gè)輕輕彈起的效果朴摊,由于目前幾乎不可能獲得具有良好分辨率的真正的WebGL輕彈,因此我不得不找到一種解決方案此虑。
由于地板是場景中最突出的形狀甚纲,而橙色是鮮艷的,所以我只是在偽造地板的彈跳朦前。
我只計(jì)算了頂點(diǎn)到地面的距離介杆,然后乘以“絕對法線”和上軸之間的點(diǎn)積鹃操。
理論的基礎(chǔ),簡單來說:越靠近地面春哨,橙色就會(huì)越多荆隘。
陰影
這里有兩種類型的陰影。
第一種是靜態(tài)陰影對于靜態(tài)的元素赴背。
我只是簡單的在 Blender 中進(jìn)行烘烤椰拒,以 PNG-8 的格式進(jìn)行保存,并對其盡可能的壓縮凰荚。
第二種是動(dòng)態(tài)的陰影對于移動(dòng)的元素燃观。
這些實(shí)現(xiàn)起來有些棘手。
我在每個(gè)移動(dòng)元素下面添加了一個(gè)平面便瑟,并根據(jù)以下內(nèi)容更新了每個(gè)平面:
相關(guān)對象的旋轉(zhuǎn)缆毁,
它的位置,
它相對地面的距離到涂,
太陽的方向
這些平面上有陰影紋理脊框,并且對象越高,透明度越低践啄。
后期處理
為了使其看起來更加美觀浇雹,我在屏幕的頂部和底部增加模糊的水平和垂直線。
我還在左側(cè)增加一個(gè)巨大的照明點(diǎn)往核,與假定的太陽光方向一致箫爷,使其更加真實(shí),并帶來良好和溫暖的感覺聂儒。
相機(jī)
相機(jī)是一種簡單的透視圖虎锚,可以看著汽車并隨車行駛。
然后衩婚,我添加了一個(gè)簡單的緩動(dòng)來平滑運(yùn)動(dòng)并讓用戶感覺到速度窜护。
許多測試人員告訴我,“項(xiàng)目”中部分內(nèi)容的不可見非春。為了解決這個(gè)問題柱徙,當(dāng)用戶進(jìn)入這個(gè)部分時(shí),我將相機(jī)的位置調(diào)整為從上向下看奇昙。
我還添加了用滾輪進(jìn)行放大縮小的功能护侮,提高了可讀性。
物理
在物理方面储耐,我決定選擇3D引擎羊初。做到這一點(diǎn)的一種方法可能是使用2D引擎并將物體放在地板上,但我想獲得更多的真實(shí)感。
Cannon.js?是一個(gè)非常不錯(cuò)的庫长赞,非常實(shí)用晦攒,但是它缺少實(shí)例,因此我在引用庫代碼時(shí)花費(fèi)了大量的時(shí)間來理解應(yīng)該怎么做得哆。在游戲中玩了幾分鐘后脯颜,我的分辨率下降了。這是因?yàn)槟J(rèn)情況下對象并不會(huì)被清理贩据,這意味著栋操,碰到的每個(gè)對象,即使它們幾乎沒有移動(dòng)乐设,也需要測試每個(gè)對象在每個(gè)像素上的影響讼庇。
為了簡化物理模型,我創(chuàng)建了更詳細(xì)的模型匹配最初的外觀近尚。Cannon.js 可以處理這些原始模型蠕啄,然后我根據(jù)原始坐標(biāo)更新了每一像素的 Three.js 集成。
天線的動(dòng)畫是完全按照我的想法完成的戈锻,沒有任何物理考量歼跟。我根據(jù)汽車的反向加速度旋轉(zhuǎn)天線,然后用一個(gè)力將其推回中心格遭。推力越大哈街,天線越遠(yuǎn)。
建模
我用Blender?進(jìn)行建模拒迅。我已經(jīng)使用它一年了骚秦,大多數(shù)用于網(wǎng)頁項(xiàng)目,我認(rèn)為它很棒璧微。一開始作箍,它并不易于上手,但你一旦開始使用前硫,對控制胞得,快捷方式和界面都是非常有意義的。
我不是 3D 動(dòng)畫方面的專家屹电,因此我覺得這是一個(gè)非常好的練習(xí)的機(jī)會(huì)阶剑。我建模了一切東西:樹木,自己危号,保齡球牧愁,我的狗,是的外莲,我把它放進(jìn)了我的作品集猪半。(順便說一句,希望你能知道,他的名字叫做 Sudo办龄。)
在此過程中,我分別對5個(gè)部分和一些特定對象建模淋昭。
絕大多數(shù)情況我會(huì)使用Eevee 進(jìn)行建模俐填。Eevee 是?Blender 用于實(shí)時(shí)渲染的引擎。它使用 GPU翔忽,大多數(shù)情況下英融,他的運(yùn)行速度也快于?Cycles。不幸的是歇式,它有一些限制驶悟,不過我的場景很簡單,所以這不是問題材失。
我使用了帶 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)憎兽,聲音是必不可少的冷离。就像我之前說過的,我希望這個(gè)項(xiàng)目的所有事情都是由我自己獨(dú)立來完成的纯命。
為了增加真實(shí)感西剥,我需要在聲音中添加一些隨機(jī)的元素。舉個(gè)例子亿汞,在實(shí)際生活中瞭空,即使你用相同的速度打擊相同的點(diǎn),發(fā)出的聲音也不是完全相同的。
據(jù)我所知咆畏,Howler.js可以根據(jù)速度的不同控制聲音的不同南捂,所以我決定使用它。
像一塊磚頭掉下來的定時(shí)聲音是由以下幾部分組成的:
檢測物理中的碰撞旧找,
測試它的速度溺健,
從一組多個(gè)相似的聲音中隨機(jī)播放一個(gè),
隨機(jī)調(diào)整音量和速度钮蛛,
然后鞭缭,我還增加了同時(shí)播放聲音數(shù)量的的限制,防止鼓膜破裂流血魏颓。
對于引擎岭辣,我測試不同速度下引擎的多次重復(fù)音。
我根據(jù)汽車的加速度添加了速度變化時(shí)的聲音甸饱。
說實(shí)在的沦童,對于結(jié)果我始終不能完全滿意,但我相信叹话,對于一個(gè)非聲音設(shè)計(jì)師來說搞动,這是一個(gè)不錯(cuò)的開端。
不幸的是渣刷,現(xiàn)在很多瀏覽器阻止任何聲音自動(dòng)播放鹦肿,除非用戶與頁面進(jìn)行交互,而且僅限于觸碰和點(diǎn)擊辅柴。(令人難過的是箩溃,沒有鍵盤的交互指令。)這就是開始按鈕背后的故事碌嘀。但是最后我發(fā)現(xiàn)涣旨,即使整個(gè)網(wǎng)站都很輕巧,這也是加載的最好時(shí)機(jī)股冗。
顯然霹陡,我還需要找一個(gè)介紹這個(gè)世界的聲音。在尋求最佳音效的過程中止状,我發(fā)現(xiàn)了這種清爽的紙張翻頁的聲音烹棉。我嘗試對它進(jìn)行了一系列編輯,創(chuàng)建了一個(gè)動(dòng)畫怯疤,當(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)畫標(biāo)題
或許你看到了,這一頁的標(biāo)題是一個(gè)動(dòng)畫聪黎。如果你向前走买优,動(dòng)畫就會(huì)向前走,反之亦然挺举。不幸的是,標(biāo)題不能被頻繁更新烘跺。
磚墻
我通過簡單的函數(shù)創(chuàng)建了不同形狀的墻湘纵。實(shí)際上,也正是這時(shí)候滤淳,我決定創(chuàng)建一個(gè)游樂場梧喷。加大油門,保持速度脖咐,全力穿過這個(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)行測試時(shí),我感到非常驚喜胶果,因?yàn)榉直媛蔬€不錯(cuò)匾嘱。但是,出于性能和可用性的考慮早抠,我應(yīng)用了一些優(yōu)化措施霎烙,例如消除模糊,限制像素比率并停用了Three.js對象的矩陣自動(dòng)更新蕊连。
控件部分悬垃,我添加了簡單的按鈕來控制速度,并添加了操縱桿來控制轉(zhuǎn)向甘苍。我知道盗忱,“沒有接口”,但是在手機(jī)上我實(shí)在找不到其他直接的解決方案羊赵。