GamePad-Werte in korrekten Kreis umrechnen

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Schrompf
Moderator
Beiträge: 4869
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Schrompf »

Hallo Leute!

Ein potentiell banales Problem heute: ich habe einen XBox-Controller. Ich vermute aber, dass das Problem bei anderen GamePads das Gleiche ist. Da sind ja zwei Sticks drauf, die man analog auslenken kann. Deren Bewegungsspielraum sieht kreisförmig aus:
pad_beispiel1.png
pad_beispiel1.png (4.26 KiB) 1956 mal betrachtet
Von XInput, DirectInput oder was auch immer bekomme ich nun aber zwei separate Achsen, deren Werte sich jeweils im Bereich -0.45 bis +0.45 oder so bewegen. Und irgendwas auf dem Weg vom physikalischen Stick auf dem Controller bis in mein Programm rechnet die Werte so um, dass ich statt eines Kreises ein Rechteck bekomme. Also etwa so:
pad_beispiel2.png
pad_beispiel2.png (794 Bytes) 1958 mal betrachtet
Das kann ich sicherlich mathematisch irgendwie wieder ausgleichen. Aber ich stehe gerade auf dem Schlauch, wie ich das tun könnte, ohne den Betrag des Auslenkungsvektors zu verlieren. Hat jemand eine Idee?

Bye, Thomas
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von CodingCat »

Eine naheliegende Möglichkeit wäre, dass der größere der beiden Achsenwertbeträge auch gleich dem Betrag des Auslenkungsvektors entspricht. Damit ergäbe sich der Auslenkungsvektor als normalize(rect) * max(abs(rect.x), abs(rect.y)).
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Schrompf
Moderator
Beiträge: 4869
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Schrompf »

Gute Idee! Ich war gerade dabei, die Achse mit dem größeren absoluten Betrag irgendwie zu korrigieren, als ob der Betrag auf beiden Achsen präsent wäre... irgendwie so. Im Gegensatz zu Deinem Vorschlag ist die Idee aber ziemlich indirekt. Danke!
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Alexander Kornrumpf
Moderator
Beiträge: 2117
Registriert: 25.02.2009, 13:37

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Alexander Kornrumpf »

Etwas unausgegoren:

Fürs Rechnen nehme ich mal an maximale Auslenkung sei 0.5

Für Winkel phi zwischen Pi/4 und Pi/2 gilt bei maximaler Auslenkung also

x_max = 0.5 = r sin(phi)

oder auch (sinus ist dort streng positiv)

r_max(phi) = 0.5/sin(phi)

Dagegen ist die maximale Auslenkung r_kreis bei einem Kreis logischerweise konstant.

Du könntest nun für alle Paare r und phi einfach r' = r(r_kreis/r_max(phi)) skalieren.

Ich bin allerdings zu faul das für die restlichen Oktanten auch noch herzuleiten.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4869
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Schrompf »

Zuerst nochmal Danke: Die Korrektur funktioniert wie erhofft, die Richtung auf dem Bildschirm hat jetzt deutlich mehr als vorher mit der Richtung des GamePad-Sticks gemeinsam.

Leider hat das GamePad toten Stellen in den vier diagonalen Hauptrichtungen. Da geht noch irgendwas anderes intern vor, so dass ich Wertänderungen in den vier Ecken gar nicht gemeldet bekomme. Und falls das als Ärger noch nicht reicht, werfen wir auch noch ein bisschen Signalverlust mit in die Gleichung: wenn man mit dem Stick ganz fix in die gegenüberliegende Auslenkung wechselt, geht diese Änderung manchmal verloren und man bekommt immernoch die alten Werte übermittelt. Ja so eine Freude.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8265
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Krishty »

Ich würde auch Alexanders Lösung vorschlagen. An den Winkel kommst du ganz einfach mit atan2(y, x). Dann berechnest du, wie weit der Punkt des Einheitsquadrats in diese Richtung entfernt ist und teilst dadurch, um das Quadrat auf einen Kreis abzubilden – das ist Alexanders Formel. Wenn man jetzt noch beachtet, dass das atan2() ein Winkelverhältnis ist und der Sinus ebenfalls, kommt am Ende vielleicht noch eine blamabel simple Formel raus. Wenn es ganz blamabel wird, vielleicht sogar Cats.

