Creăm un peisaj realist pentru 130 de linii de cod pe javascript

Creăm un peisaj realist pentru 130 de linii de cod pe javascript

Programatorii sunt niște creaturi lenești, cu o organizare emoțională subtilă, care ne ajută să găsim soluții simple și frumoase la probleme cu costuri minime. În acest articol, vom crea un peisaj realist utilizând algoritmul "diamant-pătrat". Nu vom picta terenul stancos pentru o lungă perioadă de timp, care în cele din urmă, cel mai probabil, va fi foarte mizerabil. În schimb, datorită generației fractale, vom învăța calculatorul ce înseamnă să fie o piatră.

Harta Heights

Vom păstra peisajul sub forma unei hărți de înălțimi - o matrice bidimensională care conține informații despre înălțimea fiecărui punct de teren de-a lungul coordonatelor x și y. Cu această structură de date simplă, puteți vizualiza înălțimea așa cum doriți - cu Canvas, WebGL, etc. Principala limitare este că nu putem afișa găuri verticale de peisaj, cum ar fi peșteri sau tuneluri.

Acest algoritm poate fi aplicat la o grilă de orice dimensiune, dar este mai convenabil să folosim un pătrat de mărimea unui cântar de +1. Vom folosi aceeași valoare de mărime pentru axele x. y și z. făcând peisajul într-un cub. Transformați detaliile la o putere de două + 1, astfel încât în ​​detaliu, cuburi de dimensiuni mai mari sunt generate.

Ia pătratul. Să o împărțim în patru mai multe pătrate și să mutăm centrele în sus sau în jos aleatoriu. Să le împărțim fiecare în pătrate și să repetăm, reducând în mod repetat intervalul de schimbare aleatorie pentru a obține detalii mai mici.

Acest algoritm este "diamant-pătrat". În cazul nostru, este ușor îmbunătățită pentru a obține un rezultat mai realist: spațiul este alternativ împărțit în pătrate (pătrate) și diamante (diamante).

Setați unghiurile

Mai întâi trebuie să setați colțurile la valoarea inițială a semințelor, ceea ce va afecta restul vizualizării. Codul de mai jos va ridica toate unghiurile la jumătate din înălțimea cubului:

Împărtășim harta

Acum vom observa recursiv diviziile progresiv mai mici ale hărții de altitudine. Cu fiecare divizare, vom rupe hartă în pătrate și vom actualiza poziția punctului central al fiecăruia în timpul fazei "pătrate". Apoi vom împărți cartea în romburi și vom actualiza punctele lor centrale în etapa "diamant".

Folosind scara variabilă se asigură scăderea numărului de deplasări împreună cu valoarea diviziunilor. Pentru fiecare divizie, multiplicăm mărimea curentă cu coeficientul de rugozitate a rugozității. care determină dacă terenul este neted (aproximativ 0) sau montan (aproximativ 1).

Ambele forme (pătrat și diamant) lucrează prin același principiu, dar obțin datele din diferite puncte. În faza patrată înainte de schimbarea aleatoare, găsim media celor patru puncte de colț și în faza diamantului - din cele patru puncte de pe margini.

vizualizare

Acest algoritm ne oferă doar date pe care le putem vizualiza deja în mai multe moduri. Aici vom combina mai multe tehnici pentru a crea o proiecție 3D izometrică raster a unei hărți pe o rețea.

înapoi

Mai întâi, vom crea bucle imbricate care trag dreptunghiuri din "spatele" hărții noastre (y = 0) "înainte" (y = this.size). Același ciclu pe care l-am folosi pentru a vizualiza un simplu pătrat plat.

Abordarea noastră neobișnuită oferă o textura vizuală frumoasă. Comparăm înălțimea curentă cu înălțimea următorului punct pentru a calcula panta. Și atrageți mai multe dreptunghiuri strălucitoare pentru pante mai înalte pentru a umple o parte cu lumină, iar cealaltă cu umbră.

Proiecție izometrică

Este mai interesant din punct de vedere vizual traducerea peisajului nostru de la faza "pătrat" ​​la faza "diamant" înainte de a face proiecția 3D. Proiecția izometrică reduce unghiurile superioare din stânga și din dreapta jos spre centrul imaginii.

Proiecție centrală (perspectivă)

Vom folosi o proiecție 3D la fel de simplă pentru a converti valorile lui x. y și z într-o imagine plană cu perspectivă pe ecranul 2D.

Ideea de bază a oricărei proiecții de perspectivă este împărțirea pozițiilor orizontale și verticale la adâncime astfel încât obiectele mai îndepărtate să pară mai mici.

Împreună

Creați o nouă instanță Terrain cu nivelul necesar de detalii. Apoi generați harta înălțimii cu valoarea rugozității între 0 și 1. În cele din urmă, transferăm terenul în grila.