Programowo generujące normalne wierzchołki

11

Pracuję z interfejsem API Kinect, który zapewnia tablicę wierzchołków i indeksów dla trójkątów, które mają być renderowane w celu utworzenia obrazu twarzy.

Liczba wierzchołków i ich kolejność w tablicy, a także wskaźniki podane przez kinect są zawsze stałe.

Jednak API nie podaje żadnych informacji na temat danych UV i normalnych wierzchołków.

Aplikacja wymaga ode mnie utrzymywania kolejności wierzchołków podanej przez kinect, ponieważ ich pozycje w przestrzeni 3D zmieniają się zgodnie z ruchem twarzy, więc generowanie UV i normalnych w oprogramowaniu do edycji 3D nie wchodzi w rachubę.

Udało mi się wygenerować UV, rzutując pozycje wierzchołków na płaszczyznę 2D, ponieważ na tej samej płaszczyźnie było bardzo mało wierzchołków.

Jednak nie wiem, jak wygenerować normalne wierzchołki dla siatki, bez normalnego wierzchołka siatka twarzy rysuje bez głębokości swoich elementów z perspektywy, chociaż sylwetka jest widoczna, ponieważ pozycje wierzchołków są prawidłowe.

Rozumiem, że z powodu braku normalnych wierzchołków oświetlenie nie działa na nim poprawnie, a zatem blada, pozbawiona cech siatka wygląda teraz.

więc jak wygenerować normalne wierzchołki, gdy wszystko, co mam, to po prostu pozycja wierzchołków i indeks wierzchołków, z których można zrobić trójkąty?

Allahjane
źródło
n = (v1 - v0) x (v2 - v0), gdzie v0, v1 i v2 są wierzchołkami danej (trójkątnej) powierzchni. Zamówienie jest ważne. Normalizuj, jeśli naprawdę potrzebujesz. (i xjest produktem krzyżowym)
3Dave

Odpowiedzi:

14

Obliczanie wartości normalnej z pozycji wierzchołków jest dość proste przy użyciu iloczynu wektorowego.

Iloczyn dwóch wektorówu i v (odnotowany u×vlub czasami uv) jest wektorem prostopadłym do u i vo długości ||u×v||=||u||||v||sjan(θ), z θ kąt pomiędzy u i v. Kierunek wektora będzie zależeć od kolejności mnożenia:u×v jest przeciwieństwem v×u (dwa kierunki prostopadłe do płaszczyzny).

Jeśli nie jesteś zaznajomiony z produktem krzyżowym, zapraszam do zapoznania się z nim i do zapoznania się z nim. Normalne będą wtedy wydawać się proste.

Płaskie normalne zacienienie

Jeśli masz trójkąt ZAbdo, ZAb×ZAdojest wektorem prostopadłym do trójkąta i o długości proporcjonalnej do jego powierzchni. Ponieważ normalna jest wektorem jednostek prostopadłym do płaszczyzny trójkąta, można uzyskać normalną za pomocą:

N.=ZAb×ZAdo||ZAb×ZAdo||

W kodzie wyglądałoby to n = normalize(cross(b-a, c-a))na przykład. Po prostu zastosuj to na wszystkich twarzach, a będziesz mieć swoje normalne na twarz.

For each triangle ABC
    n := normalize(cross(B-A, C-A))
    A.n := n
    B.n := n
    C.n := n

Zauważ, że zakłada to, że wierzchołki nie są dzielone między trójkąty. Nie znam interfejsu API Kinect; jest całkiem możliwe, że są one udostępnione, w takim przypadku musisz je zduplikować lub przejść do następnego rozwiązania:

Płynne cieniowanie normalne

Po oświetleniu za pomocą normalnych obliczonych jak powyżej zauważysz, że krawędzie trójkąta są widoczne. Jeśli nie jest to pożądane, możesz zamiast tego obliczyć gładkie normalne, biorąc pod uwagę wszystkie twarze, które mają ten sam wierzchołek.

Chodzi o to, że jeśli ten sam wierzchołek jest wspólny dla trzech trójkątów T.1, T.2) i T.3) na przykład normalny N. będzie średnią z N.1, N.2) i N.3). Co więcej, jeśliT.1 to duży trójkąt T.2) jest malutki, prawdopodobnie chcesz N. być pod większym wpływem N.1 niż przez N.2).

Pamiętasz, jak iloczyn krzyżowy jest proporcjonalny do powierzchni? Jeśli dodasz produkty krzyżowe, a następnie znormalizujesz sumę, zrobi dokładnie taką sumę ważoną, jak chcemy. Algorytm staje się:

For each vertex
    vertex.n := (0, 0, 0)

For each triangle ABC
    // compute the cross product and add it to each vertex
    p := cross(B-A, C-A)
    A.n += p
    B.n += p
    C.n += p

For each vertex
    vertex.n := normalize(vertex.n)

Technikę tę szczegółowo wyjaśnia Iñigo Quilez: sprytna normalizacja siatki .


Aby uzyskać więcej informacji na temat normalnych, zobacz także:

Julien Guertault
źródło
Dam to
szybko
To działało Dzięki tonnemu człowiekowi, działało dokładnie tak, jak chciałem
Allahjane,
@Allahjane: Cieszę się, że działało dobrze. :)
Julien Guertault,