Wir zeichnen ein erstes 3D Objekt, bestimmen Vertex Koordinaten und Farben.

Ein Quadrat zeichnen

Erstellen Sie eine neue Klasse Scene. Hier wollen wir künftig alles kapseln was mit dem Inhalt unserer 3D Szene zu tun hat. Denken Sie dabei an die folgenden Schritte:

  • Erstellen Sie eine neue Header-Datei: scene.h
  • Erstellen Sie eine neue Implementierungs-Datei: scene.cpp
  • Fügen Sie ein #include statement in der renderer.h Datei ein damit die Scene dort verwendet werden kann.

Die Szene

Füllen Sie die neue scene.h und scene.cpp mit Inhalt…

scene.h

#pragma once #define GLFW_INCLUDE_GLEXT #include <GLFW/glfw3.h> class Scene { public: Scene(); ~Scene(); void render(GLFWwindow *window) const; };

scene.cpp

#include "scene.h" Scene::Scene() { } Scene::~Scene() { } void Scene::render(GLFWwindow *window) const { int width, height; glfwGetFramebufferSize(window, &width, &height); double ratio = width / static_cast<double>(height); glViewport(0, 0, width, height); glClearColor(0.29f, 0.36f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-ratio, ratio, -1.0, 1.0, 1.0, -1.0); glBegin(GL_QUADS); glColor3f(0.5f, 0.73f, 0.14f); glVertex3f(-0.6f, 0.0f, 0.0f); glVertex3f(0.0f, -0.6f, 0.0f); glVertex3f(0.6f, 0.0f, 0.0f); glVertex3f(0.0f, 0.6f, 0.0f); glEnd(); }

Selbststudium

Untersuchen Sie den Code Zeile für Zeile und nutzen Sie eine Suchmaschine Ihrer Wahl um die einzelnen OpenGL Funktionsaufrufe nachzuschlagen. Auch GitHub Copilot oder ChatGPT können dabei nützlich sein. Diesen Code, so oder so ähnlich finden Sie in diversen Online-Tutorials. Stellen Sie sicher, dass Sie alles verstehen.

Anschließend erstellen Sie eine Szene und rendern diese in der while-loop.

void Renderer::start() { Scene foreground; while (!glfwWindowShouldClose(window)) { foreground.render(window); glfwSwapBuffers(window); glfwPollEvents(); } }

Multisampling aktivieren

Anti-Aliasing ist eine Methode um Alias-Effekte zu verringern. Eine Methode dazu ist das sog. Multisampling. Dazu werden pro Bildschirmpixel mehrere Subpixel berechnet. Die beiden verlinkten Artikel helfen dabei das Konzept zu verstehen. Dieser Vorgang geschieht in zwei einfachen Schritten. Zuerst müssen Sie der API mitteilen, dass beim Erzeugen des Fensters zusätzlicher Platz für die zusätzlichen Pixel bereitgestellt werden soll. Binden Sie den folgenden Code im Renderer-Konstruktor ein, bevor das Fenster erzeugt wird. Anschließend müssen Sie Multisampling als Feature aktivieren.

Renderer::Renderer(const std::string &title, uint32_t width, uint32_t height) { ... glfwWindowHint(GLFW_SAMPLES, 4); window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); ... glEnable(GL_MULTISAMPLE); }

Unterschiede in der Implementierung

Je nachdem was Ihre Hardware kann und welche Treiber Sie installiert haben, kann das Ergebnis variieren. Testen Sie ob Sie auf Ihrem System einen Unterschied in der Qualität sehen können. Falls Sie keinen Unterschied sehen, ist es möglich, dass Ihre OpenGL Implementierung dieses Feature nicht von Hause aus mitbringt. Für den weiteren Verlauf dieses Moduls ist dieses Feature nicht zwingend erforderlich.

Framerate (FPS) anzeigen

Damit wir auf der Konsole ein Lebenszeichen unserer Engine bekommen, wollen wir dort die aktuelle Bildwiederholrate ausgeben. Wir definieren dazu in unserer Renderer-Klasse eine neue Funktion printFps und die nötigen private Membervariablen.

renderer.h

class Renderer { public: ... void printFps(); private: ... double previousTime = 0.0; uint32_t frameCount = 0; uint32_t fps = 0; };

renderer.cpp

void Renderer::printFps() { double currentTime = glfwGetTime(); if (currentTime - previousTime >= 1.0) { uint32_t fps = frameCount; std::cout << "FPS: " << fps << std::endl; frameCount = 0; previousTime = currentTime; } frameCount++; }

Rufen Sie printFps() in Ihrem Renderloop auf und Sie sollten eine Ausgabe auf der Konsole erhalten.

void Renderer::start() { Scene foreground; while (!glfwWindowShouldClose(window)) { foreground.render(window); glfwSwapBuffers(window); glfwPollEvents(); printFps(); } }

Vertical Sync aktivieren

Zuletzt wollen wir noch etwas Energie sparen indem wir der Grafikkarte mitteilen, dass wir unseren Rendervorgang mit der Bildwiederholrate des Monitors synchronisieren wollen. Fügen Sie dazu die folgende Zeile im Renderer-Konstruktor ein, nachdem das Fenster erzeugt wurde. Wichtig: Dies ist lediglich eine Anweisung die dem Grafikkartentreiber unsere Vorliebe mitteilt. Der Benutzer kann in anderen Tools, beispielsweise in der NVIDIA Systemsteuerung dieses Verhalten überschreiben.

Renderer::Renderer(const std::string &title, uint32_t width, uint32_t height) { ... glfwSwapInterval(1); }

Hausaufgabe

  • Räumen Sie Ihren Code auf, schreiben Sie Kommentare und machen Sie sich Notizen für die Prüfung.
  • Bereiten Sie eigenständig bis zur nächsten Veranstaltung Kapitel 4 vor: Implementieren Sie dazu das Tutorial von meiner Website und ziehen Sie weitere Quellen zu Rate um exakt zu verstehen was die Software macht und warum.