← ST-Computer 11 / 1992

Rotor: 3D-Grafik hautnah

Grundlagen

3D-Grafik-Programme und ähnliche Anwendungen gibt es viele. In Kaufhäusern und bei Freunden kann man faszinierende Körper, die im Raum herumwirbeln, bewundern. Aber leider sind die Programme dazu meistens schon compiliert. Da man aber selbst eifriger Programmierer ist, möchte man natürlich, unter allen Umständen und möglichst bald, sein eigenes Programm laufen sehen. Doch hier beginnt für viele der grausame Weg durch alte Schulbücher. Nichts dergleichen zu finden?

Bild 1: Phantasieobjekt mit Beleuchtung

Dieser Artikel bringt Abhilfe. Er soll anhand von Rotationskörpern die Angst vor dem dreidimensionalen Raum vertreiben. Dabei wird ein Programm beschrieben, mit dem die Erstellung solcher Körper zum Kinderspiel wird. Hierbei werden Funktionen erläutert, die Sie auch in anderen 3D-Programmen verwenden können.

Bild 2: Definitionspunkte bei der Erstellung eines Glases

Was sind überhaupt Rotationskörper?

Rotationskörper sind Objekte, die durch Rotation eines in einer Ebene definierten Linienzuges entstehen. Dies klingt viel komplizierter, als es in Wirklichkeit ist. Schauen Sie sich zur Verdeutlichung Bild 2 an und stellen Sie sich vor, der Umriß des Glases rotiere um die y-Achse mit einem bestimmten Schrittwinkel. Der jetzt erhaltene Linienzug wird nun mit dem gleichen Winkel nochmals um die y-Achse gedreht. Diese Prozedur wiederholt sich solange, bis eine vollständige Rotation um 360° erreicht ist, und schon können wir unser fertiges Glas betrachten (Bild 3). Somit ergibt sich der Eindruck eines runden Körpers, der mit wenig Aufwand erstellt wurde. Je kleiner der Schrittwinkel, desto runder erscheint der Körper. Das Glas sieht jedoch noch besser aus, wenn wir die Punkte der aktuellen und die der letzten Ebene zu einer Fläche zusammensetzen und diese mit einer Lichtquelle bestrahlen.

Bild 3: Erstellung des Glases durch Rotation

Es sind also hohe Ziele für den Programmierer gesetzt. Zur Demonstration sehen Sie sich bitte die Bilder 1 und 4 an. Kommen wir nun zur Verwirklichung. Zuerst einmal benötigt man eine Datenstruktur für unseren Körper. Da uns in GFA-BASIC leider die Möglichkeit fehlt, Strukturen zu bilden, müssen wir auf Arrays zurückgreifen. Wir fangen in der Hierarchie ganz oben an und erkennen einen Körper, der aus Flächen besteht, wovon jede Fläche vier Eckpunkte besitzt. Hieraus ergibt sich schon unser erstes zweidimensionales Feld:

Flaeche(x,y), wobei x für die Anzahl der Flächen und y für die Punkte 0..3 der Fläche steht. Es ist natürlich umständlich, auch in diesem Array noch die x-,y- und z-Koordinaten der Punkte abzulegen. Deshalb speichern wir nur die Punktnummern - also den Index der Punkte - in anderen Arrays, welche wie folgt aufgebaut sind:

x_3d&(x),y_3d&(x) und z_3d&(x).

Das x beschreibt die Anzahl der Punkte, die das Feld umfaßt. Jetzt wäre es natürlich vorteilhaft zu wissen, wie sich die Anzahl der Punkte und Flächen eines jeden beliebigen Rotationskörpers berechnet. Wir kennen die Anzahl der Definitionspunkte und die der Rotationen, wodurch sich der Schrittwinkel ergibt:

Schrittwinkel = 360 / Anzahl der Rotationen

(am besten die Anzahl der Rotationen so festlegen, daß der Schrittwinkel einen Integerwert ergibt)

Wie kommen wir jetzt auf die Gesamtzahl der Punkte? Nun, die Definitionsebene mit x Punkten wird schließlich y-mal gedreht, bis ein ganzer Körper entsteht, also:

Anzahl der Punkte = Zahl der Definitionspunkte [x] * Zahl der Rotationen [y]

Eine Ebene besitzt dann logischerweise eine Fläche weniger, als Punkte vorhanden sind. Für die Gesamtzahl der Flächen erhalten wir somit eine ähnliche Formel:

Anzahl der Flächen = (Zahl der Definitionspunkte -1) * Zahl der Rotationen

Angenommen, das Objekt besäße 20 Definitionspunkte und würde 50mal rotiert, so ergäben sich 1000 Punkte und 950 Flächen. Sie können sich vorstellen, was es bedeuten würde, all diese Punkte und Flächen mit einem normalen 3D-Editor einzugeben. Bei der Definition als Rotationskörper müssen Sie nur die 20 Punkte angeben, den Rest erledigt der Computer für Sie.

Funktions- und Programmbeschreibung

Zu Beginn werden, wie besprochen, sämtliche Arrays definiert sowie einige Variablen vorbelegt, dazu zählen die maximale Anzahl der Punkte und Rotationen, die auf 512 KB ausgelegt sind. Sollten Sie mehr Speicher besitzen, können Sie diese Zahlen erhöhen. Weiterhin sind die Koordinaten der Lichtquelle und des Beobachters und die Ausgangswerte für die Drehung, Skalierung, welche das Objekt vergrößert oder verkleinert, und Translation (sorgt dafür, daß das Objekt am Anfang in der Mitte des Bildschirms erscheint) festgelegt. Nach der Initialisierung des Menüs wartet das Hauptprogramm in einer DO-LOOP-Schleife auf ein Menüereignis. Sollten Sie Eingeben angewählt haben, wird zuerst körper_eingeben angesprungen, wo das Programm die Eingabe der Punkte steuert und sie automatisch durch Linien verbindet. Das Drücken von Help bewirkt hierbei das Löschen aller bisher eingegebenen Punkte, und durch Drücken von Undo kann der zuletzt eingegebene gelöscht werden. Am Ende der Prozedur trägt das Programm noch die zweidimensionalen Punkte in das Raumpunkte-Array ein. Dies ist möglich, da die Definitionsebene gleichzeitig die x-y-Ebene im Raum ist, weshalb die z-Koordinate immer 0 bleibt und auch die x- und y-Koordinaten sich nicht ändern. Diese Punkte stellen die Urpunkte für alle Rotationen bei der Berechnung des Objekts dar.

Bild 4: Weiterer Beispielkörper

Das Programm ermittelt jetzt den Schrittwinkel und führt mit Hilfe dessen die Drehungen durch. Für diese gibt es folgende Formel:

x’= x*cos(w)+z*sin(w) y’= y z’= -x*sin(w)+z*cos(w) (Drehung um die y-Achse mit Winkel w, Koordinaten des Urpunktes: x,y,z, Bildpunkt: x’,y’;z’)

Dies ist zugleich der Angriffspunkt für eine Erweiterung. Die Drehung läßt sich nicht nur um die y-, sondern auch um die x-oder z-Achse ausführen. Wir geben hier nur die Formeln an. Der Einbau ins Programm dürfte keine Schwierigkeiten bereiten.Drehung des Urpunktes (x,y,z) um die x-Achse mit dem Winkel w:

x’=x y’=y*cos(w)-z*sin(w) z’=y*sin(w)+z*cos(w)

Drehung des Urpunktes (x,y,z) um die z-Achse mit dem Winkel w:

x’=x*cos(w)-y*sin(w) y’=x*sin(w)+y*cos(w) z’=z

Nach der Rotation aller Punkte einer Ebene werden die Punktnummern der letzten und die der aktuellen Ebene zu einer Fläche zusammengesetzt. Deshalb wird auch bei der zweiten und nicht schon in der ersten Ebene an gefangen, denn bei der ersten Ebene existieren noch keine vorher berechneten Koordinaten, die für eine Fläche genutzt werden könnten. Anschließend erfolgt die Verzweigung in die Prozedur transform, in der das Objekt erst sehenswert gemacht wird. Dazu wird es skaliert, auf Deutsch: verkleinert oder vergrößert, und um die 3 Achsen rotiert. Die dafür entsprechenden Winkel heißen rx, ry und rz.

Da wir nach der Berechnung des Objekts direkt auf die Vorderseite des Körpers blicken, erscheint uns das Bild immer noch zweidimensional. Deshalb benötigen wir in dieser Situation den Aufruf von transform. Wir drehen das Objekt hierbei etwas um die x-Achse, so daß wir schräg auf die Figur sehen und sie endlich dreidimensional bewundern können. Die Formel zur Rotation um die 3 Raumachsen in einer Rechnung entnehmen Sie bitte dem Programm. Die Sinus- und Cosinuswerte, die zur Drehung nötig sind, werden mit den SINQ- und COSQ-Funktionen berechnet, da diese etwa zehnmal schneller sind als die normale Sinus- und Cosinus-Funktion. Die Abweichungen zwischen den beiden Werten sind trotz der Interpolation bei den schnellen Funktionen vemachlässigbar klein. Doch nun zur Skalierung in transform. Bei der Vergrößerung bzw. der Verkleinerung müssen Sie nur alle Koordinaten mit einem Faktor multiplizieren .Dieser Faktor heißt Skalierungsfaktor und hat zu Beginn des Programms den Wert 1, das heißt, die Größe des Objekts bleibt unverändert. Hier nun die einfache Formel:

x’ = x * Sx y’ = y * Sy z’ = z * Sz (Skalierung mit den Faktoren Sx, Sy und Sz für die 3 Achsen, wobei gilt: 0 < S < 1 ==> Verkleinerung des Objekts S = 1 ==> keine Änderung 1 < S < ∞ ==> Vergrößerung des Objekts)

Jetzt kommt van Gogh!

Sie werden sich sicherlich fragen, was van Gogh mit unserem Rotationskörper gemeinsam hat. Die Antwort: Er hilft uns beim Verdecken der Flächen. Überlegen wir einmal, wie er seine Bilder zeichnete. Die Gemälde entstanden immer von hinten nach vorne. Zuerst kommt der Hintergrund aufs Papier und wird mit der Zeit von den weiter vorne liegenden Objekten übermalt, so daß sich für ihn keine Probleme mit verdeckten Rächen ergeben. Man nennt diese Vorgehensweise auf den Computerübertragen verständlicherweise Painter-Algorithmus, den wir vor allem wegen seiner Einfachheit halber in das Programm einbauten. Sicher gibt es bessere Algorithmen, doch sind für diese entsprechende Mathematikkenntnisse notwendig. Jetzt aber weiter mit van Gogh. Zuerst müssen wir natürlich ermitteln, welche Flächen am weitesten hinten liegen, wozu wir am besten den Mittelwert der vier z-Koordinaten errechnen, da ja nicht alle Flächen parallel zur x-y-Ebene verlaufen. Diese Werte legen wir im Feld mittel() ab. Jetzt kann die Flächennummer in Abhängigkeit von ihrem z-Mittel-Wert in das Array fl_sort() eingefügt werden, so daß die Flächennummer mit dem höchsten Mittelwert als erstes im Feld zu finden ist und deshalb auch als erstes gezeichnet wird. Die für den Painter-Algorithmus zuständige Prozedur heißt in unserem Programm verdecke.

Jetzt kommt Farbe ins Spiel

Falls Sie im Menü Schattierung angeklickt haben, verzweigt jetzt verdecke zu farbe, welche die Farbwerte für die Flächen ermittelt. Andernfalls findet keine Farbgebung statt, was Zeit einspart. Dies ist besonders bei Rotationen sinnvoll, da diese viel Zeit beanspruchen. Sollte sich Ihr Objekt in der gewünschten Stellung befinden, können Sie durch Anklicken von Schattieren dem Körper nachträglich Farbe verleihen. Da wir jedoch das Programm auf den Schwarzweißmonitor ausgelegt haben, müssen wir Füllmuster verwenden. Hierfür eignen sich vor allem die Muster des Typs 2 mit dem Index von 1 bis 8, welche praktisch Graustufen darstellen, und natürlich das weiße Füllmuster. Deshalb bringen wir die errechneten Farbwerte auf Zahlen zwischen 0 und 8. Den Algorithmus zur Beleuchtung können wir allerdings nicht näher erläutern, da auch hierzu fundierte Mathematikkenntnisse nötig wären. Es sollte auch nicht Sinn des Artikels sein, dieses Wissen vorauszusetzen.

Bitte schlagen Sie bei Interesse in den Büchern [1], [2] oder [3] nach. Sie können jedoch mit den am Anfang des Programms festgelegten Werten für die Hintergrund-und Lichtintensitäten experimentieren oder die Koordinaten der Lichtquelle ändern. Endlich kommt der Augenblick, in dem unser Objekt mit Hilfe der Polyfill-Funktion auf dem Bildschirm erscheint.

Nun fehlt uns nur noch ein Menüpunkt, nämlich „transformieren“, mit dessen Hilfe das Objekt skaliert, verschoben oder um die 3 Raumachsen rotiert werden kann. Sie können es beispielsweise durch Drücken auf die linke Maustaste an jede beliebige Bildschirmposition plazieren. Außerdem sind noch folgende Tasten mit Funktionen belegt:

1: Objekt um die x-Achse drehen (um den Winkel 30°, siehe ADD x_wink, 30, beliebig veränderbar)
2: Objekt um die x-Achse zurückdrehen
3: Objekt um die y-Achse drehen
4: Objekt um die y-Achse zurückdrehen
5: Objekt um die z-Achse drehen
6: Objekt um die z-Achse zurückdrehen
7: Objekt vergrößern (mit dem Skalierungsfaktor 1.2, siehe MUL x_skal,1.2, beliebig veränderbar)
8: Objekt verkleinern

Im Programm bewirkt das Drehen um die y-Achse jedoch gar nichts, da der Körper ja schließlich durch Rotation um diese Achse entstanden ist. Wir haben die Funktion eingebaut, da manche vielleicht die Idee verwirklichen, den Linienzug um die x- oder die z-Achse zu drehen, wobei die Drehung um die y-Achse mit Sicherheit sinnvoll ist.

Noch ein Tip: Verändern Sie doch die Koordinaten des Beobachters und legen Sie die Bilder in einem Array ab. Danach bringen Sie diese hintereinander auf den Bildschirm. Verbunden mit der Rotation und der Skalierung können Sie dadurch die tollsten Wanderungen durch den dreidimensionalen Raum und Ihre Rotationskörper erstellen und diese als Animation betrachten.

Christian Roth/Matthias Brust

Literatur:

[1] ATARI ST - 3D-Grafikprogrammierung, Uwe Braun, Verlag: Data-Becker, ISBN 3-89011-130-0

[2] Principles of interactive Computergraphic, William M. Newman/Robert F. Sproull, Verlag: Mc Graw-Hill Book Company ISBN 1-89028-015-3

[3] ATARI ST - 3D-Grafik und Animation, Axel Plenge, Verlag: Data-Becker, ISBN 3-89090-676-1

[4] ATARI ST - Das Supergrafikbuch, Axel Plenge, Verlag: Data-Becker, ISBN 3-89011-004-5

[5] Computergrafik 2D- und 3D-Programmierung, Günter Pomaska, Verlag: Vogel-Buchverlag, ISBN 3-8023-0759-3

' ******************************************* ' * ROTOR * ' * von -Christian Roth und Matthias Brust- * ' * (c) 1992 MAXON Computer * ' ******************************************* ' CLIP 0,0,639,399 ! nur nicht zu viel zeichnen raster ! Eingaberaster zeichnen shadow!=TRUE ! schattieren, yeah! ' Die folgenden 2 Zahlen gelten für 512 KB, ' ansonsten je nach Speicher vergrößern punkte_max|=50 ! maximale Zahl der Eckpunkte rotationen_max|=70 ! maximale Zahl der Rotationen anz_pu& =MUL(rotationen_max|,punkte_max|) DIM x_3d&(anz_pu&),y_3d&(anz_pu&),z_3d&(anz_pu&) DIM x_trans(anz_pu&),y_trans(anz_pu&),z_trans(anz_pu&) DIM x_2d&(3),y_2d&(3) anz_fl&=MUL(rotationen_max|,punkte_max|-1) ' Arrays für Farbgebung und Mittelwerte DIM mittel(anz_fl&),farbe|(anz_fl&) ' Arrays für Flache und deren Sortierung DIM flaeche&(anz_fl&,3),fl_sort&(anz_fl&) ' beo_x&=0 ! Koordinaten beo_y&=0 ! des Beobachters beo_z&=5000 ' licht_x&=900 ! Koordinaten licht_y&=-300 ! der Licht- licht_z&=500 ! quelle ' licht_intent=0.8 ! Lichtintensität ' hintergrund_intent=0.3 ! Hintergrundint. ' ' Start-Anzahl der Rotationen rot_anz|=35 ' x_wink=10 ! Drehwinkel y_wink=0 ! um die 3 Raum- z_wink=0 ! achsen ' x_skal=1 ! Skalierung y_skal=1 z_skal=1 x_transl&=320 ! Mittelpunkt y_transl&=200 ! des Bildschirms ' menu_init DO ON MENU LOOP ' ' Menü initialisieren PROCEDURE menu_init LOCAL i| DIM a$(17) FOR i|=0 TO 17 ! Menü- READ a$(i|) ! punkte NEXT i| ! einlesen MENU a$() ERASE a$() ON MENU GOSUB menu_choose MENU 14,1 ! Schattierung? Ja! RETURN ' ' Menü-Verteilung PROCEDURE menu_choose LOCAL i|,dummy|,back$,old_sh! i|=MENU(0) REPEAT UNTIL MOUSEK=0 MENU OFF GET 0,0,639,18,back$ ! Menü retten SELECT i| CASE 1 ! Info ALERT 4," ROTOR Version 1.1 | by Christian Roth | & Matthias Brust”,1," Super! ", dummy| CASE 10 ! Rotationskörper rot_koerper_eingeben(TRUE) ! eingeben und zeichnen ! zeichnen CASE 11 ! nachträglich schattieren old_sh!=shadow! ! spart Rechenzeit beim shadow!=TRUE ! Rotieren farbe zeichnen shadow!=old_sh! CASE 12 ! Rotation, Translation, transformieren ! Vergrößerung CASE 14 ! automatische Schattierung shadow!=NOT shadow! ! an- oder ausschalten IF shadow! MENU 14,1 ELSE MENU 14,0 ENDIF CASE 16 ! Raus hier! END ENDSELECT PUT 0,0,back$ ! Menü erneuern RETURN ' ' Transformation aller Punkte PROCEDURE transform LOCAL x_trans,y_trans,z_trans,i& PRINT AT(33,12);" " PRINT AT(35,12);"Transformation" sinx=SINQ(x_wink) ! Sinus und Cosinus siny=SINQ(y_wink) ! interpoliert (SINQ sinz=SINQ(z_wink) ! und COSQ) vorbe- cosx=COSQ(x_wink) ! rechnen => spart cosy=COSQ(y_wink) ! Rechenzeit cosz=COSQ(z_wink) a=cosy*cosz ! Elemente der b=cosy*sinz ! Rotationsmatrix c=-siny ! berechnen d=sinx*siny*cosz-cosx*sinz e=sinx*siny*sinz+cosx*cosz f=sinx*cosy g=cosx*siny*cosz+sinx*sinz h=cosx*siny*sinz-sinx*cosz j=cosx*cosy FOR i&=0 TO anz_pu&-1 x_trans=x_3d&(i&)*x_skal ! Skalierung y_trans=y_3d&(i&)*y_skal z_trans=z_3d&(i&)*z_skal x_trans(i&)=x_trans*a+y_trans*b+z_trans*c ! Rotationen urn die 3 Achsen y_trans(i&)=x_trans*d+y_trans*e+z_trans*f z_trans(i&)=x_trans*g+y_trans*h+z_trans*j NEXT i& RETURN ' PROCEDURE zeichne_punkt(nr&) LOCAL x&,y& x&=punkt_x&(nr&) y&=punkt_y&(nr&) LINE x&-3,y&+3,x&+3,y&-3 ! Kreuzchen an LINE x&-3,y&-3,x&+3,y&+3 ! Punkt-Pos. LINE 643-x&,y&+3,637-x&,y&-3 ! malen LINE 643-x&,y&-3,637-x&,y&+3 IF nr&=0 ! 1. = Punkt DRAW x&,y& ELSE ! dann Linien DRAW punkt_x&(nr&-1),punkt_y&(nr&-1) DRAW TO x&,y& DRAW 640-punkt_x&(nr&-1),punkt_y&(nr&-1) DRAW TO 640-x&,y& ENDIF RETURN ' PROCEDURE raster LOCAL i& ! Raster mit CLS ! entsprechendem DEFLINE 3 ! Linienmuster FOR i&=40 TO 640 STEP 40 ! zeichnen LINE i&,0,i&,400 NEXT i& FOR i&=40 TO 400 STEP 40 LINE 0,i&,640,i& NEXT i& DEFLINE 1 DRAW 0,200 TO 640,200 DRAW 320,0 TO 320,400 RETURN ' ' Rotationskörper berechnen PROCEDURE rot_koerper_eingeben(flag!) LOCAL step_wink&,spalte&,next_spalte&,fl_spalte& LOCAL punkt&,flaeche&,n1&,n2& IF flag! REPEAT UNTIL MOUSEK=0 koerper_eingeben ! erst Körper eingeben ENDIF PRINT AT(33,12);" " PRINT AT(35,12);"Berechnung" ' Anzahl der Punkte=Anzahl d. Rotationen* eingegebene Punkte anz_pu&=MUL(rot_anz|,punkte&) ' Anzahl der Flächen=Anzahl d. Rotationen* (eingegebene Punkte-1) anz_fl&=MUL(rot_anz|,punkte&-1) spalte&=0 next_spalte&=punkte& fl_spalte&=0 step_wink&=360/rot_anz| ! 'Step'-Winkel berechnen ' Rotationskörper berechnen (Rotation um Y-Achse) FOR winkel&=step_wink& TO 360 STEP step_wink& IF next_spalte&=anz_pu& ! Bei der letzten Fläche sind next_spalte&=0 ! die Endpunkte die Punkte der ELSE ! ersten Reihe ssin=SINQ(winkel&) ! Sin und Cos wird öfter be- ccos=COSQ(winkel&) ! nötigt, deshalb vorberechnen ' Urpunkte um Winkels drehen FOR i&=0 TO punkte&-1 x=x_3d&(i&) ! Koordinaten d. Urpunkte z=z_3d&(i&) punkt&=ADD(next_spalte&,i&) x_3d&(punkt&)=x*ccos+z*ssin ! um die y-Achse drehen y_3d&(punkt&)=y_3d&(i&) ! und Punkte ins 3D- z_3d&(punkt&)=-x*ssin+z*ccos ! Array speichern NEXT i& ENDIF ' Flächen zusammensetzen: FOR i&=0 TO punkte&-2 flaeche&=ADD(fl_spalte&, i&) n1&=ADD(spalte&,i&) n2&=ADD(next_spalte&,i&) flaeche&(flaeche&,0)=n1& ! Punktnummern speichern flaeche&(flaeche&,1)=ADD(n1&,1) ! Reihenfolge: flaeche&(flaeche&,2)=ADD(n2&,1) ! 1---4 flaeche&(flaeche&,3)=n2s ! | | NEXT i& ! 2---3 spalte&=next_spalte& ! dasselbe ADD next_spalte&,punkte& ! mit der ADD fl_spalte&,punkte&-1 ! nächsten Spalte NEXT winkel& transform ! transformieren(rotieren...) verdecke ! Painter-Algorithmus ' ! zum Verdecken der Flächen RETURN ' ' Flächen projizieren PROCEDURE zeichnen LOCAL i&,k|,flaeche&,punkt& projektion ! Punkte auf 2D bringen DEFFILL 1,0,0 CLS FOR i&=0 TO anz_fl&-1 flaeche&=fl_sort&(i&) FOR k|=0 TO 3 ! Translation aller Punkte punkt&=flaeche&(flaeche&,k|) x_2d&(k|)=x_transl&+x_trans(punkt&) y_2d&(k|)=y_transl&-y_trans(punkt&) NEXT k| IF shadow! ! wenn schattieren IF farbe|(flaeche&)<>8 ! Farbe wählen DEFFILL 1,2,farbe|(flaeche&) ELSE DEFFILL 1,0,0 ENDIF POLYFILL 4,x_2d&(),y_2d&() ! Pinsel raus! ELSE POLYFILL 4,x_2d&(),y_2d&() ENDIF NEXT i& RETURN ' ' Transformation des Objekts PROCEDURE transformieren LOCAL key%,v! REPEAT KEYTEST key% ! Taste gedrückt? key%=key% AND 255 ! Ascii-Code IF key%>48 AND key%<57 ! zwischen 1-8 v!=TRUE ! auch verdecken SELECT key% CASE 49 ! '1': um X-Achse ADD x_wink,30 ! drehen CASE 50 ! '2': X-Achse zu- SUB x_wink,30 ! rückdrehen CASE 53 ! '5': um Z-Achse ADD z_wink,30 ! drehen CASE 54 ! '6': Z-Achse zu- SUB z_wink, 30 ! rückdrehen ' Die folgende Drehung um die Y-Achse ' bringt bei diesem Rotationskörper gar ' nichts, da er durch Rotation um die Y- ' Achse entsteht, ist aber bei Rotations- ' körpern um X oder Z-Achse sinnvoll. CASE 51 ! '3': um Y-Achse ADD y_wink,30 ! drehen CASE 52 ! '4': Y-Achse zu- SUB y_wink,30 ! rückdrehen CASE 55 ! Objekt mit MUL x_skal,1.2 ! Faktor 1.2 MUL y_ska1,1.2 ! vergrößern MUL z_skal,1.2 ! Verdecken nicht v!=FALSE ! nötig CASE 56 ! Objekt mit DIV x_skal,1.2 ! Faktor 1.2 DIV y_skal,1.2 ! verkleinern DIV z_skal,1.2 ! Verdecken nicht v!=FALSE ! nötig ENDSELECT transform IF v!=TRUE ! Verdecken nötig? verdecke ENDIF zeichnen ELSE IF MOUSEK=1 x_transl&=MOUSEX ! Objekt y_transl&=MOUSEY ! verschieben zeichnen ENDIF UNTIL MOUSEK=2 RETURN ' ' Errechnet die Farbe aller Flächen PROCEDURE farbe LOCAL i&,p1&,p2&,p3& PRINT AT(33,12) ; " PRINT AT(36,12); "Farbgebung" FOR i&=0 TO anz_fl&-1 p1&=flaeche&(i&,0) ! Punktnummern holen p2&=flaeche&(i&,1) p3&=flaeche&(i&,2) p1x=x_trans(p1&) ! Punktkoordinaten,die p1y=y_trans(p1&) ! mehrmals benötigt p1z=z_trans(p1&) ! werden qx=x_trans(p2&)-p1x ! Koordinaten werden qy=y_trans(p2&)-p1y ! fürs Vektorprodukt qz=z_trans(p2&)-p1z ! benötigt rx=x_trans(p3&)-p1x ry=y_trans(p3&)-p1y rz=z_trans(p3&)-p1z ox=qy*rz-qz*ry ! Vektorprodukt be- oy=qz*rx-qx*rz ! rechnen oz=qx*ry-qy*rx lx=p1x-licht_x& ! Vektor von Licht- ly=p1y-licht y& ! quelle zur Fläche lz=p1z-licht_z& alpha=ox^2+oy^2+oz^2 ! Betrag des Vektors alpha=SQR(alpha*(lx^2+ly^2+lz^2)) IF alpha<>0 alpha=(ox*lx+oy*ly+oz*lz)/alpha ENDIF farb=hintergrund_intent IF alpha<>0 ! Fläche beleuchtet? farb=farb-licht_intent*alpha ! Intensität ENDIF ! errechnen farbe|(i&)=9-(farb-INT(farb))*8 ! Farbwert zwischen NEXT i& ! 0 und 8 RETURN ' ' Punkte des Rotationskörpers PROCEDURE koerper_eingeben LOCAL ascii|,i& DIM punkt_x&(punkte_max|),punkt_y&(punkte_max|) punkte&=-1 raster ! Raster zeichnen DEFMOUSE 5 REPEAT REPEAT ascii|=ASC(RIGHT$(INKEY$)) IF ascii|=97 AND punkte&>=0 ! mit Undo letzten DEC punkte& ! Punkt löschen raster IF punkte&>=0 FOR i&=0 TO punkte& ! Punkte zeichne_punkt(i&) ! zeichnen NEXT i& ENDIF ELSE IF ascii|=98 ! mit Help alle punkte&=-1 ! Punkte löschen raster ENDIF UNTIL MOUSEK=1 OR ascii|=27 REPEAT UNTIL MOUSEK=0 IF ascii|<>27 ! Wenn nicht ESC INC punkte& ! gedrückt, Punkt punkt_x&(punkte&)=MOUSEX ! im Array speichern punkt_y&(punkte&)=MOUSEY ! und zeichne_punkt(punkte&) ! zeichnen ENDIF UNTIL ascii|=27 OR punkte&=punkte_max| INC punkte& DEFMOUSE 0 FOR i&=0 TO punkte&-1 x_3d&(i&)=punkt_x&(i&)-320 ! Punkte von 2D nach y_3d&(i&)=200-punkt_y&(i&) ! 3D übertragen z_3d&(i&)=0 NEXT i& ERASE punkt_x&() ERASE punkt_y&() RETURN ' ' Zentralprojektion aller Raumpunkte PROCEDURE projektion LOCAL i&,i FOR i&=0 TO anz_pu&-1 i=z_trans(i&)-beo_z& x_trans(i&)=beo_x&-beo_z&*(x_trans(i&)-beo_x&)/i y_trans(i&)=beo_y&-beo_z&*(y_trans(i&)-beo_y&)/i NEXT i& RETURN ' ' Painter-Algorithmus zum Verdecken ' von Flächen PROCEDURE verdecke LOCAL i&,i1&,i|,z_summe,mittel PRINT AT(33,12);" " PRINT AT(33,12);"Flächen sortieren" FOR i&=0 TO anz_fl&-1 z_summe=0 FOR i|=0 TO 3 ! Z-Summe berechnen ADD z_summe,z_trans(flaeche&(i&,i|)) NEXT i| mittel=z_summe/4 ! Mittelwert bilden mittel(i&)=mittel i1&=0 DO ! Fläche einsortieren EXIT IF mittel(fl_sort&(i1&))<=mittel OR i1&>=i& INC i1& LOOP INSERT fl_sort&(i1&)=i& NEXT i& IF shadow! ! wenn nötig => Farbgebung farbe ENDIF RETURN ' menu_points: DATA ROTOR, Über ROTOR ,a,a,a,a,a,a,"" DATA Optionen, Eingeben, Schattieren, Transformieren,------------------, Schattierung ,-----------------, Ende,"" DATA Parameter, Beobachter, Lichtquelle, Schrittwinkel, Raster,""