Schon wieder so früh? Hallo erstmal und schön, dass du in diesen Thread gefunden hast.
Es geht um folgendes: Für eine Grafikapplikation benötige ich einen richtig schnellen viewer für sphärische Panoramen. Ein Ausschnitt dessen soll in rectilinearer Abbildung ("normale" Sichtweise mit begrenztem Field Of View, frei von radialer Verzeichnung) mit typisch 1MP (z.B. 1280x800) angezeigt werden können.
Das Problem dabei ist, dass selbst mit SSE-Befehlen beschleunigte, pixelgenaue Berechnungen bei voller Bildschirmauflösung eine Laufzeit in der Größenordnung 1 Sekunde haben, also etwas, das fernab von echtzeitfeeling ist.
Ich habe nach einigen Stunden Bauchschmerzen nun folgendes Konzept aufgestellt:
Es gibt eine Transformation, die Punkte des Quellbildes in kartesischen Koordinaten auf eine Einheitskugel abbildet. Diese Abbildung basiert auf einem Satz von Stützpunkten, die auf einer zugeordneten Skala verwendbar sind. Wird er Skalenbereich überschritten, erfolgt ein Skalensprung so, dass die Stützpunktdichte der Transformation wieder den festgelegten Nennwert hat.
Damit befinden wir uns in einer kartesischen Kugeldarstellung, die man leicht und schnell durch 3x3-Drehmatrizen manipulieren kann, was auch vergleichsweise schnell berechnet ist. Hinzukommend können auch differentielle Drehungen draufmultipliziert werden, sodass man die oben genannte, erste Transformation nur beim zoomen ausführen muss (genaugenommen auch nach einer bestimmten Zahl von differentiellen Transformationen, wenn sich Rundungsfehler akkumuliert haben...).
Um auf die Quellbilddarstellung zu kommen, die aussieht wie eine Weltkartenansicht, sodass am oberen und unteren Bildrand starke Deformationen zu sehen sind, da die Pixel dort in polnähe liegen muss man einfach Polar- und Azimuthalwinkel mit Skalierungskoeffizienten multiplizieren. Der Hund liegt jedoch bei den inversen trigonometrischen Funktionen begraben. Hier kommt der zweite Trick ins Spiel:
Anstatt die faszinierend langsamen arccos und arctan-Funktionen zu bemühen, werden sechs Projektionen von Kugelsektoren erzeugt, sodass man eine Koordinate wählen kann, die >0.5 ist, diese selektiert eine der sechs lookups, die mit den zwei verbleibenden, senkrechten Koordinaten parametrisiert wird. Auch dies sind wiederum durch Stützstellen gefütterte Projektionen. Im Prinzip zerlegt man so den vollen Raumwinkel in sechs umkehrbare (bijektive) Abbildungen. Bildlich gesprochen schaut man in eine Richtung innerhalb der Panoramakugel, quetscht sie in Blickrichtung platt und nimmt nur den inneren Bereich, der nicht zu sehr verzerrt ist.
dieser Quellbild-lookup mit koordinatenbasierter Fallunterscheidung umgeht die Umrechnung auf sphärische Koordinaten.
Bilanz der ganzen Sache:
Der Abbildungsteil von den Viewport-Koordinaten in den Kugelflächenraum erfolgt anhand einer lookup table, die bei Bedarf aus einer genäherten Abbildung neu erzeugt werden kann. die Stützpunkt der genäherten Abbildung müssen gelegentlich der Skala angepasst werden.
Im Kugelflächenraum lässt sich die Blickrichtung und Neigung des viewports durch einfache Drehmatrizen ausführen.
Punkten im Kugelflächenraum wird durch Fallunterscheidung nach der längsten Koordinate (x, y- oder z-Richtung) und anschließende senkrechte Projektion in Richtung dieser Achse anhand einer von sechs interpolierten lookup-Abbildungen ein Punkt im Quellbild zugeordnet.
Ich habe schon zwei abstrahierbare Module identifiziert:
- source lookup engine : Erzeugung und Verwaltung der sechs Ebenen-Lookups, Interpolation der Quellbildkoordinaten
- destination lookup transform : erzeugt die lustig skalenspringende Transformation vom Viewport in den Kugelflächenraum, aus der die rotierbaren Stützpunkte einer Viewport->Kugelflächenraum-Abbildung generiert werden kann
zwischendrin steht die Drehmatrix und die Verwaltung der Viewport->Kugelflächenraum-Abbildung, die beim zoomen und nach Fehlerakkumulation erneuert werden muss.
Das attraktive an diesem ganzen Getrickse ist für mich, dass es sich hierbei nun ausschließlich um lineare (oder wenn es besser sein soll polynomiale) Abbildungen handelt, die man sogar rein in MMX-beschleunigter Integer-Arithmetik implementieren kann. Klar muss man den gesamten Fehler je nach Stützpunktdichten und Approximationsgrad mit 1-3 Pixeln absolut abschätzen, jedoch ist dies vollkommen irrelevant, solange der Nutzer schnelle Drehungen / Zooming durchführen will. Für eine Ansicht im Stillstand werde ich dann in separaten Threads verteilt eine pixelgenaue Abbildung erzeugen, sobald der Viewport stillsteht. Wird in der Zeit eine Modifikation vorgenommen, wird zunächst wieder approximativ gerendert und die verfeinerte Berechnung wieder verworfen.
So was will ich nun von euch? Eure geschätzte Meinung, Kritik und Verbesserungsvorschläge, die mich davor bewahren, nach mehreren Tagen coden alt auszusehen
Oder es kommt jemand und sagt er hats schon implementiert... dann ärgere ich mir ein zweites Loch in den Hintern
edit: auf dem laptop schreibt sichs nicht so gut, entschuldigt die Vertipper...
edit2: Übersicht aller sechs maps für den Quellen-Lookup beigefügt