Schnelles 3D auf dem ST: Flächendeckende Objektgrafik in GFA-BASIC, Teil II

Im vorangegangenen Artikel, der zusammen mit dem Programmlisting als einzelner Artikel gerade noch vertretbar schien, wurde ein Programm zur Erstellung und Darstellung dreidimensionaler Objektgrafik vorgestellt. Einige Fragen, die noch offenbleiben muhten sowie einige hilfreiche Funktionen zur Programmerweiterung werden jetzt hier behandelt.

GFA-Freaks werden es schon längst erkannt haben, die Datenstruktur des Felds Xyz%(2,Pun_anz) für die Punkte weicht von der des Flächenfelds Fl%(Eck_max+3,Fl_max) ab. So werden die Punkte von 1 bis P_anz durchnumeriert im Gegensatz zu den Flächen, die von 0 bis F_anz-1 zählen. Die Einträge im Punktfeld entsprechen den Koordinaten X,Y,Z des jeweiligen Punkts. Die Einträge im Flächenfeld von 0 bis Eck_max sind die Nummern der Punkte analog zum Feld Xys%() in der ‘Korkenzieherreihenfolge’. Die drei Einträge, die darauf folgen (Eck_max+1 bis Eck_max+3) sind zuerst die Anzahl der Punkte - 1 und dann 2 Werte für die Farb- oder Musterinformation.

Mit Kenntnis dieser Struktur erschließt sich einem die hier neu vorgestellte Prozedur F use recht gut. Am linken Rand des Bildschirms werden alle vorhandenen Flächen aufgelistet. Sollten es mehr sein als der Monitor anzeigen kann, läßt sich mit Pfeilen nach oben oder nach unten scrollen. Jeder Kasten zeigt Füllfarbe oder -muster, die Flächennummer und die Anzahl der Punkte dieser Fläche Eine Mausbewegung auf einen der Kästchen, und eine Inrandung (neudeutsch: Gegensatz von Umrandung) erscheint. Zudem blinken die Punkte dieser Fläche im Anzeigefeld, falls sie sichtbar sind. Ein Mausklick auf das Flächenkästchen, und es erscheint eine Alarmbox mit den Möglichkeiten. Füllmuster oder -farbe abzuändern oder die Fläche wegzuwerfen. So lassen sich nun falsch konstruierte Flächen leicht entfernen, und die Umwandlung von Objekten verschiedener Auflösungsstufen ist auch schnell gemacht.

Diskettenkomfort

Geradezu notwendigen Komfort bringen die neuen Menüpunkte “OBJ LADEN" und “SPEICHERN". Nomen est Omen, es sollte nur erwähnt werden, daß mit Rechtsklick auf diese Menüpunkte ein Pfadname vorgegeben werden kann, und die Dateiart *.3D? sollte am besten à la DEGAS für die unterschiedlichen Auflösungsarten verwendet werden (3D1 niedrige Auflösung, 3D2 mittel, 3D3 hochauflösend).

Die Dateien werden nach einem einfachen Verfahren zusammengequetscht, man muß jedoch darauf achten, daß die Variable Eck_max nicht kleiner gewählt wird als die maximale Eckenzahl des zu ladenden Objekts, sonst erfolgt eine Warnung vom Programm. In diesem Zusammenhang der Hinweis, daß die Variablen Pun_max (maximale Punktanzahl), Fl_max (maximale Flächenanzahl) und Eck_max (maximale Anzahl der Eckpunkte einer Fläche) je nach Belieben verändert werden können.

Unbekannte Tiefen

Eine neue Funktion ist auch "TIEFENVERZERRUNG". Hiermit können die Grundwerte von Darstx und Darsty verändert werden, die die Anzeige der Tiefe im Eingabefenster regeln. Dies ist vor allem dann vonnöten, wenn mehrere Punkte so dicht beieinanderliegen, daß die Flächenerstellung zur Tortur wird. Nach einem Klick auf “TIEFENVERZERRUNG" verändert sich die Darstellung abhängig von der Mausposition. Sie sollte langsam von der oberen rechten Ecke des ersten Quadranten Richtung Ursprung geändert werden. Je näher man dem Mittelpunkt kommt, desto stärker die Verzerrung. Bei der Position, an der die Punktauflösung günstig ist, genügt ein Mausklick, und die neue Verzerrung wird von nun an vom Programm verwendet.

