Co dokładnie powoduje, że powierzchnia nakłada się na inną?

10

Naprawdę nie mogę zrozumieć, co powoduje, że jedna powierzchnia zachodzi na drugą. W silniku 3D, który tworzę, moja technika zawodzi w skrajnych przypadkach.

Moją metodą jest sortowanie powierzchni do malowania od najdalszych do najbliższych. Aby określić bliskość, porównuję średnie wartości z. Czasami jednak nakładająca się powierzchnia ma wyższą średnią wartość Z niż ta, na którą się nakłada. Tak więc powierzchnia znajdująca się dalej jest namalowana na bliższej, co powoduje dziwne renderowanie:

Duży fioletowy kwadrat z czerwoną częścią z boku

To, co należy zobaczyć, to tylko fioletowa przednia powierzchnia sześcianu, podczas gdy czerwona powierzchnia boczna jest pomalowana na fioletowej. Średnia wartość Z fioletowej powierzchni jest wyższa, a zatem „dalej”. Mam wątpliwości, czy ta technika jest poprawna.

Próbowałem też uzyskać odległość od aparatu (tj. Początek) do powierzchni, ale wtedy potrzebowałem punktu. Wybrałem środek każdej powierzchni, ale nie zawsze wydaje się to działać, ponieważ nie wszystkie powierzchnie są tak duże od siebie.

Dlatego jaki jest niezawodny sposób określenia kolejności bliskości powierzchni w stosunku do źródła?

pimvdb
źródło

Odpowiedzi:

11

Wygląda na to, że próbujesz wdrożyć algorytm malarzy . Zgaduję, że próbujesz napisać rasterizer od zera jako ćwiczenie edukacyjne, ponieważ większość współczesnego sprzętu 3D wykorzystuje to, o czym wspomniał Bart (bufor Z / Depth). Aby algorytm malarzy działał we wszystkich przypadkach, trzeba być przygotowanym na podział powierzchni podczas renderowania w celu rozwiązania możliwych scenariuszy (takich jak nakładający się problem wielokąta pokazany na stronie Wikipedii).

Renderując od najdalszego do najbliższego, spędzasz również czas renderując piksele, które być może później zostaną zasłonięte przez inne wielokąty, co gdy zaczniesz nakładać tekstury i złożone shadery na wielokąty, marnuje cenne cykle. To jest powód, dla którego nowoczesny sprzęt wolałby renderować od przodu do tyłu, używając bufora głębokości, aby ustalić, czy piksel, który ma być renderowany, znajduje się dalej niż piksel na ekranie (i dlatego może zostać odrzucony).

Nawet z najnowocześniejszym sprzętem przyspieszającym nadal będziesz musiał sortować i renderować od pół do przodu wszystkie półprzezroczyste wielokąty, renderując to dopiero po renderowaniu wszystkich nieprzezroczystych wielokątów.

Roger Perkins
źródło
Masz rację mówiąc, że tworzę prosty renderer. Chodzi o to, że nie używam żadnych bibliotek 3D. Sam wykonuję wszystkie obliczenia rzutowania, a następnie rysuję linie za pomocą biblioteki rysunków 2D. To nie jest najszybszy i nie robię nic na podstawie jednego piksela. Mam tylko 4 punkty na każdej powierzchni i wypełniam prostokątny kształt kolorem. Ponieważ od razu rysuję całą powierzchnię, czy mam rację mówiąc, że muszę rysować od tyłu?
pimvdb
Brzmi jak świetna zabawa i świetny sposób na naukę. Od początku do końca to jedyny sposób, jeśli robisz to bez jakiejkolwiek formy bufora głębokości. Myślę, że będziesz musiał ustalić wszystkie współrzędne ekranowe swoich wielokątów, a następnie sprawdzić, czy nie zachodzą na siebie. Tam, gdzie nakładają się na siebie, potencjalnie będziesz musiał pokroić wielokąty, aby je renderować, aby właściwie rozwiązać sortowanie. Warto również zajrzeć do tylnej powierzchni uboju jako sposób usunięcia wielokątów, które niekoniecznie powinny być widoczne
Roger Perkins
Roger Perkins ma rację. W ten sposób nie będziesz w stanie osiągnąć prawidłowego sortowania w Z (co oznacza, że ​​zawsze będziesz mieć pewne przypadki na krawędziach), chyba że pokroisz wielokąty. To może jednak stać się raczej powolne.
bummzack
Mam to działa! To, co zrobiłem, było kombinacją wygładzania i sortowania od tyłu: w solidnym sześcianie niektóre twarze nie są widoczne, podczas gdy inne są (maksymalnie 3). Więc najpierw pomalowałem niewidoczne części, a widoczne nad nimi części. Działa to jak urok, jeśli usunę jedną lub więcej stron, będą się one nakładać, ale nadal będą rysowane we właściwej kolejności. Dzięki!
pimvdb
1
Będzie to działać tylko w przypadku prostych wypukłych kształtów, takich jak kostki. Cieszę się, że obecnie to dla ciebie działa, ale nie jest to ogólne rozwiązanie.
Richard Fabian
3

