Dynamische Bildrate in Unity

8

Ich entwickle ein auf Unity basierendes 3D-Visualisierungstool für WebGL. Der Benutzer interagiert selten mit der 3D-Szene und wenn er dies tut, geht es nur darum, die Kamera wie das Drehen oder Zoomen der Ansicht anzupassen. Ich habe vSync ( QualitySettings.vSyncCount) deaktiviert und die Bildrate auf 30 ( Application.targetFrameRate) gesperrt , um die CPU-Auslastung mindestens ein wenig zu reduzieren, während die Benutzer beim Bewegen der Kamera immer noch eine akzeptable Reaktionsfähigkeit aufweisen. Mit 30 fps bekomme ich eine CPU-Auslastung von ca. 30%. In Anbetracht der Hardware der unteren Preisklasse scheint dies immer noch zu hoch zu sein.

Um die CPU-Auslastung weiter zu verringern, habe ich zwei "Modi" eingeführt:

  • Interaktiv: Läuft mit 30 fps
  • Leerlauf: Läuft mit 10 fps

Ich habe einige Codezeilen geschrieben, um je nach Benutzerinteraktion zwischen diesen Modi zu wechseln. Wenn also eine Eingabe erkannt wird, verwendet die Anwendung mehr fps und nach einer bestimmten Zeit ohne Interaktion verwendet die Anwendung wieder weniger fps. Bisher funktioniert es ziemlich gut: Die App verwendet 30% im interaktiven Modus und 8% bis 10% der CPU im Leerlaufmodus.

Wenn Sie die Leerlaufbildrate auf 1 setzen, wird die CPU-Auslastung im Leerlaufmodus auf 1,5% reduziert. Das ist wirklich toll. Aber wie erwartet gibt es ein Problem. Grundsätzlich habe ich alle Update()Methoden gesperrt, die nur einmal pro Sekunde aufgerufen werden sollen. Wenn der Benutzer mit der Kamera interagiert, wird das Ereignis mit einer erwarteten Verzögerung von etwa einer Sekunde verarbeitet.

Nun die Frage: Wie kann ich Benutzereingaben sofort erkennen, während die Anwendung mit einer niedrigen Bildrate ausgeführt wird, und auch sofort eine neue Bildrate (z. B. 30) ohne merkliche Verzögerung anwenden?

Ursprünglich wollte ich eine Art On-Demand-Rendering haben. Ich habe einige Beiträge darüber gelesen, wie Benutzer eine Textur rendern, um die Renderkosten in weniger interaktiven Szenen zu senken. Das dynamische Einstellen der Bildrate scheint meiner Meinung nach eine sauberere Lösung zu sein. Ich habe auch versucht, mit dieser FixedUpdate()Methode nach Eingaben zu suchen und in den interaktiven Modus zu wechseln, aber das hat auch nicht funktioniert.

Hinweis Erwähnenswert ist auch, dass dieser Ansatz Fehler im Browser erzeugt, die darauf hinweisen, dass die Framerate der Anwendung 0 sein sollte (nicht in Bezug auf die Zielframerate von Unity, sondern wie in "Lassen Sie den Browser die Framerate verarbeiten" ). Obwohl dies eine andere Frage sein könnte, bezieht sie sich immer noch auf dieses Thema. Vielleicht hat auch jemand eine Antwort darauf!


Bearbeiten 1

Wie in den Kommentaren unten erwähnt, stellt Unity die Rückrufe bereit MonoBehaviour.OnApplicationPauseund MonoBehaviour.OnApplicationFocuserkennt, ob die Anwendung den Fokus erhalten oder verlieren wird.

Das Problem ist jedoch folgendes: Meine Anwendung verliert fast nie den Fokus. Dies ist zwar eine nette zusätzliche Optimierung, aber es hilft mir nicht wirklich viel. Mein Problem ist, dass die App die meiste Zeit im Leerlauf ist und gleichzeitig den Fokus hat. Es ist wirklich nur der Benutzer, der die meiste Zeit am Fenster starrt.

Nur um etwas mehr Sinn zu machen: Ich ziele auf WebGL ab. Der einzige Zweck von Unity besteht darin, einige Dinge zu visualisieren, während der Benutzer hauptsächlich mit einigen HTML-Steuerelementen interagiert. Im seltenen Fall , dass er mit der 3D - Szene zu interagieren will, möchte ich die Framerate einstellen sagen 30. Die Idee ist , „Ich weiß nicht , die Szene neu rendern zu oft so lange , wie Sie dies nicht tun interact“ .

Hervorheben: In meinem relevantesten Anwendungsfall verliert die Anwendung nie den Fokus. Dies bedeutet, dass der einzige zuverlässige Indikator, der bestimmt, wann zwischen Bildratenprofilen gewechselt werden muss, auf Benutzereingaben basiert.

Tut mir leid, wenn mir das nicht klar war :)


Bearbeiten 2

Ich habe dieses Thema auf der Unity-Feedback-Seite veröffentlicht . Wenn Sie interessiert sind, probieren Sie es aus und hinterlassen Sie eine Stimme. Vielleicht erhält diese Anfrage genug Aufmerksamkeit, um von den Unity-Entwicklern unterstützt zu werden.

qCring
quelle
1
Sie können Ihren Update-Code einfach in einen App-Fokus einschließen, wenn blockiert. Gibt es einen Grund, Ihren Update-Code auszuführen, wenn Ihre App keinen Fokus hat? docs.unity3d.com/ScriptReference/…
John Hamilton
1
@ JohnHamilton Danke für deinen Rat! Das ist eine weitere Optimierung, die es wert ist, implementiert zu werden. Ich gehe jedoch davon aus, dass die Anwendung die meiste Zeit konzentriert bleibt. Daher bin ich hauptsächlich daran interessiert, die CPU-Arbeitslast zu minimieren, während die App ausgeführt wird.
qCring
Verwenden Sie einfach eine Pause bei Fokusverlust und setzen Sie den Fokus fort, sollte relativ einfach zu implementieren sein. Veröffentlichen Sie hier Ihre Art der Implementierung dieser Funktion (als Antwort), damit sie in Zukunft von Nutzen sein kann :)
John Hamilton

Antworten:

7

Ich denke, Render to Texture ist immer noch die beste Wahl. Wenn Sie einen "Screenshot" von dem gemacht haben, was die Kamera sieht, und nur diese Textur anzeigen, sollten die Renderkosten selbst bei 30 Bildern pro Sekunde günstig sein.

user3362964
quelle
Vielen Dank, ich werde es versuchen, wenn ich sicher bin, dass das dynamische Anpassen der Bildrate zu einer Sackgasse führt. Aber vielleicht hast du recht. Dieser Ansatz tauchte in vielen Foren auf, so dass es der richtige Weg zu sein scheint.
qCring
1

Also dachte ich darüber nach, was wäre, wenn Sie die Kamera einfach daran hindern würden, erneut zu rendern (ohne die Kamera zu deaktivieren), wenn der Benutzer stationär ist? Auf diese Weise können Sie die UpdateFunktion immer noch häufig aufrufen, sodass die Benutzereingaben weiterhin reagieren, das Gerät jedoch keinen hohen Ressourcenverbrauch aufweist. Nach einer kurzen Suche fand ich dies . Ich habe es noch nicht ausprobiert, es ist nur eine Idee, die Sie ausprobieren könnten.

Sturmmuller
quelle