Unreal의 HoloLens 사진/비디오 카메라

HoloLens 바이저에는 MRC(혼합 현실 캡처)에 사용 가능하고 카메라 프레임의 픽셀 좌표로 Unreal 세계 공간의 개체를 찾는 데 사용할 수 있는 PV(사진/비디오) 카메라가 달려 있습니다.

중요

홀로그램 원격 접속에서는 PV 카메라가 지원되지 않지만, HoloLens PV 카메라 기능을 시뮬레이션하기 위해 PC에 연결된 웹캠을 사용할 수 있습니다.

PV 카메라 피드 설정

중요

PV 카메라는 Windows Mixed Reality 및 OpenXR 플러그 인 모두에서 구현됩니다. 그러나 OpenXR은 Microsoft OpenXR 플러그 인을 설치해야 합니다. 또한 Unreal 4.26용 OpenXR는 제한 사항이 있습니다. 카메라는 DirectX11 RHI에서 작동할 수 있습니다. 이 제한은 Unreal 4.27.1 이상에서 수정되었습니다.

  • 프로젝트 설정 > HoloLens에서 웹캠 기능을 사용하도록 설정합니다.

웹캠 속성이 강조 표시된 HoloLens 프로젝트 설정의 스크린샷

  • "CamCapture"라는 새 행위자를 만들고 카메라 피드를 렌더링하는 평면을 추가합니다.

평면이 추가된 행위자의 스크린샷

  • 장면에 행위자를 추가하고, Texture Object 매개 변수와 텍스처 샘플을 사용하여 CamTextureMaterial이라는 새 장면을 만듭니다. 텍스처의 rgb 데이터를 출력 발광 색으로 보냅니다.

재질 및 텍스처 샘플 청사진

PV 카메라 피드 렌더링

  • CamCapture 청사진에서 PV 카메라를 켭니다.

PV 카메라가 켜진 Toggle ARCapture 함수의 청사진

  • CamTextureMaterial에서 동적 재질 인스턴스를 만들고 이 재질을 행위자의 평면에 할당합니다.

Create Dynamic Material Instance 함수의 청사진

  • 카메라 피드에서 텍스처를 가져와 동적 재질에 할당합니다(유효한 경우). 텍스처가 유효하지 않으면 타이머를 시작하고, 타이머 시간이 끝난 후 다시 시도합니다.

동적 재질에 할당된 카메라 텍스처의 청사진

  • 마지막으로 평면의 크기를 카메라 이미지의 가로 세로 비율로 조정합니다.

카메라 이미지의 가로 세로 비율에 맞게 크기가 조정된 평면의 청사진

세계 공간에서 카메라 위치 찾기

HoloLens 2의 카메라는 디바이스의 머리 추적에서 수직으로 오프셋됩니다. 오프셋을 고려하여 세계 공간에서 카메라를 찾는 몇 가지 기능이 있습니다.

GetPVCameraToWorldTransform은 PV 카메라의 세계 공간에서 변환을 가져오고 카메라 렌즈에 다음과 같이 배치됩니다.

Get PVCamera to World Transform 함수의 청사진

GetWorldSpaceRayFromCameraPoint는 카메라 렌즈의 광선을 Unreal 세계 공간의 장면으로 투사하여 카메라 프레임에서 픽셀의 콘텐츠를 찾습니다.

Get World Space Ray from Camera Point의 청사진

GetPVCameraIntrinsics는 카메라 프레임에서 컴퓨터 비전 처리를 수행할 때 사용할 수 있는 카메라 내장 값을 반환합니다.

Get PVCamera Intrinsics 함수의 청사진

세계 공간의 특정 픽셀 좌표에 무엇이 있는지 알아내려면 세계 공간 광선과 함께 선 추적을 사용합니다.

세계 공간의 특정 좌표에 무엇이 있는지 알아내는 데 사용되는 세계 공간 광선의 청사진

여기서는 카메라 렌즈에서 프레임의 왼쪽 위에서부터 1/4이 되는 카메라 공간 위치로 2미터 광선을 쏩니다. 그런 다음, 적중 결과를 사용하여 세계 공간에서 물체가 있는 항목을 렌더링합니다.

카메라 렌즈에서 프레임의 왼쪽 위에서부터 1/4이 되는 카메라 공간 위치로 방출되는 2미터 광선의 청사진

공간 매핑을 사용하는 경우 이 적중 위치는 카메라가 보는 표면과 일치합니다.

C++에서 PV 카메라 피드 렌더링

  • CamCapture라는 새 C++ 행위자 만들기
  • 프로젝트 build.cs 파일의 PublicDependencyModuleNames 목록에 “AugmentedReality”를 추가합니다.
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을 마우스 오른쪽 단추로 클릭하고 "참조 복사"를 선택하여 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);
}

[틱]에서 카메라의 텍스처를 가져오고, 해당 텍스처를 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 개발 과정을 따르고 있다면 현재 Mixed Reality 플랫폼 기능 및 API를 살펴보는 중입니다. 여기에서 다음 항목으로 진행할 수 있습니다.

또는 디바이스나 에뮬레이터에서 앱 배포로 직접 이동합니다.

언제든지 Unreal 개발 검사점으로 돌아갈 수 있습니다.

참고 항목