Jump to content
Sign in to follow this  
ftejada

Rotacion de objetos respecto a otros

Recommended Posts

Hola a todos!!!

Tengo el siguiente problema. Necesito poder rotar un objeto(independientemente del forward al que apunte), respecto a la orientacion de otro objeto... pufff mejor lo dejo en video porque no encuentro una manera clara para poderlo explicar escribiendo. Creo que en el video se entiende bien el problema en cuestión y lo que necesito conseguir. Necesito poder conseguirlo mediante script evidentemente.... pero no he podido encontrar el modo de hacerlo

He estado mirando en la documentacion, google, etc varios días pero no he podido encontrar la manera de hacer lo que necesito.

Ruego por favor me orienteis un poco de como podría hacer esto. Un saludo y gracias por adelantado.

https://youtu.be/NkDVEdzi10w

 

Edited by ftejada

Share this post


Link to post
Share on other sites

Estás suponiendo que ambos vectores de rotación (o ejes de rotación) son idénticos, es decir Y (como mencionas en el vid) y lo que pasa es que ambos Y locales (hablando de "up") son distintos, pero ambos Y globales (Space.Word) son iguales, obviamente, entonces necesitas hacer un Rotate pero especificando un Space.World

Fijate que en la documentación, si usas Rotate:

public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);

Space viene inicializado en "self" es decir que cada vez que uses Ej

eltransform.Rotate( Vector3.up * 5 );

... estás rotando localmente 5 grados en Y, pero si usas:

eltransform.Rotate( Vector3.up * 5 , Space.World);

estás rotando globalmente 5 grados en Y global.

 

PD: No se que estás usando ya que no está el código por ningún lado

 

Share this post


Link to post
Share on other sites

Gracias a ambos por responder...

Respecto a lo que mencionó francoe1 he de decir que no he podido conseguir que funcione con rotaciones "globales". Cada vez que he intentado algun calculo para gestionarlo de este modo, he obtenido resultados bastante erroneos en las rotaciones resultantes. Así que me he visto obligado a mezclar rotacionLocal con rotacionGlobal para poder tener resultados mas idoneos. Cualquier ejemplo de como hacerlo de esta manera sería bienvenido.

 

Respecto a lo que comentaba lightbug decir que es lo que más se ha acercado a conseguir solucionar el problema, pero aun falla en ciertas ocasiones. Lo muestro en el siguiente video.

https://youtu.be/vH-4pBvPCcY

Incluso cuando roto el padre de los cubos parece que todo funciona bien... salvo por el problema al rotar en X 90º que mencioné en el video anterior, ver en este video:

https://youtu.be/Eeq7_2xPVjw

Sin embargo cuando lo pruebo en un escenario "real" para poder influir en los huesos de la jerarquia de mi personaje, funciona peor que en el ejemplo de los cubitos. Por ejemplo con un hueso de la Espina del personaje.

Aunque con lo que dijo lightbug, en los cubos funciona casi bien salvo por el problema de cuando se rota en X, pero con mi personaje, los resultados empeoran y parece que no funciona de la misma forma que con los cubos. Dejo video para mostrarlo.

https://youtu.be/mMpV4fvc9yE

¿Como debo hacer los calculos para que todo rote correctamente? Necesito alguna ayuda para poder programarlo correctamente...

 

Share this post


Link to post
Share on other sites

Hola @ftejada, mirá me parece que lo del 90° de los cubos se puede llegar a dar por el paso de Euler a quaternion, no se si se dará mal esto pero una cosa que aprendí a la fuerza,  que trabajar con eulers casi siempre terminó en cagada, en especial cuando te pasas de los 90, no digo que sea así siempre, es solo mi experiencia con ellos, ya les tomé desconfianza.

En tu código estás determinando con un vector creado el valor del angulo("EulerAngles") que está bien, pero cuando rotás el cubo (con rotate) estás pasando el ".eulerAngles", no se si será eso pero bueno, lo menciono.

Lo que yo te planteaba originalmente es algo así (no se si se aplicará a tu personaje, solamente que quedé con lo del cubo):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class cubosRot : MonoBehaviour {

	public Transform[] m_targets;
	
	public Vector3 targetRotation;
	Vector3 oldTargetRotation;

	void Update () {
		
		if(targetRotation != oldTargetRotation)
		{
			for(int i = 0 ; i< m_targets.Length ; i++)
			{
				Vector3 currenttargetRotation = targetRotation - oldTargetRotation;
				m_targets[i].Rotate( currenttargetRotation ,Space.World);
			}

			oldTargetRotation = targetRotation;
		}

		
	}
}

