HoloLens-Foto-/Videokamera in UnrealHoloLens Photo/Video Camera in Unreal

Die HoloLens weist eine Foto-/Videokamera (FV-Kamera) auf dem Visor auf, die sowohl für die Mixed Reality-Aufnahme (Mixed Reality Capture, MRC) als auch zum Lokalisieren von Objekten im Weltbereich von Unreal anhand von Pixelkoordinaten im Kamerabild verwendet werden kann.The HoloLens has a Photo/Video (PV) Camera on the visor that can be used for both Mixed Reality Capture (MRC) and locating objects in Unreal world space from pixel coordinates in the camera frame.

Wichtig

Die PV-Kamera wird nicht mit Holographic Remoting unterstützt, aber es ist möglich, eine mit Ihrem PC verbundene Webcam zu verwenden, um die PV-Kamerafunktion von HoloLens zu simulieren.The PV Camera isn't supported with Holographic Remoting, but it's possible to use a webcam attached to your PC to simulate the HoloLens PV Camera functionality.

Setup des FV-KamerafeedsPV Camera Feed Setup

Wichtig

Die FV-Kamera ist sowohl in Windows Mixed Reality-als auch in OpenXR-Plug-Ins implementiert.PV camera is implemented in both Windows Mixed Reality and OpenXR plugins. Für OpenXR muss allerdings das Microsoft OpenXR-Plug-In installiert sein.However OpenXR needs Microsoft OpenXR plugin to be installed. Außerdem besteht für OpenXR eine aktuelle Einschränkung, die Kamera kann mit DirectX11 RHI verwendet werden.Also OpenXR has current limitation, camera can work with DirectX11 RHI. Diese Einschränkung wird in einer kommenden Unreal-Version behoben.This limitation will be fixed in a further Unreal version.

  • Aktivieren Sie in Project Settings > HoloLens (Projekteinstellungen > HoloLens) die Webcam-Funktionalität:In Project Settings > HoloLens, enable the Webcam capability:

Screenshot der HoloLens-Projekteinstellungen mit hervorgehobener Webcam-Eigenschaft

  • Erstellen Sie einen neuen Akteur mit dem Namen „CamCapture“, und fügen Sie eine Ebene zum Rendern des Kamerafeeds hinzu:Create a new actor called “CamCapture” and add a plane to render the camera feed:

Screenshot des Akteurs mit einer hinzugefügten Ebene

  • Fügen Sie Ihrer Szene den Akteur hinzu, erstellen Sie ein neues Material mit dem Namen „CamTextureMaterial“ und einem Texture-Objektparameter sowie einem Texturbeispiel.Add the actor to your scene, create a new material called CamTextureMaterial with a Texture Object Parameter, and a texture sample. Senden Sie die RGB-Daten der Textur an die Ausgabe „Emissionsfarbe“:Send the texture’s rgb data to the output emissive color:

Blaupause eines Material- und Texturbeispiels

Rendern des FV-KamerafeedsRendering the PV Camera Feed

  • Schalten Sie in der CamCapture-Blaupause die FV-Kamera ein:In the CamCapture blueprint, turn on the PV Camera:

Blaupause der Funktion zum Umschalten von ARCapture mit eingeschalteter FV-Kamera

  • Erstellen Sie eine dynamische Materialinstanz aus „CamTextureMaterial“, und weisen Sie dieses Material der Ebene des Akteurs zu:Create a dynamic material instance from CamTextureMaterial and assign this material to the actor’s plane:

Blaupause der Funktion zum Erstellen einer dynamischen Materialinstanz

  • Rufen Sie die Textur aus dem Kamerafeed ab, und weisen Sie sie dem dynamischen Material zu, wenn sie gültig ist.Get the texture from the camera feed and assign it to the dynamic material if it's valid. Wenn die Textur nicht gültig ist, starten Sie einen Timer, und versuchen Sie es nach dessen Ablauf erneut:If the texture isn't valid, start a timer and try again after the timeout:

Blaupause der Kamerafeed-Textur, die dem dynamischen Material zugewiesen ist

  • Skalieren Sie abschließend die Ebene um das Seitenverhältnis des Kamerabilds:Finally, scale the plane by the camera image’s aspect ratio:

Blaupause der Ebene, die relativ zum Seitenverhältnis des Kamerabilds skaliert ist

Finden von Kamerapositionen im WeltbereichFind Camera Positions in World Space

Die Kamera in der HoloLens 2 ist gegenüber dem Head Tracking des Geräts vertikal versetzt.The camera on the HoloLens 2 is offset vertically from the device’s head tracking. Es gibt ein paar Funktionen, um die Position der Kamera im Weltbereich zu ermitteln, um diesem Versatz Rechnung zu tragen.A few functions exist to locate the camera in world space to account for the offset.

„GetPVCameraToWorldTransform“ ruft die Transformation der FV-Kamera im Weltbereich ab und wird auf der Kameralinse positioniert:GetPVCameraToWorldTransform gets the transform in world space of the PV Camera and will be positioned on the camera lens:

Blaupause der Funktion zum Abrufen der Transformation der FV-Kamera gegenüber dem Weltbereich

„GetWorldSpaceRayFromCameraPoint“ wirft einen Strahl aus dem Kameraobjektiv in die Szene im Weltbereich von Unreal, um den Inhalt eines Pixels im Kamerabild herauszufinden:GetWorldSpaceRayFromCameraPoint casts a ray from the camera lens into the scene in Unreal world space to find a pixel's content in the camera frame:

