Rotor: 3D-Grafik hautnah

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,""


Aus: ST-Computer 11 / 1992, Seite 96

Links

Copyright-Bestimmungen: siehe Über diese Seite