Hay quizás formas más lindas de hacerlo pero se entiende. Target rotation y oldtargetRotation son contenedores donde llevás cuenta de la rotación actual (quizás haya algún error), pero con Unity solamente hablas en "idioma Quaternion" (con el rotate). Este script lo que hace es que vos le pasas los targets que quieras y cuando reconoce un cambio o delta de rotación recorre cada uno de los objetos y los rota globalmente, sin importar cada local (fijate los gizmos) bien simple.

Y el resultado:

Cubos.gif

 

Y con lo del personaje, ya no se que puede ser, cuanto más grande es el entorno donde trabajás más difícil es de encontrar la razón de la falla. ¿qué tan seguro estás de que ese "IkLogic" está rotando localmente y no globalmente? porque parecería que cuando cambiás la rotación ignora el resto (cuando caminas y girás en Y por ej) y en los cubos funciona (bueno hasta ahí nomás) pero claro no tenés este IKLogic... desconozco de IKs, solver y demás por eso pregunto.

saludos

 

Share this post


Link to post
Share on other sites

Buenas!!Otra forma con quaternions.

Calculas el offset que hay entre las dos rotaciones

Luego a la rotacion del que manda le aplicas el offset.

https://docs.unity3d.com/ScriptReference/Quaternion-operator_multiply.html

Mind Blow!!!

public Transform boss;
public Transform constrained;
private Quaternion offset;

public void OnEnable()
{ 
	offset = Quaternion.Inverse(boss.rotation) * constrained.rotation; 
}
public void Update()
{    
	constrained.rotation =  boss.rotation * offset;
}

:)

Edited by hammer

Share this post


Link to post
Share on other sites
hace 15 horas, lightbug said:

En tu código estás determinando con un vector creado el valor del angulo("EulerAngles") que está bien, pero cuando rotás el cubo (con rotate) estás pasando el ".eulerAngles", no se si será eso pero bueno, lo menciono.

Hola @lightbug, lo hago así porque:

Este "transform" de la primera linea del siguiente codigo es el cubo que se ve en el video a la dch, (digamos que hace las veces de un solver para posteriormente aplicarle una rotacion a un hueso...). Y ese hueso digamos que sería el "cubeRotate" que hay más abajo en el codigo y que es el cubo de la Izq que sale en los videos.

Y en la tercera linea del siguiente codigo es donde le aplico al supuesto "hueso", (en este ejemplo era un cubo), solo la cantidad de rotación local que hayamos rotado previamente al solver(transform de la primera linea y cubo de la dch en los videos).

transform.localRotation = Quaternion.Euler(EulerAngles);
cubeRotate.rotation = originalRotation;
cubeRotate.Rotate(transform.eulerAngles, Space.World);	

Aparte si le aplico directamente la variable "EulerAngles" de la primera linea de codigo al cubeRotate.Rotate(EulerAngles, Space.World); Sigue ocurriendo el mismo problema al rotar la X a 90º.  Aunque probando este problema, me he dado cuenta que no es de mi codigo ni de como lo estaba haciendo, sino que pasa con cualquier transform aunque no sea hijo de ningun otro transform si lo pruebas desde el inspector... dejo video:

Video

 

Por otro lado el enfoque que me has puesto en el codigo está bastante bien y "parece" que lo arregla todo, pero surgen unos errores de calculo que no se a qué se deben cuando intento en algún momento  volver a dejar la rotación que le doy a traves del EulerAngles con todo a cero. Dejo video:

Video

 

EDITO: he estado probando el enfoque que indicaba hammer y va perfecto todo ya, salvo por lo del problema de que al rotar 90º en el ejeX, las posteriores rotaciones que se le den en el ejeZ del EulerAngles las hace en el mismo eje que las de el ejeY... y se pierde la posibilidad de rotar en el ejeZ

 

Edited by ftejada

Share this post


Link to post
Share on other sites
hace 9 horas, hammer said:

Calculas el offset que hay entre las dos rotaciones

Luego a la rotacion del que manda le aplicas el offset.

Hola @hammer !!! muchas gracias por responder. He probado la solucion que aportas y parece que es la más adecuada para lo que busco y es el enfoque que creo voy a utilizar... Ya ni me acordaba que los Quaternions podian "restarse" :7_sweat_smile:.

Aparte ahora con esto, funciona perfectamente en el escenario real con los solvers y los huesos de mi character

Aunque por este lado ya quedaría todo bien, sigue habiendo un problema que no se como sulucionar... el de que cuando se rota un transform en el ejeX 90º, las demas rotaciones en Z parece que desaparecen para convertirse en rotaciones en Y como dejo en el Video de abajo...  Alguna idea de como solventar este problema?

