Obter o resultado de execução de session
Durante a execução de session, o transform de alguns objetos da cena e a imagem da câmera são alterados. Às vezes, essas alterações ainda não são suficientes para a aplicação, e pode ser necessário obter o resultado de execução de session a cada frame e processar esses dados depois. Este artigo explica como obter e usar esses dados.
Antes de começar
- Entenda os conceitos básicos, a composição e o fluxo de trabalho de session por meio de Introdução ao ARSession
- Aprenda como criar session
- Aprenda como acessar componentes de recursos AR
Obter atualizações de InputFrame
Você pode usar o evento InputFrameUpdate para obter atualizações de InputFrame. Esse evento só é disparado quando InputFrame muda nos dados de saída de cada frame de session.
Nota
InputFrameUpdate só é válido em sessions em que a imagem é desenhada pela EasyAR. Em geral, ele não é válido quando se usa AR Foundation ou headsets, e nesse caso é preciso usar os métodos fornecidos por essas bibliotecas de terceiros para obter as atualizações de dados.
Com InputFrame, você pode obter a imagem da câmera física, os parâmetros da câmera, o timestamp, o transform da câmera física em relação ao sistema de coordenadas do mundo e o estado de tracking, entre outros. Porém, como o transform da câmera já foi aplicado pela session à câmera virtual e a outros objetos, normalmente não é necessário obter o transform da câmera por meio de InputFrame.
Obter a imagem da câmera física do frame atual
Você pode usar o método InputFrame.image() para obter dados de imagem da câmera física do tipo Image.
Por exemplo, o código abaixo obtém a imagem da câmera física quando InputFrame é atualizado:
Session.InputFrameUpdate += (inputFrame) => {
using (var image = inputFrame.image())
{
}
};
Cuidado
Ao usar dados do tipo Image e outros dados do tipo class obtidos a partir dele, você deve garantir que Dispose() seja chamado corretamente (a instrução using no código acima já garante isso); caso contrário, pode haver vazamento de memória e até a imagem parar de atualizar.
Se precisar manter InputFrame ou Image para usar no frame seguinte, aumente o valor de ARAssembly.ExtraBufferCapacity de acordo com a quantidade de dados mantida; caso contrário, a obtenção de dados pode falhar por falta de buffer.
Se precisar manter InputFrame, também será necessário chamar Clone() para criar uma cópia por referência e, quando não precisar mais dela, chamar Dispose() na cópia.
Como a taxa de frames da câmera física normalmente é menor que a taxa de renderização, nem todo frame de renderização recebe o evento InputFrameUpdate, mas, do mesmo modo, a imagem da câmera física também não é atualizada em todos os frames de renderização. Todos os frames de renderização antes do próximo disparo de InputFrameUpdate têm o mesmo conteúdo de imagem do InputFrame atual.
Nota
A imagem em InputFrame sempre coincide com a imagem de fundo da câmera virtual do frame atual, mas o render do fundo pode sofrer escala e corte, então é normal que o tamanho ou a proporção da imagem obtida não coincida com o que aparece na tela.
Além disso, vale notar que os dados de imagem retornados por InputFrame.image() são legíveis pela CPU e não são uma textura GPU. Se precisar usar os dados de imagem na GPU, você deve enviá-los para uma textura GPU ou obter diretamente a textura GPU pela interface CameraImageRenderer.RequestTargetTexture(Action<Camera, RenderTexture>).
[Opcional] Interceptar o render da imagem da câmera física
Você pode usar ARAssembly.CameraImageRenderer para controlar o render da imagem da câmera física.
O código abaixo pode interromper o render da imagem da câmera física:
if (Session.Assembly != null && Session.Assembly.CameraImageRenderer.OnSome)
{
Session.Assembly.CameraImageRenderer.Value.enabled = false;
}
Observe que aqui é necessário verificar primeiro se ARAssembly.CameraImageRenderer existe.
Nota
Só em sessions em que a imagem é desenhada pela EasyAR é possível interromper a atualização da imagem pelo método acima. Em geral, ele não é válido quando se usa AR Foundation ou headsets, e nesse caso é preciso usar os métodos fornecidos por essas bibliotecas de terceiros para alcançar a função correspondente.
Depois de interromper o render da imagem da câmera física, a aplicação pode obter os dados de imagem da câmera física por meio de InputFrame e usar esses dados para renderização personalizada.
Obter atualizações de transform
Você pode obter os dados de transform dos objetos da cena após cada atualização de session por meio do evento PostSessionUpdate.
Nota
Em algumas funções (por exemplo Mega), mesmo sem mudança de imagem e sem solicitação visível de atualização ao serviço, o cálculo AR continua executando em cada frame de renderização. Por isso, se precisar obter todas as mudanças de transform, você deve pegar os dados de transform a cada frame, e não apenas em alguns frames.
Obter o transform da câmera virtual
Você pode obter o transform da câmera na cena por meio de ARAssembly.Camera.
Session.PostSessionUpdate += () =>
{
var position = Session.Assembly.Camera.transform.position;
var rotation = Session.Assembly.Camera.transform.rotation;
};
Obter o transform do target
Você pode obter o transform do target na cena pelo objeto target específico que estiver usando. Por exemplo, em image tracking, esse target é o objeto que contém o componente ImageTargetController.
Session.PostSessionUpdate += () =>
{
var position = target.transform.position;
var rotation = target.transform.rotation;
};
[Opcional] Obter pose
pose é uma estrutura de dados que descreve a posição e a orientação de um objeto, normalmente composta por position e rotation. Em aplicações AR, pose costuma ser usada para descrever a posição e a orientação da câmera física ou do target de tracking em relação a um sistema de referência.
Unity não fornece dados de pose brutos, porque pose normalmente é usada para dirigir o movimento dos objetos da cena, e isso já é feito automaticamente pela session. Para cálculo e renderização de conteúdo, transform já é suficiente.
Importante
Antes de ler o método abaixo, pense novamente se os dados de transform da câmera, do target de tracking e de outros objetos já atendem às suas necessidades. Normalmente, dados de pose adicionais não são necessários.
Se, por algum motivo, você realmente precisar de dados de pose, pode calculá-los a partir de transform no evento PostSessionUpdate. Em geral, o transform relativo entre target e camera obtido em PostSessionUpdate já é a pose.
O código abaixo mostra como obter os transforms de camera e target e calcular a pose relativa entre eles:
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);
};
Cuidado
Se você também estiver usando AR Foundation, headsets ou outras bibliotecas de terceiros em execução, essas bibliotecas podem alterar o transform da câmera da cena. É preciso garantir que o cálculo da pose aconteça depois que a lógica de atualização delas terminar; caso contrário, o resultado pode estar incorreto. Nesse tipo de cenário, a pose relativa entre target e origin em PostSessionUpdate continua correta.
[Opcional] Interceptar atualizações de transform
Quando as funções AR estão em execução, o transform da câmera, do target de tracking e de outros objetos no Unity normalmente é atualizado automaticamente pela session. Esses processos de atualização garantem a correção e a consistência do render AR, então não existe um método para interceptá-los diretamente.
Mas, se você precisar de uma lógica personalizada de atualização de transform de objetos, pode fazer isso escutando o evento PostSessionUpdate. Aqui é preciso usar um método um pouco trabalhoso:
- Embora normalmente o conteúdo renderizado deva ser montado como nós filho ou componentes anexados sob os objetos controlados pela session, se você precisar personalizar a atualização do transform desses objetos, será necessário removê-los da hierarquia controlada pela session. Ou seja, esses objetos não devem ser filhos dos objetos controlados pela session.
- No evento PostSessionUpdate, registre o transform dos objetos que você quer atualizar de forma personalizada.
- Por fim, no evento PostSessionUpdate, use a lógica personalizada para atualizar esses objetos com base nos dados fornecidos pela session.
Nota
O uso do evento PostSessionUpdate é obrigatório, porque só depois desse momento a session deixa de agir sobre os objetos da cena.
Observe que esse método não pode ser usado para modificar a camera; é necessária uma lógica mais complexa para lidar com a atualização personalizada da câmera.
Além disso, esse método serve apenas para atualizar de forma personalizada o transform dos objetos, não para modificar o transform dos objetos controlados pela session. Se o transform de um objeto controlado pela session for alterado externamente, a session continuará sobrescrevendo essas mudanças na próxima atualização de frame, o que pode afetar a correção de alguns cálculos.
Cuidado
Usar esse método exige que você garanta a correção do transform dos objetos; caso contrário, pode causar erros de render AR.
Se você também estiver usando AR Foundation, headsets ou outras bibliotecas de terceiros, essas bibliotecas podem alterar o transform dos objetos da cena. É preciso garantir que a lógica de atualização dessas bibliotecas não entre em conflito com a sua lógica personalizada; caso contrário, podem ocorrer resultados imprevisíveis.
Tópicos relacionados
- Modo central limita quais objetos a session pode modificar via transform
- Introdução aos componentes básicos de AR