[OpenGL] Verschiedene Auflösungen

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

[OpenGL] Verschiedene Auflösungen

Beitrag von BeRsErKeR »

Hallo,

mein RPG-Projekt nimmt langsam Form an. Allerdings habe ich bislang auf eine feste Auflösung von 1024x768 gesetzt. Schon allein weil dadurch die Positionierung von GUI-Objekten trivialer wird. Nun möchte ich natürlich weitere Auflösungen anbieten (auch in Hinblick auf Widescreens etc).

Dazu würde ich gern eines der folgenden Verfahren nutzen:

1. Ein virtueller Screen mit einer festen Auflösung von 1024x768, der dann auf den realen Screen gemappt wird (falls nötig mit schwarzen Rändern in eine Dimension).
2. Einen Teilbereich des Screens nutzen.


Variante 1 gefällt mir sehr viel besser, allerdings würde ich gern vermeiden alle draw-Funktionen mit einem Koordinaten/Dimensions-Mapping zu versehen. Meine Idee war daher ein separater FrameBuffer (1024x768), in den ich alles zeichne. Darin befindet sich eine Textur, die den Inhalt des Framebuffers enthält. Diese packe ich am Ende auf ein Quad welches ich über den gesamten Screen zeichne. Ich nutze dazu die GLExtension GL_FRAMEBUFFER_EXT. Allerdings läuft das Ganze recht langsam und ich erhalte diverse Grafikfehler (z.B. beim Bewegen des Cursors).

Variante 2 hat den Nachteil, dass der Screen mindestens 1024x768 groß sein muss.


Mich würde interessieren, wie ihr das mit OpenGL so umsetzt bzw welche Variante ihr besser finden würdet bzw welche anderen Vorschläge ihr da so habt. In älteren Projekten habe ich meist auch mit festen Auflösungen oder Variante 2 gearbeitet. Früher hatten die meisten Monitore auch noch das schöne 4:3 Format.
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von Krishty »

Ist wahrscheinlich keine wirkliche Hilfe, aber:
• Alle GPUs bieten in ihren Treibern die Einstellung, ob man kleine Auflösungen verzerrt hochskalieren, unverzerrt hochskalieren (schwarze Ränder entweder links und rechts oder oben und unten) oder unbearbeitet anzeigen möchte (schwarze Ränder überall drumherum)
• Bei D3D10 und später kann die Anwendung – und damit der Benutzer – beim Start festlegen, welchen dieser Modi sie benutzen möchte; vielleicht bietet OpenGL etwas Ähnliches an?
• Wir hatten hier schon einen ähnlichen Thread, vielleicht hilft er dir weiter

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von Sternmull »

BeRsErKeR hat geschrieben:Meine Idee war daher ein separater FrameBuffer (1024x768), in den ich alles zeichne. Darin befindet sich eine Textur, die den Inhalt des Framebuffers enthält. Diese packe ich am Ende auf ein Quad welches ich über den gesamten Screen zeichne.
Das heisst für Nutzer mit einer höheren Auflösung ist die Qualität genau so schlecht wie bei 1024x768. Nutzer mit einer niedrigeren Auflösung haben den Aufwand die höhere 1024x768 Auflösung zu rendern und das dann auf ihre native Auflösung herunter zu rechnen. Also haben alle außer den Leuten mit 1024x768 Auflösung allen Grund unzufrieden zu sein (was heutzutage parktisch "jeder" bedeutet). Bei beiden ist die Qualität und Performance schlechter als sie sein sollte.

Ich gehe mal davon aus das es sich um ein 2D Spiel handelt bei dem die Grafiken genau in der Auflösung vorliegen in der sie auch auf dem Bildschirm erscheinen sollen (also momentan ein Texel pro Pixel)... ansonsten hättest du ja höchstens ein Problem mit dem Seitenverhältnis und keins mit der Skalierung.

