¡Buenas! Pues tengo una duda gorda matemáticamente que no logro sacarme...
Quiero tener un sistema libre de cámara 3D en que literalmente pueda moverme con total libertad por el espacio sin estar anclado al suelo. Lo más fácil hasta ahora es tener 2 ángulos: cuánto sube/baja la cámara y si apunto a derecha e izquierda, y combinando estos ángulos puedo mirar en todas direcciones, pero siempre estás "pegado al suelo". Yo quiero tener total libertad. Que si miro hacia arriba, el techo sea el nuevo suelo. Que no haya suelo. Que pueda rotar la cámara con un tercer ángulo: rotación respecto al eje de visión.
https://www.youtube.com/watch?v=2xATkQBVidU
Como en este juego. Ahí si tú quieres, si te da la gana, puedes hacer que el suelo sea techo. Puedes volar sobre un suelo vacío, sobre un precipicio infinito, con un techo. O si quieres, puedes volar haciendo que el suelo sea una pared. O sea, rotar la cámara, girando, con total voluntad, y maniobrar de forma normal totalmente independiente de ello...
Para eso necesito 3 grados de libertad, rotar sobre los 3 ejes a la vez, y no sólo sobre los ejes z (profundidad/altura, theta) e y (longitud, phi). Pero no consigo que funcione lo anterior... ya que sigue funcionando como si estuvieras siempre pegado al suelo.
No sé si me he explicado bien y alguien capta a qué me refiero, es un concepto complicado... mi ejemplo era el sencillo:
x -> cos(phi)*cos(theta)
y -> sin(phi)*cos(theta)
z -> sin(theta)
Haciendo que el aumento en x/y sea cos/sin de phi, al mirar a los lados, giro de forma normal. Sin embargo, esto sólo aplica si theta vale 0, o sea, si estoy mirando al frente. Si comienzo a mirar arriba, la coordenada z comienza a aumentar para mirar arriba (sin(theta)) y cancela las horizontales.
Esto funciona para una cámara para mirar en todas direcciones 3D, pero no con la sensación de "poder hacer que el suelo sea techo", ya que siempre miras respecto a que el personaje tiene los pies pegados al suelo, y el suelo siempre será suelo...
Por no hablar que si intento hacer cambios, los sistemas de coordenadas se me invierten y no responden bien...
No haría la pregunta si no fuera algo realmente complejo, pero me está superando... :'(
Seguro que el GM utilice coordenadas esfericas? Yo la verdad no tengo idea pero puede ser mas conveniente utilizar otro sistema de coordenadas, por ejemplo en Godot dicen que es mejor utlilizar Quaterniones (https://es.wikipedia.org/wiki/Cuaterni%C3%B3n). Si consultas este sistema encontrarás la teoría que necesitas para implementar tu propio sistema de rotación asi como has dicho que prefieres hacerlo: https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
No entendi explicate de forma practica ya que estoy familiarizado un poco con el 3D de game maker y se mas o menos como inclinar a cualquier dirección la camara
Hice algo parecido en el ejecutable adjunto. El personaje camina con WASD y la cámara rota con el ratón.
El personaje tiene coordenadas esféricas: longitud, latitud y altitud, y un ángulo que llamé "frente" para indicar hacia dónde mira.
Con las coordenadas esféricas se calculan las coordenadas rectangulares.
Las cámara tiene coordenadas esféricas respecto al personaje, es decir, imaginando que el personaje está en el origen: phi, theta, r. Con esas coordenadas se calculan las coordenadas rectangulares respecto al personaje. El vector obtenido se rota y se traslada utilizando las coordenadas esféricas del personaje.
@Clamud ¡Mola mucho! Pero no sé si entendí la explicación xDD Yo también usaba theta, phi, r, pero no me funcionaba
@Goganpis un poco como el .exe de Clamud, que te puedes poner tanto en un extremo del meteorito como en otro y en ambos puedes moverte libremente. Que no exista un arriba y un abajo.
@Johann ya sabes que estoy estos días dándole a los quaternions y tratando de entenderlos, por eso no comenté xD Comentaré mis avances más adelante por aquí (n_n) muchas gracias
Vale. Esto es lo que tengo. No consigo que funcione, pero por todo lo que he investigado es a lo que he llegado y creo entender, y me siento bastante perdido xDD
A la hora de dibujar:
var res = scVecRotateArroundQuaternion(scArray(x, y, z), scArray(roll, pitch, yaw));
d3d_transform_add_translation(res[0], res[1], res[2]);
Pasando como parámetros el punto x, y, z que queremos dibujar, y los ángulos roll, pitch y yaw, nos devuelve el punto transformado sobre el cual dibujar, tomando la rotación respecto al 0, 0, 0, origen de coordenadas, que es donde estará siempre la cámara mirando en dirección del eje x positivo, con el vector normal en la z positiva.
scVecRotateArroundQuaternion:
var arr = scArray(0, argument0[0], argument0[1], argument0[2]), rot = argument1;
var pA = scAxisAngleToQua(rot[0], scArray(1, 0, 0));
var pB = scAxisAngleToQua(rot[1], scArray(0, 1, 0));
var pC = scAxisAngleToQua(rot[2], scArray(0, 0, 1));
var qua = scQuaMultiplicar(scQuaMultiplicar(pA, pB), pC);
var quaRes = scQuaMultiplicar(scQuaMultiplicar(qua, arr), scQuaConjugar(qua));
return scArray(quaRes[1], quaRes[2], quaRes[3]);
Esta parte no sé si está bien. Básicamente creamos 3 quaterniones, cada uno a partir del ángulo y su eje correspondiente (roll para el eje x, pues la cámara mira en dirección positiva, pitch para el y, yaw para el z). Multiplicamos los 3 quaterniones para obtener el final.
Entonces, aplicamos la fórmula mágica v = p · q · p'. Obtenemos el vector transformado por los ángulos, y como ese vector era el punto a transformar, pues obtenemos el punto transformado.
scAxisAngleToQua:
var theta = argument0/2, v = argument1;
var arrNorm = scArrNormalizar(scArray(scCos(theta), v[0]*scSin(theta), v[1]*scSin(theta), v[2]*scSin(theta)));
return scArray(
arrNorm[0],
arrNorm[1],
arrNorm[2],
arrNorm[3]
);
Tomamos el ángulo como su mitad, y aplicamos la hermosa fórmula para formar un quaternión. Lo normalizamos.
scArrNormalizar:
var arr = argument0;
var lon;
if (array_length_1d(arr) == 3)
lon = sqrt(arr[0]*arr[0] + arr[1]*arr[1] + arr[2]*arr[2]);
else
lon = sqrt(arr[0]*arr[0] + arr[1]*arr[1] + arr[2]*arr[2] + arr[3]*arr[3]);
if (lon != 0) {
arr[0] = arr[0]/lon;
arr[1] = arr[1]/lon;
arr[2] = arr[2]/lon;
if (array_length_1d(arr) == 4) arr[3] = arr[3]/lon;
}
return arr;
Hecho a mano porque no sé si existe un método que normalice, pero por si acaso lo pongo...
scQuaMultiplicar:
var qua1 = argument0, qua2 = argument1, res;
res[0] = qua1[0] * qua2[0] - qua1[1] * qua2[1] - qua1[2] * qua2[2] - qua1[3] * qua2[3];
res[1] = qua1[0] * qua2[1] + qua1[1] * qua2[0] + qua1[2] * qua2[3] - qua1[3] * qua2[2];
res[2] = qua1[0] * qua2[2] + qua1[2] * qua2[0] + qua1[3] * qua2[1] - qua1[1] * qua2[3];
res[3] = qua1[0] * qua2[3] + qua1[3] * qua2[0] + qua1[1] * qua2[2] - qua1[2] * qua2[1];
var arrNorm = scArrNormalizar(scArray(res[0], res[1], res[2], res[3]));
return scArray(arrNorm[0], arrNorm[1], arrNorm[2], arrNorm[3]);
Hermosas matemáticas.
scQuaConjugar:
var qua = argument0;
qua[1] = -qua[1];
qua[2] = -qua[2];
qua[3] = -qua[3];
return qua;
GG Easy.
También estaba el método "scQuaToAxisAngle" pero aparentemente no hace falta usarlo...
¿Alguna idea sobre el tema? Lo he hecho todo a mano con lo que he encontrado y a saber si lo hice bien o si tengo el concepto bien. No sé. Me parece increíble llevar 2 días buscando y no ser capaz de haber dado con la solución. A veces me planteo que tengo algún problema con hacer funcionar las cosas :-\
Creo que deberias preguntarle a algunos youtubers que hacen buenos juegos 3D con el game maker:
GamingEngineer
The Sivart
Los sigo desde hace mucho y pueden tener alguna idea de como hacer el efecto que vos queres
¿Tomaste los scripts de una biblioteca o los escribiste tu solo?
He estado estudiando sobre quaternions, pero aún no los domino.
¿Como es el juego que quieres hacer?
@Goganpis: ¿Crees que vaya a preguntarle a un youtuber desconocido y ya? xD Bueno, si no conseguimos sacarlo aquí en la comunidad, queda como recurso
@Clamud: Los escribí yo en base a código que encontré, copypasteando las partes e ideas clave, fórmulas, etc. La idea es sencilla: imagina un suelo rocoso y arriba el cielo. Con los ángulos de euler puedes hacer un típico "first person shooter" y mirar en todas direcciones. Es más, con sólo 2 ángulos puedes hacerlo. Imagina que eres una nave. Si yo quiero, quiero rotar en un tercer ángulo, el roll, y ponerme boca arriba, para que el suelo de rocas sea el techo (ver literalmente arriba como techo lo que antes era suelo) y que mi nuevo suelo, bajo mis pies, sea el cielo. Y si quiero rotar 90º, tener una pared de roca. Quiero total maniobrabilidad para rotar en los 3 ejes pero, desde cualquier rotación, moverme de forma normal. Al ponerme boca arriba, aunque el suelo pase a ser techo, me sigo moviendo de forma normal como si nada.
No conseguí hacer eso con los ángulos de euler, no era coherente, y por eso intentando todo esto :)