Table of Contents

Acessar componentes de função AR na session

Em uma session em execução, é possível acessar cada componente funcional pela propriedade Assembly. Este artigo apresenta como acessar esses componentes e os pontos que exigem atenção durante o acesso.

Antes de começar

Configurar componentes AR durante a edição ou antes da inicialização

Às vezes, certas opções de componente, como DesiredFocusMode, precisam ser configuradas antes que o componente seja iniciado. Se você não quiser configurar e iniciar manualmente os componentes após a inicialização da session, uma forma simples é configurar todas as componentes frame source que possivelmente serão usadas antes da montagem da session. O processo de montagem manterá uma ou mais dessas componentes e aplicará suas configurações.

Nesse momento, é possível usar qualquer método básico do Unity, como FindAnyObjectByType<T>() ou GetComponent<T>(), para encontrar os componentes e então configurá-los.

Nota

Não é certo se os componentes AR obtidos por esse método serão incluídos na session em tempo de execução. Portanto, é necessário configurar todos os casos possíveis.

Por exemplo, o código abaixo mostra o processo de modificar o modo de foco de todos os componentes frame source antes da montagem da session:

void Awake()
{
    var allFrameSources = Session.GetComponentsInChildren<FrameSource>();
    foreach (var source in allFrameSources)
    {
        if (source is CameraDeviceFrameSource)
        {
            ((CameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? CameraDeviceFocusMode.Continousauto : CameraDeviceFocusMode.Medium;
        }
        else if (source is MotionTrackerFrameSource)
        {
            ((MotionTrackerFrameSource)source).DesiredFocusMode = autoFocus ? MotionTrackerCameraDeviceFocusMode.Continousauto : MotionTrackerCameraDeviceFocusMode.Medium;
        }
        else if (source is ARCoreFrameSource)
        {
            ((ARCoreFrameSource)source).DesiredFocusMode = autoFocus ? ARCoreCameraDeviceFocusMode.Auto : ARCoreCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARKitFrameSource)
        {
            ((ARKitFrameSource)source).DesiredFocusMode = autoFocus ? ARKitCameraDeviceFocusMode.Auto : ARKitCameraDeviceFocusMode.Fixed;
        }
        else if (source is AREngineFrameSource)
        {
            ((AREngineFrameSource)source).DesiredFocusMode = autoFocus ? AREngineCameraDeviceFocusMode.Auto : AREngineCameraDeviceFocusMode.Fixed;
        }
        else if (source is ThreeDofCameraDeviceFrameSource)
        {
            ((ThreeDofCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? ThreeDofCameraDeviceFocusMode.Auto : ThreeDofCameraDeviceFocusMode.Fixed;
        }
        else if (source is InertialCameraDeviceFrameSource)
        {
            ((InertialCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? InertialCameraDeviceFocusMode.Auto : InertialCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARFoundationFrameSource)
        {
            cameraManager.autoFocusRequested = autoFocus;
        }
    }
}

O processo acima também pode ser concluído no editor, e da mesma forma é necessário configurar todos os componentes:

alt text

As configurações correspondentes aos dois frame sources ARCoreARFoundationFrameSource e ARKitARFoundationFrameSource ficam nos componentes da Main Camera.

Aviso

Os componentes AR obtidos por esse método só podem ser usados para configuração antes da execução.
Como o processo de montagem filtra os componentes AR, os componentes AR obtidos pela árvore da cena podem não estar incluídos na session e não funcionar corretamente.

Usar componentes AR montados durante a execução

Os componentes AR que rodam na session só são determinados depois da montagem. Antes que a montagem seja concluída, nenhum componente AR pode ser usado. Os componentes AR montados podem ser acessados pela propriedade Assembly.

Assembly pode ser usado quando o estado da session for >= Assembled. Em detalhes, a propriedade Assembly só será atribuída depois que o método Assemble() terminar sua execução, e então ela poderá ser usada para acessar os componentes da session. Depois que a session parar ou quebrar, a propriedade Assembly será limpa e os componentes não poderão mais ser acessados.

É possível verificar State da session no script para determinar se os componentes AR podem ser acessados naquele momento:

if (Session.State >= ARSession.SessionState.Ready)
{
    // Assembly esta disponivel
}
else
{
    // Assembly nao esta disponivel
}

Também é possível assinar o evento StateChanged para obter mudanças de estado da session e acessar os componentes AR no momento adequado. Em geral, para capturar o estado Ready, é necessário assinar o evento StateChanged antes do início da session; normalmente, assinar em Awake() é seguro:

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (Session.State == ARSession.SessionState.Ready)
        {
            // Assembly esta disponivel; depois disso, Assembly permanece acessivel ate que a session seja interrompida ou danificada
        }
        else if (Session.State < ARSession.SessionState.Ready)
        {
            // Assembly nao esta disponivel; depois disso, Assembly permanece inacessivel ate que a session seja reiniciada
        }
        else
        {
            // Assembly esta disponivel; normalmente nao precisa ser tratado
        }
    };
}
Cuidado

Se os componentes AR obtidos por métodos como FindAnyObjectByType<T>() ou GetComponent<T>() certamente forem incluídos na session, eles também poderão ser usados em tempo de execução.
Apenas armazenar referências a esses componentes é seguro, mas ao usá-los é necessário garantir que a session esteja em execução e que esses componentes estejam corretamente incluídos na session; caso contrário, exceções ou comportamentos inesperados podem ocorrer.
Antes da session iniciar e depois de parar, esses componentes não funcionam. Recomenda-se que, mesmo nesse tipo de uso, você acompanhe State e o evento StateChanged da session.

Acessar componentes frame source

É possível acessar o componente frame source pela propriedade ARAssembly.FrameSource. Em uma session funcionando normalmente, existe um e somente um ARAssembly.FrameSource.

Ao usar a session, normalmente é necessário acessar ARAssembly.FrameSource para determinar o tipo de componente frame source realmente usado em tempo de execução e, assim, acessar propriedades e métodos específicos desse componente.

Por exemplo, o código abaixo mostra como usar diferentes métodos de detecção de plano de acordo com o frame source:

void PlaceObject(Vector2 touchPosition)
{
    if (Session.Assembly.FrameSource is MotionTrackerFrameSource)
    {
        Ray ray = Session.Assembly.Camera.ScreenPointToRay(touchPosition);
        if (Physics.Raycast(ray, out var hitInfo))
        {
            TouchRoot.transform.position = hitInfo.point;
        }
    }
    else if (Session.Assembly.FrameSource is ARFoundationFrameSource)
    {
        var raycastManager = Session.Assembly.Origin.Value.GetComponent<UnityEngine.XR.ARFoundation.ARRaycastManager>();
        var hits = new List<UnityEngine.XR.ARFoundation.ARRaycastHit>();
        if (raycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinPolygon))
        {
            var hitPose = hits[0].pose;
            TouchRoot.transform.position = hitPose.position;
        }
    }
}

Acessar componentes frame filter

É possível acessar componentes frame filter pela propriedade ARAssembly.FrameFilters. Em uma session funcionando normalmente, qualquer tipo de componente na lista ARAssembly.FrameFilters pode ter várias instâncias.

Por exemplo, o código abaixo mostra como obter um MegaTrackerFrameFilter da session e registrar o evento correspondente:

var megaTracker = session.Assembly.FrameFilters.Where(f => f is MegaTrackerFrameFilter).FirstOrDefault() as MegaTrackerFrameFilter;
if (megaTracker)
{
    megaTracker.LocalizationRespond += (response) =>
    {
    };
}

Acessar componente camera

É possível acessar o componente camera pela propriedade ARAssembly.Camera. Se houver várias cameras na cena, esta é uma forma rápida de encontrar a câmera usada por AR.

Por exemplo, o código abaixo mostra como obter a camera da session e fazer raycast em objetos da cena:

var ray = Session.Assembly.Camera.ScreenPointToRay(screenPoint);
if (Physics.Raycast(ray, out var hitInfo))
{
    TouchRoot.transform.position = hitInfo.point;
};

Acessar componente origin

É possível acessar o componente origin pela propriedade ARAssembly.Origin.

Por exemplo, o código abaixo mostra como obter o origin da session e exibir na cena um cone que representa a posição e a orientação atuais da câmera:

if (session.Assembly.Origin.OnSome)
{
    GameObject frustum = Instantiate(CameraFrustumPrefab, session.Assembly.Camera.transform.position, session.Assembly.Camera.transform.rotation);
    frustum.transform.SetParent(session.Assembly.Origin.Value.transform);
}

Observe que aqui é necessário primeiro verificar se ARAssembly.Origin existe.

Nota

ARAssembly.Origin só existe em sessions com rastreamento de movimento habilitado.

Acessar componente CameraImageRenderer

É possível acessar o componente CameraImageRenderer pela propriedade ARAssembly.CameraImageRenderer.

Por exemplo, o código abaixo pode obter a RenderTexture da imagem da câmera física:

RenderTexture renderTexture;

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (state == ARSession.SessionState.Ready && Session.Assembly.CameraImageRenderer.OnSome)
        {
            Session.Assembly.CameraImageRenderer.Value.RequestTargetTexture((_, texture) => renderTexture = texture);
        }
    };
}

Observe que aqui é necessário primeiro verificar se ARAssembly.CameraImageRenderer existe.

Nota

ARAssembly.CameraImageRenderer só é válido em sessions cuja imagem é desenhada pelo EasyAR. Em geral, ao usar AR Foundation ou headsets, ele é inválido; nesse caso, a imagem da câmera física é desenhada pelo AR Foundation ou pelo SDK do headset.

Acessar componente FrameRecorder

É possível acessar o componente FrameRecorder pela propriedade ARAssembly.FrameRecorder.

Por exemplo, o código abaixo pode iniciar a gravação; o local de armazenamento do arquivo depende da configuração e, por padrão, ele será armazenado no diretório interno do aplicativo:

if (session.Assembly.FrameRecorder.OnSome)
{
    var frameRecorder = session.Assembly.FrameRecorder.Value;
    frameRecorder.enabled = true;
}

Observe que aqui é necessário primeiro verificar se ARAssembly.FrameRecorder existe.

Nota

ARAssembly.FrameRecorder não pode ser usado em alguns poucos casos, como ao usar FramePlayer.

Próximos passos

Tópicos relacionados