[Projekt] Lumina Graphics Library

Crysis nerd

Freizeitschrauber(in)
Guten Tag,

an anderer Stelle schon angekündigt, wollte ich euch nun endlich ein Projekt vorstellen. Es geht um eine Library zur Entwicklung grafischer Applikationen, die ich seit ca. 3 Monaten entwickle. Ich hatte dieses Projekt schon länger geplant und dieses Semester bot sich die geniale Gelegenheit die Library direkt bei einem Computergrafik-Praktikum einzusetzen, welches ich geleitet habe. Die letzten 3 Wochen haben also einige Leute mit dieser Library gearbeitet und sogar was cooles damit geschafft (ein Minecraft artiges Spiel mit einigen coolen Grafikeffekten; bei Interesse erzähle ich nochmal mehr darüber). Diese 3 Wochen haben die Library auf die Probe gestellt und mir einiges an Verbesserungspotenzial aufgezeigt.

Aber um zur Sachen zu kommen: Worum gehts?
Lumina ist eine Library die die OpenGL Render Pipeline abstrahieren möchte. Das muss die erste Erkenntnis sein: Es soll keine Spiele-Engine oder ähnliches sein. Es gibt auch nichts was in die Richtung Szene oder Kamera geht. Es ist lediglich ein Toolkit für grafische Applikationen. Man sollte also wissen, was eine Grafikpipeline ist und wie das alles grundlegend funktioniert, sonst kommt man damit nicht weit. Dies hat den Vorteil, dass man immer weiß, was auf der Hardware passiert. Außerdem hat man so höheres Potenzial selber etwas zu optimieren.

Und warum dann nicht direkt OpenGL?
Weil OpenGL (auf eine Art und Weise) hässlich, verdammt schwer und voller kleiner Fallen ist. Sich in OpenGL auszudrücken fällt sehr schwer. Es gibt haufenweise Fehler, die man ewig suchen muss und so viele Stolpersteine, über die man sicherlich fallen wird. Genau das soll Lumina abnehmen: Lumina legt daher viel Wert auf ein typ-sicheres Interface und jede Art von Fehlererkennung. Durch die starke Typisierung können viele Fehler schon zur Kompilierzeit erkannt werden und viele weitere Fehler werden zur Laufzeit gemeldet. Alle Fehlerabfragen zur Laufzeit kann man allerdings auch (zur Kompilierzeit) deaktivieren, sodass man durch solche Fehler-checks keine Performance opfern muss.
Das ganze ist in modernem C++ geschrieben (derzeit noch komplett C++11 kompatibel, in der Zukunft werde ich auch C++14 Features nutzen).

Links:
Bei Interesse findet ihr hier weitere Informationen: https://github.com/LukasKalbertodt/lumina

Dies ist jetzt erstmal kein Projekt zum sehen oder anfassen, sondern nur eine Library. Allerdings habe ich einige Test-Applikationen geschrieben, die sehenswert sind: https://github.com/LukasKalbertodt/lumina-test
Bemerkenswert bei den Test-Projekten sind weniger die Projekte selber, als die Tatsache in welcher (kurzen) Zeit und mit wie wenig Code ich die geschrieben habe.
Außerdem werde ich später hier noch Screenshots vom Minecraft-Klon posten.


Ich wollte euch dieses Projekt eigentlich nur vorstellen, aber eine Sache wäre da noch: Ich würde mich über Leute freuen, die daran mit arbeiten wollen. Ich habe zwar schon mit einigen Kollegen aus der Uni daran gearbeitet, aber die haben erstmal keine Zeit dafür. Wenn ihr ernsthaftes Interesse habt, Ahnung von C++11/14 und auch ein wenig Erfahrung mit Grafikprogrammierung, meldet euch!

Ansonsten bin ich gespannt was ihr davon haltet ;)

LG
Lukas
 
Auf welchen Betriebssystemen läuft die Bibliothek? Anhand der Dateien auf GitHub würde ich schließen, das du unter Linux entwickelt hast.
Hört sich aber sehr gut an. :daumen:
 
Ich habe keine Plattform-abhängigen Bibliotheken genutzt und auch nur Standard-C++ geschrieben. Daher läuft es wohl auf allen Betriebssytemen :)
Das war auch von Anfang an mein Ziel. Bis jetzt hab ich es einfach zeitlich nicht geschafft unter Windows anzupassen. Wird aber bald nachgeholt ;)
 
Also meiner Meinung nach sehr interessant! Eine Frage: Hast Du schonmal darüber nachgedacht, die Bibliothek in Visual Studio einzubauen? Ich würde das sehr begrüßen :D

LG Philipp ;)
 
Grundsätzlich ein nettes Projekt und ja, OpenGL ist stellenweise wirklich ziemlich ugly - deswegen erstmal Respekt dafür, dass ihr euch da ein Design zusammenfummelt, das auch noch weitesgehend typensicher zu sein scheint.

Paar Fragen und Anmerkungen:

Ihr benutzt GLFW als festes Backend und habt auch noch irgendwie ein paar Dinge drin, um Nutzereingaben weiterzuleiten. Wäre es nicht eigentlich sinnvoller, solche Sachen dem User eurer Bibliothek zu überlassen oder zumindest optional zu halten? (Oder ist das optional?) So wie ich das jetzt nach ein bisschen Code überfliegen beurteilen kann, wollt ihr ja hauptsächlich OpenGL selbst wrappen, das kann auch dann noch sinnvoll sein, wenn man seine eigenen Contexts erstellt.


GLEW ist leider auch nicht mehr unbedingt das Mittel der Wahl zum Laden von Extensions, weil es zwar OpenGL 4.5 können will, zum Abfragen der Extensions aber veraltete Funktionen benutzt und damit keine Core Profile-Contexts unterstützt. Deswegen ist...
Code:
glewExperimental = GL_TRUE;
... auch keine echte Lösung für das Problem, denn das holt sich einfach mal für alle Funktionen spekulativ den Funktionspointer, der aber nicht zwangsläufig nullptr ist, wenn die Funktion vom gewählten Context gar nicht unterstützt wird. Sie muss nur vom Treiber implementiert werden.

Leider gibts keine Alternative, die auch nur annähernd so komfortabel wäre - ich selbst benutze gl3w mit nem modifizierten Header (für non-ARB-Extensions) und hab dann selbst ein paar Sachen geschrieben, um auf diverse Extensions zu prüfen, die ich nutzen möchte, allerdings ist das aufwändig.


Code:
bool RenderContext::s_creationLock = false;

