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