Jedenfalls wollte ich noch anmerken, dass ich hier einen Joystick habe, der sich tatsächlich im Rechteck bewegt. Also mach bitte nicht, dass die Formel jetzt pauschal aktiv ist.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von CodingCat »

Krishty hat geschrieben:Ich würde auch Alexanders Lösung vorschlagen. An den Winkel kommst du ganz einfach mit atan2(y, x). Dann berechnest du, wie weit der Punkt des Einheitsquadrats in diese Richtung entfernt ist und teilst dadurch, um das Quadrat auf einen Kreis abzubilden – das ist Alexanders Formel. Wenn man jetzt noch beachtet, dass das atan2() ein Winkelverhältnis ist und der Sinus ebenfalls, kommt am Ende vielleicht noch eine blamabel simple Formel raus. Wenn es ganz blamabel wird, vielleicht sogar Cats.
Sogar ziemlich sicher, denn genau diese Überlegungen stecken dahinter. ;) Schlussendlich war meine Annahme, dass der Eingangsvektor nach Projektion auf das Einheitsquadrat mit dem Betrag des Eingangsvektors skaliert wird, um von einem Punkt im Kreis auf einen Punkt im Quadrat abzubilden. Genau das habe ich dann mit obiger Formel fix umgekehrt.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Alexander Kornrumpf
Moderator
Beiträge: 2117
Registriert: 25.02.2009, 13:37

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Alexander Kornrumpf »

Kannst du, wenns nicht zuviel Mühe ist, mal ein Bild machen? Ich kapier es nicht so richtig. Alternativ auch etwas was mit Vektoren arbeitet und nicht mit dubiosen "rects".
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von CodingCat »

Alexander Kornrumpf hat geschrieben:Kannst du, wenns nicht zuviel Mühe ist, mal ein Bild machen? Ich kapier es nicht so richtig. Alternativ auch etwas was mit Vektoren arbeitet und nicht mit dubiosen "rects".
rect ist doch ein Vektor, nämlich genau der Eingabevektor im Rechteck, den Schrompf beschreibt. Bild kommt.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Alexander Kornrumpf
Moderator
Beiträge: 2117
Registriert: 25.02.2009, 13:37

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Alexander Kornrumpf »

CodingCat hat geschrieben:
Alexander Kornrumpf hat geschrieben:Kannst du, wenns nicht zuviel Mühe ist, mal ein Bild machen? Ich kapier es nicht so richtig. Alternativ auch etwas was mit Vektoren arbeitet und nicht mit dubiosen "rects".
rect ist doch ein Vektor, nämlich genau der Eingabevektor im Rechteck, den Schrompf beschreibt. Bild kommt.
Mir ist jetzt glaube ich klar was du gemacht hast. Ob das dasselbe ist muss ich irgendwann in Ruhe herleiten.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von CodingCat »

Bild
Dateianhänge
rect_proj.png
rect_proj.png (8.95 KiB) 1829 mal betrachtet
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von eXile »

CodingCat hat geschrieben:Eine naheliegende Möglichkeit wäre, dass der größere der beiden Achsenwertbeträge auch gleich dem Betrag des Auslenkungsvektors entspricht. Damit ergäbe sich der Auslenkungsvektor als normalize(rect) * max(abs(rect.x), abs(rect.y)).
Korrekt. Um etwas mathematischen Nährwert noch hinzuzufügen (siehe hierzu dieses Bild):
  1. Projektion auf „Einheitsdiamant“: \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_1}$$\)
  2. Projektion auf Einheitskreis (das habt ihr schon hundertmal gemacht): \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_2}$$\)
  3. Projektion auf Einheitsquadrat (das wollen wir hier machen): \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_{\infty}} = \frac{\mathbf{v}}{\max \left(|v_1|, \ldots ,|v_n| \right)}$$\)
Das funktioniert so im Allgemeinen für beliebig viele Dimensionen, für beliebige \($p \geq 1$\)-Normen und für alle Vektoren mit Norm ungleich 0.
Zuletzt geändert von eXile am 12.04.2013, 19:03, insgesamt 1-mal geändert.
Alexander Kornrumpf
Moderator
Beiträge: 2117
Registriert: 25.02.2009, 13:37

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von Alexander Kornrumpf »

