Ir al contenido



Foto

Problema con la función RayCastIntersect

Delphi 3D FireMonkey Games

  • Por favor identifícate para responder
20 respuestas en este tema

#1 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 08 julio 2016 - 05:15

Hola amigos.

 

Estoy haciendo una aplicación donde requiero conocer el punto de colisión de una esfera con otro objeto.  hasta allí es sencillo.

 

Dada una posición inicial y la dirección del objeto se puede obtener el punto de colisión con la instrucción RayCastInteserct,  el primer paso es cambiar la referencias de coordenadas de las globales, hacia el local.

 

Todo esto funciona perfectamente, incluso si el objeto de destino tiene rotaciones,  sin embargo si el objeto de destino tiene una traslación, los cálculos ya no dan.

 

El ejemplo con la Objeto.position.Point := Point3D(0,1,0);  ya no lo puede detectar.

 

Alguna idea?  Gracias.


php
  1. Position := Objeto.AbsoluteToLocal3D(Position);
  2. FDir := Vector3D(Objeto.AbsoluteToLocalVector(FDir));
  3.  
  4. Objeto.RayCastIntersect(Position, FDir, HitPos);
  5.  
  6. Sphere1.Position.Point :=
  7. Objeto.LocalToAbsolute3D(Objeto.AbsoluteToLocal3D(HitPos));

 

Archivos adjuntos


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 09 julio 2016 - 11:06

Quise buscar documentacion de esa funcion en la wiki y en google y no sale nada. Como me molesta que una API no este documentada


  • 0

#3 BDWONG

BDWONG

    Member

  • Miembros
  • PipPip
  • 28 mensajes

Escrito 09 julio 2016 - 11:30

Agustin Ortu esto es lo que buscabas? http://docwiki.embar...ls3D.TControl3D


  • 0

#4 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 09 julio 2016 - 12:44

No, yo hablo de RayCastIntersect

 

Hasta que no vaya al trabajo no tengo un Delphi con FMX para investigar :(


  • 0

#5 BDWONG

BDWONG

    Member

  • Miembros
  • PipPip
  • 28 mensajes

Escrito 09 julio 2016 - 01:04

Este http://docwiki.embar...ayCastIntersect (h)


  • 0

#6 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 09 julio 2016 - 02:30

Es muy extraño, porque justamente intente buscar usando su nombre, "RayCastIntersect" en el buscador de la docwiki y no encontraba nada. O cometi un error de tipeo, o quiza entre en una version anterior de la wiki...

 

En fin, esto es lo que reza el articulo:

 

 

Returns whether the ray casted intersects with the 3D control.

RayCastIntersect returns True if the ray casted intersects the 3D control, False otherwise.

RayPos and RayDir specify the position and direction of the ray to be casted and about which you want to know whether it intersects with the 3D control.

 

 

Osea que es bastante escueto,  y no hay ningun ejemplo..

 

Edito:

 

Revisando en el historial de google, escribi "RayCastInteserct " :)


  • 0

#7 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 11 julio 2016 - 04:35

Hola, @genriquez

 

Quizas estas entradas, te despejen un poco el Camino, Yo trabajo con Unity, y en Delphi me ocurria lo siguiente, es un caso para probar.

 

Por favor, echele un vistazo a estas entradas

 

http://blog.arquero.net/2016/06/09/raycastintersert-12/

 

http://blog.arquero.net/2016/06/14/raycastinterserct-22/

 

Le Pueden ayudar, la funcion de por si viene con algunas debilidades.

 

Pero No se decirle si esto solucionara su inconveniente.

 

Saludos.


  • 2

#8 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 11 julio 2016 - 09:32

@sir.dev.a.lot ese blog es tuyo? No lo conocia pero ya he estado leyendo y me agrado bastante. Creo que te ganaste un lector :)


  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.259 mensajes
  • LocationArgentina

Escrito 12 julio 2016 - 05:29

Interesante blog,

Se me hace que lo voy a añadir a mis marcadores. No me viene mal aprender algunas cosillas de los artículos que tiene.

 

Saludos,


  • 0

#10 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 13 julio 2016 - 08:07

Muchas gracias por la información, la voy a revisar y les cuento.

 

Saludos.


  • 0

#11 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 14 julio 2016 - 05:09

Hola, Revisando bien el código de Embarcadero, me doy cuenta que el error no está en la función RayCastIntersect, realmente esta funciona bien al menos en planos y en cubos que he probado hasta ahora,   el problema está en el cambio de coordenadas Objeto.AbsoluteToLocal3D(Position);

 

Esta función realiza una transformación de coordenadas multiplicando por una matriz, sin embargo no tiene en cuenta la traslación del objeto, solo la rotación.


delphi
  1. function TControl3D.AbsoluteToLocal3D(const Point: TPoint3D): TPoint3D;
  2. begin
  3. Result := Point * InvertAbsoluteMatrix;
  4. end;


delphi
  1. function TControl3D.GetInvertAbsoluteMatrix: TMatrix3D;
  2. begin
  3. AbsoluteMatrix; // require this call to force recalulation if need
  4. Result := FInvAbsoluteMatrix;
  5. end;


