Answer to Question 1
a: Die Farben können auf dem Monitor A'' kräftiger wirken, weil sein Farbraum größer ist und somit eine größere Bandbreite an Farben darstellen kann, insbesondere im Bereich der orange-roten Töne.

b: Alle Chromazitätswerte, die innerhalb des Gamuts A' liegen und nicht im Gamut B enthalten sind, können mit Hilfe des zu A' gehörigen Monitors korrekt gedruckt werden. Ich würde die Fläche innerhalb von Gamut A' und außerhalb von Gamut B markieren.

c: Die Chromazitätswerte im CIE 1931 Farbraum werden berechnet als 
x = X / (X + Y + Z) und y = Y / (X + Y + Z). Also:

x = 0.5 / (0.5 + 0.3 + 0.2) = 0.5 / 1 = 0.5
y = 0.3 / (0.5 + 0.3 + 0.2) = 0.3 / 1 = 0.3

Die Chromazitätswerte wären also (x, y) = (0.5, 0.3). Diese Werte würde ich an der entsprechenden Stelle im Chromatizitätsdiagramm eintragen, indem ich einen Punkt bei (0.5, 0.3) markiere.

d: Der (gekrümmte) Rand des Chromatizitätsdiagramms stellt die Spektralfarbzüge dar, also die Farben maximaler Sättigung, die durch einzelne Wellenlängen des sichtbaren Lichts repräsentiert werden. Der Randverlauf gibt an, welche reinen Spektralfarben sichtbar sind.

e: Um die vollgesättigte Farbvalenz zur Farbe c mit dem Weißpunkt w zu bestimmen, zeichnet man im Chromatizitätsdiagramm eine direkte Linie vom Weißpunkt w durch den Punkt c bis zum Rand des Spektralfarbzuges. Der Schnittpunkt dieser Linie mit dem Rand ist die vollgesättigte Farbvalenz zur Farbe c.





****************************************************************************************
****************************************************************************************




Answer to Question 2
Teilaufgabe a):

- Lichttransportpfad (1): Dieser Pfad repräsentiert die direkte Beleuchtung von der Lichtquelle zur Kamera ohne jegliche Wechselwirkung mit einem Objekt. Dieser Pfad kann durch Whitted-Style Raytracing erzeugt werden, da Whitted-Style Raytracing direkte Sichtbarkeit zwischen Lichtquellen und Kamera berücksichtigt.
- Lichttransportpfad (2): Dieser Pfad beschreibt die Reflexion des Lichts von der Wand zur Kamera. Da die Wand diffus reflektierend ist (k_d > 0), und Whitted-Style Raytracing ideal für glänzende Reflexionen konzipiert ist, kann dieser Pfad ebenfalls erzeugt werden.
- Lichttransportpfad (3): Dieser Pfad bezieht sich auf die Transmission (Durchgang) des Lichts durch den Glasblock. Whitted-Style Raytracing unterstützt die Brechung von Licht, daher kann dieser Pfad korrekt gerendert werden.
- Lichttransportpfad (4): Hier interagiert das Licht sowohl mit dem grünen Boden als auch mit der roten Wand, bevor es die Kamera erreicht. Da Whitted-Style Raytracing keine indirekte Beleuchtung berücksichtigt, in der Licht mehrfach von Oberflächen reflektiert wird, bevor es die Kamera erreicht (bekannt als Global Illumination), kann dieser Pfad nicht erzeugt werden.

Teilaufgabe b):

Um das resultierende Bild der Kamera mittels Whitted-Style Raytracing zu skizzieren, würden wir die Bildebene in Bereiche unterteilen, die durch die Strahlen (r_1) bis (r_4) auf der Bildebene festgelegt sind, und die Bereiche entsprechend der Farbe der Oberfläche markieren, von der das Licht reflektiert oder transmittiert wird. Da Pfad (1) zu keinem Objekt führt und Pfad (4) aufgrund mehrfacher Reflexionen nicht von Whitted-Style Raytracing erfasst wird, haben wir folgende Situation:

- Bereich um (r_1): Dieser Bereich bleibt schwarz, weil kein Licht die Kamera direkt erreicht.
- Bereich um (r_2): Dieser Bereich wird rot sein, da das Licht von der roten Wand reflektiert wird und in die Kamera gelangt.
- Bereich um (r_3): Dieser Bereich wird das durchscheinende Licht des Glasblocks zeigen und somit die Brechung darstellen; jedoch, da der Glasblock als vollkommen durchsichtig (k_t = 1) ohne Absorption beschrieben ist, wird dieser Bereich einen Teil des Lichts in der Farbe des grünen Bodens oder der roten Wand darstellen, je nachdem, welcher Teil des Glasblocks vom Strahl durchdrungen wird.
- Bereich um (r_4): Dieser Bereich bleibt schwarz, weil der Lichtpfad (4) nicht von Whitted-Style Raytracing unterstützt wird und daher als nicht sichtbar angenommen wird.