void RenderContext::create() {

if (s_primedContext || s_creationLock) {
  logThrowGL("[RenderContext] You cannot create a RenderContext while "
  "another is primed or being created!");
}

s_creationLock = true;
Ich bin jetzt mal fies, das ist mir nur gerade so beim Code überfliegen aufgefallen. Ist das dafür da, um zu verhindern, dass zwei Threads gleichzeitig nen Context erstellen? Wenn ja, dann
- funktioniert das so nicht. Dafür müsste man Atomics nutzen (hat C++11 nativ dabei) und atomar exchangen, sonst habt ihr ne Race Condition, wie sie im Buche steht - oder aber, was auch passieren kann, wenn der Compiler entsprechend optimiert: Der Wert der Variable wird gar nicht verändert, weil ihr Wert nach den Zuweisungen nie benutzt wird.
- frage ich mich nach dem Sinn. Wenn ihr mehrere Contexts erlaubt, dann kann man das auch per Mutex eben locken, falls überhaupt nötig, dann bräuchte man jedenfalls keinen Fehler schmeißen. Falls nicht, ergibt eigentlich die komplette Abfrage keinen Sinn, weil an anderer Stelle festgestellt werden müsste, dass kein zweiter Context existieren darf. In dem Fall vielleicht mal böse sein und nen Singleton benutzen? :ugly:
 
Ihr benutzt GLFW als festes Backend und habt auch noch irgendwie ein paar Dinge drin, um Nutzereingaben weiterzuleiten. Wäre es nicht eigentlich sinnvoller, solche Sachen dem User eurer Bibliothek zu überlassen oder zumindest optional zu halten? (Oder ist das optional?) So wie ich das jetzt nach ein bisschen Code überfliegen beurteilen kann, wollt ihr ja hauptsächlich OpenGL selbst wrappen, das kann auch dann noch sinnvoll sein, wenn man seine eigenen Contexts erstellt.
Ja wir nutzen GLFW zum handeln von Fenstern und für alle Nutzereingaben. Ich stimme dir in deinen Anmerkungen weitgehend zu: Ich finde die Nutzung von GLFW nicht so geschickt. Vor allem nervt mich, dass Fenster und OGL-Kontext fest zusammen hängen. Leider fehlte aber die Zeit etwas eigenes zu erstellen. Außerdem muss man natürlich sagen, dass es grundsätzlich nicht gerade geschickt ist, alles selber neu zu entwickeln. Das Team von GLFW hat sicherlich viel Zeit darin investiert alles möglichst plattformunabhängig zu gestalten. Daher bin ich, was das angeht, ein wenig im Zwiespalt: Ich möchte es irgendwie selber machen, aber verschwende möglicherweise extrem viel Zeit.
Hast du sonst eine bessere Bibiothek im Sinn?

GLEW ist leider auch nicht mehr unbedingt das Mittel der Wahl zum Laden von Extensions, [...]
Leider gibts keine Alternative, die auch nur annähernd so komfortabel wäre [...]
Ja, ja. GLEW nutzen wir auch aus den selben Gründen wie GLFW: Zeit und "warum wiederholen, was andere schon mal gemacht haben?". Ich hätte auch gerne etwas besseres, aber ... man muss Nutzen/Zeit abwägen. Und wie du sagst: Alles andere ist aufwändig und unkomfortable.

Ich bin jetzt mal fies, das ist mir nur gerade so beim Code überfliegen aufgefallen. Ist das dafür da, um zu verhindern, dass zwei Threads gleichzeitig nen Context erstellen?
Nein ist es nicht. Ich hätte eventuell deutlicher sagen sollen, dass die ganze Library noch nicht annähernd fertig ist. Z.B. ist noch absolut kein Support für mehrere OGL-Kontexte oder Multithreading. Und an den Stellen, an denen noch was gemacht werden muss (also an Vielen), klaffen noch schreckliche Code-Lücken. Also keine Sorge: Diese Abfrage soll nichts wirklich bewirken ;-)


Aber ich möchte mich erstmal sehr bedanken, dass du dir die Zeit genommen hast und sogar den Code ein wenig durchgeschaut hast! Really appreciate that!

Ich frage mich auch, wie es weitergeht... Es sieht auf längere Zeit nicht so aus, als wenn ich großartig Freizeit hätte. Daher weiß ich nicht ob ich die Kraft habe da weiterzuarbeiten, vor allem da jetzt erstmal ein anderes wichtiges Hobbyprojekt ansteht. Ich habe auch letztens einiges über OpenGL NG gelesen und finde, dass es genau das ist, was ich haben möchte: Eine API auf einem viel niedrigeren Level. Das wäre super... Mal sehen wie schnell die Khronos Group da weiterkommt :P Ich bin jedenfalls sehr gespannt.

Danke nochmals!
 
Hast du sonst eine bessere Bibiothek im Sinn?
Was ich eigentlich meinte, ist, dass eure Library sich gar nicht (zwingend) selbst um den Context und das Input Handling kümmern müsste, sondern das von außen passiert, sodass folgendes möglich wird:
- man erzeugt selbst einen Context, z.B. mit GLFW oder SDL2.
- man teilt eurer Library mit "Hey, hier hast du Kontext, initialisiere dich mal"
- man rendert irgendeinen Blödsinn auf den Kontext und ist glücklich.