delphi
  1. function TControl3D.GetAbsoluteMatrix: TMatrix3D;
  2. begin
  3. if FRecalcAbsolute then
  4. begin
  5. if FParent is TControl3D then
  6. FAbsoluteMatrix := FLocalMatrix * TControl3D(FParent).AbsoluteMatrix
  7. else
  8. FAbsoluteMatrix := FLocalMatrix;
  9.  
  10. //------- AQUÍ DEBERÍA IR LA TRANSFORMACIÓN DE LA TRASLACIÓN O ALGO ASÍ------------
  11. Result := FAbsoluteMatrix;
  12. FInvAbsoluteMatrix := FAbsoluteMatrix.Inverse;
  13.  
  14. FRecalcAbsolute := False;
  15. end
  16. else
  17. begin
  18. Result := FAbsoluteMatrix;
  19. end;
  20. end;

Una salida al paso,  consistió en mover el sistema de coordenadas a la posición cero, realizar el cálculo y luego retornar a la posición original, no es muy elegante pero funcionó, sin embargo quisiera revisar la función a ver si es posible realizar la transformación de la rotación y la traslación en forma de matrices, mucho más elegante y seguramente más eficiente.

 

aquí les dejo como lo solucioné temporalmente hasta que pueda aprender un poco de transformadas.


delphi
  1. P1 := Objeto.Position.Point;
  2.  
  3. Objeto.Position.Point := Objeto.Position.Point - P1; // retorna a la posicion 0
  4.  
  5. Position := Position - P1; // ajusta la posicióon con la referencia P1
  6. Position := Objeto.AbsoluteToLocal3D(Position);
  7.  
  8. FDir := Vector3D(Objeto.AbsoluteToLocalVector(FDir));
  9.  
  10. If Objeto.RayCastIntersect(Position, FDir, HitPos) then
  11. Begin
  12.  
  13. Sphere1.Position.Point := Objeto.LocalToAbsolute3D
  14. (Objeto.AbsoluteToLocal3D(HitPos)) + P1; // ajusta el punto de intersección
  15.  
  16. Objeto.Position.Point := P1; // retorna el objeto a la posicion inicial
  17.  
  18. End
  19. else
  20. Sphere1.Visible := False;

Saludos


  • 0

#12 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 14 julio 2016 - 05:12

Tengo otra pregunta, de neofito en esto de 3D,  si tengo 50 objetos, cómo hago para saber a cual de los 50 intersecta el rayo,  en este momento lo hago porque lo selecciono manualmente,  pero existe alguna manera de saberlo, sin necesidad de preguntar por cada uno de los objetos?

 

Saludos.


  • 0

#13 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.259 mensajes
  • LocationArgentina

Escrito 14 julio 2016 - 09:12

Tengo otra pregunta, de neofito en esto de 3D,  si tengo 50 objetos, cómo hago para saber a cual de los 50 intersecta el rayo,  en este momento lo hago porque lo selecciono manualmente,  pero existe alguna manera de saberlo, sin necesidad de preguntar por cada uno de los objetos?

 

Saludos.

 

La respuesta fácil y díficil: Octree.

 

Básicamente la idea del Octree es que se tenga un "mapa" tridimensional de como están distribuídos los objetos. Para determinar si hay objetos en colisión básicamente se determinan si están en el mismo cubo del Octree. Gracias a esta estructura no hace falta recorrer todos los objetos, sino los que estén en su mismo cubo.

 

Saludos,


  • 1

#14 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 14 julio 2016 - 11:00

Muchad gracias Delphius


  • 0

#15 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.259 mensajes
  • LocationArgentina

Escrito 15 julio 2016 - 09:46

Muchad gracias Delphius

 

De nada.

Creería que el Octree te podrá ser de ayuda. Yo mucho del tema no se, salvo tocar de oreja el tema.

Se que el Octree permite organizar los objetos espacialmente, pero en cómo luego se hace uso del Octree para llevar a cabo la evaluación de colisiones ya no se.

 

También desconozco como es que funciona el método RayCastIntersect y toda la FMX en general. Como para ver por donde tirarte una idea.

En términos abstractos, si conoces los objetos dentro de un nodo del árbol del Octree, para evaluar si hay colisión basta con evaluar si hay algún punto de uno de ellos en contacto o superposición con otro.

Si son objetos simples como por ejemplo una Esfera, un Cubo, Prismas... y nada rebuscado como una persona o una nube creería que la FMX te hace el trabajo sucio de evaluar si hay un valor común (x,y,z) que cumpla la ecuación canónica tridimensional que los describe. O al menos así es como yo entiendo al tema. La cosa se compila cuando los objetos son más complejos... ahí se me queman los libros, porque no hay una ecuación canónica.

 

En los videos juegos al menos lo que se suele emplear es un HitBox, un área generalmente paralelepipedo rectangular, que encierra al objeto. Si es cierto que se pierde "realismo" y puede dar lugar a falsas colisiones, como por ejemplo que un disparo de una bala que va por encima del hombro y en realidad no toca al objeto. La otra alternativa es considerar varios HitBox que describan al objeto.