Die Texel = Pixel Geschichte könntest du einfach beibehalten. Alle gängigen Auflösungen haben quadratische Pixel, eine Streckung braucht man also nicht befürchten. Allerdings würden je nach Auflösung mehr/weniger Pixel pro Monitorfläche anfallen und die Bilder damit ja nach Auflösung kleiner/größer wirken. Die GUI Elemente könnte man für die kleinste unterstützte Auflösung designen (halt z.B. für 1024x768) und dann an den Bildschirm-Ecken/Kanten/Zentrum ausrichten. Dann sind sie bei höheren Auflösungen halt kleiner aber noch relativ am gleichen Platz.

Diese Methode hat halt den Nachteil das die Grafiken je nach Auflösung kleiner/größer dargestellt werden und die Spieler ensprechend mehr/weniger Spielfläche sehen. Allerdings vermeidet man jegliche Qualitätsverluste und Performanceeinbußen die man durch Skalierung der Grafiken zu ertragen hätte. Soweit ich mich erinnere wurde dieser Ansatz zumindest von den Strategiespielen verwendet als sie noch nicht mit 3D-Engines ausgestattet waren die ja ohne große Probleme mit allen Auflösungen umgehen können.

Alternativ könntest du dir eine Auflösung pro gängigem Seitenverhältnis aussuchen die der Pixeltdichte von 1024x768 am nähesten ist und den Bildschirmmodus entsprechend setzen. So würde der Nutzer zwar wahrscheinlich gezungen werden eine niedrigere Auflösung als seine native zu verwenden, aber dafür haben alle Nutzer annähernd gleich viele Pixel auf ihrem Bildschirm.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von BeRsErKeR »

Danke erstmal für deine Antwort.

Mich würde jedoch mal interessieren wie so der gängige Weg ist (ob DX oder OpenGL wäre erstmal egal). Transformiert ihr die Koordinaten je nach Auflösung vor den DrawCalls oder rendert ihr einfach in einen virtuellen Screen und überlasst das stretchen dem Monitor / der GraKa?

Weil neben der Anzeige wäre ja auch die korrekte Erfassung der Mausposition bei anderer Auflösung wichtig.

Edit: Hast gerade gepostet während ich geschrieben hab Sternmull. Genau genommen ist es sowohl 2D als auch 3D (je nach Map). Die Map (und somit das einzige was 3D sein kann) wird jedoch nur in einem Teilbereich gezeichnet. Die restliche Fläche ist Teil des GUIs. GUI-Elemente ausrichten könnte ein wenig schwierig werden, da ganze Hintergrundflächen Teil des GUIs sind, also nicht nur ein paar Icons oder Schaltflächen. Diese Bereiche können allerdings in gewisser Weise skaliert werden, da sie auch aus mehreren kleinen Tiles zusammengesetzt werden.

Ich bin fast schon geneigt einen 1024x768 Bereich in die Mitte des Screens zu packen, weil das auch die Maussteuerung einfacher macht und ich nichts skalieren oder stretchen muss, sondern nur ein Offset einführen müsste. Problematisch wären dabei jedoch kleinere Auflösungen. Gerade bei Widescreens könnte die Höhe kleiner sein.

So richtig entscheiden kann ich mich noch nicht. Alles hat irgendwie Nachteile.
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von Krishty »

BeRsErKeR hat geschrieben:Transformiert ihr die Koordinaten je nach Auflösung vor den DrawCalls oder rendert ihr einfach in einen virtuellen Screen und überlasst das stretchen dem Monitor / der GraKa?
Normalisierte Koordinaten ftw. Da ich aber nur wirklich minimalistische GUIs und 3D-Grafik gemacht habe, ist die Meinung wohl nicht besonders wertvoll :/
BeRsErKeR hat geschrieben:Weil neben der Anzeige wäre ja auch die korrekte Erfassung der Mausposition bei anderer Auflösung wichtig.
Garnicht mal so unbedingt. Auf Systemen mit doppelter Auflösung braucht die Maus auch doppelt so lange von einem Ende zum anderen, weil die Mausgeschwindigkeit immer in Pixeln gemessen wird. Die Mausgeschwindigkeit in Pixeln pro Sekunde ist also auf allen Systemen, unabhängig von der Auflösung, gleich (solange der Anwender das nicht anders eingestellt hat, natürlich) … wenn man nicht gerade aus mysteriösen Gründen ein clamp(int2(0, 0), mousePosition, int2(1024, 768)); drin hat bleibt also alles beim Alten. Sogar, wenn gestreckt wird.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von BeRsErKeR »