Kaum erwähnenswert ist die Programmabbruchsfunktion, die einem die Fingerakrobatik von Alternate-Shift-Control erspart. Bei Programmversionen, die man kompilieren will, sollte “End" durch “Quit" ersetzt werden.

Eine weitere Änderung ergibt sich in der Angabe der X-, Y-, Z-Werte. Die X- und Y-Koodinate können jetzt genau wie der Z-Wert mit Mausdruck oder -klick verändert werden. Damit verschiebt sich das Koordinatenkreuz, und Objekte, die größer sind als das Eingabefenster, können bearbeitet werden.

Die letzte Veränderung bezieht sich auf die neue Menüfunktion “QUADER ERSTELLEN". Hiermit kann ein beliebig großer Quader an jeder Stelle parallel zu den Koordinatenachsen erstellt werden. Nach Klick auf die Menüfunktion muß man sich zuerst entscheiden, ob man den Quader anhand des Mittelpunkts oder des vorderen linken unteren Eckpunkts bestimmen will. Danach können die Größenangaben für drei Seiten angegeben werden, und dann erfolgt die Eingabe des Eckpunkts bzw. des Mittelpunkts. Nun brauchen nur noch die 6 Muster oder Farben für die Flächen des Quaders eingegeben zu werden, und er erscheint in dem Anzeigefeld.

Versteckte Hilfe

In der bisherigen Programmbeschreibung wurden zwei Funktionen über die das Programm verfügt, nicht erläutert. Die eine bezieht sich auf das selbsttätige Überprüfen der 'Korkenzieherregel' bei der Flächenerstellung. Bei allen exakt definierten ausgefüllten Objekten gehört jede Linie zu genau 2 Flächen. Und bei konsequenter Anwendung der ‘Korkenzieherregel' stellt sich heraus, daß die Flächenecken jede Linie immer gegenläufig beschreiben. Abbildung 1 veranschaulicht diesen verbal schwer zu beschreibenden Effekt. Hier setzt auch das Programm ein und überprüft in der Prozedur F_akt, ob nach Fertigstellung einer Fläche diese mit irgendeiner Linie einer anderen Fläche dieselbe Richtung beschreibt. Falls ja, werden die Eckpunkte in umgekehrter Reihenfolge abgespeichert (unter Zuhilfenahme des X%()-Feldes). Dies erklärt, warum neue Flächen immer an bereits existierende angrenzen sollten, denn nur dann kann das Programm die richtige ‘Korkenzieherorientierung' überprüfen bzw. einsetzen.

Ein anderer Aspekt ist die Darstellung des Objekts mit den den Linienmustern innewohnenden Angaben über Flächenzugehörigkeit. Dieser für die Erstellung vollständiger Objekte hilfreiche Modus, der sich mit “INFO + ANZEIGE" umschalten läßt, wird durch die Überprüfung in der Prozedur “Show" (If Grmbo...) erreicht. Hier wird jede Linie daraufhin überprüft, ob sie bei einer anderen Fläche auch schon vorhanden ist und, falls ja, gestrichelt dargestellt. Diese Überprüfung geht (Brute Force) alle Flächen und deren Linien durch und bricht nur bei einer zweiten Linie ab. Dieser Aufwand, der für jede einzelne Linie aufgebracht werden muß. erklärt den langsamen Bildaufbau in dieser Darstellungsart. Programmtechnisch kann hier noch viel verbessert werden. da jede gestrichelte Linie ja mindestens zweimal berechnet und ausgegeben wird. Um das Programm nicht noch länger und unübersichtlich zu machen, mußte hierauf leider verzichtet werden.

Ein Hinweis noch für die Erstellung von großen Flächen mit vielen Eckpunkten. Hier muß darauf geachtet werden, mit den ersten drei Punkten ‘Korkenzieherrichtigkeit' zu erzielen, denn nur diese werden für die Berechnung des Kreuzprodukts ausgewertet. Danach entgegengesetzte Laufrichtung beeinflußt die Darstellung nicht im mindesten.

