Ausgewählte Projekte der Computergraphik (GraPro) - Exam.pdf

Ausgewählte Projekte der Computergraphik (GraPro) - Exam
Ausgewählte Projekte der Computergraphik (GraPro) - Exam Aufgabe 1) Du arbeitest an einem dreidimensionalen Modell eines komplexen Gebäudes für ein virtuelles Architekturrendering. Deine Aufgaben umfassen die Transformation von 3D-Objekten, die Anwendung fortgeschrittener Modellierungstechniken und die Implementierung von Rendering-Prozessen, um eine realistische Darstellung zu erzeugen. Dazu verw...

© StudySmarter 2024, all rights reserved.

Ausgewählte Projekte der Computergraphik (GraPro) - Exam

Aufgabe 1)

Du arbeitest an einem dreidimensionalen Modell eines komplexen Gebäudes für ein virtuelles Architekturrendering. Deine Aufgaben umfassen die Transformation von 3D-Objekten, die Anwendung fortgeschrittener Modellierungstechniken und die Implementierung von Rendering-Prozessen, um eine realistische Darstellung zu erzeugen. Dazu verwendest Du Werkzeuge wie Blender oder Maya.

a)

Transformationen und Modellierung: In deinem Gebäudeprojekt musst Du mehrere Transformationen durchführen.

  • Die Eingangstür des Gebäudes muss um 2 Einheiten nach rechts und 3 Einheiten nach vorne verschoben werden. Gib die Transformationsmatrix für diese Translation an und zeige, wie Du sie auf einen Punkt P (2, 0, 1) anwenden würdest.
  • Eine bestimmte Säule soll um 90 Grad um die y-Achse gedreht werden. Beschreibe die Rotationsmatrix für diese Transformation und zeige, wie sie auf den Vektor V (1, 1, 0) angewendet wird.
  • Eine Kugel soll um den Faktor 1.5 skaliert werden. Gib die Skalierungsmatrix an und exemplifiziere die Anwendung auf den Punkt Q (1, 2, 2).

Lösung:

Transformationen und Modellierung:

  • Translation: Um die Eingangstür des Gebäudes um 2 Einheiten nach rechts und 3 Einheiten nach vorne zu verschieben, verwenden wir die Translationsmatrix:
\[ \begin{pmatrix} 1 & 0 & 0 & 2 \ 0 & 1 & 0 & 0 \ 0 & 0 & 1 & 3 \ 0 & 0 & 0 & 1 \end{pmatrix} \]

Jetzt zeigen wir die Anwendung dieser Matrix auf den Punkt P (2, 0, 1):

\[ \begin{pmatrix} 1 & 0 & 0 & 2 \ 0 & 1 & 0 & 0 \ 0 & 0 & 1 & 3 \ 0 & 0 & 0 & 1 \end{pmatrix} \times \begin{pmatrix} 2 \ 0 \ 1 \ 1 \end{pmatrix} = \begin{pmatrix} 2 + 2 \ 0 + 0 \ 1 + 3 \ 1 \end{pmatrix} = \begin{pmatrix} 4 \ 0 \ 4 \ 1 \end{pmatrix} \]

Die neuen Koordinaten von P sind (4, 0, 4).

  • Rotation: Eine bestimmte Säule soll um 90 Grad um die y-Achse gedreht werden. Hier ist die Rotationsmatrix für diese Transformation:
\[ \begin{pmatrix} 0 & 0 & 1 & 0 \ 0 & 1 & 0 & 0 \ -1 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 \end{pmatrix} \]

Jetzt zeigen wir die Anwendung dieser Matrix auf den Vektor V (1, 1, 0):

\[ \begin{pmatrix} 0 & 0 & 1 & 0 \ 0 & 1 & 0 & 0 \ -1 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 \end{pmatrix} \times \begin{pmatrix} 1 \ 1 \ 0 \ 1 \end{pmatrix} = \begin{pmatrix} 0 \ 1 \ -1 \ 1 \end{pmatrix} \]

Der neue Vektor ist (0, 1, -1).

  • Skalierung: Eine Kugel soll um den Faktor 1.5 skaliert werden. Hier ist die Skalierungsmatrix:
\[ \begin{pmatrix} 1.5 & 0 & 0 & 0 \ 0 & 1.5 & 0 & 0 \ 0 & 0 & 1.5 & 0 \ 0 & 0 & 0 & 1 \end{pmatrix} \]

