Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

C-Kurs/DreiD

< C-Kurs
Version vom 28. August 2010, 15:48 Uhr von AndyF (Diskussion | Beiträge) (Transformation und Projektion)

In dieser Aufgabe wollen wir eine stark vereinfachte 3D-Anwendung schreiben, welche einen 3D-Körper rotieren lässt. Du kannst selbst entscheiden, bis zu welchem Zwischenergebnis du die Aufgabe lösen willst.

Vorgabe

Lade dir zunächst die Vorgaben herunter. Die "screen"-Dateien brauchen nicht verändert werden, sie sorgen für die grafische Ausgabe. Deine Aufgabe ist es, die Rechenoperationen der main.c zu ergänzen.

Kompiliert wird das Programm mit:

gcc main.c screen.c -lX11 -lm -o 3D.out

Denke daran die Pfeiltaste Hoch in der Shell zu verwenden, statt es jedesmal neu einzugeben.

Werden die Vorgaben direkt kompiliert und ausgeführt, ist ein Rechteck zu sehen. Dies ist ein frontal betrachteter Würfel, welcher eigentlich schon gedreht wird, jedoch fehlen die Transformationsoperationen.

Transformation und Projektion

Wir befinden uns in der Methode "transformation" und wollen den Würfel nun erst um die X-Achse und dann um die Y-Achse drehen. Dazu verwenden wir Rotationsmatrizen, welche wir als 3x3 Array umsetzen, wobei wir uns einigen, dass der erste Array-Index die Zeile und der zweite die Spalte der Matrix ist. Die rot_x ist bereits vorgegeben. Initialisiere auf gleiche Weise darunter die rot_y, unter Verwendung des Winkels "alpha". Schreibe direkt darunter einen Algorithmus, der die Matrizen rot_x und rot_y miteinander multipliziert und das Ergebnis auf der globalen Matrix "transform" speichert. Versuche dabei Schleifen, statt konstanter Indizes zu verwenden. Die resultierende Matrix auf einen Vektor angewandt, rotiert diesen nun entsprechend um die X- und Y-Achse. Dies soll in der Methode "projection" geschehen. Projection nimmt einen Punkt der Figur im Raum und soll diesen entsprechend der aktuellen Rotation verändern. Die Parameter sind Call-by-Reference. Ändere mit Hilfe der globalen "transform"-Matrix die Inhalte der Parameter so, das der x-y-z-Vektor am Ende rotiert ist (Matrix-Vektor-Multiplikation).

Teste deine Implementierung. Zu diesem Zeitpunkt sollte schon ein rotierender Würfel zu sehen sein. Falls der Würfel beim Rotieren verzerrt wird, sind möglicherweise Indizes bei der Matrix Multiplikation verdreht.

Nebenbei: echte 3D-Anwendungen verwenden 4x4 Matrizen, damit auch Translationen möglich sind. Da wir aber nur rotieren wollen, reichen 3x3 Matrizen.

Culling

Schalte den "WIREFRAMES_MODE" auf 0, wodurch der Würfel ausgefüllte Flächen bekommt und sieh dir zunächst das Ergebnis an. Zu sehen ist das Problem, dass wir jede Fläche einfach zeichnen, egal ob sie vor oder hinter dem bisher gezeichneten Würfel ist. Die allgemeine und standardmäßige Lösung wäre ein Z-Buffer, wodurch Pixel, die verdeckt werden würden, einfach nicht gezeichnet werden. Dies ist für unsere Zwecke zu aufwendig, daher nehmen wir eine speziellere Lösung: Culling. Die Überlegung ist, dass wir bei einem soliden Würfel nicht sein kann, dass wir irgendeine fläche von innen sehen, da diese immer von einer Außenfläche verdeckt wird. Außerdem verdeckt nie eine Außenfläche eine andere (sichtbare) Außenfläche, da der Würfel konvex ist. Wir brauchen also nur die Außenflächen zu zeichnen. Wir befinden uns in der Methode "draw_primitive", welche ein einzelnes Dreieck zeichnet. Nachdem die Punkte projeziert wurden, muss geprüft werden, ob die drei Punkte im Uhrzeigersinn angeordnet sind. Bilde dazu aus den Koordinaten die beiden Richtungsvektoren des Dreiecks (der Ortsvektor ist egal) und bilde aus ihnen das Kreuzprodukt. Nun kann man sich überlegen, dass das Dreieck genau dann von außen zu sehen ist, wenn die Z-Koordinate des Kreuzprodukts kleiner als 0 ist (Somit brauch man streng genommen die X- und Y-Koordinaten des Kreuzprodukts gar nicht). Ist die Z-Koordinate also größer-gleich 0, verlasse die Methode vorzeitig (vor dem Zeichnen des Dreiecks).

Nun sollte ein rotierender, ausgefüllter, fehlerfreier Würfel zu sehen sein.

Andere Figuren

Wenn du lust hast, kannst du mit Hilfe von draw_primitive und draw_face eigene 3D-Figuren erstellen. Ersetze dazu den Würfel in der main einfach durch deinen Algorithmus. Denke aber daran, dass sofern Wireframes aus sind, die Figur konvex sein sollte. Eine mögliche Figur ist der Kegel: