Babylon Native in einer kopflosen Umgebung

Dec 08 2022
Wenn wir Rendering sagen, sprechen wir oft über das Rendern mit 60 fps für eine Anwendung, egal ob es sich um ein Spiel oder eine andere Anwendung handelt, die die GPU nutzt. Es gibt jedoch andere Szenarien, in denen wir die GPU verwenden möchten, um Prozesse auszuführen, die überhaupt nichts anzeigen, z. B. das Verarbeiten eines Videos, das Manipulieren von Bildern oder das Rendern von 3D-Assets, die möglicherweise alle auf einem Server ausgeführt werden.

Wenn wir Rendering sagen, sprechen wir oft über das Rendern mit 60 fps für eine Anwendung, egal ob es sich um ein Spiel oder eine andere Anwendung handelt, die die GPU nutzt. Es gibt jedoch andere Szenarien, in denen wir die GPU verwenden möchten, um Prozesse auszuführen, die überhaupt nichts anzeigen, z. B. das Verarbeiten eines Videos, das Manipulieren von Bildern oder das Rendern von 3D-Assets, die möglicherweise alle auf einem Server ausgeführt werden. In diesem Artikel werde ich beschreiben, wie solche Szenarien mit Babylon Native erreicht werden können. Insbesondere werde ich ein Beispiel zeigen, wie wir Babylon Native verwenden können, um Screenshots von 3D-Assets mit DirectX 11 unter Windows aufzunehmen.

Wenn Sie noch nicht einige unserer anderen Geschichten über Babylon Native gelesen haben , insbesondere wenn Sie noch nie zuvor von Babylon Native gehört haben, lohnt es sich möglicherweise, sie zu lesen, um einen Kontext zu erhalten, bevor Sie fortfahren.

Haftungsausschluss: Die in diesem Beispiel verwendeten API-Verträge können sich ändern, da das Kernteam noch an der richtigen Form des API-Vertrags arbeitet.

ConsoleApp

Das Beispiel-Repo befindet sich hier . Es verwendet CMake, um Visual Studio-Projekte für Windows zu generieren. Babylon Native- und DirectXTK- Abhängigkeiten werden über Submodule eingebunden und in CMake verwendet. Die DirectXTK-Abhängigkeit wird nur verwendet, um eine DirectX-Textur in einer PNG-Datei zu speichern. Das Kernstück der Anwendung ist eine Datei namens App.cpp plus das JavaScript-Gegenstück in index.js . Lassen Sie uns in einige Details eintauchen, beginnend mit der nativen Seite.

Das Grafikgerät

Zuerst müssen wir ein eigenständiges DirectX-Gerät erstellen.

Dieser Code ist nichts Ungewöhnliches, kann aber so angepasst werden , dass er beispielsweise WARP verwendet , wenn die Umgebung keine GPU hat.

Als Nächstes erstellen wir mit diesem DirectX-Gerät ein Babylon Native-Grafikgerät.

Wir müssen die Breite und Höhe (in diesem Beispiel 1024 x 1024) angeben, da das Babylon Native-Gerät nicht mit einem Fenster oder einer Ansicht verknüpft ist, wie es normalerweise der Fall ist.

Der JavaScript-Host

Und natürlich müssen wir auch die JavaScript-Hostumgebung erstellen, in diesem Fall mit Chakra (der Standardeinstellung für Windows), um die Kern- und Lademodule von Babylon.js sowie die zuvor erwähnte index.js zu laden, in der sich die JavaScript-Logik befindet . Danach beginnen wir auch mit dem Rendern eines Frames, der das JavaScript von der Warteschlange für Grafikbefehle entsperrt.

Die Verwendung von Chakra ist mit Visual Studio praktisch, da wir debugger;an beliebiger Stelle im JavaScript-Code eine Anweisung hinzufügen können und der Just-In-Time-Debugger von Visual Studio mit einem Dialogfeld zum Debuggen des JavaScripts auffordert. Beachten Sie, dass die Anwendung in der Debug-Konfiguration ausgeführt werden muss, damit dies funktioniert.

Die Ausgabetextur

