Table of Contents

Obtener el resultado de ejecución de session

Durante la ejecución de session se modifican el transform de algunos objetos de la escena y la imagen de la cámara, entre otras cosas. A veces estos cambios aún no bastan para la aplicación, y puede ser necesario obtener el resultado de ejecución de session en cada frame y procesar esos datos posteriormente. Este artículo explica cómo obtener y usar esos datos.

Antes de empezar

Obtener actualizaciones de InputFrame

Puedes usar el evento InputFrameUpdate para obtener actualizaciones de InputFrame. Este evento solo se dispara cuando InputFrame cambia en los datos de salida de cada frame de session.

Nota

InputFrameUpdate solo es válido en sessions en las que la imagen se dibuja con EasyAR. En general, no es válido cuando se usa AR Foundation o visores, y en ese caso hay que usar los métodos que ofrecen esas bibliotecas de terceros para obtener actualizaciones de datos.

Con InputFrame puedes obtener la imagen de la cámara física, los parámetros de la cámara, la marca de tiempo, el transform de la cámara física respecto al sistema de coordenadas global y el estado de seguimiento, entre otros. Sin embargo, como el transform de la cámara ya se aplica a la cámara virtual y a otros objetos por parte de session, por lo general no hace falta obtener el transform de la cámara mediante InputFrame.

Obtener la imagen de la cámara física del frame actual

Puedes usar el método InputFrame.image() para obtener datos de imagen de la cámara física de tipo Image.

Por ejemplo, el siguiente código obtiene la imagen de la cámara física cuando se actualiza InputFrame:

Session.InputFrameUpdate += (inputFrame) => {
    using (var image = inputFrame.image())
    {
    }
};
Precaución

Al usar datos de tipo Image y otros datos de tipo class obtenidos a partir de él, debes asegurarte de que Dispose() se llame correctamente (la instrucción using del código anterior ya lo garantiza); de lo contrario puede producirse una fuga de memoria e incluso que la imagen deje de actualizarse.

Si necesitas conservar InputFrame o Image para usarlo en el siguiente frame, debes aumentar el valor de ARAssembly.ExtraBufferCapacity según la cantidad de datos que quieras conservar; de lo contrario, la obtención de datos puede fallar por falta de búfer.

Si necesitas conservar InputFrame, también debes llamar al método Clone() para crear una copia con referencia y, cuando ya no la necesites, llamar a Dispose() sobre la copia.

Como la tasa de frames de la cámara física suele ser menor que la tasa de renderizado, no todos los frames de renderizado reciben el evento InputFrameUpdate, pero del mismo modo la imagen de la cámara física tampoco se actualiza en todos los frames de renderizado. Todos los frames de renderizado antes de que vuelva a dispararse InputFrameUpdate tendrán el mismo contenido de imagen que el InputFrame actual.

Nota

La imagen de InputFrame siempre coincide con la imagen de fondo de la cámara virtual del frame actual, pero al renderizar el fondo puede haber escalado y recorte, así que es normal que el tamaño o la proporción de la imagen obtenida no coincida con lo que se muestra en pantalla.

Además, hay que tener en cuenta que los datos de imagen devueltos por InputFrame.image() son legibles por CPU y no son una textura GPU. Si necesitas usar los datos de imagen en la GPU, debes subirlos a una textura GPU, o bien obtener directamente la textura GPU mediante la interfaz CameraImageRenderer.RequestTargetTexture(Action<Camera, RenderTexture>).

[Opcional] Interceptar el renderizado de la imagen de la cámara física

Puedes usar ARAssembly.CameraImageRenderer para controlar el renderizado de la imagen de la cámara física.

El siguiente código puede detener el renderizado de la imagen de la cámara física:

if (Session.Assembly != null && Session.Assembly.CameraImageRenderer.OnSome)
{
    Session.Assembly.CameraImageRenderer.Value.enabled = false;
}

Ten en cuenta que primero hay que comprobar si ARAssembly.CameraImageRenderer existe.

Nota

Solo en sessions en las que EasyAR dibuja la imagen se puede detener la actualización de la imagen con el método anterior. En general, no es válido cuando se usa AR Foundation o visores, y en ese caso hay que usar los métodos que ofrecen esas bibliotecas de terceros para lograr la función correspondiente.

Después de detener el renderizado de la imagen de la cámara física, la aplicación puede obtener los datos de imagen de la cámara física mediante InputFrame y usar esos datos para dibujado personalizado.

Obtener actualizaciones de transform

Puedes obtener los datos de transform de los objetos de la escena después de cada actualización de session mediante el evento PostSessionUpdate.

Nota

Para algunas funciones (por ejemplo Mega), aunque no haya cambios de imagen ni una solicitud visible de actualización al servicio, el cálculo AR se ejecuta en cada frame de renderizado. Por eso, si necesitas obtener todos los cambios de transform, debes obtener los datos de transform en cada frame y no solo en algunos frames.