Krishty hat geschrieben:
BeRsErKeR hat geschrieben:Weil neben der Anzeige wäre ja auch die korrekte Erfassung der Mausposition bei anderer Auflösung wichtig.
Garnicht mal so unbedingt. Auf Systemen mit doppelter Auflösung braucht die Maus auch doppelt so lange von einem Ende zum anderen, weil die Mausgeschwindigkeit immer in Pixeln gemessen wird. Die Mausgeschwindigkeit in Pixeln pro Sekunde ist also auf allen Systemen, unabhängig von der Auflösung, gleich (solange der Anwender das nicht anders eingestellt hat, natürlich) … wenn man nicht gerade aus mysteriösen Gründen ein clamp(int2(0, 0), mousePosition, int2(1024, 768)); drin hat bleibt also alles beim Alten. Sogar, wenn gestreckt wird.
Naja ich meinte da auch eher die Position beim Klicken auf GUI-Elemente usw. Wenn ich jetzt in einem virtuellen Screen einen Button an Position 100,100 habe, dann wird er bei einer anderen Auflösung nicht an dieser Position sein und somit funktioniert das "Hab-ich-den-Button-gedrückt"-System nicht ohne Änderungen am Code. Mit transformierten Positionen geht das natürlich wieder, sofern ich dann in allen Mausabfragen diese Koordinaten berücksichtige. Daher müsste ich im Grunde eh eine Transformation machen für Mausabfragen.

Also wenn ich jetzt die Koordinaten transformieren würde (was sicherlich möglich wäre), dann hätt ich das Problem was Sternmull beschrieben hat (daran hatte ich noch gar nicht mal gedacht): Meine Grafiken könnten verzerrt oder halt gestretcht aussehen (besonders die Schritf -> Bitmap Font).