Jetzt zeigen wir die Anwendung dieser Matrix auf den Punkt Q (1, 2, 2):

\[ \begin{pmatrix} 1.5 & 0 & 0 & 0 \ 0 & 1.5 & 0 & 0 \ 0 & 0 & 1.5 & 0 \ 0 & 0 & 0 & 1 \end{pmatrix} \times \begin{pmatrix} 1 \ 2 \ 2 \ 1 \end{pmatrix} = \begin{pmatrix} 1.5 \ 3 \ 3 \ 1 \end{pmatrix} \]

Die neuen Koordinaten von Q sind (1.5, 3, 3).

b)

Rendering und Beleuchtung: Für dein Architekturmodell soll eine realistische Beleuchtung implementiert werden.

  • Beschreibe die Unterschiede zwischen diffusen und spekulären Reflexionen und wie sie in Phong Shading implementiert werden.
  • Angenommen, eine Punktlichtquelle befindet sich bei (10, 10, 10) und du hast eine Oberflächen-Normalen N (0, 1, 0). Berechne die Intensität des Lichts, das auf eine Fläche an der Position R (5, 5, 0) fällt. Die Materialeigenschaften der Fläche sind: Ambient-Koeffizient = 0.1, Diffus-Koeffizient = 0.7, Spekular-Koeffizient = 0.2 und die Beleuchtungskoeffizienten sind: Ambient = 1.0, Diffus = 1.0, Spekular = 1.0.

Lösung:

Rendering und Beleuchtung: Für dein Architekturmodell soll eine realistische Beleuchtung implementiert werden.

  • Unterschiede zwischen diffusen und spekulären Reflexionen:

Diffuse Reflexion:

  • Diffuse Reflexion entsteht, wenn Licht in alle Richtungen gleichmäßig von einer Oberfläche reflektiert wird.
  • Sie hängt nicht von der Betrachtungsrichtung ab, sondern nur vom Einfallswinkel des Lichts und der Materialeigenschaft.
  • Diffuse Reflexion wird verwendet, um matte oder raue Oberflächen zu simulieren.
  • Im Phong Shading wird dies durch die Lambert'sche Reflexion modelliert:
\( I_d = k_d (\mathbf{L} \cdot \mathbf{N}) I_L \)\[ \begin{align*} I_d &= \text{intensität der diffusen Reflexion} \ k_d &= \text{diffus-Koeffizient des Materials} \ \mathbf{L} &= \text{Vektor zur Lichtquelle} \ \mathbf{N} &= \text{Normale der Oberfläche} \ I_L &= \text{intensität des Lichts} \end{align*} \]

Spekuläre Reflexion:

  • Spekuläre Reflexion entsteht, wenn Licht spiegelartig reflektiert wird und die Reflexion stark abhängig vom Betrachtungswinkel ist.
  • Sie simuliert glänzende Oberflächen wie Metall oder polierte Materialien.
  • Im Phong Shading wird dies durch die spekuläre Reflexion modelliert:
\( I_s = k_s (\mathbf{R} \cdot \mathbf{V})^\alpha I_L \)\[ \begin{align*} I_s &= \text{intensität der spekulären Reflexion} \ k_s &= \text{Spekular-Koeffizient des Materials} \ \mathbf{R} &= \text{Reflexionsvektor des Lichts} \ \mathbf{V} &= \text{Betrachtungsrichtung} \ \alpha &= \text{Glanzexponent (Schärfe der Reflexion)} \ I_L &= \text{intensität des Lichts} \end{align*} \]
  • Für die Gesamtbeleuchtung im Phong Shading kombiniert man ambientes, diffuses und spekuläres Licht:
\( I = I_a + I_d + I_s \)\[ \begin{align*} I_a &= \text{intensität des ambienten Lichts} \ I_d &= \text{intensität der diffusen Reflexion} \ I_s &= \text{intensität der spekulären Reflexion} \end{align*} \]

Berechnung der Lichtintensität: Angenommen, eine Punktlichtquelle befindet sich bei (10, 10, 10) und du hast eine Oberflächen-Normalen N (0, 1, 0). Berechne die Intensität des Lichts, das auf eine Fläche an der Position R (5, 5, 0) fällt.Materialeigenschaften der Fläche:

  • Ambient-Koeffizient = 0.1
  • Diffus-Koeffizient = 0.7
  • Spekular-Koeffizient = 0.2
  • Ambient = 1.0
  • Diffus = 1.0
  • Spekular = 1.0

