W Minecraft, gdy patrzysz na wodę, im głębiej patrzysz, tym ciemniej się robi. Czy ktoś wie, jak zakodować coś takiego?
Minecraft z efektem
podobna gra bez efektu
W Minecraft, gdy patrzysz na wodę, im głębiej patrzysz, tym ciemniej się robi. Czy ktoś wie, jak zakodować coś takiego?
Minecraft z efektem
podobna gra bez efektu
Odpowiedzi:
Istnieją zasadniczo dwa różne podejścia do oświetlania wody w zależności od głębokości:
Minecraft wykorzystuje oświetlenie oparte na wokselach, które działa poprzez propagowanie światła do sąsiednich kostek, obniżając jasność w zależności od rodzaju bloku. Ciemne oceany są efektem ubocznym tego systemu.
Woda blokuje światło słoneczne i redukuje światło o 3 poziomy na blok (zamiast domyślnego poziomu 1), co oznacza, że jasność oceanu dla każdej odległości od powierzchni wynosi:
0 (surface): 15 (direct sunlight)
1: 12
2: 9
3: 6
4: 3
5 and below: 0 (darkness)
Źródło: Minecraft Wiki - Light
W grach z tradycyjnym modelem oświetlenia efekt ten można uzyskać, mierząc ilość wody między źródłem światła a dnem oceanu. Światło jest następnie wyblakłe na podstawie tej odległości. Można to zrobić na kilka sposobów:
Jeśli masz płaską powierzchnię, możesz łatwo obliczyć odległość, jaką światło pokonuje w wodzie, jeśli przejdziesz powierzchnię normalną z dala od akwenu i iloczyn skalarny tej normalnej oraz pozycję powierzchni w module cieniującym geometrię.
Efektywna odległość wody wynosi
gdzie jest pozycja wierzchołka i kąt między kierunkiem światła pod powierzchnią a powierzchnią wody jest normalny w stosunku do części wód.
O zachodzie słońca osiąga tylko nieco mniej niż 50 °, ponieważ światło załamuje się po wejściu do wody.
Oto post na blogu z dobrym wyjaśnieniem: Aparat cyfrowy: całkowite odbicie wewnętrzne
Kolejny post z bardziej szczegółowymi informacjami: Aparat cyfrowy: prawo załamania Snella
Jeśli używasz mapy wysokości na powierzchni równoległej do wody, staje się . Właściwy współczynnik wynosi 1, jeśli słońce znajduje się bezpośrednio nad powierzchnią wody.
W przypadku światła punktowego należy obliczyć dla każdego wierzchołka na podstawie względnej pozycji względem źródła światła.
Przy stałym poziomie wody lub stałym kierunku światła części równania są stałe i nie powinny być obliczane w module cieniującym ze względu na wydajność.
Jeśli renderujesz powierzchnię wody na osobną mapę głębokości (widzianą ze źródła światła), możesz użyć tej tekstury głębokości, aby obliczyć odległość, jaką światło przebywa w wodzie przed uderzeniem w powierzchnię.
Aby to zrobić, należy rzutować każdy wierzchołek na rzut źródła światła w module cieniującym wierzchołki i wyszukiwać teksturę w module cieniującym piksele.
Jeśli powierzchnia jest stosunkowo płaska, należy użyć załamanego źródła światła, aby uzyskać lepsze wyniki.
* Możesz określić ilość wody przed najbliższą stałą powierzchnią, licząc głębokość z POV światła w następujący sposób:
Wynikowa tekstura zawiera teraz ilość wody przed światłem w jasnej przestrzeni widokowej, więc wartość należy przekształcić z powrotem przed użyciem. Ta metoda działa w celu obliczenia światła kierunkowego (minus załamanie światła), ale doprowadzi do nieprawidłowego światła otoczenia, jeśli powierzchnie są bardzo nieregularne i między częściami wody występuje duża ilość powietrza wpływająca na te same fragmenty.
Plusy i minusy są takie same jak w przypadku normalnego mapowania cieni, z tym wyjątkiem, że potrzebujesz jeszcze jednego bufora podczas obliczania głębokości, a wydajność jest gorsza, ponieważ musisz narysować więcej geometrii.
Śledzenie promieni jest zdecydowanie najdokładniejszym, ale także najdroższym rozwiązaniem do renderowania przezroczystych woluminów. Można to zrobić na dwa sposoby: 1. Śledzenie z dna oceanu w kierunku powierzchni i 2. Śledzenie od źródła światła w kierunku wody. Aby obliczyć jasność, dla każdego punktu na podłodze potrzeba wielu promieni.
Podczas renderowania wody należy wziąć pod uwagę jeszcze kilka rzeczy:
Światło w wodzie jest ponownie rozpraszane podczas podróży do obserwatora, więc powinieneś mieszać go w jednolitym kolorze.
Jeśli obserwator jest zanurzony , możesz po prostu renderować mgłę na podstawie końcowego wyniku bufora głębokości. Kolor mgły, ale nie jej gęstość, powinien zmieniać się wraz z odległością obserwatora od powierzchni! (Minecraft używa tylko tej części efektu).
Jeśli obserwator patrzy na wodę z góry , musisz obliczyć mgłę na podstawie różnicy głębokości między powierzchnią a geometrią pod wodą. Kolor mgły powinien być nieco ciemniejszy z większymi różnicami głębokości, ale powinien zmieniać się tylko do punktu, w którym mgła jest całkowicie nieprzezroczysta.
Kolor mgły powinien również zależeć od kierunku widoku każdego piksela, więc w obu przypadkach jest nieco ciemniejszy.
Jeśli zamiast fałszywej kaustyki użyjesz bezszwowej tekstury 3D zamiast kafelków, możesz uniknąć rozciągania na pionowych powierzchniach. Siła rozproszonego światła w pobliżu powierzchni zmienia się w trzech wymiarach, więc użycie tekstury 2D zwykle powoduje rozciąganie gdzieś na scenie. Możesz modelować zmieniające się kąty światła poprzez rzutowanie pozycji wierzchołków podłogi na inny układ współrzędnych.
Inną możliwością jest obliczenie gęstości światła na podstawie położenia powierzchni w układzie współrzędnych światła, chociaż najprawdopodobniej kosztowałoby to pewną wydajność.
Środki kaustyczne powinny zanikać szybciej niż rozproszone światło o coraz większej głębokości.
Kolory są rozproszone w różny sposób, więc kolor światła powinien się zmieniać wraz ze wzrostem głębokości. Zapobiega to również nagłym krawędziom, gdy na przykład plaża przecina powierzchnię wody.
Z powodu załamania światła światło uderza w dno oceanu znacznie bardziej stromo niż normalnie. Artykuł w Wikipedii o prawie Snella zawiera wzory na kąty i wektory.
Wierzę, że efekt oświetlenia nieba w Minecrafcie jest skierowany w dół - rzeczy są zacienione przez to, co jest nad nimi, bez względu na to, gdzie jest słońce. Następnie stosuje się lokalne oświetlenie z pochodniami itp. Z efektem odpadania - im dalej od źródła światła, tym mniej światła dostaje kostka.
Jeśli zostanie to zrobione w ten sposób, każda warstwa wody kumuluje cień pod warstwą pod nią, więc każda z nich będzie stopniowo ciemnieć. Liście drzew zapewniają taki cień, jednak nie kumulują się. Otrzymujesz ten sam odcień pod drzewem, bez względu na to, czy jest to 1 czy 100 kostek liści.
Jednym ze wskazówek, że jest to stosowana metoda, jest to, że woda nie ciemnieje, gdy znajduje się dalej od widza - tylko podczas schodzenia. Tak, efekt mgły pojawia się na odległość, ale nie efekt ciemnej wody.
Podstawową formułą obliczania oświetlenia byłoby coś takiego w pseudokodzie ...
light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
if cube being examined is tree foliage
light_on_cube = 0.5
else if cube being examined is water
light_on_cube = light_on_cube - 0.1
else if cube being examined is solid
light_on_cube = 0
}
Nie jest to idealne do obliczania oświetlenia pod nawisami lub w jaskiniach, ponieważ przy zwisie byłoby to bardzo ciemne. Można jednak dodać zarówno lokalne źródła światła (pochodnie, pożary itp.), Jak i traktując bloki oświetlone słońcem jako źródła światła. Coś takiego może to zrobić ...
Chodzi o to, że jeśli sześcian zostanie oświetlony przez słońce lub pochodnię, sześcian obok niego również zostanie w jakiś sposób oświetlony. A im dalej jesteś od oświetlonego sześcianu, tym mniej światła będzie. To trochę dziwny sposób na oszacowanie rozproszonego oświetlenia, ale myślę, że to by zadziałało.
Być może nie rozumiem pytania, ale dlaczego nie możesz po prostu zmienić koloru bloków w zależności od ich głębokości?
Jeśli masz głębokość d (w blokach, zaczynając od 0), wówczas rozsądnym równaniem jasności byłoby:
L = (1 m ) e - kd + m
Kod: L = (1.0 - m) * exp(-k * d) + m;
k kontroluje, jak szybko robi się ciemniej (wyżej = szybciej). Rozsądna wartość to 0,5.
m to minimalna wymagana jasność.
L zmienia się od 0 do 1.
Jeśli nie wiesz, jak zmienić kolor bloków w jakimkolwiek graficznym interfejsie API, którego używasz, zadaj to jako osobne pytanie (określając, jakiego interfejsu API używasz i czy używasz shaderów).
e^-kd
Bit jest tylko gwałtowny rozpad, który jest standardową funkcją dla rzeczy, które stopniowo mają tendencję do zera powyżej pewnej wartości (głębokość). Mnożenie przez (1-m)
i dodawanie m
służą jedynie do skalowania i równoważenia rozpadu, tak że kończy się na minimum, m
ale wciąż zaczyna się od 1
. en.wikipedia.org/wiki/Exponential_decay