Stereogram 3D w zero liniach JavaScriptu


Stereogramy to płaskie obrazy, które tworzą efekt 3D (iluzję), gdy patrzy się na nie w określony sposób.
Były hitem lat 90. i czas przywrócić je do łask!

1. Skopiuj ten tekst:

learncoding

2. Wklej go 6 razy do notatnika (upewnij się, że używasz czcionki o stałej szerokości, takiej jak Courier):

learncodinglearncodinglearncodinglearncodinglearncodinglearncoding


3. Usuń ostatnie 3 wystąpienia litery 'g':

learncodinglearncodinglearncodinglearncodinlearncodinlearncodin


Gratulacje! Właśnie stworzyłeś swój pierwszy stereogram! I nawet nie potrzebowałeś do tego kodu!

Co prawda ten jest bardzo prosty i nieco trudny do zobaczenia – mimo to, przy odrobinie wprawy, można go zobaczyć w 3D. Ten poniżej jest lepszy, a pod nim znajduje się program, który go wygenerował:




learncodinglearncodinglearncodinglearncodinglearncodinglear
learncodinglearncodinglearncodinglearncodinglearncodinglear
learncodinglearncodinglearncodinglearncodinglearncodinglear
learnc%odinglearnc%odinglearnc%odinglearnc%odinglearncoding
learnc(odinglearnc(odinglearnc(odinglearnc(odinglearncoding
learnc(odinglearnc(odinglearnc(odinglearnc(odinglearncoding
learnc/odinglearnc/odinglearnc/odinglearnc/odinglearncoding
learnc"oding7learnc"oding7learnc"oding7learnc"odng7leanc"od
learnc8oding7learnc8oding7learnc8oding7learnc8odng7leanc8od
learnc&oding9learnc&oding9learnc&oding9learnc&odng9leanc&od
learnc7oding!learn0c7oding!learn0c7oding!larn0c7ding!lrn0c7
learnc5oding#learn#c5oding#learn#c5oding#larn#c5ding#lrn#c5
learnc*oding#learn/c*oding#learn/c*oding#larn/c*ding#lrn/c*
learnc,oding'learn%c,oding'learn%c,oding'larn%c,ding'lrn%c,
learnc(oding3learn8c(oding3learn8c(oding3larn8c(ding3lrn8c(
learnc*oding&learn'c*oding&learn'c*oding&larn'c*ding&lrn'c*
learnc3oding6learnc3oding6learnc3oding6learnc3odng6leanc3od
learnc4oding/learnc4oding/learnc4oding/learnc4odng/leanc4od
learnc+oding8learnc+oding8learnc+oding8learnc+odng8leanc+od
learnc1odinglearnc1odinglearnc1odinglearnc1odinglearncoding
learnc-odinglearnc-odinglearnc-odinglearnc-odinglearncoding
learnc7odinglearnc7odinglearnc7odinglearnc7odinglearncoding
learnc0odinglearnc0odinglearnc0odinglearnc0odinglearncoding
learncodinglearncodinglearncodinglearncodinglearncodinglear
learncodinglearncodinglearncodinglearncodinglearncodinglear
learncodinglearncodinglearncodinglearncodinglearncodinglear




Oto jak patrzeć na stereogramy, aby faktycznie zobaczyć je w 3D (możesz pominąć tę sekcję, jeśli już wiesz, jak to zrobić):
Patrz prosto przed siebie, tak jakbyś patrzył na punkt za ekranem (jakby monitor był przezroczysty). Zamiast skupiać wzrok na jednym punkcie na ekranie, postaraj się, aby oczy były rozluźnione i patrzyły w dal.

Wyobraźmy sobie, że obrazek poniżej to widok z góry na dwie pary oczu (niebieskie koła z zielonymi kropkami reprezentującymi siatkówki) i dwa ekrany komputerowe (niebieskie prostokąty).
Osoba na górze skupia wzrok na ekranie, co jest normalnym sposobem patrzenia. Oboje oczu widzi tę samą część ekranu, np. słowo.
Osoba na dole patrzy "przez" ekran na punkt daleko w oddali. Jest to patrzenie równoległe, które pozwala nam widzieć stereogramy w 3D. Lewe oko widzi lewą stronę ekranu, a prawe prawą.



Patrzenie równoległe bardzo różni się od naszego naturalnego sposobu patrzenia. Nasze oczy i mózgi są wytrenowane, by skupiać się na obiektach, a nie patrzeć przez nie, więc wymaga to trochę praktyki, często kilku prób w ciągu kilku minut.
Upewnij się, że stereogram znajduje się bezpośrednio przed Tobą i z dala od innych obiektów (kursora, przycisków, pasków przewijania, jakiegokolwiek tekstu typu pasek adresu), ponieważ Twoje oczy będą miały tendencję do skupiania się na tych obiektach.

Jeśli masz trudności z zobaczeniem efektu 3D, wstaw to jako linię [71]:

body.innerHTML = body.innerHTML + '<br><br>x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x';


To narysuje dwa znaki x pod stereogramem. Teraz zbliż twarz bardzo blisko ekranu, tak aby nos prawie dotykał go tuż pod iksami (NSFW!).
Teraz patrz prosto przed siebie i powoli oddalaj twarz od ekranu. Powinieneś zobaczyć jeden lub dwa rozmyte 'fantomowe' iksy oprócz tych prawdziwych, ponieważ Twoje oczy nie mogą się prawidłowo skupić. Cofaj się powoli i nie pozwalaj oczom złapać ostrości. Jeśli fantomowe iksy znikną, straciłeś efekt i musisz zacząć od nowa.
Gdy będziesz około 25 cm od ekranu, powoli przenieś wzrok w górę na stereogram, ponownie nie pozwalając oczom się zrelaksować (złapać ostrości na powierzchni).

Jeśli zrobisz to dobrze, powinieneś nadal widzieć te same znaki, ale teraz niektóre z nich będą wydawać się głębiej niż inne. Iluzja jest bardzo silna – jeśli nie jesteś pewien, czy ją widzisz, to znaczy, że jeszcze nie robisz tego poprawnie.

A oto jak i dlaczego to działa:

W zasadzie oszukujesz swój mózg, sprawiając, że lewe oko widzi coś innego niż prawe. Jeśli w naszym przykładzie oboje oczu patrzy prosto przed siebie, lewe oko zobaczy pełne słowo ('learncoding'), podczas gdy prawe zobaczy to bez litery 'g' ('learncodin').
W prawdziwym życiu taka sytuacja (każde oko widzi coś innego) zdarza się tylko wtedy, gdy przed nami znajduje się narożnik 3D (a w konsekwencji dwie różne głębokości/odległości), coś takiego:



Twoje lewe oko widzi tylko 'learncodin', ponieważ litera 'g' jest ukryta za rogiem:



Twoje prawe oko widzi pełne słowo, ponieważ róg nie zasłania litery 'g'



W skrócie, mamy powtarzający się wzór (mogą to być litery lub kolorowe kropki). W pewnym momencie dodajemy lub usuwamy jeden element ze wzoru. Nasz mózg zobaczy zmianę głębi w miejscu, gdzie wzór się zmienił – usunięcie elementu zmniejsza głębię, a dodanie zwiększa ją.
W tym samouczku elementami są znaki. Oryginalnym wzorem jest słowo 'learncoding' (składające się tylko z liter). Dodatkami do wzoru są znaki specjalne (#+% itp.) lub cyfry. Moglibyśmy nadal używać liter jako dodatków, ale różnica ułatwia zrozumienie, co dzieje się ze wzorem.
Należy również unikać powtarzania elementów we wzorze, ponieważ może to osłabić efekt.

Podsumowanie kodu:
przejdź przez każdą linię obrazu źródłowego:
    zresetuj wzór do oryginału ('learncoding')
    przejdź od lewej do prawej przez każdy znak linii źródłowej:
        jeśli znak linii źródłowej jest wyższy niż obecna głębokość, dodaj losowy znak do wzoru
        jeśli znak linii źródłowej jest niższy niż obecna głębokość, usuń znak ze wzoru
        narysuj następny znak ze wzoru

<html>
<style>
  body {
    font-familycourier;
    text-aligncenter;
  }
</style>
<body>
<br><br><br><br><br><br>
<script>
let body = document.body;
let sourcePattern = 'learncoding';
let source = [
  '00000000000000000000000000000000000000000000000000000000000',
  '00000000000000000000000000000000000000000000000000000000000',
  '00000000000000000000000000000000000000000000000000000000000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222233333333333333333333333322222211111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111122222222222222222222222222222222222211111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000011111111111111111111111111111111111111111111111100000',
  '00000000000000000000000000000000000000000000000000000000000',
  '00000000000000000000000000000000000000000000000000000000000',
  '00000000000000000000000000000000000000000000000000000000000', 
  ];
 
for (let y = 0y < source.lengthy++) {
  let currentDepth = source[y][0];
  let currentPattern = [];
  let length = sourcePattern.length;
  for (let i = 0i < lengthi++)
    currentPattern.push(sourcePattern[i]);
  let position = 0;
  for (let x = 0x < source[y].lengthx++) {  
    let next = source[y][x];
    if (next < currentDepth) {
      currentPattern.splice(position1);
      length--;
      if (position == length)
        position = 0;
    }
    if (next > currentDepth) {
      currentPattern.splice(position0String.fromCharCode(Math.random() * 25 + 33));
      length++;
    }
    currentDepth = next;
    body.innerHTML = body.innerHTML + currentPattern[position];
    position++;
    if (position == length)
      position = 0;
  }
  body.innerHTML = body.innerHTML + '<br>';
}
</script>
</body>
</html>


Szczegóły:

[4] - upewnij się, że używasz czcionki o stałej szerokości (monospaced)
[12] - oryginalny wzór
[13-40] - obraz źródłowy. Wyższa liczba = większa głębia
[42] Dla każdego wiersza:
[43] Pobierz głębokość z pierwszej kolumny
[44-47] przekonwertuj wzór źródłowy na tablicę (currentPattern)
[49] Dla każdej kolumny:
[50] pobierz następny znak z obrazu źródłowego
[51-53] usuń znak ze wzoru, jeśli głębokość maleje
[54-55] zrestartuj wzór, jeśli dotarliśmy do końca
[57-60] dodaj znak do wzoru, jeśli głębokość rośnie
[61] zaktualizuj obecną głębokość
[62] napisz następny znak ze wzoru
[63] przesuń się w prawo we wzorze
[64-65] zrestartuj wzór, jeśli dotarliśmy do końca
[67] narysuj następną linię
Nie ma nic magicznego w obrazie źródłowym, znakach ani wzorze, który wybrałem, więc śmiało eksperymentuj z innymi, na przykład zastąp źródło tym wspaniałym przykładem sztuki programistycznej:

  '000000000000000000000000000000000000000000000000000000000', 
  '000000000000000000000000000000000000000000000000000000000', 
  '000000000000111111111111111111111111111111111000000000000', 
  '000000000001111111111111111111111111111111111100000000000', 
  '000000000011111111111111111111111111111111111100000000000', 
  '000000000111110000001111111111111111000000111110000000000', 
  '000000000111110000001111111111111111000000111110000000000', 
  '000000001111110000001111111111111111000000111111000000000', 
  '000000011111111111111111111111111111111111111111100000000', 
  '000000011111111111111111111111111111111111111111100000000', 
  '000000011111111111111111111111111111111111111111100000000', 
  '000000001111111111111111111111111111111111111111000000000', 
  '000000000111111110000111111111111110000111111110000000000', 
  '000000000111111110000111111111111110000111111110000000000', 
  '000000000011111111100000000000000000011111111100000000000', 
  '000000000001111111110000000000000000111111111100000000000', 
  '000000000000111111111111111111111111111111111000000000000', 
  '000000000000111111111111111111111111111111111000000000000', 
  '000000000000000000000000000000000000000000000000000000000', 
  '000000000000000000000000000000000000000000000000000000000', 


Dość łatwo zmodyfikować kod, aby używał losowo kolorowych kropek (pikseli) zamiast znaków jako wzoru. Tworzy to Stereogram z Losowych Kropek (RDS - Random Dot Stereogram):



Z odrobiną dodatkowego kodu można stworzyć stereogram, w którym początkowy wzór jest inny w każdym wierszu. Wzór ten można pobrać z innego małego obrazka, na przykład:





Więcej samouczków JS

Gra "Wieża" - 84 linie JavaScript

Fraktale - 25 linii

Sinus scroll - 30 linii

Gra "Angry Chickens"

Animowane krzywe kwadratowe - 40 linii

Animowane konstelacje cząsteczek - 42 linie

Eksperyment z enginem fizyki