Ich hatte auch überlegt so 3-4 Auflösungen anzubieten und zwar jede in einem anderen Seitenverhältnis (4:3, 16:9, usw). Und dann halt eine etwas geringere Auflösung, dass möglichst viele Leute spielen können. Das Problem daran ist nur, dass das gesamte Interface auf eine Mindesthöhe von 768 und eine Mindestbreite von 1024 ausgelegt ist. Und kleinere Grafiken machen find ich auch nicht so toll. Vielleicht könnte man das ganze aber noch um einige Pixel verkleinern. Ich denk mal 960 Breite und 700 Höhe sollten heutige Monitore doch mindestens hinkriegen oder? Oder wie sind da zur Zeit die kleinsten Größen (bitte nicht diese mikrigen Notebooks, ka wie die heißen. allen kann ich's nun wirklich nicht recht machen).


Ich denke mal ich werd es jetzt vielleicht so machen:

Koordinaten werden transformiert. Dabei gehe ich jedoch immer von einem Seitenverhältnis von 4:3 aus. Für Auflösungen mit einem anderen Verhältnis wird der größtmögliche 4:3-Bereich als Viewport genommen und der Rest bleibt schwarz. Damit könnte ich alle Auflösungen problemlos anbieten und sogar kleinere Auflösungen als 1024x768 wären möglich. Und durch das konsistente 4:3-Verhalten könnte man die Anordnung von GUI-Elementen usw recht einfach umsetzen ohne groß Code zu ändern. Wenn ich das richtig sehe beschränkt sich das ganze auf:

Koordinaten-Transformation beim Rendern
Koordinaten-Transformation bei Maus-Clicks / GUI-Events
Viewport-Berechnung für andere Seitenverhältnisse (schwarzer Rand kann ja durch ClearColor auf dem kompletten Screen gemacht werden, bevor ich dann den Viewport setze).
Ohne Input kein Output.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von BeRsErKeR »

So ich habe das ganze mal mit Koordinatentransformation umgesetzt. Erstaunlichweise war das ganze doch recht simpel. Ich musste nur an 3-4 Stellen im Code eine Transformation vornehmen. Die Skalierungsfaktoren und das Offset berechne ich beim Resizen. Und die Transformation der Mausposition musste ich gar nicht machen, denn der Cursor wird durch eine Grafik angezeigt, die intern zur Anzeige dann auch transformierte Koordinaten nutzt. Dadurch stimmen die virtuellen Koordinaten (fürs GUI-System) mit den realen Koordinaten von z.B. Button und Cursor überein und alle GUI-Events werden korrekt erfasst.

Im Fenstermodus kann man nun beliebig große Fenster wählen. Selbst Größen wie 1040x760 oder ähnliches sind problemlos möglich. Im Vollbildmodus kann man auch verschiedenste Auflösungen nutzen.

Danke für eure Hinweise.


Edit: Mir ist da grad was unschönes aufgefallen. Wenn ich kleinere Fenster nutze und mit dem Cursor ziemlich weit nach rechts oder unten gehe, sieht man den Windows-Cursor außerhalb des Fensters und den gezeichneten im Fenster. Das ist nicht nur unschön, sondern verhindert auch, dass MausClicks an das Fenster geschickt werden. Scheinbar darf ich den Mauscursor beim zeichnen nicht transformieren, aber dafür dann die reale Mausposition. :|
Ohne Input kein Output.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Verschiedene Auflösungen

Beitrag von BeRsErKeR »

Nur noch mal als Feedback meine Endlösung, falls mal jemand was ähnliches machen will und das ganze als nützlich erachtet:

Mein Device bietet Funktionen zum transformieren von Positionen, Dimensionen und Rects an, die dann abhängig von der Größe des virtuellen Screens und der tatsächlichen Auflösung sind, welche wiederum beim Erstellen des Devices bzw beim Resize spezifiziert werden. Bei der Mauskoordinaten-Transformation muss die Transformationsrichtung natürlich umgekehrt werden, weshalb es dafür noch eine Extrafunktion im Device gibt.

Damit das ganze nicht zu komplex wird, werden nicht komplett alle Auflösungen angeboten, sondern nur die meisten gängigen (jedenfalls was den Fullscreen-Modus betrifft). Außerdem wird das Seitenverhältnis vom virtuellen Screen beibehalten, wodurch bei anderen Seitenverhältnissen der Auflösung ein schwarzer Rand gezeichnet wird (ist aber nur in eine Dimension nötig, da die andere Dimension dann auf 100% Breite oder Höhe skaliert wird und die jeweils andere Dimension in Abhängigkeit davon skaliert wird).

Bei Fensteranwendungen kann allerdings in beide Dimensionen ein schwarzer Rand auftreten, denn ich möchte krumme Dimensionen wie 1023x765 verhindern, weil das ganze dann recht verzerrt aussehen kann. Daher wird eine "schöne" Auflösung, die ins Fenster passt als Viewport genutzt. Im Fullscreen werden von der Auflösung her natürlich schon keine krummen Auflösungen akzeptiert. Beim Fenster kann man die Größe allerdings frei resizen, daher der Viewport.

Klappt an sich recht gut. Das einzig unschöne dabei ist mein Bitmap-Font, da dieser in einer festen Größe erstellt wird und über DrawListen gezeichnet wird. Daher ist die Skalierung nicht möglich bzw umständlich. Zur Zeit erstelle ich die BitmapFonts neu, wenn sich die Auflösung ändert, was allerdings keine schöne Lösung ist (vor allem für Fensteranwendungen, wo ich permanent resizen kann).

Vielleicht hat dazu ja noch jemand eine Idee.
Ohne Input kein Output.
Antworten