HoloLens foto/videokamera i Unreal

I HoloLens finns en foto-/videokamera (PV) på visor-programmet som kan användas för både Inspelning av mixad verklighet (MRC) och hitta objekt i Unreal World-utrymmet från pixelkoordinater i kameraramen.

Viktigt

PV-kameran stöds inte med Holographic Remoting, men det är möjligt att använda en webbkamera som är ansluten till datorn för att simulera funktionen HoloLens PV-kamera.

Installation av PV-kameraflöde

Viktigt

PV-kameran implementeras i både Windows Mixed Reality- och OpenXR-plugin-program. OpenXR måste dock ha microsoft OpenXR-plugin-programmet installerat. Dessutom har OpenXR för Unreal 4.26 en begränsning: kameran kan fungera med DirectX11 RHI. Den här begränsningen har åtgärdats i Unreal 4.27.1 eller senare.

  • I Project Inställningar HoloLensaktiverar du funktionen Webbkamera:

Skärmbild av HoloLens projektinställningar med egenskapen Webbkamera markerad

  • Skapa en ny skådespelare med namnet "CamCapture" och lägg till ett plan för att rendera kameraflödet:

Skärmbild av en aktör med ett tillagt plan

  • Lägg till skådespelaren i din scen, skapa ett nytt material som heter CamTextureMaterial med en Parameter för strukturobjekt och ett exempel på en struktur. Skicka rgb-data för strukturen till den tillåtande utdatafärgen:

Skiss av ett material- och strukturexempel

Rendering av PV-kameraflödet

  • I CamCapture-skissen aktiverar du PV-kameran:

Skiss för funktionen Toggle ARCapture med PV-kameran aktiverad

  • Skapa en dynamisk materialinstans från CamTextureMaterial och tilldela det här materialet till aktörens plan:

Skiss för funktionen Skapa dynamisk materialinstans

  • Hämta strukturen från kameraflödet och tilldela den till det dynamiska materialet om det är giltigt. Om strukturen inte är giltig startar du en timer och försöker igen efter tidsgränsen:

Skiss för kameraflödesstruktur som tilldelats det dynamiska materialet

  • Slutligen skalar du planet efter kamerabildens bredd–höjd-förhållande:

Skiss av planskalade i förhållande till kamerabilders bredd–höjd-förhållande

Hitta kamerapositioner i world space

Kameran på HoloLens 2 förskjuts lodrätt från enhetens huvudspårning. Det finns några funktioner för att hitta kameran i rymden för att ta hänsyn till förskjutningen.

GetPVCameraToWorldTransform hämtar transformeringen i rymden av PV-kameran och placeras på kameralinsen:

Skiss för funktionen Get PVCamera to World Transform

GetWorldSpaceRayFromCameraPoint kastar en tavla från kameralinsen till scenen i Unreal World-utrymmet för att hitta en pixels innehåll i kameraramen:

Skiss av Get World Space Ray från kamerapunkt

GetPVCameraIntrinsics returnerar kamerans inbyggda värden, som kan användas vid bearbetning av datorseende på en kameraram:

Skiss för get PVCamera-inbyggda funktioner

Om du vill hitta det som finns i rymden på en viss pixelkoordinat använder du en linjespårning med rymdbilden i världen:

En skiss av rymdbilden som används för att ta reda på vad som finns i rymden vid en viss koordinat

Här kastar vi en 2-meter ray från kameralinsen till kamerautrymmets position 1/4 upptill till vänster på ramen. Använd sedan träffresultatet för att rendera något där objektet finns i världrymden:

Skiss av en 2-meters ray cast från kameralinsen till kamerautrymmets position 1/4 från det övre vänstra hörnet av ramen

När du använder rumslig mappning matchar träffpositionen den yta som kameran ser.

Rendering av PV-kameraflödet i C++

  • Skapa en ny C++-skådespelare med namnet CamCapture
  • I projektets build.cs lägger du till "AugmentedReality" i listan PublicDependencyModuleNames:
PublicDependencyModuleNames.AddRange(
    new string[] {
        "Core",
        "CoreUObject",
        "Engine",
        "InputCore",
        "AugmentedReality"
});
  • I CamCapture.h inkluderar du ARBlueprintLibrary.h
#include "ARBlueprintLibrary.h"
  • Du måste också lägga till lokala variabler för nät och material:
private:
    UStaticMesh* StaticMesh;
    UStaticMeshComponent* StaticMeshComponent;
    UMaterialInstanceDynamic* DynamicMaterial;
    bool IsTextureParamSet = false;
  • I CamCapture.cpp uppdaterar du konstruktorn för att lägga till ett statiskt nät i scenen:
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);
}

I BeginPlay skapar du en dynamisk materialinstans från projektets kameramaterial, tillämpar den på komponenten för statiskt nät och startar HoloLens kameran.

I redigeraren högerklickar du på CamTextureMaterial i innehållswebbläsaren och väljer "Kopiera referens" för att hämta strängen för 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);
}

I Tick hämtar du strukturen från kameran, ställer in den på parametern för struktur i CamTextureMaterial-materialet och skalar den statiska nätkomponenten med kameraramens bredd–höjd-förhållande:

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));
    }
}

Nästa kontrollpunkt för utveckling

Om du följer den Unreal-utvecklingsresa som vi har skapat är du inte ute efter att utforska de Mixed Reality plattformsfunktionerna och API:erna. Härifrån kan du fortsätta till nästa avsnitt:

Eller gå direkt till att distribuera din app på en enhet eller emulator:

Du kan alltid gå tillbaka till kontrollpunkterna för Unreal-utveckling när som helst.

Se även