W moim profilu znajdowanie współrzędnych barycentrycznych jest w pewnym sensie wąskim gardłem. Chcę sprawić, by był bardziej wydajny.
Podąża za metodą Shirleya , w której oblicza się powierzchnię trójkątów utworzonych przez osadzenie punktu P wewnątrz trójkąta.
Kod:
Vector Triangle::getBarycentricCoordinatesAt( const Vector & P ) const
{
Vector bary ;
// The area of a triangle is
real areaABC = DOT( normal, CROSS( (b - a), (c - a) ) ) ;
real areaPBC = DOT( normal, CROSS( (b - P), (c - P) ) ) ;
real areaPCA = DOT( normal, CROSS( (c - P), (a - P) ) ) ;
bary.x = areaPBC / areaABC ; // alpha
bary.y = areaPCA / areaABC ; // beta
bary.z = 1.0f - bary.x - bary.y ; // gamma
return bary ;
}
Ta metoda działa, ale szukam bardziej wydajnej!
barycentric-coordinates
Bobobobo
źródło
źródło
Odpowiedzi:
Przepisywane z Christer Ericson's Real-Time Collision Detection (która, nawiasem mówiąc, jest doskonałą książką):
Jest to skutecznie reguła Cramera polegająca na rozwiązaniu układu liniowego. Nie zyskasz o wiele bardziej wydajnego niż to - jeśli nadal jest to wąskie gardło (a może być: nie wygląda na to, że różni się znacznie obliczeniami od obecnego algorytmu), prawdopodobnie będziesz musiał znaleźć inne miejsce aby przyspieszyć.
Zauważ, że przyzwoita liczba wartości jest tutaj niezależna od p - w razie potrzeby można je buforować za pomocą trójkąta.
źródło
p
dla tej funkcji.Reguła Cramera powinna być najlepszym sposobem na jego rozwiązanie. Nie jestem grafikiem, ale zastanawiałem się, dlaczego w książce Wykrywanie kolizji w czasie rzeczywistym nie robią następującej prostszej rzeczy:
To bezpośrednio rozwiązuje układ liniowy 2x2
podczas gdy metoda z książki rozwiązuje system
źródło
.z
) wymiaru (a konkretnie tego, że nie istnieje)?Nieco szybciej: oblicz wstępnie mianownik i pomnóż zamiast dzielić. Podziały są znacznie droższe niż mnożenie.
Jednak w mojej implementacji buforowałem wszystkie zmienne niezależne. Obliczam wstępnie w konstruktorze:
Ostateczny kod wygląda następująco:
źródło
Użyłbym rozwiązania opublikowanego przez Johna, ale użyłbym wewnętrznego SSS 4.2 i wewnętrznego rcpss dla podziału, zakładając, że nie przeszkadzasz sobie w Nehalem i nowszych procesach i ograniczonej precyzji.
Alternatywnie możesz obliczyć kilka współrzędnych barycentrycznych jednocześnie za pomocą sse lub avx dla przyspieszenia 4 lub 8x.
źródło
Możesz przekształcić swój problem 3D w problem 2D, rzutując jedną z płaszczyzn wyrównanych do osi i używając metody zaproponowanej przez user5302. Spowoduje to uzyskanie dokładnie takich samych współrzędnych barycentrycznych, o ile upewnisz się, że trójkąt nie wystaje w linię. Najlepiej jest rzutować na płaszczyznę wyrównaną do osi, która jest jak najbliżej orientacji twojego triagla. Pozwala to uniknąć problemów z współliniowością i zapewnia maksymalną dokładność.
Po drugie, możesz wstępnie obliczyć mianownik i zapisać go dla każdego trójkąta. Zapisuje to później obliczenia.
źródło
Próbowałem skopiować kod @ NielW do C ++, ale nie otrzymałem poprawnych wyników.
Łatwiej było przeczytać https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Barycentric_coordinates_on_triangles i obliczyć lambda1 / 2/3 jak tam podano (żadne funkcje wektorowe nie są potrzebne).
Jeśli p (0..2) to punkty trójkąta o x / y / z:
Precalc dla trójkąta:
wtedy są lambdami dla „punktu” Punktu
źródło
Dla danego punktu N wewnątrz trójkąta ABC można uzyskać masę barocentryczną punktu C, dzieląc obszar podtrójkąta ABN przez całkowitą powierzchnię trójkąta AB C.
źródło