Jaskinie Podróże Nurki Grafika Mizar Teksty Kulinaria Lemkov Namiary Mapa RSS English
Spelunka Trybików Grafika Śledzenie promieni (ray tracing) Rzutowanie promieni (ray casting) YAC Software
  Wróć

Wprowadzenie

Śledzenie promieni (ray tracing)

Rzutowanie promieni (ray casting)

Obliczenia wstępne

Antyaliasing

Rzutowanie promieni (ray casting)
Zacznijmy od problemu prostszego: rzutowania promieni.



Użyjemy promieni wychodzących z naszego wirtualnego oka (lub kamery) aby sprawdzać, które obiekty sceny są widoczne w kierunku kolejnych pikseli ekranu. Jeżeli jakiś obiekt jest widoczny w kierunku promienia od oka do piksela, rysujemy ten piksel w kolorze znalezionego obiektu. Jeżeli żaden obiekt nie jest widoczny w tym kierunku, rysujemy czarne tło.

Jest to rzutowanie promieni (ray casting), a nie śledzenie promieni (ray tracing), gdyż promienie są rzutowane od oka w scenę wirtualną tylko do obliczania widoczność obiektów. Nie są analizowane: źródła światła, cieniowanie, cienie, odbicia, itd.

Algorytm idzie jak następuje:
  dla każdego piksela na ekranie ps
    niech v będzie wektorem z naszego wirtualnego oka przez ps
    niech dmin (minimalna odległość do elementu) będzie równa max float
    niech emin (element sceny najbliższy oku) będzie równy NULL
    dla każdego elementu sceny e
      niech p będzie punktem przecięcia v i e
      jeżeli p istnieje to
        niech d będzie odległością p od oka
        jeżeli d < dmin to
          dmin := d;
          emin := e;
        koniec;
      koniec;
    koniec;
    jeżeli emin <> NULL to
      niech ps będzie koloru emin
    wpp
      niech ps będzie czarny
    koniec;
  koniec.
Zatem, jeżeli emin <> NULL, emin wskazuje na ten element sceny wirtualnej, który jest najbliższy oka (a więc widoczny) w kierunku wektora v. Nadajemy więc odpowiedniemu pikselowi ekranu kolor elementu emin.

Jednakże, jeżeli emin = NULL, wtedy w kierunku wektora v nie zostały znalezione żadne obiekty, więc rysujemy domyślny kolor tła (na razie niech to będzie czarny).

Mimo, że jest to tylko rzutowanie promieni, nawet ten prosty algorytm wymaga obudowy która będzie potrzebna przy implementacji bardziej złożonych obliczeń.

Najpierw, musimy zdecydować, jakiego typu obiekty chcemy umieszczać w naszej wirtualnej scenie. Z różnych powodów, zacznijmy od scen zawierających jedynie trójkąty. Inne kształty dodamy w przyszłości, ale wzory stojące za renderingiem trójkątów przedstawiają podstawowe obliczenia. Tudzież, z trójkątów można budować bardziej złożone kształty, a nawet symulować dowolne inne kształty (o ile skorzystamy z wystarczającej liczby wystarczająco małych trójkątów).

Następnie, musimy móc obliczyć punkt przecięcia promienia z trójkątem. To mając, reszta algorytmu powyżej jest już całkiem banalna.

Przed przejściem do szczegółów, zatrzymajmy się jeszcze na chwilę aby omówić terminologię.
  • Punkt w przestrzeni trójwymiarowej - rzecz prosta. Trzy wartości typu float przedstawiające położenie punktu w standardowym układzie współrzędnych (x, y, z).
  • Promień w przestrzeni trójwymiarowej to wektor o punkcie początkowym p1 = (x1, y1, z1) i punkcie końcowym p2 = (x2, y2, z2). Zakładamy, że kierunek promienia jest od p1 do p2.
  • Wektor to promień z punkcie początkowym p1 = (0, 0, 0). Zatem, tak naprawdę nie ma istotnej różnicy między wektorami (które są jednoznacznie zdefiniowane przez ich punkty końcowe) a punktami w przestrzeni trójwymiarowej - zatem pojęć tych będziemy używać zamiennie.
Wróćmy do przecięcia promieni z trójkątami. Istnieje wiele różnych sposobów na obliczanie takiego przecięcia, jednak powinniśmy wybrać te, które wymagają jak najmniejszej liczby obliczeń (zwróćmy uwagę, że powyższy algorytm sprawdza w sumie #pikseli x #trójkątów przecięć).

Intersections of Rays, Segments, Planes and Triangles in 3D przedstawia wymagane algorytmy. Nie będę tutaj opisywał ich szczegółów (jako że w artykule jest to wystarczająco dobrze zrobione), jednak zwróćmy tylko uwagę na dwa główne kroki procesu:
  • Znajdujemy przecięcie promienia z płaszczyzną, w której leży trójkąt.
  • Jeżeli taki punkt istnieje, sprawdzamy, czy punkt ten leży wewnątrz trójkąta.
Implementacja powyższego nie powinna być trudna (po lekturze załączonego artykułu). Przed ściągnięciem źródeł, może należy jeszcze wyjaśnić kilka drobiazgów:
  • Nie została zdefiniowana klasa "punkt"; wektory zostały zdefiniowane jako pojedyncze punkty (punkt początkowy jest znany). Można korzystać z wektorów gdziekolwiek potrzebne są punkty.
  • Tak naprawdę nie obliczamy odległości, a kwadrat odległości. Ponieważ szukamy tylko najbliższego obiektu, nie musimy wyniku przekazywać do (czasochłonnej) funkcji sqrt().
  • Niekiedy, do porównania dwóch punktów / wektorów korzystam z małej wartości (EPSILON). Problem leży w immanentnej niedokładności obliczeń zmienno-przecinkowych. Rozwiązaniem nie jest porównywanie dokładnych wartości, a ich przybliżeń (które jednak muszą być wystarczająco dokładne; stąd EPSILON zdefiniowane jest jako 1e-10).
  • Właśnie, korzystamy z typu float miast typu double, gdyż duża dokładność nie jest tak bardzo ważna w renderingu scen. Za to prędkość obliczeń jest (i to bardzo).
  • Klasa "engine" przeprowadza obliczenia renderingu; Canvas->Pixels[x][y] jest dosyć wolne (zabiera około połowy czasu renderingu sceny poniżej), ale gdy zaczniemy komplikować algorytm, rzecz przestanie być istotnym problemem.
  • Klasa "scene" odpowiedzialna jest za obsługę obiektów należących do renderowanej sceny. Ma też metody generowania scen. TYRTScene::GenerateExample_01Triangles zostały użyta do utworzenia obrazka poniżej.
No dobra, po całym tym wstępie, wypróbujmy algorytm na prostym przykładzie:

Niezbyt to skomplikowana scena, ale jest to już jakiś początek!
Niezbyt to skomplikowana scena, ale jest to już jakiś początek!
Poprzednie Następne Zamknij


A źródła (projekt C++Builder) do powyższego można znaleźć tutaj.

Góra

Komentarze
Kurczę!
Na razie brak komentarzy...

Góra

Dodaj komentarz (pola z gwiazdką są obowiązkowe)
Imię / ksywa *
Mail (pozostanie ukryty) *
Twoja strona
Komentarz (bez tagów) *
Wpisz tekst wyświetlony poniżej *
 

Góra