Câmera de foto/vídeo do HoloLens no Unreal

O HoloLens traz uma Câmera de PV (foto/vídeo) no visor que pode ser usada para a MRC (Captura de Realidade Misturada) e para localizar objetos no espaço de mundo do Unreal por meio de coordenadas de pixel no quadro da câmera.

Importante

A câmera PV não é compatível com a Comunicação Remota Holográfica, mas é possível usar uma webcam anexada ao seu PC para simular a funcionalidade da câmera PV do HoloLens.

Configuração do feed da câmera PV

Importante

A câmera PV é implementada nos plug-ins do Windows Mixed Reality e do OpenXR. No entanto, o OpenXR precisa que o plug-in do Microsoft OpenXR esteja instalado. Além disso, o OpenXR para Unreal 4.26 tem uma limitação: a câmera pode funcionar com o DirectX11 RHI. Essa limitação é corrigida no Unreal 4.27.1 ou posterior.

  • Em Configurações do Projeto > HoloLens, habilite a funcionalidade Webcam:

Captura de tela das configurações de projeto do HoloLens com a propriedade Webcam realçada

  • Crie um ator chamado “CamCapture” e adicione um plano para renderizar o feed da câmera:

Captura de tela do ator com um plano adicionado

  • Adicione o ator à cena, crie um material chamado CamTextureMaterial com um parâmetro de objeto de textura e um exemplo de textura. Envie os dados RGB da textura para a cor emissiva de saída:

Blueprint de um exemplo de material e de textura

Como renderizar o feed da câmera PV

  • No blueprint CamCapture, ligue a Câmera de PV:

Blueprint da função Alternar ARCapture com a câmera PV ligada

  • Crie uma instância de material dinâmico com base em CamTextureMaterial e atribua esse material ao plano do ator:

Blueprint da função Criar Instância de Material Dinâmico

  • Obtenha a textura do feed de câmera e atribua-a ao material dinâmico se ela for válida. Se a textura não for válida, inicie um temporizador e tente novamente após o tempo limite:

Blueprint da textura do feed de câmera atribuída ao material dinâmico

  • Por fim, escale o plano pela taxa de proporção da imagem da câmera:

Blueprint do plano escalado em relação à taxa de proporção das imagens da câmera

Localizar posições da câmera no espaço de mundo

A câmera do HoloLens 2 é deslocada verticalmente começando no acompanhamento de cabeça do dispositivo. Existem algumas funções para localizar a câmera no espaço de mundo para levar em conta o deslocamento.

A função GetPVCameraToWorldTransform obtém a transformação no espaço de mundo da Câmera de PV e será posicionada na lente da câmera:

Blueprint da função Obter Transformação da PVCamera para o Mundo

A função GetWorldSpaceRayFromCameraPoint converte um raio da lente da câmera na cena em um espaço de mundo do Unreal para localizar o conteúdo de um pixel no quadro da câmera:

Blueprint da função Obter Raio do Espaço de Mundo do Ponto da Câmera

A função GetPVCameraIntrinsics retorna os valores intrínsecos da câmera, que podem ser usados durante o processamento da pesquisa visual computacional em um quadro da câmera:

Blueprint das funções Obter Intrínsecos da PVCamera

Para localizar o que existe no espaço de mundo em uma coordenada de pixel específica, use um rastreamento de linha com o raio do espaço de mundo:

Blueprint do raio do espaço de mundo sendo usado para descobrir o que existe no espaço de mundo em uma coordenada específica

Aqui, converteremos um raio de 2 metros começando na lente da câmera até a posição do espaço da câmera, a ¼ do canto superior esquerdo do quadro. Em seguida, usaremos o resultado da ocorrência para renderizar algo no local em que o objeto existe no espaço de mundo:

Blueprint de uma conversão de raio de 2 metros começando na lente da câmera até a posição do espaço da câmera, a 1/4 do canto superior esquerdo do quadro

Quando você usar o mapeamento espacial, a posição dessa ocorrência corresponderá à superfície vista pela câmera.

