2010-08-09 16 views
12

¿Cómo puedo limitar eficazmente el paso de la cámara cuando solo tengo cámara quaternion? ¿Tengo que convertir a ángulos euler y luego volver al cuaternión o hay alguna otra manera?Limite el paso de la cámara

+0

Wert, intenté pensar en una buena respuesta para las últimas horas ahora ... hombre, que ha sido años desde que lidié con cuaterniones ... ahora tengo humo saliendo de mis oídos ... Me rindo ... ;-) – ysap

Respuesta

0

cuaterniones rotación de la cámara se pueden definir como:

vector A = [x, y, z] 
Q.x = A.x * sin(theta/2) 
Q.y = A.y * sin(theta/2) 
Q.z = A.z * sin(theta/2) 
Q.w = cos(theta/2) 

Donde A es la posición y theta es el ángulo que desea girar la cámara (ajustar el tono).

Si tiene el cuaternión disponible, puede limitar el ángulo de paso verificando cada vez si el ángulo de rotación más/menos el ángulo real es correcto.

Creo que se puede evitar la conversión si establece sus límites como

+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2) 

Como coseno es una función continua esto se supone que funciona.

Si pudieras publicar el código que estás usando, tal vez podamos ayudar un poco más.

+0

Hmm ... ¿no es A el eje de la rotación? ¿Cómo puedo configurar el quaternion al límite de tono si excede los límites? – Wert

+0

A es definitivamente el eje como un vector unitario. Incluso si "posición" fuera un error tipográfico, la respuesta solo funcionaría si Q ya fuera solo la rotación de tono, no la rotación total de la cámara C. Estamos tratando de extraer Q de C. – SuperElectric

1

El tono es solo un componente de la rotación completa, por lo que si quieres pensar en tu rotación así, será mejor que almacenes el tono por separado, posiblemente usando ángulos de Euler.

Simplemente conviene convertir ángulos de Euler y volver cuando necesita limitar el movimiento podría no funcionar demasiado bien, ya que tendrá que recordar el último cuadro (si tiene alguno) para ver si pasó el límite, y en qué dirección.

Como yo lo veo, el punto principal de los cuaterniones es que no necesitas molestarte con límites como ese. Todo funciona sin ninguna singularidad. ¿Por qué exactamente quieres limitar el campo?

2

Si la cámara no tiene ningún rollo (como es habitual en muchos juegos, como los shooters en primera persona), la solución es simple. Si hay una tirada, hay un paso adicional involucrado. Comenzaré con qué hacer si no hay ninguna tirada, y generalizaré la solución sobre qué hacer si lo hay.

Deje que qc sea la rotación de la cámara. Deje qy una rotación con la misma orientación que qc, pero con paso cero. Si no hay un rollo, la rotación de la cámara es una rotación de guiñada seguida de una rotación de tono:

qc = qp * qy 

podemos recuperar la QP rotación tono que la rotación de qy de control de calidad:

qp = qc * qy^-1 

El truco , entonces, es construir qy, entonces podemos conectarlo a la ecuación anterior para resolver qp. Deje vc ser el vector de la unidad que señala desde la lente de la cámara, o el "vector de avance". Deje que vy sea el mismo vector, pero proyectado al plano horizontal y normalizado. Finalmente, deje que v0 sea el vector de avance cuando la rotación de la cámara qc es la rotación de identidad. La rotación que gira v0 en vy es la rotación de guiñada. El ángulo se puede dar como:

yaw = asin(Norm(cross(v0, vy))) 

La rotación de guiñada correspondiente es:

qy = { cos(yaw/2), up * sin(yaw/2) } 

Donde "arriba" es el vector unitario en la dirección hacia arriba, también conocido como el eje de rotación de guiñada. Enchufa esto en qp = qy^-1 * qc arriba para obtener el tono quaternion qp.Finalmente, obtener el ángulo de paso de qp como:

pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]])) 

Donde "derecha" es el vector unitario en la dirección correcta, también conocido como el eje de rotación de tono.

Como dije, las cosas se complican más si la cámara también tiene balanceo, pero la estrategia general es la misma. Usted formula la rotación de la cámara como un producto de los componentes de rotación, luego aísla el componente que desea (en este caso, el tono). Por ejemplo, si la secuencia de Euler que se utiliza para definir el "pitch" es la secuencia de guiñada-pitch-line común, se define qc como:

qc = qr * qp * qy 

Podemos definir una qx variable a las rotaciones de cabeceo y balanceo combinados :

qx = qr * qp 

ahora podemos escribir como qc:

qc = qx * qy 

ya sabemos cómo resolver para qx en esta forma, volviendo sobre los pasos que hemos utilizado anteriormente para resolver QP. Reordenar la definición para qx, obtenemos:

qp = qr^-1 * qx 

Nos acabamos de resolver para qx, por lo que para resolver la QP rotación de paso, sólo tenemos el rollo QR. Podemos construirlo usando vectores como lo hicimos anteriormente. Dejado vc sea el vector delantero otra vez. El rollo será una rotación alrededor de este vector. Deje que vu sea el vector ascendente de la cámara (en coordenadas mundiales) y deje que vu0 sea el vector ascendente de la cámara con cero desplazamiento. Podemos construir vu0 proyectando el vector ascendente global al plano perpendicular a vc, luego normalizando. La rotación del rodillo qr es entonces la rotación de vu0 a vu. El eje de esta rotación es el vector directo vc. El ángulo de balanceo es

roll = asin(Dot(vc, cross(vu0, vu))) 

El cuaternión correspondiente es:

qr = { cos(roll/2), forward * sin(roll/2) } 

Donde "hacia adelante" es el eje de rotación del rodillo.

0

Puede que sea un poco tarde a la fiesta, pero esta es la forma en que lo resolvió:

 // "Up" = local vector -> rotation * Vector3.UnitY 
     // "Forward" = local vector -> rotation * Vector3.UnitZ 
     // "Right" = local vector -> rotation * Vector3.UnitX 

    public void Rotate(Vector3 axis, float angle) 
    { 
     if (LerpRotation) 
     { 
      RotationTarget *= Quaternion.FromAxisAngle(axis, angle); 
     } 
     else 
     { 
      Rotation *= Quaternion.FromAxisAngle(axis, angle); 
     } 
     //Locking the Pitch in 180° 
     float a = Vector3.CalculateAngle(Vector3.UnitY, Up); 
     float sign = Math.Sign(Forward.Y); 
     float delta = (float)Math.PI/2 - a; 
     if(delta < 0) 
      Rotation *= Quaternion.FromAxisAngle(Right, delta * sign); 
    } 
Cuestiones relacionadas