Evaluar colisiones de hitbox paralelepipedo rectangulares es mucho más fácil y rápido para una máquina.

 

Si hay técnicas más avanzadas las desconozco.

 

Saludos,


  • 0

#16 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 15 julio 2016 - 11:00

Igual soy nuevo en estas lides del 3D, un mundo excelente y que en la práctica empresarial, puede ayudar a solucionar muchos problemas, (estoy trabajando en algo que pronto lo compartiré en ese aspecto).

 

El RayCast hace precisamente eso que tu dices, primero evalua si hay colisión en un cuboide, si es así, sigue con la evaluación ya mas en detalle, de lo contrario termina, así optimiza el procesador, sin embargo hay que preguntarle a todos los objetos uno por uno,  así que la idea es indexar de alguna manera para reducir el numero de objetos a quien preguntarle, y la idea del octree es excelente,  no he pensado como implementarla, pero disminuye en 8 la cantidad de objetos a procesar.

 

Saludos.


  • 0

#17 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 516 mensajes
  • LocationCali, Colombia

Escrito 15 julio 2016 - 11:27

Por lo pronto, solucioné el problema con la creación de una clase helper con una nueva funcion RayCast de la siguiente forma


delphi
  1. TControl3DHelper = Class Helper for TControl3D
  2. function RayCast(RayPos, RayDir: TPoint3D;
  3. var Intersection: TPoint3D): Boolean;
  4. End;
  5.  
  6. .........
  7.  
  8. { TControl3DHelper }
  9.  
  10. function TControl3DHelper.RayCast(RayPos, RayDir: TPoint3D;
  11. var Intersection: TPoint3D): Boolean;
  12. var
  13. P: TPoint3D;
  14. begin
  15. P := Position.Point;
  16. Position.Point := NullPoint3D;
  17. Try
  18. RayPos := AbsoluteToLocal3D(RayPos-P);
  19. RayDir := Vector3D(AbsoluteToLocalVector(RayDir));
  20. Result := RayCastIntersect(RayPos, RayDir, Intersection);
  21. Finally
  22. Position.Point := P;
  23. Intersection := Intersection + P
  24. End;
  25. end;

y en el llamado ya queda fácil.


php
  1. Objeto.RayCast(Position, FDir, HitPos);

Hasta ahora en Delphi 10 y 10.1 funciona perfectamente.

 

Saludos.


  • 1

#18 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.962 mensajes
  • LocationMéxico

Escrito 15 julio 2016 - 11:59

Por lo pronto, solucioné el problema con la creación de una clase helper con una nueva funcion RayCast .....

 

Vaya, debo ponerme a estudiar esos Helper. :(

 

Buen trabajo amigo Gustavo.

 

Saludos


  • 0

#19 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.259 mensajes
  • LocationArgentina

Escrito 15 julio 2016 - 12:54

Viendo los códigos y sus comentarios, quedo un tanto descolgado.

En buena parte por desconocer, por obvias razones, FireMonkey.

 

Esas vueltas de cambiar entre coordenadas absolutas y locales, y el de cambiar de posición de objetos me marea. Me cuesta entenderle al código.

 

Por otro lado, que FMX tenga algunos errores en su código, a estas alturas de su desarrollo, no deja un lindo mensaje.

 

Me quedé pensando en lo que comentas genriquez sobre como realizar de manera eficiente traslación y rotación de las matrices. A mi entender no hay mucho que se pueda hacer, la asíntota dice que estas operaciones es de orden O(n3) o "semi-cúbicas" O(n*m2) dependiendo de cuantas filas/columnas tengas.

En principio, y si no me falla la teoría, el álgebra lineal dice que si hay una transformación T1(g(x)) y luego otra T2(h(x)) a continuación el proceso T2(T1(g(x))) se puede hacer como T1+T2. Por lo que puede hacerse en una misma matrix T3 que combine ambas operaciones. Si T1 define la rotación y T2 la traslación la matriz T3 tendrá en cada posición algo como esto por ejemplo:

 

T3ij = f(ang)ij + traslacionij

 

Siendo f(ang) alguna función trigonométrica que le imprima su rotación, y traslacion el desplazamiento sobre dicha posición. Entonces no va a hacer falta hacer algo como:

 

Vrotado = T1*Voriginal

Vtrasladofinal = T2*Vrotado

 

EDITO:

Quizá no venga mal repasar esto y esto.

 

Saludos,


  • 0

#20 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 15 julio 2016 - 02:59

Hey, Bien!

 

Ya te iba a comentar algo de HitPos, Porque en Unity3D a donde enfocas el te devuelve el Objeto con el que colisiona.

 

Pero hay tantas cosas que relacionan uno con otro lenguaje, que es un poco dificil, llevar funciones de uno al otro.

 

Pero............................................................. En Hora buena que Resolvio! :ap: .

 

Saludos!


  • 0





Etiquetado también con una o más de estas palabras: Delphi, 3D, FireMonkey, Games