2010-01-19 4 views
16

J'ai un plan 3D décrit par 2 vecteurs:Compte tenu d'une surface normale, trouver rotation 3D avion

P: un point qui se trouve sur le plan
N: la surface normale pour le plan

Et j'ai un très grand polygone carré plat, que je veux rendre pour représenter ce plan. Je peux facilement traduire le polygone au point donné, mais ensuite j'ai besoin de trouver la rotation correcte à appliquer pour que la surface normale soit réellement la surface normale.

I a essayé un procédé mentionné ailleurs où était:

1) Prendre tout aucun vecteur parallèle (V) à la normale (N), et prendre le produit croisé (W1)
2) Prendre le produit vectoriel de (W1) et (N) présent (W2) et qui est un vecteur (V «) qui se trouve sur le plan

I puis générer une matrice de rotation par rapport à (V ») est couché sur la Plan, de sorte que mon polygone soit aligné avec (V '). cela a fonctionné, mais il est clair que cette méthode ne fonctionne pas correctement dans son ensemble. Le polygone n'est pas parfaitement perpendiculaire à la surface normale.

Des idées sur la façon de générer la rotation appropriée?

Répondre

13

Certaines choses utiles sur les rotations:

  • Les trois vecteurs orthonormés disposés en rangées définissent une transformation en une nouvelle base (une rotation dans cette base).
  • La transposition de toute rotation est son inverse.
  • Ainsi, trois vecteurs orthonormés disposés en colonnes définissent une rotation d'une certaine base dans votre cadre de référence "monde".

Ainsi, le problème est de trouver un ensemble de trois vecteurs orthonormés et les organiser comme

| x1 x2 x3 0 | 
| y1 y2 y3 0 | 
| z1 z2 z3 0 | 
| 0 0 0 1 | 

c'est exactement ce que la méthode décrite essaie de faire, si cela ne fonctionne pas, alors il est un problème avec votre implémentation.

Nous pouvons évidemment utiliser votre normal comme (x1, y1, z1), mais le problème est que le système a une infinité de solutions pour les deux vecteurs restants (bien que connaître l'un d'eux vous donne l'autre, comme produit croisé) . Le code suivant devrait donner un vecteur stable perpendiculaire à (x1, y1, z1):

float normal[3] = { ... }; 

int imin = 0; 
for(int i=0; i<3; ++i) 
    if(std::abs(normal[i]) < std::abs(normal[imin])) 
     imin = i; 

float v2[3] = {0,0,0}; 
float dt = normal[imin]; 

v2[imin] = 1; 
for(int i=0;i<3;i++) 
    v2[i] -= dt*normal[i]; 

Il utilise essentiellement Gram-Schmidt orthogonalisation avec la dimension qui est déjà le plus orthogonal au vecteur normal.v3 peut alors être obtenu en prenant le produit croisé normal et v2.

Vous devrez peut-être prendre soin de configurer la rotation, il s'agit de l'origine, donc vous devez appliquer la translation après la rotation et c'est pour les vecteurs colonnes plutôt que pour les vecteurs lignes. Si vous utilisez OpenGL, assurez-vous qu'OpenGL accepte les tableaux dans l'ordre des colonnes (plutôt que dans l'ordre majeur de la rangée C), donc vous devrez peut-être transposer. Je crains de ne pas avoir testé ce qui précède, je l'ai simplement récupéré à partir d'un code que j'ai écrit il y a un certain temps et je l'ai adapté à votre problème! J'espère n'avoir oublié aucun détail.

Edit: J'ai oublié quelque chose :)

La matrice ci-dessus suppose votre normale au polygone est le long de l'axe x, et je soupçonne de Furtif il ne sera pas, tout ce que vous devez faire est Mettez le vecteur "normal" dans la colonne correcte de la matrice de rotation, et v2/v3 dans les deux autres colonnes. Donc, si la normale à votre polygone est le long de l'axe z, alors la normale va dans la troisième colonne et v2/v3 vont dans les deux premières colonnes. Nous sommes désolés si cela peut causer de la confusion.

+2

Pour une raison aléatoire je me retrouve à revoir cette réponse, quand je choisis la dimension la plus orthogonale j'aurais dû utiliser la valeur absolue des composantes du vecteur normal - j'ai corrigé cela dans la réponse. –

+0

Que faire si la normale n'est pas le long des axes? Si, à la place, c'est quelque chose comme <1, 1, 1>? – Ren

+0

L'algorithme mappe une normale arbitraire sur l'un des axes (ou l'inverse), si vous voulez faire tourner une normale sur une autre normale, je trouverais une rotation autour du produit croisé des deux normales. –

2

Je ne sais pas quelle méthode que vous utilisez pour rendre, mais empruntant OpenSceneGraph's matrix:

void Matrix_implementation::makeLookAt(const Vec3d& eye,const Vec3d& center,const Vec3d& up) 
{ 
    Vec3d f(center-eye); 
    f.normalize(); 
    Vec3d s(f^up); 
    s.normalize(); 
    Vec3d u(s^f); 
    u.normalize(); 

    set(
     s[0],  u[0],  -f[0],  0.0, 
     s[1],  u[1],  -f[1],  0.0, 
     s[2],  u[2],  -f[2],  0.0, 
     0.0,  0.0,  0.0,  1.0); 

    preMultTranslate(-eye); 
} 

inline void Matrixd::preMultTranslate(const Vec3d& v) 
{ 
    for (unsigned i = 0; i < 3; ++i) 
    { 
     double tmp = v[i]; 
     if (tmp == 0) 
      continue; 
     _mat[3][0] += tmp*_mat[i][0]; 
     _mat[3][1] += tmp*_mat[i][1]; 
     _mat[3][2] += tmp*_mat[i][2]; 
     _mat[3][3] += tmp*_mat[i][3]; 
    } 
} 

Espérons que cela vous donnera une idée pour votre mise en œuvre. Je ne suis pas très bon avec les quaternions qui pourraient avoir une solution plus simple, mais cette méthode fonctionne bien pour moi.

+0

Hhhmmm ... Donc, cela donnerait une matrice de rotation pour pointer une caméra à un point spécifique? En adaptant ceci à mon problème, j'aurais besoin d'un vecteur pour tourner à non? – Adam

+0

Cela donnerait une rotation pour la caméra, vous avez besoin de la position de l'œil (les vecteurs sont aussi des positions dans OSG), la position centrale (votre P), puis votre vecteur haut (N). Vous dites que vous devez rendre la surface normale et la surface normale et je ne suis pas sûr de ce que vous entendez par là. Voulez-vous regarder directement le centre de l'avion à partir d'un point sur le vecteur normal? Si c'est le cas, placez votre oeil sur une échelle normalisée. P.S. Quelqu'un d'autre pense que c'est drôle tout le monde est nommé Adam ici :) –

+0

Ya il semble être un nom commun ici: P Désolé si ma question est confuse, je ne veux pas vraiment faire quoi que ce soit avec mon appareil photo. Je veux faire pivoter mon polygone de sorte que ma surface normale, qui est calculée ailleurs, soit la même que celle du polygone (si je devais le calculer) – Adam

Questions connexes