Video

Saludos

Share this post


Link to post
Share on other sites

Gimbal Lock, hasta el apolo 13 tuvo problemas con el.

Basicamente las rotaciones por eule se aplican una a una en ciierto orden y por separado, en este caso es xyz(unity no deja cambiarlo),entonces.......como no se me ocurre como explicarlo te dejo un video(no he encontrado en español,aunque me extraña que no haya) y un ejemplo para que puedas reproducirlo en Unity para poder verlo bien y se entiende a la primera.

Puedes hacer la prueba, crea 3 planos uno para cada eje(ponle su color correspondiente son solo para que se vea la idea), pon cada plano con su normal apuntando en su eje, un plano para x donde su normal apunte en la misma direcion que el eje X,otra para y ,otro para z.Luego crea 3 gameobjects vacios y emparentalos uno detras de otro y dentro de cada uno emparentas el plano que le corresponda(no se pueden utilizar los planos ya que al posicionarlos ya no partiriamos de r:0,0,0 que queden asi:(los planos son solo para ayuda visual

-x(vacio rotacion 0 , 0 ,0)

  --planoX

  --y(vacio rotacion 0 , 0 ,0)

       --planoX

       ---z(vacio rotacion 0 , 0 ,0)

          --planoX

Ahora prueba a rotar el objecto, y ,en el eje y(el gameobject vacio) en el inspector y veras como se reproduce el problema.

Esto no tiene solucion,es asi,no hay mas.Cada año miles de riggers y animadores se suicidan por culpa del gimbal lock.Y es la razon por la que se utilizan Quaternions para representar rotaciones en el espacio.

Como lo has implementado?? porque se supone que haciendolo con quaternions no deberias encontrarte este problema.Tambien es posible que segun que jerarquia padres/hijos tengas y como la estes rotando estes reproduciendo el error como hemos hecho con el ejemplo.

3oz8xXJ5NB2owg5V16.gif

:)

edit el ejemplo estaba mal, no recordaba que unity no deja resetear rotations,estaba pensando en maya :)

Edited by hammer

Share this post


Link to post
Share on other sites
5 hours ago, ftejada said:

Por otro lado el enfoque que me has puesto en el codigo está bastante bien y "parece" que lo arregla todo, pero surgen unos errores de calculo que no se a qué se deben cuando intento en algún momento  volver a dejar la rotación que le doy a traves del EulerAngles con todo a cero. Dejo video:

Claro exactamente por eso puse que se podía hacer de forma más linda, a mi también me daba algunos errores, y además fijate que estoy calculando un delta entre vectores, digo que la rot haga ese delta, y luego impongo que la nueva rot del registro sea dicho valor (ponele X grados) cuando en realidad podría ser otro (X + 0.01f grados, que se yo, por inventar un valor), la cosa es que mientras más acciones realices más error se podría llegar a dar, por eso cuando puse "quizás haya algún error".

Jaja en 6 o 7 post hay como 6 videos :6_smile:, tenés que ser youtuber ... eso sí acordate para la proxima de subir el código que usás de entrada, fijate que acá recién en el sexto o septimo post está (sacando al vid que lo tieneque no me acuerdo cual es)

Saludos

Share this post


Link to post
Share on other sites

primero... muy buena la explicacion con videos... facilita la explicacion del problema que te atañe....

muchas veces queda poco claro el problema que se plantea en los posts... este no es el caso... esta claro que una imagen vale mas que mil palabras... anímo a todos a ser mas "visuales" en las explicaciones en los posts...

 

bueno, ...esto de las rotaciones a veces es un verdadero quebradero de cabezas.....

 

otro posible truco para hacer esto seria emparentar/desemparentar todo el rato el objeto quer quieres rotar...

es decir, tienes un empty gameobject,

1-lo orientas como la camara,

2-lo colocas en la posicion donde esta el objeto que quieres rotar,

3-haces que el objeto que quieres rotar sea hijo del objeto vacio

4-rotas el objeto vacio y deshaces el emparentamiento...

y vuelta a empezar... cada frame... cada objeto que quieras rotar...

 

ah, cuidado con los eulerAngles... que como dice @lightbug yo tambien he tenido malas experiencias con ellos... 

Share this post


Link to post
Share on other sites

Gracias de nuevo a todos por las respuestas....

@lightbug es cierto y llevas razón... debo poner antes el codigo para que lo veais...

@Igor hola!! Gracias por los comentarios. Prefiero hecer muchas veces un video, pq se me hace muy dificil de explicar ciertas cosas escribiendolo para que se me entienda... aunque tampoco es que me explique muy bien en video, pero pienso que es algo mejor jeje