Schritte zur Berechnung der Lichtintensität:

  • Position des Lichts: \((10, 10, 10)\)
  • Position der Fläche: \((5, 5, 0)\)

Berechne den Lichtvektor \(\mathbf{L}\):

\[ \mathbf{L} = \mathbf{L_{pos}} - \mathbf{R} \] \[ \mathbf{L} = (10, 10, 10) - (5, 5, 0) \] \[ \mathbf{L} = (5, 5, 10) \]

Normalisiere den Lichtvektor \(\mathbf{L}\):

\[ \|\mathbf{L}\| = \sqrt{5^2 + 5^2 + 10^2} = \sqrt{25 + 25 + 100} = \sqrt{150} = 5\sqrt{6} \] \[ \mathbf{\hat{L}} = \frac{1}{5\sqrt{6}} (5, 5, 10) = \left( \frac{1}{\sqrt{6}}, \frac{1}{\sqrt{6}}, \frac{2}{\sqrt{6}} \right) \]

Berechne den Winkel zwischen \(\mathbf{L}\) und \(\mathbf{N}\):

\[ \mathbf{N} = (0, 1, 0) \] \[ \mathbf{N} \cdot \mathbf{L} = (0, 1, 0) \cdot \left( \frac{1}{\sqrt{6}}, \frac{1}{\sqrt{6}}, \frac{2}{\sqrt{6}} \right) = \frac{1}{\sqrt{6}} \]

Berechne die diffuse Komponente:

\[ I_d = I_L \cdot k_d \cdot \max(0, \mathbf{N} \cdot \mathbf{L}) \] \[ I_d = 1.0 \cdot 0.7 \cdot \frac{1}{\sqrt{6}} = 0.7 \cdot \frac{1}{2.45} \approx 0.286 \]

Berechne die spekuläre Komponente (angenommen der Betrachtungs- und Reflexionsvektor sind ideal):

\[ \mathbf{R} = 2 (\mathbf{N} \cdot \mathbf{L}) \mathbf{N} - \mathbf{L} \] \[ \mathbf{R} = 2 \cdot \frac{1}{\sqrt{6}} \cdot (0, 1, 0) - \left( \frac{1}{\sqrt{6}}, \frac{1}{\sqrt{6}}, \frac{2}{\sqrt{6}} \right) = \left( - \frac{1}{\sqrt{6}}, \frac{1}{\sqrt{6}}, - \frac{2}{\sqrt{6}} \right) \] \[ I_s = I_L \cdot k_s \cdot (\mathbf{R} \cdot \mathbf{V}) \] \[ I_s = 1.0 \cdot 0.2 \cdot (\mathbf{R} \cdot \mathbf{V}) \cdot \approx 0.2 \]

Die Gesamtintensität:

\[ I = I_a + I_d + I_s \] \[ I = 0.1 + 0.286 + 0.2 = 0.586 \]

Die Lichtintensität, die auf die Fläche fällt, beträgt ungefähr 0.586.

Aufgabe 2)

In der Computergrafik gibt es zwei grundlegende Verfahren zur Bildsynthese: Ray-Tracing und Rasterization.

  • Ray-Tracing simuliert das Verhalten von Lichtstrahlen, um realistische Effekte wie Spiegelungen, Brechungen und Schatten zu erzeugen. Diese Methode hat eine Zeitkomplexität von \( O(n^3) \).
  • Rasterization transformiert Objekte in ein Raster und scannt dabei Dreiecke, um sie zu pikselieren, was wesentlich schneller funktioniert als Ray-Tracing, mit einer Zeitkomplexität von \( O(n \log n) \).
  • Rasterization wird oft von Grafikkarten für Echtzeitanwendungen genutzt.
  • Eine Kombination beider Methoden wird als Hybrid Rendering bezeichnet.

a)

Erkläre den Unterschied zwischen Ray-Tracing und Rasterization hinsichtlich der Komplexität und der Anwendungen in der Computergrafik. Nenne jeweils ein Beispiel, wo die jeweilige Methode besonders vorteilhaft ist.

Lösung:

