Фото- и видеокамера HoloLens в Unreal
Устройство HoloLens оборудовано фотовидеокамерой, установленной на видоискателе, которую можно использовать для съемки смешанной реальности и для поиска объектов в мировом пространстве Unreal по пиксельным координатам в кадре камеры.
Важно!
Фото-/видеокамера не поддерживается в голографическом удаленном взаимодействии, но вы можете использовать веб-камеру, подключенную к компьютеру, для имитации функциональности фото-/видеокамеры в HoloLens.
Настройка потока данных с фотовидеокамеры
Важно!
Фото- и видеокамера реализована в подключаемых модулях для Windows Mixed Reality и OpenXR. Но для работы OpenXR необходимо установить подключаемый модуль Microsoft OpenXR. Кроме того, OpenXR для Unreal 4.26 имеет ограничение: камера работает только с DirectX11 RHI. Это ограничение устранено в версии Unreal 4.27.1 и более поздних.
- В разделе Project Settings > HoloLens (Параметры проекта > HoloLens) включите возможность Webcam (Веб-камера):
- Создайте субъект с именем CamCapture и добавьте плоскость для визуализации данных с камеры:
- Добавьте субъект в сцену, создайте материал с именем CamTextureMaterial с параметром объекта текстуры и пример текстуры. Отправьте RGB-данные текстуры в выходной излучаемый цвет:
Визуализация потока данных с фотовидеокамеры
- В схеме CamCapture включите фотовидеокамеру:
- Создайте экземпляр динамического материала из CamTextureMaterial и назначьте этот материал плоскости субъекта:
- Получите текстуру из потока данных камеры и назначьте ее динамическому материалу (если она допустимая). Если текстура не является допустимой, запустите таймер и повторите попытку после его истечения:
- Наконец, масштабируйте плоскость по пропорциям изображения камеры:
Поиск позиций камеры в мировом пространстве
Камера на HoloLens 2 смещена вертикально по отношению к позиции отслеживания головы на устройстве. Для компенсации такого смещения доступно несколько функций, которые позволяют определить положение камеры в абсолютном пространстве.
GetPVCameraToWorldTransform получает преобразование в абсолютном пространстве фотовидеокамеры, располагаясь на линзе камеры:
GetWorldSpaceRayFromCameraPoint пускает луч из объектива камеры в сцену в абсолютном пространстве Unreal, чтобы определить содержимое пикселя в кадре камеры:
GetPVCameraIntrinsics возвращает характерные значения камеры, которые можно использовать при обработке кадра камеры с помощью компьютерного зрения:
Чтобы определить, что находится в реальном пространстве по определенной пиксельной координате, используйте трассировку линии с помощью луча абсолютного пространства:
Здесь мы выпускаем из объектива камеры луч длиной 2 метра в верхнюю левую четверть кадра камеры. Затем мы используем результат попадания для визуализации той позиции, в которой существует объект в мировом пространстве:
При использовании пространственного сопоставления такая позиция попадания будет соответствовать поверхности, которую видит камера.
Визуализация потока данных с фотовидеокамеры в C++
- Создание нового субъекта C++ с именем CamCapture
- В файле build.cs проекта добавьте AugmentedReality в список PublicDependencyModuleNames:
PublicDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore",
"AugmentedReality"
});
- в файле CamCapture.h включите ARBlueprintLibrary.h:
#include "ARBlueprintLibrary.h"
- Вам также нужно добавить локальные переменные для сетки и материала:
private:
UStaticMesh* StaticMesh;
UStaticMeshComponent* StaticMeshComponent;
UMaterialInstanceDynamic* DynamicMaterial;
bool IsTextureParamSet = false;
- В файле CamCapture.cpp обновите конструктор для добавления статической сетки в сцену:
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);
}
В BeginPlay создайте экземпляр динамического материала из материала камеры в проекте, примените его к компоненту статической сетки и запустите камеру HoloLens.
В редакторе щелкните CamTextureMaterial в обозревателе содержимого и выберите Copy Reference (Копировать ссылку), чтобы получить строку для 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);
}
В Tick получите текстуру с камеры, сопоставьте ее с параметром текстуры в материале CamTextureMaterial и масштабируйте компонент статической сетки по пропорциям кадра камеры:
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));
}
}
Следующий этап разработки
Если вы следуете изложенной нами стратегии разработки для Unreal, вы как раз прошли половину в изучении возможностей и API платформы Смешанной реальности. Вы можете перейти к следующей статье:
Или сразу перейдите к развертыванию приложения на устройстве или эмуляторе:
Вы можете в любой момент вернуться к этапам разработки для Unreal.