Bueno... La idea que planteas ( emparentar/desemparentar ) es de las primeras que tantee, pero no se si es muy buena idea hacer eso en una jerarquia de huesos de un character o si fallaría algo por el tema de ls animaciones o yo que se...entiendo que no pero si no puedo conseguirlo haciendo los calculos puros mediante quaternions, tendré que tantear esa idea a fondo. Aparte creo que me viene muy bien aprender a gestionar los Quaternions para dominar todo este lio de las rotaciones.

@hammer Pensaba que al introducir los valores de rotacion que queramos,  mediante el inspector para la rotación de cuanquier Transform, Unity se encargaba internamente de gestionarlo adecuadamente mediante Quaternions para que no se produjese el bloque de Gimbal... al igual que creando una rotación mediante Quaternion.Euler(Vector3 EulerAngles);... Pensé que creando rotaciones con está función no se creaba dichos bloqueos.

On 6/6/2018 at 20:37, hammer said:

Como lo has implementado?? porque se supone que haciendolo con quaternions no deberias encontrarte este problema.Tambien es posible que segun que jerarquia padres/hijos tengas y como la estes rotando estes reproduciendo el error como hemos hecho con el ejemplo.

En este video expongo un poco la jerarquia de huesos y sus rotaciones locales en mi character de Unity.... el codigo que viene no te guies por el pq ya está modificado y adecuado a la solucion que aporte (hammer) con la que funciona todo bastante bien. Es solo para que veas la jerarquia de hueso si te interesa

https://youtu.be/mMpV4fvc9yE

Referente a como lo he implementado, no entiendo bien tu pregunta ya que en los videos, (no en todos), se mostré el codigo que utilizo... pero por si no los has visto, mea culpa...

En el ejemplo de los cubos y siguiendo tus consejos con lo del offset, el codigo sería este...

cubeSolver.localRotation = Quaternion.Euler(EulerAngles);	//EulerAngles es una variable publica para modificarla por el inspector
cubeBone.rotation = cubeSolver.rotation * offsetRot;	//offsetRot es la diferencia inicial entre la rotacion de cubeSolver y cubeBone

//Basicamente es lo que comentó hammer

En el codigo de la escena de mi character, es más lioso poner el codigo por que intervienen varios script por otros motivo, pero en realidad es exactamente lo mismo que en el codigo que he puesto aquí arriba.

Por lo que he estado probando en este dia y medio, tu solución funciona bastante bien en mi character y su jerarquia de huesos. Pero en estos dias quiero subir un video mostrando un problema que no estoy sabiendo calcular mediante Quaternions referente a este asunto utilizando la solucion que dijiste hammer. Voy a intentar solucionarlo yo unos dias más y si no puedo prepararé el video para exponer el problema en cuestion, que es algo lioso.

 

Saludos

 

 

Share this post


Link to post
Share on other sites

Eii buenas,esta vez si que me he mirado los videos :).Mhhh esta dificil....,preguntas y consideraciones.

En el anterior video que rotas el cubo a traves del inspector y te sale el gimbal lock, fijate que si pones x 90,luego rotas desde la scene con el handler de rotacion en local el eje y,veras como unity automaticamente te corrige los ejes yz

Es decir x90y0z0 gimballlock yz ,pero x90y-90z-90 es exactamente la misma orientacion pero sin el problema del gimball.Cuando rotas desde la scena unity corrige el gimball,desde el inspector no se corrige.

Lo mismo te pasara si lo haces desde la variable eulerAngles que tienes en el scriptable.

La verdad que esta complicado de saber,pueden ser muchas cosas o varias a la vez,por ejemplo si algun padre del spine que no es padre del solver tiene rotacion durante la ejecucion,animacion o script,problema,ya que entonces el offset ya no seria el mismo que el inicial, y al estar asignando una rotacion(mejor dicho orientacion) global,el spine va a quedar bloqueado en esta orientacion global sin importarle que el padre rote, el siempre apuntara con esa orientacion mientras no cambie el offset
 
Se me ocurren algunas cosas, pero sin saber como funciona lo mas probable es que me equivoque y acabe liandote 

Mira lo de los padres del spine que no roten, y haz una prueba quitando lo del vector3 euler del scriptable y haz la rotacion directamente en el solver en la ventana scene.Haber si asi funciona.


Lo de los euler lo miramos despues,primero asegurarse que esta primera parte funciona y luego le buscamos otra manera a aplicar los euler.Quiza sacando los quaternions por separado y luego sumandolos a los otros,....... * offset * qx * qy * qz,pero eso luego,primero asegurarse que funciona la relacion solver/spine sin la variable euler del scriptable conduciendo al solver.

