Unreal 中的 HoloLens 相片/影片相機

HoloLens 的面板上有相片/影片 (PV) 相機,不僅可用於混合實境擷取 (MRC),也可用來透過相機框架中的像素座標定位 Unreal 世界空間中的物件。

重要

PV 攝影機不支援全像攝影遠端功能,但可以使用連接到您電腦的網路攝影機來模擬 HoloLens PV 攝影機功能。

PV 相機摘要設定

重要

PV 相機會在 Windows Mixed Reality 和 OpenXR 外掛程式中實作。 不過, OpenXR 需要安裝 Microsoft OpenXR 外掛程式 。 此外,OpenXR for Unreal 4.26 有限制:相機可以使用 DirectX11 RHI。 Unreal 4.27.1 或更新版本中已修正這項限制。

  • [專案設定 > HoloLens] 中,啟用 網路攝影機 功能:

已醒目提示 [網路攝影機] 屬性的 HoloLens 專案設定螢幕擷取畫面

  • 建立名為 "CamCapture" 的新動作項目,並新增平面來呈現相機摘要:

螢幕擷取畫面:已新增平面的動作項目

  • 將動作項目新增至您的場景,建立具有「材質物件參數」且名為 CamTextureMaterial 的新材質,以及材質範例。 將材質的 rgb 資料傳送至輸出放射色彩:

藍圖:材質和材質範例

呈現 PV 相機摘要

  • 在 CamCapture 藍圖中,開啟「PV 相機」:

藍圖:已開啟 PV 相機的「切換 ARCapture」函式

  • 從 CamTextureMaterial 建立動態材質執行個體,並將此材質指派給動作項目的平面:

藍圖:建立動態材質執行個體函式

  • 從相機摘要取得材質,並將其指派給動態材質 (如果此材質有效的話)。 如果此材質無效,請啟動計時器,並在逾時後再試一次:

藍圖:指派給動態材質的相機摘要材質

  • 最後,依據相機影像的外觀比例來調整平面:

藍圖:相對於相機影像外觀比例來調整的平面

尋找世界空間中的相機位置

HoloLens 2 上的相機會與裝置的頭部追蹤垂直偏移。 有幾個函式可用來定位世界空間中的相機,以因應此情況。

GetPVCameraToWorldTransform 會取得 PV 相機世界空間中的轉換,並將其定位在相機鏡頭上:

藍圖:取得 PVCamera 對世界轉換函式

GetWorldSpaceRayFromCameraPoint 會從相機鏡頭射出光線到 Unreal 世界空間中的場景,以找出相機框架中特定像素的內容:

藍圖:取得從相機位置點射出的世界空間光線

GetPVCameraIntrinsics 會傳回相機內建值,這可在對相機框架進行電腦視覺處理時用到:

藍圖:取得 PVCamera 內建函式

若要找出世界空間內的特定像素座標上有何項目,請搭配使用光線追蹤與世界空間光線:

藍圖:世界空間光線,用來找出世界空間內的特定座標上有何項目

在這裡,我們會從相機鏡頭射出 2 公尺的光線到框架左上角的相機空間位置 1/4 處。 然後,使用命中結果來呈現物件存在於世界空間中的某些內容:

藍圖:從相機鏡頭射出 2 公尺的光線到框架左上角的相機空間位置 1/4 處

使用空間對應時,此命中位置會符合相機所看到的表面。

在 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 開發旅程,此時您會探索混合實境平台功能和 API。 接下來,您可以繼續進行下一個主題:

或者,直接跳到在裝置或模擬器上部署應用程式的主題:

您可以隨時回到 Unreal 開發檢查點

另請參閱