Estoy codificando una mecánica que permite a un usuario moverse alrededor de la superficie de una esfera. La posición en la esfera se almacena actualmente como theta
y phi
, donde theta
es el ángulo entre el eje z y la proyección xz de la posición actual (es decir, la rotación alrededor del eje y), y phi
es el ángulo desde el eje y hasta la posición. Lo expliqué mal, pero es esencialmente theta = yaw
,phi = pitch
Vector3 position = new Vector3(0,0,1);
position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta);
position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta);
position.Z = (float)Math.Cos(phi);
position *= r;
Creo que esto es correcto, sin embargo, podría estar equivocado. Necesito poder moverme en una dirección pseudo bidimensional arbitraria alrededor de la superficie de una esfera en el origen del espacio mundial con radio r
. Por ejemplo, sostener Wdebe moverse alrededor de la esfera en una dirección hacia arriba en relación con la orientación del jugador.
Creo que debería estar usando un Quaternion para representar la posición / orientación en la esfera, pero no puedo pensar en la forma correcta de hacerlo. La geometría esférica no es mi fuerte.
Esencialmente, necesito completar el siguiente bloque:
public void Move(Direction dir)
{
switch (dir)
{
case Direction.Left:
// update quaternion to rotate left
break;
case Direction.Right:
// update quaternion to rotate right
break;
case Direction.Up:
// update quaternion to rotate upward
break;
case Direction.Down:
// update quaternion to rotate downward
break;
}
}
(1,1,1)
mantiene a la izquierda rotaría alrededor de la esfera, pasaría(~1.2,0,~-1.2)
, luego(-1,-1,-1)
, luego(~-1.2,0,~1.2)
y volvería a(1,1,1)
.theta
y, aphi
medida que se actualiza su posición, está haciendo su problema innecesariamente complejo. Mucho más fácil simplemente calcular los 2 ejes de rotación de cada cuadro (uno de los cuales (guiñada) nunca cambia) yVector3.Transorm
alrededor de la esfera. Esto simplificaría su problema pero hará que se desconecte conphi
&theta
.Respuestas:
En realidad, resulta que no puedes tenerlo "en ambos sentidos": si tu intención es no tener ningún sentido de "orientación absoluta" en la esfera (es decir, si los jugadores no siempre están, por ejemplo, mirando hacia los polos ), deberá tener una noción de orientación del jugador. Esto se debe a que, contrariamente a lo que pueda sugerir la intuición, el movimiento en la esfera no es exactamente como el movimiento en un plano, ni siquiera localmente (bastante); ¡La curvatura intrínseca de la esfera significa que los jugadores pueden tomar acciones que rotarán por sí mismos!
Para el ejemplo más extremo de lo que estoy hablando, imagine que el jugador comienza en un punto del ecuador (por conveniencia, imaginaremos una cara del reloj mapeada en el ecuador desde arriba, y colocaremos al jugador a las 6 en punto ), mirando hacia arriba, es decir, hacia el Polo Norte. Supongamos que el jugador camina hasta el Polo Norte; entonces se enfrentarán directamente hacia el punto de las 12 en punto. Ahora, deje que el jugador se mueva directamente a su derecha, desde el Polo Norte de regreso al ecuador; terminarán en el punto de las 3 en punto, pero porque su orientación no cambia cuando se mueven a la derecha(la idea es que su orientación no cambia sin importar cómo se muevan), aún estarán frente al punto de las 12 en punto, ¡ahora están orientados a lo largo del ecuador! Ahora, déjelos moverse 'hacia atrás' de regreso a su punto inicial (6 en punto); entonces todavía estarán orientados a lo largo del ecuador, por lo que estarán orientados hacia el punto de las 3 en punto, simplemente moviéndose a lo largo de la esfera sin cambiar nunca su orientación 'personal' les ha hecho rotar desde la orientación hacia el polo norte hacia mirando a lo largo del ecuador! En cierto sentido, esta es una elaboración de la vieja broma 'un cazador se mueve una milla al sur, una milla al oeste y luego una milla al norte', pero aquí estamos aprovechando la curvatura de la esfera para efectuar un cambio de dirección. Tenga en cuenta que el mismo efecto todavía ocurre incluso en escalas mucho más pequeñas;
Afortunadamente, los cuaterniones manejan esta situación (como notó usted mismo); Como un cuaternión representa una rotación arbitraria, efectivamente representa un 'punto más orientación' arbitrario en la esfera: imagínese comenzando con una 'triaxis' en el origen y dándole cierta rotación arbitraria, luego moviendo una unidad en cualquier dirección de los ejes rotados ' Puntos del eje Z; un poco de pensamiento lo convencerá de que esto lo lleva a un punto en la esfera de la unidad con alguna 'orientación' (es decir, una disposición de los ejes X e Y de su triaxis), y que puede llegar a cada punto + orientación en el Esfera de unidad de esta manera (solo asigne su eje Z para apuntar a lo largo de la línea desde el origen a través de su punto en la esfera, luego transporte sus triaxes de regreso al origen a lo largo de esa línea). Y lo que es más, Dado que la multiplicación de los cuaterniones corresponde a la composición de las rotaciones, cada una de las operaciones que describe puede representarse multiplicando su 'orientación actual' por un cuaternión elegido adecuadamente: específicamente, dado que el cuaternión (unidad) (qx, qy, qz, qw) significa 'rotar alrededor del eje (qx, qy, qz) por arccos (qw)', luego (dependiendo de su elección específica del sistema de coordenadas, y dejar que c_a sea cos (alpha) y s_a sea sin (alpha)) dos de los tres cuaterniones M_x = (s_a, 0, 0, c_a), M_y = (0, s_a, 0, c_a) y M_z = (0, 0, s_a, c_a) representarán 'rotar (es decir, moverse) en la dirección I 'Actualmente estoy mirando por alfa' y 'girar en una dirección ortogonal a la que estoy mirando actualmente por alfa'. (El tercero de esos cuaterniones representará 'rotar mi personaje sobre su propio eje'
Cur_q = M_x * Cur_q
si el jugador presionó hacia arriba, oCur_q = M_y * Cur_q
si el jugador presionó hacia la derecha (o posiblemente algo así comoCur_q = M_yinv * Cur_q
si el jugador presionó hacia la izquierda, donde M_yinv es el 'inverso' del cuaternión M_y, que representa una rotación en la otra dirección). Tenga en cuenta que debe tener cuidado en qué 'lado' aplica la rotación, ya sea premultiply o postmultiply; para ser sincero, puede ser más fácil resolver eso con prueba y error, probando ambas multiplicaciones y viendo cuál funciona.Pasar de su cuaternión actualizado a un punto en la esfera (y a una orientación de su personaje) también es relativamente sencillo: según la correspondencia del último párrafo, todo lo que tiene que hacer es usar su cuaternión en los vectores de base (1, 0,0), (0,1,0) y (0,0,1) de su marco a través de la operación 'rotar vector por cuaternión' v → qvq -1 (donde las multiplicaciones aquí son cuaterniones se multiplican e identificamos el vector v = (x, y, z) con el 'cuaternión degenerado' (x, y, z, 0)). Por ejemplo, la posición en la esfera de la unidad se obtiene simplemente transformando el vector z: pos = (qx, qy, qz, qw) * (0, 0, 1, 0) * (-qx, -qy, -qz, qw) = (qx, qy, qz, qw) * (qy, -qx, qw, qz) = (2 (qy * qw + qz * qx), 2 (qz * qy-qw * qx), (qz ^ 2 + qw ^ 2) - (qx ^ 2 + qy ^ 2), 0), entonces
(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))
serían las coordenadas del usuario 'transformado' en la esfera de la unidad (y para obtener las coordenadas en una esfera arbitraria, por supuesto, simplemente las multiplicaría por el radio de la esfera); cálculos similares funcionan para los otros ejes, para definir, por ejemplo, la dirección de orientación del usuario.fuente
Move()
procedimiento, pero para obtener el eje normalizado (es decir, mi posición), ¿lo tomaría(sin(qx),sin(qy),sin(qw)) * r
?Creo que quieres algo similar a esto http://www.youtube.com/watch?v=L2YRZbRSD1k
Desarrollé eso para un gamejam de 48h ... puedes descargar el código aquí ... http://archive.globalgamejam.org/2011/evil-god
Utilicé algo similar a tu código para obtener las coordenadas 3D ... pero roté el planeta y el jugador estaba en la misma posición, creo que estás interesado en el movimiento de la criatura, es esto:
fuente