Un saludo.

Share this post


Link to post
Share on other sites
On 8/6/2018 at 12:22, hammer said:

Mira lo de los padres del spine que no roten, y haz una prueba quitando lo del vector3 euler del scriptable y haz la rotacion directamente en el solver en la ventana scene.Haber si asi funciona.


Lo de los euler lo miramos despues,primero asegurarse que esta primera parte funciona y luego le buscamos otra manera a aplicar los euler.Quiza sacando los quaternions por separado y luego sumandolos a los otros,....... * offset * qx * qy * qz,pero eso luego,primero asegurarse que funciona la relacion solver/spine sin la variable euler del scriptable conduciendo al solver.

Hola @hammer!!! de nuevo gracias por la ayuda... No he podido contestar antes.

He estado probando varias cosas...a ver...

No se a qué te referias con esto de lo de que los padres de spine no roten.... De todos modos te comento, aunque ya lo hemos visto en alguno de los videos. La jerarquia de padres/hijos del character seria algo así:

EthanCharacter(rot(0,0,0))->EthanSkeleton(rot(0,0,0))->EthanHips(rot(0,90,-90))->EthanSpine(rot(0,0,4.95))->EthanSpine1(rot(0,0,0))...

Este ultimo de "EthanSpine1" es el que queremos manipular... Aparte este "EthanSpine1" cambia en cada frame su rotacionLocal por los clip de animacion que estén ejecutandose. Dicha variaciones pequeñas en la rotacion local cada frame por el clip de animacion, también tenemos que tenerla en cuenta para los resultados finales que apliquemos en el LateUpdate.

Dicho esto, ya lo tengo programado para que haga todo esto, y va perfecto. Lo unico que falla y debo solucionar es el bloqueo de Guimbal en ciertos angulos/circustancia. Este sería el codigo que tengo hasta ahora:

//Se ejecuta en cada frame en el LateUpdate
void UpdateRotSpine()
{
	advIK.solverSpine[i].localRotation = Quaternion.identity;								//Reset to 0 localRotation
	Quaternion newOffset = Quaternion.Inverse(solverSpine.rotation) * spineBone.rotation;	//Creamos el nuevo offset en cada frame para que contenga los cambios de la animacion

    solverSpine.localRotation = Quaternion.Euler(EulerAngles);     							//Aplicamos rotacion adicional           
    spineBone[i].rotation = solverSpine.rotation * newOffset;								//lo aplicamos todo al hueso spine
}

La prueba rotando el solver directamente desde la pantalla scene, soluciona el problema del bloqueo de guimbal, ya que de este modo Unity si te corrige internamente la rotacion para que no haya guimbal lock.

 

Edited by ftejada

Share this post


Link to post
Share on other sites

Buenas,pues esa es la parte dificil,no se como lo hara unity internamente la verdad, lo veo dificil, en el momento que intentas controlar las rotacion con 3 variables encontraras gimbal,aunque lo hagas en quaternions,el orden en que se aplican las rotaciones siempre importa,,prueba a rotar desde el rotator handler en la scena 90z,90x ,luego partiendo otra vez del reposo hazlo al reves,90x,90z, el resultado es completamente diferente.Aparte el gimbal del editor engaña mucho crees que estas rotando en x,pero si miras inspector lo estas haciendo en z en verdad,Asi que creo que tampoco puedes guiarte mucho por el gimbal del editor.Un follon vamos, me dan caspa los quaternions vs eulers, cuando son 3 angulos a rotar. XD

Quizas algun modo de control picth(x),yaw(y),roll(z) te pueda servir o algun 6dof

Prueba asi haber si te sirve(ni 6dof ni nada), plantealo como si con x controlas la inclinacion hacia delante,con y el twist, con el z el bend,lo dijo porque si miras los vectores te puede chocar al ver que no coincide a cuando lo mueves con el handler,peor creo que alomejor te puede servir al ser un personaje.Basicamente hay un parent para el cubo donde controlaremos zx, en el cubo controlaremos y.

boss.parent.localRotation = Quaternion.identity;
boss.localRotation = Quaternion.identity;
constrained.localRotation = Quaternion.identity; 

boss.parent.localRotation = Quaternion.Euler(uler.x, 0f, uler.z);
boss.Rotate(Vector3.up,uler.y,Space.Self) ; 

Quaternion newOffset = Quaternion.Inverse(boss.rotation) * constrained.rotation;    

constrained.rotation = boss.rotation * offset;

a ver si hay suerte!!!

:)

 

Share this post


Link to post
Share on other sites
Sign in to follow this  

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...