In meinem Profiler ist das Finden von Schwerpunktkoordinaten anscheinend ein gewisser Engpass. Ich versuche es effizienter zu machen.
Es folgt der Methode in Shirley , bei der Sie die Fläche der durch Einbetten des Punkts P in das Dreieck gebildeten Dreiecke berechnen.
Code:
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 ;
}
Diese Methode funktioniert, aber ich suche eine effizientere!
barycentric-coordinates
Bobobobo
quelle
quelle
Antworten:
Transkribiert von Christer Ericsons Echtzeit-Kollisionserkennung (die übrigens ein ausgezeichnetes Buch ist):
Dies ist effektiv die Cramer-Regel für die Lösung eines linearen Systems. Sie werden nicht viel effizienter als dies sein - wenn dies immer noch ein Engpass ist (und es könnte sein, dass es in Bezug auf die Berechnung nicht viel anders aussieht als Ihr aktueller Algorithmus), müssen Sie wahrscheinlich einen anderen Ort finden eine Beschleunigung erreichen.
Beachten Sie, dass hier eine anständige Anzahl von Werten unabhängig von p ist - sie können bei Bedarf mit dem Dreieck zwischengespeichert werden.
quelle
p
für diese Funktion.Die Cramer-Regel sollte der beste Weg sein, um es zu lösen. Ich bin kein Grafiker, aber ich habe mich gefragt, warum in dem Buch Real-Time Collision Detection nicht die folgende einfache Sache gemacht wird:
Dies löst direkt das 2x2-Linearsystem
während die Methode aus dem Buch das System löst
quelle
.z
Dimension () aus (insbesondere davon, dass sie nicht existiert)?Etwas schneller: Den Nenner vorberechnen und multiplizieren statt dividieren. Divisionen sind viel teurer als Multiplikationen.
In meiner Implementierung habe ich jedoch alle unabhängigen Variablen zwischengespeichert. Ich habe folgendes im Konstruktor vorberechnet:
Der endgültige Code sieht also so aus:
quelle
Ich würde die von John veröffentlichte Lösung verwenden, aber ich würde für die Teilung die intrinsische Punktzahl SSS 4.2 und die intrinsische Punktzahl sse rcpss verwenden, vorausgesetzt, Sie beschränken sich in Ordnung auf Nehalem und neuere Prozesse und beschränkte Präzision.
Alternativ können Sie mit sse oder avx mehrere Schwerpunktkoordinaten gleichzeitig für eine 4- oder 8-fache Beschleunigung berechnen.
quelle
Sie können Ihr 3D-Problem in ein 2D-Problem umwandeln, indem Sie eine der achsenausgerichteten Ebenen projizieren und die von user5302 vorgeschlagene Methode anwenden. Dies führt zu genau den gleichen Schwerpunktkoordinaten, solange Sie sicherstellen, dass Ihr Dreieck nicht in eine Linie hineinragt. Am besten projizieren Sie auf die achsenausgerichtete Ebene, die so nah wie möglich an der Ausrichtung Ihres Triagles liegt. Dies vermeidet Co-Linearitätsprobleme und gewährleistet maximale Genauigkeit.
Zweitens können Sie den Nenner vorberechnen und für jedes Dreieck speichern. Dies spart später Berechnungen.
quelle
Ich habe versucht, den Code von @ NielW nach C ++ zu kopieren, aber ich habe keine korrekten Ergebnisse erhalten.
Es war einfacher, https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Barycentric_coordinates_on_triangles zu lesen und das Lambda1 / 2/3 wie dort angegeben zu berechnen (keine Vektorfunktionen erforderlich).
Wenn p (0..2) die Punkte des Dreiecks mit x / y / z sind:
Precalc für Dreieck:
dann sind die Lambdas für einen Punkt "Punkt"
quelle
Für einen gegebenen Punkt N innerhalb des Dreiecks ABC können Sie das Schwerpunktgewicht von Punkt C erhalten, indem Sie die Fläche des Subtriangels ABN durch die Gesamtfläche des Dreiecks AB C dividieren.
quelle