eXile hat geschrieben:
CodingCat hat geschrieben:Eine naheliegende Möglichkeit wäre, dass der größere der beiden Achsenwertbeträge auch gleich dem Betrag des Auslenkungsvektors entspricht. Damit ergäbe sich der Auslenkungsvektor als normalize(rect) * max(abs(rect.x), abs(rect.y)).
Korrekt. Um etwas mathematischen Nährwert noch hinzuzufügen (siehe hierzu dieses Bild):
  1. Projektion auf „Einheitsdiamant“: \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_1}$$\)
  2. Projektion auf Einheitskreis (das habt ihr schon hundertmal gemacht): \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_2}$$\)
  3. Projektion auf Einheitsquadrat (das habt ihr schon hundertmal gemacht): \($$\mathbf{v_p} = \frac{\mathbf{v}}{\|\mathbf{v}\|_{\infty}} = \frac{\mathbf{v}}{\max \left(|x_1|, \ldots ,|x_n| \right)}$$\)
Das funktioniert so im Allgemeinen für beliebig viele Dimensionen, für beliebige \($p$\)-Normen und für alle Vektoren mit Norm ungleich 0.
Da hell, das bringe ich sogar meinen Studenten bei. Also WiWis. Manchmal hat Mensch ein Brett vor dem Kopf.

Ich kann aber auch sagen warum: Früher in den MFC hieß NormalizeRect dafür zu sorgen dass die obere rechte Ecke eines Rechtecks tatsächlich über und rechter war als die untere linke (oder so ähnlich). Also (0,1),(1,0) -> (0,0),(1,1). Deswegen hat Cats Schreibweise bei mir das völlig falsche Mindset getriggert.

Aber da ich Polarkoordinaten nur einmal im Jahrzehnt benutze, werde ich zu meiner Erbauung trotzdem am WE die Äquivalenz von Kartesischer- und Polardarstellung des Sachverhalts nachweisen. Es ist zumindest ein schönes Hobby.
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: GamePad-Werte in korrekten Kreis umrechnen

Beitrag von eXile »

Ich habe das ganze mir noch mathematisch etwas genauer betrachtet, und bin zum Ergebnis gekommen, dass die obige Vorgehensweise für jede Funktion \($f: \mathbb{R}^n \to \mathbb{R}$\) funktioniert, wobei für \($f$\) gelten muss:
  1. \($f(\mathbf{x}) > 0$\) für \($\mathbf{x} \neq 0$\)
  2. \($f(\alpha \mathbf{x})=|\alpha| f(\mathbf{x})$\)
Das sind exakt die Bedingungen für eine Norm, nur ohne Dreiecksungleichung; diese brauchen wir hier nicht. Wenn wir unsere Projektion \($$\begin{align}\mathbf{p}: \quad \mathbb{R}^n &\to \mathbb{R}^n, \\
\mathbf{p}(\mathbf{v}) &\mapsto \frac{\mathbf{p}}{f(\mathbf{p})}\end{align}$$\)
uns dann anschauen, stellen wir fest:
\($$\mathbf{p}(\alpha \mathbf{x}) = \frac{\alpha \mathbf{x}}{f(\alpha \mathbf{x})} = \frac{\alpha \mathbf{x}}{|\alpha| f(\mathbf{x})} = \operatorname{sgn}(\alpha) \cdot \frac{\mathbf{x}}{f(\mathbf{x})} = \operatorname{sgn}(\alpha) \cdot \mathbf{p}(\mathbf{x})$$\)Auch wenn man es erstmal nicht glauben mag, so entspricht obige Formel genau unseren Vorstellungen: Wenn \($\alpha$\) positiv ist, so ist \($\mathbf{p}(\alpha \mathbf{x}) = \mathbf{p}(\mathbf{x})$\); dies ist genau die Projektionseigenschaft, dass Punkte auf Linien vom Nullpunkt aus alle auf den gleichen Punkt abgebildet werden. Das Signum da ist leider notwendig, weil wir bei einem negativen \($\alpha$\) auf die andere Seite vom Nullpunkt aus gesehen abbilden wollen.

Durch den Verzicht auf die Dreiecksungleichung funktioniert das also auch in solchen Fällen:
Bild
Antworten