Übersicht über das Scene Understanding SDK

Szenenverständnis transformiert die unstrukturierten Umgebungssensordaten, die Ihr Mixed Reality Gerät erfasst, und wandelt sie in eine leistungsstarke abstrakte Darstellung um. Das SDK fungiert als Kommunikationsebene zwischen Ihrer Anwendung und der Scene Understanding-Runtime. Ziel ist es, vorhandene Standardkonstrukte wie 3D-Szenendiagramme für 3D-Darstellungen und 2D-Rechtecke und Panels für 2D-Anwendungen nachzuahmen. Während die Konstrukte, die Scene Understanding nachahmt, konkreten Frameworks zugeordnet werden, ist SceneUnderstanding im Allgemeinen Framework-agnostisch, was die Interoperabilität zwischen verschiedenen Frameworks ermöglicht, die mit ihr interagieren. Bei der Weiterentwicklung von Scene Understanding besteht die Rolle des SDK darin, sicherzustellen, dass neue Darstellungen und Funktionen weiterhin innerhalb eines einheitlichen Frameworks verfügbar gemacht werden. In diesem Dokument werden zunächst allgemeine Konzepte vorgestellt, die Ihnen helfen, sich mit der Entwicklungsumgebung/-nutzung vertraut zu machen und dann ausführlichere Dokumentationen für bestimmte Klassen und Konstrukte bereitzustellen.

Wo erhalte ich das SDK?

Das SceneUnderstanding SDK kann über das Mixed Reality Featuretool heruntergeladen werden.

Hinweis: Die neueste Version hängt von Vorschaupaketen ab, und Sie müssen Vorabversionspakete aktivieren, um sie anzuzeigen.

Ab Version 0.5.2022-rc unterstützt Scene Understanding Sprachprojektionen für C# und C++, sodass Anwendungen Anwendungen für Win32- oder UWP-Plattformen entwickeln können. Ab dieser Version unterstützt SceneUnderstanding Unity-Unterstützung im Editor, wobei der SceneObserver ausschließlich für die Kommunikation mit HoloLens2 verwendet wird.

SceneUnderstanding erfordert Windows SDK Version 18362 oder höher.

Konzeptionelle Übersicht

Die Szene

