HoloLens-Foto-/Videokamera 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.
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.
Setup des FV-Kamerafeeds
Wichtig
Die FV-Kamera ist sowohl in Windows Mixed Reality- als auch in OpenXR-Plug-Ins implementiert. Für OpenXR muss allerdings das Microsoft OpenXR-Plug-In installiert sein. Außerdem gilt für OpenXR für Unreal 4.26 eine Einschränkung: Die Kamera kann mit DirectX11 RHI funktionieren. Diese Einschränkung wurde in Unreal 4.27.1 oder höher behoben.
- Aktivieren Sie in Project Settings > HoloLens (Projekteinstellungen > HoloLens) die Webcam-Funktionalität:
- Erstellen Sie einen neuen Akteur mit dem Namen „CamCapture“, und fügen Sie eine Ebene zum Rendern des Kamerafeeds hinzu:
- Fügen Sie Ihrer Szene den Akteur hinzu, erstellen Sie ein neues Material mit dem Namen „CamTextureMaterial“ und einem Texture-Objektparameter sowie einem Texturbeispiel. Senden Sie die RGB-Daten der Textur an die Ausgabe „Emissionsfarbe“:
Rendern des FV-Kamerafeeds
- Schalten Sie in der CamCapture-Blaupause die FV-Kamera ein:
- Erstellen Sie eine dynamische Materialinstanz aus „CamTextureMaterial“, und weisen Sie dieses Material der Ebene des Akteurs zu:
- Rufen Sie die Textur aus dem Kamerafeed ab, und weisen Sie sie dem dynamischen Material zu, wenn sie gültig ist. Wenn die Textur nicht gültig ist, starten Sie einen Timer, und versuchen Sie es nach dessen Ablauf erneut:
- Skalieren Sie abschließend die Ebene um das Seitenverhältnis des Kamerabilds:
Finden von Kamerapositionen im Weltbereich
Die Kamera in der HoloLens 2 ist gegenüber dem Head Tracking des Geräts vertikal versetzt. Es gibt ein paar Funktionen, um die Position der Kamera im Weltbereich zu ermitteln, um diesem Versatz Rechnung zu tragen.
„GetPVCameraToWorldTransform“ ruft die Transformation der FV-Kamera im Weltbereich ab und wird auf der Kameralinse positioniert:
„GetWorldSpaceRayFromCameraPoint“ wirft einen Strahl aus dem Kameraobjektiv in die Szene im Weltbereich von Unreal, um den Inhalt eines Pixels im Kamerabild herauszufinden:
„GetPVCameraIntrinsics“ gibt die systeminternen Werte der Kamera zurück, die bei der Verarbeitung eines Kamerabilds beim maschinellen Sehen verwendet werden können:
Um herauszufinden, was an einer bestimmten Pixelkoordinate im Weltbereich vorhanden ist, verwenden Sie eine Zeilenablaufverfolgung mit dem Weltbereichs-Strahl:
Hier werfen wir einen 2-m-Strahl vom Kameraobjektiv auf die Raumposition der Kamera, die ¼ vom oberen linken Punkt des Bilds entfernt ist. Verwenden Sie dann das Trefferergebnis, um etwas an der Position zu rendern, an der das Objekt im Weltbereich vorhanden ist:
Wenn räumliche Abbildung verwendet wird, stimmt diese Trefferposition mit der Oberfläche überein, die von der Kamera gesehen wird.
Rendern des FV-Kamerafeeds in C++
- Erstellen Sie einen neuen C++-Akteur mit dem Namen „CamCapture“.
- Fügen Sie in der Datei „build.cs“ des Projekts „AugmentedReality“ zur Liste „PublicDependencyModuleNames“ hinzu:
PublicDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore",
"AugmentedReality"
});
- Schließen Sie „ARBlueprintLibrary.h“ in „CamCapture.h“ ein
#include "ARBlueprintLibrary.h"
- Darüber hinaus müssen Sie lokale Variablen für das Gittermodell und das Material hinzufügen:
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:
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.
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.
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:
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üfpunkt
Wenn Sie der Unity-Entwicklungs-Journey folgen, die wir entworfen haben, befinden Sie sich mitten im Kennenlernen der Mixed Reality-Plattformfunktionen und APIs. Von hier aus können Sie mit dem nächsten Thema fortfahren:
Oder wechseln Sie direkt zur Bereitstellung Ihrer App auf einem Gerät oder Emulator:
Sie können jederzeit zu den Prüfpunkten für die Unreal-Entwicklung zurückkehren.