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:
- Crie um ator chamado “CamCapture” e adicione um plano para renderizar o feed da câmera:
- 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:
Como renderizar o feed da câmera PV
- No blueprint CamCapture, ligue a Câmera de PV:
- Crie uma instância de material dinâmico com base em CamTextureMaterial e atribua esse material ao plano do ator:
- 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:
- Por fim, escale o plano pela taxa de proporção da imagem 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:
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:
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:
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:
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:
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.