Lo siento si el título es un poco críptico. Es lo mejor que se me ocurrió.
En primer lugar, esta pregunta está relacionada con otra pregunta que publiqué aquí , pero esa pregunta no se planteó correctamente y terminó generando respuestas que pueden ser útiles para algunas personas que se topan con la pregunta, pero no abordan mi problema. soportes
Además, un descargo de responsabilidad: voy a publicar un código aquí. Lo estaré anotando para tratar de dejar lo más claro posible lo que estoy haciendo.
Bien, entonces estoy usando el lenguaje de programación Processing para mover una caja al azar (de acuerdo con el ruido de Perlin). A medida que la caja se mueve, me gustaría que girara para que pareciera que está rodando. No busco simular la física exacta aquí, solo busco una solución visualmente agradable.
Las reglas generales para la rotación son que, si la caja solo se mueve hacia la derecha, debe girar alrededor del eje Y de manera que gire hacia la derecha y si la caja solo se mueve hacia arriba, debe girar alrededor del eje Y. -eje tal que parece que está rodando directamente hacia arriba.
En otras palabras, si así es como se ve normalmente la caja:
Entonces, si digo: rotate2D(45,0)
debería obtener:
y si digo rotate2D(0,45)
que debo obtener:
(para mayor claridad, la declaración de la función para rotar2D parece rotate2D(horizontal, vertical)
)
Processing hace que esto sea fácil de hacer con las funciones de rotación que proporciona, que son:
rotateX();
rotateY();
rotatez();
El problema surge cuando quieres rotar en 2 dimensiones simultáneamente. Verá, en Procesamiento, si llamo rotateX()
para rotar un objeto sobre el
-eje, en realidad es el sistema de coordenadas en sí mismo el que se desplaza y todos los demás ejes lo acompañan, por lo que cuando voy a hacer rotateY()
después de hacer un rotateX()
no obtendré el resultado que quiero porque el
-El eje alrededor del cual estoy rotando ahora está sesgado. Puedes ver esto en las imágenes de arriba.
Entonces, si lo hago:
rotateX(radians(45));
rotateY(radians(45));
Yo obtengo:
y si lo hago:
rotateY(radians(45));
rotateX(radians(45));
Yo obtengo:
Pero lo que quiero es algo como:
que dibujé llamando a mi funciónrotate2D()
El problema es que los resultados que produce mi función son un poco contrarios a la intuición. No es evidente en el ejemplo anterior, pero digamos que quiero hacer: rotate2D(90,90);
. Creo que eso produciría una caja que parece que no se ha girado en absoluto, ¿verdad? Sin embargo, en realidad produce:
Esta es mi implementación actual derotate2D()
void rotate2D(float horizontal, float vertical)
{
float[] rotations ={horizontal, vertical};
if(rotations[0]>rotations[1])
{
float tmp = rotations[1];
rotations[1]=rotations[0];
rotations[0]=tmp;
}
if(rotations[1]==vertical) rotateX(radians(rotations[1]-rotations[0]));
else rotateY(radians(rotations[1]-rotations[0]));
float hIncr= (horizontal<0) ? -0.1 : 0.1;
float vIncr= (vertical<0) ? -0.1 : 0.1;
for(float i=0; i<=abs(rotations[0]);i+=0.1)
{
rotateY(radians(hIncr));
rotateX(radians(vIncr));
}
}
Explicación de la función: lo que hace la función es esencialmente lo siguiente (y esto es todo lo que realmente necesita para abordar la pregunta desde un punto de vista matemático).
La función realiza lentamente un montón de y rotaciones del eje uno tras otro en una pequeña cantidad cada vez (0,1 grados) hasta que alcanza un límite superior. Ese límite superior es el menor de los valores que se pasó la función. La caja ya se habrá girado sobre el eje adecuado por la diferencia entre el valor mayor y el menor antes de que tenga lugar esta secuencia.
Para aclarar aún más, estoy buscando una explicación matemática de por qué este proceso produce resultados contrarios a la intuición, que con suerte arrojarán luz sobre una solución.
El objetivo final ideal aquí es encontrar una fórmula que pueda usar para simular la rotación sobre un eje fijo en múltiples dimensiones cuando todo lo que puedo hacer es rotar 'el mundo' un eje a la vez como se describe arriba (que es esencialmente equivalente a rotar los ejes relativos de los objetos)
por favor, no dude en pedirme que aclare más. Gracias de antemano.
Después de leer los comentarios, ahora entiendo que las rotaciones sobre 2 ejes no conmutan y no debería esperar los resultados que esperaba anteriormente.
Lo que estoy calculando y pasando a mi función es la rotación neta en cada dirección.
Entonces, ¿es posible editar mi fórmula para que produzca esta rotación neta? Por ejemplo, en el ejemplo 90/90, si continúo la secuencia durante ~37 pasos adicionales (127 en total) obtengo el resultado que intuitivamente quiero obtener). Sin embargo, esto debería funcionar para todas las combinaciones de entradas.
Lo siento, Luke, no creo que tu solución funcione. Debe tener una solución rigurosa que se base en las matemáticas de las rotaciones. Esto se hace más fácilmente usando cuaterniones, o mejor aún, sus análogos del álgebra de Clifford llamados rotores .
Explicaré brevemente los rotores de álgebra de Clifford y cómo se pueden usar para convertir rotaciones secuenciales en una rotación neta.
Álgebra de Clifford
El álgebra de Clifford introduce un producto de vectores que no es conmutativo pero sigue siendo asociativo. Si está familiarizado con los productos punto y cruz, incorpora propiedades de ambos. Dada una base ortogonal , tenemos lo siguiente:
De nuevo, también es asociativo, así que por ejemplo. Esto crea un espacio vectorial de 8 dimensiones, con los siguientes elementos básicos:
múltiplos escalares de son escalares. combinaciones lineales de son vectores. combinaciones lineales de se denominan bivectores y son de interés para las rotaciones. Las rotaciones tienen lugar en planos (solo en 3D podemos decir que son alrededor de un eje, de manera equivalente), y los bivectores describen directamente los planos en los que tienen lugar las rotaciones.
Rotores y rotaciones
Declararé lo siguiente sin pruebas, aunque debería ser familiar para cualquier persona con una comprensión básica de los cuaterniones.
Defina un rotor como la exponencial de un bivector (generalmente definido a través de una serie de potencias). Dejar sea algún bivector unitario. Entonces el rotor para algún escalar es
Un mapa de rotación en el plano correspondiente a por el ángulo toma la forma
dónde es cualquier vector.
(Nota: para aquellos con antecedentes de cuaterniones, , , y , por lo que no hay discrepancia de signos con esta definición).
Aplicación: encontrar una rotación neta
El uso de rotores simplifica muchas de las matemáticas del análisis de rotaciones. Por ejemplo, consideremos el problema que tiene: sus funciones de rotación rotan el marco global y ellas mismas usan el marco global como el marco de referencia para estas rotaciones. Esto hace que secuenciar las rotaciones no sea algo trivial, pero los rotores nos permiten encontrar una forma más sencilla de hacer las cosas.
Dejar ser el marco original. Si desea rotar sobre el original y luego sobre el original , entonces sus rotores se verían así:
Luego podemos multiplicar esto para encontrar el plano de rotación neto y el ángulo neto.
Podemos encontrar el ángulo de rotación neto por
Consideremos el caso como usted sugirió, . Entonces deberíamos tener
o .
El plano de rotación neta es , o una rotación sobre el eje .
Editar: con esto en mente, esto es lo que debe hacer.
rotate(angle,x,y,z)
? función en un vector unitario y un ángulo? (en el chat)¡A todos en la sección de comentarios, me gustaría agradecerles por su ayuda ya que me han guiado a una solución!
Entonces, como dijiste, mi intuición era incorrecta y las rotaciones sobre múltiples ejes no conmutan.
Para que quede completamente claro con qué estoy trabajando, quiero reiterar que los valores que se pasan a mi función representan la rotación neta deseada en las direcciones horizontal y vertical, respectivamente.
entonces, cuando probé la rotación 2D (90,90) no obtuve una rotación de 90 grados en cada dirección, sino un compromiso entre los dos. En otras palabras, ¡estaba tratando de usar la longitud de uno de los lados pequeños del triángulo como hipotenusa!
Como tengo la magnitud de cada lado pequeño cuando se llama a la función, puedo usar el teorema de Pitágoras para determinar cuál debe ser la longitud de la hipotenusa. Después de leer los comentarios, creo que esta hipotenusa es equivalente al vector unitario de la rotación resultante. (Por favor, corríjame si me equivoco en ese punto).
Entonces, al usar el teorema de Pitágoras para determinar cuánto tiempo continuar la secuencia de rotaciones de 0,1 grados en función de las rotaciones netas deseadas en las direcciones horizontal y vertical, ¡puedo lograr los resultados que quiero!
Aquí está el nuevo código:
void rotate2D(float horizontal, float vertical)
{
float[] rotations ={horizontal, vertical};
if(rotations[0]>rotations[1])
{
float tmp = rotations[1];
rotations[1]=rotations[0];
rotations[0]=tmp;
}
float c= sqrt(pow(rotations[0],2)+pow(rotations[1],2));
float cIncr=0.1;
float hIncr=(horizontal/(c/cIncr));
float vIncr=(vertical/(c/cIncr));
for(float i=0; i<c; i+=cIncr)
{
rotateY(radians(hIncr));
rotateX(radians(vIncr));
}
}
EDITAR: resulta que este método no funciona, hubo una falla en mi método de prueba, pero SÍ produce rotaciones visualmente agradables para mis propósitos.
grego
Andrew D Hwang
rotate2D(90,90)
, pero las rotaciones sobre ejes distintos (incluso perpendiculares) no conmutan. Rompergrego
Lucas
grego
Lucas
grego
Lucas
Andrew D Hwang
Lucas
mufrido
Lucas