四分鐘四十億年!國(guó)外小哥在GPU上模擬世界
四十億年里的地球,是什么樣子?
最近,一位外國(guó)小哥寫了一個(gè)程序,在幾分鐘內(nèi),就模擬了一顆類地行星的完整歷史。
這個(gè)實(shí)現(xiàn)是完全用GLSL片段著色器編寫的,模擬的更新速度為每秒60幀。
1 原行星
這個(gè)故事始于四億五億年前,有一塊熔巖……
早期的地球是一顆原行星,溫度熾熱,且因小行星撞擊而布滿隕石坑。
由于這個(gè)地球模擬完全是按程序生成的,沒有預(yù)先渲染的紋理,因此第一個(gè)任務(wù),就是生成該地形的地圖。
要計(jì)算給定經(jīng)度和緯度處的地形高度,首先要轉(zhuǎn)換為3D笛卡爾坐標(biāo):
vec3 p = 1.5 * vec3(
sin(lon*PI/180.) * cos(lat*PI/180.),
sin(lat*PI/180.),
cos(lon*PI/180.) * cos(lat*PI/180.));
現(xiàn)在,小行星的大小各不相同,因此產(chǎn)生的隕石坑也不盡相同。
為了適應(yīng)這種情況,著色器迭代了五級(jí)細(xì)節(jié),將大小逐漸減小的隕石坑層層疊加。
fBM() 用于生成地形、云、樹木分布、它們的顏色變化以及頂篷細(xì)節(jié)
為了使隕石坑具有逼真的凹凸不平的外觀,小哥在隕石坑中混入了一些分?jǐn)?shù)布朗運(yùn)動(dòng)噪音,并按比例調(diào)整,使最大的隕石坑對(duì)地形的影響最大。
float height = 0.;
for (float i = 0.; i < 5.; i++) {float c = craters(0.4 * pow(2.2, i) * p);float noise = 0.4 * exp(-3.c) * FBM(10.p);float w = clamp(3. * pow(0.4, i), 0., 1.);
height += w * (c + noise);
}
height = pow(height, 3.);
隕石坑本身是在3D網(wǎng)格上生成的,而地表地形則是從網(wǎng)格中劃分出來(lái)的一個(gè)球體。
為避免明顯的規(guī)律性,隕石坑中心使用哈希函數(shù)從網(wǎng)格點(diǎn)中隨機(jī)生成。
要計(jì)算給定位置上隕石坑的影響,就可以對(duì)屬于附近網(wǎng)格點(diǎn)的隕石坑進(jìn)行加權(quán)平均,權(quán)重隨距離中心的距離呈指數(shù)遞減。
而坑的邊緣,由一條簡(jiǎn)單的正弦曲線生成。
float craters(vec3 x) {
vec3 p = floor(x);
vec3 f = fract(x);
float va = 0.;
float wt = 0.;
for (int i = -2; i <= 2; i++)
for (int j = -2; j <= 2; j++)
for (int k = -2; k <= 2; k++) {
vec3 g = vec3(i,j,k);
vec3 o = 0.8 * hash33(p + g);
float d = distance(f - g, o);
float w = exp(-4. * d);
va += w * sin(2.*PI * sqrt(d));
wt += w;
}
return abs(va / wt);
}
最終,程序生成的高度圖如下——
雖然相對(duì)簡(jiǎn)單,但在低洼地區(qū)注滿水后,這個(gè)程序地形類似于科學(xué)家認(rèn)為的早期地球的實(shí)際樣子:
NASA提供的對(duì)早期地球的藝術(shù)印象
其中所含的水被熱量蒸發(fā),逸出并開始在地球周圍形成的早期大氣中循環(huán)。隨著時(shí)間的推移和巖石的冷卻,水蒸氣開始凝結(jié)成海洋。液態(tài)水在地表流動(dòng),在地形上刻畫出一道道溝壑,留下了大量沉積物。
2 構(gòu)造板塊
山脈、海溝和我們熟悉的大陸地貌的形成,需要一個(gè)構(gòu)造運(yùn)動(dòng)模型。
我們讓模擬隨機(jī)生成板塊的種子位置,并設(shè)定初始速度。
隨著時(shí)間的推移,這些板塊的大小會(huì)隨著一個(gè)簡(jiǎn)單的聚集模型而增長(zhǎng),該模型會(huì)隨機(jī)選擇相鄰的點(diǎn),如果這些點(diǎn)還沒有被分配到另一個(gè)板塊中,就會(huì)被添加到一個(gè)板塊中。
板塊內(nèi)的所有像素都會(huì)存儲(chǔ)板塊的移動(dòng)速度。這種聚合模型類似于擴(kuò)散限制聚合(但實(shí)際并沒有擴(kuò)散):
板塊的連續(xù)移動(dòng)是很困難的,因?yàn)檫@需要板塊邊界來(lái)解釋以像素為單位的移動(dòng)。
為避免出現(xiàn)這種情況,板以離散的時(shí)間步長(zhǎng)移動(dòng),橫向或縱向均以一個(gè)像素為單位。
每個(gè)板塊的移動(dòng)時(shí)間都是隨機(jī)的,這樣就可以使平均速度保持在設(shè)定的速度和方向上,而且相鄰板塊不太可能同時(shí)移動(dòng)。
當(dāng)一個(gè)板塊的一些邊界像素移動(dòng)到以前被另一個(gè)板塊的像素占據(jù)的位置時(shí),就會(huì)發(fā)生板塊碰撞。
這會(huì)導(dǎo)致俯沖,只要稍微增加碰撞位置的地形海拔,即可對(duì)這種情況進(jìn)行建模。
雖然這種情況只發(fā)生在板塊邊界的像素點(diǎn)上,但通過(guò)簡(jiǎn)單的熱侵蝕模型,這種影響會(huì)逐漸擴(kuò)散到鄰近的像素點(diǎn)上,從而將像素點(diǎn)的海拔高度推向其鄰近像素點(diǎn)的平均海拔高度方向。
總之,這就形成了對(duì)有山脈的大陸很好地模擬(在下一節(jié)中,我們會(huì)引入水力侵蝕,對(duì)模擬進(jìn)一步改進(jìn))——
3 水力侵蝕
自然地形的崎嶇外觀,很大程度上是由河流流域形成的,它們會(huì)以我們熟悉的分支模式,來(lái)侵蝕著地貌景觀。
想要模擬出這種景觀,有很多水流模擬的方法。
然而有一個(gè)難題:對(duì)于整個(gè)地球來(lái)說(shuō),地形圖的分辨率相當(dāng)?shù)汀?/span>
因此,模型必須能夠模擬出寬度不超過(guò)一個(gè)像素的河流。
好在,Barnes提出的一個(gè)簡(jiǎn)單模型,就能實(shí)現(xiàn)這一目標(biāo)。
簡(jiǎn)單來(lái)說(shuō),每個(gè)像素都會(huì)檢查與它相鄰的八個(gè)像素,以確定哪個(gè)方向的海拔降低幅度最大(由于對(duì)角線上的相鄰像素距離較遠(yuǎn),因此需要進(jìn)行調(diào)整)。
這個(gè)坡度最大的方向,就是水流出這個(gè)像素點(diǎn)的方向。
水流最初通過(guò)降雨在各單元之間分配,然后會(huì)在每個(gè)時(shí)間步長(zhǎng)內(nèi),在相鄰像素之間傳輸。
侵蝕是由水流冪律驅(qū)動(dòng)的:
elevation -= 0.05 * pow(water, 0.8) * pow(slope, 2.);
在這里,我們有當(dāng)前單元的海拔高度和水量,以及水流方向的坡度。
海拔的降低是有上限的,這樣就不會(huì)低于水流方向的位置。
水流和侵蝕之間的相互作用,會(huì)導(dǎo)致地形中河谷的自然形成:
通過(guò)給相連的水道著色(顏色由河口位置決定),就可以制作出令人印象深刻的可視化效果,直接能讓人聯(lián)想到真實(shí)的流域圖——
模擬河流流域
來(lái)自《蚱蜢地理》的美國(guó)河流流域
4 全球氣候
模擬整個(gè)星球的氣候系統(tǒng)是一項(xiàng)艱巨的任務(wù),但幸運(yùn)的是,它可以相對(duì)容易地被近似模擬出來(lái)。
在我的氣候模擬中,程序生成的平均海平面氣壓(MSLP)地圖,就是一切背后的驅(qū)動(dòng)力。
根據(jù)《氣候食譜》,生成MSLP圖的主要因素,就是地貌在海洋中的位置以及緯度的影響。
事實(shí)上,如果從真實(shí)的地球MSLP地圖中提取數(shù)據(jù),根據(jù)陸地或海洋的位置將其分開,并繪制 MSLP與緯度的關(guān)系圖,就會(huì)得出陸地和海洋的兩條正弦曲線,二者的形狀略有不同。
通過(guò)適當(dāng)調(diào)整參數(shù),就可以得出了一個(gè)粗略的年平均氣壓模型(此處緯度以度為單位):
if (land) {
mslp = 1012.5 - 6. * cos(lat*PI/45.);
} else { // ocean
mslp = 1014.5 - 20. * cos(lat*PI/30.);
}
當(dāng)然,這還不足以生成真實(shí)的MSLP地圖,因?yàn)榉謩e生成陸地和海洋的數(shù)值,會(huì)導(dǎo)致它們之間的邊界出現(xiàn)明顯的不連續(xù)性。
實(shí)際上,MSLP會(huì)在從海洋到陸地的過(guò)渡過(guò)程中,發(fā)生平穩(wěn)變化,這是由于氣體壓力的局部擴(kuò)散造成的。
只需對(duì)MSLP地圖(標(biāo)準(zhǔn)偏差為10-15度)進(jìn)行高斯模糊處理,就能很好地近似這種氣體擴(kuò)散過(guò)程。
考慮到氣候會(huì)隨季節(jié)變化而變化,有必要對(duì)1月和7月之間的MSLP差異進(jìn)行建模。
陸地?cái)?shù)據(jù)再次表明,這種差異呈正弦模式。
通過(guò)調(diào)整參數(shù)和應(yīng)用高斯模糊,可以將其與年度MSLP地圖相結(jié)合,生成全年變化的動(dòng)態(tài)氣候模式。
if (land) {
delta = 15. * sin(lat*PI/90.);
} else { // ocean
delta = 20. * sin(lat*PI/35.) * abs(lat)/90.;
}
現(xiàn)在,有了MSLP,就可以生成風(fēng)流和溫度。
實(shí)際上,是氣溫產(chǎn)生了氣壓,但相關(guān)性就是相關(guān)性。
這就需要更多的處理,才能生成真實(shí)的數(shù)值(season全年在-1和1之間波動(dòng))。
float temp = 40. * tanh(2.2 * exp(-0.5 * pow((lat + 5.season)/30., 2.)))
- 15.(mslp - 1012.) / 1.8 + 1.5 * land - 4. * elevation;
風(fēng)往往從高壓流向低壓,但在全球范圍內(nèi),我們還需要考慮科里奧利力,它是導(dǎo)致風(fēng)在氣壓帶周圍環(huán)流的原因(grad是MSLP梯度矢量)。
vec2 coriolis = 15. * sin(lat*PI/180.) * vec2(-grad.y, grad.x);
vec2 velocity = coriolis - grad;
雖然這是一種相對(duì)粗糙的模擬,但它生成的風(fēng)環(huán)流模式,卻非常逼真。
如果仔細(xì)觀察,你口會(huì)發(fā)現(xiàn)許多自然現(xiàn)象都被復(fù)制了,包括季風(fēng)季節(jié)印度上空的風(fēng)向逆轉(zhuǎn):
作為一個(gè)細(xì)節(jié),降水可以通過(guò)水蒸氣從海洋通過(guò)風(fēng)矢量場(chǎng)平移到陸地來(lái)模擬。
平流的實(shí)現(xiàn)方式與流體模擬類似。
5 生命
氣候影響著地球上的生命分布。降雨模式和溫度變化決定了植物的生長(zhǎng)速度。
隨著季節(jié)的變化,食草動(dòng)物會(huì)遷移到有足夠植被的地區(qū)。
隨著植被的遷移,食肉動(dòng)物也跟著遷移。
所有這些動(dòng)態(tài)都可以通過(guò)Lotka–Volterra擴(kuò)散模型來(lái)捕獲
float dx = plant_growth - c.y;
float dy = reproduction * c.x - predation * c.z - 1.;
float dz = predation * c.y - 1.;
float dt = 0.1;
c.xyz += dt * c.xyz * vec3(dx, dy, dz);
c的xyz元素,分別代表植被、食草動(dòng)物和食肉動(dòng)物的種群。
在大范圍內(nèi),動(dòng)物種群的動(dòng)態(tài)會(huì)產(chǎn)生有趣的模式:
在現(xiàn)實(shí)生活中,這些模式最容易在培養(yǎng)皿中的微生物種群中看到,但同樣的規(guī)律,也適用于全球的大型動(dòng)物種群。
霉菌菌落中的螺旋波紋
6 人類
早期地球的序幕結(jié)束了。
影片的節(jié)奏放慢到晝夜循環(huán),地形變得固定,構(gòu)造運(yùn)動(dòng)變得難以察覺。
很快,隨著人類開始在地球表面殖民,夜晚就會(huì)呈現(xiàn)出前所未有的光影模式。
隨著人類開始燃燒大量化石燃料,為自己的生活提供動(dòng)力,這種快速擴(kuò)張帶來(lái)了一系列變化。
沉睡了數(shù)百萬(wàn)年的碳,被釋放到了大氣中,并且散布到了地球的各個(gè)角落。
幾百年來(lái),人類燒盡了所有可用的化石燃料資源,向大氣釋放了五萬(wàn)億噸碳。
這加劇了溫室效應(yīng),使全球的平均氣溫上升了近10攝氏度。
赤道附近的大片土地因?yàn)闃O端溫度而變得不適合居住,導(dǎo)致人類從地球上很大一部分地區(qū)消失了。