Die Farbunterschiede aufgrund der unterschiedlichen Intensität und Farbmischung durch die Brechung wären komplizierter zu berechnen und würden detailliertere Informationen über den Brechungsindex, die Dicke des Glases und die genaue Farbe des Lichtes benötigen. In einer allgemeinen Skizze würde man also die genannten Bereiche rot und schwarz markieren und den durch den Glasblock sichtbaren Bereich basierend auf den simplifizierten Annahmen gestalten.





****************************************************************************************
****************************************************************************************




Answer to Question 3
a) Die Abbildungen (a) bis (d) zeigen verschiedene Komponenten des Phong-Beleuchtungsmodells, wie es in der Computergrafik verwendet wird. Hier sind die Komponenten, die durch jede Abbildung beschrieben werden:

- Abbildung (a): Dies stellt die Ambient-Komponente dar. Sie ist unabhängig vom Winkel und sorgt für eine grundlegende Helligkeit jeder Oberfläche.
- Abbildung (b): Hier sieht man die Diffuse-Komponente. Ihre Intensität hängt vom Kosinus des Winkels zwischen der Lichtrichtung und der Normalen der Oberfläche ab.
- Abbildung (c) und Abbildung (d): Beide zeigen die Spekulare-Komponente. Der Hauptunterschied zwischen diesen beiden besteht in der "Wölbung" der Kurve, was auf den Exponenten des Spekularterms im Phong-Modell zurückzuführen ist.

b) Die Variation zwischen Abbildung (c) und Abbildung (d) wird durch den Glanzgrad (auch als Spekular-Exponent oder Shininess bezeichnet) verursacht. Je höher der Glanzgrad, desto kleiner und konzentrierter ist der helle Fleck (der sogenannte "Specular Highlight"). In Abbildung (d) ist der helle Fleck kleiner und konzentrierter verglichen mit Abbildung (c), was darauf hindeutet, dass der Glanzgrad in Abbildung (d) höher ist als in Abbildung (c).

c) Bei Gouraud Shading werden Lichtberechnungen nur für die Eckpunkte des Dreiecks durchgeführt und die Ergebnisse werden innerhalb des Dreiecks interpoliert. Daher würde das Beleuchtungsmodell nur dreimal ausgewertet werden - einmal für jeden Eckpunkt. Bei Phong Shading hingegen werden Lichtberechnungen für jeden einzelnen Pixel durchgeführt, da die Normale interpoliert und dann das Beleuchtungsmodell für jeden Pixel angewendet wird. Da das Dreieck fünf Pixel bedeckt, würde das Beleuchtungsmodell für jedes dieser fünf Pixel separat ausgewertet werden, was zu fünf Auswertungen führt.





****************************************************************************************
****************************************************************************************




Answer to Question 4
a) Für Strahl 1 werden die Hüllkörper in der Reihenfolge 2 -> A -> B und für Strahl 2 in der Reihenfolge 3 -> 5 -> F traversiert.

b) Um die neuen Hüllkörper zu skizzieren, würde ich zuerst eine Gesamthülle um alle sechs Objekte A, B, C, D, E, F zeichnen. Dann würde ich separaten Hüllkörper um die Objektpaare A und B, C und D sowie E und F zeichnen. Da sich die Objekte in der animierten Szene relativ zu ihrer ursprünglichen Position verändert haben, würden die neuen Hüllkörper größer ausfallen und möglicherweise separat liegen, statt wie in der ursprünglichen Hierarchie ein Teil der anderen Hüllkörper zu sein.

c) Ein Vorteil der Wiederverwendung der Hüllkörper-Hierarchie ist, dass weniger Berechnungen erforderlich sind, da keine völlig neue Hierarchie von Grund auf neu aufgebaut werden muss. Das kann Zeit sparen, besonders wenn die Geometrieänderungen gering sind. Ein Nachteil ist, dass die wiederverwendeten Hüllkörper möglicherweise nicht optimal für die neue Geometrie sind. Sie könnten größer als nötig sein, was zu weniger effizienten Kollisionstests und Rendering führen könnte.

d) Zwei Alternativen zu achsenparallelen Boxen (AABBs) als Hüllkörper sind Sphären und Oriented Bounding Boxes (OBBs).

- Sphären:
  - Vorteil: Einfacher zu berechnen, besonders bei der Kollisionserkennung, da nur ein Abstandstest nötig ist.
  - Nachteil: Kann eine schlechte Passform für viele Objektformen bieten und so zu einer ineffizienten Raumausnutzung führen.
   