Como renderizar o feed da câmera PV em C++

  • Crie um ator em C++ chamado CamCapture
  • No build.cs do projeto, adicione “AugmentedReality” à lista PublicDependencyModuleNames:
PublicDependencyModuleNames.AddRange(
    new string[] {
        "Core",
        "CoreUObject",
        "Engine",
        "InputCore",
        "AugmentedReality"
});
  • Em CamCapture.h, inclua ARBlueprintLibrary.h
#include "ARBlueprintLibrary.h"
  • Você também precisa adicionar variáveis locais à malha e ao material:
private:
    UStaticMesh* StaticMesh;
    UStaticMeshComponent* StaticMeshComponent;
    UMaterialInstanceDynamic* DynamicMaterial;
    bool IsTextureParamSet = false;
  • Em CamCapture.cpp, atualize o construtor para adicionar uma malha estática à cena:
ACamCapture::ACamCapture()
{
    PrimaryActorTick.bCanEverTick = true;

    // Load a mesh from the engine to render the camera feed to.
    StaticMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/EngineMeshes/Cube.Cube"), nullptr, LOAD_None, nullptr);

    // Create a static mesh component to render the static mesh
    StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CameraPlane"));
    StaticMeshComponent->SetStaticMesh(StaticMesh);

    // Scale and add to the scene
    StaticMeshComponent->SetWorldScale3D(FVector(0.1f, 1, 1));
    this->SetRootComponent(StaticMeshComponent);
}

Em BeginPlay, crie uma instância de material dinâmico com base no material da câmera do projeto, aplique-a ao componente de malha estática e inicie a câmera do HoloLens.

No editor, clique com o botão direito do mouse em CamTextureMaterial no navegador de conteúdo e selecione “Copiar Referência” para obter a cadeia de caracteres de CameraMatPath.

void ACamCapture::BeginPlay()
{
    Super::BeginPlay();

    // Create a dynamic material instance from the game's camera material.
    // Right-click on a material in the project and select "Copy Reference" to get this string.
    FString CameraMatPath("Material'/Game/Materials/CamTextureMaterial.CamTextureMaterial'");
    UMaterial* BaseMaterial = (UMaterial*)StaticLoadObject(UMaterial::StaticClass(), nullptr, *CameraMatPath, nullptr, LOAD_None, nullptr);
    DynamicMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);

    // Use the dynamic material instance when rendering the camera mesh.
    StaticMeshComponent->SetMaterial(0, DynamicMaterial);

    // Start the webcam.
    UARBlueprintLibrary::ToggleARCapture(true, EARCaptureType::Camera);
}

Em Tick, obtenha a textura da câmera, defina-a como o parâmetro de textura no material CamTextureMaterial e escale o componente de malha estática pela taxa de proporção do quadro da câmera:

void ACamCapture::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    // Dynamic material instance only needs to be set once.
    if(IsTextureParamSet)
    {
        return;
    }

    // Get the texture from the camera.
    UARTexture* ARTexture = UARBlueprintLibrary::GetARTexture(EARTextureType::CameraImage);
    if(ARTexture != nullptr)
    {
        // Set the shader's texture parameter (named "Param") to the camera image.
        DynamicMaterial->SetTextureParameterValue("Param", ARTexture);
        IsTextureParamSet = true;

        // Get the camera instrincs
        FARCameraIntrinsics Intrinsics;
        UARBlueprintLibrary::GetCameraIntrinsics(Intrinsics);

        // Scale the camera mesh by the aspect ratio.
        float R = (float)Intrinsics.ImageResolution.X / (float)Intrinsics.ImageResolution.Y;
        StaticMeshComponent->SetWorldScale3D(FVector(0.1f, R, 1));
    }
}

Próximo ponto de verificação de desenvolvimento

Se está seguindo o percurso de desenvolvimento do Unreal que apresentamos, você está no meio da exploração de funcionalidades e APIs da plataforma de Realidade Misturada. Deste ponto, você pode prosseguir para o próximo tópico:

Ou vá diretamente para a implantação de seu aplicativo em um dispositivo ou emulador:

Você sempre pode voltar para os pontos de verificação de desenvolvimento do Unreal a qualquer momento.

Veja também