Obtener el transform de la cámara virtual

Puedes obtener el transform de la cámara de la escena mediante ARAssembly.Camera.

Session.PostSessionUpdate += () =>
{
    var position = Session.Assembly.Camera.transform.position;
    var rotation = Session.Assembly.Camera.transform.rotation;
};

Obtener el transform del target

Puedes obtener el transform del target de la escena a través del objeto target concreto que estés usando. Por ejemplo, en image tracking, ese target es el objeto que contiene el componente ImageTargetController.

Session.PostSessionUpdate += () =>
{
    var position = target.transform.position;
    var rotation = target.transform.rotation;
};

[Opcional] Obtener pose

pose es una estructura de datos que describe la posición y la orientación de un objeto, y normalmente se compone de position y rotation. En aplicaciones AR, pose suele usarse para describir la posición y orientación de la cámara física o del target de seguimiento respecto a un sistema de referencia.

Unity no proporciona datos pose en bruto, porque pose suele usarse para impulsar el movimiento de los objetos de la escena, y eso es justo lo que session hace automáticamente. Para el cálculo y el renderizado del contenido, basta con transform.

Importante

Antes de leer el método siguiente, piensa otra vez si los datos de transform de la cámara, el target de seguimiento y otros objetos ya satisfacen tus necesidades. Por lo general, no hace falta obtener datos pose adicionales.

Si por alguna razón realmente necesitas datos pose, puedes calcularlos a partir de transform en el evento PostSessionUpdate. En general, el transform relativo entre target y camera obtenido en PostSessionUpdate ya es la pose.

El siguiente código muestra cómo obtener el transform de camera y target, y calcular la pose relativa entre ambos:

Session.PostSessionUpdate += () =>
{
    Pose cameraToWorld = new(Session.Assembly.Camera.transform.position, Session.Assembly.Camera.transform.rotation);
    Pose targetToWorld = new(target.transform.position, target.transform.rotation);
    Pose worldToTarget = new()
    {
        position = Quaternion.Inverse(targetToWorld.rotation) * (-targetToWorld.position),
        rotation = Quaternion.Inverse(targetToWorld.rotation)
    };
    Pose cameraToTarget = cameraToWorld.GetTransformedBy(worldToTarget);
};
Precaución

Si al mismo tiempo estás usando AR Foundation, visores u otras bibliotecas de terceros en ejecución, esas bibliotecas también pueden modificar el transform de la cámara de la escena. Debes asegurarte de que el cálculo de pose se haga después de que terminen sus lógicas de actualización; de lo contrario, el resultado puede ser incorrecto. En ese tipo de escena, la pose relativa entre target y origin en PostSessionUpdate sigue siendo correcta.

[Opcional] Interceptar actualizaciones de transform

Cuando las funciones AR están en ejecución, el transform de la cámara y de los objetos de seguimiento en Unity suele actualizarse automáticamente por session. Ese proceso de actualización garantiza la corrección y coherencia del renderizado AR, así que no hay forma de interceptarlo directamente.

Pero si necesitas una lógica personalizada para actualizar el transform de objetos, puedes lograrlo escuchando el evento PostSessionUpdate. Aquí hace falta un método algo engorroso:

  1. Aunque normalmente el contenido de renderizado debería montarse como nodos hijo o componentes adjuntos bajo los objetos controlados por session, si necesitas personalizar la actualización del transform de esos objetos, debes sacarlos de la jerarquía controlada por session. Es decir, esos objetos no deben ser hijos de los objetos controlados por session.
  2. En el evento PostSessionUpdate, registra el transform de los objetos que quieras actualizar de forma personalizada.
  3. Finalmente, en el evento PostSessionUpdate, usa la lógica personalizada para actualizar esos objetos según los datos que proporciona session.
Nota

Es necesario usar el evento PostSessionUpdate, porque solo después de ese momento session deja de operar sobre los objetos de la escena.

Ten en cuenta que este método no se puede usar para modificar la camera; para eso hace falta una lógica más compleja.

Además, este método solo sirve para actualizar de forma personalizada el transform de objetos, no para modificar el transform de objetos controlados por session. Si el transform de un objeto controlado por session se modifica desde fuera, session seguirá sobrescribiendo esos cambios en la siguiente actualización de frame, y eso puede afectar a la corrección de algunos cálculos.

Precaución

Usar este método exige que garantices la corrección del transform de los objetos; de lo contrario, puede provocar errores de renderizado AR.

Si también estás usando AR Foundation, visores u otras bibliotecas de terceros, esas bibliotecas pueden modificar el transform de los objetos de la escena. Debes asegurarte de que la lógica de actualización de esas bibliotecas no entre en conflicto con tu lógica personalizada; de lo contrario, pueden producirse resultados imprevisibles.

Temas relacionados