- Oriented Bounding Boxes (OBBs):
  - Vorteil: Bessere Übereinstimmung mit dem Objekt, da sie im Vergleich zu AABBs in beliebigen Winkeln ausgerichtet sein können.
  - Nachteil: Kollisionserkennung und andere Berechnungen sind komplexer und zeitaufwändiger als bei AABBs.





****************************************************************************************
****************************************************************************************




Answer to Question 5
a: Um die Transformation M zu erzeugen, die das Objekt wie in der Abbildung "figures/transformation_first.png" verändert, ist es notwendig, die Matrizen zu kombinieren, die eine Skalierung, Rotation und Translation durchführen. Da die endgültige Form des Objekts gedreht und verzerrt zu sein scheint und sich auch verlagert hat, könnte eine Kombination aus den Matrizen C (Rotation), E (Scherung) und eventuell A oder B (Translation) erforderlich sein. Ohne mehr spezifische Details über die Abfolge, in der die Transformationen angewendet werden sollen, kann ich jedoch keine genaue Antwort geben.

b: Um das Objekt schrittweise durch die Matrizen F, C und B zu transformieren, würde es wie folgt aussehen:
- F: Zuerst würde das Objekt durch die Matrix F skaliert und verzerrt, wobei die x-Koordinate um den Faktor 1/2 reduziert und die y-Koordinate unverändert bleibt. Das würde das Objekt horizontal stauchen.
- C: Als nächstes würde das Objekt durch die Matrix C rotiert, was einer Spiegelung an der y-Achse entspricht.
- B: Schließlich würde das Objekt durch die Matrix B entlang der x-Achse um 1 Einheit nach rechts verschoben, da dies eine Translation ist, die im letzten Teil der Matrix (ganz rechts oben) notiert ist.

In Worte gefasst, würde die Zeichnung so entstehen:
1. Nehmen Sie das Startobjekt (Dreieck mit dem Quadrat darüber).
2. Stauchen Sie es horizontal um die Hälfte.
3. Spiegeln Sie das gestauchte Objekt an der y-Achse.
4. Verschieben Sie das gespiegelte Objekt um eine Einheit nach rechts.

c: Normalen werden durch eine Transformation, die eine Kombination aus reiner Rotation und Skalierung ist (so wie bei der Matrix T = E · C · F), nicht zuverlässig transformiert. Um Normalen korrekt zu transformieren, wird im Allgemeinen die invers transponierte der linearen Transformation Teilmatrizen verwendet, allerdings ohne jegliche Translationsteil.

Für T' = E · C · F könnten Normalen korrekt transformiert werden, indem man die Inverse von E · C · F nimmt und diese dann transponiert. Translation ist bei der Transformation von Normalen nicht relevant und sollte ignoriert werden. Dies ist wichtig, um sicherzustellen, dass die Normalen weiterhin senkrecht zu den Oberflächen ihres Objekts stehen, insbesondere nach Nicht-Uniformen Skalierungen oder Scherungen.





****************************************************************************************
****************************************************************************************




Answer to Question 6
a) Zwei Alternativen zu bilinearer Interpolation bei Texturen, die aus der Vorlesung bekannt sind, sind:

- Nearest-Neighbor-Interpolation
- Trilineare Interpolation

b) Um die Interpolationsgewichte für die Stellen (x, y) zu berechnen, verwenden wir bilineare Interpolation.

Für (x, y) = (1/4, 1/2) (erste Zeile der Tabelle), berechnen sich die Gewichte wie folgt:

- Gewicht \( w_{0,0} = (1 - x) \cdot (1 - y) = (1 - 1/4) \cdot (1 - 1/2) = 3/4 \cdot 1/2 = 3/8 \)
- Gewicht \( w_{1,0} = x \cdot (1 - y) = 1/4 \cdot 1/2 = 1/8 \)
- Gewicht \( w_{0,1} = (1 - x) \cdot y = 3/4 \cdot 1/2 = 3/8 \)
- Gewicht \( w_{1,1} = x \cdot y = 1/4 \cdot 1/2 = 1/8 \)

Für (x, y) = (2/3, 1/4) (zweite Zeile der Tabelle), berechnen sich die Gewichte wie folgt:

- Gewicht \( w_{0,0} = (1 - x) \cdot (1 - y) = (1 - 2/3) \cdot (1 - 1/4) = 1/3 \cdot 3/4 = 1/4 \)
- Gewicht \( w_{1,0} = x \cdot (1 - y) = 2/3 \cdot 3/4 = 1/2 \)
- Gewicht \( w_{0,1} = (1 - x) \cdot y = 1/3 \cdot 1/4 = 1/12 \)
- Gewicht \( w_{1,1} = x \cdot y = 2/3 \cdot 1/4 = 1/6 \)

c) Die Auflösungsstufe bei Mip-Mapping einer Textur sollte idealerweise so gewählt werden, dass die Texturauflösung möglichst nah an der von der Szene geforderten Detailstufe liegt. Die beiden Probleme, die auftreten können, wenn dies nicht der Fall ist, sind:

- Minification: Wenn die Textur stärker verkleinert dargestellt wird, als es die Mip-Map-Stufen zulassen, kann es zu Aliasing kommen.
- Magnification: Wenn die Textur vergrößert dargestellt wird und die Detailstufe zu niedrig ist, führt das zu unscharfen oder blockigen Texturen.

d) Es ist akzeptabel, die Stufen in einer Mip-Map jeweils in halbierter Auflösung zu speichern, weil dadurch die Anzahl der zu speichernden und zu verarbeitenden Bilddaten deutlich reduziert wird, ohne signifikanten Verlust der Bildqualität. Dies liegt daran, dass bei weiter entfernten Objekten weniger Details wahrgenommen werden und daher eine niedrigere Auflösung ausreichend ist. Die Summe der Speichergrößen aller niedrigeren Mip-Map-Stufen ist nur so groß wie die Speichergröße der Originaltextur.

e) Da baryzentrische Koordinaten \(\lambda_1\), \(\lambda_2\) und \(\lambda_3\) (wobei \(\lambda_3 = 1 - \lambda_1 - \lambda_2\)) zusammen die Koordinaten eines Punktes im Dreieck bezüglich der Dreiecksvertices angeben, kann man anhand der Werte dieser Koordinaten feststellen, ob ein Punkt in einem Dreieck liegt. Für den Punkt x mit \(\lambda_1 = 0.5\) und \(\lambda_2 = 0.4\) gilt, dass der dritte baryzentrische Koordinate \(\lambda_3 = 1 - \lambda_1 - \lambda_2 = 1 - 0.5 - 0.4 = 0.1\) ist, also ist \(\lambda_3\) ebenfalls positiv. Da alle drei baryzentrischen Koordinaten positiv sind und ihre Summe 1 ergibt, liegt der Punkt x innerhalb des Dreiecks.

f) Wir berechnen die baryzentrischen Koordinaten \(\lambda'_1\), \(\lambda'_2\), \(\lambda'_3\) für den Punkt \(x' = x + \frac{1}{2} (v_2 - v_1)\) unter Berücksichtigung der ursprünglichen baryzentrischen Koordinaten von x.