Wir müssen auch eine Ausgabe-Renderzieltextur für outputRenderTargetdie Babylon.js-Kamera erstellen. Zuerst erstellen wir eine DirectX-Renderzieltextur.

Dann setzen wir die native Textur über ein Babylon Native-Plugin namens ExternalTexture.

Beachten Sie, dass wir, da dies keine normale Rendering-Anwendung ist, explizit einzelne Frames rendern und daher ( std::promisein diesem Fall) auch Synchronisationskonstrukte benötigen, um die richtige Reihenfolge sicherzustellen. Wie in der Dokumentation für ExternalTexture erwähnt , ExternalTexture::AddToContextAsyncerfordert die Funktion, dass das Grafikgerät einen Frame rendert, bevor sie abgeschlossen ist. Die addToContextZukunft wird warten, bis AddToContextAsyncsie aufgerufen FinishRenderingCurrentFramewird, und einen Rahmen rendern, damit AddToContextAsyncsie beendet werden kann.

Das JavaScript (Teil 1)

Als Nächstes sehen wir uns den ersten Teil ( startup) der JavaScript-Seite an. Diese Funktion ignoriert die typische Babylon.js-Engine und das Szenen-Setup und nimmt ein Argument namens an nativeTexture, das die Textur aus dem Ergebnis von ist AddToContextAsync. Dieses Argument wird dann wrapNativeTextureumschlossen und als Farbanhang einer Renderzieltextur von Babylon.js hinzugefügt. Wir werden sehen, wie dies in Kürze verwendet wird.

Die glTF-Assets

Zurück zur nativen Seite sind wir jetzt bereit, die glTF-Assets zu laden und Screenshots aufzunehmen.

Das mag lang aussehen, ist aber nicht zu kompliziert. Wir durchlaufen jedes Asset in einer Schleife und rufen die JavaScript-Funktion loadAndRenderAssetAsyncauf, warten darauf, dass sie abgeschlossen ist, und speichern ein PNG auf der Festplatte.

Das JavaScript (Teil 2)

Die loadAndRenderAssetAsyncFunktion auf der JavaScript-Seite importiert das glTF-Asset, richtet eine Kamera ein, wartet darauf, dass die Szene fertig ist, und rendert einen einzelnen Frame. Dies sollte ähnlich aussehen wie bei einer Webanwendung, die Babylon.js verwendet!

Dem Ausgabe-Renderziel der Kamera wird die Ausgabe-Renderzieltextur von früher zugewiesen, sodass die Szene in diese Ausgabetextur gerendert wird, anstatt in den standardmäßigen Hintergrundpuffer, der in diesem Zusammenhang natürlich nicht vorhanden ist. Dies wiederum rendert direkt in die native DirectX-Renderzieltextur, die wir zuvor eingerichtet haben.

Das Ergebnis

Das Erstellen und Ausführen des ConsoleApp-Beispiels sieht folgendermaßen aus.

Zusammen mit drei PNG-Dateien.

Das RenderDoc

Es gibt noch eine Sache! Beachten Sie die Hilfsfunktionsaufrufe an RenderDoc::StartFrameCaptureund RenderDoc::StopFrameCapture? Diese weisen RenderDoc an, die Aufnahme eines Frames zu starten und zu stoppen, da RenderDoc nicht weiß, wann ein Frame beginnt oder endet, da wir uns nicht im typischen Rendering-Fall befinden. Wir können die RenderDoc-Erfassung aktivieren, indem wir eine Zeile in auskommentieren RenderDoc.h. Die Verwendung von RenderDoc ist unglaublich nützlich, um Probleme mit der GPU zu debuggen.

Fazit

Ich hoffe, dies gibt Ihnen eine Vorstellung davon, wie Babylon Native in einer kopflosen Umgebung verwendet werden kann. Es ist kein typisches Szenario, aber es ist ein Szenario, das mit anderen Technologien schwieriger oder teurer zu erreichen ist. Wir werden uns weiterhin bemühen, Babylon Native in so vielen Szenarien wie möglich nützlich zu machen.

Gary Hsu – Teamleiter der Babylonischen Eingeborenen