To, co masz, to problem z widocznością . Jednym z rozwiązań jest za pomocą bufora Z .

Bart van Heukelom
źródło
Dzięki, ale buforowanie Z wymaga renderowania na piksel, jeśli się nie mylę. Nie robię tego - rysuję proste linie między rzutowanymi punktami sześcianu. Czy buforowanie Z jest nadal możliwe?
pimvdb
Nawet jeśli rysujesz linie proste, w pewnym momencie, zanim obraz dotrze do ekranu (lub pliku bitmapy), będzie miał format pikseli.
Bart van Heukelom
Zgadza się, ale moja biblioteka rysunków jest zbyt wolna, aby renderować piksele przy 20 klatkach na sekundę. W każdym razie dzięki.
pimvdb
2

Sortowanie ścian według ich średniej wartości Z nie działa, ponieważ średnia wartość Z nie dostarcza informacji o rzeczywistej wartości Z wierzchołków, a nawet pikseli powierzchni.

Przykład (ostrzeżenie, grafika ASCII przed nami):

          /
         /
cam     /
-->    / 
      /
     /--       <--B
    /
    ^--A

Istnieją dwie twarze A i B. Z perspektywy aparatu A znajduje się przed B. Jednak średnia wartość Z dla B jest mniejsza. Spójrzmy na inne wartości Z:

  • minimalna wartość Z dla A wynosi 4
  • maksymalna wartość Z dla A wynosi 11
  • dlatego średnia wartość Z dla A wynosi 7,5
  • minimalna wartość Z dla B wynosi 6
  • maksymalna wartość Z dla B wynosi 8
  • dlatego średnia wartość Z dla B wynosi 7

Możesz spróbować posortować je według ich minimalnych wartości Z, ale są przypadki, w których to też nie zadziała. Po prostu nie ma możliwości prawidłowego sortowania dowolnych ścian przy użyciu tylko jednej wartości Z.

W algorytmie Newella http://en.wikipedia.org/wiki/Newell 's_algorytm to, co robisz, to sortowanie zakresów min / max wartości Z. Jeśli zakresy dwóch ścian się nie pokrywają, możesz być pewien, która z nich jest z przodu. Jeśli tak, czasami trzeba absolutnie podzielić twarze. Czasami wystarczy prześledzić każdy wierzchołek w celu okluzji lub innej techniki.

Jonas Bötel
źródło
Ten schemat to ogólny widok tego, co chciałem odgadnąć na jego zrzucie ekranu.
jhocking
1

Dobrze, że uczysz się o renderowaniu przez działanie. Sława. W tym przypadku nie ma rozwiązania „algorytmu malarzy”, zamiast próbować to naprawić przez sortowanie, na PS1 próbowaliśmy utrzymać wielokąty mniej więcej tego samego rozmiaru, gdy były obok siebie (co robisz jako o ile mogę powiedzieć) i cull backface (czego nie robisz)

Wykończenie tylnej powierzchni sprawdza, czy powierzchnia jest normalna w przestrzeni ekranu pod kątem jej kierunku (wystarczy uzyskać znak elementu głębokości z przestrzeni ekranu przekształconej normalnie (w naszym przypadku była to wartość z normy) lub iloczyn krzyżowy dwóch wektorów trójkąt tj. krzyż (v1-v0, v2-v0))

Jeśli zastosujesz culling backface, zmniejszysz również ilość rasteryzacji, którą wykonujesz .. podwójna wygrana.

Richard Fabian
źródło
Dzięki za twoją odpowiedź. Czytałem o wygładzaniu tylnej powierzchni, ale chodzi o to, że chciałbym móc usunąć jedną stronę. Z solidnym sześcianem może to działać po prostu świetnie, ale jeśli usunę jedną stronę, nastąpi okluzja - więc chyba nadal muszę je posortować. W każdym razie wpadłem na pomysł, aby wystrzelić promień od źródła przez środek powierzchni. Jeśli promień ten przecina następnie inną powierzchnię, wówczas pierwsza powierzchnia nakłada się na drugą. Czy mógłbyś mi powiedzieć, czy ten pomysł jest właściwy? Dzięki!
pimvdb
Chociaż Twój pomysł zadziałałby na przykładowy przypadek, istnieje wiele innych przypadków, w których nie zadziała. Na przykład ta sama scena, którą tam masz, ale z kamerą pochyloną, aby środek nieprawidłowego kwadratu renderowania nie zachodził na siebie. Myślę, że będziesz musiał podzielić te prymitywy na mniejsze kawałki.
Richard Fabian,