Was sind einige bewährte Methoden für OpenGL-Codierung (esp. W.r.t. Objektorientierung)?

StackOverflow https://stackoverflow.com/questions/166356

  •  03-07-2019
  •  | 
  •  

Frage

In diesem Semester habe ich einen Kurs in der Computergrafik an meiner Universität. Im Moment starten wir in einige der fortgeschrittenen Sachen wie Height zu erhalten, durchschnittlich Normalen, tesselation etc.

Ich komme aus einem objektorientierten Hintergrund, so versuche ich, alles zu setzen wir in wieder verwendbare Klassen tun. Ich habe eine Kamera Klasse gute Erfolge hat erstellen, da es vor allem auf den zu gluLookAt einen Anruf abhängig (), die ziemlich unabhängig vom Rest der OpenGL-Zustandsmaschine ist.

Aber ich habe einige Probleme mit anderen Aspekten. Verwendung von Objekten Primitiven darzustellen war nicht wirklich ein Erfolg für mich. Dies liegt daran, die tatsächlichen Anrufe auf so viele äußere Dinge, wie die zur Zeit gebunden Textur usw. abhängig machen Wenn Sie plötzlich von einer Oberfläche senkrecht zu einer Eckpunktnormale für eine bestimmte Klasse ändern wollen eine starke Kopfschmerzen verursacht.

Ich fange an, ob OO Prinzipien in OpenGL Codierung anwendbar sind zu fragen. Zumindest denke ich, dass ich meine Klassen weniger körnig machen.

Was ist die Stack-Überlauf-Community Ansichten über das? Was sind Ihre Best Practices für die OpenGL-Codierung?

War es hilfreich?

Lösung

Der praktischste Ansatz scheint die meist OpenGL-Funktionalität zu ignorieren zu sein, die nicht unmittelbar anwendbar ist (oder langsam ist, oder nicht Hardware beschleunigt, oder ist ein nicht mehr ein gutes Spiel für die Hardware).

OOP oder nicht, eine Szene zu machen, das sind verschiedene Typen und Objekte, die Sie haben in der Regel:

Geometrie (Maschen). Meist geschieht dies ist eine Anordnung von Scheitelpunkten und Anordnung von Indizes (d.h. drei Indizes pro Dreieck, auch bekannt als „Dreiecksliste“). Ein Knoten kann in einem beliebigen Format sein (beispielsweise nur eine float3 Position, eine Position float3 + float3 normal; a + float3 Position float3 normal + float2 texcoord, und so weiter und so weiter). Also ein Stück Geometrie definieren Sie brauchen:

  • definiert es ist Vertex-Format (könnte eine Bitmaske sein, eine Enumeration aus einer Liste von Formaten, ...),
  • hat Array von Eckpunkten, mit ihren Komponenten verschachtelt ( "verschachtelten arrays")
  • haben Array von Dreiecken.

Wenn Sie in OOP Land sind, können Sie diese Klasse nennen Mesh .

Werkstoffe - Dinge, die definieren, wie einige Stück Geometrie gemacht wird . Im einfachsten Fall könnte dies eine Farbe des Objekts, zum Beispiel. Oder ob Beleuchtung angewandt werden. Oder ob das Objekt mit Alpha-Mischung sein. Oder eine Textur (oder eine Liste von Texturen) zu verwenden. Oder ein Vertex / Fragment-Shader zu verwenden. Und so weiter, sind die Möglichkeiten endlos. Beginnen Sie, indem Dinge setzen, dass Sie müssen in Materialien. In OOP landen kann, dass die Klasse (Überraschung!) Ein Material .

aufgerufen werden

Szene - Sie haben Stücke von Geometrie, eine Sammlung von Material, Zeit zu definieren, was in der Szene ist. In einem einfachen Fall wird jedes Objekt in der Szene könnte durch definiert werden:  - Welche Geometrie verwendet es (Zeiger auf Mesh),  - Wie es gemacht werden soll (Zeiger auf Material)  - Wo es sich befindet. Dies könnte eine 4x4 Transformationsmatrix, oder eine 4x3 Transformationsmatrix, oder einen Vektor (Position), Quaternion (Orientierung) und einen anderen Vektor (Skala) sein. Nennen wir dies ein node in OOP Land.