Unterschied zwischen Ray-Tracing und Rasterization hinsichtlich der Komplexität und der Anwendungen in der Computergrafik:

  • Ray-Tracing: Dieses Verfahren simuliert das Verhalten von Lichtstrahlen, wodurch realistische Effekte wie Spiegelungen, Brechungen und Schatten erzeugt werden. Die Zeitkomplexität von Ray-Tracing beträgt \(O(n^3)\) , was bedeutet, dass der Rechenaufwand exponentiell mit der Anzahl der Lichtstrahlen und Objekte im Bild steigt. Dadurch ist Ray-Tracing rechenintensiv und wird daher vor allem für vorgerenderte Szenen verwendet, bei denen die Bildqualität und die Genauigkeit im Vordergrund stehen.Beispiel: Ray-Tracing wird häufig in animierten Filmen und Werbespots verwendet, bei denen höchste Bildqualität und realistische Lichtverhältnisse gefragt sind.
  • Rasterization: Bei diesem Verfahren werden Objekte in ein Raster transformiert und Dreiecke gescannt, um sie zu pikselieren. Dies funktioniert wesentlich schneller als Ray-Tracing und hat eine Zeitkomplexität von \(O(n \log n)\) . Da Rasterization weniger rechenintensiv ist, wird sie oft von Grafikkarten für Echtzeitanwendungen genutzt, bei denen die Leistung und die Geschwindigkeit im Vordergrund stehen.Beispiel: Rasterization wird hauptsächlich in Videospielen und interaktiven Anwendungen verwendet, bei denen Echtzeit-Rendering erforderlich ist.
  • Hybrid Rendering: Um die Vorteile beider Methoden zu kombinieren, wird oft ein hybrides Rendering verwendet. Dabei können bestimmte Teile einer Szene mit Ray-Tracing und andere mit Rasterization gerendert werden, um eine Balance zwischen Bildqualität und Rendering-Geschwindigkeit zu erreichen.

b)

Angenommen, Du hast eine Szene mit \( n = 1000 \) Objekten. Berechne die theoretische Anzahl der Operationen für Ray-Tracing und Rasterization und veranschauliche damit den Unterschied in der Rechenzeit. Zeige die Berechnungen detailliert.

Lösung:

Berechnung der theoretischen Anzahl der Operationen für Ray-Tracing und Rasterization bei einer Szene mit \( n = 1000 \) Objekten:

  • Ray-Tracing:Die Zeitkomplexität von Ray-Tracing beträgt \( O(n^3) \).Das bedeutet, die Anzahl der Operationen ergibt sich aus der Formel \( n^3 \).Berechnen wir die Anzahl der Operationen für \( n = 1000 \):
    n = 1000Anzahl der Operationen = n^3 = 1000^3 = 1000 \times 1000 \times 1000 = 1.000.000.000
  • Rasterization:Die Zeitkomplexität von Rasterization beträgt \( O(n \log n) \).Das bedeutet, die Anzahl der Operationen ergibt sich aus der Formel \( n \log n \).Berechnen wir die Anzahl der Operationen für \( n = 1000 \):
    n = 1000\log n (Basis 2) ≈ 10 (Da \( \log_2(1000) \approx 10 \))Anzahl der Operationen = n \times \log n = 1000 \times 10 = 10.000
Fazit:Bei einer Szene mit \( n = 1000 \) Objekten ergibt sich für Ray-Tracing eine theoretische Anzahl von 1.000.000.000 Operationen, während Rasterization nur etwa 10.000 Operationen benötigt. Dies veranschaulicht den signifikanten Unterschied in der Rechenzeit zwischen den beiden Verfahren und zeigt, warum Rasterization oft für Echtzeitanwendungen bevorzugt wird.

c)

Diskutiere den Nutzen von Hybrid Rendering und beschreibe ein Szenario, in dem die Kombination von Ray-Tracing und Rasterization sinnvoll ist. Gehe dabei auf die Balance von Realismus und Performance ein.

Lösung:

Nutzen von Hybrid Rendering:Hybrid Rendering kombiniert die Vorteile von Ray-Tracing und Rasterization, um sowohl realistische als auch performante Bilddarstellungen zu ermöglichen. Dies geschieht, indem bestimmte Szenenbestandteile mit der einen Methode und andere mit der anderen Methode gerendert werden. So können besonders ressourcenintensive Effekte gezielt mit Ray-Tracing berechnet werden, während für weniger rechenintensive Aufgaben die schnellere Rasterization verwendet wird.Die Vorteile von Hybrid Rendering sind:

  • Balance von Realismus und Performance: Durch die Kombination beider Methoden kann eine Balance zwischen realistischer Darstellung und schneller Berechnung gefunden werden.
  • Optimierte Ressourcennutzung: Rechenressourcen können effizienter genutzt werden, indem komplexe Berechnungen nur dort angewendet werden, wo sie wirklichen Mehrwert bieten.
  • Anpassungsfähigkeit: Hybrid Rendering lässt sich an unterschiedliche Szenarien und Anforderungen anpassen, je nachdem, welcher Teil der Szene besonders realistisch oder performant sein muss.