Da \( x = \lambda_1 v_1 + \lambda_2 v_2 + \lambda_3 v_3 \) und \( \lambda_3 = 0.1 \) (berechnet aus Teil e), ist \( x' = \lambda_1 v_1 + \lambda_2 v_2 + \lambda_3 v_3 + \frac{1}{2} (v_2 - v_1) \).

Wir können nun \( x' \) in baryzentrischen Koordinaten bezüglich \( v_1 \), \( v_2 \), \( v_3 \) ausdrücken:

\( x' = \left(\lambda_1 - \frac{1}{2}\right) v_1 + \left(\lambda_2 + \frac{1}{2}\right) v_2 + \lambda_3 v_3 \).

So ergibt sich:

- \( \lambda'_1 = \lambda_1 - \frac{1}{2} = 0.5 - \frac{1}{2} = 0 \)
- \( \lambda'_2 = \lambda_2 + \frac{1}{2} = 0.4 + \frac{1}{2} = 0.9 \)
- \( \lambda'_3 = \lambda_3 = 0.1 \)

Also liegen die baryzentrischen Koordinaten von \(x'\) bei \( \lambda'_1 = 0 \), \( \lambda'_2 = 0.9 \), \( \lambda'_3 = 0.1 \).





****************************************************************************************
****************************************************************************************




Answer to Question 7
a:
- Fragment Shader: Eingabedaten sind einzelne Fragmente, die durch die Rasterisierung entstehen (jedes Fragment entspricht möglicherweise einem Pixel auf dem Bildschirm, aber vor der Ausführung von Tiefentests etc.). Diese Fragmente enthalten Daten wie Position, Farbe und Texturkoordinaten von der Rasterisierung, sowie jeden anderen Varying-Werten, die vom Vertex Shader übermittelt wurden. Die Ausgabedaten sind die finalen Farben der Fragmente, die an den Framebuffer zur Anzeige geschickt werden. Anzahl Eingabe: 1, Anzahl Ausgabe: 0 oder 1.

- Vertex Shader: Die Eingabedaten sind Vertices (Punkte, die das 3D-Modell definieren), die Informationen wie Position, Farbe, Normalen, Texturkoordinaten usw. enthalten können. Die Ausgabe sind transformierte Vertices mit möglicherweise weiteren berechneten Attributen (z. B. Beleuchtung), die an die nächste Pipeline-Stufe gesendet werden. Anzahl Eingabe: 1, Anzahl Ausgabe: 1.

- Rasterisierung: Nimmt als Eingabedaten die von der Primitive Assembly bereitgestellten Primitiven (z. B. Dreiecke) und erzeugt eine Karte von Fragmenten, die in Pixel auf dem Bildschirm umgesetzt werden können. Hier wird entschieden, welche Fragmente potenziell in die endgültige Szene gezeichnet werden sollen. Anzahl Eingabe: M (Anzahl der Primitiven), Anzahl Ausgabe: M = N.

- Primitive Assembly: Die Eingabedaten sind eine Sammlung von Vertices vom Vertex Shader. Diese Stufe arrangiert die Vertices in grafische Primitive (z.B. Punkte, Linien, Dreiecke). Die Ausgabe sind diese grafischen Primitive, die zur Rasterisierung geschickt werden. Anzahl Eingabe: N (abhängig von der Art des Primitivs), Anzahl Ausgabe: M (wobei M die Anzahl der erzeugten Primitiven ist).

b:
Das Backface-Culling in OpenGL kann erst nach der Primitive Assembly und nachdem die Primitiven in Kamera- oder Weltkoordinaten umgewandelt wurden, durchgeführt werden, weil erst zu diesem Zeitpunkt die Orientierung der Dreiecke im Verhältnis zur Kamera feststeht. Die Normalen der Flächen können daraufhin mit dem Betrachtervektor verglichen werden, um zu bestimmen, ob eine Fläche zur Kamera zeigt oder von ihr abgewandt ist. Dreiecke, die von der Kamera abgewandt sind (i.e., deren Normale in die entgegengesetzte Richtung des Betrachtervektors zeigt), können ausgelassen werden, um die Leistung zu verbessern, da sie im endgültigen Bild sowieso nicht sichtbar wären.

c:
Im Geometry Shader können aus jedem Vertex, der die Position eines Rauchpartikels repräsentiert, zwei Dreiecke generiert werden, indem der Shader vier zusätzliche Punkte berechnet, um ein Viereck um den ursprünglichen Vertex zu bilden. Der Geometry Shader kann Informationen wie die Ausrichtung und die Größe des Partikels nutzen, um die entsprechenden Ecken des Vierecks zu definieren und die zwei Dreiecke zu erzeugen, die üblicherweise einem Quad entsprechen. Aus diesem Quad können zwei Dreiecke generiert werden, die eine Textur aufnehmen, um den Rauch darzustellen.

d:
Ohne den Einsatz eines Geometry Shaders besteht eine alternative Möglichkeit darin, dass bereits im Vertexbuffer für jeden Rauchpartikel nicht nur ein Punkt, sondern die vier Eckpunkte des aus den zwei Dreiecken bestehenden Quads gespeichert werden. Diese Eckpunkte könnten dann über die Indexierung in der richtigen Reihenfolge zu zwei Dreiecken verbunden werden, welche die Grundstruktur für die Rauchpartikel bilden und auf die dann die Textur angewandt wird.

e:
Bereiche der Textur, die nicht gezeichnet werden sollen, können durch die Verwendung eines Alphakanals in der Textur implementiert werden, wobei Bereiche mit einem Alphawert von 0 als transparent gekennzeichnet werden. Im Fragment Shader könnte man dann überprüfen, ob der Alphawert eines Fragments unter einem bestimmten Schwellenwert liegt. Wenn das der Fall ist, kann das Fragment verworfen werden, ohne Blending zu verwenden. Diese Methode wird als "Alpha Testing" bezeichnet und kann benutzt werden, um sicherzustellen, dass nur die gewünschten Teile der Textur auf die Rauchpartikel angewendet werden.





****************************************************************************************
****************************************************************************************




Answer to Question 8
a) Das Blending findet in der OpenGL-Pipeline nach dem Fragment Shader und vor dem Schreiben in den Framebuffer statt. Genauer gesagt erfolgt es im "Blender", der Teil der Output-Merger-Stufe ist.

b) 
i) Für \(1 \cdot F_s + 0 \cdot F_d\) ist die Konfiguration:
```
glBlendFunc(GL_ONE, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
```
ii) Für \(A_s \cdot F_s + (1 - A_s) \cdot F_d\) ist die Konfiguration:
```
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
```
iii) Für \(A_d \cdot F_s - A_s \cdot F_d\) ist die Konfiguration:
```
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_SUBTRACT);
```

c) Beim Alpha-Blending von semitransparenten Objekten ist eine Sortierung notwendig, weil die Reihenfolge, in der die Fragmente gemischt werden, das Endergebnis beeinflusst. Wenn ein weiter entferntes Objekt zuerst gezeichnet und dann mit einem näheren, halbtransparenten Objekt gemischt wird, hat dies einen anderen visuellen Effekt, als wenn die Reihenfolge umgekehrt wäre. Der Tiefentest (Depth Test) allein reicht nicht aus, da er nur entscheidet, welches Fragment sichtbar bleibt, basierend auf der Tiefe, jedoch ohne Berücksichtigung der Transparenz.