Kamera . Nun, eine Kamera, ist nichts anderes als „wo sie platziert“ (auch hier eine 4x4 oder 4x3-Matrix, oder eine Position und Orientierung), sowie einige Projektionsparameter (Sichtfeld, Seitenverhältnis, ...).

Also im Grunde das ist es! Sie haben eine Szene, die eine Reihe von Knoten, die Meshes und Materialien verweisen, und Sie haben eine Kamera, die definiert, wo ein Betrachter ist.

Jetzt, wo tatsächliche OpenGL Anrufe setzen ist eine Design-Frage nur. Ich würde sagen, nicht setzen OpenGL Anrufe in Knoten oder Netz oder Materialklassen. Stattdessen macht so etwas wie OpenGLRenderer , die die Szene durchqueren können und alle Anrufe ausgeben. Oder, noch besser, macht etwas, das die Szene unabhängig von OpenGL durchläuft, und setzt untere Ebene ruft in OpenGL abhängige Klasse.

Also ja, alle der oben genannten ist so ziemlich plattformunabhängig. Gehen auf diese Weise, werden Sie feststellen, dass glRotate, glTranslate, gluLookAt und Freunde ziemlich nutzlos sind. Sie haben alle die Matrizen schon, nur um sie zu OpenGL übergeben. Dies ist, wie die meisten von real tatsächlicher Code in echten Spielen / Anwendungen funktionieren trotzdem.

Natürlich kann die oben durch komplexere Anforderungen kompliziert sein. Insbesondere können Materialien recht komplex sein. Meshes benötigen in der Regel viele verschiedene Formate Scheitels (z.B. gepackte Normalen für Effizienz) zu unterstützen. Szene Knoten müssen möglicherweise in einer Hierarchie organisiert werden (dies kann einfach sein - nur hinzufügen, Eltern / Kinder Zeiger auf den Knoten). Gehäutet Maschen und Animationen im allgemeinen Komplexität hinzuzufügen. Und so weiter.

Aber die Grundidee ist einfach: Es ist Geometrie, gibt es Materialien gibt es Objekte in der Szene. Dann einige kleine Stück Code ist in der Lage, sie zu machen.

In OpenGL Fall Maschen einrichten würde höchstwahrscheinlich erstellen / aktivieren / ändern VBO Objekte. Bevor ein Knoten gemacht wird, müßten Matrizen eingestellt werden. Und Material Einrichtung würden die meisten der verbleibenden Op berührenENGL Zustand (Blending, Texturieren, Beleuchtung, Combiner, Shadern, ...).

Andere Tipps

Objekttransformationen

Vermeiden Sie auf OpenGL abhängig Ihre Transformationen zu tun. Oft lernen Sie Tutorials, wie man mit dem Transformations-Matrix-Stack spielen. Ich würde mit diesem Ansatz nicht empfehlen, da Sie später eine Matrix benötigen, die nur durch diesen Stapel zugänglich sein wird, und deren Verwendung ist sehr lang, da der GPU-Bus ausgelegt ist, schnell zu sein von der CPU zu GPU, aber nicht in der anderen Richtung.

Master Objekt

Eine 3D-Szene wird oft als ein Baum von Objekten, um Objektabhängigkeiten zu kennen. Es gibt eine Debatte darüber, was an der Wurzel dieses Baumes sein sollte, eine Liste von Objekt oder ein Master-Objekt.

I Beratung eines Master-Objekt. Während es keine grafische Darstellung hat, wird es einfacher sein, weil Sie Rekursion effektiver zu nutzen in der Lage.

entkoppeln Szene Manager und Renderer

Ich bin nicht einverstanden mit @ejac, dass Sie eine Methode für jedes Objekt haben soll OpenGL Anrufe zu tun. eine separate Renderer Klasse Surfen Szene zu haben und alle OpenGL Anrufe tun wird Ihnen helfen, Ihre Szene Logik und OpenGL-Code zu entkoppeln.