Die Einbindung der neuen Prozeduren dürfte nicht schwerfallen. Außer den DATA-Zeilen muß nur noch der Befehlsaufruf in der Hauptschleife ersetzt werden (siehe Listing). Die Prozeduren selbst können einfach an das bisherige Programm angehängt werden. Und nach all der Mühe bleibt lediglich noch der Wunsch, daß sie mit beeindruckenden 3D-Konstruktionen und erfolgreichen Programmerweiterungen gekrönt werden. Die Redaktion würde sich freuen, an Ihren Erfahrungen und Ergebnissen teilzuhaben.

Martin A. Wielebinski

Literatur

William M. Newman/Robert F. Sproull,
Grundzüge der interaktiven Computergrafik,
1986, McGraw-Hill, Hamburg

c't 1984,
Heise Verlag, Hannover
(Sehr unterhaltsame Artikelserie über ein 6502-Assemblerpaket für dreidimensionale Drahtmodelle.)

c't S.144 ff
Von Vektoren und Volumina: Nr. 2 1988,
Heise Verlag, Hannover

CHIP SPECIAL
Computergrafik: März 1981,
Vogel Verlag, Würzburg.


'
' *************************************************
' *                                               *
' * 3D-Grafik Edier- und Demoprogramme für die ST *
' * von Martin A Wielebinski.                     *
' * Teil 2, die bisher 'reservierten' Funktionen: *
' * Flächeneditor, Load & Save.                   *
' *                                               *
' *************************************************
'
' Um die zusätzlichen Prozeduren lauffähig zu machen müssen zwei kleine
' Änderungen des Originalprogramms vorgenommen werden
'
' Die Befehlsaufrufe in der Hauptschleife lauten nunmehr:
'
If Com<10
	On Com Gosub Wert,Wert,Wert,In_gr,Verz,Gitt,Phol,Fhol,G3d 
Else
	On Com-9 Gosub F_use,Quader,D,D,D.D,D,D,Olad,Osp,Pstp 
