Sunday, November 09, 2008

Caso de estudio 002: Relación entre rotación y deslizamiento



Hace algunas semanas leí una pregunta sobre como 'riggear' un sistema mecánico como el del esquema y me pareció un tema interesante para comentar acá en el blog, lo interesante desde mi punto de vista es que pese a ser una estructura muy sencilla (apenas 2 elementos) su resolución puede ser no tan directa como aparenta.

Nuestro objetivo en este caso será lograr que al rotar el elemento principal la segunda barra secundaria se deslice adaptandose a la rotación, algo similar a lo que sucede con la biela y el cigueñal en un motor de combustión interna.

Antes de hacer nada creo que es importante plantearnos como queremos interactuar con el mecanismo, tenemos básicamente 2 opciones: o rotamos la barra principal y dejamos el resto automático o bien deslizamos la barra secundaria y automatizamos la rotación. En este caso me parece más práctico rotar la barra principal y automatizar el resto :)

Ok, manos a la obra! lo primero que habría que hacer es una estructura de huesos que represente a la geometría, posiblemente en este caso al ser algo simple se podría trabajar directamente sobre la geometría pero siempre es una buena idea animar una estructura que guíe la geometría, nos ahorrará muchos problemas en caso de tener que reemplazar la pieza por algún motivo (por ejemplo riggeamos el modelo en baja resolución y luego le asignamos el rig a las piezas en alta definición).



Hasta ahora lo único que he hecho es crear 2 cadenas de huesos, una FK que representa la barra principal y otra cadena IK linekada a esta última que representa la barra secundaria, como vemos en las imágenes cuando rotamos la barra principal el efector IK queda fijo en el lugar en lugar de desplazarse, ahora nuestro objetivo es lograr ese deslizamiento horizontal :)

El camino "fácil":
Lo primero que uno pensaría en hacer para ese deslizamiento es usar reaction manager (3dsmax)/set driven key (Maya)/link with... (XSI) para establecer una relación entre la rotación con el desplazamiento, es una solución válida y rápida pero nos enfrentaremos a un problema interesante, la relación entre el desplazamiento y la rotación no es lineal, esto quiere decir que si lo configuramos de esta forma sólo considerando los extremos el efector tendrá un offset no deseado en su deslizamiento. El defecto se puede disimular agregando puntos/keys intermedios pero nunca lograremos una solución exacta de esta forma.

El camino "difícil":
Si descartamos la opción anterior nos queda como solución encontrar el modelo matemático que representa ese desplazamiento y "bajarlo" a una expresión, puede sonar complicado pero no lo es en la práctica, con un poco de trigonometría es pan comido ;)

Por donde empezar? básicamente nuestro problema se reduce a un triángulo al cual debemos calcular la dimensión de sus lados, en el siguiente esquema se puede ver una síntesis gráfica del problema (espero se entienda la letra a mano alzada).



Básicamente el desplazamiento que necesitamos calcular es equivalente a calcular la longitud del lado b del triángulo, en base al esquema no es difícil asociar que si recurrimos a las funciones seno y/o coseno podemos dar con aquella longitud, para ponernos en contexto wikipedia nos ilustra con este gráfico que representa el seno y el coseno de un ángulo cuando es multiplicado por el radio de la circunferencia a la que pertenece.

De esta forma podemos deducir que en nuestro caso:
b = c * cos(α) + a * cos(γ) (1)
**b es igual a c por el coseno de alfa más a por el coseno de gamma

Donde:
c, a y γ son conocidos.

Por lo tanto nos queda calcular α, para ello nos podemos basar en el teorema del seno, básicamente es una relación de proporcionalidad entre las longitudes de los lados de un triángulo y los senos de los ángulos respectivamente opuestos (en el link lo explica en imágenes).

De esta forma se puede afirmar que

sen(γ) / c = sen(α) / a
sen(α) = a * sen(γ) / c
α = senֿ¹ ( a * sen(γ) / c ) (2)
** senֿ¹ representa a la función arcoseno

Por lo tanto, reemplazando el valor de α en la ecuación (1) tenemos que el lado b del triángulo, es decir el deslizamiento del efector, es igual a:

b = c * cos( senֿ¹ ( a * sen(γ) / c ) ) + a * cos(γ)

Ok, tenemos la expresión pero como se aplica esto en nuestro rig? en este caso estoy usando 3dsmax por lo que la expresión la escribiré usando este software y explicaré la estructura que actualmente tengo montada (convención de nombres y tal, para que se entienda), de todas formas entendiendo el concepto y como llegamos a la expresión es fácilmente aplicable a cualquier software.



Para recrear el comportamiento en este rig usando 3dsmax vamos a usar un controlador "float script" en el desplazamiento en el eje Y del efector (secondary_eff), en el script controller escribiremos algo como esto:

(
DependsOn $main_anim $secondary_bone
local c = $secondary_bone.length
local a = in coordsys gimbal $secondary_bone.position.x
local gamma = 90 - (in coordsys gimbal $main_anim.rotation.z)
c * cos( asin ( a * sin(gamma) / c ) ) + a * cos(gamma)
)

** Lo ideal sería usar nodos como variables en lugar de usar los nombres de los objetos y el dependsOn, en este caso no los uso sólo para hacer el script entendible en base a mi convención de nombres.

En el editor de max debería verse asi:


Y el resultado en acción:


Más allá del rig en si mismo tenía ganas de compartir una de las tantas formas de encarar los desafíos que puede representar un rig, espero que les halla parecido interesante.

Salu2

4 comments:

Ruramuq said...

Hola César, El año pasado alguien pregunto algo así en cgtalk, y al principio pense en usar angulos como tú, pero al final use pitagoras para simplificarlo :

Cx = abs(in coordsys EJE XX.pos.x)
Cy = (in coordsys EJE XX.pos.z)
C = 70
pit = sqrt(C^2-Cx^2)
Dz = -pit+Cy
[ 0, 0, Cz]

(esta rotado -90º)
donde XX es la posicion de la articulacion q se forma entre C y A en tu dibujo.
Pero para entonces lo q esperaba era encontrar una manera sin usar MXS.. cosa q no parece posible..

César Sáez said...

Hola Ruramuq, gracias por comentar.

Buen apunte! el único problema es que pitágoras tal como lo tienes ahí es aplicable sólo a triángulos rectángulos (con 1 ángulo recto), de todas formas se podría usar el teorema del coseno y debería funcionar :-)

c^2 = a^2 + b^2 - 2ab*cos(gamma)

Sería una expresión mucho más directa que la del post original.

Gracias por el apunte, un abrazo.

Ruramuq said...

•Triangulos Interiores•
El rig funciona, creedme. es como en IK, hay 2 triangulos rectos en realidad.
solamente q en lugar de usar IK solver, hay un lookat
es otra manera, si no me estoy olvidando de algo...

Mario said...

Hola César,
en primer lugar felicitarte por tu blog. Me resulta realmente interesante e inspirador. Gracias.

Ahora el efecto. No sé si llego un poco tarde, pero ahí va. Casualmente me ha tocado un proyecto donde tengo que recrear el movimiento de una máquina que hace exactamente esto, mover un brazo diagonal que lleva un al final del brazo un carro que se desliza sobre un puente que a su vez se mueve hacia adelante y hacia atrás en línea recta en función de la rotación del brazo.

Yo lo he solucionado de la siguiente manera en xsi: el carro que va al final del brazo es hijo del brazo, pero no hereda sus rotaciones. Añado un null, lo alineo con el puente y lo constriño en posición con el carro. La traslación en X del puente la linko (link with) con la del null. El único requisito es poner antes sus transforms (null y puente) en 0 con un neutral pose (creo que en maya es un freeze transforms).

De este modo, al rotar el brazo, el carro se desliza por el puente que se ve obligado a avanzar o retroceder según la posición del carro.

No sé si lo he explicado bien, pero funciona y es super-sencillo de hacer para los negados de las matemáticas como yo.

Mi auténtica duda es ¿Y si lo que quiero menejar en realidad es el puente?

Gracias y un saludo,

Mario (Navassi)