Blaupause des Strahls vom Kamerapunkt zum Abrufen des Weltbereichs

„GetPVCameraIntrinsics“ gibt die systeminternen Werte der Kamera zurück, die bei der Verarbeitung eines Kamerabilds beim maschinellen Sehen verwendet werden können:GetPVCameraIntrinsics returns the camera intrinsic values, which can be used when doing computer vision processing on a camera frame:

Blaupause der Funktionen zum Abrufen der systeminternen PVCamera-Werte

Um herauszufinden, was an einer bestimmten Pixelkoordinate im Weltbereich vorhanden ist, verwenden Sie eine Zeilenablaufverfolgung mit dem Weltbereichs-Strahl:To find what exists in world space at a particular pixel coordinate, use a line trace with the world space ray:

Blaupause des Weltbereich-Strahls, der verwendet wird, um zu ermitteln, was im Weltbereich an einer bestimmten Koordinate vorhanden ist

Hier werfen wir einen 2-m-Strahl vom Kameraobjektiv auf die Raumposition der Kamera, die ¼ vom oberen linken Punkt des Bilds entfernt ist.Here we cast a 2-meter ray from the camera lens to the camera-space position ¼ from the top left of the frame. Verwenden Sie dann das Trefferergebnis, um etwas an der Position zu rendern, an der das Objekt im Weltbereich vorhanden ist:Then use the hit result to render something where the object exists in world space:

Blaupause eines 2-m-Strahls, der vom Kameraobjektiv aus auf die Raumposition der Kamera geworfen wird, die 1/4 vom oberen linken Punkt des Bilds entfernt ist.

Wenn räumliche Abbildung verwendet wird, stimmt diese Trefferposition mit der Oberfläche überein, die von der Kamera gesehen wird.When using spatial mapping, this hit position will match the surface that the camera is seeing.

Rendern des FV-Kamerafeeds in C++Rendering the PV Camera Feed in C++

  • Erstellen Sie einen neuen C++-Akteur mit dem Namen „CamCapture“.Create a new C++ actor called CamCapture
  • Fügen Sie in der Datei „build.cs“ des Projekts „AugmentedReality“ zur Liste „PublicDependencyModuleNames“ hinzu:In the project’s build.cs, add “AugmentedReality” to the PublicDependencyModuleNames list:
PublicDependencyModuleNames.AddRange(
    new string[] {
        "Core",
        "CoreUObject",
        "Engine",
        "InputCore",
        "AugmentedReality"
});
  • Schließen Sie „ARBlueprintLibrary.h“ in „CamCapture.h“ einIn CamCapture.h, include ARBlueprintLibrary.h
#include "ARBlueprintLibrary.h"
  • Darüber hinaus müssen Sie lokale Variablen für das Gittermodell und das Material hinzufügen:You also need to add local variables for the mesh and material:
private:
    UStaticMesh* StaticMesh;
    UStaticMeshComponent* StaticMeshComponent;
    UMaterialInstanceDynamic* DynamicMaterial;
    bool IsTextureParamSet = false;
  • Aktualisieren Sie in „CamCapture.cpp“ den Konstruktor, um der Szene ein statisches Gittermodell hinzuzufügen:In CamCapture.cpp, update the constructor to add a static mesh to the scene:
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);
}

Erstellen Sie in „BeginPlay“ eine dynamische Materialinstanz aus dem Kameramaterial des Projekts, wenden Sie es auf die statische Gittermodellkomponente an, und starten Sie die HoloLens-Kamera.In BeginPlay create a dynamic material instance from the project’s camera material, apply it to the static mesh component, and start the HoloLens camera.

Klicken Sie im Editor mit der rechten Maustaste auf das „CamTextureMaterial“ im Inhaltsbrowser, und wählen Sie „COPY-Referenz“ aus, um die Zeichenfolge für „CameraMatPath“ abzurufen.In the editor, right-click on the CamTextureMaterial in the content browser and select “Copy Reference” to get the string for 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);
}

Rufen Sie in Tick die Textur bei der Kamera ab, legen Sie sie auf den Texturparameter im Material „CamTextureMaterial“ fest, und skalieren Sie die statische Gittermodellkomponente um das Seitenverhältnis des Kamerabilds:In Tick get the texture from the camera, set it to the texture parameter in the CamTextureMaterial material, and scale the static mesh component by the camera frame’s aspect ratio:

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ächster EntwicklungsprüfpunktNext Development Checkpoint

Wenn Sie der Unity-Entwicklungs-Journey folgen, die wir entworfen haben, befinden Sie sich mitten im Kennenlernen der Mixed Reality-Plattformfunktionen und APIs.If you're following the Unreal development journey we've laid out, you're in the midst of exploring the Mixed Reality platform capabilities and APIs. Von hier aus können Sie mit dem nächsten Thema fortfahren:From here, you can continue to the next topic:

Oder wechseln Sie direkt zur Bereitstellung Ihrer App auf einem Gerät oder Emulator:Or jump directly to deploying your app on a device or emulator:

Sie können jederzeit zu den Prüfpunkten für die Unreal-Entwicklung zurückkehren.You can always go back to the Unreal development checkpoints at any time.

Siehe auchSee also