Ich schreibe einen Minecraft-Mod, der Eingaben von der Razer Hydra unterstützt . Es handelt sich um ein Paar Bewegungssteuerungen (eine für jede Hand), die unglaublich genaue Positions- und Rotationsinformationen liefern.
Für die Zwecke dieser Frage bewirkt das Drehen des rechten Controllers auf der Y-Achse, dass der Charakter des Spielers nach links oder rechts schaut (Gieren), und das Drehen auf der X-Achse lässt den Spieler nach oben und unten schauen (Tonhöhe).
Die Eingabe vom Controller wird direkt der Überschrift des Charakters zugeordnet. Wenn der Controller um 30 Grad nach links gedreht wird, dreht sich das Zeichen um 30 Grad nach links.
Das Problem ist, dass der Eingang "zittert". Wenn ich versuche, den Controller perfekt ruhig zu halten, bewegt sich die Überschrift des Charakters unregelmäßig innerhalb eines sehr kleinen Kegels (vielleicht 1 Grad).
Dies liegt wahrscheinlich an meinen zitternden Händen, da die Daten des Controllers scheinbar genau sind.
Ich habe versucht, Eingaben zu filtern, indem ich Daten aus den letzten X-Frames gemittelt habe, aber dies lässt Eingaben butterartig erscheinen.
Meine Frage ist: Wie kann ich die Rotationsdaten filtern, um Jitter zu entfernen, ohne an Präzision zu verlieren?
Antworten:
Dieses Problem zwischen Verzögerung und Reaktionsfähigkeit tritt bei praktisch allen Motion Controllern auf, egal ob es sich um die Hydra, die Wii-Fernbedienung, den Kinect oder den PlayStation Move handelt.
Das Problem ist folgendes:
Wenn ein Eingabestream eingeht, entscheiden Sie Frame für Frame, ob Sie den Eingabedaten vertrauen möchten oder nicht. ob sich die Trends, die Sie jetzt sehen, in den Daten fortgesetzt haben, die Sie in einem Dutzend Millisekunden erhalten. Wenn sich dieser Frame plötzlich nach rechts verschiebt, wissen Sie nicht, ob es sich um echte Eingabedaten handelt (und Sie sollten darauf reagieren) oder ob es sich lediglich um Jitter handelt (und Sie sollten ihn daher ignorieren). Unabhängig davon, was Sie auswählen, wenn Sie später feststellen, dass Sie sich geirrt haben, haben Sie entweder dem Eingabe-Jitter erlaubt, es in Ihr Spiel zu schaffen (im ersten Fall), oder Sie haben eine Verzögerung in Ihr Spiel eingeführt (im letzteren Fall).
Dafür gibt es keine gute Lösung. Eine "richtige" Lösung, um festzustellen, ob die Eingabe real oder jitter ist, erfordert das Wissen darüber, was der Eingabestream in Zukunft tun wird und was er in der Vergangenheit getan hat. Wir können das in Spielen aus offensichtlichen Gründen nicht tun. Nein, es gibt keine Möglichkeit, Rotationsdaten zu filtern, um Jitter zu entfernen, ohne an Präzision zu verlieren, im Kontext eines Spiels, das mit Eingabedaten in Echtzeit arbeitet.
Ich habe gesehen, dass ein großer Hersteller den Entwicklern empfohlen hat, dieses Problem zu lösen, indem die Spieler beim Drehen des Steuerelements eine Taste gedrückt halten, damit das Spiel an diesem Punkt seinen Anti-Jitter-Code ausschalten kann, sodass es nicht verzögert wird. (Ich empfehle dies nicht, aber es ist ein Ansatz).
Ich habe einige Middleware-Bibliotheken für Bewegungseingaben gesehen, die dieses Problem lösen, indem sie eine künstliche Verzögerung in der Eingabe einführen. Es gibt einen Viertelsekundenpuffer, in den die Eingabedaten eingehen, und Ihr Spiel hört erst eine Viertelsekunde später von der Eingabe. Damit die Bibliothek den Jitter für Sie ausgleichen kann, indem Sie wissen, was aus Sicht des Spiels sowohl vor als auch nach der "Gegenwart" passiert. Das funktioniert großartig, abgesehen von einer Viertelsekunde Verzögerung für alles. Aber es ist eine Möglichkeit, das Problem zu lösen, und es kann eine großartige Arbeit leisten, eine Bewegung mit entferntem Jitter auf Kosten einer konstanten Verzögerung genau darzustellen.
Aber ohne so extrem zu werden, gibt es noch einige Dinge, die wir tun können, um das Verhalten erheblich zu verbessern, obwohl wir wissen, dass es immer "Worst-Case-Szenarien" geben wird, die sich nicht ideal verhalten.
Die zentrale Erkenntnis ist, dass wir uns nur dann wirklich um Jitter kümmern, wenn der Controller größtenteils stationär ist, und dass wir uns nur wirklich um Verzögerungen kümmern, wenn der Controller bewegt wird. Daher sollte unsere Strategie darin bestehen, zu versuchen, mit den Dingen so umzugehen, dass wir eine Verzögerung haben, wenn der Controller stationär ist, und Jitter haben, wenn der Controller in Bewegung ist.
Hier sind zwei Möglichkeiten, dies zu tun:
Ein gängiger Ansatz ist ein "gesperrtes / entsperrtes" System, bei dem Sie die Ausrichtung des Geräts verfolgen. Wenn sich das Gerät für kurze Zeit (etwa eine halbe Sekunde) nicht ändert, "sperren" Sie diese Ausrichtung, indem Sie "Nein" verwenden Aktion basierend auf der vom Gerät gemeldeten Ausrichtung, bis sie sich so weit unterscheidet, dass sie erneut entsperrt werden kann. Dies kann orientierungsbasierten Jitter vollständig unterdrücken, ohne eine Verzögerung einzuführen, wenn sich die Ausrichtung aktiv ändert. Es kann einen Hinweis auf eine Verzögerung geben, bevor der Code entscheidet, dass er in den "entsperrten" Modus wechseln muss, aber es ist viel besser, als überall eine Verzögerung zu haben.
Ein anderer Ansatz besteht darin, Eingabedaten aus Frames zusammen zu mitteln. Der wichtige Punkt hierbei ist, nur die Eingabedaten aus Frames zu mitteln, in denen die Eingabedaten vage ähnlich waren. Dies bedeutete, dass kleine Jitter zusammen verschwimmen und weicher werden, größere Änderungen jedoch nicht unscharf werden, da ihre Daten nicht verschwimmen ähnlich genug zu den Daten aus vorherigen Frames.
Es gibt auch andere Möglichkeiten, einen ähnlichen Effekt zu erzielen. Die zentrale Erkenntnis ist, dass Sie nicht gleichzeitig Jitter und Lag in Ihrem Echtzeitspiel haben können, da dies Kenntnisse über die Zukunft erfordern würde. Sie müssen also auswählen, wann das Verhalten Ihres Steuerelements auf das Akzeptieren von Jitter und wann auf das Akzeptieren von Verzögerungen ausgerichtet werden soll, um das Gesamterlebnis so schlecht wie möglich zu gestalten.
quelle
Ich entwickle Software, die Bewegungseingaben in reaktionsschnelle und präzise Mauseingaben umwandelt, und pflege eine Website, die Entwicklern hilft, gleich gute Lösungen selbst zu implementieren. Ich rate generell von Bewegungsschwellen ab, obwohl es davon abhängt, wie viel Reaktionsfähigkeit und Präzision die Spieler wollen, bin ich froh, dass das in Ihrer Situation für Sie funktioniert. Aber hier biete ich eine andere Lösung an:
Ich benutze etwas namens Soft Tiered Smoothing . Die Idee ist, dass wir die Eingabe abhängig von der aktuellen Größe der Kreiselgeschwindigkeit durch verschiedene Glättungsalgorithmen umleiten (in der Praxis ist einer dieser Glättungsalgorithmen nur "keine Glättung"). Das ist der "abgestufte" Teil. Der "weiche" Teil ist, dass wir die Eingabe tatsächlich reibungslos zwischen verschiedenen Glättungsalgorithmen aufteilen können, je nachdem, wie sie mit 2 Schwellenwerten verglichen wird.
Es bewahrt die Verschiebung korrekt und fügt schnellen Bewegungen keinerlei Verzögerung hinzu.
In der Praxis haben Sie zwei Schwellenwerte. Wenn die Größe der Eingabegeschwindigkeit unter dem unteren Schwellenwert liegt, verwenden wir einen einfachen Glättungsalgorithmus (Durchschnitt über mehrere Frames). Wenn es größer als der andere Schwellenwert ist, verwenden wir überhaupt keinen Glättungsalgorithmus. In diesem Fall übergeben wir jedoch immer noch Nullen an den Glättungsalgorithmus mit niedrigerem Schwellenwert.
Wenn die Eingabegeschwindigkeit zwischen den beiden Schwellenwerten liegt, teilen wir die Eingabe entsprechend zwischen den beiden Algorithmen auf.
Hier ist ein Ausschnitt aus dem obigen Artikel:
GetDirectInput gibt nur das zurück, was ihm gegeben wurde, aber es soll zeigen, dass hier ein anderer Glättungsalgorithmus verwendet werden könnte. GetSmoothedInput nimmt eine Geschwindigkeit an und gibt eine geglättete Geschwindigkeit zurück.
Mit Soft Tiered Smoothing wird keine Glättung auf offensichtlich absichtliche Bewegungen angewendet (oberhalb der größeren Schwelle). Es wird eine Glättung angewendet, um kleine Mengen an Jitter zu überdecken, die sich auch auf sehr kleine Bewegungen auswirken. Wenn Sie jedoch Ihre Schwellenwerte richtig einstellen, ist dies nicht sehr bemerkbar. Und es gibt einen sehr reibungslosen Übergang zwischen den beiden (ohne den Jitter tatsächlich verstärkt werden kann).
Während die anderen Antworten zu Recht sagen, dass es schwierig ist, Jitter zu erkennen, sobald eine Eingabe empfangen wird, ist es auch wahr, dass Jitter fast immer eine sehr niedrige Geschwindigkeit aufweist und die mit der Glättung einhergehende Eingangsverzögerung bei Eingaben mit niedriger Geschwindigkeit weitaus weniger spürbar ist .
Wie im Artikel erwähnt, wird dies an mehreren Stellen in meinem Open-Source-Tool JoyShockMapper verwendet , einem Eingabe-Mapper, der Kreiseleingaben in Mauseingaben umwandelt . Selbst für Benutzer anderer Remapping-Tools wie Steam oder reWASD verwenden einige JoyShockMapper gleichzeitig nur für die Kreiselsteuerung.
Bei dieser Antwort wird davon ausgegangen, dass die Eingabe in Winkelgeschwindigkeit (wie bei Steuerungen mit Bewegungssteuerung üblich) erfolgt, nicht in absoluter Ausrichtung (wie es sich anhört, als würde Ihnen die Razer Hydra geben). Bei absoluter Ausrichtung hoffe ich, dass Sie den Unterschied zwischen der aktuellen Ausrichtung und der zuvor gemeldeten Ausrichtung verwenden können, um eine Geschwindigkeit zu erhalten, aber ich weiß nicht genau, ob dies funktioniert, sowie bei Controllern, die die Winkelgeschwindigkeit selbst melden .
Eine gängige Glättungslösung, wenn Sie sich eher mit einer absoluten Position / Orientierung als mit Geschwindigkeiten befassen, besteht darin, über die Zeit in Richtung Ihrer Zielorientierung zu interpolieren - dies wird in diesem Gamasutra-Artikel ausführlich beschrieben. Dies kann auch mit Soft Tiered Smoothing funktionieren. Sie berechnen die Geschwindigkeitsgröße anhand der Differenz zwischen dieser Eingabe und der zuvor gemeldeten Eingabe. Sie wenden den Orientierungsunterschied zwischen diesem Frame und dem letzten Frame multipliziert mit Ihrem "directWeight" -Wert an, wie im obigen Snippet berechnet. Der letzte Schritt ist das Hinzufügen der geglätteten Eingabe. Aufgrund der Funktionsweise der Glättung der interpolierten Ausrichtung wenden Sie jedoch einfach die Änderung der interpolierten Ausrichtung wie gewohnt an - "directWeight" muss überhaupt nicht berücksichtigt werden. Stellen Sie einfach Ihre Zielausrichtung (dies ist das, worauf Sie mit der in diesem Gamasutra-Artikel beschriebenen Glättung interpolieren) auf die Ausrichtung ein, die Sie vom Gerät erhalten, und interpolieren Sie Ihre Ausrichtung darauf, wie in diesem Artikel beschrieben.
quelle
Es fühlt sich komisch an, meine eigene Frage zu beantworten, aber ich denke, ich habe meine Lösung gefunden.
Anstatt die Überschrift des Spielers direkt zu ändern, "drücke" ich einfach einen Kegel mit einem bestimmten Winkel (in meinem Fall 2,5 Grad). Ich habe eine kleine HTML5-Demo dieser Technik erstellt.
Sobald Sie anfangen, den Kegel zu drücken, gibt es keine Verzögerung und volle Präzision. Wenn Sie jedoch den Kegel nach links drücken und dann nach rechts zielen möchten, müssen Sie sich über den gesamten Winkel des Kegels bewegen, um einen Effekt zu sehen.
Damit werden die Probleme der zeitlichen Verzögerung und der schrecklichen Glättung gelöst, aber das neue Problem einer Bewegungsschwelle eingeführt. Wenn der Stabilisierungskegel jedoch richtig eingestellt ist, ist die Schwelle nicht wahrnehmbar.
quelle