Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

19.06.2012, 18:20

FreeType und die Non-ASCII Zeichen...

Hallo zusammen,
bin relativ neu hier und hoffe, dass ich mit meinem ersten Beitrag richtig gelandet bin.
Ich bringe mir aktuell OpenGL (3.3+) bei und konnte bisher einen recht guten Fortschritt erziehlen. Meine Modelle werden mitsamt Texture korrekt angezeigt und da drüber kann ich in 2D Zeichen. Ich habe mir für 2D und 3D jeweils eigene Shader sowie dazu gehörende Klassen geschrieben und versuche nun den Sprung aufs Font-Rendern.
Ich bin mir nur noch nicht ganz sicher, ob ich das Konzept soweit richtig verstanden habe.
  1. Initialisieren von Freetype
  2. Laden der Font
  3. Ermitteln der zu ladenden Buchstaben
  4. Rendern der Buchstaben
  5. Zeichnen eines Strings mittels 2D Texturshader
Bei 3 und 4 habe ich so meine Probleme.
zu 3.:
Wie ermittel ich alle Buchstaben, die eine Font hat? Ist es überhaupt Sinnvoll alle Buchstaben bereits im Voraus zu rendern (Offline, also als Bitmap beilegen)? Ich möchte möglichst viele (gängige!) Symbole unterstützen. Sowohl der ASCII Zeichensatz, als auch Sonderzeichen wie Ä, Ö, ß, â oder É möchte ich anzeigen können. Sonderformate, wie z.B. unterschiedliche Darstellungen des Buchstaben "f" brauche ich nicht. Standard reicht :D
Wie ermittel ich die (char) Werte dafür am besten? Mir sind hierfür 3 Möglichkeiten eingefallen, aber vieleicht habe ich eine vergessen:
  1. Liste "Hardcoden"
  2. On-The-Fly generieren und cachen
  3. Fontmap im Voraus generieren und als Bitmap beilegen
Ich würde nur ungern eine Bitmap im Voraus generieren, aber ich mache mir Sorgen bei der On-The-Fly Methode bezüglich der Performance. Mit der "Hardcode"-Liste könnte ich meine Fontmap während eines "Ladescreens" generieren, jedoch werden so nicht alle Buchstaben unterstützt.
Hintergrund ist, dass ich mein UI mittels LUA anpassbar machen möchte und daher muss ich davon ausgehen, dass Zeichen im UI angezeigt werden sollen, die ich möglicherweise nicht auf meiner Fontmap habe, aber häufig genutzt werden. Welche Methode haltet ihr für am besten geeignet?
zu 4.:
Um Fonts möglichst performant Rendern zu können, sollten sich diese auf einer Textur befinden.. aber welche Dimensionen sollte diese haben? Kann ich alle 2 Millionen (fiktive Zahl) Buchstaben in eine "Zeile" Rendern, oder sollte ich Höhe und Breite der Textur ausnutzen?
Bei der Suche nach einer geeigneten Lib zum lesen von Texturen, habe ich gelesen, dass die Texturen in Höhe und Breite identisch und dabei ein Vielfaches von 2 sein sollten. Gilt dies immernoch oder ist das einfach nur eine veraltete Information? Bei den ganzen OpenGL Tutorials, die ich gelesen habe, würde mich das nicht wundern ;D
Ums nochmal zusammen zu fassen: Wie bekomme ich eine Liste gängiger Buchstaben, um sie mittels FreeType zu laden und darf meine FontMap 2048x32 Pixel sein, ohne dass mir ne BitmapLib daraus 2048x2048 machen muss, nur weil OpenGL nix anderes kann? :o


Danke schonmal im Voraus,
Xalcon

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

19.06.2012, 23:44

Ich geh den Weg über Caching. Ich hab eine oder mehrere Texturen. Wenn eine Glyphe benötigt wird, dann schau ich nach, ob sie bereits in einer Textur liegt. Wenn nicht, wird ein freier Platz gesucht und die Glyphe dort hin geschrieben. Man könnte natürlich evtl. anhand der Sprachinformation des aktuellen Benutzers etc. sehr gut raten, welche Glyphen wohl am ehesten benötigt werden. Eine allgemeine Lösung gibt es aber wohl nicht. Da du eben kaum mit Sicherheit im Vorhinein wissen kannst, welche Glyphen du benötigen wirst und welche nicht und die Zahl der Möglichkeiten viel zu groß ist, als dass einfach alles zu laden praktikabel wäre, halte ich Caching für eine gute Lösung.

