2010-01-19 24 views
16

Así que he un plano 3D descrito por 2 Vectores:Dada una superficie normal, encontrar rotación para Plane 3D

P: un punto que se encuentra en el Plano
N: la superficie normal para el plano

Y tengo un polígono cuadrado muy grande, plano, que quiero representar para representar este plano. Puedo traducir fácilmente el polígono al punto dado, pero luego necesito encontrar la rotación adecuada para aplicar para que la superficie normal sea realmente la superficie normal.

probé un método mencionado en otro lugar que era:

1) Tomar cualquier vector paralelo ninguno (V) a la normal (N), y tomar el producto cruzado (W1)
2) Tomar el producto vectorial de (W1) y (N) ahora (W2) y que es un vector (V ') que se encuentra en el Plano

entonces generar una matriz de rotación basado en (V') que pone en el Plano, para que mi polígono esté alineado con (V '). eso funcionó, pero está claro que este método no funciona correctamente como un todo. El Polígono no es perfectamente perpendicular a la superficie normal.

¿Alguna idea sobre cómo generar la rotación correcta?

Respuesta

13

Algunas cosas útiles acerca de rotaciones:

  • Cualquier tres vectores ortonormales dispuestos como filas definen una transformación en una nueva base (una rotación en esa base).
  • La transposición de cualquier rotación es inversa.
  • Por lo tanto, cualesquiera tres vectores ortonormales dispuestos como columnas definen una rotación desde alguna base en su marco de referencia "mundial".

Por lo tanto, el problema es encontrar cualquier conjunto de tres vectores ortonormales y disponerlos como

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

esto es exactamente lo que el método que se describe trata de hacer, si no funciona, entonces hay es un problema con su implementación.

Obviamente podemos usar su normal como (x1, y1, z1), pero el problema es que el sistema tiene infinitas soluciones para los dos vectores restantes (aunque conocer uno de ellos le da al otro, como producto cruzado) . El siguiente código debe dar un vector estable perpendicular a (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]; 

Esto básicamente utiliza Gram-Schmidt descomposición ortogonal con la dimensión que ya es más ortogonal al vector normal.v3 puede obtenerse tomando el producto cruzado de normal y v2.

Es posible que deba tener cuidado al configurar la rotación, se trata del origen, por lo que debe aplicar la traducción después de la rotación y para los vectores de columnas en lugar de los vectores de filas. Si usa OpenGL, observe que OpenGL toma las matrices en orden principal de la columna (en lugar del orden principal de la fila de C), por lo que es posible que deba transponer.

Me temo que no he probado lo anterior, simplemente lo he atrapado de algún código que escribí hace un tiempo y lo he adaptado a su problema. Espero no haber olvidado ningún detalle.

Edit: se olvidó de algo :)

La matriz anterior supone su normal al polígono es a lo largo del eje x, y tengo la sospecha de que no será, todo lo que necesita hacer es coloque el vector "normal" en la columna correcta de la matriz de rotación, y v2/v3 en las otras dos columnas. Entonces, si la normal a su polígono es a lo largo del eje z, entonces la normal va en la tercera columna y v2/v3 en las dos primeras columnas.

Lo siento si eso causa alguna confusión.

+2

Por una razón aleatoria me encuentro revisitando esta respuesta, cuando selecciono la dimensión más ortogonal debería haber usado el valor absoluto de los componentes normales del vector; lo he corregido en la respuesta. –

+0

¿Qué pasa si la normal no está en ninguno de los ejes? Si, en cambio, es algo así como <1, 1, 1>? – Ren

+0

El algoritmo asigna una normalidad arbitraria a uno de los ejes (o viceversa), si desea rotar una normal a otra normal, encontraría una rotación sobre el producto cruzado de las dos normales. –

2

No está seguro de qué método se está utilizando para hacer, pero los préstamos de 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]; 
    } 
} 

Esperemos que esto le dará una idea para su aplicación. No soy muy bueno con los cuaterniones que podrían tener una solución más simple, pero este método funciona bien para mí.

+0

Hhhmmm ... ¿Así que esto daría una matriz de rotación para apuntar una cámara en un punto específico? Adaptando esto a mi problema, ¿necesitaría un vector para rotar a no? – Adam

+0

Esto daría una rotación a la cámara, necesita la posición del ojo (los vectores también son posiciones en OSG), la posición central (su P) y luego su vector ascendente (N). Dices que necesitas hacer que la superficie sea normal, en realidad la superficie sea normal y no estoy seguro de a qué te refieres con eso. ¿Quieres mirar directamente al centro del avión desde un punto en el vector normal? Si es así, coloque la posición de su ojo en una escala normalizada hacia arriba. PD Alguien más piensa que es gracioso que todos se llamen Adam aquí :) –

+0

Ya parece ser un nombre común: P Lo siento si mi pregunta es confusa, en realidad no quiero hacer nada con mi cámara. Quiero rotar mi polígono para que mi Surface Normal, que se calcula en otro lugar, sea igual a la del Polígono (si tuviera que calcularlo) – Adam

Cuestiones relacionadas