Szenario für den Einsatz von Hybrid Rendering:Ein typisches Beispiel für den Einsatz von Hybrid Rendering ist die Darstellung einer spielbaren Echtzeitszene in einem modernen Videospiel:
  • Ray-Tracing für kritische Licht- und Spiegelungseffekte: Reflektionen auf Wasseroberflächen, Glas oder glänzenden Metallen können mithilfe von Ray-Tracing berechnet werden, um einen hohen Grad an Realismus zu erzielen. Diese Effekte tragen stark zur visuellen Immersion bei und sind oft auf bestimmte Bereiche der Szene beschränkt.
  • Rasterization für allgemeine Geometrie und Animationen: Die restliche Szene, darunter Umgebungsgeometrie, Charaktere und Animationen, wird mittels Rasterization gerendert. Diese Methode ist schneller und kann problemlos mit der hohen Zahl an Polygonen umgehen, die in Echtzeitszenen auftreten.
Durch diese Kombination kann eine ansprechende, realistische Szene geschaffen werden, ohne die Performance drastisch zu beeinträchtigen. Besonders in schnelllebigen Szenarien wie Videospielen, in denen sowohl realistische Visualisierungen als auch hohe Bildraten erforderlich sind, ist Hybrid Rendering ideal geeignet.

Aufgabe 3)

Du bearbeitest eine Szene in einem 3D-Rendering-Projekt, in der Du realistische Beleuchtung und Schattenberechnungen umsetzen möchtest. Die Szene enthält eine primäre Lichtquelle, mehrere reflektierende Objekte und muss sowohl harte als auch weiche Schatten korrekt wiedergeben. Für diese Aufgabe sollst Du verschiedene Techniken der Global Illumination und Schattenberechnung auf die Szene anwenden.

b)

b) Vergleiche und kontrastiere die Techniken Photon Mapping, Radiosity und Path Tracing hinsichtlich ihrer Fähigkeit, die realistische Beleuchtung und Schatten in der Szene zu berechnen. Diskutiere Vor- und Nachteile jeder Technik und gib an, welche Technik Du für die aktuelle Szene bevorzugen würdest. Beziehe Dich dabei sowohl auf die Qualität des Ergebnisses als auch auf die Berechnungsaufwand.

Lösung:

b) Die Techniken Photon Mapping, Radiosity und Path Tracing sind alle Methoden der globalen Beleuchtung, die unterschiedliche Ansätze zur Simulation realistischer Beleuchtung und Schattenberechnung in 3D-Szenen bieten. Im Folgenden werden sie verglichen und kontrastiert:

Photon Mapping

  • Vorteile:- Kann sowohl indirekte Beleuchtung als auch caustics (lichtfokussierende Effekte) effizient simulieren.- Bietet eine gute Balance zwischen Genauigkeit und Berechnungsaufwand.- Gut geeignet für Szenen mit reflektierenden und refraktierenden Oberflächen.
  • Nachteile:- Komplexe Implementierung.- Kann Artefakte wie Photon Noise aufweisen, besonders in feineren Details.- Kann durch begrenzte Photonanzahl in großen Szenen ungenau werden.

Radiosity

  • Vorteile:- Besonders gut für diffuse Oberflächen geeignet, da es die Energiebilanz zwischen Oberflächen effizient berechnet.- Liefert weiche und realistische Schatten für diffuse Szenen.- Kann präzise und artefaktfreie Beleuchtung in Innenräumen liefern.
  • Nachteile:- Nicht effizient für Szenen mit vielen spiegelnden oder transparenten Materialien.- Hoher Berechnungsaufwand bei komplexen Geometrien.- Benötigt oft ein hohes Maß an Speicherplatz und Rechenleistung.