Was die Texturgröße angeht: Ich verwende im Moment einfach eine quadratische Textur, deren Breite/Höhe eine Zweierpotenz ist.
Das ist heutzutage aber nichtmehr wirklich so wesentlich wie es früher einmal war.
Die Textur unterteile ich in kleine (z.B. 4x4) Zellen und speichere mir in einer Bitmap, welche Zellen belegt und welche frei sind. Wenn eine Glyphe in den Cache soll, such ich mir einfach eine Stelle mit entsprechend viel Platz, allokier diese und kopier meine Glyphe dort hin. Funktioniert so weit ganz gut :)

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »dot« (19.06.2012, 23:54)


3

20.06.2012, 09:30

Ich geh den Weg über Caching. Ich hab eine oder mehrere Texturen. Wenn eine Glyphe benötigt wird, dann schau ich nach, ob sie bereits in einer Textur liegt. Wenn nicht, wird ein freier Platz gesucht und die Glyphe dort hin geschrieben. Man könnte natürlich evtl. anhand der Sprachinformation des aktuellen Benutzers etc. sehr gut raten, welche Glyphen wohl am ehesten benötigt werden. Eine allgemeine Lösung gibt es aber wohl nicht. Da du eben kaum mit Sicherheit im Vorhinein wissen kannst, welche Glyphen du benötigen wirst und welche nicht und die Zahl der Möglichkeiten viel zu groß ist, als dass einfach alles zu laden praktikabel wäre, halte ich Caching für eine gute Lösung.
Also eine kombination aus allen dreien :) Hätte ich auch selbst drauf kommen können. Ich müsste nur sehen, wie auch Crossplattform die Sprache ermittel, aber zum Glück sinds ja nur Windows, Mac und Linux :P
Was die Texturgröße angeht: Ich verwende im Moment einfach eine quadratische Textur, deren Breite/Höhe eine Zweierpotenz ist.
Das ist heutzutage aber nichtmehr wirklich so wesentlich wie es früher einmal war.
Die Textur unterteile ich in kleine (z.B. 4x4) Zellen und speichere mir in einer Bitmap, welche Zellen belegt und welche frei sind. Wenn eine Glyphe in den Cache soll, such ich mir einfach eine Stelle mit entsprechend viel Platz, allokier diese und kopier meine Glyphe dort hin. Funktioniert so weit ganz gut :)
Kann ich eigentlich Texturdaten verändern, während Sie verwendet wird? In OpenGL 3.1+ brauch ich meine Texturen ja nicht mehr Binden, da ich diese direkt (mittels UniformVariable) in den Grafikkarten Speicher lade. Wenn ich die Daten der Textur dann änder, werden diese dann im Grafikspeicher geändert oder muss ich die Textur erneut "hochladen"?


Eine weitere Frage habe ich noch. Um viel Text möglichst effektiv Rendern zu können, werden in einigen Tutorials VertexBuffer verwendet (so, wie ich es auch gemacht hätte). Jedoch wird bei jedem DrawCall ein bestehender Buffer verändert. Ist das Bedenklich (Grafikkarte und CPU arbeiten ja nicht syncron, nicht dass durch nen Buffer-Lock mein Renderthread sinnlos rum-idled)?
Ich hätte gerne eine Lösung, bei der ich nur einen einzigen VertexBuffer habe, aber einen dynamischen IndexBuffer und das ganze mittels Instancing zeichne (Uniform Arrays zum unterscheiden der Daten?). Ist das überhaupt möglich oder sollte ich einen anderen Weg verfolgen?

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

4

20.06.2012, 11:02

Du kannst für eine niedrige Anzahl von Zeichen komplett die Daten über den Constant Buffer zufüttern. Ein dynamischer IndexBuffer macht da nach meiner Ansicht gar keinen Sinn, da die Daten (wo, welches Zeichen, Größe, Farbe, Rotation, etc) ja im Vertex stehen. Ich kann den Ansatz über Instancing trotzdem sehr empfehlen, aber die Resourcen dafür sehen eher so aus:

- VertexBuffer: statisch, vier Vertizes, wird von allen Sprite-Renderern gemeinsam verwendet
- IndexBuffer: statisch, sechs Indizes, wird von allen Sprite-Renderern gemeinsam verwendet
- Instancing-VertexBuffer: dynamisch, einer pro SpriteBatch, wird nur von Frame zu Frame wiederverwendet

Bei OpenGL weiß ich das nicht, aber ich vermute, es ist ähnlich zu DirectX: Du kannst einen Buffer als "wird oft neu befüllt" markieren und beim Befüllen dann sagen "der bisherige Inhalt kann weg". Der Grafiktreiber managed das dann intern so, dass er der einfach einen neuen Buffer gibt und die GPU mit dem alten noch zufrieden fertigrendern kann, während Du den neuen schon mit den nächsten Daten füllst. Bei DirectX passiert das wie gesagt vollautomatisch im Hintergrund, wenn man den Buffer mit DYNAMIC flaggt - das geht rasend schnell. Ich komme mit Instancing und dynamischem VertexBuffer auf ~20 Millionen Sprites pro Sekunde.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Werbeanzeige