Фото- и видеокамера 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 (Веб-камера):

Снимок экрана: параметры проекта HoloLens с выделенным свойством Webcam

  • Создайте субъект с именем CamCapture и добавьте плоскость для визуализации данных с камеры:

Снимок экрана: субъект с добавленной плоскостью

  • Добавьте субъект в сцену, создайте материал с именем CamTextureMaterial с параметром объекта текстуры и пример текстуры. Отправьте RGB-данные текстуры в выходной излучаемый цвет:

Схема материала и пример текстуры

Визуализация потока данных с фотовидеокамеры

  • В схеме CamCapture включите фотовидеокамеру:

Схема функции Toggle ARCapture с включенной фотовидеокамерой

  • Создайте экземпляр динамического материала из CamTextureMaterial и назначьте этот материал плоскости субъекта:

Схема функции Create Dynamic Material Instance

  • Получите текстуру из потока данных камеры и назначьте ее динамическому материалу (если она допустимая). Если текстура не является допустимой, запустите таймер и повторите попытку после его истечения:

Схема текстуры из потока данных камеры, назначенной динамическому материалу

  • Наконец, масштабируйте плоскость по пропорциям изображения камеры:

Схема плоскости, масштабированная относительно пропорций изображения с камеры

Поиск позиций камеры в мировом пространстве

Камера на HoloLens 2 смещена вертикально по отношению к позиции отслеживания головы на устройстве. Для компенсации такого смещения доступно несколько функций, которые позволяют определить положение камеры в абсолютном пространстве.

GetPVCameraToWorldTransform получает преобразование в абсолютном пространстве фотовидеокамеры, располагаясь на линзе камеры:

Схема функции Get PVCamera to World Transform

GetWorldSpaceRayFromCameraPoint пускает луч из объектива камеры в сцену в абсолютном пространстве Unreal, чтобы определить содержимое пикселя в кадре камеры:

Схема функции Get World Space Ray from Camera Point

GetPVCameraIntrinsics возвращает характерные значения камеры, которые можно использовать при обработке кадра камеры с помощью компьютерного зрения:

Схема функций Get PVCamera Intrinsics

Чтобы определить, что находится в реальном пространстве по определенной пиксельной координате, используйте трассировку линии с помощью луча абсолютного пространства:

Схема луча мирового пространства, используемого для определения того, что находится в мировом пространстве по определенной координате

Здесь мы выпускаем из объектива камеры луч длиной 2 метра в верхнюю левую четверть кадра камеры. Затем мы используем результат попадания для визуализации той позиции, в которой существует объект в мировом пространстве:

Схема выпуска из объектива камеры луча длиной 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.

См. также статью