Path Tracing

  • Vorteile:- Sehr flexibel und kann realistische Bilder durch stochastische Nachverfolgung von Lichtpfaden erzeugen.- Kann komplexe Beleuchtungsszenarien, wie indirekte Beleuchtung, weiche Schatten und caustics, ohne zusätzliche Tricks simulieren.- Führt zu sehr realistischen Ergebnissen.
  • Nachteile:- Hoher Rechenaufwand, da viele Lichtpfade verfolgt werden müssen, um Rauschen zu reduzieren.- Lange Renderzeiten, besonders für hochqualitative Ergebnisse.- Benötigt Sampling-Strategien, um effektiv zu sein, was die Implementierung komplexer machen kann.

Bevorzugte Technik für die aktuelle Szene

Für die aktuelle Szene, die sowohl harte als auch weiche Schatten sowie reflektierende Objekte enthält, würde ich Path Tracing bevorzugen, obwohl es rechenintensiv ist. Path Tracing bietet den Vorteil, dass es eine sehr realistische Darstellung komplexer Beleuchtungsszenarien ermöglicht. Es kann sowohl die harten Schatten von einer primären Lichtquelle als auch die weichen Schatten und indirekte Beleuchtung, die durch reflektierende Objekte entstehen, akkurat simulieren. Trotz der langen Renderzeiten und des hohen Berechnungsaufwands führt es zu qualitativ hochwertigen Bildern, die in der aktuellen Szene wünschenswert sind. Mit modernen Optimierungstechniken und ausreichenden Rechenressourcen kann Path Tracing die beste Wahl sein, um das gewünschte Maß an Realismus zu erreichen.

c)

c) Implementiere eine Methode zur Berechnung weicher Schatten in der Szene unter Verwendung von Shadow Maps. Beschreibe den Algorithmus und seine Schritte im Detail, und erkläre, wie Du Antialiasing berücksichtigen würdest, um Schattenartefakte zu minimieren. Nutze dazu Pseudocode, um Deine Lösung zu veranschaulichen.

'Pseudocode:  Function GenerateSoftShadows(scene, lightSource)\tInitialize shadowMap\tFor each sample in lightSource\t\tGenerate shadow map for the sample\t\tAccumulate the results in shadowMap\tCalculate average shadow value\tApply Antialiasing to shadow edges\tReturn final shadow map'

Lösung:

c) Um weiche Schatten in der Szene zu berechnen, kann man eine Methode unter Verwendung von Shadow Maps implementieren. Der Algorithmus zur Berechnung weicher Schatten durch Verwendung von Shadow Maps beinhaltet mehrere Schritte. Hier ist eine detaillierte Beschreibung des Algorithmus und wie Antialiasing berücksichtigt werden kann:

Algorithmus zur Berechnung weicher Schatten

Der Hauptansatz besteht darin, mehrere Shadow Maps zu generieren, indem man verschiedene Lichtproben verwendet und die Ergebnisse mittelt, um weichere Schatten zu erhalten.

Die Schritte des Algorithmus sind wie folgt:

  1. Initialisieren einer Shadow Map: Erstelle eine leere Shadow Map, die die Schatteninformationen sammeln wird.
  2. Proben der Lichtquelle: Erzeuge mehrere Proben der Lichtquelle, um unterschiedliche Lichtwinkel zu simulieren. Dies führt zu weichen Schattenkanten.
  3. Generiere Shadow Maps für jede Probe: Für jede Lichtprobe generiere eine Shadow Map, indem Du die Szene aus der Perspektive der Lichtquelle renderst. Berechne für jeden Punkt in der Szene, ob er im Schatten liegt oder nicht.
  4. Ergebnisse akkumulieren: Füge die Ergebnisse der einzelnen Shadow Maps zur Initialisierten Shadow Map hinzu.
  5. Mittlere Schattenwerte berechnen: Berechne den durchschnittlichen Schattenwert, indem Du die akkumulierenden Schatteninformationen mittelt.
  6. Antialiasing anwenden: Verwende Techniken wie Percentage-Closer Filtering (PCF) oder andere Antialiasing-Methoden, um Schattenartefakte zu minimieren und die Schattenränder zu glätten.
  7. Erstelle die finale Shadow Map: Nutze die berechneten Schattenwerte zur Erstellung der finalen Shadow Map, die weiche Schatten enthält.

Pseudocode

Function GenerateSoftShadows(scene, lightSource)\tInitialize shadowMap to zero values\tNumSamples = 16  // Number of samples for soft shadows\tFor each sample in NumSamples:\t\tlightSample = SampleLightPosition(lightSource, sample)\t\tshadowMapSample = GenerateShadowMap(scene, lightSample)\t\tAccumulate(shadowMap, shadowMapSample)\tEndFor\t// Calculate average shadow value\tFor each pixel in shadowMap:\t\tshadowMap[pixel] /= NumSamples\tEndFor\t\t// Apply Antialiasing (Percentage-Closer Filtering)\tAntialiasing(shadowMap)\t\tReturn shadowMapFunction GenerateShadowMap(scene, lightSample)\t// Render the scene from the light's perspective and generate depth map\tshadowMapSample = RenderDepthMap(scene, lightSample)\tFor each pixel in shadowMapSample:\t\tif IsInShadow(pixel, shadowMapSample)\t\t\tshadowMapSample[pixel] = 1\t\telse\t\t\tshadowMapSample[pixel] = 0\tEndFor\tReturn shadowMapSampleFunction Antialiasing(shadowMap)\t// Apply Percentage-Closer Filtering to smooth shadow edges\tFor each pixel in shadowMap:\t\tshadowValue = 0\t\tFor each offset in FilterKernel:\t\t\tshadowValue += Sample(shadowMap, pixel + offset)\t\tEndFor\t\tshadowMap[pixel] = shadowValue / FilterKernel.size()\tEndFor

Erklärung des Pseudocodes

  • GenerateSoftShadows: Diese Funktion initialisiert eine Shadow Map und erzeugt mehrere Shadow Maps durch Probenahme der Lichtquelle. Die Ergebnisse werden akkumuliert und gemittelt, um weiche Schatten zu erzeugen. Schließlich wird Antialiasing angewendet, um die Schattenkanten zu glätten.
  • GenerateShadowMap: Diese Funktion generiert eine Shadow Map aus der Perspektive einer Lichtprobe, indem sie prüft, ob jeder Pixel im Schatten liegt.
  • Antialiasing: Diese Funktion wendet Percentage-Closer Filtering (PCF) an, um die Schattenkanten zu glätten und Schattenartefakte zu minimieren.

Durch diesen Ansatz können weiche Schatten realistisch simuliert werden, indem mehrere Lichtproben verwendet und Antialiasing-Techniken angewendet werden, um ein hochwertigeres Resultat zu erzielen.

Aufgabe 4)

Du planst, eine einfache 3D-Szene mit OpenGL zu erstellen und möchtest sie später in WebGL portieren. Die Szene besteht aus einem rotierenden Würfel, der mit einer Textur versehen ist und sich kontinuierlich um seine eigene Achse dreht. Beschreibe detailliert, wie Du dies mit OpenGL umsetzen würdest.

a)

  • Initialisierung und Aufbau: Beschreibe die Schritte zur Initialisierung der OpenGL Umgebung (z.B. OpenGL Kontext, Shaders, Buffers) und zur Erstellung der Transformationen (Translation, Rotation, Skalierung) für den rotierenden Würfel.
  • Stelle sicher, dass Deine Antwort die mathematische Formulierung der Transformationen und die Implementierung der Buffer in \texttt{OpenGL C/C++} beinhaltet.