Ihr Mixed Reality-Gerät integriert ständig Informationen darüber, was es in Ihrer Umgebung sieht. Scene Understanding trichtert alle diese Datenquellen und erzeugt eine einzelne zusammenhängende Abstraktion. Scene Understanding generiert Szenen, bei denen es sich um eine Komposition von SceneObjects handelt, die eine instance einer einzelnen Sache darstellen (z. B. eine Wand/Decke/einen Boden).) Szenenobjekte selbst sind eine Komposition von [SceneComponents, die differenziertere Teile darstellen, aus denen dieses SceneObject besteht. Beispiele für Komponenten sind Quads und Gitter, aber in der Zukunft könnten begrenzungsfelder, Kollisionsgitter, Metadaten usw. darstellen.

Der Prozess der Konvertierung der Rohdaten des Sensors in eine Szene ist ein potenziell teurer Vorgang, der für mittlere Räume (~10x10m) in Minuten für große Räume (~50x50m) dauern kann und daher nicht vom Gerät ohne Anwendungsanforderung berechnet wird. Stattdessen wird die Szenengenerierung bei Bedarf von Ihrer Anwendung ausgelöst. Die SceneObserver-Klasse verfügt über statische Methoden, mit denen sie eine Szene berechnen oder deserialisieren können, mit der Sie dann auflisten/interagieren können. Die Aktion "Compute" wird bei Bedarf ausgeführt und wird auf der CPU ausgeführt, jedoch in einem separaten Prozess (der Mixed Reality-Treiber). Während wir jedoch in einem anderen Prozess berechnen, werden die resultierenden Szenendaten in Ihrer Anwendung im Scene-Objekt gespeichert und verwaltet.

Im Folgenden finden Sie ein Diagramm, das diesen Prozessablauf veranschaulicht und Beispiele für zwei Anwendungen zeigt, die mit der Scene Understanding-Runtime interfacieren.

Prozessdiagramm

Auf der linken Seite befindet sich ein Diagramm der Mixed Reality-Runtime, die immer aktiv ist und in einem eigenen Prozess ausgeführt wird. Diese Runtime ist für die Durchführung der Gerätenachverfolgung, räumlichen Zuordnungen und anderer Vorgänge verantwortlich, die Scene Understanding verwendet, um die Welt um Sie herum zu verstehen und zu verstehen. Auf der rechten Seite des Diagramms zeigen wir zwei theoretische Anwendungen, die Scene Understanding verwenden. Die erste Anwendung schnittstellen mit MRTK, das intern das Scene Understanding SDK verwendet, die zweite App berechnet und verwendet zwei separate Szeneninstanzen. Alle drei Szenen in diesem Diagramm generieren unterschiedliche Instanzen der Szenen, der Treiber verfolgt nicht den globalen Zustand, der von Anwendungen gemeinsam genutzt wird, und Szenenobjekte in einer Szene werden in einer anderen nicht gefunden. Scene Understanding bietet zwar einen Mechanismus zum Nachverfolgen im Laufe der Zeit, aber dies geschieht mithilfe des SDK. Der Nachverfolgungscode wird bereits im SDK im Prozess Ihrer App ausgeführt.

Da jede Szene ihre Daten im Speicherplatz Ihrer Anwendung speichert, können Sie davon ausgehen, dass alle Funktionen des Scene-Objekts oder seiner internen Daten immer im Prozess Ihrer Anwendung ausgeführt werden.

Layout

Für die Arbeit mit Scene Understanding kann es nützlich sein, zu wissen, wie die Runtime Komponenten logisch und physisch darstellt. Die Szene stellt Daten mit einem bestimmten Layout dar, das als einfach ausgewählt wurde, während eine zugrunde liegende Struktur beibehalten wird, die für zukünftige Anforderungen geeignet ist, ohne dass größere Überarbeitungen erforderlich sind. Die Szene speichert dazu alle Komponenten (Bausteine für alle Szenenobjekte) in einer flachen Liste und definiert Hierarchie und Komposition durch Verweise, in denen bestimmte Komponenten auf andere verweisen.

Im Folgenden stellen wir ein Beispiel für eine Struktur in ihrer flachen und logischen Form dar.

Logisches LayoutPhysisches Layout
    Szene
    • SceneObject_1
      • SceneMesh_1
      • SceneQuad_1
      • SceneQuad_2
    • SceneObject_2
      • SceneQuad_1
      • SceneQuad_3
    • SceneObject_3
      • SceneMesh_3
  • SceneObject_1
  • SceneObject_2
  • SceneObject_3
  • SceneQuad_1
  • SceneQuad_2
  • SceneQuad_3
  • SceneMesh_1
  • SceneMesh_2

In dieser Abbildung wird der Unterschied zwischen dem physischen und logischen Layout der Szene hervorgehoben. Auf der linken Seite sehen Wir das hierarchische Layout der Daten, die Ihre Anwendung beim Auflisten der Szene sieht. Auf der rechten Seite sehen wir, dass die Szene aus 12 verschiedenen Komponenten besteht, die bei Bedarf einzeln zugänglich sind. Bei der Verarbeitung einer neuen Szene erwarten wir, dass Anwendungen diese Hierarchie logisch durchlaufen, aber bei der Nachverfolgung zwischen Szenenupdates sind einige Anwendungen möglicherweise nur daran interessiert, bestimmte Komponenten anzusprechen, die zwischen zwei Szenen gemeinsam genutzt werden.

API-Übersicht

Der folgende Abschnitt bietet eine allgemeine Übersicht über die Konstrukte in Scene Understanding. Wenn Sie diesen Abschnitt lesen, erfahren Sie, wie Szenen dargestellt werden und wofür die verschiedenen Komponenten dienen bzw. wofür sie verwendet werden. Der nächste Abschnitt enthält konkrete Codebeispiele und zusätzliche Details, die in dieser Übersicht erläutert werden.

Alle unten beschriebenen Typen befinden sich im Microsoft.MixedReality.SceneUnderstanding Namespace.

SceneComponents

Nachdem Sie nun das logische Layout von Szenen verstanden haben, können wir das Konzept von SceneComponents und deren Verwendung für die Erstellung von Hierarchien darstellen. SceneComponents sind die präzisesten Zerlegungen in SceneUnderstanding, die eine einzelne Kernsache darstellen, z. B. ein Gitter oder ein Quad oder ein umgebendes Feld. SceneComponents sind Dinge, die unabhängig aktualisiert werden können und von anderen SceneComponents referenziert werden können. Daher verfügen sie über eine einzelne globale Eigenschaft, eine eindeutige ID, die diese Art von Nachverfolgungs-/Verweismechanismus ermöglicht. IDs werden für die logische Zusammensetzung der Szenenhierarchie sowie für die Objektpersistenz (akt der Aktualisierung einer Szene relativ zu einer anderen) verwendet.

Wenn Sie jede neu berechnete Szene als unterschiedlich behandeln und einfach alle darin enthaltenen Daten auflisten, sind IDs für Sie weitgehend transparent. Wenn Sie jedoch planen, Komponenten über mehrere Updates nachzuverfolgen, verwenden Sie die IDs zum Indizieren und Suchen nach SceneComponents zwischen Scene-Objekten.

SceneObjects

Ein SceneObject ist ein SceneComponent, das eine instance eines "Dings" darstellt, z. B. eine Wand, einen Boden, eine Decke usw.... ausgedrückt durch ihre Kind-Eigenschaft. SceneObjects sind geometrisch und verfügen daher über Funktionen und Eigenschaften, die ihre Position im Raum darstellen, enthalten jedoch keine geometrische oder logische Struktur. Stattdessen verweisen SceneObjects auf andere SceneComponents, insbesondere Auf SceneQuads und SceneMeshes, die die verschiedenen Darstellungen bereitstellen, die vom System unterstützt werden. Wenn eine neue Szene berechnet wird, listet Ihre Anwendung höchstwahrscheinlich die SceneObjects der Szene auf, um zu verarbeiten, was sie interessiert.

SceneObjects kann über eine der folgenden Elemente verfügen:

SceneObjectKind BESCHREIBUNG
HintergrundDas SceneObject ist bekannt, dass es sich nicht um eine der anderen erkannten Arten von Szenenobjekten handelt. Diese Klasse sollte nicht mit Unbekannt verwechselt werden, wobei Hintergrund bekannt ist, dass es sich nicht um Wand/Boden/Decke usw. handelt. während unbekannt noch nicht kategorisiert ist.
WallEine physische Wand. Wände werden als unbewegliche Umweltstrukturen angenommen.
EtageBöden sind beliebige Oberflächen, auf denen man gehen kann. Hinweis: Treppen sind keine Stockwerke. Beachten Sie auch, dass Böden jede begehbare Oberfläche annehmen und daher keine explizite Annahme eines einzelnen Bodens besteht. Mehrstufige Strukturen, Rampen etc.... sollte alle als Boden klassifiziert werden.
CeilingDie obere Oberfläche eines Raums.
PlattformEine große flache Oberfläche, auf der Sie Hologramme platzieren können. Diese stellen in der Regel Tische, Arbeitsplatten und andere große horizontale Flächen dar.
WorldEine reservierte Bezeichnung für geometrische Daten, die von der Bezeichnung unabhängig ist. Das durch Festlegen des EnableWorldMesh-Updateflags generierte Gitter wird als welt klassifiziert.
UnknownDieses Szenenobjekt muss noch klassifiziert und einer Art zugewiesen werden. Dies sollte nicht mit Hintergrund verwechselt werden, da es sich bei diesem Objekt um ein beliebiges Objekt handeln könnte. Das System hat dafür noch keine ausreichend starke Klassifizierung gefunden.

SceneMesh

Ein SceneMesh ist ein SceneComponent, der die Geometrie beliebiger geometrischer Objekte mithilfe einer Dreiecksliste nähert. SceneMeshes werden in verschiedenen Kontexten verwendet. Sie können Komponenten der wasserdichten Zellstruktur oder als WorldMesh darstellen, die das der Szene zugeordnete ungebundene räumliche Zuordnungsgitter darstellt. Die index- und vertex-Daten, die für jedes Gitter bereitgestellt werden, verwenden das gleiche vertraute Layout wie die Vertex- und Indexpuffer , die zum Rendern von Dreiecksgittern in allen modernen Rendering-APIs verwendet werden. In Scene Understanding verwenden Gitter 32-Bit-Indizes und müssen möglicherweise für bestimmte Rendering-Engines in Blöcke unterteilt werden.

Wickelreihenfolge und Koordinatensysteme

Von allen Gittern, die von Scene Understanding erstellt werden, wird erwartet, dass sie Gitter in einem Right-Handed Koordinatensystem mit der Wicklungsreihenfolge im Uhrzeigersinn zurückgeben.

Hinweis: Betriebssystembuilds vor .191105 weisen möglicherweise einen bekannten Fehler auf, bei dem "World"-Gitter in Counter-Clockwise Wicklungsreihenfolge zurückgegeben wurden, was anschließend behoben wurde.

SceneQuad

Ein SceneQuad ist ein SceneComponent, der 2D-Oberflächen darstellt, die die 3D-Welt belegen. SceneQuads können ähnlich wie ARKit ARPlaneAnchor oder ARCore-Ebenen verwendet werden, aber sie bieten eine höhere Funktionalität als 2D-Leinwände, die von flachen Apps oder erweiterten UX verwendet werden können. 2D-spezifische APIs werden für Quads bereitgestellt, die die Platzierung und das Layout einfach zu verwenden machen, und die Entwicklung (mit Ausnahme des Renderns) mit Quads sollte eher dem Arbeiten mit 2D-Leinwänden als mit 3D-Gittern ähneln.

SceneQuad-Shape

SceneQuads definieren eine rechteckige Begrenzungsfläche in 2d. SceneQuads stellen jedoch Oberflächen mit beliebigen und potenziell komplexen Formen dar (z. B. eine Ringtabelle). Um die komplexe Form der Oberfläche eines Quads darzustellen, können Sie die GetSurfaceMask-API verwenden, um die Form der Oberfläche in einem von Ihnen bereitgestellten Bildpuffer zu rendern. Wenn das SceneObject mit dem Quad auch ein Gitter hat, sollten die Gitterdreiecke diesem gerenderten Bild entsprechen. Beide stellen die reale Geometrie der Oberfläche dar, entweder in 2d- oder 3D-Koordinaten.

Szenenverständnis: SDK-Details und Referenz

Hinweis

Wenn Sie MRTK verwenden, beachten Sie, dass Sie mit dem MRTK ['WindowsSceneUnderstandingObserver'](xref:Microsoft.MixedReality.Toolkit.WindowsSceneUnderstanding.Experimental.WindowsSceneUnderstandingObserver?view=mixed-reality-toolkit-unity-2020-dotnet-2.8.0&preserve-view=true) interagieren und daher diesen Abschnitt unter den meisten Umständen überspringen können. Weitere Informationen finden Sie in der Dokumentation [MRTK Scene Understanding](/windows/mixed-reality/mrtk-unity/features/spatial-awareness/scene-understanding).

Der folgende Abschnitt hilft Ihnen, sich mit den Grundlagen von SceneUnderstanding vertraut zu machen. In diesem Abschnitt sollten Die Grundlagen bereitgestellt werden. An diesem Punkt sollten Sie über genügend Kontext verfügen, um die Beispielanwendungen zu durchsuchen, um zu sehen, wie SceneUnderstanding ganzheitlich verwendet wird.

Initialisierung

Der erste Schritt bei der Arbeit mit SceneUnderstanding besteht darin, dass Ihre Anwendung verweise auf ein Scene-Objekt erhält. Dies kann auf zwei Arten erfolgen. Eine Szene kann entweder vom Treiber berechnet werden, oder eine vorhandene Szene, die in der Vergangenheit berechnet wurde, kann deserialisiert werden. Letzteres ist nützlich für die Arbeit mit SceneUnderstanding während der Entwicklung, bei der Anwendungen und Erfahrungen schnell ohne Mixed Reality-Gerät prototypisch erstellt werden können.

Szenen werden mithilfe eines SceneObservers berechnet. Vor dem Erstellen einer Szene sollte Ihre Anwendung Ihr Gerät abfragen, um sicherzustellen, dass Es SceneUnderstanding unterstützt, und um Benutzerzugriff auf Informationen anzufordern, die SceneUnderstanding benötigt.

if (!SceneObserver.IsSupported())
{
    // Handle the error
}

// This call should grant the access we need.
await SceneObserver.RequestAccessAsync();

Wenn RequestAccessAsync() nicht aufgerufen wird, schlägt das Berechnen einer neuen Szene fehl. Als Nächstes berechnen wir eine neue Szene, die um das Mixed Reality Headset herum verwurzelt ist und einen Radius von 10 Metern aufweist.

// Create Query settings for the scene update
SceneQuerySettings querySettings;

querySettings.EnableSceneObjectQuads = true;                                       // Requests that the scene updates quads.
querySettings.EnableSceneObjectMeshes = true;                                      // Requests that the scene updates watertight mesh data.
querySettings.EnableOnlyObservedSceneObjects = false;                              // Do not explicitly turn off quad inference.
querySettings.EnableWorldMesh = true;                                              // Requests a static version of the spatial mapping mesh.
querySettings.RequestedMeshLevelOfDetail = SceneMeshLevelOfDetail.Fine;            // Requests the finest LOD of the static spatial mapping mesh.

// Initialize a new Scene
Scene myScene = SceneObserver.ComputeAsync(querySettings, 10.0f).GetAwaiter().GetResult();

Initialisierung von Daten (auch bekannt als PC-Pfad)

Szenen können zwar für die direkte Nutzung berechnet werden, aber sie können zur späteren Verwendung auch in serialisierter Form berechnet werden. Dies hat sich als nützlich für die Entwicklung erwiesen, da Entwickler in Scene Understanding arbeiten und testen können, ohne dass ein Gerät erforderlich ist. Das Serialisieren einer Szene ist nahezu identisch mit dem Berechnen der Szene. Die Daten werden an Ihre Anwendung zurückgegeben, anstatt vom SDK lokal deserialisiert zu werden. Sie können es dann selbst deserialisieren oder für die zukünftige Verwendung speichern.

// Create Query settings for the scene update
SceneQuerySettings querySettings;

// Compute a scene but serialized as a byte array
SceneBuffer newSceneBuffer = SceneObserver.ComputeSerializedAsync(querySettings, 10.0f).GetAwaiter().GetResult();

// If we want to use it immediately we can de-serialize the scene ourselves
byte[] newSceneData = new byte[newSceneBuffer.Size];
newSceneBuffer.GetData(newSceneData);
Scene mySceneDeSerialized = Scene.Deserialize(newSceneData);

// Save newSceneData for later

SceneObject-Enumeration

Nachdem Ihre Anwendung nun über eine Szene verfügt, betrachtet Ihre Anwendung SceneObjects und interagiert mit ihnen. Dazu greifen Sie auf die SceneObjects-Eigenschaft zu:

SceneObject firstFloor = null;

// Find the first floor object
foreach (var sceneObject in myScene.SceneObjects)
{
    if (sceneObject.Kind == SceneObjectKind.Floor)
    {
        firstFloor = sceneObject;
        break;
    }
}

Komponentenupdate und -optimierung

Es gibt eine weitere Funktion, die Komponenten in der Szene mit dem Namen FindComponent abruft. Diese Funktion ist nützlich, wenn Sie Nachverfolgungsobjekte aktualisieren und in späteren Szenen suchen. Der folgende Code berechnet eine neue Szene relativ zu einer vorherigen Szene und findet dann den Boden in der neuen Szene.

// Compute a new scene, and tell the system that we want to compute relative to the previous scene
Scene myNextScene = SceneObserver.ComputeAsync(querySettings, 10.0f, myScene).GetAwaiter().GetResult();

// Use the Id for the floor we found last time, and find it again
firstFloor = (SceneObject)myNextScene.FindComponent(firstFloor.Id);

if (firstFloor != null)
{
    // We found it again, we can now update the transforms of all objects we attached to this floor transform
}

Zugreifen auf Gitter und Quader aus Szenenobjekten

Sobald SceneObjects gefunden wurden, möchte Ihre Anwendung höchstwahrscheinlich auf die Daten zugreifen, die in den Quads/Meshes enthalten sind, aus denen sie besteht. Auf diese Daten wird mit den Eigenschaften Quads und Meshes zugegriffen. Der folgende Code listet alle Quads und Gitternetze unseres Bodenobjekts auf.


// Get the transform for the SceneObject
System.Numerics.Matrix4x4 objectToSceneOrigin = firstFloor.GetLocationAsMatrix();

// Enumerate quads
foreach (var quad in firstFloor.Quads)
{
    // Process quads
}

// Enumerate meshes
foreach (var mesh in firstFloor.Meshes)
{
    // Process meshes
}

Beachten Sie, dass das SceneObject-Objekt über die Transformation verfügt, die relativ zum Szenenursprung ist. Dies liegt daran, dass das SceneObject eine instance eines "Dings" darstellt und im Raum erkennbar ist, die Quads und Gitter die Geometrie darstellen, die relativ zum übergeordneten Element transformiert wird. Es ist möglich, dass separate SceneObjects auf dieselben SceneMesh/SceneQuad SceneComponents verweisen, und es ist auch möglich, dass ein SceneObject über mehrere SceneMesh/SceneQuad verfügt.

Umgang mit Transformationen

Scene Understanding hat bewusst versucht, sich an herkömmlichen 3D-Szenendarstellungen auszurichten, wenn es um Transformationen geht. Jede Szene ist daher auf ein einzelnes Koordinatensystem beschränkt, ähnlich wie die meisten gängigen 3D-Umgebungsdarstellungen. SceneObjects geben jeweils ihre Position relativ zu diesem Koordinatensystem an. Wenn Ihre Anwendung mit Szenen zu tun hat, die die Grenze des einzelnen Ursprungs überschreiten, kann sie SceneObjects in SpatialAnchors verankern oder mehrere Szenen generieren und zusammenführen, aber der Einfachheit halber gehen wir davon aus, dass wasserdichte Szenen in ihrem eigenen Ursprung vorhanden sind, der durch eine NodeId lokalisiert wird, die durch Scene.OriginSpatialGraphNodeId definiert wird.

Der folgende Unity-Code zeigt beispielsweise, wie Sie Windows-Wahrnehmungs- und Unity-APIs verwenden, um Koordinatensysteme miteinander auszurichten. Ausführliche Informationen zu den Windows-Wahrnehmungs-APIs finden Sie unter SpatialCoordinateSystem und SpatialGraphInteropPreview und Mixed Reality nativen Objekten in Unity für Details zum Abrufen eines SpatialCoordinateSystem, das dem Weltursprung von Unity entspricht.

private System.Numerics.Matrix4x4? GetSceneToUnityTransformAsMatrix4x4(SceneUnderstanding.Scene scene)
{
    System.Numerics.Matrix4x4? sceneToUnityTransform = System.Numerics.Matrix4x4.Identity;

    
    Windows.Perception.Spatial.SpatialCoordinateSystem sceneCoordinateSystem = Microsoft.Windows.Perception.Spatial.Preview.SpatialGraphInteropPreview.CreateCoordinateSystemForNode(scene.OriginSpatialGraphNodeId);
    Windows.Perception.Spatial.SpatialCoordinateSystem unityCoordinateSystem = Microsoft.Windows.Perception.Spatial.SpatialCoordinateSystem.FromNativePtr(UnityEngine.XR.WindowsMR.WindowsMREnvironment.OriginSpatialCoordinateSystem);

    sceneToUnityTransform = sceneCoordinateSystem.TryGetTransformTo(unityCoordinateSystem);

    if (sceneToUnityTransform != null)
    {
        sceneToUnityTransform = ConvertRightHandedMatrix4x4ToLeftHanded(sceneToUnityTransform.Value);
    }
    else
    {
        return null;
    }
            
    return sceneToUnityTransform;
}

Jedes SceneObject verfügt über eine Transformation, die dann auf dieses Objekt angewendet wird. In Unity konvertieren wir in rechtshändige Koordinaten und weisen lokale Transformationen wie folgt zu:

private System.Numerics.Matrix4x4 ConvertRightHandedMatrix4x4ToLeftHanded(System.Numerics.Matrix4x4 matrix)
{
    matrix.M13 = -matrix.M13;
    matrix.M23 = -matrix.M23;
    matrix.M43 = -matrix.M43;

    matrix.M31 = -matrix.M31;
    matrix.M32 = -matrix.M32;
    matrix.M34 = -matrix.M34;

    return matrix;
}

 private void SetUnityTransformFromMatrix4x4(Transform targetTransform, System.Numerics.Matrix4x4 matrix, bool updateLocalTransformOnly = false)
 {
    if(targetTransform == null)
    {
        return;
    }

    Vector3 unityTranslation;
    Quaternion unityQuat;
    Vector3 unityScale;

    System.Numerics.Vector3 vector3;
    System.Numerics.Quaternion quaternion;
    System.Numerics.Vector3 scale;

    System.Numerics.Matrix4x4.Decompose(matrix, out scale, out quaternion, out vector3);

    unityTranslation = new Vector3(vector3.X, vector3.Y, vector3.Z);
    unityQuat        = new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
    unityScale       = new Vector3(scale.X, scale.Y, scale.Z);

    if(updateLocalTransformOnly)
    {
        targetTransform.localPosition = unityTranslation;
        targetTransform.localRotation = unityQuat;
    }
    else
    {
        targetTransform.SetPositionAndRotation(unityTranslation, unityQuat);
    }
}

// Assume we have an SU object called suObject and a unity equivalent unityObject

System.Numerics.Matrix4x4 converted4x4LocationMatrix = ConvertRightHandedMatrix4x4ToLeftHanded(suObject.GetLocationAsMatrix());
SetUnityTransformFromMatrix4x4(unityObject.transform, converted4x4LocationMatrix, true);
        

Viereck

Quads wurden entwickelt, um 2D-Platzierungsszenarien zu unterstützen und sollten als Erweiterungen für 2D-Canvas-UX-Elemente gedacht werden. Während Quads Komponenten von SceneObjects sind und in 3D gerendert werden können, gehen die Quad-APIs selbst davon aus, dass Quads 2D-Strukturen sind. Sie bieten Informationen wie Umfang, Form und STELLEN APIs für die Platzierung bereit.

Quads haben rechteckige Blöcke, aber sie stellen willkürlich geformte 2D-Oberflächen dar. Um die Platzierung auf diesen 2D-Oberflächen zu aktivieren, die mit den 3D-Umgebungs-Quads interagieren, bieten Hilfsprogramme, die diese Interaktion ermöglichen. Derzeit stellt Scene Understanding zwei solche Funktionen bereit: FindCentermostPlacement und GetSurfaceMask. FindCentermostPlacement ist eine allgemeine API, die eine Position auf dem Quad findet, an der ein Objekt platziert werden kann, und versucht, die beste Position für Ihr Objekt zu finden, um sicherzustellen, dass der von Ihnen bereitgestellte Begrenzungsrahmen auf der zugrunde liegenden Oberfläche verbleibt.

Hinweis

Die Koordinaten der Ausgabe sind relativ zum Quad in "Quad Space", wobei die obere linke Ecke (x = 0, y = 0) ist, genau wie bei anderen Rect-Typen von Fenstern. Achten Sie darauf, dass Sie dies berücksichtigen, wenn Sie mit den Ursprüngen Ihrer eigenen Objekte arbeiten.

Das folgende Beispiel zeigt, wie Sie die zentrierbare Position finden und ein Hologramm am Quad verankern.

// This code assumes you already have a "Root" object that attaches the Scene's Origin.

// Find the first quad
foreach (var sceneObject in myScene.SceneObjects)
{
    // Find a wall
    if (sceneObject.Kind == SceneObjectKind.Wall)
    {
        // Get the quad
        var quads = sceneObject.Quads;
        if (quads.Count > 0)
        {
            // Find a good location for a 1mx1m object  
            System.Numerics.Vector2 location;
            if (quads[0].FindCentermostPlacement(new System.Numerics.Vector2(1.0f, 1.0f), out location))
            {
                // We found one, anchor something to the transform
                // Step 1: Create a new game object for the quad itself as a child of the scene root
                // Step 2: Set the local transform from quads[0].Position and quads[0].Orientation
                // Step 3: Create your hologram and set it as a child of the quad's game object
                // Step 4: Set the hologram's local transform to a translation (location.x, location.y, 0)
            }
        }
    }
}

Die Schritte 1 bis 4 hängen stark von Ihrem jeweiligen Framework/Ihrer Implementierung ab, aber die Designs sollten ähnlich sein. Es ist wichtig zu beachten, dass quad einfach eine begrenzte 2D-Ebene darstellt, die im Raum lokalisiert ist. Indem Ihre Engine/Ihr Framework weiß, wo sich das Quad befindet, und Ihre Objekte relativ zum Quad verwurzelt, werden Ihre Hologramme im Hinblick auf die reale Welt korrekt lokalisiert.

Mesh

Gitter stellen geometrische Darstellungen von Objekten oder Umgebungen dar. Ähnlich wie bei der räumlichen Zuordnung verwenden Gitterindex- und Vertexdaten, die mit jedem räumlichen Oberflächengitter bereitgestellt werden, das gleiche vertraute Layout wie die Vertex- und Indexpuffer, die zum Rendern von Dreiecksgittern in allen modernen Rendering-APIs verwendet werden. Vertexpositionen werden im Koordinatensystem des Scenebereitgestellt. Die spezifischen APIs, die zum Verweisen auf diese Daten verwendet werden, lauten wie folgt:

void GetTriangleIndices(int[] indices);
void GetVertices(System.Numerics.Vector3[] vertices);

Der folgende Code enthält ein Beispiel für das Generieren einer Dreiecksliste aus der Gitterstruktur:

uint[] indices = new uint[mesh.TriangleIndexCount];
System.Numerics.Vector3[] positions = new System.Numerics.Vector3[mesh.VertexCount];

mesh.GetTriangleIndices(indices);
mesh.GetVertexPositions(positions);

Die Index-/Vertexpuffer müssen = die Index-/Scheitelpunktanzahl sein >, können aber andernfalls beliebig groß sein, um eine effiziente Speicherwiederverwendung zu ermöglichen.

ColliderMesh

Szenenobjekte bieten über die Eigenschaften Meshes und ColliderMeshes Zugriff auf Mesh- und ColliderMeshes-Daten. Diese Gitter entsprechen immer, was bedeutet, dass der i'ten Index der Meshes-Eigenschaft die gleiche Geometrie wie der i'ten Index der ColliderMeshes-Eigenschaft darstellt. Wenn die Laufzeit/das Objekt Collider-Gitter unterstützt, erhalten Sie garantiert das niedrigste Polygon und die höchste Reihenfolge näherung, und es empfiehlt sich, ColliderMeshes überall dort zu verwenden, wo Ihre Anwendung Colliders verwenden würde. Wenn das System keine Collider unterstützt, ist das in ColliderMeshes zurückgegebene Mesh-Objekt dasselbe Objekt wie das Gitter, das Speichereinschränkungen reduziert.

Entwickeln mit Szenenverständnis

An diesem Punkt sollten Sie die wichtigsten Bausteine der Scene Understanding Runtime und des SDK kennen. Der Großteil der Leistungsfähigkeit und Komplexität liegt in Zugriffsmustern, interaktion mit 3D-Frameworks und Tools, die auf diesen APIs geschrieben werden können, um komplexere Aufgaben wie Raumplanung, Raumanalyse, Navigation, Physik usw. auszuführen. Wir hoffen, diese in Beispielen zu erfassen, die Sie hoffentlich in die richtige Richtung leiten sollten, um Ihre Szenarien zum Leuchten zu bringen. Wenn es Beispiele oder Szenarien gibt, auf die wir nicht eingehen, teilen Sie uns dies mit, und wir versuchen, die benötigten Beispiele zu dokumentieren bzw. einen Prototyp zu erstellen.

Wo erhalte ich Beispielcode?

Scene Understanding-Beispielcode für Unity finden Sie auf unserer Unity-Beispielseite . Mit dieser Anwendung können Sie mit Ihrem Gerät kommunizieren und die verschiedenen Szenenobjekte rendern, oder sie ermöglicht es Ihnen, eine serialisierte Szene auf Ihren PC zu laden und Scene Understanding ohne Gerät zu erleben.

Wo kann ich Beispielszenen abrufen?

Wenn Sie über eine HoloLens2-Instanz verfügen, können Sie jede szene speichern, die Sie aufgenommen haben, indem Sie die Ausgabe von ComputeSerializedAsync speichern, um sie nach Belieben zu deserialisieren.

Wenn Sie kein HoloLens2-Gerät besitzen, aber mit Scene Understanding spielen möchten, müssen Sie eine vorab aufgezeichnete Szene herunterladen. Das Scene Understanding-Beispiel wird derzeit mit serialisierten Szenen ausgeliefert, die nach Belieben heruntergeladen und verwendet werden können. Sie finden sie hier:

Szenenverständnis - Beispielszenen

Siehe auch