Die Objekte werden in der Regel von hinten nach vorne sortiert, d.h., die am weitesten entfernten Objekte werden zuerst gezeichnet und die nächstgelegenen zuletzt, damit die Transparenz korrekt verarbeitet werden kann. Diese Sortierung ist insbesondere bei nicht assoziativen Blending-Operationen wichtig, bei denen das Ergebnis von der Reihenfolge der Operanden abhängt.





****************************************************************************************
****************************************************************************************




Answer to Question 9
a) Die Einschränkung, dass Lichtbrechung nur am ersten Schnittpunkt eines Kamerastrahls mit dem Objekt stattfindet, ist bei der Rasterisierung notwendig, weil die Rasterisierung ein algorithmischer Prozess ist, der geometrische Primitiven wie Dreiecke in Pixel auf einem Bildschirm umwandelt. Diese Technik berücksichtigt im Normalfall nicht die Komplexität der Lichtpfade wie die fortgeschrittene Strahlverfolgung (Raytracing). Die Berechnung der Lichtbrechung an jedem möglichen Schnittpunkt würde eine rekursive und berechnungsintensive Analyse der Lichtpfade erfordern, was weit über das übliche Leistungsspektrum und den Einsatzbereich der Rasterisierung hinausgehen würde. Deshalb wird diese Vereinfachung vorgenommen, um die Berechnung zu beschleunigen und auf die Fähigkeiten der Rasterisierung abzustimmen.

b) Für das Rendering mit möglichst wenigen Shadern benötigt man mindestens zwei: einen Vertex Shader und einen Fragment Shader. 
- Der Vertex Shader berechnet die Vertex-Positionen und andere per-vertex Daten wie Normale und Texturkoordinaten, die dann an den Fragment Shader weitergeleitet werden.
- Der Fragment Shader berechnet die endgültige Farbe jedes Fragments (potenziell sichtbaren Pixels) basierend auf den von Vertex Shader bereitgestellten Daten und der Logik für Beleuchtung, Schattierung, Transparenz und Reflektion.

c) Die Aufgaben bzw. Funktionsaufrufe (nummeriert entsprechend der Abbildung) in den Shadern:
(1) `gl_Position = ...;`
   - Der Vertex Shader setzt die gl_Position, da diese Operation die endgültige Position des Vertex im Clip-Space definiert, bevor die Rasterisierung stattfindet.

(2) Berechnung der Richtung vom Betrachter zu einem Oberflächenpunkt
   - In einem Vertex Shader könnte die generelle Richtung für jeden Vertex berechnet werden. Genauere Berechnungen, insbesondere wenn per-fragment Genauigkeit benötigt wird, erfolgen jedoch häufig im Fragment Shader, der Zugriff auf mehr Informationen über die Szene und den Betrachter hat.

(3) `textureCube`
   - Der Aufruf von `textureCube` gehört in den Fragment Shader, da die Texturierung ein per-fragment Prozess ist und die entsprechende Cube-Map-Textur anhand der Reflektions- oder Brechungsrichtung für das Fragment ausgelesen wird.

(4) `refract`
   - Die `refract` Funktion würde im Fragment Shader verwendet, um die Lichtbrechung zu berechnen. Dies ist per-fragment erforderlich, um eine korrekte Visualisierung von Refraktion basierend auf den Oberflächennormalen und dem Blickwinkel des Betrachters zu gewährleisten.

(5) Berechnung des Fresnel-Terms
   - Die Berechnung des Fresnel-Terms erfolgt typischerweise im Fragment Shader, um zu entscheiden, wie viel Licht reflektiert und wie viel gebrochen wird. Der Fresnel-Effekt ist abhängig vom Betrachtungswinkel und muss für jedes Pixel individuell berechnet werden.

Die vorgestellten Konzepte sind Standardverfahren in der Computergrafik und die Zuordnung der Operationen zu Vertex- oder Fragment-Shader basiert auf ihren jeweiligen Verantwortungsbereichen in der Grafikpipeline.





****************************************************************************************
****************************************************************************************




Answer to Question 10
a:
Um die Funktion `intersectDF` zu vervollständigen, die mittels Sphere-Tracing das Distanzfeld nach einem Schnittpunkt absucht, könnte der Code wie folgt aussehen:

```glsl
bool intersectDF(vec3 o, vec3 d, out vec3 s, out float t) {
    t = 0.0;
    for (int i = 0; i < maxSteps; ++i) {
        s = o + t * d;      // Berechnung der aktuellen Position auf dem Strahl
        float dist = DF(s);  // Distanz zum nächsten Objekt (Distanzfunktion)

        if (dist < eps) {    // Überprüfung, ob die Distanz unterhalb des Schwellwerts liegt
            return true;     // Schnittpunkt gefunden
        }
        t += dist;           // Fortschreiten entlang des Strahls um dist
        if (t > MAX_DIST) {  // Überprüfung, ob die maximale Distanz überschritten wurde
            break;
        }
    }
    return false; // kein Schnittpunkt gefunden
}
```

