2012-12-17 11 views
5

Piszę raytracera 3D jako osobisty projekt edukacyjny (Enlight) i natknąłem się na interesujący problem związany z wykonaniem testów przecięć między promieniem a sceną obiektów.Struktura danych/podejście do efektywnego raytracingu

Sytuacja jest:

  • Mam szereg prymitywów, że promienie mogą się przecinać z (kulki, pudełka, samoloty, etc.) i ich grup. Łącznie nazywam te obiekty sceny.
  • Chcę być w stanie prymitywów obiektów sceny z dowolnymi transformacjami afinicznymi, owijając je w obiekt Transform (co ważne, umożliwi to użycie wielu wystąpień tego samego prymitywu w różnych położeniach w scenie, ponieważ prymitywy są niezmienne)
  • obiekty Scene mogą być przechowywane w drzewo bvh (tj robię podział przestrzenny)
  • moich testów przecięcia pracować z Ray obiektów, które reprezentują segment ray częściowe (start wektor, znormalizowany wektor kierunku, start dystans , odległość końcowa)

Problem polega na tym, że kiedy promień uderza w ramkę ograniczającą obiektu Transform, wygląda na to, że jedynym sposobem na wykonanie testu przecięcia z transformowanymi prymitywami zawartymi w nim jest przekształcenie Ray w przekształconą współrzędną. Jest to dość łatwe, ale jeśli promień nie trafi żadnych przekształconych obiektów, muszę wrócić do oryginalnego Ray, aby kontynuować śledzenie. Ponieważ transformacje mogą być zagnieżdżone, oznacza to, że muszę utrzymywać cały stos Ray s dla każdego śledzonego przecięcia.

Jest to oczywiście wewnętrzna pętla całej aplikacji i główne wąskie gardło wydajności. Będzie się to nazywać miliony razy na sekundę, więc chcę zminimalizować złożoność/uniknąć niepotrzebnego przydzielania pamięci.

Czy istnieje sprytny sposób na uniknięcie konieczności przydzielania nowego Ray s/utrzymania stosu Ray?

Czy jest na to jeszcze bardziej sprytny sposób?

+1

Nie jestem pewien, czy byłby szybszy niż alokacja pamięci, ale można spróbować wymyślić skuteczny algorytm odwrócenia transformacji, a następnie pomnożyć bieżący promień z transformacją odwrotną, gdy wycofa się z bieżącego obiektu. –

+0

@Ivan - ciekawy pomysł. Wydaje mi się, że może to być nieznacznie szybsze, chociaż martwiłbym się wtedy o kompilację liczbowych problemów precyzji ..... – mikera

+0

Można wstępnie obliczać i buforować transformację i odwrotną transformację (tj. Obiekt macierzowy) dla każdego obiektu (jak również obiekty w grupie), które zostaną przekształcone w ramkę globalną i z niej. W ten sposób nie potrzebujesz zagnieżdżonej hierarchii, ponieważ możesz wykonać test trafień bezpośrednio na każdym obiekcie. To znaczy. przekształć promień w ramę obiektu, a następnie przekształć go, aby uzyskać punkt trafienia w globalnej ramce. Robię to w moim znaczniku: http://github.com/danieljfarrell/pvtrace –

Odpowiedz

2

W większości przypadków w ray-tracingu masz kilka (setek tysięcy) obiektów i całkiem sporo więcej promieni. Prawdopodobnie miliony promieni. W tym przypadku warto sprawdzić, jakie obliczenia można poświęcić na obiekty, aby przyspieszyć/ułatwić ich interakcję.

Pamięć podręczna będzie bardzo pomocna, jak zasugerował boyfarrell. Może być sensowne nie tylko tworzenie transformacji do przodu i do tyłu obiektów, które mogłyby przenosić je do lub z ramki globalnej, ale także zachowanie kopii obiektu w globalnej ramce. Dzięki temu tworzenie obiektów lub ich przenoszenie jest droższe (ponieważ zmienia się transformacja, a także buforowane kopie klatek globalnych), ale prawdopodobnie jest to w porządku.

Jeśli rzucisz promienie N i masz obiekty M i N >> M, to znaczy, że każdy obiekt będzie miał wiele promieni uderzających w niego. Jeśli założymy, że każdy promień uderza w obiekt, to każdy obiekt ma promienie N/M, które go uderzają. Oznacza to przekształcanie promieni N/M w każdy obiekt, testowanie trafień i ewentualnie cofnięcie go. Lub N/M przekształca na obiekt co najmniej. Ale jeśli buforujemy transformowany obiekt, możemy wykonać pojedynczą transformację na obiekt, aby dostać się do globalnej ramki, a następnie nie potrzebować żadnych dodatkowych. Przynajmniej do testowania trafień.

1

Zdefiniuj swoje prymitywy w ich podstawowej formie (jedność w skali, skupiona na 0,0,0, nie obrócona), a następnie przenieś je w scenę tylko za pomocą transformacji. Buforuj wynik wszystkich transformacji do przodu i do tyłu w każdym obiekcie. (Nie zapomnij o normalnych wektorach, będziesz potrzebować ich do odbicia)

To da ci możliwość przetestowania trafienia za pomocą uproszczonej matematyki (ty odwracasz transformację promienia do przestrzeni obiektu i obliczasz uderzenie z obiektem formy podstawowej) a następnie przekształć punkt trafienia i możliwy wektor odbicia z powrotem na rzeczywistą przestrzeń światową za pomocą innej transformacji.

Musisz obliczyć skrzyżowania ze wszystkimi obiektami w scenie i wybrać trafienie najbliższe promieniowi (ale nie w odległości ujemnej). Aby przyspieszyć to jeszcze bardziej, umieść wiele obiektów w "obwiedniach", które będą bardzo proste do obliczenia trafienia i przejdą promień realnego świata do zamkniętych obiektów, jeśli zostanie trafiony (ale wszystkie obiekty nadal będą używać swoich macierzy wstępnych).