Dies fügt einige Schwierigkeiten Design, sondern werden Ihnen mehr Flexibilität, wenn Sie jemals von OpenGL zu DirectX oder irgendetwas anderes API verwendet haben zu ändern.

Eine Standardtechnik ist die Objekt Effekt auf dem Render Zustand voneinander zu isolieren, indem Sie alle Änderungen von einigem Standard OpenGL Zustand innerhalb eines glPushAttrib / glPopAttrib Umfangs tun. In C ++ definiert eine Klasse mit Konstruktor mit

  glPushAttrib(GL_ALL_ATTRIB_BITS);
  glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);

und destructor mit

  glPopClientAttrib();
  glPopAttrib();

und verwenden Sie die Klasse RAH-Stil beliebigen Code zu wickeln, die mit dem OpenGL Zustand verunstaltet. Vorausgesetzt, Sie das Muster folgen, jedes Objekt Render-Methode eine „clean slate“ bekommt und muss nicht über Stoßen jedes möglicherweise geändert bisschen openGL Zustand zu befürchten zu sein, was es braucht.

Als Optimierung, in der Regel werden Sie den OpenGL-Zustand versetzt, sobald bei App Start in einem gewissen Zustand, der so nahe wie möglich ist, was alles will; diese minimisies die Anzahl der Anrufe, die innerhalb der geschoben Bereiche vorgenommen werden müssen.

Die schlechte Nachricht ist, diese sind nicht billig telefonieren. Ich habe noch nie wirklich untersucht, wie viele pro Sekunde Sie weg erhalten können; sicher genug, um in komplexen Szenen nützlich zu sein. Die Hauptsache ist, zu versuchen, die meisten Staaten zu machen, sobald Sie sie eingestellt haben. Wenn Sie eine Armee von Orks haben zu machen, mit verschiedenen Shader, Texturen usw. für Rüstung und die Haut, durchlaufen nicht über alle Orks Rendering Rüstung / Haut / Rüstung / Haut / ...; stellen Sie sicher, sobald der Staat für die Rüstung eingerichtet und machen all die Rüstung der Orcs, dann Setup die ganze Haut zu machen.

Wenn Sie nicht möchten, Ihre eigene Rolle die oben genannten Antworten funktionieren gut genug. Viele der Prinzipien, die erwähnt werden, sind in den meisten der Open-Source-Grafik-Engines implementiert. Szenengraphen ist eine Methode, um aus dem Direktmodus OpenGL wegbewegen.

Open ist eine Open-Source-Anwendung, die Ihnen eine große (vielleicht zu groß) Bibliothek von Werkzeugen gibt für tun OO 3D-Grafik, gibt es viele andere da draußen.

Ich habe in der Regel eine drawOpenGl () Funktion, pro Klasse, die gemacht werden kann, dass es opengl Anrufe enthält. Diese Funktion wird von der renderloop genannt. Die Klasse enthält alle Informationen für seine opengl Funktionsaufrufe benötigt, zB. über Position und Orientierung, so kann es seine eigene Transformation tun.

Wenn Objekte sind abhängig von ihnen, zum Beispiel. sie machen einen Teil eines größeren Objekt, dann diese Klassen in einer anderen Klasse zusammensetzen, die dieses Objekt darstellt. Welche seine eigene drawOpenGL () Funktion hat, die die drawOpenGL alle () Funktionen seiner Kinder ruft, so dass Sie rund um Position haben können / Orientierung fordert Push- und popmatrix verwendet wird.

Es ist schon einige Zeit, aber ich denke, etwas Ähnliches ist möglich, mit Texturen.

Wenn Sie zwischen Flächennormalen oder Vertex-Normalen wechseln wollen, dann lassen Sie das Objekt erinnern, ob seine eine oder die andere und haben 2 private Funktionen für jede Gelegenheit, dass drawOpenGL () ruft bei Bedarf. Es gibt sicherlich andere elegantere Lösungen (z. B. die Strategie Design-Muster oder etwas mit), aber dies konnte man arbeiten, soweit ich das Problem verstehen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top