Hierbei ist `MAX_DIST` eine Konstante, die die maximale Distanz bestimmt, bis zu der gesucht wird.

b:
Die Korrektur des Schnittpunkts `s` um `ds` ist erforderlich, um sicherzustellen, dass der Startpunkt für die weitere Verfolgung des Refraktionsstrahls R nicht auf oder innerhalb der Oberfläche liegt, sondern leicht davor oder dahinter. Dadurch wird verhindert, dass das Raymarching "stecken bleibt" oder fälschlicherweise sofort einen weiteren Schnittpunkt meldet. Die Berechnung der relativen Brechzahl `relEta` ist notwendig, da die Refraktion vom Verhältnis der Brechungsindizes der beteiligten Medien abhängt. Der Code unterscheidet hier, ob der Strahl von außen nach innen oder umgekehrt geht und passt entsprechend die relative Brechzahl an.

Die `if(DF(o))`-Bedingung testet, ob der Ursprungspunkt `o` innerhalb des Objekts liegt (wenn `DF(o) < 0`). Dies ist wichtig, da an dieser Stelle entschieden wird, ob der Strahl das Medium verlässt oder in das Medium eintritt, was beeinflusst, wie die Refraktion umgekehrt werden muss.

c:
Gloss-Mapping ist eine Technik, bei der eine Textur verwendet wird, um die Glanzstärke und Rauheit einer Oberfläche an unterschiedlichen Stellen zu variieren. Diese Information wird oft dazu verwendet, um die reflexiven Eigenschaften der Oberfläche zu verändern, sodass zum Beispiel einige Bereiche stärker glänzen als andere. Bei der verwendeten Schattierungstechnik mit Environment Mapping und Normal Mapping ist es relativ einfach und effizient, Gloss-Mapping hinzuzufügen, da man für die Bereiche, wo die Oberfläche glänzender sein sollte, die Reflexionen stärker hervorhebt und die Rauigkeit in den Berechnungen entsprechend anpasst. Das kann direkt im Shader erfolgen, ohne zusätzliche Geometrie berechnen oder komplizierte Lichtsimulationen durchführen zu müssen.

d:
Um Dispersionseffekte bei der Refraktion hinzuzufügen, könnte man den Refraktionsprozess für verschiedene Wellenlängen des Lichts (also verschiedene Farben) separat durchführen und die Ergebnisse dann zusammenführen. Das bedeutet, dass man die Brechungsindizes für Rot, Grün und Blau leicht variieren würde, um den Effekt zu simulieren, dass unterschiedliche Wellenlängen des Lichts sich unterschiedlich in einem Medium brechen (Dispersion).

Der Berechnungsaufwand würde dadurch steigen, weil die Refraktion nun mehrmals (mindestens einmal pro Farbkanal) berechnet werden müsste. Dies führt zu mehr Shaderberechnungen pro Pixel und kann die Leistung beeinflussen, jedoch kann der Effekt visuell sehr ansprechend sein, insbesondere bei high-end Grafiken, wo Realismus von hoher Bedeutung ist.





****************************************************************************************
****************************************************************************************




Answer to Question 11
a) Eine BVH B', die mit T_K'(x) für K' ≤ K konstruiert wird, ist eine korrekt funktionierende BVH für die Szene, weil T_K'(x) eine vereinfachte Version der Szene darstellt, in der einige Details (höhere Frequenzen des Rauschens) möglicherweise fehlen. Da T_K'(x) somit nie eine größere Höhe als T_K(x) an einer gegebenen Stelle haben kann, werden alle Quader, die durch T_K(x) repräsentiert werden, definitiv von der BVH B' umfasst. Der Nachteil gegenüber einer BVH B, die mit T_K(x) für K' < K generiert wurde, ist, dass die BVH B' potenziell weniger genau ist und größere umbüllende Volumen nutzt, die mehr Quader umfassen. Das bedeutet, dass bei einer Kollisionssuche mehr Kandidaten zu berücksichtigen sind, was die Effizienz des Raytracings verringern kann.

b) Um die Rauschfunktion n(x) nur minimal oft auszuwerten, kann man die Strategie des Raymarching mit adaptiven Schrittgrößen anwenden. Beim konventionellen Raymarching würde man für jeden Schritt i den genauen Wert von T_K am Punkt r(i) = o + id evaluieren. Eine mögliche Optimierung wäre:

1. Beginne mit einem initialen Schrittgrößenfaktor s.
2. Für den nächsten Punkt r(i) auf dem Strahl r berechne nur die Höhe T_K für den aktuell betrachteten Punkt.
3. Vergleiche r_z(i) mit T_K(r_x(i), r_y(i)).
4. Wenn r_z(i) > T_K(r_x(i), r_y(i)), bewege den Strahl um s*d weiter. Sonst, reduziere s und beginne erneut bei Schritt 2.
5. Wiederhole die Schritte 2 bis 4, bis r_z(i) ≤ T_K(r_x(i), r_y(i)) – der Schnittpunkt ist gefunden.
6. Adapte den Schrittgrößenfaktor s während des Raymarching-Prozesses, um größere Schritte zu machen, wenn r ziemlich weit von der Oberfläche entfernt ist, und kleinere Schritte, wenn r sich der Oberfläche nähert.

c) Die Funktion n(x) = sin(x), x ∈ R ist zu regelmäßig und wiederholt sich periodisch. Eine Eigenschaft von Rauschfunktionen, die in der Grafik verwendet werden, ist, dass sie unregelmäßig und möglichst nicht wiederholend sein sollten, um natürliche Unregelmäßigkeiten besser simulieren zu können. Obwohl die Sinusfunktion unendlich differenzierbar ist, was bei Rauschfunktionen erwünscht ist, ist sie zu vorhersagbar und erzeugt ein unnatürlich aussehendes Muster. Daher ist sie keine gute Wahl für eine Rauschfunktion in grafischen Anwendungen.

d) Für das gewünschte L-System mit V = {F, +, -}, α = 60° und Startwort F--F--F könnten die Regeln für die Ableitung (Produktionen) wie folgt aussehen:

F → F+F--F+F

Das bedeutet, dass für jedes F im aktuellen Wort, dieses durch F+F--F+F ersetzt werden soll. Das Symbol '+' bedeutet hier eine Drehung der Turtle um 60° im Uhrzeigersinn und '-' eine Drehung um 60° gegen den Uhrzeigersinn. Das Startwort F--F--F, zusammen mit der angegebenen Regel und Interpretation als Turtle-Grafik, würde dann die gezeigten Schneeflocken erzeugen.





****************************************************************************************
****************************************************************************************




Answer to Question 12
a: Um den Punkt F(0.5) der Bézier-Kurve zu finden, wenden wir den de Casteljau-Algorithmus an, um die Kontrollpunkte für u = 0.5 zu berechnen. Wir zeichnen die Linie von \( b_0 \) nach \( b_1 \), \( b_1 \) nach \( b_2 \), und \( b_2 \) nach \( b_3 \). Die Mitte dieser Linien sind die neuen Punkte \( b_{01} \), \( b_{12} \), und \( b_{23} \) für u = 0.5. Dann verbinden wir diese neuen Punkte: \( b_{01} \) nach \( b_{12} \) und \( b_{12} \) nach \( b_{23} \). Die Mitte dieser Linien sind die Punkte \( b_{012} \) und \( b_{123} \). Verbinden wir schließlich \( b_{012} \) mit \( b_{123} \) und nehmen die Mitte dieser Linie, erhalten wir den Punkt \( b_{0123} \), der dem Punkt F(0.5) entspricht. Wir markieren alle erwähnten Punkte und zeichnen die resultierenden Linien, um den Punkt F(0.5) zu finden und die Kurve zu skizzieren.

b: Eine affine Abbildung erhält die linearen Eigenschaften einer Bézier-Kurve, was bedeutet, dass man die Transformation direkt auf die Kontrollpunkte anwenden kann, statt auf die gesamte Kurve. Um also die Bézier-Kurve durch eine affine Transformation zu rotieren, skalieren und zu verschieben, wenden wir die Transformation auf die einzelnen Kontrollpunkte \( b_0 \), \( b_1 \), \( b_2 \), und \( b_3 \) an. Die transformierten Punkte bilden das Kontrollpolygon für die transformierte Bézier-Kurve.

c: Zur Untersuchung, ob die abgebildete Kurve einer kubischen Bézier-Kurve entspricht, überprüfen wir die Variation von Kontrollpunkten und Kurven. Die abgebildete Kurve zeigt eine deutliche Abweichung von der glatten Bézier-Kurve, die von den Kontrollpunkten \( c_0 \), \( c_1 \), \( c_2 \), und \( c_3 \) erzeugt werden sollte. Insbesondere sehen wir, dass die Kurve in sich geschwungen ist und Spitzen aufweist, was nicht möglich ist für eine einfache kubische Bézier-Kurve, die definiert ist durch ein einzelnes Kontrollpolygon. Daher kann man schlussfolgern, dass die abgebildete Kurve nicht der kubischen Bézier-Kurve G(u) entspricht.





****************************************************************************************
****************************************************************************************




