Posy 1.5.0

Avatar-Bewegungen mit nur 115 Bytes pro Frame

Posy ist ein offenes Protokoll, das Körper-, Finger- und Gesichtsbewegungen von Avataren in Echtzeit zwischen mehreren Teilnehmern über einen WebRTC-Datenkanal oder einen WebSocket übertragen kann.

  • Header + bone_mask16
  • 13 Knochenrotationen52
  • Position + Hüfthöhe8
  • Finger, beide Hände24
  • 13 Emotes + Blick15
Ein typischer Oberkörper-Frame hat 115 Bytes, hier im Maßstab mit einem Feld pro Byte. Dieselbe Pose braucht über VMC ca. 3,3 KB, das 25- bis 35-Fache.
1

Ist es was für deine App?

Optimal, wenn

  • Avatarbewegungen vieler Nutzer übertragen werden
  • Bandbreite und Fehlertoleranz ein Thema sind
  • Neben Fullbody & Face weitere Extras benötigt werden
  • Bewegungsdaten schnell online übertragen werden sollen

Eher nichts, wenn

  • Motion-Capture verlustfrei aufgezeichnet werden soll (nimm VMC)
  • Das Ganze eh nur im Heimnetzwerk bleibt (geht, bringt aber wenig)
2

Funktionsweise

Jeder Bewegungs-Frame geht vom Sender zum Server und von dort zu den Empfängern. Der Server gibt Takt, Uhrzeit und Berechtigungen vor. Er braucht kaum Power, kann also locker auch auf einem lokalen PC oder einem kleinen gehosteten VPS laufen.

Sendertrackt, kodiert Serverprüft, leitet weiter Empfängerinterpolieren, rendern
  1. Der Sender deklariert, dann sendet er. Er deklariert die Datentypen, die sein Tracker liefert und sein Avatar zeigen kann, und sendet nur diese. Ein verlorener Frame ist weg und wird nicht neu gesendet.
  2. Der Server serviert. Zumindest solange die Länge der Frames dem entspricht, was dem Sender gewährt wurde. Wird ihm was Falsches untergeschoben, verwirft er den ganzen Frame, ohne die Rotationen überhaupt anzufassen.
  3. Der Empfänger rendert den ganzen Bumms. Jeder Empfänger verwendet die Daten der Frames, um die Avatarbewegungen darzustellen, interpoliert zwischen den Frames und überbrückt kurze Lücken.
Posy avatar space (§3)
Ist identisch zum normalisierten Rig der VRM-1.0-Runtime. Fertig. Wir haben das Rad nicht neu erfunden.
Humanoides steht in §3, der Rest in §2.6
Katzenohren, Flügel, Schwänze und weitere Gliedmaßen sind optional deklarierte Extras, alles, was die Avatar-Datei so hergibt.
3

Einen Frame bauen

Links kann man Knochen und Blöcke an- und ausschalten, rechts sieht man den resultierenden Frame.

Quaternion in 4 Bytes (§5.3)

Wir sparen bei jedem Knochen, indem wir die größte der vier Komponenten weglassen und die anderen drei auf je 10 Bit quantisieren.

normalisiertes Quaternion (x, y, z, w)
–

Die markierte Komponente (?) wird weggelassen und beim Dekodieren neu berechnet.

gepacktes u32
–
Bit-Layout: Index (2) a (10) b (10) c (10)
–
Fehler nach Kodieren und Dekodieren
–

Im Worst Case ≈ 0,25°. Bei 0 / 0 / 0 stehen hier ≈ 0,14°, weil die Identität genau auf einer Rundungsgrenze liegt. Sieht man beides nicht.

4

Bandbreite

Jeder User mit Tracking lädt jeweils einen Stream hoch und der Server schickt ihn an alle Teilnehmer. Dem User kann es also egal sein, wie viele Leute dabei sind, solange er nicht selbst den Server hostet. Der Server hingegen muss alles an alle weiterleiten, da kann sich die Bandbreite schnell summieren.

Szenario
Gesichtsblock
–sendet der Server

–

Raum–
Ein Zuschauer empfängt–
Ein Sender empfängtdie Bewegungen aller anderen, ohne die eigenen–
Der Server empfängt–
Pro Sender Upload bei Full/Normal/Minimal– / – / – kbit/s
5

Tabellen der Spec

Der vollständige und normative Text ist spec/Posy.md, auf Englisch.

Eine 64-Bit-Maske. Ist Bit n gesetzt, ist das Quaternion von Knochen n vorhanden; die Quaternionen folgen in aufsteigender Bit-Reihenfolge. Die Farben zeigen den deklarierten Typ, zu dem ein Bit gehört. Setzt ein Frame ein Bit, dessen Typ dem Sender nicht gewährt wurde, oder eines der Bits 55–63, lehnt der Server ihn ab.

6

Posy implementieren

  1. Die Spec lesen und implementieren. §3 (Avatar-Raum), §4 (Knochen) und §5 (Pakete) von spec/Posy.md sind das, wo jede Implementierung übereinstimmen muss. §2 beschreibt den Session Layer. Hier kannst du eigentlich schon aufhören, der Rest ist nice to have.
  2. Referenz-Codec nutzen. Das posy-protocol auf npm (reference/js) ist in TypeScript geschrieben, hat keine Laufzeit-Abhängigkeiten und ist per se nur eine Implementierungshilfe.
  3. Teste deine Implementierung mit den testvectors/frames. Sie prüfen Bytes: jede .bin wird mit ihrer .json verglichen. testvectors/poses checkt hauptsächlich, ob irgendwas aus Versehen invertiert wurde.
  4. Schau dir die Loopback-Demo an. Sie simuliert einen verlustbehafteten Kanal, ergo scheiß Internet.
npm install posy-protocol