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?
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.
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.
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.
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.
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)
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.
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,""