Lösung:

  • Initialisierung und Aufbau: Um eine einfache 3D-Szene mit einem rotierenden, texturierten Würfel in OpenGL zu erstellen, müssen mehrere Schritte zur Initialisierung und Konfiguration der OpenGL-Umgebung durchgeführt werden. Hier ist eine detaillierte Schritt-für-Schritt-Anleitung:
  • 1. OpenGL Kontext und Fenster erstellen:
      // Initialisiere die GLFW-Bibliothek, die für die Erstellung des Fensters zuständig ist                                 if (!glfwInit()) { return -1; } // Erstelle ein Fenster mit der GLFW-Funktion GLFWwindow* window = glfwCreateWindow(800, 600, 'Rotierender Würfel', nullptr, nullptr); if (!window) { glfwTerminate(); return -1; } // Setze den erstellten Fensterkontext als aktuellen Kontext glfwMakeContextCurrent(window); // Initialisiere GLEW (OpenGL Extension Wrangler Library), um moderne OpenGL-Funktionen zu nutzen glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { return -1; }  
  • 2. Shader-Programme laden und kompilieren:
      // Vertex-Shader (vshader.glsl) const char* vertexShaderSource = ' #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; uniform mat4 MVP; out vec2 TexCoord; void main() { gl_Position = MVP * vec4(aPos, 1.0); TexCoord = aTexCoord; } '; // Fragment-Shader (fshader.glsl) const char* fragmentShaderSource = ' #version 330 core out vec4 FragColor; in vec2 TexCoord; uniform sampler2D texture1; void main() { FragColor = texture(texture1, TexCoord); } '; // Shader Kompilierungs- und Linkprozess GLuint vertexShader, fragmentShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader); fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); // Shader Programm erstellen GLuint shaderProgram; shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); // Shaders löschen, da sie nicht mehr benötigt werden glDeleteShader(vertexShader); glDeleteShader(fragmentShader);  
  • 3. Vertex-, Buffer-Daten und Textur konfigurieren:
      float vertices[] = { // Positionen und Texturkoordinaten // Vorderseite -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, ... }; GLuint VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Positionsattribut konfigurieren glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // Texturattribut konfigurieren glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);  
  • 4. Transformationen anwenden:
      // Mathematische Formulierung der Transformationen glm::mat4 model = glm::mat4(1.0f); model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f)); // Rotation um die Y-Achse glm::mat4 view = glm::mat4(1.0f); view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); // Kamera zurücksetzen glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); glm::mat4 MVP = projection * view * model; // Die Model-View-Projection Matrix zum Vertex-Shader senden unsigned int modelLoc = glGetUniformLocation(shaderProgram, 'MVP'); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(MVP));  

b)

  • Texturierung und Rendering: Erkläre den Prozess, wie Du eine Textur auf den rotierenden Würfel aufbringst und beschreibe den Rendering-Prozess. Gehe auf die Schritte vom Laden des Bildes über die Texturkoordinaten bis hin zur Ausgabe des Bildes ein.
  • Stelle sicher, dass Du in Deiner Erklärung die Rolle des Fragment Shaders ausführlich behandelst und den entsprechenden Code in \texttt{OpenGL C/C++} beifügst.

Lösung:

  • Texturierung und Rendering: Um eine Textur auf den rotierenden Würfel in OpenGL aufzubringen und die Szene zu rendern, müssen folgende Schritte unternommen werden:
  • 1. Bild laden und Textur erzeugen:
      // STB Image Library wird verwendet, um das Bild zu laden #define STB_IMAGE_IMPLEMENTATION #include  GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); // Textur-Wrap-Parameter setze glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Textur-Filter setze glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Bild laden int width, height, nrChannels; unsigned char *data = stbi_load('path/to/your/texture.jpg', &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << 'Failed to load texture' << std::endl; } // Speicher freigeben stbi_image_free(data);  
  • 2. Texturkoordinaten zu den Vertexdaten hinzufügen:
      // Beispielkoordinaten des Würfels (Position, Texturkoordinate) float vertices[] = { -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.5f,  0.5f, -0.5f,  1.0f, 1.0f, -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // und so weiter für die anderen Seiten des Würfels... }; GLuint VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Positionsattribut glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // Texturattribut glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);  
  • 3. Fragment Shader (FRAGMENT SHADER - HINZUFÜGEN):
      // Fragment-Shader (fshader.glsl) const char* fragmentShaderSource = ' #version 330 core out vec4 FragColor; in vec2 TexCoord; uniform sampler2D texture1; void main() { // Die Textur als Farbe des Fragments verwenden FragColor = texture(texture1, TexCoord); }'; GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); GLuint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glDeleteShader(fragmentShader); glUseProgram(shaderProgram);  
  • 4. Rendering-Schleife:
      while (!glfwWindowShouldClose(window)) { // Bildschirm löschen glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Transformationen (detaillierte Schritte wie zuvor) glm::mat4 model = glm::rotate(glm::mat4(1.0f), (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f)); glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f); glm::mat4 MVP = projection * view * model; unsigned int modelLoc = glGetUniformLocation(shaderProgram, 'MVP'); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(MVP)); // Binde und aktiviere Textur glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(glGetUniformLocation(shaderProgram, 'texture1'), 0); // Rendera den Würfel glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 36); glfwSwapBuffers(window); glfwPollEvents(); }  
Sign Up

Melde dich kostenlos an, um Zugriff auf das vollständige Dokument zu erhalten

Mit unserer kostenlosen Lernplattform erhältst du Zugang zu Millionen von Dokumenten, Karteikarten und Unterlagen.

Kostenloses Konto erstellen

Du hast bereits ein Konto? Anmelden