Dans mon profileur, trouver des coordonnées barycentriques est apparemment un peu un goulot d'étranglement. Je cherche à le rendre plus efficace.
Il suit la méthode de Shirley , où vous calculez l'aire des triangles formés en incorporant le point P à l'intérieur du triangle.
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 ;
}
Cette méthode fonctionne, mais je cherche une méthode plus efficace!
barycentric-coordinates
bobobobo
la source
la source
Réponses:
Transcrit à partir de la détection de collision en temps réel de Christer Ericson (qui est d'ailleurs un excellent livre):
C'est effectivement la règle de Cramer pour résoudre un système linéaire. Vous ne serez pas beaucoup plus efficace que cela - si cela reste un goulot d'étranglement (et cela pourrait être le cas: cela ne semble pas être très différent du point de vue du calcul par rapport à votre algorithme actuel), vous devrez probablement trouver un autre emplacement. pour gagner du temps.
Notez qu'un nombre décent de valeurs ici sont indépendantes de p - elles peuvent être mises en cache avec le triangle si nécessaire.
la source
p
pour cette fonction.La règle de Cramer devrait être le meilleur moyen de le résoudre. Je ne suis pas un graphiste, mais je me demandais pourquoi dans le livre Détection de collision en temps réel, ils ne font pas la chose plus simple suivante:
Cela résout directement le système 2x2 linéaire
alors que la méthode du livre résout le système
la source
.z
dimension (en particulier, le fait qu’elle n’existe pas)?Légèrement plus rapide: Précalculez le dénominateur et multipliez au lieu de diviser. Les divisions sont beaucoup plus chères que les multiplications.
Dans mon implémentation, cependant, j'ai mis en cache toutes les variables indépendantes. J'ai précalculé ce qui suit dans le constructeur:
Donc, le code final ressemble à ceci:
la source
J'utiliserais la solution publiée par John, mais j'utiliserais les points intrinsèques SSS 4.2 et intrinsèques pour la division, en supposant que vous vous en tenez à vous limiter à Nehalem et aux processus plus récents et à une précision limitée.
Alternativement, vous pouvez calculer plusieurs coordonnées barycentriques à la fois en utilisant sse ou avx pour une accélération de 4 ou 8x.
la source
Vous pouvez convertir votre problème 3D en problème 2D en projetant l’un des plans alignés sur l’axe et en utilisant la méthode proposée par user5302. Cela donnera exactement les mêmes coordonnées barycentriques tant que vous vous assurez que votre triangle ne se projette pas dans une ligne. Le mieux est de projeter sur le plan aligné sur l’axe le plus proche possible de l’orientation de votre triagle. Cela évite les problèmes de colinéarité et garantit une précision maximale.
Deuxièmement, vous pouvez pré-calculer le dénominateur et le stocker pour chaque triangle. Cela enregistre les calculs par la suite.
la source
J'ai essayé de copier le code de @ NielW en C ++, mais je n'ai pas obtenu de résultats corrects.
Il était plus facile de lire https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Barycentric_coordinates_on_triangles et de calculer le lambda1 / 2/3 comme indiqué (aucune fonction vectorielle requise).
Si p (0..2) sont les points du triangle avec x / y / z:
Précalc pour triangle:
alors les lambdas pour un point "point" sont
la source
Pour un point N donné dans le triangle ABC, vous pouvez obtenir le poids barycentrique du point C en divisant l'aire du sous-angle ABN par l'aire totale du triangle AB C.
la source