Endif
'
' Und die Data-Zeilen mit dan Menütasten folgendermaßen:
'
Data "- X:              +"
Data "- Y:              +"
Data "- Z:              +""
Data INFO + ANZEIGEMODUS 
Data TIEFEN-VERZERRUNG 
Data GITTER | SETZEN 
Data PUNKTMOD|XYZ-EING 
Data FLÄCHEN ERSTELLEN 
Data 3D-GRAFIK STARTEN 
Data FLÄCHEN EDITIEREN 
Data QUADER EINGEBEN 
Data FREI,FREI,FREI 
Data FREI,FREI,FREI 
Data OBJ LADEN|PFAD BEST 
Data SPEICHERN|PFAD BEST 
Data 3D PROGRAMM BEENDEN
'
' Die nun folgenden Prozeduren werden einfach an das Originalprogramm 
' angehängt, eigene Funktionen müsstan problemlos 
' weiterbenützt werden können.
'
Procedure Verz ! Bildschirmverzerrung einstellen 
    Local I,J,A$
    A$="Darstellungsverzerrung:|Je näher sie die Maus dem|Mittelpunkt bringen"
    Gosub Ali(0,A$+' desto|stärker die Verzerrung.",1,"Aha!")
    Gosub Mclr
    J=Grmbo ! Schnelle Darstellung
    Grmbo=0
    Repeat
        Darstx=(Mousex-Ymi)/10 ! Verzerrung x und y anhand
        Darsty=(Ymi-Mousey)/10 ! des Mittelpunkts berechnen
        If Darstx=0 ! Dürfen aber nicht 0 betragen 
            Darstx=1 
        Endif
        If Darsty=0 ! dito 
            Darsty=1 
        Endif
        Gosub Show  ! Veränderungen anzeigen
    Until Mousek    ! bis Maustaste geklickt wird
    Grmbo=J         ! Originaldarstellung wieder herstellen
Return
'
Procedure Hol_pfad ! Kein Kommentar
    Gosub Inbox("DEN ZUGRIFFSPFAD FÜR|DIE DATEN ANGEBEN.|z.B: A:\GFA\GRAFIK\3D\",1)
    Disk$=Wert$
Return
''
Procedure Osp       ! Objekt abspeichern
    Local I,J,Maxeck
    If Mk=2
        Gosub Hol_pfad  ! Bei Rechtsklick Pfad holen
    Else                ! sonst:
        Fileselect Disk$+"*.3D?",F$
        If F$<>""
            Open "O",#1,F$ ! Falls guter Dateiname öffnen
            Maxeck=0
            For I=0 To F_anz-1
                If Fl%(Eck_max+1,I)>Maxeck
                    Maxeck=Fl%(Eck_max+1,I) ! Maximale Eckanzahl einer Fläche des 
                Endif ! Objekts ermitteln
            Next I
            Gosub Byte(F_anz) ! Punktanzahl,
            Gosub Byte(F_anz) ! Flächenanzahl 
            Gosub Byte(Maxeck) ! und maximale Eckenanzahl zur Datai
            If P_anz
                For I=1 To P_anz 
                    For J=0 To 2
                        Gosub Byte(Xyz%(J,I)) ! Alle Punktkoordinaten,
                    Next J 
                Next I 
            Endif 
            If F_anz
                For I=0 To F_anz-1 
                    For J=0 To Maxeck
                        Gosub Byte(Fl%(J,I))! alle relevanten Flächennummern
                    Next J
                    For J=Eck_max+1 To Eck_max+3 
                        Gosub Byte(Fl%(J,I))! und die Flächeninformationen ausgeben.
                    Next J 
                Next I 
            Endif
            Close #1 ! Das war es schon.
        Endif
    Endif
Return
'
Procedure Byte(W) ! Diese Proz. wirft 2 Bytes zur Diskette
    W=W+32768
    Out #1,(W Div 256)
    Out #1,(W Mod 256)
Return
'
Procedure Olad ! Lädt ein Objekt von Disk
    Local I,J,Maxeck 
    If Mk=2
        Gosub Hol_pfad ! Rechtsklick -> holt Pfad
    Else
        Fileselect Disk$+"*.3D?","",F$
        If F3<>""
            Open "I",#1,F$ ! Falls guter Dateiname anfügan
            Gosub Wrd
            I=Ww ! und 3 Words einlesen
            Gosub Wrd
            J=Ww
            Gosub Wrd 
            Maxeck=Ww
            If Maxeck>Eck_max ! Maximale Eckanzahl möglich?
                Gosub Ali(3,"Objekt hat mehr Ecken|als die Var. Eck_max.",1,"Stop")
            Else
                P_anz=I ! JA, Werte übernehmen
                F_anz=J
                If P_anz
                    For I=1 To P_anz 
                        For J=0 To 2 
                            Gosub Wrd
                            Xyz%(J,I)=Ww ! Alle Punktkoordinaten 
                        Next J 
                    Next I 
                Endif 
                If F_anz
                    For I=0 To F_anz-1 
                        For J=0 To Maxeck 
                            Gosub Wrd
                            Fl%(J,I)=Ww ! alle Flächennummern 
                        Next J
                        For J=Eck_max+1 To Eck_max+3 
                            Gosub Wrd
                            Fl%(J,I)=Ww ! und alle Flächeninfos lesen.
                        Next J 
                    Next I 
                Endif 
            Endif
            Close #1 ! das wars...
        Endif
    Endif
Return
'
Procedure Wrd ! Diese Procedure liest 2 Bytes
    Wl=Inp(#1)
    Ww=Wl*256+Inp(#1)-32768 
Return
'
Procedure Pstp ! Programm abbrechen???
    Local A$
    A$="Programm wirklich|beenden und alle|Daten vernichten?"
    Gosub Ali(3,A$,2," JA |Nein")
    If But=1
        Cls ! Jawoll!!!
        End 
    Endif 
Return
'
' Diese umfangreiche Procedure ermöglicht die Edierung von Flächen:
'
Procedure F_use
    Local Mmx,Mmy,Mmk,I,Stnr,Aktnr,Rnr,A$
    If F_anz
        A$="Sie können links die Fläche|auswählen und durch|Mausklick edieren!"
        Gosub Ali(0,A$+"Zurück mit Rechtsklick!",1,"Aha!")
        Deffill 0,1 
        Pbox 0,0,50,Ysl 
        Text 10,Tyo,"^^^^^"
        Text 10,Yty*19+Tyo,"vvvvv" ! Bildschirm ruinieren
        Color 1
        Stnr=0 ! Startnummer = 0
        '
        Starty:
        Deffill 0,1
        Pbox 0,Yty,50,Yty*19 ! Flächenbox am linken Schirmrand
        Aktnr=-1 
        For I=1 To 18
            Box 0,Yty*I,50,Yty*(I+1) ! Box ausgeben 
            If Stnr+I-1<F_anz
                A$=Str$(Stnr+I)+" "+Str$(Fl%(Eck_max+1,Stnr+I-1)+1)+"P"
                Text 28-3*Len(A$),Yty*I+Tyo,A$ ! Text ausgeben
                Mmy=Fl%(Eck_max+2,Stnr+I-1)
                Mmx=Fl%(Eck_max+3,Stnr+I-1)
                If Max
                    Deffill 1,Mmx,Mmy 
                Else
                    Deffill Mmy,1 
                Endif
                Pbox 0,Yty*I,8,Yty*(I+1) ! Füllfarbe oder -muster
            Endif 
        Next I
        Do ! Warteschleife
            Mouse Mmx,May,Mak
            If Mmx<40 ! Maus In Box?
                I=Mmy Div Yty
                If I>0 And I<19 And Stnr+I-1<F_anz ! ja, gültige Flächennummer?
                    If I<>Aktnr
                        Graphmode 3 ! ja, aktivieren
                        If Aktnr<>I ! alte ausschalten???
                            Box 10,Yty*Aktnr+2,48,Yty*(Aktnr+1)-2 ! jawoll 
                        Endif
                        Box 10,Yty*I+2,48,Yty*(I+1)-2 ! Inrandung
                        Aktnr=I ! aktive Position
                        Rnr=Stnr+Aktnr-1 ! aktuelle Flächennummer
                        Graphmode 0 
                    Endif 
                Endif
                If Mmk=1 ! Maus auch noch gedrückt?
                    If I>0 And I<19 ! ja, auf Flächennummer?
                        If Aktnr<>-1
                            Gosub Ali(2,"Fläche löschen oder|neu einfärben ???",1,"Mix|Kill|Farbe") 
                            If But=3
                                Gosub Colget ! neue Farbe oder Muster holen 
                                Fl%(Eck_max+2,Rnr)=Cnr !abspeichern 
                                Fl%(Eck_max+3,Rnr)=Czei 
                            Endif
                            If But=2 And F_anz>0 !Fläche löschen???
                                For I=Rnr To F_anz !jawoll, durch Verschieben 
                                    For J=0 To Eck_max+3 ! hinauswerfen 
                                        Fl%(J,I)=Fl%(J,I+1)
                                    Next J 
                                Next I
                                Dec F_anz ! Flächenzähler -= 1 
                            Endif 
                        Endif
                        Goto Starty ! und neue Box zeichnen.. 
                    Else
                        If I=0 ! Nach oben scrollen?
                            Sub Stnr,16 
                            If Stnr<0 
                                Stnr=0 
                            Endif
                            Goto Starty 
                        Else
                            Add Stnr,16 ! ansonsten nach unten
                            If Stnr+16>F_anz 
                                Stnr=F_anz-18 
                            Endif
                            Goto Starty 
                        Endif 
                    Endif 
                Endif 
            Endif
            If Aktnr<>-1 ! Falls Fläche gewählt
                Gosub Flacker(Stnr+Aktnr-1) ! Die Punkte blinken
                Gosub Flacker(Stnr+Aktnr-1) ! lassen 
            Endif
            Exit If Mmk=2 ! Bei Rechtsklick beenden 
        Loop 
    Endif 
Return
'
Procedure Flacker(F_nr) ! Punktblinkroutine
    Local I,J,X,Y 
    Graphmode 3
    For J=0 To Fl%(Eck_max+1,F_nr) ! Alle Punkte 
        I=Fl%(J,F_nr) ! umrechnen
        X=Ymi-Arbxyz%(0)+(Xyz%(0,I)+(Xyz%(2,I)-Arbxyz%(2))/Darstx)
        Y=Ymi-Arbxyz%(1)-(Xyz%(1,1)+(Xyz%(2,I)-Arbxyz%(2))/Darsty)
        Xf X>53 And X<Ys-3      ! und falls sichtbar
            Circle X,Y,4        ! anzeigen
        Endif 
    Next J 
    Graphmode 0 
Return
'
Procedure Quader ! Quader in einem Zug erstellen 
    Local P1,P2,P3,P4,P5,P6,F7,P8,I,Bo,A$ 
    A$="Quader erstellen. Wodurch|festlegen? (Mitte oder|Ecke unten links vorne)" 
    Gosub Ali(2,A$,1,"Nix|Mitte|Ecke")
    If But>1
        Gosub Inbox("LÄNGE DER X,YZ-SEITEN|EINGEBEN.",3)
        Bo=1
        For I=0 To 2
            Y%(I)=X%(I) ! Werte merken
            If Y%(I)=0
                Bo=0            ! Falls 0 abbrechen
            Endif 
        Next I 
        If Bo
            Gosub Inbox("UND JETZT DEN BE-|FESTIGUNGSPUNKT ",3)
            If But=2 ! Falls Mittelpunkt
                For I=0 To 2
                    X%(I)=X%(I)-Y%(I)/2 ! Un.li vor Ecke errechnen
                Next I 
            Endif
            Gosub P_neu(X%(0),X%(1),X%(2)) ! Alle neuen Punkte anfordern
            P1=Pnr
            Gosub P_neu(X%(0),X%(1)+Y%(1),X%(2))
            P2=Pnr
            Gosub P_neu(X%(0)+Y%(0),X%(1)+Y%(1),X%(2)) 
            P3=Pnr
            Gosub P_neu(X%(0)+Y%(0),X%(1),X%(2))
            P4=Pnr
            Gosub P_neu(X%(0),X%(1),X%(2)+Y%(2))
            P5=Pnr
            Gosub P_neu(X%(0),X%(1)+Y%(1),X%(2)+Y%(2)) 
            P6=Pnr
            Gosub P_neu(X%(0)+Y%(0),X%(1)+Y%(1),X%(2)+Y%(2))
            P7=Pnr
            Gosub P_neu(X%(0)+Y%(0),X%(1),X%(2)+Y%(2)) 
            P8=Pnr
            Gosub F14_neu(P1,P2,P3,P4) ! und die 6 Flächen erstellen
            Gosub F14_neu(P1,P5,P6,P2)
            Gosub F14_neu(P2,P6,P7,P3)
            Gosub F14_neu(P3,P7,P8,P4)
            Gosub F14_neu(P4.P8,P5,P1)
            Gosub F14_neu(P8,P7,F6,P5)
        Endif 
    Endif 
Return
'
Procedure F14_neu(A,B,C.D) ! 4-Punktfläche erstellen
    Fl%(0,F_anz)=A 
    Fl%(1,F_anz)=B 
    Fl%(2,F_anz)=C 
    Fl%(3,F_anz)=D
    Fl%(Eck_max+1,F_anz)=3   ! alles eintragen
    Gosub Colgat             ! Farbe oder Muster holen
    Fl%(Eck_max+2,F_anz)=Cnr ! abspeichern 
    Fl%(Eck_max+3,F_anz)=Czei
    Inc F_anz           ! Flächenzähler erhöhen
Return

Listing: 3 D-Grafik-Edier- und Demoprogramm Teil 2



Aus: ST-Computer 01 / 1989, Seite 127

Links

Copyright-Bestimmungen: siehe Über diese Seite