Zumindest würde ich die Kontexterzeugung vom eigentlichen OpenGL-Wrapper strikt trennen, da das auch die Art und Weise beeinflusst, wie man mit der Library Anwendungen entwickeln kann. Ich hab selbst was in der Mache, was vollständig modular arbeitet - aktuell mit SDL2 nen OpenGL-Context erzeugt, früher aber auch mal zusätzlich ein GLFW-Backend hatte und theoretisch auch z.B. einen Direct3D-Renderer erlaubt, solange irgendein Backend existiert, mit dem man einen Context dafür erzeugen kann. Trotzdem ist beides an sich unabhängig voneinander.

Ich meine, echte Männer schreiben ihren OpenGL-Code eh von Hand :ugly:, aber so wäre die Lib z.B. nicht vernünftig nutzbar, weil mich der Renderer dazu zwingen würde, auch damit den Context zu erstellen. Auch wenn der Rest der Library auch ohne die direkte Bindung funktionieren könnte.

Edit:
Und wie du sagst: Alles andere ist aufwändig und unkomfortable.
Wobei man sich wirklich mal gl3w anschauen könnte. Solange man sich auf das beschränkt, was ohnehin im glcorearb-Header zu finden ist, funktioniert das Teil ganz wunderbar.
 
Was ich eigentlich meinte, ist, dass eure Library sich gar nicht (zwingend) selbst um den Context und das Input Handling kümmern müsste[...]
Die Idee ist tatsächlich nicht schlecht, aber ich möchte nicht nur einen OpenGL Wrapper schreiben. Es soll schon mehr werden, eher ein komplettes Toolkit zur Entwicklung von Grafik Krams. Bei OpenGL Wrappern bin ich sicherlich nicht der Erste und ganz bestimmt nicht der Beste, der sowas probiert ;-)
Von daher soll es schon mehr sein als nur ein Wrapper.

Wobei man sich wirklich mal gl3w anschauen könnte. Solange man sich auf das beschränkt, was ohnehin im glcorearb-Header zu finden ist, funktioniert das Teil ganz wunderbar.
Ich werd mir das bei Gelegenheit mal anschauen. Aber diese Loader sind sowieso... argg. Ich warte vllt auf OGL NG und hoffe, dass sie das dort besser gelößt haben :D
 
Ich warte vllt auf OGL NG und hoffe, dass sie das dort besser gelößt haben
Ich hoffe, das dauert nicht noch ewig - zumal die ersten stabilen Treiber auch ihre Zeit brauchen. Eigentlich gäbe es für mich keinen besseren Zeitpunkt für OpenGL 5 als heute, muss mein OpenGL-Zeug eh größtenteils mal neu schreiben, da wäre es super, wenn die neue Version einfach schon da wäre. :D

Was die Loader angeht: Also los werden wir die garantiert nie, solange man seine libgl dynamisch linkt. Das Problem ist ja auch nicht das dynamische Linken an sich, sondern die Tatsache, dass GL einige tausend Funktionen hat, die abgefragt werden wollen. Aber dass GLEW einfach beim Support moderner Contexts pennt (OpenGL 3.2 kam wann? irgendwann 2008/9?), ist allein die Schuld von GLEW bzw. dessen Entwicklern.

Es soll schon mehr werden, eher ein komplettes Toolkit zur Entwicklung von Grafik Krams.
Ja, okay, ergibt Sinn. Würde aber trotzdem dafür sorgen, dass das ganze modular bleibt, für irgendwen hat das eigentlich immer irgendwelche Vorteile.

Bei OpenGL Wrappern bin ich sicherlich nicht der Erste und ganz bestimmt nicht der Beste, der sowas probiert
Mal mit LibGDX oder Slick2D in Java gearbeitet? Ich meine, ich hasse Java ohnehin und benutze es auch nur, wenn die Uni mich dazu zwingt, aber alles ist besser als LibGDX und Slick2D. :ugly:
Insofern stehen die Chancen nicht schlecht, dass da am Ende was brauchbare(re)s bei rauskommt.
 
Zurück