der Arbeit

Werbung
Konzeption & Realisierung
eines prozeduralen Ansatzes
zur Erzeugung
von Gebäuden
Masterarbeit
von
Sven Janusch
Fachbereich Informatik
Hochschule Darmstadt
Darmstadt, 2007
Referentin: Prof. Dr. Elke Hergenröther
Korreferent: Prof. Dr. Wolf-Dieter Groch
Eidesstattliche Erklärung
Hiermit erkläre ich an Eides Statt, dass ich die vorliegende Masterarbeit selbständig und ohne fremde
Hilfe verfasst habe. Diese Arbeit hat in gleicher oder ähnlicher Form noch keiner Prüfungsbehörde
vorgelegen.
_____________________
Sven Janusch
Kelkheim, den 25.04.2007
Danksagung
Mein erster Dank geht an Prof. Dr. Elke Hergenröther für die Betreuung dieser Arbeit und Hilfe bei der
Gliederung. Der nächste Dank geht an die gesamte 3D-Abteilung von Related Designs. Darunter besonders an Burkhard Ratheiser, der die Idee für dieser Arbeit hatte und für Betreuung innerhalb der Firma
zuständig war und an Wolfgang Klose für die tatkräftige Unterstützung bei der MFC-Programmierung.
Weiterhin danke ich Andreas Jupe für die Fertigung von grafischen Inhalten und Siegfried Janusch, Dr.
Gerd Schrader sowie Prof. Dr. Kurt-Ulrich Witt für das Korrekturlesen der Arbeit.
Inhaltsverzeichnis
1. Einleitung.......................................................................................................................... 1
1.1 Anforderungen......................................................................................................... 2
1.2 Historischer Rückblick............................................................................................ 3
1.3 Verwandte Arbeiten................................................................................................. 8
1.4 Lösungsansatz und Überblick.................................................................................. 14
2. Architektonische Grundlagen.......................................................................................... 15
2.1 Merkmale................................................................................................................. 15
2.2 Dächer..................................................................................................................... 16
2.2.1 Begriffe....................................................................................................... 16
2.2.2 Dachformen................................................................................................ 17
2.2.3 Dachneigung............................................................................................... 17
2.2.4 Dachausmittlung......................................................................................... 18
3. Lindenmayer-Systeme...................................................................................................... 19
3.1 Deterministisch kontextfreie Lindenmayer-Systeme.............................................. 20
3.2 Deterministisch kontextsensitive Lindenmayer-Systeme........................................ 21
3.3 Verzweigende Lindenmayer-Systeme..................................................................... 23
3.4 Stochastische Lindenmayer-Systeme...................................................................... 24
3.5 Parametrische Lindenmayer-Systeme..................................................................... 25
3.6 Umgebungssensitive und offene Lindenmayer-Systeme........................................ 26
4. Straight-Skeleton.............................................................................................................. 28
4.1 Ereignisse................................................................................................................ 29
4.2 Distanz..................................................................................................................... 30
4.3 Definition................................................................................................................. 31
4.4 Algorithmus............................................................................................................. 31
4.5 Berechnung der Ereignisse...................................................................................... 32
4.5.1 Edge Events................................................................................................ 32
4.5.2 Split Events................................................................................................. 33
4.5.3 Vertex Events............................................................................................... 34
4.6 Gewichtung............................................................................................................. 35
5. Konzept.............................................................................................................................. 37
5.1 Regelbasierte System.............................................................................................. 39
5.1.1 Variablen..................................................................................................... 40
5.1.2 Funktionen.................................................................................................. 40
5.1.3 Konstanten.................................................................................................. 41
5.1.4 Produktionen............................................................................................... 42
5.1.5 Wahrscheinlichkeiten.................................................................................. 43
5.1.6 Bedingungen............................................................................................... 45
5.1.7 Transformation .......................................................................................... 45
5.1.8 Verzweigungen............................................................................................ 47
5.1.9 Ausführung.................................................................................................. 48
5.2 Grammatiken........................................................................................................... 49
5.2.1 Mass-Grammar........................................................................................... 50
5.2.1.1 Raum............................................................................................. 50
5.2.1.2 Anwendung.................................................................................... 50
5.2.2 Facade-Grammar....................................................................................... 52
5.2.2.1 Raum............................................................................................. 52
5.2.2.2 Anwendung.................................................................................... 52
5.2.3 Border-Grammar........................................................................................ 54
5.2.3.1 Raum............................................................................................. 54
5.2.3.2 Anwendung.................................................................................... 54
5.2.4 Profile-Grammar........................................................................................ 56
5.2.4.1 Raum............................................................................................. 57
5.2.4.2 Texturierung.................................................................................. 57
5.2.4.3 Anwendung.................................................................................... 57
5.2.5 Kommunikation........................................................................................... 60
5.3 Primitive.................................................................................................................. 61
5.3.1 Wand-Primitive........................................................................................... 61
5.3.1.1 Formen.......................................................................................... 61
5.3.1.2 Fassaden....................................................................................... 62
5.3.1.2 Ecken............................................................................................. 62
5.3.1.3 Texturierung.................................................................................. 63
5.3.1.4 Funktionen.................................................................................... 63
5.3.2 Dach-Primitive........................................................................................... 64
5.3.2.1 Formen.......................................................................................... 64
5.3.2.2 Dachdurchdringung...................................................................... 64
5.3.2.3 Fassaden....................................................................................... 67
5.3.2.4 Kanten........................................................................................... 69
5.3.2.5 Texturierung.................................................................................. 69
5.3.2.6 Funktionen.................................................................................... 70
5.4 Gruppen................................................................................................................... 71
5.4.1 Modell-Gruppen......................................................................................... 71
5.4.1.1 Funktion........................................................................................ 72
5.4.1.2 Schnitt............................................................................................ 72
5.4.1.3 CutOut-Modell.............................................................................. 73
5.4.1.4 Anwendung.................................................................................... 74
5.4.2 Textur-Gruppen........................................................................................... 74
5.5 Subdivision und Symmetrie.................................................................................... 75
5.5.1 Subdivision.................................................................................................. 75
5.5.1.1 SubDiv........................................................................................... 76
5.5.1.2 Part................................................................................................ 76
5.5.1.3 Split............................................................................................... 77
5.5.2 Symmetrie................................................................................................... 78
5.6 Umwelt.................................................................................................................... 79
5.6.1 Globale Umwelt.......................................................................................... 79
5.6.2 Lokale Umwelt............................................................................................ 80
5.6.2.1 Umgebungstypen........................................................................... 81
5.6.2.2 Abtastung....................................................................................... 81
5.6.2.2.1 Punkt-Abtastung.................................................................. 82
5.6.2.2.2 Flächen-Abtastung.............................................................. 82
5.6.2.2.3 Kanten-Abtastung................................................................ 83
5.6.2.2.4 Punkt-Gerade-Abtastung..................................................... 84
5.6.2.3 Anfrage-Funktionen...................................................................... 84
6. Resultate............................................................................................................................. 87
7. Schlussbemerkungen........................................................................................................ 91
7.1 Fazit......................................................................................................................... 91
7.2 Ausblick................................................................................................................... 92
7.3 Zusammenfassung................................................................................................... 93
8. Literaturverzeichnis......................................................................................................... 94
1. Einleitung
Die vorliegende Arbeit wurde für das Computerspiel Anno 4 (Working Title) konzeptioniert, basierend auf den Erkenntnissen durch
dessen Vorgängertitel Anno 1701. Das von
Related Designs1 hergestellte Anno 1701 ist
ein Wirtschaftssimulations- und Aufbauspiel,
bei dem die Kolonialisierung, die Diplomatie, der Handel und der Aufbau einer Stadt
im Vordergrund stehen. Begonnen wird meist
mit einem Schiff, durch dessen Hilfe die erste Insel besiedelt werden kann, um dort eine
Kolonie zu errichten. Je größer die Kolonie
wird, desto mehr Waren fordert die Bevölkerung, was unabwendbar zur Ausweitung der
Kolonie führt. Im Laufe der Zeit entwickelt
Abb. 1.1 Anno 1701
sich die kleine Kolonie zur einer Großstadt
und schließlich zu einem riesigen Imperium.
Dieses erstreckt sich über mehrere Inseln,
besitzt Handelsstrukturen, Straßennetze und
vor allem jede Menge Produktionsgebäude,
Wohnhäuser und sonstige Bauwerke. Obwohl bereits über einhundert unterschiedliche
Gebäude in dem Spiel integriert sind, lässt
es sich nicht vermeiden, dass immer wieder
gleiche Gebäude und Strukturen zu erkennen
sind. Diese Wiederholungen vermitteln ein
unrealistisches Stadtbild. Zwar sind auch in
der realen Welt häufig Gebäude vom gleichen
Typ (z.B. Fachwerkbau) vorhanden, dessen
ungeachtet sieht jedes Gebäude jedoch einzigartig aus, von den Reihenhäusern der NeuAbb. 1.2 Stadt aus Anno 1701
zeit einmal abgesehen. Aus diesem Grund ist
es wichtig, dass sich jedes Gebäude von den anderen unterscheidet und somit eine lebendigere und
organische Stadt entsteht. Um dies zu erreichen, müssten noch mehr Gebäude für das Spiel modelliert
werden, wodurch allerdings die Arbeitszeiten und die Kosten steigen. Eine andere Möglichkeit ist, dass
die Modellierung der kompletten Gebäude oder einzelnen Gebäudeteilen ­automatisch berechnet wird.
Abb. 1.3 No Man‘s Land
Related Designs ist eine der führenden Entwicklerfirmen von Computerspielen in Deutschland. Bekannte Projekte sind unter
anderem America, No Man’s Land, Castle Strike und Anno 1701.
1
An dieser Stelle kommt ein prozeduraler Ansatz ins „Spiel“. Prozedural bedeutet, dass ein Gebäude
nicht mehr bis ins kleinste Detail vormodelliert wird, sondern der Computer dieses anhand bestimmter
Vorgaben und Regeln berechnet. Während dieser Berechnung kann der Computer Varia­tionen in die
einzelnen Gebäude einbauen, wodurch eine größere Vielfalt entsteht und damit kein Gebäude mehr
dem anderen gleicht. Durch die größere Vielfalt könnte wiederum die Langzeitmotiva­tion beim Spielen
steigen, weil es immer wieder etwas Neues zu sehen und zu entdecken gibt. Außerdem entsteht für den
Spieler ein neues Spielerlebnis, da der Spieler eine einzigartige Stadt aufbauen kann und dies jedes Mal,
wenn er das Spiel von vorne beginnt.
Obwohl das System vorerst für Computerspiele entwickelt wurde, sind auch andere Bereiche denkbar,
in denen es eingesetzt werden könnte, beispielsweise zur Unterstützung in der Filmindustrie oder als
erster Entwurf bei der Städteplanung.
1.1 Anforderungen
Das Hauptaugenmerk dieser Arbeit liegt auf dem Entwurf möglichst detailreicher, vielfältiger und
ansprechender Gebäude. Dazu muss ein System entwickelt werden, über das verschiedene Gebäudetypen
anhand von Regeln formuliert werden können. Aus diesen Regeln kann das System dann beliebig
viele Varianten des Typs erzeugen. Damit diese in einem Computerspiel einsetzbar sind, existieren
selbstverständlich Restriktionen in punkto Speicher und Performance. D.h. das Gebäude sollte zwar
detailreich und vielfältig sein, trotz alldem müssen gewisse Richtlinie bzgl. des Speichers und der
Berechnungszeit eingehalten werden. Zu dem sollte eine einfache und möglichst gezielte Steuerung der
Gebäudegenerierung vorhanden sein, damit die einzelnen Gebäudetypen einfach und schnell erstellt,
verändert und angepasst werden können.
Im Vergleich zu natürlichen Phänomenen (wie beispielsweise Landschaften, Flüsse oder Bäume) ist
die prozedurale Generierung bzw. die Formulierung von Gebäuden sehr viel komplexer. Ein Gebäude
besteht aus den verschiedensten Materialien, der Zusammensetzungen von unterschiedlichen Teilen,
besitzt Symmetrien, und vor allem ist das Äußere stark geprägt durch den künstlerischen Einfluss
des Architekten. Das folgende Kapitel 1.2 Historischer Rückblick beschreibt einen kleinen Überblick
bisheriger Forschungen sowie die Vor- und Nachteile prozeduraler Ansätze.
1.2 Historischer Rückblick
Eine der ersten prozeduralen Methoden wurde bereits in den vierziger Jahren des 20. Jahrhunderts entwickelt. Damals entwarf John von Neumann nach einer Idee von Stanislaw Ulam den ersten zellularen
Automaten. Auf der Suche nach einem dynamischen System, das Selbst-Replikationen bilden kann,
wies Stanislaw Ulam von Neumann auf eine mathematische Abstraktion hin, die Ulam bereits in seiner
Arbeit zur Simulation von Kristallwachstum verwendete. Von Neumann erweiterte die Idee zu einem
allgemeinen System und entwickelte den zellularen Automaten. Dieser besteht aus einer Anordnung
meist quadratischer Zellen, einer Zustandsmenge und mehreren Überführungsfunktionen. Jede Zelle
des Zellraums kann einen Zustand annehmen und wechselt diesen abhängig von seinem eigenen Zustand und denen seiner Nachbarzellen. In einem
iterativen Verfahren verändert sich das System anhand der Funktionen und Zustände, und kann so
beispielsweise Pflanzenwachstum simulieren. Ein
bekanntes Anwendungsbeispiel stellte der Mathematiker John Conway im Jahr 1970 vor. In seinem
Spiel des Lebens simuliert ein zweidimensionaler
zellularer Automat die Evolution von Lebewesen.
Jede Zelle entspricht dabei einem Lebewesen, das
sich über die Zeit hinweg weiterentwickelt. Bei
jedem Schritt kann entweder eine tote Zelle lebendig werden, eine bereits lebendige Zelle normal
weiterleben oder eine lebendige Zelle ihr Leben
aufgrund von Überbevölkerung oder Isolation
verlieren. Der Spieler gibt lediglich den StartzuAbb. 1.4 Spiel des Lebens (Bild: [4])
stand der Zellen vor und stößt die erste Iteration
an. Danach kann er die Evolution seines Systems
beobachten.
Ein weiterer sehr bekannter Begriff ist der des Fraktals. Benoît Mandelbrot leitete diesen 1975 vom
dem lat. fractus ab, was übersetzt soviel wie „gebrochen“ bedeutet. Fraktale besitzen einen großen Stellenwert in der computergenerierten Erstellung von Inhalten, werden allerdings häufig missverstanden.
Grundlegend bezeichnen Fraktale geometrische Muster und Formen, die einen gewissen Grad an Selbstähnlichkeit1 besitzen und sich durch eine meist reelle Dimension2 auszeichnen. Selbstähnlichkeit bedeutet, dass Teile eines Objektes, kleineren Teile des gleichen Objektes ähneln, die wiederum kleineren
Teile ähneln, usw. Das Objekt besitzt demnach einen rekursiven Charakter. Dabei spielt es keine Rolle
ob die selbstähnlichen Teile zwei Stufen oder unendlich oft fortführbar sind. Die zwei folgenden Zitate
definieren noch einmal genau den Begriff des Fraktals.
“A rough or fragmented geometric shape that can be subdivided in parts, each of which is (at least approximately) a reduced/size copy of the whole.” [Man82]
“The main point is this: as long as something displays self-similarity over some, albeit perhaps small,
range of scale, it may qualify as fractal.” [EBE+03, S. 434]
Für den Begriff der Selbstähnlichkeit wird oft der aus der Mathematik und Physik stammende Begriff Skaleninvarianz verwendet.
2
Nicht-ganzzahlige Dimensionen, z.B. deren Hausdorff-Besikowitsch-Dimension größer ist als ihre topologische Dimension.
1
Sehr viele Fraktale besitzen eine schöne Ästhetik,
weshalb sie häufig in der digitalen Kunst zum
Einsatz kommen. Eines der bekanntesten
Beispiele, das sogenannte Apfelmännchen, wird
in Abb. 1.5 dargestellt. Des Weiteren eignen sich
Fraktale zur Beschreibung von Landschaften oder
sonstigen natürlichen Phänomenen wie Wasser,
Küsten, Flüssen, Rauch, etc. All diese Phänomene
besitzen einen hohen Grad an Selbstähnlichkeit
und können aus diesem Grund als Fraktal
bezeichnet werden. Zur Definition und Ermittlung
von Fraktalen kommen verschiedene Systeme
in Frage, vornehmlich zählen zu diesen die
Abb. 1.5 Mandelbrot-Menge (Bild: [3])
mehrfache Iteration von Funktionen, dynamische
Systeme oder grammatik- bzw. regelbasierende Systeme. Zu letzterem zählen wiederum die bekannten
L-Systeme. All diese Systeme können auf verschiedene Arten, aber mit einfachen Mitteln rekursive
oder iterative Objekte beschreiben.
Nun stellt sich die Frage, kann ein Bauwerk als Fraktal bezeichnet werden? Diese Frage kann nicht
so einfach beantwortet werden. Im Normalfall würde die Antwort „nein“ lauten, allerdings sind die
selbstähnlichen Teile eines Objekts nicht immer offensichtlich zu erkennen. [Lor02] erforschte diese
Problematik in seiner Arbeit, die im späteren Kapitel 1.3 Verwandete Arbeiten noch genauer vorgestellt
wird.
Ein weiterer Meilenstein stellt das 1968 von Aristid Lindenmayer entwickelte Textersetzungssystem
dar. Diese nach seinem Erfinder benannten Lindenmayer-Systeme vereinen formale Grammatiken und
später Turtle-Grafiken1 [AS82], um Pflanzen bzw. biologische Systeme prozedural zu generieren und
darzustellen. Ähnlich wie eine Grammatik verwendet ein L-System Regeln, um die Zeichen eines Wortes
durch neue Zeichen zu ersetzen. Durch diese Substitution kann ein Anfangswort in ein sehr komplexes
Endwort, hier ein Synonym für Pflanze,
gewandelt werden. Die Zeichen des
erzeugten Wortes werden schließlich
interpretiert und grafisch dargestellt.
Diese Interpretation wird auch als TurtleMetapher oder Turtle-Grafik bezeichnet.
Durch die von A. Lindenmayer, P.
Prusinkiewicz und anderen später
erforschten Weiterentwicklungen können
L-Systeme Verzweigungen erzeugen,
stochastisch arbeiten oder Einfluss durch
die Umwelt erhalten. Obwohl L-System
hauptsächlich bei pflanzenähnlichen
Strukturen zur Anwendung kommen,
eignen diese sich auch zum Beschreiben
Abb. 1.6 Pflanzen generiert durch L-Systeme [DHM+98]
von Fraktalen und anderer Formen.
Der Ausdruck Turtle ist üblich, da sich die Interpretation ähnlich wie eine Schildkröte verhält. Die so lange strickt geradeaus
läuft, bis eine Änderung der Richtung notwendig wird.
1
Mitte der achtziger Jahre entwickelten sich prozedurale Methoden speziell im Bereich der Computer-Grafik rasch weiter. Im Vordergrund stand
anfangs hauptsächlich die Generierung von Texturen. Zum Beispiel die Erforschung iterierter
Funktionen, die prozedural Texturen für Holzmaserungen, Marmormaserungen oder ähnliche
Strukturen erzeugen. Vorreiter in diesem Gebiet
waren unter anderem Ken Perlin, Darwyn Peachey und Geoffrey Gardner. Ein Teil ihrer Forschung
bestand aus der Erfindung der so genannten Solid
Textures. Diese stellen eine Alternative zu den
üblichen zweidimensionalen Texturen dar und
arbeitet mit drei Dimensionen. Traditionelle Texturen benötigen sehr komplizierte Verfahren, um
eine Textur (z.B. die einer Holzmaserung) auf ein
komplexes Objekt abzubilden, und führen in den
meisten Fällen zu unrealistischen Abbildungen.
Durch Solid Textures können Maserungen für
beliebige Objekte prozedural generiert werden,
ohne komplizierte Texturkoordinaten erstellen
zu müssen. Ken Perlin wurde ebenfalls bekannt
durch seine berühmte Zufallsfunktion, die so genannte Perlin Noise Funktion. Die Zufallsfunktion verwendet eine feste Permutationstabelle,
Hash-Funktionen und Interpolationen, um einen
kontinuierlichen und kontrollierbaren Zufall zu
erhalten. Es handelt es sich deswegen mehr um
eine pseudo-random Funktion.
Abb. 1.7 Solid Textures (Bild: [Jag04])
Abb. 1.8 Cirrus clouds von David S. Ebert
In den letzten Jahrzehnten gewann der prozedurale Entwurf in vielen Gebieten neue Erkenntnisse. Vor
allem im Bereich der Fraktale wie Landschaften [EBE+03], Wolken [Gar85][EBE+03] und Partikelsystem für Rauch [FSJ01], Feuer [FKM+06] und ähnliches. Die meisten Verfahren zum Erzeugen von
Partikeleffekten verwenden einfache Zufallsfunktionen. Diese beeinflussen die Eigenschaften wie z.B.
Position, Farbe oder Größe, und animieren die Partikel zufällig. Weiterhin wurden sehr viele Ergebnisse
im Bereich der Generierung und Tesselierung von Geometrien erreicht. Dies geht von der computergesteuerten Generierung einfacher Kugeln bis hin zur dynamischen Tesselierung komplexer geometrischer Objekte. Neben den typischen Computer-Grafik Bereichen wurde auch in anderen Gebieten
geforscht, zum Beispiel im Bereich der Musik und Komposition[Hol81][Pru86][WS05]. Dort werden
Ersetzungssysteme (z.B. Lindenmayer-Systeme) eingesetzt, um Musik prozedural zu komponieren.
Die Interpretation erfolgt in diesen Fällen nicht grafisch, sondern akustisch.
In diesem Kapitel wird nur ein sehr kleiner Ausschnitt aller Arbeiten und Forschungen beschrieben,
die im Bereich der prozeduralen Generierung tätig waren und sind. Vor allem in den 80er, 90er und
den letzten Jahren haben prozedurale Ansätze einen großen Schub erhalten. Da die Rechner immer
leistungsfähiger wurden und die zu erzeugenden Objekte immer komplexer werden sollen, gewannen prozedurale Ansätze an Attraktivität. Anstatt Texturen, Modelle, Animationen und vieles mehr von
einem Programmierer bzw. Grafiker kreieren zu lassen, werden einmalig prozedurale Systeme erzeugt,
die dann den größten Teil dieser Arbeit bewältigen. Dies gilt vor allem für Objekte, die einen hohen
Grad an Selbstähnlichkeit aufweisen.
Was bedeutet prozedural und welche Vorteile bzw. Nachteile liegen in einem solchen Ansatz?
„Procedural techniques are code segments or algorithms that specify some characteristic of a computergenerated model or effect.“ [EBE+03, S. 1]
[EBE+03] formuliert prozedurale Methoden als Programmcode bzw. Algorithmen, die einige
charakteristische Merkmale von computergenerierter Modellen1 beschreiben. So wird, um ein Beispiel
zu nennen, kein Foto zur Darstellung einer Pflanze verwendet. Vielmehr wird die Pflanze zuerst anhand
von Regeln definiert. Aus diesen Regeln wird schließlich eine virtuelle Pflanze erzeugt und dargestellt.
Mit anderen Worten, ein prozeduraler Ansatz verwendet Prozeduren, um die Objekte zu generieren.
Prozeduren sind in der Datenverarbeitung eine Kette von Anweisungen, demnach Algorithmen. D.h. ein
Großteil der Komplexität eines Objektes wird nun vom einem Computer durch Prozeduren erzeugt und
nicht von dem Programmierer bzw. Grafiker. Diese werden durch einen prozeduralen Ansatz entlastet.
Als stärksten Vorteil führt [EBE+03] die Abstraktion prozeduraler Verfahren auf. Durch prozedurale
Methoden können komplexe Modelle in Funktion bzw. Algorithmen abstrahiert werden. Aus diesem
Grund ist es nicht notwendig, ein komplexes Modell zu speichern, sondern nur dessen Abstraktion in
Form einer Funktion, woraus ein enormer Speichervorteil entsteht. Aus dem geringen Speicherverbrauch
kann wiederum eine bessere Ladezeit resultieren. Dies ist natürlich stark von der Berechnungszeit der
prozeduralen Funktion abhängig.
Durch die Abstraktion kann variabel entschieden werden, wie komplex ein Modell durch den Algorithmus
erzeugt werden soll. Als geeignetes Beispiel für diese Flexibilität kann die Auflösung einer Textur
angesehen werden. Normalerweise muss ein Grafiker zu Beginn entscheiden, in welcher Auflösung eine
Textur gestaltet wird. Dies ist bei einem prozeduralen System nicht notwendig. Die Textur kann nach
Belieben in ihrer Genauigkeit variieren und für ein gegebene Situation passend erzeugt werden, auch
direkt zur Laufzeit.
Weiterhin verfügen Prozeduren über eine parametrische Kontrolle, durch die sich die zu erzeugenden
Inhalte einfach steuern und variieren lassen. So könnte die Größe eines Baums, die Anzahl der Äste
und sonstige Eigenschaften über mehrere Parameter kontrolliert werden. Smith bezeichnet dies auch als
Data-base amplification [Smi84]. Es bedeutet, dass komplexe Strukturen aus geringen Eingabedaten
generiert werden können. Wurden die Parameter festgelegt, so können diese entweder durch den Nutzer
gesetzt werden, der damit das Aussehen der Inhalte steuert. Oder aber, damit kommen wir schon zum
nächsten Vorteil, die Parameter werden von dem Programm stochastisch erzeugt. D.h. die Parameter
oder sonstige Einstellungen werden von dem Programm bzgl. vorgegebener Wahrscheinlichkeiten während der Berechnung ermittelt. Dafür verwendet das Programm ein Zufallsgenerator und generiert für
jede Ausführung einen neuen Inhalt. Durch stochastische Mittel erzeugen prozedurale Methoden eine
sehr große Vielfalt, die durch handgefertigte Modellierung nicht erreicht werden kann.
So mächtig ein stochastischer Ansatz ist, beinhaltet dieser auch einen großen Nachteil und bildet die
Achillesferse dieser Systeme. Was durch prozedurale, vor allem stochastische Methoden an Vielfalt
gewonnen wird, verliert der Nutzer an Genauigkeit der Ergebnisse. Es entsteht ein Wechselspiel zwischen
Flexibilität/Vielfalt und gezielten Ergebnissen. Das bedeutet, wenn ein Künstler eine exakte Vorstellung
von einem Ergebnis hat, kann dieses mit Hilfe prozeduraler Methoden meist nicht erreicht werden.
Dafür können sehr viele Ergebnisse erschaffen werden, die alle der exakten Vorstellung im gewissen
Maße ähneln. Zu dem kommt, dass viele prozedurale Verfahren schwer nachvollziehbar sind, vor allem
für Nutzer, die nur geringe Vorkenntnisse besitzen. Außerdem sind die meisten Systeme schwer zu
programmieren und fehleranfällig.
Je nach System und zu erzeugendem Inhalt bzw. Komplexität des Ergebnisses können lange Berechnungszeiten entstehen. Vor allem bei Objekten, die Verzweigungen erzeugen, kann die Komplexität und
damit die Berechnungszeit sehr schnell expandieren.
1
Modelle ist in diesem Fall ein Platzhalter für Texturen, Geometrien, Animationen, usw.
Oliver Deussen unterteilt in seinem Buch [Deu03] prozedurale Ansätze in „prozedurale“ und regelbasierte Verfahren. Prozedurale Verfahren sind nach seiner Definition parametrisierte Algorithmen, die
meist speziell für eine Aufgabe konzipiert werden, zum Beispiel eine rekursive Funktion zum Erzeugen
einer speziellen Baumart. Im Gegensatz dazu wird in regelbasierten Systemen eine formale Regelbasis
verwendet. Diese ermöglicht eine allgemeine Spezifikation des Systems und ordnet dem System keine
genaue Aufgabe zu. Ein sehr bekanntes Beispiel sind die so genannten Lindenmayer-Systeme, die als
Textersetzungssystem eine Untermenge der regelbasierten Systeme bilden. Zusätzlich listet Deussen
die iterierten Funktionssysteme und Graphen mit entsprechenden Abarbeitungsmethoden als weitere
Regelsysteme auf.
In regelbasierten Systemen lassen sich durch den Einsatz von einfachen Regeln aufwändige und komplexe Systeme definieren. Der größte Vorteil von regelbasierten System gegenüber üblichen prozeduralen Verfahren liegt klar auf der Hand. Durch das Austauschen der Regelbasis kann mit geringem
Aufwand ein komplett unterschiedliches Modell definiert werden. Anfangs noch ziemlich langsam, benötigen die regelbasierende Systeme durch die heutige Rechenleistung der Computer nur noch einen
Bruchteil der Verarbeitungszeit und sind somit fast uneingeschränkt einsetzbar, auch zum Erstellen sehr
komplexer Strukturen.
1.3 Verwandte Arbeiten
Nach dem im vorhergehenden Kapitel eine allgemeine Zusammenfassung von prozeduralen Verfahren
aufgelistet wurde, wenden wir uns in diesem Kapitel noch einmal genauer dem Bereich des prozeduralen Städte- und Gebäudeentwurfs zu. Auch hier wird nur ein kleiner, aber bedeutsamer Ausschnitt der
Arbeiten erläutert, die auf diesem Gebiet bereits erforscht wurden.
Michael Hansmeyer beschreibt
in seiner Arbeit [Han]
fünf
Ansätze, bei denen Algorithmen
in der Architektur unterstützend
angewendet werden können. Im
ersten Ansatz dient das System zur
Simulation von Personenströmen.
Mit Hilfe dieser Simulation können
Wege nach Effizienz und Sicherheit
beurteilt und verbessert werden.
Im zweiten Ansatz können mit
der Hilfe genetischer Algorithmen
Optimierungen im Entwurf der
Gebäude vorgenommen werden.
Abb. 1.9 Verzweigtes L-System (Bild: [Han])
Dazu zählen zum Beispiel eine
optimale Aufteilung des Grundrisses
in Korridore und unterschiedliche Wohnungen. Die Aufteilung verfolgt dabei das Ziel einen möglichst
hohen Markpreis zu erzielen. Das dritte Verfahren behandelt die Erzeugung von Formen über die Angabe
von vordefinierten Parametern hinaus. Dabei findet das System über Permutationen immer wieder neue
Formen. Im vierten Ansatz steht die Generierung eines Gebäudes, basierend auf den Regeln eines LSystems. Es geht um die Frage, ob natürliche Wachstumsprozesse auch in der Architektur Anwendung
finden, siehe Abb. 1.9. Im letzten Teil der Arbeit werden die Parameter eines Gebäudes direkt in das
Abbild des Gebäudes übertragen und dort dargestellt. Dazu werden mit Hilfe von Transformationen die
Farbe, Geometrie und ähnliche Komponenten verändert und dadurch die Parameter über das Bauwerk
sichtbar gemacht.
Abb. 1.10 Gebäudevariante erzeugt aus vordefinierten Entwurfsregeln (Bild: [Han])
W. Lorenz untersucht in seiner Arbeit „Fractal and Fractal Architecture“ [Lor02] die Grundrisse von
Bauwerken und deren Fassaden nach selbstähnlichen Strukturen und damit nach Fraktalen. Auch wenn
sich die Arbeit nicht direkt mit dem prozeduralen Entwurf von Bauwerken befasst, gibt sie aufschlussreiche Erkenntnisse darüber, ob Gebäude als Fraktale bezeichnet werden können.
Innerhalb der Arbeit werden Beispiele für selbstähnliche Struktur in Städten erläutert. Zum Beispiel
weisen die Straßennetze einer Stadt, Ähnlichkeiten mit denen eines Stadtviertels auf und diese wiederum
mit den Netzen eines Einfamilienhauses. Auch wenn es sich nur um eine statistische Selbstähnlichkeit
handelt und nicht um eine exakte Selbstähnlichkeit, können die Straßennetze einer Stadt als Fraktal
bezeichnet werden. Mit Hilfe der Box-Counting Dimension, einer der möglichen Varianten, fraktale
Dimensionen zu beschreiben, werden in der Arbeit die Dimensionen von Grundrissen und Fassaden
berechnet. Das Box-Counting Verfahren kann auf beliebige Schwarz-Weiß-Zeichnungen ausgeführt
werden und eignet sich deshalb besonders gut für die Zeichnungen von Gebäudegrundrissen. Mit Hilfe des
Verfahrens werden die Fassaden
und Grundrisse verschiedener
Gebäude untersucht und so
der Grad an Selbstähnlichkeit
festgestellt. Dabei soll bestimmt
werden, ob ein Gebäude aufgrund
der Fassadenstruktur, Symmetrien
oder ähnlichen Eigenschaften
„schön“ wirkt oder nicht. Es folgt
eine Analyse mehrerer Bauwerke,
dessen Ergebnisse in Statistiken
Abb. 1.11 Kathedrale von Lincoln, England (Bild: [Lor02])
zusammengefasst werden.
Die Abbildung 1.12 zeigt ein offensichtliches Beispiel für Selbstähnlichkeiten eines Gebäudegrundrisses.
Es handelt sich um das von Kaiser Friedrich II erbaute Castel del Monte, auch die „steinernen Krone
Apuliens“ genannt. In Abbildung 1.11 verdeutlicht [Lor02] Selbstähnlichkeiten zwischen den einzelnen
Fenstern der Kathedrale von Lincoln. Neben den Ähnlichkeiten der einzelnen Fenster weisen die Muster
der Fensterscheiben ebenfalls selbstähnliche Strukturen auf.
Abb. 1.12 Castel del Monte in Apulia, Italien (Bild: [Lor02])
Pascal Müller beschreibt in seiner Arbeit [Mül99] den Entwurf eines Systems, das Straßennetze einer
Großstadt prozedural verlegt und die einzelnen Bauwerke an die erzeugten Netze anpasst. Dabei liegt
der Schwerpunkt nicht im Entwurf der Formen und Details von Gebäuden, sondern eher auf dem gesamten Erscheinungsbild der Stadt.
Als Werkzeug für die Straßennetze verwendet [Mül99] ein sequentiell selbstsensitives LindenmayerSystem. Lindenmayer-Systeme wurden eigentlich entwickelt, um Verzweigungen von Pflanzen
zu generieren. Diese wachsen, sobald ein Ast sich aufspaltet, immer getrennt voneinander weiter.
Straßennetze dagegen bilden Verzweigungen, die wieder aufeinander treffen und damit Zyklen bilden.
Um solche Gegebenheiten durch ein System erzeugen zu lassen, erkennt das von [Mül99] aufgestellte
selbstsensitive L-System Straßen, die
auf bereits erzeugte Segmente/Straßen
stoßen, und verbindet diese miteinander
(siehe Abb. 1.13). Weiterhin reagieren
die Straßen auf Kollisionen mit
Wasserbereichen oder Waldgebieten und
werden entsprechend umgeleitet. Nach
dem das Straßennetz verlegt wurde,
müssen in den Zwischenbereichen
des Netzes passende Gebäude erstellt
Abb. 1.13 Selbstsensitives L-System (Bild: [Mül99])
werden. Dazu ermittelt das System
die möglichen Bereiche, spaltet deren
Flächen mehrfach und zerlegt diese
damit in einzelne Häusergrundrisse.
[Mül99] bezeichnet diesen Vorgang als
Subdivision. Durch die Parzellierung
werden die einzelnen Häuserblöcke
mit mehreren Bauwerken belegt. Die
einzelnen Bauwerke werden dann
entsprechend ihrer Position innerhalb der
Stadt texturiert und extrudiert (in die Höhe
gezogen). Die Hochhäuser variieren noch
nicht in ihren Formen und erhalten noch
keine besonderen Merkmale. Abbildung
1.15 präsentiert eine von dem System
Abb. 1.14 Subdivision eines Polygons (Bild: [Mül99])
generierte Großstadt, die das heutige
Manhattan widerspiegeln soll.
Abb. 1.15 Virtuelles Manhattan (Bild: [Mül99])
10
In seiner späteren Arbeit [Mül01] verbessert P. Müller das System
an den bisherigen Schwachstellen, erweitert es um neue Funktionen
und entwickelt daraus die so genannte City Engine. Diese vereint
die bereits in seiner vorherigen Arbeit [Mül99] entwickelten
selbstsensitive L-Systeme, das Verfahren zur Parzellierung von
Häuserblöcken und die neu entwickelte Grammatik zum Erzeugen
der einzelnen Gebäudestrukturen. Die prozedurale Generierung der
Gebäude erfolgt über eine so genannte Shape Grammar. Diese kann
auf alle beliebigen durch das Straßennetz und die Subdivisionen
erzeugten Grundformen angewendet werden, d.h. die Grammatik
ist formunabhängig. Angewendet auf einen Grundriss kann die
Shape Grammar diesen verändern, darauf Extrusionen1 anwenden
und innerhalb diesen volumetrische Grundformen erzeugen.
Wie bei Lindenmayer-Systemen können Verzweigung erzeugt
werden und daraus hierarchische Strukturen entstehen. Abb. 1.16
veranschaulicht den von einer Shape Grammar erzeugten Sears
Tower aus Chicago. Mit Hilfe der Shape Grammar werden in
der City Engine verschiedene Gebäudetypen entworfen, die dann
zufällig innerhalb der Stadt platziert werden.
Im Gegensatz zur vorherigen Arbeit gewinnen die Gebäude an
Struktur und Vielfalt, wodurch die Stadt einen realistischeren und
lebendigeren Eindruck erhält. Mit Hilfe der City Engine können
die einzelnen Schritte zum Entwerfen einer Stadt bearbeitet und
angezeigt werden. Dies beinhaltet die Einstellung von Parametern,
Aufstellen der verschiedenen Grammatiken für Straßennetze
und Gebäudestrukturen, usw. Obwohl eine größere Vielfalt und
ein höherer Detailgrad für die Gebäude-Grundrisse sowie die
Grundformen erzielt wurde, besitzen die Bauwerke noch keine
Feinheiten wie Regenrinnen, Fensterrahmen, Treppen oder
Ähnliches.
Abb. 1.16 Sears Tower
(Bild: [Mül01])
Extrusion wird abgeleitet aus dem lat. extrusus von extrudere ”hinausdrängen, -stoßen“. Die Gebäude werden förmlich aus
ihrem Grundriss „herausgepresst“ und expandieren in die Höhe.
1
11
[WWS+03] widmen sich in ihrer Arbeit
ausschließlich der prozeduralen Erstellung von
Fassaden. Im Gegensatz zur City Engine sollen
die Gebäude einen noch höheren Detailgrad
erhalten, z.B. sollen Fenster, Türen, Säulen und
sonstige Formen über das System formuliert
und daraus generiert werden. Um eine möglichst
große Vielfalt zu erhalten, wurden zwei
verschiedene Grammatiken implementiert, die
sogenannte Split Grammar und die sogenannte
Control Grammar.
Die Split Grammar ist eine veränderte Variante
einer Shape Grammar. Durch die Grammatik
können Fassaden in verschiedene Teile
gespalten bzw. durch mehrere Formen ersetzt
werden und dadurch Strukturen, Fenster und
sonstige Formen an den Häusern erzeugen.
Abbildung 1.17 verdeutlicht die Regeln und
den Prozess einer Split Grammar. Die weißen
Abb. 1.17 Split Grammar (Bild: [WWS+03])
Kästen repräsentieren nichtterminale Symbole
bzw. Formen, die restlichen Formen beenden
die Ersetzung. Beginnend mit einer Grundform, also einer Wand, wird diese sukzessive durch neue
Formen ersetzt bzw. unterteilt. Dieser Vorgang wird so lange fortgesetzt, bis ausschließlich Formen
existieren, die keine weitere Ersetzung ermöglichen.
Bei der erwähnten Control Grammar handelt es sich um eine einfache kontextfreie Grammatik. Im
Gegensatz zur Split Grammar soll die Control Grammar keine Formen erzeugen, sondern anhand von
architektonischen Richtlinien und Regeln die räumliche Aufteilung der Split Grammar steuern und
deren Attribute (z.B. Material) entsprechend setzen.
Ziel der Arbeit ist es, komplexe Fassaden für beliebige Gebäude zu erstellen, wobei die meisten Gebäude
bis zu 100.000 Polygone besitzen. Diese hohe Komplexität schließt die Nutzung für Echtzeit-Systeme
aus, zumindestens für größere Städte mit mehreren hundert Gebäuden. Durch den Einsatz der Control
Grammar können sehr große Regelwerke sinnvoll verwaltet und auf die einzelnen Gebäude angewandt
werden. Dadurch erzeugt das System eine große Vielfalt zwischen den Gebäuden, und es entsteht ein
lebendigeres und organischeres Bild der Stadt.
Abb. 1.18 Virtuelle Fassaden (Bild: [WWS+03])
12
In den Arbeiten [MVU+05] und [MWH+06] wird die bereits beschriebene City Engine erneut erweitert.
Durch den Einsatz einer verbesserten Shape Grammar kann eine gezielte und effizientere Generierung des
Masse-Modells erreicht werden. Zum Masse-Modell gehören die grundlegenden Teile eines Bauwerks,
die aus transformierten Würfeln, Kugeln und sonstigen Formen zusammengesetzt werden. Zusätzlich
kann die Grammatik alle Formen auf ihre Flächen, Kanten und Punkte herunterbrechen und auf diese
Subdivisionen ausführen. Ähnlich wie in der von [WWS+03] eingeführten Split Grammar können
damit die Fassaden des Masse-Modells in verschiedene Stockwerke und Bereiche unterteilt werden.
In diesen Bereichen können Fenster, Türen oder sonstige Elemente durch Formen oder vorgefertigte
Modelle erzeugt werden. Ebenfalls ist es möglich, vorgefertigte Objekte zu laden, z.B. das Objekt
einer Feuerleiter oder sonstige komplexe Objekte, die nicht mit Hilfe des Systems generiert werden
können. Alle Grundrissverformungen, Extrusionen, Generierungen, Transformationen, Unterteilungen,
Splits oder sonstige Operationen werden innerhalb einer einzigen Grammatik angegeben. Durch diesen
Ansatz können schnell sehr große und unübersichtliche Grammatiken entstehen. Wie in der Arbeit von
[WWS+03] weisen die hier erzeugten Gebäude-Modelle mehrere tausend Polygone auf. Allerdings kann
der Detailgrad, in der Computer-Grafik bekannt als Level of Detail, über das System verändert werden
und ermöglicht so ein interaktives arbeiten.
Die Abbildung 1.19 zeigt ein mit Hilfe der neuen Grammatik generiertes Haus. Ebenfalls zu erkennen
sind die einzelnen Unterteilungen, die durch spezielle Split-Befehle innerhalb der Grammatik erreicht
werden. In der Arbeit beschreibt [MVU+05], wie die Stadt Pompeji virtuell durch die City Engine nachgestellt wird, siehe Abb. 1.20.
Abb. 1.19 Shape Grammar (Bild: [MWH+06])
Abb. 1.20 Virtuelles Pompeji
(Bild: [MWH+06])
13
1.4 Lösungsansatz und Überblick
Auf den vorherigen Seiten wurde eine kurze Zusammenfassung einiger verwandter Arbeiten aufgestellt.
Vor allem die Arbeiten von [WWS+03] und [MWH+06] erzielen bereits sehr realistische und vielfältige
Ergebnisse. Aus diesem Grund wurden die beiden Arbeiten als Vorlage für das zu implementierende
System verwendet, d.h. einige der Ideen wurden übernommen und teilweise angepasst oder erweitert.
Das entwickelte System zum prozeduralen Generieren von Gebäuden besitzt im Ansatz große
Ähnlichkeit mit dem von P. Müller aufgestellten System [MWH+06]. Wie bei [MWH+06] bildet die
Basis ein verändertes Lindenmayer-System, allerdings wurde dafür eigens eine neue Syntax und
eine neue Definition für das L-System aufgestellt. Diese machen die Grammatiken übersichtlicher,
verständlicher und ermöglichen eine effizientere Transformation der Formen. Über die Grammatik des
L-Systems können Regeln aufgestellt werden, aus denen das System Formen für ein Masse-Modell
anfertigt. Allerdings wird anders als bei [MWH+06] kein Straßennetz erzeugt und deshalb auch keine
Parzellierung von Häuserblöcken ermittelt. D.h. die einzelnen Häuser besitzen keine speziellen
Grundrissflächen, aus denen die Gebäude extrahiert werden. Die Masse-Modelle werden lediglich durch
Transformation eigens benannter Primitive erzeugt, also aus Würfeln, Zylindern, etc. Ebenfalls anders
als bei [MWH+06] wird das Masse-Modell nicht innerhalb der Grammatik auf seine einzelnen Flächen
und Kanten heruntergebrochen. Dieser Vorgang wird vom System automatisch ausgeführt, dabei kann
jeder Fläche und Kante eine neue Grammatik zugewiesen werden. Anstatt nun das komplette Gebäude
(inklusive Fassaden) von einer einzigen Grammatik erzeugen zu lassen, werden die Teile des Gebäudes
auf verschiedene Grammatiken aufgeteilt. Dadurch verringert sich die Komplexität der Grammatiken
und sorgt für eine klare Struktur zwischen den einzelnen Bereichen des Gebäudes. Zum Beispiel fertigt
eine Masse-Grammatik das Grundmodell des Bauwerks an und eine Fassaden-Grammatik die einzelnen
Fassaden des erzeugten Grundmodells. Ein weiterer Vorteil dieser Aufspaltung entsteht durch die
Wiederverwendbarkeit der einzelnen Grammatiken. Eine Grammatik, die Regeln für Fassadenstrukturen
besitzt, kann mit jeder beliebigen Grammatik zum Erzeugen eines Masse-Modells kombiniert werden.
Zusätzlich können Bereiche der einzelnen Grammatiken (z.B. der Bereich einer Fassade) in verschiedene
Teile gespalten werden, ähnlich wie bei der Split Grammar von [WWS+03] und [MWH+06]. D.h. die
Grammatiken verfügen über verschiedene Subdivision- und Split-Methoden. Diese wurden insofern
erweitert, so dass mit einfachen Mitteln Symmetrien formuliert werden können, wie z.B. das symmetrische
Muster eines Fachwerkbaus.
Wie in dem System von [MWH+06] können auch vorgefertigte Objekte geladen und platziert werden.
Allerdings wurden auch hier einige Veränderungen und Erweiterungen eingeführt, um dadurch die Vielfalt zu steigern. Zusätzlich ist das eigens aufgestellte System erstmalig umgebungssensitiv im Bereich
der Gebäudegenerierung, d.h. die Gebäude, Fassaden und erzeugten Modelle können Einfluss durch die
Umwelt erhalten. Dazu kann die Umwelt durch verschiedene Methoden analysiert werden und so z.B.
die Höhe des Hauses, die Größe und Position von Fenster und vieles mehr beeinflussen.
Die nächsten drei Kapitel beschreiben die Grundlagen des Systems. Dazu gehören die in Kapitel 2
Architektonische Grundlagen beschriebenen architektonischen Grundkenntnisse und Begriffe. Diese
werden vermittelt und benötigt, damit zum einen das Verständnis für die Fachbegriffe entsteht. Und
zum anderen, um aufzuzeigen, dass das Systeme einfache Regeln aus der Architektur umsetzen kann.
Darauf folgend, werden in Kapitel 3 Lindenmayer-Systeme verschiedene Varianten der LindenmayerSysteme dargelegt. Diese bilden die Basis zum Formulieren der Regeln, aus denen ein Gebäude erbaut
werden soll. Im vierten Kapitel Straight-Skeleton folgt ein Algorithmus, mit dem Dachflächen für
beliebige Grundrisse ermittelt werden können. Der Algorithmus ermöglicht eine einfache Formulierung
der Dachstrukturen in Form von Polygonen. Im Kapitel 5 Konzept folgt schließlich das Konzept
des entwickelten Systems. D.h. es wird erklärt, wie alle Komponenten zusammenspielen, welche
Veränderungen an den Lindenmayer-Systemen vorgenommen werden, wie das Straight-Skeleton
eingesetzt wird, wie die Analyse der Umwelt realisiert wird, etc.
14
2. Architektonische Grundlagen
In diesem Grundlagenkapitel werden typische charakteristische Merkmale von Bauwerken, insbesondere
Wohnhäuser, beschrieben. Zusätzlich werden einige Grundbegriffe aus der Architektur erläutert. Ein
besonderes Augenmerk liegt auf den Grundlagen und Begriffen der Dachkonstruktionen, da hier viele
der Begriffe innerhalb der Arbeit benötigt werden. Das Kapitel soll verdeutlichen, das einfache Regeln
und Merkmale über das System formuliert und schließlich umgesetzt werden können, und keinen
tiefgründigen Einblick in die Architektur oder Statik geben.
2.1 Merkmale
Auffallend an den meisten Gebäuden sind die Unterschiede bzw.
Gleichheiten der einzelnen Stockwerke. Das unterste Stockwerk
besitzt meist eine andere Fassade als die darüber liegenden
Stockwerke, bei denen jedes Stockwerk häufig die gleiche Struktur
und Fassade besitzt. Ein Beispiel wird in Abb. 2.1 dargestellt. In
der Abbildung ist zu erkennen, dass das unterste Stockwerk große
Fenster und eine weiße Fassade besitzt und die darüber liegenden
Stockwerke ein Fachwerk-Muster aufweisen sowie Fenster, die
sich an den gleichen Stellen innerhalb der einzelnen Stockwerke
befinden.
Zur damaligen Zeit wurde hauptsächlich zwischen Stein- und
­Holzbauten unterschieden. In der Moderne kamen dann die Stahlund Betonbauten hinzu. Während die Mauern mehrstöckiger
Steinbauten direkt aufeinander sitzen und nach oben hin häufig
dünner werden, können die Wände von Holzkonstruktionen
etagenweise vortreten. Diese Eigenschaft bildet ein wesentliches
Abb. 2.1 Fachwerkhaus
charakteristisches Merkmal der Holzbauten gegen über den
Steinbauten. Ein weiteres Merkmal, das sehr häufig von Architekten eingesetzt wird, bildet die
Symmetrie. Ohne Symmetrie würden die meisten Gebäude chaotisch wirken und ihre schöne Ästhetik
verlieren. Ein typisches Beispiel für die Symmetrie eines Gebäudes verdeutlicht das „Weiße Haus“. Wie
in der Abbildung 2.2 zu erkennen ist, kann in der Mitte des „Weißen Hauses“ eine vertikale Achse gelegt
werden. An dieser Achse kann die linke bzw. rechte Hälfte des Gebäudes gespiegelt werden und erhält
dadurch genau die gegenüberliegende Seite. Auch das Gebäude aus Abb. 2.1 besitzt ein symmetrisches
Fachwerkmuster. Man könnte sagen, dass bei fast allen Gebäuden Symmetrien zu erkennen sind und
dies eines der wesentlichsten Merkmale darstellt, egal aus welcher Region, Zeitalter oder Kultur das
Bauwerk stammt.
An dieser Stelle könnten unzählige Regeln
erläutert werden, z.B. die optimale Größe
von Fenster bzgl. der Wand- und Raumgröße [BFH+80]; doch dies würde zu weit
führen. Möchte ein Nutzer ein Gebäude
entwerfen, kann er sich vorher erkundigen
welche Größe sein Haus besitzen soll, wie
die einzelnen Stockwerke sich verhalten,
ob Symmetrien innerhalb des Gebäudes
existieren, usw. All diese Regeln können
durch das realisierte System formuliert
werden und bilden damit die Grundpfeiler
des Gebäudes.
Abb. 2.2 „Weiße Haus“
15
2.2 Dächer
Das Dach bildet den oberen Abschluss eines Gebäudes, es besteht aus Dach-Tragewerk (Dach-Konstruktion) und Dach-Haut (Dach-Deckung und Hilfskonstruktionen). Die Dach-Konstruktion ist die Gesamtheit der tragenden Bauteile. [Bro88, S. 74]
Das Dach dient in seiner praktischen Ausübung, vor allem als Schutz vor Niederschlägen, Hitze und
Kälte. Die Konstruktion des Dachs muss aus diesem Grund gut überlegt sein und erfordert viel Erfahrung
über Deckmaterialien, Balkenkonstruktionen, Statik etc. All diese Punkte sollen im Folgenden außer
Acht gelassen werden, der wichtigste Punkt ist, die Dachkonstruktion möglichst realistisch und optisch
ansprechend vom dem System erzeugen zu lassen. Auch in der Architektur wird die Dachkonstruktion,
speziell die Dachausmittlung, nicht nur auf ihre Funktion beschränkt, sondern bestimmt zu einem
großen Teil die Optik des Gebäudes:
„Nicht allein in technischer, sondern auch in formaler Beziehung ist das Dach als wesentlicher Teil
eines Bauwerks von großer Bedeutung, da seine Form einen großen Einfluss auf die äußere Erscheinung
des Gebäudes ausübt.“ [War00, S. 129]
Dieses Kapitel wird die Begriffe, die verschiedenen Formen sowie die Problematik bei der Erstellung
einer Dachkonstruktion erläutern und verdeutlichen. Im späteren Kapitel 4 Straight-Skeleton dieser
Arbeit folgt die Erklärung eines grundlegenden Algorithmus zur Generierung der Dächer, sowie in
Kapitel 5 Konzept schließlich ein Konzept zum Erzeugen prozeduraler Dächer.
2.2.1 Begriffe
In der Architektur wird ein Dach
üblicherweise in 14 Komponenten [Pre99]
gegliedert. Dazu zählen die in Abb. 2.3
dargestellten Bezeichnungen:
First, Traufe, Ortgang, Hauptdach,
Nebendach, Walm, Krüppelwalm, Grat,
Giebel, Kehle, Verfallung und Anfallspunkt.
Zusätzlich sind noch die Elemente Gaube
und Dachflächenfenster gebräuchlich.
Abb. 2.3 Dach-Begriffe
Der Giebel bzw. die Giebelseite definiert
die Seite eines Gebäudes, an der sich keine geneigte Dachfläche befindet (meist die kürzere Seite des
Hauses), siehe Abb. 2.5 in der Spalte Giebeldach. Wenn diese Seite des Hauses ebenfalls eine geneigte
Dachfläche aufweist, ist von einem Walm bzw. von einem Walmdach die Rede. Wenn der Walm nicht
direkt bei der Traufe beginnt, entstehen der so genannte Krüppelwalm und Trapezgiebel. Die Längsseite
ist das genaue Gegenteil der Giebelseite, sie bezeichnet die meist längeren Walmseiten.
Der First beschreibt die oberste horizontale Kante eines geneigten Dachs. Im Gegensatz zur Traufe, die
die unteren Kanten und damit den Beginn des Dachs definiert. Der Ortgang bezeichnet die seitlichen
Schnittkanten einer Dachfläche mit einer Giebelwand und verbindet damit die Traufe mit dem First.
Treffen zwei Dachflächen aufeinander, wird die Kante nicht als Ortgang, sondern als Grat bzw. Kehle
bezeichnet. Wenn die Kante eine Außenkante bildet, wird der Begriff Grat verwendet und unter der
Bedingung, dass die Kante eine Innenkante bildet, der Begriff Kehle. Ein Grat, der nicht bis zur Traufe
verläuft, trägt die Bezeichnung Verfallung. Eine Verfallung entsteht meist beim Zusammenfassen von
Haupt- und Nebendach und verläuft vom First des Hauptdachs bis zum First des Nebendachs. Genaueres
zur Zusammenfassung von Dächern, in der Architektur auch als Dachausmittlung bezeichnet, wird im
Kapitel 2.2.4 Dachausmittlung beschrieben.
16
Dachflächenfenster sind flach auf einer Walmbzw. Längsfläche liegende Fenster. Handelt
es sich um ein stehendes Dachfenster, ist der
Ausdruck Dachgaube (Dachgaupe) üblich.
Die verschiedenen Formen für Dachgauben
[Pre99] werden in Abbildung 2.4 vorgestellt,
dazu zählen die Schleppgaube (a), Gaube mit
Satteldach (b) und deren spezielle Ableitung in
Form eines Dreiecks (Spitzgaube) (d), Gaube
mit Walmdach (c), Fledermausgaube (e) und
Ochsenauge (f).
Abb. 2.4 Dachgauben (Bild: [Pre99])
2.2.2 Dachformen
Die Form eines Dachs ist meist, zumindestens
in früheren Zeiten, abhängig von den zu
Verfügung stehenden Deckmaterialien, den
klimatischen Bedingungen und natürlich der
jeweiligen Region und Kultur. Die gängigsten
Dachformen werden in Abb. 2.5 tabellarisch
aufgelistet, dazu zählen die Dachformen:
Sattel-, Mansard- und Pultdach [BFH+80]
[Pre99][War00], zusätzlich existiert noch
das Flachdach [Pre99], das Zeltdach bzw.
Regeldach bei einem Kreis [War00] und das
Tonnendach [War00].
Das Satteldach besteht aus zwei entgegengesetzt
geneigten Längsflächen, dabei befindet sich an
der Vorderseite meist ein Giebel, Walm oder
Krüppelwalm. Im Gegensatz zum Satteldach
Abb. 2.5 Dachformen
verfügt ein Pultdach nur über eine einzige
geneigte Dachfläche. Die Vorderseite eines Pultdachs entspricht in den meisten Fällen einer Giebelwand.
Weist die Dachkonstruktion einen Knick auf, so dass die unteren Teile steiler sind als die oberen,
handelt es sich um ein Mansarddach. Das Mansarddach geht auf den französischen Architekten Mansart
(1625-1708) zurück, dieser entwarf seiner Zeit ebenfalls das Versailler Schloss. Die Besonderheit des
Mansarddachs liegt in dem zusätzlichen Wohnraum, der durch die spezielle Dachkonstruktion geschaffen
wird. Dieser Wohnraum, die sogenannten Mansarden, besaßen zur damaligen Zeit Steuervorteile, da
eine Mansarde nicht als vollwertiges Stockwerk zählte. Sind die Längs- und Giebelseite gleich lang oder
besitzen die Seiten eine passende Dachneigung, so dass nur ein Anfallspunkt für das gesamte Dach entsteht.
Dann trägt diese spezielle Form des Sattel- oder Mansarddachs auch die Bezeichnung Zeltdach.
2.2.3 Dachneigung
Die Dachneigung gibt die Neigung oder das Gefälle der Dachflächen an. Sie wird als Verhältnis der
Dachhöhe zur Breite des von der betreffenden Dachseite überdachten Gebäudeteils in Prozent oder in
Winkelgraden angegeben. [Bro88]
Die Dachneigung darf, je nach Verwendung des Materials für Dachkonstruktion und Dachdeckung,
nicht unter- oder überschritten werden. Weiterhin unterteilt [Pre99] die Dächer je nach Neigung in drei
verschiedene Kategorien. Als da wäre das Flachdach, für Dächer mit einer Dachneigung zwischen 0°
und 8°, das flach geneigte Dach ab einem Neigungswinkel von 8° bis zu einem Winkel von 30° und
schließlich das Steildach mit einer Neigung von 30° bis 60°.
17
2.2.4 Dachausmittlung
Die Dachausmittlung bestimmt zu einem vorgegebenen Hausgrundriss die Zusammensetzung des Dachs
und damit die Lage und Neigung der einzelnen Dachflächen. Dabei handelt es sich um ein Problem aus
der darstellenden Geometrie (Projektionslehre): dreidimensionale Raumgebilde als zweidimensionale
Flächengebilde auf die Grundrissebene zu projizieren. Ziel der Dachausmittlung ist die Ermittlung der
Form, Lage, Neigung und Abgrenzung der einzelnen Dachflächen.
Zur Berechnung der Dachausmittlung existieren zwei
Standard-Vorgehensweisen [Pre99][BFH+80]. Beide setzen voraus, dass die Traufe der zu verbindenden Dachtrakte jeweils auf gleicher Höhe liegt. Für den in Abb. 2.6
gezeigten Fall, wird keine gemeinsame Dachausmittlung
ermittelt, da sich die Traufe des Nebentrakts nicht auf
gleicher Höhe mit der des Haupttrakts befindet.
In der ersten Variante werden die Dachflächen so angelegt,
dass der First von allen Dächern auf gleicher Höhe liegt.
Daraus folgt zwangsläufig, dass die Dachneigung zwischen
Haupt- und Nebendach unterschiedlich ausfallen kann.
Man kann versuchen, dies an den Walmflächen optisch
einzuschränken, indem die Walmfläche des Nebendachs
flacher konstruiert wird als das anschließende Satteldach
(in Abb. 2.7 durch die gestrichelte Linien dargestellt),
allerdings wirkt dadurch „das eine peinlicher als das
andere“. [BFH+80, S. 33]
Diese Variante ist in der Architektur eher verpönt und gilt
als einfache, nicht stilvolle Lösung.
Abb. 2.6 Ungleiche Traufe
Abb. 2.7 Gleiche Firsthöhe, ungleiche
Dachneigung
Die zweite Variante ist schwieriger zu konstruieren, was
sowohldieProjektionalsauchdiespätereBalkenkonstruktion
angeht. Die Variante sieht vor, dass die Dachneigung aller
Dachflächen gleich ist und aus diesem Grund die Firsthöhen
Abb. 2.8 Ungleiche Firsthöhe, gleiche
zwischen den einzelnen Dächern ­ verschieden ausfallen
Dachneigung
können. Die korrekte Dachausmittlung ergibt dann eine
Verfallung, d.h. ein kurzes Stück Grat, das den höheren mit
dem niedrigeren Dachfirst verbindet. In vielen Fällen sieht die Verfallung unangenehm aus und das umso
mehr, je kürzer sie ist, siehe Abb. 2.9 (b). Aus diesem Grund sollte der Haupttrakt sich deutlich von den
Nebentrakten unterscheiden und erkennbar sein, siehe Abb. 2.9 (a).
Die Dachausmittlung stellt einen nichttrivialen Teil bei der Generierung eines Dachs dar. Ein geeigneter
Algorithmus zur Ermittlung der Dachausmittlung bzgl. der oben beschriebenen zweiten Variante, wird
innerhalb des Grundlagen-Kapitels 4 Straight-Skeleton vorgestellt.
Abb. 2.9
(a) Korrekte Dachausmittlung
(b) Kurze Verfallung
18
3. Lindenmayer-Systeme
Der ungarischer Biologe Aristid Lindenmayer schuf 1968 einen mathematischen Formalismus zur
Simulation biologischer Entwicklungen, basierend auf einem Ersetzungssystem. Anfang der 90er
veröffentlichen A. Lindenmayer und P. Prusinkiewicz das Buch „The algorithmic beauty of plants“
[LP90]. Dieses zählt heute zu den Klassikern der Computer-Grafik und beschreibt, wie durch
Kombination von formalen Grammatiken und Turtle-Grafiken ein System entsteht, mit dem Pflanzen
und biologische Systeme prozedural generiert und dargestellt werden können. Diese Systeme sind nach
ihrem Erfinder benannt und tragen deshalb den Namen Lindenmayer-Systeme, oder kurz L-Systeme.
Im Laufe der Zeit wurden die L-Systeme von A. Lindenmayer selbst und anderen weiterentwickelt.
Diese Entwicklung führte einmal zur Generierung immer realistischerer Pflanzen, und zum anderen
wurde immer mehr Wissenschaftlern bewusst, wie mächtig diese Systeme sind. Dies führte wiederum
dazu, dass Lindenmayer-Systeme zur Erzeugung vieler Fraktale genutzt werden.
Obwohl L-Systeme vornehmlich zu Beschreibung von Pflanzen, Fraktalen oder ähnlichen Formen
verwendet werden, eignen sich die Systeme ebenfalls zu Formulierung von Bauwerken. Auch diese
weisen in manchen Fällen rekursive Charakteristika auf (s. Kapitel 1.3 Verwandte Arbeiten), die durch
einfache Regeln eines L-Systems verfasst werden können. Allerdings werden L-Systeme, die Gebäude
generieren, meistens nicht ihr gesamtes Potenzial ausnutzen können, und zwar aufgrund der niedrigen
oder oft ganz fehlenden Selbstähnlichkeit eines Gebäudes. Trotzdem stellen Ersetzungssysteme ein
geeignetes Mittel dar, um Regeln für ein Bauwerk und dessen Fassaden aufzustellen. Als praktisches
Beispiel können die Shape-Grammar [MWH+06], sowie die Split- und Control-Grammar [WWS+03]
aufgezählt werden, siehe Kapitel 1.3 Verwandte Arbeit.
L-Systeme gehören zu der Gruppe der regelbasierten Systeme und zur Untergruppe der Textersetzungssysteme. In einem Textersetzungssystem wird ein gegebenes Startwort mit Hilfe von Regeln sukzessive in ein neues Wort gewandelt. Dabei kann pro Iteration jedes Zeichen des Wortes, auch Variable
genannt, mit Hilfe einer passenden Regel durch ein oder mehrere Zeichen ersetzt werden. Durch diese
Substitution wächst das Wort immer weiter an und wird komplexer. Dies geschieht so lange, bis keine
passende Regel mehr gefunden werden kann oder eine festgelegte Anzahl von Schritten erreicht wurde.
Im Gegensatz zu den formalen Grammatiken von N. Chomsky arbeiten Lindenmayer-Systeme parallel
und nicht sequentiell. Begründet wird dies durch das parallele Wachstum sowie die parallele Zellteilung
von Pflanzen. Und genauer heißt dies, dass innerhalb eines Schrittes alle Variablen gleichzeitig durch
eine passende Regel ersetzt werden. Anders als bei formalen Grammatiken, wo in einer Iteration lediglich die erste Variable von links beginnend ersetzt wird. Sobald das erzeugte Wort nicht mehr weiter
anwachsen soll oder kann, wird es interpretiert. Der Interpreter durchläuft das erzeugte Wort von links
beginnend und führt für jedes Symbol eine festgelegte Aktion aus, z.B. das Zeichnen einer Linie.
Abbildung 3.1 zeigt die berühmte Von-Koch-Kurve bzw. Koch’sche Schneeflocke, benannt nach dem
schwedischen Mathematiker Helge von Koch. Die Von-Koch-Kurve zählt zu den bekanntesten Fraktalen und kann durch ein L-System mit einer einzigen Regel erzeugt werden.
Abb. 3.1 Koch’sche Schneeflocke beim
Start (a), nach einer Iteration (b) und
nach zwei Iterationen (c)
19
Bevor auf die einzelnen Systeme genauer eingegangen wird, werden noch ein paar Grundkenntnisse aus
der Mengenlehre und theoretischen Informatik erläutert. Diese werden benötigt, um die Definition der
verschiedenen Lindenmayer-Systeme nachvollziehen zu können.
Ein Alphabet Σ ist eine endliche und nicht leere Menge. Die Elemente eines Alphabets werden auch
Symbole oder Zeichen genannt. Ein Symbol a Σ bezeichnet genau ein Element aus der Menge Σ,
während ω Σ+ ein beliebiges, nicht leeres Wort aus dem Alphabet beschreibt. Gilt ω Σ*, so ist ω ein
beliebiges Wort, inklusive dem leeren Wort ε. Für ein Wort ω bezeichnet |ω| die Länge des Wortes, also
die Anzahl der Zeichen, die in dem Wort enthalten sind. So gilt zum Beispiel |ε| = 0.
3.1 Deterministisch kontextfreie Lindenmayer-Systeme
Deterministisch kontextfreie L-Systeme, kurzgefasst D0L-Systeme, sind die einfachste Form dieses
Textersetzungssystems. Die Grundlage wird durch eine formale Grammatik G festgelegt, die durch das
Tripel G = (V, ω, P) definiert wird, wobei gilt:
(1)
(2)
(3)
(4)
V ist eine endliche und nichtleere Menge, genannt Alphabet
ω V + ist das nichtleere Ausgangswort oder auch Axiom genannt
P ist eine endliche Menge, genannt Produktionen (Ersetzungsregeln)
Eine Produktion (φ, χ) P wird geschrieben als φ → χ, wobei gilt φ, χ
|φ| = 1 in einem kontextfreien L-System
V+ und außerdem
Die linke Seite einer Produktion (auch Predecessor genannt) gibt das zu ersetzende Zeichen an, während
die rechte Seite (auch Successor genannt) das Wort definiert, durch welches der Predecessor ersetzt
werden soll. Zeichen, für die keine Produktion angegeben wird, verwenden die Identitätsproduktion (φ
→ φ). Sie bleiben deshalb unverändert und lösen keine weitere Textersetzung aus. Aus diesem Grund
werden Zeichen ohne Ersetzungsregeln auch als Konstanten oder als Terminalzeichen angesehen. In
einem deterministischen System existiert zu einem φ höchstens eine Regel mit φ auf der linken Seite.
Das bedeutet, dass zu einem gegebenen Ausgangswort das Ergebnis eindeutig berechnet wird und immer gleich ist.
Um die Funktionsweise eines kontextfreien L-System zu verdeutlichen, wird das häufig beschriebene
Beispiel der Von-Koch-Kurve erklärt. Gegeben sei das Alphabet V = {F, +, -}, das Axiom ω = F--F--F
und die Produktionsmenge P = {F → F+F--F+F}. Durch die parallele Abarbeitung des L-Systems werden in der ersten Iteration die drei F Symbole des Axioms jeweils durch die Produktion von F ersetzt und
bilden damit die folgende Ableitungsfolge.
1. Schritt
2. Schritt
3. Schritt
F--F--F
F+F--F+F--F+F--F+F--F+F--F+F
F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--
F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F
An dieser Stelle wird der Vorgang einfach abgebrochen. Bis zum jetzigen Zeitpunkt existiert noch kein
Unterschied zu einer formalen Grammatik, einzig und allein die parallele statt sequentielle Abarbeitung
stellt einen Unterschied dar. Aus diesem Grund wurden in einer Iteration alle Symbole gleichzeitig bzgl.
ihrer Ersetzungsregel substituiert.
Wie bereits erwähnt wurde, verwenden L-Systeme eine graphische Interpretation ihrer erzeugten Wörter.
Dieser Vorgang wird als Turtle-Metapher [AS82] bezeichnet. In diesem Beispiel entspricht die Schildkröte
einem Vektor mit dem Format (x, y, α), dabei bestimmen x und y die Position und α die Ausrichtung der
Schildkröte. Ähnlich wie eine reale Schildkröte, bewegt sich die virtuelle Schildkröte ausschließlich in
ihre aktuelle Bewegungsrichtung und zwar so lange bis eine Richtungsänderung notwendig wird. Nach
20
dem das Endwort mit Hilfe der Ersetzungsregeln aus dem Axiom gebildet wurde, läuft der Interpreter
jedes Zeichen von links beginnend ab und führt je nach Art des Zeichens eine festgelegte Funktion aus.
Für dieses Beispiel würde die Interpretation des Alphabets so aussehen [Deu03].
F
Bewege Turtle um d in aktueller Richtung, zeichne Linie:
(x, y, α) → (x + d cos α, y + d sin α, α)
+
Erhöhe aktuellen Winkel um δ:
(x, y, α) → (x, y, α + δ)
-
Erniedrige aktuellen Winkel um δ:
(x, y, α) → (x, y, α - δ)
Wenn nun die Länge d und der Winkel δ festgelegt werden, sagen wir d = 1 und δ = 60°, können die
gebildeten Wörter mit Hilfe der Befehle interpretiert werden. Das interpretierte Axiom erzeugt das in
Abb. 3.1 (a) dargestellte Dreieck und nachdem eine Iteration durchlaufen wurde, wird der in Abb. 3.1 (b)
gezeigte Stern gezeichnet. Mit jedem weiteren Schritt wird die Struktur feiner und nähert sich dem Aussehen einer Schneeflocke, Abb. 3.1 (c). Mit Hilfe eines kleinen Alphabets, der Angabe einer einzigen
Ersetzungsregel sowie eines Axioms kann ein beliebig detailreiches Objekt erzeugt werden.
3.2 Deterministisch kontextsensitive Lindenmayer-Systeme
Kontextsensitive Systeme bieten dem Nutzer die Möglichkeit, die Ersetzungsregel eines Zeichens abhängig von dessen lokaler Umgebung zu machen. Wird dem Predecessor einer Ersetzungsregel ein
linker und/oder rechter Kontext1 zugeteilt, kann die Regel nur ausgeführt werden, wenn der angegebene
Kontext im Wort auch wirklich das Zeichen umschließt.
Ein kontextsensitives System ist die Erweiterung eines kontextfreien Systems und kann demnach
mindestens alle Wörter erzeugen, die mit einem kontextfreien System erzeugt werden können. In einem
kontextsensitiven System verändern sich das Alphabet sowie das Axiom nicht, der einzige Unterschied
besteht in der Angabe der Produktionen. Dabei wird genau definiert, im Gegensatz zu den formalen
Grammatiken von Chomsky, welches Zeichen auf der linken Seite ersetzt werden soll und welche
Zeichen den Kontext bilden. Eine Produktion (σ, τ, φ, χ) P hat demnach die Form σ < φ > τ → χ,
wobei gilt φ V, χ V+ und σ, τ V*. Durch Einklammern (mit Hilfe der Größer- und Kleinerzeichen)
des zu ersetzenden Zeichens φ wird klar festgelegt, welches Zeichen (nämlich φ) ersetzt werden soll und
welche Zeichen (σ, τ) den Kontext bilden. D.h. das Symbol φ kann nur ersetzt werden, wenn innerhalb
des Wortes links bzw. rechts neben φ, genau der Kontext σ bzw. τ steht. Bei einem D1L-System kann
entweder ein linker oder ein rechter Kontext angeben werden, bei der Klasse der D2L-Systeme werden
immer ein linker und ein rechter Kontext angeben und bei (k, l)L-Systemen wird auf der linken Seite ein
Kontext der Länge k und auf der rechten Seiten ein Kontext der Länge l platziert.
Ein Kontext, aus dem lat. contextus für ”Zusammenhang“, bezeichnet den ein Wort umgebenden Text, durch den oft die
Bedeutung erst klar wird.
1
21
Wieder wird an dieser Stelle auf ein Standard-Beispiel zurückgegriffen. Dabei wird mit Hilfe einer kontextsensitiven Produktion ein Symbol durch ein Wort geleitet. Gegeben sei das Alphabet V = {a, b}, das
Axiom ω = baaaaa und die Produktionsmenge P = {b < a → b, b → a}.
1.Schritt
2.Schritt
3.Schritt
4.Schritt
…
baaaaa
abaaaa
aabaaa
aaabaa
Dadurch, dass a in der ersten Produktion im Kontext zu b steht, wird in jedem Schritt das rechts von
einem b liegende a durch ein b ersetzt. Gleichzeitig wird das bereits vorhandene b durch ein a ersetzt
(zweite Produktion). Für alle a Symbole, die kein b als linken Nachbar besitzen, trifft die erste Produktion nicht zu, und es wird stattdessen die Identitätsproduktion ausgeführt. Damit wandert der Buchstabe
b von der linken zur rechten Seite des Wortes.
Da es sich weiterhin um ein deterministisches System handelt, ist das Ergebnis immer gleich, obwohl
diesmal für jedes φ V mehrere Regeln angegeben werden können. Allerdings nur unter der Bedingung, dass sie einen verschiedenen Kontext besitzen und damit eine eindeutige linke Seite erhalten.
Diese Bedingung schließt immer noch nicht die Möglichkeit aus, dass mehrere Regeln für ein Zeichen
angewendet werden können. In solchen mehrdeutigen Fällen wird immer die Regel mit dem größten
Kontext angewendet.
Die Abbildung 3.2 zeigt drei unterschiedlich verzweigende kontextsensitive L-Systeme, entwickelt von
[HH74]. Wie Verzweigungen innerhalb eines L-Systems erzeugt werden können, wird im nächsten Kapitel 3.3 Verzweigende Lindenmayer-Systeme erklärt.
Abb. 3.2 Kontextsensitive L-Systeme (Bilder: [3])
22
3.3 Verzweigende Lindenmayer-Systeme
Die bisherigen L-Systeme können ausschließlich zusammenhängende Gebilde erzeugen; da allerdings
die meisten Pflanzen und biologischen Systeme Verzweigungen besitzen, werden die L-Systeme um
eine neue Eigenschaft erweitert. Das System ist nun imstande, den aktuellen Zustand der Schildkröte
zu speichern und zu einem späteren Zeitpunkt wieder zu laden. Realisiert wird dies mit der Hilfe eines
Stacks1. Ein Stack ist ein spezieller Typus von Speicher, bei dem der Zugriff lediglich auf zwei Arten
erfolgen kann. Dies wäre zum einen der Push-Befehl, der den aktuellen Zustand auf die oberste Speicherstelle legt. Und zum anderen der Pop-Befehl, dieser liest den obersten Zustand vom Speicher und
löscht ihn danach. Damit wird der zuletzt gespeicherte Zustand immer zuerst geladen.
Um den Stack verwirklichen zu können, müssen zwei Änderungen eingeführt werden. Als Erstes wird
das Alphabet um zwei Zeichen erweitert, meistens werden dafür die öffnende und schließende eckige
Klammer verwendet. Des Weiteren muss der Interpreter die beiden neuen Zeichen ausführen können.
Dazu verhält sich der Interpreter wie folgt: Liest der Interpreter die öffnende eckige Klammer [ innerhalb des erzeugten Wortes, so wird der aktuelle Zustand der Schildkröte auf den Stack geschrieben
(Push). Wenn der Interpreter die schließende eckige Klammer ] identifiziert, wird der oberste Zustand
vom Speicher entnommen, gelöscht und als aktueller Zustand für die Schildkröte gesetzt (Pop). Damit
wird die Schildkröte quasi an einen früheren Zeitpunkt zurückversetzt und kann in eine andere Richtung weiter marschieren.
Es folgt ein kleines Beispiel, diesmal zur Verdeutlichung der verzweigten L-Systeme. Dazu ist wieder
ein Alphabet V = {A, F, +, -, [, ]} gegeben, nur diesmal werden die beiden zusätzlichen Zeichen zur
Abfrage des Stacks sowie eine weitere Variable A dem Alphabet beigefügt. Zusätzlich sind das Axiom
ω = A und die Produktionen P = {A → F[+A][-A]FA, F → FF} gegeben.
1. Schritt
2. Schritt
3. Schritt
…
A
F[+A][-A]FA
FF[+F[+A][-A]FA][-F[+A][-A]FA]FFF[+A][-A]FA
Das Zeichen A (für Apex) dient lediglich zum Erzeugen eines
neuen Astes, d.h. der Interpreter führt beim Lesen des Zeichens
keine besondere Aktion aus. Die Ersetzungsregel für A erzeugt
drei Verzweigungen und damit eine baumähnliche Struktur. Während die Ersetzungsregel für F nur dazu dient, die Länge der bereits bestehenden mittleren Äste zu verdoppeln. Mit Hilfe dieses
Lindenmayer-Systems entsteht nach 7 Iterationen der in Abb. 3.3
dargestellte Baum.
Abb. 3.3 Verzweigtes L-System
1
Stack zu Deutsch „Stapel“, bezeichnet einen Stapel- oder Kellerspeicher.
23
3.4 Stochastische Lindenmayer-Systeme
Wie in den Kapiteln 3.1 - 3.3 festgestellt wurde, sind die bisher vorgestellten Lindenmayer-Systeme
deterministisch und liefern zu einem gegebenen Axiom immer das gleiche Ergebnis. Um der Vielfalt
der Natur gerecht zu werden, können die Systeme auf zwei Wege in ein indeterministisches System
ausgebaut werden. Eine Möglichkeit dafür, stellen die in diesem Kapitel erklärten stochastischen Systeme dar und eine weitere Möglichkeit, die in Kapitel 3.5 erklärten parametrischen L-Systeme. Beide
Variationen können kombiniert werden und ein kontextfreies oder -sensitives System erweitern.
In einem stochastischen System ist die Angabe mehrerer Ersetzungsregeln mit identisch linker Seite
erlaubt. D.h. für jedes Zeichen der Sprache können beliebig viele verschiedene Regeln angegeben
werden. Allerdings muss das System bei einem Ersetzungsschritt eine dieser Regeln auswählen.
Diese Auswahl geschieht mit Hilfe einer Wahrscheinlichkeit, die jeder Regel zugeteilt werden muss.
Stochastische Systeme stellen demnach eine Ergänzung der bisherigen Systeme dar, indem die formale
Grammatik zu einem 4-Tupel G = (V, ω, P, π) erweitert wird. Dabei gelten die bereits in den vorherigen
Kapiteln erklärten Eigenschaften für kontextfreie bzw. kontextsensitive L-Systeme, wobei eine Menge
von Wahrscheinlichkeiten hinzukommt. Die Wahrscheinlichkeitsverteilung π: P → (0, 1] bildet die
Menge der Wahrscheinlichkeiten auf die Menge der Produktionen ab. Oder anders gesagt, π ordnet
jeder Regel eine Wahrscheinlichkeit zu, die einen Wert größer 0 und kleiner gleich 1 besitzt. D.h.
π enthält genauso viele Elemente wie die Menge der Produktionen P und ordnet jeder dieser Regel
genau ein Element zu. Addiert man die Wahrscheinlichkeiten aller Produktionen mit identisch linker
Seite (gleiches Ersetzungszeichen (Predecessor) sowie gleicher Kontext, falls vorhanden), so muss die
Summe all dieser Wahrscheinlichkeiten eine 1 ergeben. Durch diese Bedingung wird festgelegt, dass
das System immer eine Regel auswählen kann. Eine Produktion (φ, χ, υ) P hat für ein kontextfreies
System schließlich folgende Notation: φ → χ : υ. Dabei sind wie gewohnt φ, χ V+ mit |φ| = 1. Neu
angegeben wird υ π, hier bestimmt υ die Wahrscheinlichkeit mit der die Produktion zwischen allen
passenden Produktionen ausgewählt wird.
Kurz zusammengefasst, für jedes Zeichen φ V können in einem stochastischen System mehrere Regeln angeben werden. Dabei muss jeder Regel eine Wahrscheinlichkeit zwischen 0 und 1 (einschließlich 1) zugewiesen werden. Die Wahrscheinlichkeiten aller Ersetzungsregeln, die über eine identische
linke Seite verfügen, müssen in der Summe 1 ergeben. Daraus folgt, dass immer eine Produktion ausgewählt werden kann. Soll in einem Ersetzungsschritt nun das Zeichen φ ersetzt werden, so wird durch
einen Zufallsgenerator eine der passenden Regeln anhand ihrer Wahrscheinlichkeiten ausgewählt und
φ schließlich entsprechend der ermittelten
Regel ersetzt.
Da stochastische L-Systeme mit Hilfe eines
Zufallsgenerators arbeiten, ist nicht mehr garantiert, dass für ein gegebenes Axiom immer
dasselbe Ergebnis erzeugt wird. Aus diesem
Grund sind stochastische Systeme indeterministisch. Weiterhin wird durch die Auswahl
verschiedener Regeln die grundlegende Topologie des Ergebnisses verändert. Dies führt
zu verschiedenen Verzweigungsstrukturen,
wie in Abb. 3.4 zu erkennen ist. Jede der verschiedenen Pflanzen aus der Abbildung wurde durch die gleichen Regeln erzeugt. Die zufällige Auswahl der Regeln führt schließlich
zu den verschiedenen Resultaten.
24
Abb. 3.4 Ergebnisse eines stochastisches L-Systems
3.5 Parametrische Lindenmayer-Systeme
Parametrische L-Systeme sind eine weitere Variante, mehr Abwechslung von einem Lindenmayer-System erzeugen zu lassen. Im Gegensatz zu den vorher beschriebenen stochastischen Systemen verändern
paramterische Systeme nicht die topologische Struktur des Ergebnisses. Ein weiterer Vorteil von parametrischen Systemen liegt in der einfachen Kontrolle der einzelnen Parameter. Mit deren Hilfe können
z.B. die maximale Länge von Ästen, die Anzahl der Verzweigungen und vieles mehr innerhalb der aufgestellten Regeln festgelegt werden und sind damit nicht mehr konstant definiert.
In einem parametrischen L-System können allen Zeichen zusätzlich ein oder mehrere Parameter angehängt werden, diese Kombination wird als Modul bezeichnet. Ein Modul A(s0, s1, s2, …, sn) besteht
demnach aus dem Zeichen A V und den formalen Parametern1 s0, s1, s2, …, sn Σ. Auf die Parameter
kann innerhalb der Regel zurückgegriffen werden, außerdem können einfache arithmetische Operationen (z.B. Addition und Multiplikation) auf die Parameter ausgeführt werden. Eine weitere Neuerung
stellen die eingeführten Bedingungen dar, die jeder Regel angehängt werden können. Eine Regel mit
einer Bedingung kann nur ausgeführt werden, wenn die Bedingung erfüllt ist.
Definiert wird ein parametrisches L-System durch ein 4-Tupel G = (V, Σ, ω, P). Dabei ist wie gehabt
V die Menge der Variablen und ω das Axiom. Σ ist eine endliche Menge formaler Parameter. Für das
Axiom gilt immer noch ω V+. Mit dem Unterschied, dass die formalen Parameter von Modulen durch
reelle Zahlen ersetzt werden müssen. Eine Produktion φ : μ → χ erhält nun die Bedingung μ, diese kann
aus formalen sowie reellen Parameter bestehen. Es dürfen außerdem arithmetische und logische Ausrücke auf die Parameter angewendet werden.
Verdeutlichen lässt sich die Funktionsweise schnell anhand eines Beispiels. Gegeben ist das Alphabet V
= {A(x)}, das Axiom ω = A(4) und die Produktionen P = {A(x) : x > 0 → A(x-1)}. Zu beachten ist, dass
das Symbol A zusätzlich den formalen Parameter x erhält und mit diesem zusammen ein Modul bildet.
Der Parameter x ist ein Platzhalter für beliebige reelle Zahlen, im Axiom A(4) beispielsweise die reelle
Zahl 4. Durch einen Doppelpunkt nach dem Predecessor wird eine Bedingung für die Regel eingeleitet,
in diesem Fall die Bedingung x > 0. Wird nun die Produktion auf das Axiom angewendet, entsteht die
nachfolgende Ersetzungssequenz.
1. Schritt
2. Schritt
3. Schritt
4. Schritt
A(4)
A(3)
A(2)
A(1)
In jedem Schritt wird durch Anwendung der Regel der Parameter x um 1 dekrementiert, und zwar solange die Bedingung erfüllt bleibt. Im 5. Schritt kann die Bedingung x > 0 nicht mehr erfüllt und die Regel
deshalb nicht mehr ausgeführt werden. Das Beispiel zeigt ein mögliches Anwendungsgebiet der parametrischen L-Systeme, in dem die Parameter als Abbruchbedingung eingesetzt werden. Ein weiteres
Anwendungsgebiet wäre z.B. die Beeinflussung des Interpreters über die Parameter. Dabei kann der
Interpreter die Parameter auslesen, anhand dessen den Zustand der Schildkröte verändern und dadurch
z.B. die Äste eines Baums (die bisher immer gleich lang waren) mit voranschreitender Verzweigung
kürzer werden lassen.
Sind die Parameter fest gewählt, bleibt das System deterministisch. Werden die Parameter allerdings
zufällige oder dynamisch zur Laufzeit berechnet, wird das System indeterministisch und bietet somit
große Variationsmöglichkeiten.
Formale Parameter dienen zur Spezifikation eines Moduls. Reelle Parameter sind definierte Parameter, d.h. Parameter denen
eine reelle Zahl zugewiesen wurde.
1
25
Ein weiteres Beispiel wird in
Abbildung 3.5 dargestellt. Das dort
gezeigte parametrische L-System
wird durch das Axiom ω = A(1) sowie
die Produktion P = {A(s) → F(s)
[+A(s/1.456)] [-A(s/1.456)]} erzeugt.
In jedem Schritt erzeugt das System
zwei Verzweigungen, die mit jeder
fortschreitenden Iteration ihre Länge
und Ausrichtung ändern. Diese werden
beide über den formalen Parameter s
bestimmt. Der Parameter s wird bei
jeder Ersetzung von A durch einen
festen Wert dividiert und verringert
dadurch die Abweichung und Größe.
Auch hier wird durch eine einzige
Ersetzungsregel eine sehr komplexe
und beliebig detailreiche Geometrie
formuliert.
Abb. 3.5 Parametrisches L-System (Bild: [LP90])
3.6 Umgebungssensitive und offene Lindenmayer-Systeme
Die bisher vorgestellten Systeme bieten bereits eine große Bandbreite von Optionen an, möglichst
realistische und ansprechende Pflanzen zu erschaffen. So können mit kontextsensitiven Systemen
zwar Pflanzen auf ihre eigene lokale Umgebung zurückgreifen und diese zu weiteren Ausbreitung
verwenden, allerdings bleibt die wirkliche Umwelt von dessen Ausbreitung völlig ungenutzt. Um
dieses Verhältnis zwischen Pflanze und Umwelt simulieren zu können, wurden von [MPJ95] die so
genannten umgebungssensitiven bzw. umweltsensitiven Systeme eingeführt. Bei diesen handelt es sich
um eine Erweiterung der parametrischen Systeme, wobei ausschließlich eine einseitige Kommunikation
stattfindet. D.h. das System kann lediglich Information von der Umgebung anfordern, aber verändert
diese nicht. In den später erforschten offenen Systemen [MP96] findet eine beidseitige Kommunikation
statt, damit verändert das L-System auch die Umgebung und beeinflusst über diese andere Systeme.
In einem umgebungssensitiven L-System wird die Umwelt in zwei Eigenschaftsklassen gegliedert,
die globalen und lokalen Eigenschaften. Die globalen Eigenschaften definieren globale, nicht an einen
kleinen Ort festgelegte Eigenschaften. Dazu zählen zum Beispiel die Länge der Tageszeit oder die
minimalen und maximalen Temperaturen während des Tages. Die lokalen Eigenschaften der Umgebung
stellen dagegen meist physische und in der näheren Umgebung der Pflanze existierende Eigenschaften
dar. Zu diesen zählen z.B. feste Objekte, die das Wachstum der Pflanzen stören können, oder die Dichte
und Beschaffenheit des Erdbodens.
Umgebungssensitive Systeme bauen auf paramterischen L-Systemen auf, dabei werden neue sogenannte
Anfrage-Module1 eingeführt. Der Unterschied zu den in Kapitel 3.5 Parametrische Lindenmayer-Systeme
beschriebenen parametrischen Modulen besteht darin, dass die Parameter der Anfrage-Module während
der Ersetzung noch nicht mit konkreten Werten belegt werden. Sie bleiben also vorerst undefiniert. Nun
wird nach jedem Ersetzungsschritt das aktuelle Wort sofort interpretiert, allerdings noch nicht grafisch
dargestellt. Durch diese Interpretation werden die Position und Orientierung (Zustand) der Schildkröte
wie gewohnt verändert. Sobald ein Anfrage-Modul interpretiert werden soll, wird die Umgebung mit
1
in Englisch query modules.
26
Hilfe des aktuellen Zustands der Schildkröte abgefragt. Diese Anfrage an die Umgebung liefert Werte
für die undefinierten Parameter zurück und weist diesen damit konkrete Werte zu, die wiederum in der
nächsten Iteration eingesetzt werden können.
Wenn das endgültige Wort erreicht wurde, wird erneut das gesamte Wort interpretiert und diesmal auch
grafisch dargestellt, woraus dann das Abbild der Pflanze resultiert.
Offene L-System können im Vergleich zu umgebungssensitiven L-Systemen nicht nur Anfragen an die
Umgebung stellen, sondern aufgrund einer beidseitig Kommunikation auch Änderungen an die Umwelt
senden, deshalb erweitern sich die vorherigen Anfrage-Module zu Kommunikations-Modulen2. Im
Grunde verändert sich nichts an dem Verfahren des bereits beschriebenen umgebungssensitiven Systems,
außer dass die Parameter eines Kommunikations-Moduls nicht zwangsläufig undefiniert bleiben müssen.
D.h. ein Kommunikations-Modul kann über definierte Parameter Eingaben an die Umwelt schicken und
durch undefinierte Parameter Einflüsse von der Umwelt erhalten.
Bei beiden Modulen (Anfrage- und Kommunikations-Modul) wird den Modulen ?E(s0, s1, s2, …, sn)
lediglich ein Fragezeichen vorausgesetzt. Damit kann das System die speziellen Module von normalen
parametrischen Modulen unterscheiden.
An dieser Stelle sparen wir uns eines der sehr komplexen und abstrakten Beispiele und zeigen stattdessen
direkt zwei Ergebnisse, siehe Abbildungen 3.6 und 3.7. In der ersten Abbildung wird gezeigt, wie eine
rankenartige Pflanze sich der Geometrie eines Objektes anpasst. In der zweiten Abbildung reagieren
die beiden Bäume zusätzlich auf globale Eigenschaften. Mit dem Bestreben möglichst viel Licht zu
erhalten, interagieren die beiden Bäume miteinander und passen ihr Wachstum dementsprechend an.
Abb. 3.6 Umgebungssensitives L-System
(Bild: [MPJ95])
Abb. 3.7 Offenes L-System (Bild: [MP96])
1
in Englisch communication modules.
27
4. Straight-Skeleton
Wie sich im späteren Verlauf der Arbeit herausstellen wird, werden die Dächer eines Gebäudes lediglich
durch ein Polygon definiert. Dieser Linienzug bildet die Traufe der Dächer und besitzt noch keinerlei
innere Struktur, d.h. die Lage und Ausrichtung der einzelnen Dachflächen ist noch nicht festgelegt. Es
wird demnach ein Verfahren benötigt, das die Dachausmittlung für eine Traufe berechnen kann, und
aus dieser die einzelnen Dachflächen ermittelt. Da die Traufe eines Gebäudes beliebig verlaufen kann,
muss das Verfahren die Dachausmittlung für jedes Polygon bestimmten können, egal, ob es sich um ein
konvexes oder konkaves Polygon handelt.
Das zurzeit bekannteste und robusteste Verfahren zur Ermittlung einer Dachausmittlung wurde 1995
von Aichholzer und anderen vorgestellt. Die Arbeit [Aic+95] beschreibt eine neue Form der Darstellung
von inneren Strukturen einfacher Polygone, auch kurz als Straight-Skeleton bezeichnet. Dabei wird die
Form des Polygons durch ein topologisches Skelett widergespiegelt und stellt eine Alternative zu dem
bekannten Medial-Axis Verfahren, im deutschen Mittelachsen oder Medial-Achsen, dar. Im Gegensatz
zu den Mittelachsen enthält das Straight-Skeleton als Repräsentationsform ausschließlich geradlinige
Segmente und keinerlei Kurven. Kurvenelemente sind durch die spätere Darstellung des Dachs aus
Flächen nicht zweckdienlich, weshalb das Mittelachsen-Verfahren ungeeignet für die Dachausmittlung
ist. Weiterhin beruht die Berechnung des Straight-Skeletons nicht auf der Basis von Abständen, wie es
bei den Mittelachsen der Fall ist. Vielmehr wird bei der Ermittlung des Straight-Skeletons auf eine Art
„Schrumpfprozess“ (im engl. shrinking process) zurückgegriffen. Dabei bedienen sich die Autoren der
Idee, dass das Polygon gleichmäßig in sich zusammenschrumpft. D.h. dass alle Punkte des Polygons
gleichmäßig in Richtung ihrer Winkelhalbierenden laufen und aus diesem Grund schließlich zusammenfallen. Oder anders gesagt, alle Kanten des Polygons laufen mit konstanter Geschwindigkeit ins innere
des Polygons. Dabei verlaufen die Kanten immer parallel zur ihrer Ursprungskante und verändern während der Bewegung nur ihre Länge. Das Polygon schrumpft so lange, bis sein Flächeninhalt eine Größe
von Null aufweißt bzw. die Kantenlängen auf Null sinken.
Beide Verfahren bilden ein und dasselbe Ergebnis unter der Bedingung, dass das Polygon konvex ist
[Aic+95] [Gör04]. Besitzt das Polygon konkave Stellen, so enthalten die Mittelachsen parabolische Elemente und sind aus diesem Grund nicht geeignet für die Dachausmittlung.
Die Struktur des Straight-Skeletons ist identisch mit einer von vielen Möglichkeiten der Dachausmittlung. Dabei wird als Polygon einfach der Grundriss des Hauses bzw. die Traufe des Dachs verwendet.
Für diese Traufe berechnet das Straight-Skeleton die innere Struktur, woraus anschließend die einzelnen
Dachflächen erzeugt werden können. Allerdings besitzt das Straight-Skeleton eine Einschränkung: Die
innere Struktur (Synonym für Dachausmittlung) eines Polygons (Synonym für Traufe) wird immer so
berechnet, als wenn alle Dachflächen eine Steigung von 45 Grad besitzen würden.
Abb. 4.1 (a) Schrumpf-Prozess, (b) Straight-Skeleton und (c) Dach (Bilder (a)(b): [Aic+95])
28
Die Abbildung 4.1 (a) zeigt mehrere Schritte des Schrumpfprozesses. Dabei ist zu erkennen, wie das
Polygon immer kleiner wird, die Kanten aber trotzdem parallel zu ihrer Ausgangskante verlaufen. In
Abb. 4.1 (b) wird schließlich das erzeugte Straight-Skeleton von Abb. 4.1 (a) durch die gestrichelten
Linien dargestellt. Abbildung 4.1 (c) präsentiert schließlich die aus dem Straight-Skeleton erzeugten
Dachflächen, demnach das fertige Dach.
Die nachfolgenden Kapitel beschreiben zuerst die speziellen Ereignisse (Kapitel 4.1), die während des
Schrumpfens auftreten können. Weiterhin wird eine Definition von Distanz (Kapitel 4.2) innerhalb des
Straight-Skeletons definiert, sowie eine Definition für das Straight-Skeleton (Kapitel 4.3) selbst aufgeführt. Schließlich wird ein Algorithmus (Kapitel 4.4) zur Bestimmung des Straight-Skeletons erläutert.
4.1 Ereignisse
Wie bereits beschrieben, laufen während des Schrumpfens alle Kanten mit gleicher Geschwindigkeit
in das Innere des Polygons. Während dieser Bewegung können zwei verschiedene Ereignisse [Aic+95]
auftreten. Nach Eppstein und Erickson [EE98] bei speziellen konkaven Polygonen noch ein drittes
Ereignis. Bei jedem Ereignis verbinden sich zwei Kanten oder eine Kante wird in mehrere Teile gespalten.
Dies hat zur Folge, dass sich an genau den Stellen, wo die Ereignisse auftreten, die Topologie des
Straight-Skeletons verändert. Deshalb schrumpft das Polygon bis zum Auftreten des ersten Ereignisses,
verändert dort seine Struktur und schrumpft weiter bis um nächsten Ereignis, usw. (mehr dazu in Kapitel
4.4 Algorithmus).
(1) Edge Event
Eine Kante schrumpft zu einem Punkt zusammen, besitzt damit die Länge null und
verbindet nunmehr ihre Nachbar-Kanten miteinander.
(2) Split Event
Ein reflex Vertex1 trifft während des Schrumpfprozesses auf eine gegenüberliegende
und entgegenlaufende2 Kante und spaltet diese, demnach auch das gesamte
Polygon, in zwei Teile. Die beiden adjazenten Kanten des Reflex-Vertex sind nach
dem Ereignis adjazent zu den beiden aufgesplitterten und damit neu erzeugten
Kanten. Nachdem das Polygon in zwei neue Polygon gespalten wurde, schrumpft
jedes der neuen Polygon rekursiv weiter. Da Reflex-Vertices nur in konkaven
Polygonen entstehen, können Split Events auch nur in genau diesen auftreten.
(3) Vertex Event
In speziellen Fällen können zwei oder mehr simultane Ereignisse in genau
demselben Punkt auftreten. In den meisten Fällen, und zwar, wenn es sich bei den
Ereignissen um Edge Events handelt, stellen diese Ereignisse keine Ausnahme
dar. Treffen allerdings zwei oder mehr Reflex-Vertices zeitgleich auf einem Punkt
zusammen, so entsteht dadurch ein neues Ereignis: das Vertex Event. Bei einem
Vertex Event kann das Polygon in mehr als zwei Teile gespaltet werden. Genauer
gesagt, wird das Polygon in so viele Teile gespalten, die der Anzahl simultaner
Ereignisse entspricht.
[Aic+95][EE98] formulieren, dass jeder neue Knoten immer einen stumpfen Winkel besitzt und deshalb niemals ein neuer Reflex-Vertex entstehen kann. Nach
[EE98] stellen die durch ein Vertex Event entstehenden Knoten die einzige Ausnahme dar, siehe Abb. 4.2 (c).
Die Autoren benennen Punkte die einen überstumpfen Winkel besitzen als Reflex-Vertex, abgeleitet von dem englischen
mathematischen Begriff „reflex Angle“, für einen überstumpfen Winkel.
2
Wie sich im späteren Verlauf herausstellen wird, handelt es sich dabei nicht immer um entgegenlaufende Kanten. Bei entarteten Polygonen existieren Ausnahmen, die der Einfachheit halber erst einmal ignoriert werden.
1
29
Die Abbildung 4.2 (a) zeigt, wie zeitgleich zwei Kanten des Polygons auf eine Länge von Null
zusammenschrumpfen und deshalb simultan zwei Edge Events auslösen (gekennzeichnet durch die
zwei Kreise). Das durch die Ereignisse entstehende und geschrumpfte Polygon wird durch die roten
Linien verdeutlicht. Abbildung 4.2 (b) veranschaulicht, wie ein Reflex-Vertex beim Schrumpfen des
Polygons in die gegenüberliegende Kante läuft und diese bzw. damit das gesamte Polygon in zwei
Teile spaltet. Dadurch entstehen zwei neue Polygone, die beide getrennt voneinander weiter in sich
zusammenschrumpfen. Das konkave Polygon aus Abb. 4.2 (c) löst ein Vertex Event aus, da sich zwei
Reflex-Vertices in einem Punkt treffen. Oder anders gesagt, da jeder der beiden Vertices die Kante des
anderen spaltet.
Abb. 4.2 (a) Zwei zeitgleiche Edge Events, (b) Split Event und (c) Vertex Event (Bilder: [EE98])
4.2 Distanz
In einem Straight-Skeleton wird die Schrumpf-Distanz1 immer
senkrecht zu den Kanten des Polygons angegeben. Dies ist darin
begründet, dass während des Schrumpfprozesses alle Kanten des
Polygons parallel zu ihrer Ausgangskante verlaufen, wie bereits beschrieben und verdeutlicht in Abb. 4.1 (a). Wie sich im späteren
Verlauf heraus stellen wird, muss für jedes Ereignis eine Distanz
angegeben werden. Diese beschreibt den Zeitpunkt, nach dem das
Ereignis ausgelöst wird. Benötigt wird die Distanz, um die ver- Abb. 4.3 Distanz bei Edge Event
schiedenen Ereignisse miteinander zu vergleichen und dadurch eine
Reihenfolge der Ereignisse aufzustellen zu können.
Würde zum Beispiel das in Abb. 4.3 dargestellte Edge Event auftreten, so wäre die Distanz, die das Polygon bis zum Eintritt des
Ereignisses schrumpft, nicht gleich der Länge zwischen dem Ausgangspunkt und dem geschrumpften Punkt, sondern der senkrechte
Abstand des geschrumpften Punktes bis zu einer der beiden Nachbar-Kanten des Ausgangspunktes.
Bei einem Split Event (s. Abb. 4.4) entspräche die Distanz ebenfalls
nicht der Länge zwischen dem Ausgangspunkt und dem geschrumpften Punkt. Die Distanz wird auch hier durch den senkrechten Abstand des geschrumpften Punktes bis zu einer der beiden Nachbar- Abb. 4.4 Distanz bei Split Event
Linien des Ausgangspunktes ermittelt. Wichtig ist, dass der Abstand
zur Linie der jeweiligen Kante (grau gestrichelte Linie in Abb. 4.4)
berechnet wird und nicht der Abstand bis zur Kante (Strecke) selbst.
1
Im engl. shrink distance.
30
4.3 Definition
„The straight skeleton, S(P), is defined as the union of the pieces of angular bisectors traced out by
polygon vertices during the shrinking process. S(P) is a unique structure defining a polygonal partition
of P. Each edge e of P sweeps out a certain area which we call the face of e. Bisector pieces are called
arcs, and their endpoints which are not vertices of P are called nodes, of S(P).“ [Aic+95]
Übersetzt man die Definition des Straight-Skeletons nach [Aic+95], ist das Straight-Skeleton die
Vereinigung aller Winkelhalbierenden, die während des Schrumpfprozesses an den Punkten des Polygons
entstehen. Weiterhin beinhaltet die Definition, dass jedes Straight-Skeleton einzigartig ist und für ein
Polygon eindeutig bestimmt werden kann.
Die Bezeichnung Node1 anstatt Vertices für die neuen Punkte, die an den Enden der kollidierenden
Winkelhalbierenden entstehen, kommt daher, dass jeder der erzeugten Punkte auch als Knoten innerhalb
eines Graphen angesehen werden kann. Diese Knoten besitzen in den meisten Fällen einen Grad von 3,
nur unter speziellen Umständen2 können evtl. Knoten mit einem größeren Grad entstehen. Das StraightSkeleton bildet von diesem Gesichtspunkt aus einen Graph, dessen Knoten die innere Struktur des
Polygons unterteilen und damit wiedergeben. Die Fläche die aus einer Ursprungskante des Polygons
gebildet wird, quasi die spätere Dachfläche, wird auch als Face dieser Kante bezeichnet.
4.4 Algorithmus
In diesem Kapitel wird ein Algorithmus zur Berechnung des Straight-Skeletons vorgestellt. Der hier
beschriebene Algorithmus ist nicht sehr effizient, sowohl [EE98] als auch [Obd] stellen in ihren Arbeiten Methoden zur Optimierung vor. Diese werden hier allerdings nicht weiter berücksichtigt. Wie von
[EE98] formuliert, werden alle möglichen Ereignisse berechnet und anhand ihrer Schrumpf-Distanz,
also dem „Zeitpunkt“, nach dem sie ausgelöst werden, in eine Liste sortiert. Wenn alle Ereignisse berechnet wurden, wird das erste Ereignis aus der Liste entnommen und das Polygon bis zum Auftreten
dieses Ereignisses geschrumpft. An dieser Stelle verändert das Polygon seine Struktur, indem z.B. zwei
Kanten durch ein Edge Event in einem Punkt zusammenfallen. Diese Veränderung kann wieder neue
Ereignisse zufolge haben und erfordert eine erneute Berechnung der Ereignisse. Ist dies geschehen, wird
das Polygon erneut bis zum Auftreten des ersten Ereignisses geschrumpft. Bei jeder neuen Iteration wird
das Polygon kleiner, bis es irgendwann einen Flächeninhalt von Null besitzt und der Algorithmus damit
terminiert. Die genauen Schritte sehen folgendermaßen aus:
1.
2.
3.
4.
5.
1
2
Berechne die Winkelhalbierenden für alle Punkte des Polygons. Um die Ausrichtung der
Winkelhalbierenden eindeutig bestimmen zu können, müssen die Punkte des Polygons gegen
den Uhrzeigersinn angegeben werden.
Berechne alle Edge, Split und Vertex Events, Genaures dazu in dem späteren Kapiteln 4.5. Füge
das jeweilige Ereignis sortiert (anhand der Schrumpf-Distanz) in eine Ereignis-Liste ein. Dabei
gilt, je kleiner die Distanz, desto höher die Priorität des Ereignisses.
Entnehme das Ereignis bzw. die Ereignisse mit der höchsten Priorität aus der Liste und schrumpfe das Polygon entsprechend der/des Ereignisse/s, genaures in Kapitel 4.5.
Berechne die Winkelhalbierenden für alle durch ein Split/Vertex Event neu entstandenen oder durch
ein Edge Event zusammengefassten Punkte. Da der Schrumpfprozess keinerlei Einfluss auf die Winkelhalbierenden der anderen Punkte ausübt, müssen diese nicht noch einmal berechnet werden.
Für das geschrumpfte Polygon und jedes eventuell durch ein Split oder Vertex Event neu entstandene Polygon führe erneut Schritt 2 aus. Es sei denn, der Flächeninhalt des Polygons ist Null.
Zu Deutsch „Knoten“.
Dies ist der Fall, wenn zeitgleich mehrere Ereignisse in einem Punkt auftreten, zum Beispiel bei einem Vertex Event.
31
Jedes Mal, wenn ein Polygon schrumpft, wird das unveränderte Polygon (Polygon vor dem Schrumpfen) beibehalten und nicht durch das geschrumpfte Polygon überschrieben. Jeder Punkt innerhalb des
Ursprungspolygons erhält eine Verbindung (Zeiger) auf seinen geschrumpften Punkt in dem neu erzeugten und verkleinerten Polygon. Damit bilden das ursprüngliche Polygon und alle in den verschiedenen Iterationen geschrumpfte Polygone einen Graphen, das Straight-Skeleton.
4.5 Berechnung der Ereignisse
4.5.1 Edge Events
Wie bereits beschrieben, tritt ein Edge Event ein, wenn die Kante zwischen zwei Punkten auf eine
Länge von Null schrumpft und damit die beiden Nachbar-Punkte zu einem Punkt zusammenfallen. Die
Berechnung aller Edge Events für ein Polygon erweist sich als relativ einfach. Hierzu muss lediglich
für jeden Punkt des Polygons die Schnittpunkte zwischen der Winkelhalbierenden des Punktes und den
Winkelhalbierenden der Nachbar-Punkte ermittelt werden. Konnte ein Schnittpunkt berechnet werden,
wird die Schrumpf-Distanz (siehe Kapitel 4.2 Distanz) berechnet und der Schnittpunkt als Edge Event
in die Ereignis-Liste sortiert. Falls zwei Schnittpunkte berechnet werden konnten, wird der Schnittpunkt
mit der kürzeren Distanz verwendet. Konnte kein Schnittpunkt berechnet werden, löst der aktuelle Punkt
kein Edge Event aus.
Sollte das Edge Event die höchste Priorität besitzen, wird das Polygon bis zum Auftreten des Edge
Events geschrumpft. Dazu werden alle Punkte entlang ihrer Winkelhalbierenden und entsprechend der
Schrumpf-Distanz des Ereignisses verschoben. Dadurch fallen mindestens zwei Punkt zu einem Punkt
zusammen, die nun durch einen gemeinsamen Knoten ersetzt werden.
Abbildung 4.5 zeigt die drei möglichen Fälle bei der Berechnung eines Edge Events. In allen drei
Zeichnungen wird der aktuelle Knoten, für den das Edge Event berechnet werden soll, durch einen roten
Punkt gekennzeichnet. In Abb. 4.5 (a) entsteht nur ein Schnittpunkt zwischen den Winkelhalbierenden,
dieser bildet damit das Edge Event für den roten Knoten. In Abb. 4.5 (b) entstehen zwei Schnittpunkte,
da der Schnittpunkt mit dem rechten Nachbar deutlich früher auftritt, wird dieser verwendet, um als
Edge Event in die Ereignis-Liste aufgenommen zu werden. Abb. 4.5 (c) zeigt schließlich ein Beispiel,
in dem kein Schnittpunkt für den aktuellen Knoten berechnet werden kann und damit auch kein Edge
Event für diesen stattfindet.
Abb. 4.5 (a) Edge Event mit einem Schnittpunkt, (b) Edge Event mit zwei Schnittpunkten und (c) kein
Edge Event
32
4.5.2 Split Events
Zur Erinnerung, Split Events treten auf, wenn ein Reflex-Vertex während des Schrumpfprozesses in
eine andere Kante des Polygons läuft und diese damit in zwei Teile spaltet, daher der Name „split“,
zu Deutsch „gespalten“ oder „zweiteilig“. Berechnet werden die Split Events, indem jeder ReflexVertex des Polygons gegen alle Kanten des Polygons getestet wird. Ausgeschlossen davon sind die
zwei Nachbar-Kanten des aktuellen Reflex-Vertex. Um schließlich den Auftrittspunkt bzw. Schnittpunkt
eines möglichen Splits für ein Reflex-Vertex zu berechnen, werden in der Literatur zwei verschiedene
Varianten erklärt. Bei der erste Variante [Obd] wird das Split Event im R2 berechnet, die zweite Variante
[EE98] ermittelt das Split Event im R3.
(1)
Die Berechnung des Split Events beruht auf der Tatsache, dass der senkrechte Abstand des
Schnittpunkts P zur Linie (nicht Strecke) der Kante E der gleiche ist wie zu den beiden Linien
der Nachbar-Kanten des Reflex-Vertex V, siehe Kapitel 4.2 Distanz und Abb. 4.6 (a) und (c).
Zuerst wird der Schnittpunkt R berechnet, dieser ist gegeben durch den Schnitt der Linie von
E und einer der Nachbar-Kanten von V, die nicht parallel zur Kante E verlaufen darf. Wichtig,
es wird der Schnittpunkt der beiden Linien und nicht der beiden Strecken berechnet. Wenn R
ermittelt wurde, kann die Winkelhalbierende zu R berechnet werden. Diese wird durch die
Kante E und der verwendeten Hilfskante von V ermittelt. Der endgültige Schnittpunkt P ergibt
sich schließlich durch den Schnitt der Winkelhalbierenden von V und R. Die Abbildungen 4.7
(a) und (c) zeigen die graphische Ermittlung des Punktes P.
Nachdem der Punkt P bestimmt wurde, muss geprüft werden, ob dieser innerhalb der möglichen
Fläche (Face) liegt, die E während des Schrumpfens annehmen kann. Die Fläche ist durch E und
die beiden Winkelhalbierenden B0 und B1 gegeben und bildet meist ein Dreieck, siehe Abb.
4.6 (b).
Für [Obd] gelten Reflex-Vertices, die hinter der zu prüfenden Kante E liegen und damit nicht
entgegenlaufen, als keine möglichen Kandidaten für ein Split Event. Allerdings haben [EE98]
bewiesen, dass durch spezielle Konstellationen trotzdem Split Events entstehen können, siehe
Abb. 4.6 (d). Selbst wenn eine solche Konstellation mit dem Verfahren geprüft werden würde,
würde die oben beschriebene Berechnung kein korrektes Ergebnis liefern und einen falschen
Punkt P berechnen, siehe erneut Abb. 4.6(d). Aus diesem Grund ist diese Art der Berechnung
nicht ausreichend.
Abb. 4.6 (a) Berechnung des Split Event Punktes P, (b) Mögliche Fläche der Kante E,
(c) Berechnung des Split Event Punktes P, (d) Keine bzw. falsche Berechnung
33
(2)
[EE98] verwenden zum Ermitteln des Split Events, die durch die beiden Winkelhalbierenden
entstehende Fläche der Kante E. Diese Fläche wird im R3 angegeben, besitzt immer eine Steigung
von 45° und wird durch die beiden Winkelhalbierenden B0 und B1 bestimmt. Abbildung 4.7
(a) und (b) zeigen die zwei möglichen Fälle der Fläche. Entweder bildet die Fläche ein Dreieck
oder verläuft ins Unendliche, wobei dieser Unterschied für die Berechnung des Ereignisses
keine Rolle spielt.
Der Split-Punkt/Schnittpunkt P des aktuellen Reflex-Vertex V wird berechnet, indem der
Schnitt zwischen der Winkelhalbierenden von V und der Ebene von E ermittelt wird. Wenn
der Schnittpunkt berechnet werden konnte, muss festgestellt werden, ob dieser sich innerhalb
der möglichen Fläche von E befindet. Liegt der Punkt außerhalb der Fläche, so kommt der
Punkt als mögliches Split Event nicht in Frage. Das Verfahren zu Berechnung des Split Events
funktioniert in allen Fällen, auch bei nicht entgegenlaufender Kante, wie das Beispiel aus Abb.
4.7 (b) verdeutlicht.
Die Abbildung 4.7 (a) zeigt die dreidimensionale Darstellung eines Polygons, das ungefähr
dem Polygon aus Abb. 4.2 (b) gleich kommt. Abb. 4.7 (b) zeigt eine dreidimensionale Variante
ähnlich des Polygons aus Abb. 4.2 (c). Es ist zu erkennen, dass die Winkelhalbierende von V
die Fläche der Kante E genau in der Winkelhalbierende B1 schneidet und dort ein Split Event
auslöst.
Abb. 4.7 Berechnung des Split Events im R3
Nachdem der Schnittpunkt berechnet wurde, muss ermittelt werden, wann das Split Event auftritt. Dazu
wird die Schrumpf-Distanz des Schnittpunktes berechnet (siehe Kapitel 4.2 Distanz). Wenn alle Kanten
gegen den aktuellen Reflex-Vertex getestet wurden, wird das Split Event mit der geringsten SchrumpfDistanz unter allen ermittelt und in die Ereignis-Liste sortiert eingefügt.
Sollte ein Split Event die höchste Priorität innerhalb der Ereignis-Liste besitzen, so wird das Polygon in
zwei Teile gespalten. Dabei wird der Reflex-Vertex, der das Ereignis auslöst, jeweils in beide Polygone
eingefügt, siehe Abb. 4.2 (b).
4.5.3 Vertex Events
Wie in Kapitel 4.1 Ereignisse bereits erläutert wurde, sind Vertex Events zwei oder mehr simultane
Split Events, die zur gleichen Zeit im gleichen Punkt auftreten. D.h. konkret, wenn zwei Split Events im
selben Punkt und bei gleicher Distanz ausgelöst werden, so werden diese Split Events zu einem Vertex
Event zusammengefasst. Jedes neue Split Event, das ebenfalls in diesem Punkt zum gleichen Zeitpunkt
(Distanz) auftritt, wird zusätzlich dem Vertex Event beigefügt. Die eigentliche Berechnung des Vertex
Events beinhaltet also lediglich den Vergleich aller Split Events, und zwar anhand deren Auftrittspunkte
und Schrumpf-Distanzen.
34
4.6 Gewichtung
Wie auf letzten Seiten deutlich geworden ist, laufen beim Schrumpfen alle Kanten mit gleicher und
konstanter Geschwindigkeit in das Innere des Polygons. Wurde das Straight-Skeleton auf die Weise
ermittelt, werden aus dem entstandenen Skelett die Dachflächen erzeugt, die alle eine Steigung von 45°
besitzen.
Wie im Kapitel 2.2.2 Dachformen dargelegt wurde, existieren Dächer, deren Flächen an den Giebelseiten
steil nach oben verlaufen und demnach über eine Steigung von 90° an den Giebelseiten verfügen.
Solche Gegebenheiten können durch eine individuelle Gewichtung der Kanten erreicht werden. Erhält
eine Kante des Polygons eine Gewichtung, so schrumpft die Kante entsprechend der Gewichtung
langsamer als die Kanten ohne Gewichtung1. Dabei darf die Gewichtung nur zwischen 0 und 1 liegen,
einschließlich 0 und 1. Zum Beispiel schrumpft eine Kante mit einer Gewichtung von 0.5 nur halb so
schnell wie alle restlichen Kanten, falls diese über eine Gewichtung von 1 verfügen. Berücksichtigt
werden muss die Gewichtung zum einen bei der Schrumpf-Distanz und zum anderen bei der Ermittlung
der Winkelhalbierenden.
Abbildung 4.8 (a) präsentiert ein einfaches Polygon mit einer Standardgewichtung für alle Kanten. Wird
für die beiden kürzeren Seiten eine Gewichtung von 0.5 festgelegt, schrumpfen diese nur mit der halben
Geschwindigkeit und es entsteht das Straight-Skeleton aus Abb. 4.8 (b). Bei einer Gewichtung von 0
für die linke und rechte Kante entsteht das Skelett aus Abb. 4.8 (c). Bei diesem verlaufen die Flächen
der linken und rechten Kante steil nach oben, besitzen demnach eine Steigung von 90°. Abbildung 4.8
(a) entspricht der Dachausmittlung eines Walmdachs, während Abb. 4.8 (c) der Dachausmittlung eines
Satteldachs mit Giebelseiten gleichkommt.
Abb. 4.8 Gewichtung
1
Keine Gewichtung entspricht einer Gewichtung von 1.
35
36
5. Konzept
In den vorherigen Kapiteln wurden einige Grundlagen erläutert, darunter waren die LindenmayerSysteme, das Straight-Skeleton, architektonische Grundlagen sowie einige Arbeiten, die bereits
Ergebnisse auf dem Gebiet der prozeduralen Gebäudegenerierung erzielt haben. Im Laufe dieses
Kapitels wird beschrieben, wie all diese Verfahren eingesetzt werden, um ein System zu schaffen, das
Gebäude prozedural generiert.
Die Grundlage des entwickelten Systems bildet ein regelbasierendes Ersetzungssystem, das stark auf
den in Kapitel 3 beschriebenen Lindenmayer-Systemen beruht. Über das Ersetzungssystem, das im weiteren Verlauf der Arbeit meist nur als Grammatik bezeichnet wird, können Regeln aufgestellt werden,
aus denen verschiedene Merkmale von Gebäuden erzeugt werden. Dazu werden einige Änderungen an
den erklärten Lindenmayer-System vorgenommen, unter anderem z.B. an der Definition, an der Syntax,
bei der Angabe von Wahrscheinlichkeiten und Bedingungen und vieles mehr. Diese Änderungen und
Ausbauten ermöglichen die Aufstellung von übersichtlicheren Grammatiken und eine effizientere und
gezielte Steuerung der Transformationen (Zustand der Schildkröte).
Wie bei der von [MWH+06] entwickelten Shape-Grammar wird zuerst durch Kombination verschiedener Formen ein Masse-Modell [MWH+06] gebaut. Der Begriff Masse-Modell wird übernommen und
bezeichnet das Grundmodell bzw. den Grundriss des Bauwerks. Im Unterschied zu [MWH+06] wird
kein Straßennetz generiert, und als Initialgrundriss steht deshalb keine beliebige Form zur Verfügung,
auf der Extrusionen angewendet werden könnten. Das Masse-Modell wird ausschließlich aus speziellen
Körpern, im Fortlaufenden als Primitive bezeichnet, zusammengebaut. Um diesen Vorgang zu erleichtern, wurde für das System eine gezielte Steuerung von Transformationen entwickelt.
Im Vergleich zu [MWH+06] wird das Gebäude nicht aus einer einziger Grammatik gefertigt, sondern
auf verschiedene Grammatiken aufgeteilt. D.h. für die unterschiedlichen Teile des Gebäudes existieren
verschiedene Grammatiken und Regelbasen. Eine Startgrammatik erstellt das oben beschriebene
Masse-Modell. Den einzelnen Teilen des Masse-Modells können dabei andere Grammatiken zugeordnet
werden. Diese werden z.B. an den Fassaden oder den Kanten der Gebäudeteile ausgeführt und erzeugen
dort Fenster, Türen, Dachgauben, Regenrinnen oder sonstige Objekte.
Zusätzlich wird ein sehr abstrakte Grammatik eingeführt, die es dem Nutzer ermöglicht, Polygone zu erstellen und anhand dieser die Geometrie des Masse-Modells zu verändern, um z.B. Säulen, Querbalken,
Mansarddächer und vieles mehr zu generieren.
Neben den Primitiven können vorgefertigte Modell geladen werden, ähnlich wie bei [MWH+06]. Auch
hier wurde eine Erweiterung eingeführt, dabei handelt es sich um die sogenannten Gruppen. Gruppen
verwalten Modelle oder Texturen, die logisch zu einer Kategorie gehören (z.B. verschiedene Arten von
Türen). Die Grammatiken können über eine Gruppe Objekte aus dieser anfordern und beispielsweise auf
den Wänden, Ecken oder Dachflächen platzieren.
Wie bei einer Split-Grammar [WWS+03] kann das System die einzelnen Grundrisse, Fassaden und
Kanten in verschiedene Bereiche aufspalten. Allerdings existiert für diesen Vorgang keine spezielle
Split-Grammar, sondern Funktionen, die in die bereits vorhandenen Grammatiken integriert wurden.
D.h. Grammatiken, die bereits das Masse-Modell oder die Fassaden generieren, können zusätzlich Splitbzw. Subdivision-Methoden ausführen und dadurch den Gebäudebereich bzw. die Fassade unterteilen.
Eine Neuerung ermöglicht hier eine einfache Formulierung von Symmetrien bzgl. der durch die
Aufteilung erzeugten Partitionen.
Eine weitere Entwicklung ermöglicht erstmals die Beeinflussung von Gebäuden durch ihre Umwelt. So
können z.B. die Größe eines Gebäudes, die Anzahl der Fenster, die Art der Fenster und sonstige Eigenschaften durch die lokale und globale Umgebung beeinflusst werden. Zu diesem Zweck wurden verschiedene Verfahren ermittelt, die die Umgebung möglichst schnell und effizient analysieren können.
Über die Fertigung von Regeln, das Anlegen von Gruppen und durch den Einsatz bereits vorgegebener
Funktionen lassen sich schließlich verschiedene Gebäudetypen definieren. Ein Gebäudetyp könnte zum
37
Beispiel Wohnhäuser aus dem 17. Jahrhundert beschreiben. Anhand dieser Definition können dann beliebig viele Gebäude prozedural generiert werden, die je nach Regeln und Gruppen mehr oder weniger
unterschiedlich ausfallen.
Das folgende erste Unterkapitel 5.1 Regelbasierte System wird hauptsächlich das eigens eingeführte
regelbasierende Ersetzungssystem erklären. Darunter zählen unter anderem die Definition des Systems,
die Erläuterung der Syntax und die Anwendung von Transformationen. Nach diesem sehr theoretischen
Kapitel werden im Kapitel 5.2 Grammatiken verschiedene Grammatik-Arten beschrieben. Diese werden für die unterschiedlichen Bereiche des Gebäudes (Masse-Modell, Fassaden, Kanten) eingesetzt
und anhand eines durchgängigen Beispiels erläutert. Das Kapitel 5.3 Primitive beschäftigt sich mit
der genauen Definition der Primitive. D.h. welche Primitive stellt das System zum Bauen von Wänden
und Dächern zu Verfügung, welche Bereiche benutzen die verschiedenen Primitive, um Objekte zu
erzeugen, wie kann das Straight-Skeleton eingesetzt werden, um Dächer zu fertigen, usw. Die genaue
Funktionsweise von Gruppen sowie die Methoden zum Anfordern von Objekten aus der Gruppe werden
im Kapitel 5.4 Gruppen erklärt. Darauf folgend im Kapitel 5.5 Subdivison wird die Implementierung
der verschiedenen Split-Verfahren erläutert und schließlich im Kapitel 5.6 Umwelt die Realisierung und
Analyse der Umwelt.
38
5.1 Regelbasiertes System
Wie bereits erwähnt wurde, bildet die Basis ein Ersetzungssystem, das auf den in Kapitel 3 LindenmayerSysteme beschriebenen L-Systemen aufbaut. Genauer handelt es sich um ein verändertes parametrisches,
stochastisches, umgebungssensitives und kontextfreies System. Es wurde keine kontextsensitive
Grammatik implementiert, da für diese keine Anwendungsgebiet ersichtlich war und zudem schwer
verständlich und fehleranfällig sind. Selbstverständlich arbeitet das System stochastisch, d.h. den
verschiedenen Regeln können Wahrscheinlichkeiten zugewiesen werden, damit auf einfache Weise eine
sehr große Vielfalt erzeugt werden kann. Die Grammatik verwendet die Ansätze der parametrischen
L-Systeme, damit noch mehr Variationen erzeugt werden können und eine einfache parametrische
Kontrolle (s. Kapitel 1.2 Historischer Rückblick unter Vorteile eines prozeduralen Ansatzes) möglich ist.
Außerdem ist in vielen Fällen der Einsatz von Bedingungen unablässig. Weiterhin sind die entwickelten
Grammatiken umgebungssensitiv. Hier wurde allerdings lediglich die Grundidee, das Objekte Einfluss
durch ihre Umwelt erhalten, übernommen. Die Implementierung basiert auf komplett eigenständigen
Forschungen.
Aufgrund der stochastischen Auswahl der Regeln sowie einiger Zufallsfunktionen innerhalb der Regel
ist das System indeterminiert. Die eigentliche Definition der Grammatik wurde ebenfalls verändert und
für die Modellierung von Gebäuden optimiert. Die Definition erfolgt durch das 7-Tupel G = {V, K, F,
Σ, ω, P, π}, wobei gilt:
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
V ist eine endliche und nichtleere Menge, genannt Variablen
K ist eine endliche Menge, genannt Konstanten oder Definitionen
F ist eine endliche Menge, genannt Funktionen
Σ ist eine endliche Menge formaler Parameter
V K = Ø, V F = Ø, V Σ = Ø, K F = Ø, K Σ = Ø sowie F Σ = Ø müssen erfüllt sein.
Damit darf kein Symbol doppelt innerhalb der Mengen der Variablen, Funktionen, Kostanten
oder formalen Parametern existieren
ω ist das nichtleere Ausgangswort, auch Axiom genannt
ω V, das Ausgangswort ist genau ein Zeichen aus dem Alphabet der Variablen
P ist eine endliche Menge, genannt Produktionen
π ist eine endliche Menge, genannt Wahrscheinlichkeiten
π : P → [0, ∞) weißt jeder Regel aus P genau eine Wahrscheinlichkeit zwischen 0 und unendlich
zu (einschließlich 0)
Die schwerwiegendste Veränderung gegenüber der Grammatik eines L-Systems ist die Aufteilung des
Alphabets in Variablen und Funktionen. Die Menge der Variablen beinhaltet alle Zeichen des Alphabets,
die ausschließlich zur Expansion des Wortes verwendet werden und sonst über keinerlei Funktion
verfügen. Genauer heißt dies, dass Variablen als Predecessor einer Ersetzungsregel verwendet werden
dürfen, aber nie vom Interpreter interpretiert werden.
Funktionen bilden das Gegenteil von Variablen, d.h. Funktionen sind Symbole, die vom Interpreter ausgeführt werden müssen, aber keine Ersetzungsregel einleiten dürfen (dürfen nicht der Predecessor einer
Produktion sein). Funktionen dürfen selbstverständlich auf der rechten Seite einer Produktion stehen
und damit durch die Ersetzung von Variablen erzeugt werden.
Konstanten können als globale, formale Parameter angesehen werden, denen einmalig zu Beginn der
Grammatik ein Wert zugewiesen wird. Sie können dann als formaler Parameter innerhalb der Grammatik
an allen Stellen verwendet werden, z.B. als Argument einer Funktion oder als Wahrscheinlichkeit einer
Regel. Bei der Menge der formalen Parameter handelt es sich dagegen um lokale, formale Parameter.
Diese können, genau wie bei einem parametrischen L-System (s. Kapitel 3.5 Parametrische LindenmayerSysteme), nur innerhalb einer bestimmten Produktion eingesetzt werden.
39
Die Definition des Axioms wurde ebenfalls verändert. Während bei einem L-System das Axiom ein
beliebiges, nicht leeres Wort aus dem Alphabet sein durfte, besteht das Axiom nun nur noch aus einem
einzigen Zeichen aus der Menge der Variablen. Falls kein Axiom definiert wurde, bildet die erste Variable
das Axiom.
Durch die Aufspaltung des Alphabets muss die Notation der Produktionen ebenfalls neu angegeben
werden. Produktionen dürfen als Predecessor nur ein Element aus der Menge der Variablen enthalten,
sonst nichts. Die rechte Seite darf beliebig aus Variablen und Funktionen gebildet werden, wobei auch
das leere Wort erlaubt ist. D.h. die Produktion darf als Terminalzeichen dienen, in dem der Predecessor
durch das leere Wort ersetzt wird.
Alle hier beschriebenen und einige noch nicht beschriebenen Änderungen werden auf den nächsten
Seiten noch einmal genauer erklärt und anhand von Beispielen verdeutlicht.
5.1.1 Variablen
Variablen dienen ausschließlich zur Erzeugung von Regeln und damit zur Expansion des Wortes,
d.h. mit der Hilfe von Ersetzungsregeln können Variablen substituiert werden. Dieses Recht bleibt
ausschließlich Variablen vorbehalten, und weder Konstanten noch Funktionen dürfen durch eine Regel
ersetzt werden. Weiterhin führt der Interpreter keine Aktion aus, falls er eine Variable liest. Der Einsatz
von Variablen beschränkt sich damit ausschließlich auf die Erzeugung von Verzweigungen, Kapseln von
anderen Variablen und Funktionen, Bildung von Schleifen, etc.
Variablen können, wie in einem paramterischen L-System (siehe Kapitel 3.5 Parametrische LindenmayerSysteme), zu Modulen erweitert werden. Dazu kann jeder Variablen zusätzlich eine Liste formaler
Parameter angehängt werden. Die Schreibweise wurde vollständig übernommen und hat demnach die
Form v(s0, s1, s2, …, sn), wobei v V und s0 - sn Σ gilt. Innerhalb einer Regel (auf der rechten Seite einer
Produktion) darf der Parameter eines Moduls nicht ausschließlich durch reelle und formale Parameter
belegt werden, sondern durch beliebige Kombinationen von Konstanten, Funktionen, Zeichenketten1
oder reellen und formalen Parametern2, die jeweils durch einen arithmetischen oder logischen Ausdruck
getrennt werden.
Das Symbol bzw. der Name einer Variablen darf ein beliebiges und zusammenhängendes Wort aus
Buchstaben und Ziffern sein. Allerdings muss der Name eindeutig sein, d.h. das Wort darf nicht bereits als
Name einer anderen Variable, Konstante, Funktion oder eines anderen formalen Parameters existieren,
siehe Kapitel 5.1 Regelbasierte System unter (5).
5.1.2 Funktionen
Im Gegensatz zu Variablen dürfen Funktionen keine Regeln einleiten, d.h. sie sollen das Wort nicht
erzeugen, sondern sind lediglich Bestandteil des erzeugten Wortes. Dafür besitzen alle Funktionen eine
Aktion, die vom Interpreter ausgeführt wird, falls dieser das Symbol der Funktion liest. Solche Aktionen
können zum Beispiel Transformationen auslösen (Zustand der Schildkröte ändern), Wände und Dächer
erzeugen, trigonometrische Funktionen ausführen, Eigenschaften des Systems ändern, Zufallswerte
generieren, usw.
1
2
in der Datenverarbeitung auch „Strings“ genannt, zum Beispiel die Zeichenkette "Test".
reelle Parameter sind feste reelle Dezimalwerte, zum Beispiel die reelle Zahl 3.14159.
40
Funktionen weisen große Ähnlichkeiten mit den Modulen eines parametrischen L-Systems auf. Wie ein
Modul besteht eine Funktion aus einem Namen mit angehängten Parametern, auch Argumente genannt.
Die Notation wurde von den Modulen übernommen und hat demnach die Form f(s0, s1, s2, …, sn), wobei gilt; f F und s0-sn sind jeweils eine beliebige Kombination von formalen Parametern, Konstanten,
Funktionen, reellen Parametern oder Zeichenketten, jeweils durch einen arithmetischen oder logischen
Ausdruck getrennt. Damit sind Variablen die einzigen Symbole, die nicht Teil eines Argumentes sein
dürfen.
Zusätzlich dürfen Funktionen einen Rückgabewert liefern, wobei als zulässige Rückgabewerte nur reelle Zahlen oder Zeichenketten erlaubt sind. So liefert z.B. die Funktion rand(s0, s1) einen zufälligen
reellen Dezimalwert zwischen s0 und s1 zurück. Weiterhin dürfen Funktionen beliebig tief geschachtelt
werden und damit andere Funktionen als Argument enthalten. Ein Beispiel für eine verschachtelte Funktion könnte so aussehen: rand(rand(0,1), 2).
Eine detaillierte Liste aller bisherigen Funktionen ist im Anhang zu finden.
5.1.3 Konstanten
Konstanten bzw. Definitionen sind globale, formale Parameter. Global bedeutet, dass sie innerhalb der
gesamten Grammatik eingesetzt werden können und damit eine einfache parametrische Kontrolle ermöglichen. Jeder Konstanten wird, noch bevor die erste Iteration auf das Axiom ausgeführt wird, einmalig ein Wert zugewiesen. Mit Hilfe der Konstante kann schließlich innerhalb der Grammatik jederzeit
über diesen Wert verfügt werden. Zum Beispiel könnte eine Konstante das Argument einer Funktion
sein oder als Teil einer Bedingung dienen. Wichtig ist, dass der Wert einer Konstante nach der Zuweisung zu keinem Zeitpunkt mehr verändert werden kann. Eine Konstante k K wird folgendermaßen
deklariert und definiert:
k = σ;
Dabei gilt; σ ist eine beliebige Kombination von Funktionen, reellen Parametern, Zeichenketten oder
bereits vorher definierter Konstanten, auch hier jeweils durch einen arithmetischen oder logischen Ausdruck getrennt. Die Zuweisung eines Wertes erfolgt ähnlich wie in bekannten Programmiersprachen,
dazu stehen der Name der Konstanten links des Gleichheitszeichens und die eigentliche Zuweisung
rechts davon. Abgeschlossen wird die Zuweisung mit einem Semikolon. Im Laufe der Zuweisung erkennt jede Konstante automatisch, welchen Typ sie besitzt, also ob sie eine reelle Zahl oder Zeichenkette enthält. Die nachfolgenden Zeilen enthalten einige Beispiele für die Definition von Konstanten.
Test = "Test";
a = 0;
b = (0 + 1) ∙ 2;
c = rand(a, b);
Der Konstante Test wird eine Zeichenkette zugewiesen, den Konstanten a und b die reellen Zahlen 0
und 2. Nach dem diese Konstanten berechnet wurden, wird die Konstante c ermittelt. Diese erhält einen
zufälligen Wert zwischen a und b.
41
5.1.4 Produktionen
Bei einem stochastischen L-System werden alle Ersetzungsregeln getrennt angeben, auch wenn sie einen identischen Predecessor besitzen. D.h. eventuell muss die linke Seite einer Produktion mehrmals
definiert werden, obwohl es sich dabei immer um den gleichen Predecessor handelt. Dies kann schnell
zu Fehlern führen, in dem beispielsweise eine Änderung am Predecessor vorgenommen wurde, aber
vergessen wurde, diese Änderung bei allen zugehörigen Produktionen vorzunehmen. Ebenso entsteht
ein erhöhter Zeitaufwand bei der Definition und Änderungen von Produktionen. Und als letzter Kritikpunkt kann die fehlende Übersichtlichkeit aufgeführt werden. Dadurch dass viele verschiedene Regeln
für einen Predecessor angegeben werden, verliert der Nutzer schnell die Übersicht über all diese Regeln,
deren Wahrscheinlichkeiten, deren Bedingungen, etc.
Um dies zu umgehen, werden nun alle Regeln zusammen in einer Produktion angegeben. D.h. für einen
Predecessor darf nur noch eine einzige Produktion aufgestellt werden, innerhalb dieser werden alle
weiteren Regeln getrennt angeben. Dadurch verringert sich die Fehlerrate bei Änderungen, und die
Übersichtlichkeit über die Regeln und deren Wahrscheinlichkeiten erhöht sich.
Bisher war der Begriff Regel gleichgesetzt mit dem Begriff der Produktion. Da jetzt alle Regeln (bisher
Synonym zu „Produktion“) innerhalb einer einzigen Produktion (bisher Synonym zu „Regel“) angeben
werden, müssen die Begriffe neu definiert werden. Eine Produktion beschreibt ab jetzt die komplette
linke sowie rechte Seite, während eine Regel nur noch eine der vielen Ersetzungen bezeichnet, die
jeweils auf der rechten Seite einer Produktion stehen. Die genaue Form einer Produktion sieht dann
folgendermaßen aus:
φ→σ|υ|…;
Dabei ist φ V der Predecssor der Produktion und σ, υ sind zwei verschiedene Regeln, die jeweils aus
einer beliebigen Kombination von Variablen und Funktionen bestehen dürfen. Auch das leere Wort wird
als Regel erlaubt, d.h. wurde keine Variable oder Funktion für eine Regel angegeben, entspricht dies
dem leeren Wort. Die verschiedenen Regeln werden durch das Symbol | getrennt und alle innerhalb einer
Produktion angeben. Abgeschlossen wird eine Produktion durch ein Semikolon.
Es folgt ein kleines Beispiel, um die neue Schreibweise zu verdeutlichen. Gegeben ist die Menge der
Funktionen F = {T(x0)}, die Variablen V={F} und deren Produktionsmenge P = {F → F T(5) F | ;}. Da
für die Produktion zwei Regeln angegeben wurden, einmal F T(5) F und zum anderen das leere Wort,
wird eine der beiden Regeln zufällig ausgewählt. Deshalb stellt die nachfolgende Ersetzungssequenz
eine von vielen Möglichen dar. Genaueres zu Auswahl der Regeln kann im Kapitel 5.1.5 Wahrscheinlichkeiten nachgelesen werden.
1. Schritt
2. Schritt
3. Schritt
…
F
F T(5) F
T(5) F T(5) F
Zur Erinnerung, da keine Startvariable angeben wurde, ist das Axiom durch die erste Variable aus der
Menge aller Variablen gegeben, in diesem Beispiel die Variable F. Die Ersetzung folgt wie bei normalen
L-System „parallel“ und führt zu den aufgelisteten Schritten.
Weiterhin wird die Wahrscheinlichkeit einer Regel nicht mehr am Ende der Regel (durch einen Doppelpunkt getrennt) angeben, sondern ebenfalls auf der linken Seite einer Produktion, mehr dazu in Kapitel
5.1.5 Wahrscheinlichkeiten. Dasselbe gilt für die Bedingungen, die ebenfalls übersichtlich auf der linken
Seite einer Produktion angeben werden, siehe Kapitel 5.1.6 Bedingungen.
42
5.1.5 Wahrscheinlichkeiten
Die Menge der Wahrscheinlichkeiten π besitzt die gleiche Bedeutung wie in einem stochastischen LSystem. Die Wahrscheinlichkeit einer Regel definiert immer noch, mit welcher Wahrscheinlichkeit der
Zufallsgenerator die Regel unter allen passenden Regeln auswählt.
Anstatt die Wahrscheinlichkeit der jeweiligen Regel anzuhängen, werden nun alle Wahrscheinlichkeiten
übersichtlich auf der linken Seite einer Produktion angegeben. Dadurch können die Wahrscheinlichkeiten schnell angepasst werden und außerdem behält der Nutzer den Überblick über das Verhältnis der
Wahrscheinlichkeiten zueinander.
φ [p0, p1, …, pn] → σ0 | σ1 | … | σn;
Wie zu erkennen ist, werden die Wahrscheinlichkeiten aller Regeln innerhalb der eckigen Klammern
definiert. Die erste Wahrscheinlichkeit wird dann der ersten Regel zugeordnet, die zweite Wahrscheinlichkeit der zweiten Regel, usw.
Weiterhin können die Wahrscheinlichkeiten p0 - pn nicht nur durch reelle Zahlen bestimmt werden,
sondern durch Kombinationen von Konstanten, Funktionen, formale und reelle Parameter, auch hier
jeweils durch ein arithmetischen oder logischen Ausdruck getrennt. Da auch Funktionen oder formale
Parameter die Wahrscheinlichkeit einer Regel bestimmen dürfen und diese sich zur Laufzeit ändern
bzw. komplett zufällige Werte erhalten können (wir erinnern uns an die rand-Funktion), folgt, dass die
Wahrscheinlichkeiten nicht konstant sind. Dies kann einige Probleme mit sich bringen, die im nächsten
Absatz genauer erläutert werden.
In einem stochastischen L-System musste immer darauf geachtet werden, dass die Summe aller
Wahrscheinlichkeiten 1 ergibt, dies ist jetzt nicht mehr der Fall. Außerdem darf die Wahrscheinlichkeit
für eine Ersetzungsregel auch Werte größer 1 und den Wert 0 annehmen. Die Begründung für diese
Definition liegt in der Möglichkeit, dass sich Wahrscheinlichkeiten während der Laufzeit ändern
können. Dies sind drastische Änderungen, wodurch eine Menge Fragen aufkommen. Wie verhält sich
der Zufallsgenerator, wenn die Wahrscheinlichkeiten nicht die Summe von 1 erreichen? Was passiert
wenn die Summe größer als 1 wird? ...
Es existieren genau vier mögliche Fälle, die der Zufallsgenerator beachten muss. Entweder ergibt die
Summe aller Wahrscheinlichkeiten für einen gleichen Predecessor genau eine 0, oder sie ist größer 0 und
kleiner 1, oder sie ist genau 1, oder der letzte Fall tritt ein und die Summe ist sogar größer als 1. Eventuell
muss das System in mancher dieser Fälle eingreifen und automatisch Anpassungen vornehmen. Wie der
jeweilige Fall vom dem System behandelt wird, wird in der folgenden Liste festgelegt.
(1) Summe gleich 0
Alle Ersetzungsregeln besitzen jeweils eine Wahrscheinlichkeit von 0, daraus
folgt, dass keine Regel vom Zufallsgenerator ausgewählt wird und damit die zu
ersetzende Variable durch das leere Wort (also nichts) ersetzt wird.
(2) Summe kleiner 1 Eine oder mehrere Regeln besitzen Werte die kleiner 1 sind und auch in der
Summe nicht 1 erreichen. In diesem Fall werden alle Werte entsprechend ihrer
Verhältnisse zueinander so abgebildet, dass die Summe aller Wahrscheinlichkeiten nach der Abbildung genau 1 ergibt. Genauer gesagt, werden die Wahrscheinlichkeiten einfach mit der reziproken Summe multipliziert. Es sind z.B.
drei Regeln mit ihren Wahrscheinlichkeiten p0, p1 und p2 gegeben.
p0: 0.5
p1: 0.1
p2: 0.2
43
Werden die drei Wahrscheinlichkeiten addiert, ergibt dies eine Summe von
0.8 und liegt damit unter 1. Die reziproke Summe ist dann 1 / 0.8 = 1.25 und
nachdem die Wahrscheinlichkeiten mit dieser multipliziert werden, entstehen
die neuen Wahrscheinlichkeiten.
(3) Summe gleich 1
(4) Summe größer 1
p0: 0.625
p1: 0.125
p2: 0.250
Nun ergibt die Summe eine 1, und der Zufallsgenerator kann immer eine der
Regeln zufällig auswählen.
Der Zufallsgenerator kann normal arbeiten und bestimmt zufällig eine der
Ersetzungsregeln.
Eine Wahrscheinlichkeit oder alle Wahrscheinlichkeiten ergeben in der Summe
einen Wert, der größer als 1 ist. In diesem Fall bleiben die Wahrscheinlichkeiten
unverändert, d.h. es wird keine Veränderung wie in Fall (2) durchgeführt. Die
Regeln werden von vorne beginnend zufällig ausgewählt. Sobald die Summe
größer 1 wird, können die dahinter definierten Regeln vom Zufallsgenerator
nicht mehr ausgewählt werden. Daraus folgt, dass die Reihenfolge, in der die
Regeln angegeben werden, eine große Rolle spielt und zuerst definierte Regeln
bevorzugt behandelt werden.
Dies hat einen triftigen Grund. Indem die Wahrscheinlichkeiten unverändert
bleiben, können bestimmte Regeln vor Anderen erzwungen werden. Dazu ein
einfaches Beispiel. Es seien die folgenden drei Wahrscheinlichkeiten für eine
jeweilige Regel gegeben.
p0: 0.9
p1: 0.2
p2: 0.4
Da die erste Regel mit einer neunzigprozentigen Wahrscheinlichkeit ausgewählt
wird, kann die zweite Regel nur noch zu 10% ausgewählt werden, obwohl
diese eine Wahrscheinlichkeit von 20% besitzt. Die Wahrscheinlichkeit p2 wird
als Letztes angeben und hat momentan keine Chance, vom Zufallsgenerator
bestimmt zu werden. Darf p0 nicht mehr ausgeführt werden, z.B. auf Grund
einer nicht erfüllten Bedingung, fällt die Wahrscheinlichkeit p0 weg. Dies führt
dazu, dass mit den Wahrscheinlichkeiten p1 und p2 wie gehabt verfahren wird.
D.h. da deren Summe 0.6 ergibt und damit kleiner 1 ist, würde Fall (2) zur
Anwendung kommen.
Es bleibt nur noch zu klären, was mit Regeln passiert, für die keine Wahrscheinlichkeit angegeben wurde. Die Wahrscheinlichkeiten bleiben vorerst undefiniert und zwar so lange, bis der Zufallsgenerator eine
Regel auswählen möchte. Wenn dies geschieht, werden die Wahrscheinlichkeiten aller Regeln (deren
Bedingung erfüllt ist, siehe Kapitel 5.1.6 Bedingungen) addiert. Ist diese Summe größer oder gleich 1,
erhalten alle undefinierten Wahrscheinlichkeiten den Wert 0 und können damit nicht ausgewählt werden.
Liegt die Summe unter 1, wird der Rest gleichmäßig unter allen undefinierten Wahrscheinlichkeiten verteilt. Angenommen es existieren zu einer Variablen vier Regeln mit folgenden Wahrscheinlichkeiten.
44
p0: 0.5
p1: 0.1
p2: *
p3: *
Der Stern kennzeichnet die undefinierten Wahrscheinlichkeiten p2 und p3. Die Wahrscheinlichkeiten p0
und p1 ergeben in der Summe 0.6, der Rest von 0.4 bleibt undefiniert. Diese vierzig Prozent werden nun
unter p2 und p3 gleichmäßig aufgeteilt, und beide erhalten damit 0.2, also jeweils eine zwanzigprozentige
Chance vom Zufallsgenerator ausgewählt zu werden.
Durch die automatische Anpassung der Wahrscheinlichkeiten wird gewährleistet, dass der Zufallsgenerator
immer eine Regel auswählen kann, dass manche Regeln vor anderen erzwungen werden können und
die Wahrscheinlichkeiten ohne große Probleme dynamisch verändert werden dürfen. Damit kann das
System wie ein normales stochastisches L-System genutzt werden. Darüber hinaus wird dem Nutzer die
Möglichkeit geben, dynamisch die Wahrscheinlichkeiten zu ändern, ohne selbst allzu viel bedenken zu
müssen.
5.1.6 Bedingungen
Die in Kapitel 3.5 Parametrische Lindenmayer-Systeme eingeführten Bedingungen eines parametrischen
L-Systems werden ebenfalls entsprechend ihrer Funktionalität eingeführt. Allerdings verändert sich auch
hier die Art und Weise, in der die Bedingungen angegeben werden, dazu erweitert sich eine Produktion
wie folgt:
φ [p0, p1, …, pn] {c0, c1, …, cn} → σ0 | σ1 | … | σn;
φ, σ, υ und die Wahrscheinlichkeiten p0 - pn bleiben unverändert, hinzukommen die auf der linken
Seite der Produktion angegebenen Bedingungen c0 bis cn. Diese werden mit Hilfe einer öffnenden und
schließenden geschweiften Klammer gekennzeichnet. Genau wie bei den Wahrscheinlichkeiten wird
auch hier jeweils die erste Bedingung der ersten Regel zugeordnet, die zweite Bedingung der zweiten
Regel, usw. Ebenfalls wie bei den Wahrscheinlichkeiten ist die Definition der Bedingungen c0 – cn. Diese
können beliebig aus Funktionen, Konstanten, lokalen Parameter usw. definiert werden. Ist das Ergebnis
einer Bedingung 0, gilt diese als nicht erfüllt, und die entsprechende Regel kann nicht ausgewählt werden.
Ist die Bedingung ungleich 0, gilt diese als erfüllt, und die Regel wird anhand ihrer Wahrscheinlichkeit
vom Zufallsgenerator eventuell ausgewählt.
Falls eine Regel keine Bedingung zugeordnet wurde, gilt die Bedingung standardmäßig als erfüllt, und
die Regel besitzt immer die Chance, vom Zufallsgenerator ausgewählt zu werden.
5.1.7 Transformation
Wie in der Einleitung des Konzepts (s. Kapitel 5 Konzept) erwähnt wurde, werden die Gebäude aus
speziellen Primitiven (z.B. Würfel oder Zylinder) und vorgefertigten Modellen zusammengesetzt.
D.h. anstatt eine Linie zu zeichnen, wie es bei den bisherigen L-Systemen (s. Kapitel 3 LindenmayerSysteme) der Fall ist, werden nun vom dem System Körper und Objekte erzeugt. Damit ein Gebäude
durch die Kombination von mehreren Primitiven und Modellen erzeugt werden kann, müssen
verschiedene Transformationen auf die einzelnen Teile des Gebäudes durchführbar sein. Dies beinhaltet
eine Veränderung der Position, Ausrichtung und Größe des jeweiligen Objekts.
Der Zustand der „Schildkröte“ (s. Kapitel 3 Lindenmayer-Systeme) ist aus diesen Gründen zu einer
Transformation, bestehend aus einer dreidimensionalen Verschiebung, Rotation und Skalierung,
erweitert worden. Genauer gesagt, ist der Zustand nicht nur eine Transformation, sondern eine Sequenz
von Transformationen. Dabei kann jede Transformation (welche durch eine Matrix repräsentiert werden
kann) der Sequenz jeweils Informationen für eine Translation, Rotation und Skalierung erhalten. Die
Matrix einer Transformation ist so aufgebaut, dass zuerst die Skalierung ausgeführt wird, gefolgt von
45
der Rotation und zuletzt schließlich die Verschiebung. Daraus ergibt sich folgende Form für die Matrix
einer Transformation:
M=
[
(cos α cos β) sx (cos α sin β sin γ – sin α cos γ) sx (cos α sin β cos γ + sin α sin γ) sx 0
(sin α cos β) sy (sin α sin β sin γ + cos α cos γ) sy (sin α sin β cos γ - cos α sin γ) sy 0
- sin β sz
tx
cos β sin γ sz
ty
cos β cos γ sz
tz
0
1
]
Dabei beschreiben (sx, sy, sz) die Skalierung, (tx, ty, tz) die Verschiebung entlang der x-, y- und z-Achse
und die Winkel (α, β, γ) die Rotation. Der Zustand bzw. die aktuelle Transformations-Matrix kann innerhalb der Grammatik über bereits vordefinierte Funktionen verändert werden. Einige der möglichen
Funktionen werden hier aufgelistet, die restlichen sind im Anhang zu finden.
T(tx, ty, tz)
R(α, β, γ)
S(sx, sy, sz)
TR(rx, ry, rz)
Führe eine zusätzliche Verschiebung aus
Führe eine zusätzliche Rotation aus, dabei werden alle Winkel in Radien angegeben.
Ersetze die aktuelle Skalierung
Führe eine zusätzliche Verschiebung bzgl. der aktuellen Ausrichtung aus
Wie bereits beschrieben wurde, entspricht der Zustand einer Sequenz von Transformationen bzw. deren
Matrizen. Jede Funktion verändert immer nur die aktuelle Matrix. Eine neue Matrix kann durch die öffnende geschweifte Klammer eingeleitet werden. Mit der schließenden geschweiften Klammer wird die
aktuelle Matrix gelöscht, und die vorherige Matrix wieder zur aktuellen Matrix, ähnlich wie bei einem
Push- und Pop-Befehl.
Eine Sequenz kann zum Beispiel dazu dienen, eine Rotation nach der Translation auszuführen. Dazu
wird die Rotation in eine neue Matrix verschoben und damit erst später ausgeführt. Das folgende Beispiel verdeutlicht noch einmal die Funktionsweise der Transformations-Sequenz.
Main → T(10, 0, 0) S(3, 1, 2) R(0, 3.14/2, 0) Box();
Wie beschrieben, spielt es keine Rolle, in welcher Reihenfolge die Funktionen ausgeführt werden, da alle
Funktionen immer die aktuelle Transformation verändern und für diese eine feste Reihenfolge definiert
wurde. Die Reihenfolge lautet, zuerst die Skalierung, dann die Rotation und zum Schluss schließlich die
Verschiebung. Durch die Produktion entsteht der in Abb. 5.1.1 dargestellte Würfel. Dabei werden die
verschiedenen Teile der Transformation von links nach rechts innerhalb der Abbildung aufgelistet.
Abb. 5.1.1 Transformation eines Würfels
46
Wird durch eine geschweifte Klammer eine neue Transformation eingeleitet, so werden alle darauf folgenden Funktionen auf die neue Transformation ausgeführt.
Main → T(10, 0, 0) S(3, 1, 2) { R(0, 3.14/2, 0) Box() };
Die Verschiebung und Skalierung werden wie im ersten Beispiel bestimmt, d.h. sie werden auf die erste
Transformation innerhalb der Sequenz ausgeführt. Danach wird eine neue Transformation eingeleitet.
Alle Funktionen, die nun folgen, werden auf eine neue Transformation (Matrix) ausgeführt, in diesem
Fall eine Rotation um 90°. Daraus folgt, dass der Würfel zuerst durch die erste Transformation der
Sequenz verändert wird, dargestellt durch die ersten drei Zeichnungen der Abbildung 5.1.2. Nachdem
diese beendet ist, folgen alle weiteren Transformationen der Reihe nach, hier nur noch eine einzige
weitere. Diese führt eine Rotation aus, diesmal allerdings nach der Verschiebung, siehe viertes Bild der
Abb. 5.1.2.
Abb. 5.1.2 Transformation eines Würfels
Die Metapher der Schildkröte bzw. Turtle (s. Kapitel 3 Lindenmayer-Systeme) ist für die neue Art
der Transformation nicht mehr passend. Dies liegt z.B. daran, dass Objekte in eine Richtung bewegt
werden können, die nicht der aktuellen Ausrichtung entspricht. Deshalb wird hier eine neue und eher
Gebäuden entsprechende Metapher eingeführt. Dabei kann man sich den aktuellen Zustand wie einen
Kran vorstellen. Dieser kann, da er über einen frei schwenkbares Oberteil verfügt, in eine Richtung
fahren, während er in eine beliebige andere Richtung ausgerichtet ist. Wurde der Bestimmungsort
erreicht, platziert der Kran ein Stück des Gebäudes, das beliebig groß skaliert sein kann.
Die Steuerung über die Transformations-Sequenz ermöglicht eine viel gezieltere und vielseitigere
Veränderung des Zustands. Auf der anderen Seite sollte die Sequenz nicht zu groß ausfallen, weil
ansonsten die Übersicht verloren geht und die Grammatik schwer nachvollziehbar wird.
5.1.8 Verzweigungen
Wie in einem verzweigten L-System (siehe Kapitel 3.3 Verzweigende Lindenmayer-Systeme) verfügt das
neue System auch über einen Stack. Mit dessen Hilfe kann der aktuelle Zustand gespeichert und zu einem
späteren Zeitpunkt wieder geladen werden. Dafür werden ebenfalls die öffnende und schließende eckige
Klammer verwendet. Falls ein Push-Befehl ausgeführt werden soll, müssen alle Transformationen der
Sequenz auf dem Stack gespeichert werden. Und bei einem Pop-Befehl wird selbstverständlich wieder
die gesamte Sequenz geladen und vom Stack gelöscht.
Zusätzlich wird bei jeder Substitution einer Variablen durch eine Ersetzungsregel, automatisch ein
Push-Befehl zu Beginn der Ersetzung und ein Pop-Befehl am Ende der Ersetzung ausgeführt. Über die
Funktion AutoPP (siehe Anhang) kann dieser Vorgang aktiviert oder deaktiviert werden. D.h. sobald die
Funktion ausgeführt wird, aktiviert oder deaktiviert das System sofort das automatische Push und Pop
bei einer Ersetzung. Der neue Zustand gilt so lange, bis die Funktion erneut aufgerufen wird und der
Status sich damit ändert.
47
5.1.9 Ausführung
Zum Schluss dieses Unterkapitels noch ein paar Worte zur Ausführung der Grammatiken. Wie bei einem
Lindenmayer-System werden alle Variablen innerhalb einer Iteration „gleichzeitig“ ersetzt. Bei einem
umgebungssensitiven System lief der Interpreter bereits nach jeder Iteration einmal über das aktuelle
Wort. Dadurch haben die undefinierten Parameter der Anfrage-Module konkrete Werte erhalten, siehe
Kapitel 3.6 Umgebungssensitive und offene Lindenmayer-Systeme. Ein ähnliches Verhältnis liegt ebenfalls bei dem neu eingeführten System vor. Nur hier muss der Interpreter jedes Zeichen sofort interpretieren, d.h. während eines Ersetzungsschrittes, bei dem die Variablen durch eine passende Regel ersetzt
werden, müssen alle Funktionen sofort ausgeführt werden. Die Ausführung muss sofort stattfinden, da
es Funktionen gibt, die die Einstellungen des Systems verändern (z.B. die AutoPP-Funktion) und damit
die fortlaufende Ersetzung beeinflussen können. Außerdem existieren spezielle Funktionen die Schleifen, Bedingungen oder Partitionen einleiten (z.B. die Funktionen SubDiv und Part), die ebenfalls eine
sofortige Interpretation der Funktionen voraussetzen.
48
5.2 Grammatiken
Wie in der Einleitung des Konzepts (s. Kapitel 5. Konzept) beschrieben wurde, sollen für unterschiedliche
Gebäudebereiche verschiedene Grammatiken zum Einsatz kommen. Zum einen kann dadurch die
Verständlichkeit der einzelnen Grammatiken gesteigert werden, da das gesamte Gebäude nicht vollständig
innerhalb einer einzigen Grammatik formuliert werden muss. Und zum anderen sind die verschiedenen
Grammatiken beliebig austauschbar, wodurch wiederum eine große Wiederverwendbarkeit entsteht. Eine
einmal aufgestellte Grammatik kann so bei einer Vielzahl von Gebäudetypen zum Einsatz kommen.
Insgesamt wurden eigens vier unterschiedliche Grammatiken entwickelt. Die sogenannte Mass-Grammar
ist die zuerst ausgeführte Grammatik1. Der Begriff Mass steht dabei für das Masse-Modell [MWH+06]
bzw. Grundmodell des Gebäudes und Grammar ist der englische Begriff für Grammatik. Die MassGrammar ist die Startgrammatik, erstellt das grundlegende Modell und ruft dann für die verschiedenen
Wände und Kanten des Masse-Modells weitere Grammatiken auf. D.h. zusätzlich zu der bereits
erwähnten Mass-Grammar existieren noch drei weitere Grammatiken. Bei diesen handelt es sich um
die Facade-Grammar, Border-Grammar und Profile-Grammar. Mass-, Border- und Facade-Grammar
besitzen die gleichen Funktionen, arbeiten allerdings alle in einem anderen Raum (Koordinatensystem).
Die Profile-Grammar besitzt einen anderen Funktionssatz und arbeitet ebenfalls in einem anderen, sehr
abstrakten Raum.
(1) Mass-Grammar
(2) Facade-Grammar
(3) Border-Grammar
(4) Profile-Grammar
Die Grammatik ist für die Erstellung des Grundmodells (Masse-Modells) zuständig. Durch die Regeln und Funktionen der Grammatik werden zufällige
Grundmodelle eines Gebäudetyps erstellt. Dies können beispielsweise die
gebäudetypischen I-, L-, T-, H- oder U-Formen sein.
Facade ist der englische Begriff für Fassade. Mit Hilfe dieser Grammatik
sollen Regeln aufgestellt werden, die eine zufällige Fassade erzeugen. Dazu
gehören z.B. Fenster, Türen, Fachwerkmuster, etc. Die Facade-Grammar behandelt nicht ausschließlich die Flächen von Hauswänden, sondern auch die
Flächen des Dachs und erzeugt an diesen z.B. Schornsteine oder Dachgauben.
Die Border-Grammar oder auch Edge-Grammar genannt wird an allen Kanten des Masse-Modells ausgeführt. Zu diesen gehören die Kanten der Hauswände sowie die des Daches. Dort erzeugt die Grammatik anhand ihrer Regelbasis zum Beispiel eine Regenrinne, die an der Traufe des Dachs entlang
läuft. Oder einen Wetterhahn, der meistens zufällig auf dem Dachfirst angebracht wird.
Der Begriff Profile bedeutet ins Deutsch übersetzt „Profil“ oder „Seitenansicht“. Die Grammatik generiert Profile von Wand- und Dachflächen und
aus diesen die Geometrie des Masse-Modells. Damit können anhand der Regeln zum Beispiel neben den üblichen Walmdächern auch Mansarddächer
geformt werden.
Auf den nächsten Seiten werden alle aufgelisteten Grammatiken genauer erklärt, außerdem wird
anhand eines durchgängigen Beispiels ein sehr einfaches Haus erzeugt. Zum einen wird dadurch der
Unterschied zwischen den einzelnen Grammatiken klarer, und zum anderen wird das Verständnis für die
Anwendbarkeit der Grammatiken erhöht.
1
auch Startgrammatik oder Initialgrammatik genannt
49
5.2.1 Mass-Grammar
Die Mass-Grammar ist für die Erzeugung einer grundlegenden Gebäudestruktur zuständig, u. a. zählen
dazu die einzelnen Wände und Dächer des Gebäudes. Diese werden aus sogenannten Primitiven erzeugt,
Genaueres zu Primitiven kann im Kapitel 5.3 Primitive nachgelesen werden. Während die Grammatik
den Haupttrakt, Nebentrakt, Türme oder sonstige Teile des Gebäudes aus Primitiven zusammenbaut,
kann sie den einzelnen Teilen weitere Grammatiken zuteilen. Diese erzeugen dann die Fenster, Türen
und andere Details des Gebäudes. Die von der Mass-Grammar anwendbaren Funktionen werden im
Anhang aufgelistet. Zusätzlich besitzt jede Grammatik spezielle bereits vordefinierte Konstanten, diese
werden ebenfalls im Anhang beschrieben.
5.2.1.1 Raum
Zuerst muss geklärt werden, in welchen Raum die Mass-Grammar fungiert. D.h. wo werden bzw. dürfen
überhaupt die Primitive innerhalb der Welt platziert werden. Jedes Gebäude besitzt zu Beginn einen
rechteckigen Grundriss, quasi das Grundstück des Gebäudes. Dieses Grundstück besitzt eine Länge, eine
Breite und ein Koordinatensystem, welches die Position und Ausrichtung des Grundstücks bestimmt.
Der Ursprung des Koordinatensystems, welches vergleichbar mit dem Object-Space eines Objektes ist,
befindet sich in der Mitte des Grundstücks, siehe Abb. 5.2.1. Die Ausrichtung der Achsen entspricht
genau den World-Space Achsen, d.h.
die x-Achse verläuft nach rechts, die zAchse nach hinten und die y-Achse steht
senkrecht zu beiden und verläuft direkt
nach oben, wodurch ein linkshändiges
und orthogonales Koordinatensystem
entsteht. Alle Transformationen, die
innerhalb der Grammatik aufgerufen
werden, finden in dem oben beschriebenen
Raum statt. Die Länge und Breite des
Grundstücks kann über vordefinierte
Abb. 5.2.1 Koordinatensystem der Mass-Grammar
Konstanten abgefragt werden, s. Anhang.
5.2.1.2 Anwendung
Am einfachsten lässt sich die Grammatik anhand einer direkten Anwendung erklären. Die Grammatik
aus Abb. 5.2.2 formuliert die Mass-Grammar eines Gebäudetyps. Die Grammatik soll zwei Stockwerke
und ein Dach erzeugen. Dazu verwendet die Grammatik zwei Primitive (Würfel) und ein Dach-Primitiv,
s. Kapitel 5.3 Primitive. Die Primitive bekommen während der Ausführung weitere Grammatiken
zugeteilt, diese führt jedes Primitiv nach Berechnung der Mass-Grammar aus.
cWidth = rand(20, 25);
cDepth = rand(10, 15);
cFloor = 8;
//Axiom der Mass-Grammar
Main -> S(cWidth, cFloor, cDepth) TY(-2*cFloor) Floor(0);
//Die Produktion erzeugt mehrere Stockwerke und am Ende ein Dach
Floor(nFloor) [1, 1] {nFloor < 2, 1} ->
TY(2*cFloor) Box("PWall", "FWall", "") Floor(nFloor+1) |
RoofBox("PRoof", "", "BRoof");
Abb. 5.2.2 Mass-Grammar
50
Da kein Axiom angegeben wurde, bildet die erste Variable das Axiom. Dies ist in der angegebenen
Grammatik die Variable Main. Bevor jedoch die erste Iteration auf das Axiom ausgeführt wird, werden
einmalig die drei Konstanten berechnet. Dabei erhalten die Konstanten cWidth und cDepth einen zufälligen Wert und die Konstante cFloor einen festen Wert von 8.
Nachdem die Konstanten ihre Werte erhalten haben, wird die Produktion für das Axiom aufgerufen.
Die Regel der Produktion führt zuerst eine Skalierung aus, d.h. die aktuelle Transformation wird um
die Konstanten cWidth, cFloor und cDepth skaliert. Nach der Skalierung, welche die Breite, Tiefe und
Höhe eines Stockwerks bestimmt, wird die Produktion des Moduls Floor aufgerufen.
Das Modul soll nun einige Stockwerke erstellen und am Ende schließlich ein Dach erzeugen. Dafür
besitzt die Produktion zwei Regeln. Die Erste zum Erzeugen der Stockwerke und die Zweite zum Erstellen des Dachs. Erreicht wird die Unterteilung durch das Erzwingen der ersten Regel, solange deren
Bedingung erfüllt bleibt. Sowohl der ersten als auch der zweiten Regel wurde dafür jeweils eine Wahrscheinlichkeit von 1 zugeteilt. Die Bedingung nFloor < 2 bestimmt damit die Anzahl der Stockwerke.
Steigt der formale Parameter nFloor auf 2, kann die Bedingung nicht weiter erfüllt werden und es wird
stattdessen die zweite Regel ausgeführt. Durch diese wird ein Dach erzeugt und die Grammatik terminiert, weil keine weitere Variable existiert.
Zum Erzeugen der Stockwerke wird die Funktion Box verwendet. Die Funktion erzeugt ein Primitiv in
Form eines Würfels und ruft für die Flächen und Kanten des Würfels jeweils eine Facade- bzw. BorderGrammar auf. Bevor die Facade- und Border-Grammar ausgeführt werden, wird eine Profile-Grammar
erstellt und damit die Geometrie des Primitiv’s bestimmt, s. Kapitel 5.2.4 Profile-Grammar. Die Argumente der Funktion geben dabei die Namen der aufzurufenden Grammatik an. Das erste Argument
bestimmt die Profile-Grammar, das zweite Argument die Facade-Grammar und das dritte Argument die
Border-Grammar. Die Funktion aus dem Beispiel führt als Profile-Grammar die Grammatik "PWall"
aus, usw. Da für die Border-Grammar eine leere Zeichenkette gesetzt wurde, wird für die zwei erzeugten Würfel keine Border-Grammar ausgeführt.
Das Dach wird ebenfalls über eine Funktion erstellt, anstatt der Funktion Box wird hier die Funktion
RoofBox verwendet. Genaueres über die Argumente der Funktion kann im Anhang nachgelesen werden. Das erste Argument bestimmt auch hier welche Profile-Grammar für das Dach ausgeführt werden
soll, in diesem Fall die Grammatik "PRoof".
Auf den nächsten Seiten wird das angefangene
Beispiel fortgeführt. D.h. bisher wurden zwei
Würfel und ein Dach erzeugt, siehe Abb. 5.2.3.
Die beiden Würfel sind momentan nicht zu unterscheiden, da sie sich direkt übereinander befinden und keinen Schnitt erzeugen. Den beiden
Würfeln wurden jeweils eine Profile- und Facade-Grammar zugeordnet, diese werden nun nach
Berechnung des Masse-Modells ausgeführt.
Das Dach ruft ebenfalls eine Profile-Grammar
auf und zusätzlich noch eine zugeteilte BorderGrammar.
Abb. 5.2.3 Ergebnis der Mass-Grammar
51
5.2.2 Facade-Grammar
Die Facade-Grammar ist für die Erstellung der Objekte zuständig, die entlang der einzelnen Wand- und
Dachflächen angebracht werden. Oder anders gesagt, die Objekte die relativ zur jeweiligen Fassade
oder Dachfläche platziert werden sollen. Zu diesen Objekten gehören beispielsweise Fenster, Türen,
Dachgauben, usw. Eine Facade-Grammar kann nur den speziellen Primitiven sowie Dach-Primitiven
zugewiesen werden und wird aus diesem Grund auch nur an deren Flächen ausgeführt. Dabei wird für
jede Fläche eines Primitiv’s bzw. Dach-Primitiv’s die Facade-Grammar jeweils einmal aufgerufen, falls
dem Primitiv eine Grammatik zugewiesen wurde.
5.2.2.1 Raum
Auch hier muss zuerst geklärt werden, in welchen Raum und Bereich die Grammatik arbeitet.
Im Gegensatz zu Mass-Grammar befindet sich
die Position des Koordinatensystems nicht in der
Mitte des Gebäudegrundstücks, und die Ausrichtung entspricht nicht der des Weltsystems.
Der Ursprung des Systems1 liegt immer an der
linken unteren Ecke der jeweiligen Fläche/
Fassade. Die x-Achse verläuft rechts entlang
der Fläche und die y-Achse nach oben entlang
der Fläche. Die z-Achse steht senkrecht zur xund y-Achse und bildet die inverse Normale
der Fläche, da es sich um ein linkshändiges
und orthogonales System handelt. Der
Wirkungsbereich, in dem eine Facade-Grammar
arbeiten darf, wird ebenfalls durch ein Rechteck
bestimmt, das sich relativ zur Fassade befindet.
Abb. 5.2.4 Mögliche Koordinatensysteme der
Die Abb. 5.2.4 verdeutlicht noch einmal bildlich
Facade-Grammar
die Lage und Ausrichtung einiger FassadenKoordinatensysteme und deren Bereiche.
D.h. alle Operationen und Transformation, die innerhalb der Grammatik ausgeführt werden, finden in
dem jeweiligen oben beschriebenen System statt. Wird zum Beispiel eine Translation in x-Richtung
ausgeführt, verläuft diese direkt nach rechts entlang der Fassade. Die Verschiebung wird also relativ
zur Fassade ausgeführt. Dies ermöglicht eine einfache Modellierung und Aufstellung der Grammatiken.
Die Fassaden der Dachflächen sind nicht so eindeutig zu bestimmen, da jede Fassade eine rechteckige
Fläche besitzen muss. Die genaue Ermittlung der Fassaden für Primitive und Dach-Primitive wird im
Kapitel 5.3 Primitive erklärt.
5.2.2.2 Anwendung
Zur Erinnerung, zu Beginn des Beispiels wurden in der Mass-Grammar zwei Stockwerke (Würfel) und
ein passendes Dach generiert. Den beiden Würfeln wurde jeweils ein Facade-Grammar zugeordnet, diese wird nun für jede Fläche der beiden Würfel jeweils einmal ausgeführt. Da die beiden Würfel unten
und oben offen sind (s. Kapitel 5.3 Primitive), wird insgesamt achtmal die Facade-Grammar aufgerufen.
Die Abb. 5.2.5 formuliert die Grammatik "FWall", die den beiden Würfeln zugewiesen wurde. Mit Hilfe der Grammatik sollen drei Fenster auf jeder Seite eines Stockwerks platziert werden. Dabei werden
die Fenster nicht durch Primitive gebildet, sondern durch bereits vormodellierte 3D-Modelle.
1
Der Raum einer Fassade wird auch als Facade-Space bezeichnet.
52
Main ->
TY(HEIGHT/3)
T(WIDTH/4) ModelGroup("Window")
T(WIDTH/4) ModelGroup("Window")
T(WIDTH/4) ModelGroup("Window");
Abb. 5.2.5 Facade-Grammar "FWall"
Die Variable Main ist die einzige Variable und damit das Axiom. Die Produktion verschiebt durch die
TY Funktion alle Fenster um ein Drittel der Fassadenhöhe nach oben. HEIGHT und WIDTH sind zwei
von dem System vordefinierte Konstanten. Die Konstante HEIGHT gibt dabei die Höhe der aktuellen
Fassade an und die Konstante WIDTH die Breite der Fassade. Durch die beiden Konstanten lässt sich
verhindern, dass Objekte außerhalb der Fassade platziert werden. Die Regel erzeugt dreimal in gleichmäßigen Abständen jeweils ein Fenster. Die dafür verwendete Funktion ModelGroup wird im Kapitel
5.4 Gruppen genauer vorgestellt. Kurz gesagt, kann mit Hilfe der Funktion ein Modell geladen und
bzgl. der aktuellen Transformations-Sequenz platziert werden.
In diesem einfachen Beispiel wurde die Grammatik nur für die Wände eines Würfels aufgerufen. Allerdings könnte dieselbe Grammatik auch für die Flächen eines Daches zum Einsatz kommen. Deshalb
muss innerhalb der Grammatik die Möglichkeit existieren, festzustellen, welcher Typ von Fassade gerade generiert wird. Zu diesem Zweck wurde die vordefinierte Konstante TYPE eingeführt. Dieser wird
eine spezielle Zeichenkette zugewiesen, die den aktuellen Typ der Fassade beschreibt. Mögliche Werte
die TYPE annehmen kann, sind entweder "Wall", "Roof" oder "Gable". Besitzt die Konstante den Wert
"Wall", so wird die Grammatik zum Erstellen einer Wand ausgeführt, d.h. die Fassade eines normalen
Primitiv’s. Enthält TYPE die Zeichenkette "Roof", dann soll die Grammatik die Fassade einer Walmfläche erzeugen und bei dem Wert "Gable" die Fassade einer Giebelseite. Die Konstante kann nun beispielsweise als Teil einer Bedingung eingesetzt werden und damit entscheiden, welche Ersetzungsregel
ausgeführt wird.
In Abbildung 5.2.6 ist eines der möglichen Ergebnisse zu sehen, das durch die Mass-Grammar aus Kapitel 5.2.1.2 in Verbindung mit der in
diesem Kapitel beschriebenen Facade-Grammar
erstellt wurde. Für jede Seite eines Stockwerks
wurden jeweils drei Fenster erzeugt. Ohne eine
spezielle Transformation ausführen zu müssen,
wurden die Fenster relativ zu jeweiligen Fassade
platziert.
Abb. 5.2.6 Ergebnis der Facade-Grammar
53
5.2.3 Border-Grammar
Bisher wurde das Masse-Modell samt Dach und Wänden erzeugt und deren Fassaden mit Fenster belegt.
Dafür kamen die Mass- sowie die Facade-Grammar zum Einsatz. Viele Häuser weisen noch spezielle
Objekte und Auffälligkeiten an den Ecken der Hauswände oder den Kanten des Dachs auf. Mit einer
Border-Grammar können diese an einer Kante verlaufenden Objekte, mit einfachen Mitteln realisiert
werden. Zusätzlich zu jeder Fläche eines Primitivs, bei der eine Facade-Grammar ausgeführt wurde,
wird nun für jede Kanten eines Primitivs eine Border-Grammar aufgerufen.
5.2.3.1 Raum
Im Gegensatz zur Mass- und Facade-Grammar besitzt
eine Kante keine rechteckige Fläche, weshalb bei der
Ermittlung des Raums1 die benachbarten Flächen mitberücksichtigt werden müssen. Der Raum ist außerdem
abhängig von Typ der Kante. Der Typ einer Kante ist
durch die Lage der Kante definiert, bildet die Kante z.B.
den First eines Dachs, den Teil einer Traufe, etc.
Trotz der unterschiedlichen Typen sind zwei ­Definitionen
bei allen Räumen gleich. Zum einen verläuft die x­Achse des Koordinatensystems immer genau entlang
der Kante. Und zum anderen befindet sich der Ursprung
des Systems immer im Startpunkt der jeweiligen Kante.
Die y-Achse und damit auch die z-Achse sind abhängig
vom jeweiligen Typ der Kante. Sie bilden aber immer ein
orthogonales, linkshändiges System. Abbildung 5.2.7
Abb. 5.2.7 Mögliche Koordinatensysteme
zeigt einige der vielen möglichen Koordinatensysteme
der Border-Grammar
der Kanten. Auch hier wird die x-Achse in Grün, die
y-Achse in Blau und die z-Achse in Rot dargestellt. Eine genaue Beschreibung aller Kanten und deren
Koordinatensysteme werden im Kapitel 5.3 Primitive beschrieben.
5.2.3.2 Anwendung
Sowohl eine Facade-Grammar als auch eine Border-Grammar werden immer einem kompletten Primitiv
zugewiesen, d.h. alle Flächen und Kanten erhalten dieselbe Grammatik. Da insbesondere im Bereich des
Dachs viele verschiedene Kanten-Arten existieren, muss die Grammatik diese unterscheiden können.
Innerhalb der Grammatik kann der Typ einer Kante über die vordefinierte Konstante TYPE abgefragt
werden, wie bereits bei der Facade-Grammar. Die Konstante enthält eine der folgenden Zeichenketten:
"Border", "Eave", "GableEave", "GableBoard", "Groin", "Coving" oder "Ridge".
Enthält die Konstante die Zeichenkette "Border", so wurde die Grammatik einem Primitiv zugeordnet,
welches gerade die Ecke einer Wand berechnet. Alle restlichen Typen beschreiben die Kanten eines
Dach-Primitivs. Falls TYPE den Wert "Eave" enthält, entspricht die aktuelle Kante einer Traufe, bei
"GableEave" einer Traufe die an einer Giebelseite verläuft, "GableBoard" einem Ortgang, "Groin"
einem Grat, "Coving" einer Kehle und bei "Ridge" einem First. Die genaue Erklärung der Begriffe
wurde im Grundlagenkapitel 2.2 Dächer erläutert.
1
Der Raum einer Kante wird auch als Border-Space bezeichnet.
54
Zurück zum Beispiel. Die Grammatik "BRoof" aus Abb. 5.2.8 wird für alle Kanten des Dachs ausgeführt. Mit Hilfe der Grammatik soll ein Schornstein in der Nähe des Dachfirsts generiert werden,
d.h. die Grammatik muss den Typ der Kante erkennen und nur im Falle eines Firsts auch wirklich den
Schornstein erzeugen.
cDis = rand(-5, 5);
Main { TYPE == "Ridge" } ->
T(rand(0, WIDTH), -abs(cDis), cDis) ModelGroup("Chimney");
Abb. 5.2.8 Border-Grammar "BRoof"
Die Border-Grammar "BRoof", besitzt nur eine Variable und für diese eine Produktion. Das größte
Augenmerk liegt auf der Bedingung. Ohne die Bedingung würde die Grammatik für alle Kanten des
Dachs (inklusive Traufe, Kehle, Grat, usw.) ausgeführt werden und damit mehrere Schornsteine erzeugen. Weil die Bedingung den Typ abfragt und sie nur erfüllt ist, wenn der Typ die Zeichenkette "Ridge"
enthält, wird die Regel nur für den First ausgeführt.
Wird die Ersetzungsregel aufgerufen, verschiebt sie zuerst die Position zufällig entlang der x-Achse
(Kante) und zwar zwischen dem Start und dem Ende der Kante. Außerdem wird eine Verschiebung
senkrecht zur Kante vorgenommen, diese wird zufällig ermittelt, um noch mehr Variationen zu erzeugen. Über die Funktion ModelGroup wird das einfache Modell eines Schornsteins geladen und auf dem
Dach platziert.
Abbildung 5.2.9 bildet ein mögliches Ergebnis
der bisherigen Grammatiken ab. Zu diesen zählen
die in Kapitel 5.2.1.2 erklärte Mass-Grammar, die
in Kapitel 5.2.2.2 erklärte Facade-Grammar und
die in diesem Kapitel erläuterte Border-Grammar. Letzteres erzeugt den in der Abbildung dargestellten Schornstein.
Abb. 5.2.9 Ergebnis der Border-Grammar
55
5.2.4 Profile-Grammar
Die letzte der vier Grammatik-Arten ist die so genannte Profile-Grammar. Diese soll zu jedem Primitiv
und Dach-Primitiv eine variable Geometrie erzeugen. Wände können so zufällig Säulen oder Querbalken erhalten und Dächer können zum Beispiel zwischen einem Walmdach und einem Mansarddach
variieren.
Die Idee beruht darauf, dass ein zweidimensionaler
Linienzug die Struktur einer Wand bzw. eines Dachs
repräsentiert. Dazu stellt man sich vor, dass man die
jeweilige Wand von der Seite anschaut und demnach
das Profil der Wand sieht. Nun können mit Hilfe der
Grammatik zusammenhängende Punkte erzeugt
werden, also ein Polygon, das das Profil der Wände
bzw. der Dachflächen formt. Zum Verständnis wird in
Abb. 5.2.10 (a) ein fertiges Polygon dargestellt. Dieses
wurde durch eine Profile-Grammar erzeugt, und aus
diesem wurde die Geometrie der Wand von Abb. 5.2.10
(b) generiert.
Neben vertikalen Profilen können auch horizontale
Profile erzeugt werden. Ein Beispiel für ein horizontales
Profil wird in Abb. 5.2.11 dargestellt. Oder aber, es wird
ein vertikales sowie ein horizontales Profil berechnet,
und beide werden nachträglich kombiniert. Abbildung
5.2.12 zeigt eine Kombination der beiden Profile aus
den Abbildungen 5.2.10 und 5.2.11. Dabei wird ein
vertikales Profil lediglich einmal für das gesamte
Primitiv erstellt, während ein horizontales Profil jeweils
einmal für jede Fläche eines Primitivs erzeugt wird.
Zusätzlich zur variablen Erzeugung der Geometrie eines
Primitivs, ist die Profile-Grammar ebenfalls für dessen
Texturierung zuständig. D.h. mit Hilfe der ProfileGrammar können zufällige Texturen geladen und auf
die einzelnen Abschnitte des Profils gelegt werden.
Abb. 5.2.10 Vertikale Profile-Grammar
Abb. 5.2.11 Horizontale Profile-Grammar
Damit aus einem Polygon später passende Flächen
generiert werden können, muss die Profile-Grammar
mindestens zwei vertikale Punkte erzeugen. Zusätzlich
können zwei bis beliebig viele horizontale Punkte erzeugt werden, diese sind aber nicht notwendig.
Eine Profile-Grammar, die das Profil eines Dachs ermittelt, unterliegt einigen Einschränkungen. Zum einen
können für Dächer lediglich vertikale Profile erstellt
werden, und zum anderen kann das erzeugte Profil nur
dann verwendet werden, wenn das Dach nur einen einzigen durchgängigen First besitzt.
Abb. 5.2.12 Kombination aus horizontaler und
vertikaler Profile-Grammar
56
5.2.4.1 Raum
Wie bereits erwähnt wurde, arbeitet die Profile-Grammar in einem sehr abstrakten Raum. Die x-Achse
gibt dabei eine Verschiebung senkrecht zur Fläche an. Diese Verschiebung wird auf der späteren Wandbzw. Dachfläche entlang der Normalen durchgeführt. Handelt es sich um ein vertikales Profil, definiert
der y-Wert eines Profil-Punktes die Höhe, in der ein Punkt erzeugt wird. Im Gegensatz zum horizontalen
Profil, wo die Breite über den y-Wert definiert wird. Da ein Profil zweidimensional angegeben wird,
besitzt der Raum einer Profil-Grammar keine z-Achse.
5.2.4.2 Texturierung
Sowohl den vertikalen als auch den horizontalen Punkten kann eine Textur zugewiesen werden. Dies
geschieht mit Hilfe der TextureGroup-Funktion. Im Kapitel 5.4 Gruppen kann mehr über Gruppen und
speziell über Textur-Gruppen nachgelesen werden. Sobald die Funktion aufgerufen wird, setzt diese
eine zufällige Textur aus der Gruppe als aktuelle Textur. Alle Punkte, die nach dem Setzen der Textur erzeugt werden, bekommen die aktuelle Textur zugewiesen. Genauer gesagt, die aus dem Punkt erzeugte
Fläche bekommt die Textur zugewiesen.
Soll eine Fläche keine Textur verwenden, kann mit Hilfe der Reset-Funktion die aktuelle Textur zurückgesetzt werden. Alle Punkte, die nach der Funktion aufgerufen werden, erhalten keine Textur zugewiesen. Es sei denn, es wurde erneut die TextureGroup-Funktion aufgerufen.
Welche Textur wird bei der Kombination eines vertikalen und horizontalen Profils verwendet? In diesen
Fällen gilt immer, dass die Texturen von horizontalen Punkten vorrangig behandelt werden. Demnach
wird immer die Textur eines horizontalen Punktes verwendet, um eine Fläche zu texturieren, aber nur,
falls dem horizontalen Punkt eine Textur zugewiesen wurde. Wurde weder einem vertikalen noch einem
horizontal Punkt eine Textur zugeteilt, bleibt die Fläche untexturiert.
5.2.4.3 Anwendung
Die Profile-Grammar für die Wände und Dächer sind die letzten Grammatiken, die für das durchgängige
Beispiel benötigt werden. Die Wände sollen jeweils an der linken und rechten Seite eine Säule erhalten
und am Boden jedes Stockwerks einen kleinen Vorsprung bilden. Das Dach dagegen soll leicht nach innen verlaufen, d.h. das Anfangsstück des Dachs verläuft flacher als das Endstück. Es handelt sich quasi
um ein inverses Mansarddach, bei dem normalerweise das Dach zuerst steil beginnt und dann nach oben
hin flacher wird.
Zuerst folgt die Grammatik "PRoof" (s. Abb. 5.2.13) zum Berechnen des vertikalen Dachprofils. Wie
bereits erwähnt wurde, können Dächer nur vertikale Profile erstellen.
d = rand(0.10*HEIGHT, 0.15*HEIGHT);
Main ->
TextureGroup("Roof")
T( 0, 0.0*HEIGHT) PointV()
T(-d, 0.4*HEIGHT) PointV()
T( d, 0.6*HEIGHT) PointV();
Abb. 5.2.13 Profile-Grammar "PRoof"
57
Innerhalb einer Profile-Grammar existieren
drei wichtige Funktionen: die Funktion
TextureGroup und die Funktion PointV bzw.
PointH. Die Funktion TextureGroup lädt eine
zufällige Textur aus einer Gruppe und setzt
diese als aktuelle Textur. Alle Punkte, die
nach dem Setzen der Textur erzeugt werden,
bekommen die aktuelle Textur zugewiesen.
Die Funktion PointV bzw. PointH erzeugt
einen neuen Punkt des Profil-Polygons.
Dabei erzeugt die Funktion PointV einen
neuen vertikalen Punkt und die Funktion
PointH einen neuen horizontalen Punkt.
Jeder weitere erstellte Punkt wird immer mit
Abb. 5.2.14 (a) Vertikales Profil des Dachs und
dem vorherigen Punkt verbunden und bildet
(b) Profil bzgl. der Dachfläche
später eine Fläche. Auf dieser Fläche wird die
Textur gelegt, die zum Zeitpunkt der Erstellung des Punktes aktuell war. Die Grammatik aus Abb.
5.2.13 generiert drei Punkte. Der erste Punkt direkt beim Start des Dachs, der zweite Punkt bei vierzig
Prozent der Dachhöhe und den letzten Punkt genau am Ende des Dachs. Der mittlere Punkt erhält eine
zufällige Verschiebung zwischen 10% und 15% der Dachhöhe. Abbildung 5.2.14 (a) verdeutlich noch
einmal das aus der Grammatik erzeugte vertikale Profile. Wird dieses Profil relativ zur Dachausrichtung
gesehen, entsteht die Abbildung 5.2.14 (b). Da die Funktion TextureGroup zu Beginn aufgerufen wurde
und sonst zu keinem weiteren Zeitpunkt, erhalten alle Flächen die gleiche Textur. Diese wird zufällig
aus der Gruppe "Roof" bestimmt.
Nun folgt die Profile-Grammar der Wände für die beiden Würfel-Primitive. Hier wird mit Hilfe eines
horizontalen Profils, an der linken und rechten Seite einer Wand jeweils eine Säule ermittelt. Außerdem
wird mit Hilfe eines vertikalen Profils, am Anfang jedes Stockwerks ein kleiner Vorsprung erstellt.
Main [1, 1] {PTYPE == VERTICAL} ->
TextureGroup("Brick")
T(0.0,
0.0) PointV()
T(0.0,
2.0) PointV()
TextureGroup("Wall")
T(0.5,
0.1) PointV()
T(0.0, HEIGHT-2.1) PointV()
TextureGroup("Brick")
T(-0.5, 0.0*WIDTH) PointH()
T( 0.0, 0.1*WIDTH) PointH()
Reset()
T( 0.5, 0.0*WIDTH) PointH()
TextureGroup("Brick")
T( 0.0, 0.8*WIDTH) PointH()
T(-0.5, 0.0*WIDTH) PointH()
T( 0.0, 0.1*WIDTH) PointH();
Abb. 5.2.15 Profile-Grammar "PWall"
58
|
Die Grammatik besitzt lediglich eine Produktion und innerhalb dieser zwei Regeln. Die erste Regel
soll einmalig das vertikale Profil für alle Wände erzeugen und die zweite Regel jeweils ein horizontales
Profil für jede Wand. Über eine Bedingung und mit Hilfe der vordefinierten Konstanten PTYPE wird
innerhalb der Grammatik eine Abfrage eingeleitet. Diese Abfrage prüft, ob die Grammatik ein vertikales oder ein horizontales Profil berechnen soll. Im Falle eines vertikalen Profils werden vier vertikale
Punkte generiert. Die ersten beiden Punkte bilden hier einen kleinen Vorsprung. Die beiden hinteren
Punkt die restliche Wand bis zum Ende. Im Falle eines horizontalen Profils werden sechs Punkte erstellt. Die vorderen und hinteren zwei Punkte bilden jeweils eine Säule an den Enden der Wand. Die
beiden mittleren Punkte verbinden die beiden Säulen. Zusätzlich erhalten die vier Punkte der Säule eine
spezielle Backstein-Textur aus der Gruppe "Brick". Auf Grund der Reset-Funktion erhält die Fläche
zwischen den beiden Säulen keine Textur. Da dieser Fläche keine Textur zugewiesen wurde, verwendet
sie die Textur des vertikalen Profils, siehe Kapitel 5.2.4.2 Texturierung. Der restliche Teil bedarf keiner
weiteren Erklärung.
Die Figuren 5.2.16 bis 5.2.18 zeigen eines von vielen
möglichen Ergebnissen, das aus den Grammatiken
der vorherigen Kapitel erzeugt wurde. Bei jeder
neuen Ausführung der Grammatiken variiert das
Haus. Bisher allerdings noch relativ schwach, da
keine wirklichen Veränderungen am Masse-Modell,
den Fassaden und der Dachstruktur vorgenommen
werden. Anhand des Beispiels ist außerdem die
Wiederverwendbarkeit der einzelnen Grammatiken
gut zu erkennen. So könnte beispielsweise die
Grammatik für das Masse-Modell gegen eine
andere Mass-Grammar ausgetauscht werden, ohne
eine Veränderung an den sonstigen Grammatiken
durchführen zu müssen. D.h. die Facade-, Border- und
Profile-Grammar blieben unverändert und könnten
auf jedes beliebige Primitiv angewendet werden.
Abb. 5.2.17 Fertiges Gebäude mit Texturen
Abb. 5.2.16 Fertiges Gebäude ohne Texturen
Abb. 5.2.18 Nahansicht des Gebäudes
59
5.2.5 Kommunikation
Im Laufe dieses Kapitels wurde gezeigt, dass
die Mass-Grammar sogenannte Primitive
erzeugen kann. Dabei kann jedem Primitiv
eine Profile-, Facade- und/oder eine BorderGrammar zugeteilt werden. Diese werden
dann für jede Fläche bzw. Kante des Primitivs
einmal ausgeführt und erzeugen an diesen
Objekte. Es ist ebenfalls möglich, innerhalb
einer Facade- oder Border-Grammar erneut
Primitive zu erstellen, die wiederum neue
Profile-, Facade- und Border-Grammars
zugeteilt bekommen und diese ausführen.
Abb. 5.2.19 Grammatik-Kommunikation
Anderseits ist es ebenso möglich, innerhalb
der Mass-Grammar vormodellierte 3D-Modelle zu laden. Dies könnten zum Beispiel fertiggestaltete
Bäume oder gar komplett vordefinierte Stockwerke sein. Es bleibt den Nutzer freigestellt, wie er das
Gebäude aus Primitiven und Modellen zusammenbaut. Die Profile-Grammar ist die einzige Grammatik,
die keinen neuen Primitiven und Modelle erstellen kann.
In manchen Fällen ist es notwendig, dass die Grammatik bestimmte Parameter an eine andere
Grammatik weiterleitet. Zum Beispiel könnte eine Mass-Grammar die Nummer des Stockwerks an eine
Profile-Grammar übergeben. Diese verwendet die Nummer, um eine passende Textur für dass jeweilige
Stockwerk zu finden.
Diese einseitige Kommunikation findet über so genannte Register statt. Es handelt sich um eine
einseitige Kommunikation, da nur die aufrufende Grammatik Daten an die aufzurufenden Grammatiken
weiterleiten kann und nicht umgekehrt. Ein Register wird definiert durch einen eindeutigen Namen
und erhält als Daten eine einzelne reelle Zahl oder Zeichenkette. Innerhalb der Grammatiken kann
ein Register über die Funktion Out bzw. In angelegt bzw. ausgelesen werden. Zum Beispiel erzeugt
die Funktion Out(3, "Floor") ein Register mit dem Namen "Floor" und weist diesem Register einen
Wert von 3 zu. Sobald nun ein Primitiv erzeugt wird, werden alle aktuell angelegte Register an alle
drei Grammatiken (Facade-, Border- und Profile-Grammar) des Primitiv’s weitergeleitet. Diese
Grammatiken können das Register über die Funktion In("Floor") wieder auslesen. Der Rückgabewert
der Funktion würde in diesem Beispiel 3 betragen.
60
5.3 Primitive
Der Begriff Primitiv ist abgeleitet aus dem latein. primitivus für „einfach“. Primitive sind demzufolge
einfache, grundlegende und bereits vordefinierte Körper. Das System stellt verschiedene Typen von Primitiven mit jeweils unterschiedlichen Formen zur Verfügung. Diese bilden dann Teile eines Gebäudes
und können über die Grammatiken erzeugt werden. Im vorherigen Kapitel wurden Primitive bereits zur
Generierung des Masse-Modells verwendet. Dabei hat sich herausgestellt, das Primitive in zwei Kategorien eingeteilt werden können. Dies wäre zum einen die Wand-Primitive1, die zur Erzeugung der Hauswände dienen. Und zum anderen die Dach-Primitive zum Erstellen der Dachflächen. Weiterhin wurde
bereits verdeutlicht, dass jedem Primitiv drei verschiedene Grammatiken zugeteilt werden kann. Dies
sind die im Kapitel 5.2 Grammatiken erläuterten Profile-, Facade- und Border-Grammar. Ein Primitiv
führt diese jeweils einmal für jede Fläche bzw. Kante aus und erzeugt damit die Details des Gebäudes.
Aber an welchen Flächen bzw. Kanten werden die Grammatiken konkret ausgeführt? Welche Arten von
Primitiven stellt das System zu Verfügung? Wie können die verschiedene Primitive erzeugt werden? ...
In den beiden nächsten Unterkapiteln werden diese Fragen beantwortet. Dabei wird zuerst auf die zur
Erzeugung der Wände benötigten Primitive eingegangen und darauf folgend auf die für die Dachstrukturen benötigten Primitive.
5.3.1 Wand-Primitive
Wand-Primitive sind einfache, konvexe Körper und werden durch eine oder mehrere Flächen definiert.
Bislang wurden nur konvexe Körper implementiert, weil bei diesen eventuell anfallende SchnittAlgorithmen, schnell und einfach durchführbar sind. Durch Kombinationen verschiedener Primitive
soll der Grundriss eines Gebäudes entworfen werden. Dazu zählen zum Beispiel die typische T, L oder
U-Form eines Wohnhauses, die aus zwei bzw. drei Würfeln zusammengestellt werden kann.
5.3.1.1 Formen
Das System verfügt über fünf unterschiedliche Formen. Zu diesen zählen der Würfel, der Zylinder, der
Halb-Würfel, der Halb-Zylinder und eine einzige, unabhängige Fläche. Die Abbildung 5.3.1 verdeutlicht noch einmal bildlich die verschiedenen Primitive. Der Halb-Würfel und Halb-Zylinder besitzen,
wie der Name bereits verrät, nur eine Hälfte des Würfels bzw. Zylinders. Dies ist in beiden Fällen die
vordere Hälfte. Der Einsatz von halben Primitiven ist für den Zusammenbau mit ganzen Körpern vorgesehen. Beispielsweise kann eine T-Form mit Hilfe eines ganzen Würfels und einem angehängten halben
Würfel realisiert werden.
Alle erwähnte Primitive sind oben und unten offen. Diese Flächen werden nicht benötigt, da der obere Teil über
ein Dach-Primitiv geschlossen werden kann und der untere Teil im Normalfall sowieso nicht sichtbar ist.
Abb. 5.3.1 Primitive: (a) Würfel, (b) Zylinder, (c) Halb-Würfel, (d) Halb-Zylinder und (e) Wand
1
Im Gegensatz zu Dach-Primitive werden Wand-Primitive häufig einfach nur als Primitive bezeichnet.
61
5.3.1.2 Fassaden
Im Kapitel 5.2.2 Facade-Grammar wurde bereits notdürftig erläutert, an welchen Stellen eines Primitivs
die zugewiesene Facade-Grammar ausgeführt wird. Im Grunde entspricht es genau den eigenen
Vorstellungen und Vermutungen: Jede Fläche eines Primitiv’s entspricht genau einer Fassade. Dabei
befindet sich der Ursprung der Fassade in der linken, unteren Ecke der jeweiligen Fläche. Die x- und
y-Achsen des Koordinatensystems liegen direkt auf der Fläche. D.h. die x-Achse verläuft direkt nach
rechts entlang der unteren Kante einer Fläche. Während die y-Achse entlang der linken Kante nach
oben verläuft. Da jedes Primitiv nur über rechteckige Flächen verfügt, stehen die beiden Achsen immer
orthogonal zueinander. Dies erleichtert die Vorstellungen einer Fassade und ermöglicht die einfache
Aufstellung einer Facade-Grammar. Die z-Achse des Fassaden-Koordinatensystems steht senkrecht zu
beiden Achsen und bildet mit diesen ein linkshändiges System. Die Breite einer Fassade entspricht
demnach genau der Länge der unteren Kante, durch welche bereits die x-Achse definiert wurde, während
die Höhe einer Fassade durch die Länge der linken Kanten bestimmt wird.
Zur Erklärung zeigt Abbildung 5.3.2 die Koordinatensysteme einiger Fassaden, die jeweils bläulich dargestellt werden. Die x-Achse des Systems wird in Grün dargestellt, die y-Achse in Blau und die z-Achse
in Rot. Egal, für welches Primitiv eine Fassade bestimmt wird, der Raum bildet immer ein orthogonales,
linkshändiges System.
Abb. 5.3.2 Facade-Space (a) Würfel, (b) Zylinder, (c) Halb-Würfel, (d) Halb-Zylinder und (e) Wand
5.3.1.2 Ecken
Innerhalb des Kapitels 5.2 Grammatiken wurde notdürftig erklärt, dass für jede Kante eines Primitivs
jeweils eine Border-Grammar aufgerufen wird. Dies entspricht nicht ganz der Wahrheit. Vielmehr wird
nur für alle inneren Kanten eines Primitivs, die zugewiesene Border-Grammar ausgeführt. Daraus folgt,
dass die oberen sowie unteren Kanten keine Grammatiken aufrufen.
Der Ursprung des Koordinatensystems eine Border-Grammar liegt an dem unteren Punkt der Kante, siehe
Abb. 5.3.3. Die x-Achse des Systems verläuft genau entlang der Kante, d.h. wird eine Verschiebung in
x-Richtung vorgenommen, so verläuft diese immer auf der Kante. Die z-Achse entspricht der inversen
Normale der darauf folgenden Fläche. Die y-Achse steht schließlich senkrecht zur x- und z-Achse und
bildet mit diesen ein linkshändiges System.
Abbildung 5.3.3 verdeutlicht noch einmal die Koordinatensysteme einiger Kanten. Auch hier wird die
x-Achse in Grün, die y-Achse in Blau und die z-Achse in Rot dargestellt. Die zugehörige Kante wird
leicht bläulich unterstrichen und so sichtbar gemacht.
62
Abb. 5.3.3 Border-Space (a) Würfel, (b) Zylinder, (c) Halb-Würfel, (d) Halb-Zylinder und (e) Wand
5.3.1.3 Texturierung
Die Texturierung erfolgt relativ einfach, indem die Textur flach
auf jede Fläche des Primitivs gelegt wird, siehe Abb. 5.3.4 (a).
Damit der Nutzer nachträglich Einfluss auf die Koordinaten
erhält, können mittels der Funktion TexCoord(u, v) innerhalb
der Profile-Grammar die Texturkoordinaten der einzelnen
Abschnitte faktorisiert werden. D.h. die Funktion setzt jeweils
einen unabhängigen Faktor für die u- und v-Koordinate, der allen
darauf folgenden Punkten bzw. deren Flächen zugeordnet wird,
ähnlich wie bei der TextureGroup-Funktion (s. Kapitel 5.2.4.2
Texturierung). Beispielsweise könnte eine Textur gestaucht
werden, in dem beide Argumente eine 2 erhalten und dadurch
die Texturkoordinaten verdoppelt werden, siehe Abb. 5.3.4 (b).
(a)
5.3.1.4 Funktionen
Innerhalb der Grammatiken können die vorgestellten Primitive über Funktionen erzeugt werden, wie bereits geschehen in
Kapitel 5.2 Grammatiken. Diese Funktionen können innerhalb (b)
einer Mass-, Facade- und Border-Grammar ausgeführt werden.
Deshalb bleibt es diesen drei Grammatiken vorbehalten, Primitive zu erzeugen. Mögliche Funktionen sind dabei Box, Cylinder, HalfCylinder, HalfBox und Wall. Logischerweise erstellt
jede der Funktionen eines der oben beschriebenen Primitive.
Bevor das jeweilige Primitive erstellt wird, wird es vorher bzgl.
der aktuellen Transformations-Sequenz transformiert. D.h. der
Abb. 5.3.4 Texturierung (a) normal
aktuelle Zustand beeinflusst die Größe, Ausrichtung und Pound (b) gestaucht
sition der Primitive. Die Argumente der Funktionen werden
durch drei Zeichenketten bestimmt. Das erste Argument enthält den Namen der auszuführenden Profile-Grammar, das zweite Argument, den der auszuführenden Facade-Grammar und das dritte Argument schließlich den Namen der Border-Grammar. Daraus folgt, dass die Grammatiken immer einem
kompletten Primitiv zugeteilt werden. Es ist nicht möglich einzelnen Flächen oder Kanten verschiedene
Grammatiken zu zuteilen. Allerdings ist es möglich, nach dem Namen der Grammatik, durch einen
Doppeltpunkt getrennt, das Axiom (Namen einer Variablen) anzugeben, z.B. "FWall:Axiom".
Eine weitere Möglichkeit, eines der fünf Primitiven zu erstellen, ist durch die allgemeine Funktion Prim gegeben. Das erste Argument gibt hier nicht den Namen der Profile-Grammar an, sondern den Namen des zu
erzeugenden Primitivs. Das zweite Argument gibt schließlich den Namen der Profile-Grammar an, gefolgt
von den Argumenten für die Namen der Facade- und Border-Grammar.
63
5.3.2 Dach-Primitive
Die soeben beschriebenen Primitive, die der Erstellung von Wänden bzw. des Grundrisses dienen, sind
aus Flächen definierte konvexe Körper. Im Gegensatz dazu stehen die im Folgenden beschriebenen
Dach-Primitive. Diese werden zu Beginn lediglich als Linienzug definiert, der an den oberen Kanten
der einzelnen Primitiven entlangläuft und damit die Traufe des Gebäudes bestimmt. Auf dieses Polygon
(Synonym für Traufe) kann der im Kapitel 4 Straight-Skeleton erklärte Algorithmus des Straight-Skeletons angewendet werden. Das Verfahren ermittelt die innere Struktur des Dachs und daraus dessen
Flächen. Wurde die Dachausmittlung und damit die Flächen des Dachs berechnet, wird für das gesamte
Dach einmalig eine vertikale Profile-Grammar ausgeführt. Diese bestimmt den Typ und die Form des
Dachs. Nach dem das Dach erzeugt wurde, werden alle möglichen Fassaden und Kanten berechnet
und an diesen, die zugewiesene Facade- bzw. Border-Grammar ausgeführt. Durch die Ausführung der
Grammatiken werden schließlich Dachfenster, Gauben, Schornsteine, Regenrinnen und weitere Details
generiert.
5.3.2.1 Formen
Im Gegensatz zu Wand-Primitiven sind Dach-Primitive nicht aus Flächen definiert. Ein Dach-Primitiv
wird am Anfang nur als Linienzug angegeben. Dieser läuft an den oberen Kanten eines Primitivs entlang
und bildet damit die passende Traufe zum jeweiligen Wand-Primitiv. Dem einzigen Wand-Primitiv, dem
kein Dachelement zugeordnet werden kann, ist das Primitiv der unabhängigen Wand, siehe Abb. 5.3.1
(e). Da dieses Primitiv nur über eine einzige Kante verfügt und deshalb keinen geschlossenen Linienzug
bildet, ist es nicht möglich, ein Dach für dieses zu bestimmen.
Obwohl der Halb-Zylinder und Halb-Würfel keine geschlossenen Polygone formen, kann für beide Primitive ein Dach ermittelt werden. Dazu werden die Linienzüge beider Primitive einfach als geschlossen
angenommen und die beiden Endpunkte miteinander verbunden. In Abbildung 5.3.5 werden alle DachPrimitive, zu den jeweilig passenden Wand-Primitiven, durch die grünen Linien gekennzeichnet.
Abb. 5.3.5 Dach-Primitive: (a) Würfel, (b) Zylinder, (c) Halb-Würfel, (d) Halb-Zylinder
5.3.2.2 Dachdurchdringung
Eine neue Eigenschaft der Dach-Primitive liegt darin, dass mehrere dieser Primitive miteinander verbunden werden können. Schneiden sich zwei oder mehr Dach-Primitive an ein oder mehreren Stellen, so
werden diese zu einem Polygon zusammengefasst. Wie bei der Dachausmittlung (s. Kapitel 2.2.4 Dachausmittlung) werden nur Polygone die auf gleicher Höhe liegen miteinander verbunden. Das System
berechnet demnach das Straight-Skeleton erst, nachdem alle Dach-Primitive zusammengefasst wurden
und dadurch alle Dachdurchdringungen feststehen.
Die Ermittlung der Dachdurchdringungen findet in zwei Phasen statt, weshalb zwei Algorithmen eigens
dafür entwickelt wurden. Die erste Phase bestimmt unter allen erzeugten Dach-Primitiven diejenigen,
die sich schneiden und auf gleicher Höhe befinden, und ordnet diese einer Gruppe zu. In der zweiten
Phase werden alle Primitive einer Gruppe zu einem Dach-Primitiv bzw. Polygon zusammengefasst.
64
Abbildung 5.3.6 gibt das Bild einiger Wand-Primitive mit passenden Dach-Primitiven, auch hier wieder
durch die grünen Linien gekennzeichnet. Die Grundrissprojektion von Abb. 5.3.6 wird in der Zeichnung
5.3.7 dargestellt. Da sich die zwei mittleren Würfel und der Zylinder durchdringen, sollen diese
miteinander verbunden werden. Der kleinere Würfel im Bild schneidet zwar ebenfalls einen der mittleren
Körper, aber besitzt nicht die gleiche Höhe. Aus diesem Grund soll dieser sowie der freistehende Würfel
jeweils ein eigenständiges Dach erhalten. In den nächsten Abschnitten wird ausführlich erklärt, wie die
Dachdurchdringung und Verbindung der Dächer berechnet werden kann.
Abb. 5.3.6 Dachdurchdringung
Abb. 5.3.7 Grundriss
Im ersten Schritt werden die Durchdringungen aller
Dach-Primitive ermittelt. Dazu werden die Polygone aller
Primitive gegeneinander verglichen, aber nur, falls sie auf
gleicher Höhe liegen. Ist dies gegeben, so wird das erste
Primitiv in eine Gruppe eingeordnet. Danach werden die
Schnitte des ersten Primitivs mit allen anderen Primitiven
berechnet. Falls das Polygon des Primitivs ein oder mehrere
andere Polygone schneidet, werden diese der Gruppe
zugeordnet. Nun werden wiederum die Primitive, die der
Gruppe neu zugeordnet wurden, gegen alle Primitive, die
noch keiner Gruppe angehören, getestet. Konnten erneut
Durchdringungen gefunden werden, werden die neu
geschnittenen Primitive ebenfalls der Gruppe zugewiesen.
Dieser Vorgang wird so lange fortgesetzt, bis kein Schnitt
mehr gefunden werden kann. Existieren danach noch
Primitive, die keiner Gruppe angehören, so wird mit diesen
erneut von vorne begonnen. Das heißt, das nächste freie
Polygon wird in eine neue Gruppe eingefügt, und es wird
der Schnitt mit allen Primitiven berechnet, die noch keiner
Gruppe zugewiesen wurden. Und so weiter.
Durch den Algorithmus werden die Primitive schrittweise
in ein bis mehrere Gruppen eingeordnet und als Ergebnis
erhält das System alle Primitive, die sich schneiden und in
gleicher Höhe befinden.
Abb. 5.3.8 Iterationen zur Bestimmung
Die Abbildung 5.3.8 verdeutlicht die einzelnen Iterationen
aller Dachdurchdringungen
des Algorithmus. Begonnen wird mit dem blauen Polygon
aus Zeichnung 5.3.8 (a). Im zweiten Schritt (b) konnte der
Zylinder der blauen Gruppe zugeteilt werden. In der dritten Iteration (c) konnte das nächste Primitiv in
die Gruppe eingeordnet werden. Danach existiert kein weiteres Objekt, das der blauen Gruppe angehört. Das heißt, es wird in der vierten Iteration die rote Gruppe erzeugt und in der fünften Iteration die
grüne Gruppe, beide in Abb. 5.3.8 (d) dargestellt.
65
Nachdem alle Primitive den Gruppen zugeordnet wurden, kann in der zweiten Phase für jede Gruppe
ein verbundenes Polygon ermittelt werden. D.h. der nachfolgende Algorithmus wird für jede Gruppe
einmal ausgeführt. Zuerst wird ein Startpunkt für die Gruppe ermittelt. Dieser darf nicht innerhalb eines
der Gruppe angehöriger Polygone liegen. Da alle Polygon die Traufe eines konvexen Wand-Primitivs
bilden, sind diese ebenfalls alle konvex. Weiterhin werden alle Polygone gegen den Uhrzeigersinn angegeben. Durch diese zwei Voraussetzungen lässt sich schnell und einfach ermitteln, ob sich ein Punkt
innerhalb eines Polygons befindet.
Wurde der Startpunkt bestimmt, wird von diesem beginnend das Polygon gegen den Uhrzeigersinn verfolgt. Dafür wird ein Strahl, ausgehend von dem aktuellen Punkt, in Richtung der zum Punkt gehörigen
Kante geschickt. Trifft der Strahl auf ein anderes Polygon, so ergibt der Schnittpunkt einen neuen Punkt
des verbundenen Polygons. Trifft der Strahl auf kein anderes Polygon, so bestimmt der nächste Punkt
des aktuellen Polygons den neuen Punkt des verbundenen Polygons. Dies wird so lange fortgesetzt, bis
der Startpunkt wieder erreicht wurde und damit alle Primitive miteinander verbunden wurden.
Abb. 5.3.9 (a) zeigt die ersten fünf Iterationen zum Verbinden der Primitive. In Abb. 5.3.9 (b) gibt ein
Bild des Ergebnisses, also das verbundene Polygon. Abb. 5.3.9 (c) verdeutlicht durch die gestrichelten
Linien zusätzlich das Straight-Skeleton.
Abb. 5.3.9 (a) Verbinden der Primitive, (b) Ergebnis der Zusammenfassung und
(c) Ergebnis mit Straight-Skeleton
Durch verbinden der durchdringenden Dach-Primitive wurde für den Haupttrakt ein einziges, zusammenhängendes Dach berechnet, Abb. 5.3.10.
Das frei stehende Gebäude sowie der kleinere
Nebentrakt erhalten jeweils ein eigenes unabhängiges Dach.
Ein Problem beim Verbinden mehrerer Dach-Primitive könnte dadurch entstehen, dass den verAbb. 5.3.10 Dachverbindung
schiedenen Dach-Primitiven auch verschiedene
Profile-Grammars zugewiesen werden. Dies stellt
insofern ein Problem dar, als dass durch diese Kombination Lücken innerhalb der Dachflächen entstehen könnten. Aus diesem Grund verwenden zusammengefasste Dach-Primitive immer die Grammatik
des größten Primitivs. Das größte Primitiv stellt den Haupttrakt des Gebäudes dar und bestimmt damit
die Form und das Aussehen des Dachs.
66
5.3.2.3 Fassaden
Bei einem Wand-Primitiv entsprach jede Fläche genau einer Fassade. Die Bestimmung der Fassaden für
ein Dach kann nicht so trivial beschrieben werden. Zum einen bildet eine Dachfläche in den wenigsten
Fällen ein Rechteck. Und zum anderen existieren oft Dachflächen, an denen es nicht sinnvoll wäre, eine
Facade-Grammar aufzurufen. Aus diesem Grund wurden eigens zwei Bedingungen aufgestellt, die eine
Fassade (eine Fläche an der die Facade-Grammar ausgeführt wird) erfüllen muss. Erstens, die Fläche
muss immer rechteckig sein, und zweitens muss sie direkt bei der Traufe beginnen und bis zum First
verlaufen. Kann für eine Dachfläche kein Rechteck mit den passenden Kriterien gefunden werden, wird
für diese Fläche auch keine Facade-Grammar ausgeführt.
Warum müssen die beiden Kriterien erfüllt sein? Zur Erinnerung, eine Fassade definiert den
Wirkungsbereich einer Facade-Grammar. Diese soll Objekte entlang der Dachflächen platzieren,
z.B. Dachfenster, Schornsteine oder Dachgauben. Nun existieren viele Bereiche innerhalb einer
Dachkonstruktion, an denen Objekte nicht platziert werden sollten bzw. in der Realität nicht platziert
werden können. Beispielsweise in der linken unteren Ecke einer geneigten Walmfläche, in Abb. 5.3.11
verdeutlicht durch den grünen Punkt. An dieser Stelle würden normalerweise keine Dachfenster, keine
Gauben und auch keine sonstigen Objekte platziert werden, da diese direkt auf die Balkenkonstruktion
stoßen würden. Die verbotenen Bereiche existieren nicht an den Stellen, die strikt und durchgängig von
der Traufe bis zum First verlaufen. Werden all diese Stellen zusammengefasst, erhält man ein Rechteck,
das von der Traufe bis zum First verläuft und damit die Fassade der Dachfläche abgrenzt.
Die nächsten Abschnitte beschreiben einen Algorithmus, mit dem rechteckige Fassaden für alle Formen
von Dachflächen bestimmt werden können. Dazu
muss zuerst die genaue Struktur des Dachs berechnet werden. Hierfür wird das Straight-Skeleton verwendet (s. Kapitel 4 Straight-Skeleton), allerdings
dürfen die Zwischenschritte des Straight-Skeletons
nicht verworfen werden. Die verschiedenen Iterationen werden benötigt, um möglichst einfach ein
oder eventuell mehrere passende Rechtecke für die
Dachflächen zu erhalten. D.h. zuerst werden für die
einzelnen Iteration geeignete Rechtecke berechnet,
die dann in einem zweiten Durchgang miteinander
verbunden und evtl. an den Seiten gekürzt werden.
Ein Beispiel für die verschiedenen Iterationen des
Straight-Skeletons wird in Abb. 5.3.11 durch die gestrichelten Linien dargestellt.
Abb. 5.3.11 Straight-Skeleton
Im ersten Durchlauf muss der entwickelte Algorithmus für jede Fläche einer Straight-Skeleton Iteration,
jeweils ein Rechteck bestimmen. Da diese Flächen entweder ein Trapez, Parallelogramm oder Dreieck
bilden, wie in Abb. 5.3.11 zu erkennen ist, muss für jede dieser Formen ein Rechteck berechnet werden.
Das Rechteck muss innerhalb der Form liegen und von der unteren bis zur oberen Kante verlaufen.
Außerdem müssen die untere und obere Kante des Rechtecks parallel zur oberen bzw. unteren Kante
der Form liegen. Kann für eine Form kein passendes Rechteck bestimmt werden, so wird auch keine
Fassade für diese Fläche angegeben. Diese Fälle sind allerdings nur bei Parallelogrammen möglich,
siehe Abb. 5.3.12 (c). Für ein Trapez und ein Dreieck kann immer ein passendes Rechteck gefunden
werden, siehe Abb. 5.3.12 (a) und (b). Bei einem Dreieck nimmt das Rechteck immer die Form einer
Linie an, dies spielt für den späteren Verlauf des Algorithmus keine Rolle. Es handelt sich einfach um
ein Rechteck mit einer Breite von null.
67
Abb. 5.3.12 Bestimmung des Rechtecks
Zum Verständnis wird in Abb. 5.3.13 (a) die erste Iteration des Algorithmus angezeigt, dabei konnte für das
Parallelogramm des linken Nebentrakts kein Rechteck
bestimmt werden, zur Erklärung siehe Abb. 5.3.12 (c).
Für die restlichen Flächen konnte jeweils ein passendes
Rechteck ermittelt werden. Diese werden innerhalb der
Abbildung durch die blauen Flächen verdeutlicht. In der
zweiten Iteration (b) werden die Flächen grün dargestellt
und in der dritten Iteration (c) rot.
Wurden die Rechtecke für alle Stufen des Straight-Skeletons bestimmt, können diese als nächstes schrittweise
zusammengefasst werden. Dabei wird wieder mit der
untersten Stufe begonnen. Diese wird mit dem darüber liegenden Level verbunden. Damit zwei Flächen
verbunden werden dürfen, müssen sie eine Schnittlinie
besitzen, d.h. die obere Kante des unteren Rechtecks
muss die untere Kante des oberen Rechtecks schneiden.
Als Ergebnis entsteht ein minimales Rechteck, dessen
Längsseite durch die Schnittlinie bestimmt wird.
Abbildung 5.3.13 (d) zeigt, wie die erste Stufe mit
der zweiten Stufe zusammengefasst wird. Dabei
können die beiden Rechtecke des rechten Nebentrakts
nicht miteinander verbunden werden, weil sie keinen
gemeinsamen Schnitt besitzen. Das Gleiche gilt für die
Frontseite des Haupttrakts. Da hier der erste mit dem
zweiten Level nicht verbunden werden konnte, kann
auch nicht der zweite mit dem dritten Level verbunden
werden. Abbildung 5.3.13 (e) zeigt schließlich die letzte
Iteration, bei der erneut das Rechteck des Haupttrakts
zusammengefasst wird. Wie zu erkennen ist, verlaufen
alle Rechtecke von der Traufe bis zum First des jeweiligen
Abb. 5.3.13 Iterationen zur Bestimmung der
Dachs und grenzen die Fassade ab.
Fassaden
Innerhalb der berechneten Bereiche dürfen nun von einer Facade-Grammar Objekte platziert werden.
Damit diese Platzierung gesteuert werden kann, muss zu guter Letzt für jede Fassade ein Koordinatensystem berechnet werden. Wie bei den Fassaden der Wand-Primitive befindet sich der Ursprung an der
linken unteren Ecke des Rechtecks. Die x-Achse verläuft entlang der unteren Kante des Rechtecks und
die y-Achse entlang der linken Außenkante. Die z-Achse steht auch hier senkrecht auf beiden Achsen
und erzeugt ein linkshändiges System. Für Rechtecke, die eine Breite von Null besitzen, da sie z.B.
durch ein Dreieck erzeugt wurden, existiert eigentlich keine untere Kante. D.h. die x-Achse kann nicht
durch das Rechteck ermittelt werden. Allerdings kann immer noch auf die Kante des Straight-Skeletons
zurückgegriffen werden, um in diesen Fällen die x-Achse zu bestimmen.
68
5.3.2.4 Kanten
Bei einem Dach-Primitiv wird, im Gegensatz zu den Wand-Primitiven, an jeder Kante die zugewiesene
Border-Grammar ausgeführt. Allerdings entstehen hier Unterschiede bei der Angabe der einzelnen
Koordinatensysteme, die abhängig von dem Typ der jeweiligen Kante sind. Die verschiedenen Typen
wurden im Grundlagenkapitel 2.2.1 Dachbegriffe definiert.
Trotz einiger Unterschiede besitzen die Systeme der verschieden Kanten auch gleiche Eigenschaften.
So liegt der Ursprung des Koordinatensystems bei allen Kanten im Startpunkt der jeweiligen Kante.
Außerdem verläuft die x-Achse immer genau entlang der Kante, egal bei welchem Typ. Handelt es sich
bei der Kante um den Teil einer Traufe oder eines Firsts, so steht die y-Achse genau senkrecht nach oben,
siehe Abb. 5.3.14 (a). Ist die Kante
dagegen vom Typ Grat oder Kehle,
läuft die y-Achse senkrecht zur x-Achse
und bildet die Winkelhalbierende
der beiden benachbarten Flächen.
Bei einem Ortgang steht die y-Achse
ebenfalls senkrecht auf der x-Achse
und der benachbarten Walmseite.
Siehe Abbildung 5.3.14 (b) für die
Koordinatensysteme eines Ortgangs,
eines Grats und einer Kehle. Die zAbb. 5.3.14 Border-Space für (a) Traufe und First,
Achse wird für alle Typen orthogonal
(b) Ortgang, Kehle und Grat
zur x- und y-Achse erzeugt und bildet
mit diesen das Linkshandsystem der
Kante.
5.3.2.5 Texturierung
Im Gegensatz zu Wand-Primitiven existieren bei
Dach-Primitiven zwei verschiedene Arten, die
Texturierung durchzuführen. Dabei wird die Art
der Texturierung anhand der Steigung des Dachs
festgelegt. Handelt es sich um ein flach geneigtes
Dach oder um ein Steildach (siehe Kapitel 2.2.3
Dachneigung), werden die Texturen wie bei einem
Wand-Primitive auf die Flächen gelegt, siehe
Abb. 5.3.14. Bei einem Flachdach (siehe Kapitel
2.2.3 Dachneigung) dagegen würde eine solche
Texturierung zu falschen Eindrücken führen, siehe
Abb. 5.3.15. Denn Flachdächer sind in den meisten
Fällen aus Stein, Beton oder ähnliches direkt
zusammengebaut und nicht mit Dachziegel belegt.
D.h. es ist im Normalfall kein Schnitt zwischen den
Dachflächen zu erkennen, da diese übergehend durch
Steine oder Sonstiges verlegt werden. Aus diesem
Grund wird die Textur gleichmäßig direkt von oben
auf alle Flächen projiziert, wie in der Abbildung
5.3.16 zu erkennen ist.
Abb. 5.3.14 Texturierung eines Steildachs
Abb. 5.3.15 Falsche Texturierung eines
Flachdachs
69
Wie bereits bei den Wand-Primitiven erläutert wurde,
können die Texturkoordinaten (in beiden Fällen) über
die TexCoord-Funktion faktorisiert werden. Dadurch
kann die Textur auf den Dachflächen gestaucht oder gestreckt werden, je nachdem, ob der Faktor größer oder
kleiner 1 übergeben wird.
Abb. 5.3.16 Texturierung eines Flachdachs
5.3.2.6 Funktionen
Um ein Dach-Primitiv durch eine Grammatik erzeugen zu lassen, wurden die Befehle RoofBox, RoofCylinder, RoofHalfBox und RoofHalfCylinder implementiert. Auch hier erzeugt die Funktion das zum
Namen passende Dach-Primitiv. Wie bei den Wand-Primitiven bestimmen die ersten drei Argumente
die Namen der Profile-, Facade- und Border-Grammar. Auch hier kann optional durch ein Doppelpunkt
getrennt, nach dem Namen das Axiom festgelegt werden. Zusätzlich besitzen die Funktionen noch bis
zu vier weitere Argumente.
Das vierte Argument bestimmt die Steigung des Dachs. Diese wird in Radien angegeben und beträgt im
Normalfall 45 Grad. Über das fünfte Argument kann die Überlauflänge des Dachs angegeben werden,
d.h. ist der Wert größer als 0, bestimmt dieser die Länge, die das Dach über die Wand hinausläuft.
Wie im Kapitel 4.6 Gewichtung erklärt wurde, können die Kanten eines Polygons gewichtet werden und
durch diese entsprechend langsamer schrumpfen. Durch Gewichten der vorderen und hinteren Kante
eines Dach-Primitivs können so Giebelseiten erzeugt werden. Als sechstes Argument kann dieser Wert
zur Gewichtung der Giebelseiten übergeben werden. In Normalfall ist der Wert gleich 1, das heißt, die
Giebelseiten besitzen die gleiche Steigung wie die Längsseiten des Dachs.
Das letzte Argument kann entweder den Wert 0 oder 1 annehmen. Falls eine 1 übergeben wird, wird
das Dach nach dem Algorithmus von Kapitel 5.3.2.2 Dachdurchdringung mit anderen Dach-Primitiven
verbunden. Bei einer 0 wird das Primitiv mit keinem anderen Dach-Primitiv verbunden, auch wenn
die Primitive die gleiche Höhe besitzen und eine Durchdringung stattfindet. Das System behandelt das
Dach immer als eigenständig und unabhängig.
Wie bereits bei den Wand-Primitiven (s. Kapitel 5.3.1.4 Funktionen) existiert eine allgemeine Funktion
Roof, deren erstes Argument den Namen des Primitivs enthält. Damit werden alle weiteren Argumente
um eins nach hinten verschoben, d.h. der Namen der Profile-Grammar wird als zweites Argument übergeben, der Namen der Facade-Grammar als drittes, usw.
70
5.4 Gruppen
Allein durch die Zusammensetzung mehrerer Primitive ist es möglich, komplette Gebäude samt Details
zu entwerfen. Allerdings würde durch einen solchen Ansatz die Komplexität der Grammatiken drastisch
steigen, was wiederum längere Berechnungszeiten mit sich bringen würde. So würde ein rein aus
Primitiven bestehendes Gebäude eine möglichst große Vielfalt mit sich bringen, allerdings würde der
Nutzer so gut wie jede Kontrolle über das exakte Aussehen des Gebäudes verlieren. Der Zeitaufwand
wäre ebenfalls beträchtlich. Je feiner und strukturierter das Gebäude werden soll, umso komplexer
werden die Grammatiken und der damit verbundene Zeitaufwand sowie die Fehleranfälligkeit steigen.
Aus diesem Grund ist es möglich, bereits vorgefertigte Modelle zu laden. Der Nutzer kann dadurch
gewisse von ihm bestimmte Teile des Gebäudes fest definieren. Außerdem wird so ein Großteil der
Komplexität aus den Grammatiken ausgelagert. Zum Beispiel ist ratsam, Details (wie Fensterrahmen,
Türen, Blumenkästen und Ähnliches) als bereits vormodellierte Objekte zu laden und durch die
Grammatiken zufällig platzieren zu lassen.
Aber wie kann trotz der Nutzung vorgefertigter Modelle immer noch eine möglichst große Vielfalt
erzeugt werden? Um dies zu erreichen, wurden sogenannte Modell-Gruppen eingeführt. ModellGruppen sind eine Ansammlung von Objekten, die alle zu einer Kategorie von Typen gehören sollten.
Beispielsweise könnte eine Gruppe verschiedene Modelle von Türen enthalten. Sobald die Grammatik
ein Objekt von der Gruppe anfordert, liefert die Gruppe eine zufällige Tür zurück und die Grammatik
kann diese platzieren.
Gruppen unterteilen sich in zwei unterschiedliche Klassen. Dies sind zum einen die Modell-Gruppen
und zum anderen die Textur-Gruppen. Modell-Gruppen wurden weiter oben bereits ausführlich behandelt. Textur-Gruppen besitzen dieselben Eigenschaften, nur anstatt der Modelle enthalten sie Texturen.
Zum Beispiel könnte eine Textur-Gruppe verschiedene Arten von Holz-Texturen enthalten und bei jeder
Anfrage zufällig eine der Texturen zurückgeben.
Das Prinzip von Gruppen ist einfach, aber sehr effektiv, und lagert einen großen Teil der Komplexität
aus den Grammatiken aus. Wie auf Gruppen innerhalb der Grammatik zugegriffen werden kann, sowie
einige Besonderheiten von Modellen, wird auf den nächsten Seiten innerhalb dieses Kapitels erklärt.
5.4.1 Modell-Gruppen
Eine Modell-Gruppe enthält mehrere Variationen des gleichen Typs, beispielsweise verschiedene Arten
von Türen. Jede Modell-Gruppe verfügt demnach über eine bestimmte Anzahl an Objekten und erhält
zusätzlich einen eindeutigen Namen. Mit Hilfe des Namens kann über eine Funktion auf die Gruppe
zugegriffen werden. Bei jedem Zugriff bestimmt die Gruppe ein zufälliges Objekt und liefert dieses
zurück. Die Grammatik transformiert dieses Objekt anhand des aktuellen Transformations-Zustands und
erzeugt schließlich das Modell.
71
5.4.1.1 Funktion
Wurde einer Gruppe der Name und die Objekte zugewiesen, kann über die Funktion ModelGroup("Name:
Index", UndoRotate, IntersectSetting) ein Objekt aus der Gruppe angefordert werden. Nur eine Mass-,
Facade- oder Border-Grammar darf eine Gruppe laden, damit bleibt die Profile-Grammar als einzige
Grammatik ausgeschlossen, s. Kapitel 5.2.5 Kommunikation. Die Bedeutung der einzelnen Argumente
wird durch die folgende Tabelle erklärt.
Name:Index
Das erste Argument gibt den Namen der Modell-Gruppe an. Zusätzlich kann dem
Namen, durch einen Doppelpunkt getrennt, ein Index mit übergeben werden. Wird
kein Index angegeben, dann liefert die Gruppe ein zufälliges Objekt zurück. Wird
allerdings ein Index angehängt, lässt sich ein bestimmtes Modell aus der Gruppe
erzwingen. So würde ein Index von 1 zur Folge haben, dass immer das zweite Objekt
(da die Indexierung bei 0 beginnt) aus der Gruppe geladen wird.
UndoRotate
Wird fast ausschließlich beim Laden von Objekten auf Dach-Fassaden benötigt. Falls
das Argument eine 1 erhält, wird die Rotation der Fassade bzw. Kante rückgängig
gemacht.
IntersectSetting Das Argument bestimmt die Einstellungen für den Schnitt mit Primitiven. Mögliche
Werte die das Argument annehmen kann, sind 0, 1, oder 2. Genaueres über den
Schnitt von Modellen wird Kapitel 5.4.1.2 Schnitt erläutert.
5.4.1.2 Schnitt
In manchen Fällen kann es vorkommen, dass die Flächen eines Primitivs teilweise oder gar komplett
innerhalb des Volumens eines anderen Primitivs liegen. In solchen Fällen liegen dann ebenfalls häufig,
die an den Fassaden bzw. Kanten erzeugte Modelle vollständig oder teils innerhalb des Primitivs. Über
die ModelGroup-Funktion kann nun entschieden werden, wie mit solchen Modellen weiterverfahren
werden soll. Dabei können drei verschiedene Fälle für ein Objekt eintreten. Die erste Möglichkeit wäre,
dass sich das Modell komplett außerhalb jedes Primitivs befindet. Die zweite, das Modell befindet
sich vollständig in einem oder mehreren Primitiven. Oder aber, der dritte Fall tritt ein und das Modell
schneidet ein oder mehrere Primitive, aber befindet sich in keinem vollständig. Zur Demonstration
präsentiert Abb. 5.4.1 die drei verschiedenen Möglichkeiten. Die Fenster-Modelle wurden jeweils
von dem Haupttrakt erzeugt und befinden sich evtl.
vollständig (rot) oder teilweise (grün) innerhalb des
Nebentrakts.
Abb. 5.4.1 Schnitt
72
Das dritte Argument der ModelGroup-Funktion
steuert in welchen der Fälle die Objekte angelegt
werden. Wie in Kapitel 5.4.1.1 Funktion erklärt
wurde, kann an das Argument entweder eine 0, 1
oder 2 übergeben werden. Wurde eine 0 gesetzt,
wird das erzeugte Objekt verworfen, wenn es sich
innerhalb eines Primitivs befindet oder dieses nur
schneidet. Bei einer 1 wird das Modell nur verworfen, wenn es sich komplett innerhalb eines anderen
Primitivs befindet. Beträgt der Wert des Arguments
eine 2, dann wird das Modell immer platziert, auch
wenn es vollständig oder teilweise innerhalb eines
Primitivs liegt.
5.4.1.3 CutOut-Modell
Im bisherigen Verlauf der Arbeit wurde gezeigt, dass
beliebige Modelle an den Fassaden oder sonstigen Bereichen
platziert werden können. Einige Modelle verlaufen dabei ins
Innere des Gebäudes, z.B. Fenster, Türen, Nischen, etc. Da
die Wände des Masse-Modells nicht aufgespaltet werden
und deshalb keine Lücke enthalten, durchlaufen sie häufig
die einzelnen Modelle. Das entstehende Problem kann in
Abb. 5.4.2 beobachtet werden.
Eine mögliche Lösung für dieses Problem wäre, für jedes
einzelne Modell eine Lücke innerhalb der Wand zu formen.
Diese Variante birgt allerdings einige Nachteile in sich.
Zum einen müssen die Schnitte zwischen den eventuell sehr
komplexen Modellen und den Flächen der Primitive ermittelt
werden. Zum anderen muss ein Algorithmus entwickelt
werden, der die Wand inklusive der Lücken geeignet
trianguliert. Beide Verfahren benötigen sehr komplizierte
Algorithmen, welche die Laufzeit, die Anzahl der Polygone
und den Speicherverbrauch drastischen steigern.
Anstatt die Geometrie der Wände zu unterteilen, wird
auf einen kleinen grafischen Trick zurückgegriffen. Jedes
Modell mit Bereichen, die in das Innere einer Wand
verlaufen, wird zusätzlich ein spezielles CutOut-Modell
zugeteilt. Das CutOut-Modell benötigt keine Textur und soll
nur bestimmte Bereiche des Tiefenbuffers „ausschneiden“.
Damit können die Wände an den Stellen dieser speziellen
Modelle nicht gezeichnet werden.
Abb. 5.4.2 Fehler aufgrund einer
durchlaufenden Wand
Damit das Verfahren funktioniert, werden die Modelle und
Primitive in einer bestimmten Reihenfolge gezeichnet.
Zuerst müssen alle Modelle wie gewohnt in den Z-Buffer
und Color-Buffer gezeichnet werden. Nach diesem Schritt
können die zugewiesenen CutOut-Modelle gezeichnet
werden, allerdings nur auf den Z-Buffer und nicht auf
den Color-Buffer. Infolge dessen verändern die Modelle
zwar den Tiefenbuffer, sind aber nicht sichtbar, da keine
Farbinformationen gespeichert werden. Werden nun im
letzten Schritt die Flächen der Primitive gezeichnet, und
zwar wie gehabt auf den Z-Buffer und Color-Buffer,
geschieht dies an allen Stellen, außer an denen durch die
CutOut-Modelle veränderten Bereiche.
In Abbildung 5.4.3 wird das Modell eines Fensters
dargestellt. Zusätzlich wird in der Abbildung ein passendes
CutOut-Modell in Rot angezeigt. Dieses Modell wird
verwendet, um den Tiefenbuffer zu verändern und damit die
dahinter liegende Wand auszuschneiden.
Abb. 5.4.3 CutOut-Modell
73
5.4.1.4 Anwendung
Die Mass-Grammar aus Abb. 5.4.4 soll in gleichmäßigen Abständen drei Fenster erstellen. Dazu wurde
eine Modell-Gruppe mit der Bezeichnung "Window" angelegt und danach zwei Modelle zugeordnet.
Die Grammatik erzeugt die in Abbildung 5.4.5 dargestellten Fenster. Das linke Fenster wird dabei zufällig aus der Gruppe ausgewählt und verändert sich jedes Mal, wenn die Grammatik erneut ausgeführt
wird. Das zweite Fenster erhält zusätzlich einen Index von 1, der bewirkt, dass immer das zweite Fenster aus der Gruppe geladen wird. Das dritte Fenster wurde zuerst einer Konstanten zugewiesen, diese
erhält zu Beginn ein zufälliges Objekt aus der Gruppe. Die Konstante kann schließlich als Argument an
die Funktion ModelGroup übergeben werden und bewirkt damit, dass immer das Modell geladen wird,
das ihr zu Beginn zugewiesen wurde. Alle Fenster werden normal durch die Transformations-Sequenz
beeinflusst und umgewandelt, in diesem Fall eine Skalierung und Translation.
cModel = ModelGroup("Window");
Main -> S( 2,
T( 0,
T(20,
T(20,
2,
0,
0,
0,
2)
0) ModelGroup("Window")
0) ModelGroup("Window:1")
0) ModelGroup(cModel);
Abb. 5.4.4 Mass-Grammar
Abb. 5.4.5 Ergebnis der Mass-Grammar
5.4.2 Textur-Gruppen
Textur-Gruppen enthalten Varianten von Texturen, die einer Kategorie zugeordnet werden können, zum
Beispiel verschiedene Marmor-Texturen. Wie bei einer Modell-Gruppe erhält jede Textur-Gruppe einen
eindeutigen Bezeichner. Dieser wird auch hier benötigt um Gruppe zu identifizieren.
Textur-Gruppen können ausschließlich von einer Profile-Grammar geladen werden. Verwendet wird
dafür die Funktion TextureGroup("Name:Index"). Wie bei der bereits beschriebenen ModelGroupFunktion gibt auch hier das erste Argument den Namen der Gruppe und eventuell ein Index an. Falls ein
Index angehängt wird, bestimmt dieser, welche Textur geladen werden soll (die Indexierung beginnt auch
hier bei 0). D.h. bei Angabe eines Index wird die Textur nicht mehr zufällig aus der Gruppe ermittelt,
sondern immer die, durch den Index bestimmte Textur, geladen.
Die drei Wand-Texturen aus Abbildung 5.4.6 veranschaulichen eine beispielhafte Gruppe für die MauerAbschnitte eines Bauwerks. Über die Gruppe kann nun zufällig oder gezielt eine dieser Texturen geladen
und auf den Abschnitten einer Profile-Grammar gesetzt werden.
Abb. 5.4.6 Textur-Gruppe für Mauerstrukturen
74
5.5 Subdivision und Symmetrie
Aufgrund der räumlichen Aufteilung von Häusern und vor allem durch die Trennung in einzelne
Stockwerke besitzen die meisten Fassaden eine dementsprechende Anordnung der Fenster, Türen und
sonstigen Merkmalen bzgl. dieser Aufteilung. Dahingehend werden die Fassaden in Zeilen und Spalten
strukturiert, und die Objekte innerhalb einer Zeile bzw. Spalte verfügen meist über eine exakte oder
ähnliche Anordnung.
Zusätzlich treten bei vielen Gebäuden häufig Symmetrien innerhalb des Grundmodells und der Fassaden
auf, als Beispiel kann man das „Weiße Haus“ benennen. Wird dieses in der Mitte geteilt, bildet die
linke Hälfe eine gespiegelte Variante der rechten Hälfte. Als Beispiel für symmetrische Fassaden
müssen nur die meisten Fachwerkbauten betrachtet werden. Diese besitzen meistens ein symmetrisches
Fachwerkmuster.
Ein geeignetes Mittel, solche Aufteilungen durch Regeln zu formulieren, wurde von [WWS+03] mit
einer Split-Grammar umgesetzt. Diese Idee wurde übernommen und ähnlich realisiert. Allerdings
wird dazu keine komplett eigenständige Grammatik (Split-Grammar) definiert, sondern wie in dem
Ansatz von [MWH+06] werden einige Methoden in die bereits bestehende Grammatik integriert. Mit
Hilfe dieser Funktionen können Unterteilungen an den Fassaden oder Kanten vorgenommen werden.
Außerdem wurde ein Verfahren hinzugefügt, welches dem Nutzer ermöglicht, mit einfachen Mitteln
Symmetrien zu erzeugen.
5.5.1 Subdivision
Wie bei der von [MWH+06] definierten Shape-Grammar können vertikale und horizontale Unteilungen an allen Fassaden (Bereich einer Facade-Grammar), aber auch Grundstücken (Bereich einer
Mass-Grammar) oder Kanten (Bereich einer Border-Grammar) vorgenommen werden. Anders als bei
[MWH+06] wird dabei nicht die Geometrie der Wände unterteilt bzw. durch Formen ersetzt, sondern
nur der Bereich, in dem eine Grammatik arbeitet. Abbildung 5.5.1 (a) zeigt die Fassaden der beiden
Stockwerke aus dem durchgängigen Beispiel von Kapitel 5.2 Grammatiken. Wird nun eine horizontale
Subdivision in drei Teile1 vollführt, entstehen die in Abbildung 5.5.1 (b) dargestellten Fassaden. Der
Vorgang könnte nun für jede einzelne Unterteilung erneut horizontal oder vertikal durchgeführt werden
und damit weitere Teilungen erzeugen.
Innerhalb der Grammatik können die verschieden Partitionen durch Funktionen erzeugt werden. Um
die Handhabung möglichst einfach zu halten, wurden vier verschiedene Funktionen implementiert,
dies sind die Funktionen SubDiv,
Part und SplitX bzw. SplitY. Alle
Funktionen können vertikale und
horizontale Spaltungen durchführen
und für jeden neu entstandenen Teil
eine Produktion aufrufen. Allerdings
wird die Anzahl und die Größe der
Teilung bei jeder Funktion anders
formuliert. Auf den nachfolgenden
Seiten werden die vier Funktionen
genauer erläutert.
Abb. 5.5.1 Subdivision
1
Im fortlaufenden auch Zelle oder Partition genannt.
75
5.5.1.1 SubDiv
Die Funktion SubDiv("Production", d, "Type", SameRule) unterteilt den Bereich, in dem eine Grammatik arbeitet, und ruft danach für jeden Teil eine Produktion auf. Die Produktion wird durch das erste
Argument bestimmt. Bei der Unterteilung geht die Funktion so vor, dass sie die Größe der jeweiligen
Zellen festlegt und nicht die Anzahl der Unterteilungen. D.h. jede Zelle besitzt eine genau festgelegte
Größe d, und der Bereich wird in soviel Zellen geteilt, wie Zellen der Größe d in den Bereich hineinpassen. Dabei kann die letzte Zelle eventuell nicht die volle Größe besitzen, sondern nur den Rest des
Bereichs erhalten, siehe Abb. 5.5.3. Die Größe (Breite oder Höhe, je nach dem ob eine vertikale oder
horizontale Unterteilungen vorgenommen wird) wird durch das zweite Argument d definiert.
Das dritte Argument bestimmt die Art der Subdivision. Hier kann entweder die Zeichenkette "X" oder
die Zeichenkette "Y" übergeben werden. "X" veranlasst eine horizontale Teilung, während "Y" eine
vertikale Unterteilung festlegt.
Das vierte Argument bestimmt, ob alle Zellen die gleiche Regel der zugeteilten Produktion ausführen,
für den Unterschied zwischen einer Regel und einer Produktion siehe Kapitel 5.1.4 Produktionen. D.h.
falls eine 1 übergeben wird, wird zu Beginn der Subdivision zufällig eine Regel aus der Produktion
ausgewählt und dann für alle Zellen ausgeführt. Bei einer 0 dagegen wird für jede Zelle zufällig eine
Regel aus der Produktion gewählt. Wofür wird dieses Argument benötigt? Sehr viele Gebäude, vor
allem Hochhäuser, besitzen innerhalb eines Stockwerks (Zeile) oder über mehrere Stockwerke hinaus
(Spalte) die gleichen Merkmale, z.B. Fenster vom gleichen Typ. Für solche Gegebenheiten wird das
Argument auf 1 gesetzt, damit wird für alle Bereiche (z.B. Synonym für Stockwerke) die gleiche Regel
(Synonym für Merkmal) ausgeführt.
Hier ein kleines Beispiel. Die Facade-Grammar aus Abb. 5.5.2 unterteilt eine Fassade in Zellen der
Größe 10. Da die Fassade in diesem Fall eine Breite von 45 besitzt, kann die letzte Zelle nur eine
Breite von 5 erhalten. Es entsteht die Unterteilung aus Abbildung 5.5.3. Zusätzlich wurde das letzte
Argument auf 1 gesetzt, d.h. nach der Subdivision wird aus der Produktion Tile, zufällig eine der beiden
Regel A oder B ausgewählt, siehe Kapitel 5.1.5 Wahrscheinlichkeiten. Diese Regel wird für alle Zellen
aufgerufen, in diesem Fall rein zufällig A. Gekennzeichnet wird dies innerhalb der Abb. 5.5.3, durch die
Buchstaben in den Zellen.
Main -> SubDiv("Tile", 10, "X", 1);
Tile -> A | B;
A -> ...;
B -> ...;
Abb. 5.5.2 SubDiv Grammatik
Abb. 5.5.3 SubDiv Ergebnis
5.5.1.2 Part
Im Gegensatz zur Funktion Subdiv, bei der die Größe der einzelnen Zellen festgelegt wurde, definiert
die Funktion Part("Production", n,"Type", SameRule) die Anzahl der Zellen. D.h. ein Bereich wird in
n Partitionen gespalten, wobei jede Partition die gleiche Größe besitzt. Nach der Unterteilung wird für
jede Zelle die Produktion "Production" aufgerufen, die eventuell für alle die gleiche Regel ausführt,
falls SameRule gleich 1 ist (s. Kapitel 5.5.1.1 SubDiv).
Abbildung 5.5.4 verdeutlicht die erweiterte Facade-Grammar von Abb. 5.5.2. Nachdem die Subdivision
durch die Funktion SubDiv ausgeführt (s. Abb. 5.5.3) und für alle Zellen die Produktion A aufgerufen
76
wurde, wird erneut eine Unterteilung durchgeführt. Dabei werden die bereits erzeugten Zellen in 4 gleich
große Partitionen gespalten. Dieser Vorgang wird in Abb. 5.5.5 dargestellt. Diesmal wurde zur Unterteilung die Funktion Part verwendet, welche eine vertikale statt einer horizontalen Teilung durchführt.
Außerdem wurde das letzte Argument auf 0 gesetzt, dies bedeutet, dass für jede Zelle eine zufällige
Regel C oder D ermittelt wird. Abbildung 5.5.5 verdeutlicht deshalb eines von sehr vielen möglichen
Ergebnissen, die durch die zwei Funktionen (SubDiv und Part) erzielt werden können.
Main -> SubDiv("Tile1", 10, "X", 1);
Tile1 -> A | B;
Tile2 -> C | D;
A
B
C
D
->
->
->
->
Part("Tile2", 4, "Y", 0);
...;
...;
...;
Abb. 5.5.4 Part Grammatik
Abb. 5.5.5 Part Ergebnis
5.5.1.3 Split
Die dritte Variante, den Bereich einer Mass-, Facade- oder Border-Grammar aufzuspalten, wird durch
die Funktion SplitX bzw. SplitY ermöglicht. Die Funktion SplitX führt eine horizontale Spaltung durch,
während die Funktion SplitY eine vertikale Spaltung ausführt. Anders als bei den vorherigen Methoden
(s. Kapitel 5.5.1.1 SubDiv und Kapitel 5.5.1.2 Part) können hier variabel viele Argumente übergeben
werden. Die genaue Angabe der Argumente wird durch die folgende Notation bestimmt.
SplitX("Production0", p0, "Production1", p1, ...)
SplitY("Production0", p0, "Production1", p1, ...)
Anstatt nun die Größe oder die Anzahl der Zellen festzulegen, werden hier prozentual die Bereiche definiert. Wird beispielsweise für p0 der Wert 0.3 übergeben, werden die ersten 30% des Bereichs in eine
Zelle gespalten. Für diese Zelle wird die Produktion "Production0" aufgerufen. Erhält danach p1 den
Wert 0.7, werden die hinteren 70% in eine zweite Zelle gespalten, für welche diesmal die Produktion
"Production1" aufgerufen wird. Dieser Vorgang ist variabel, und es können beliebig viele Argumente
übergeben werden und damit der Bereich in beliebig viele Zellen gespalten werden. Selbstverständlich
müsse die Werte immer zwischen 0 und 1 liegen und dürfen in der Summe nicht 1 überschreiten, da
ansonsten der Bereich der Grammatiken verlassen wird.
Ein Beispiel für den Einsatz einer Split Funktion wird in Abb. 5.5.6 und Abb. 5.5.7 dargelegt. Das Beispiel bedarf keiner weiteren Erklärung, da die Seite hier endet.
Main -> SplitX("A", 0.1, "B", 0.6, "C", 0.3);
A -> ...;
B -> ...;
C -> ...;
Abb. 5.5.6 Split Grammatik
Abb. 5.5.7 Split Ergebnis
77
5.5.2 Symmetrie
Kommen wir zur Formulierung von Symmetrien innerhalb der Subdivisionen. Die nachfolgenden
Erweiterungen betreffen nur die Funktionen SubDiv (s. Kapitel 5.5.1.2 SubDiv) und Part (s. Kapitel
5.5.1.2 Part) und können über ein zusätzliches Argument aktiviert werden. Wird beiden Funktionen als
zusätzliches fünftes Argument eine 1 übergeben, so wird damit eine symmetrische Unterteilung eingeleitet. D.h. anstatt für alle Zellen eine zufällige Regel aus der Produktion zu ermitteln (s. Kapitel 5.5.1.2
SubDiv und Kapitel 5.5.1.2 Part) oder für alle Zellen eine einzige zufällige Regel zu berechnen, werden
nun nur noch für die linke Hälfte der Unterteilung (einschließlich der mittleren Zelle, falls vorhanden)
zufällig Regeln ermittelt. Die rechte Hälfte erhält dann die gespiegelte Variante der linken Hälfte.
Die Vorgehensweise sieht folgendermaßen aus. Die Funktion beginnt von links bzw. unten und ermittelt
für jede Zelle eine zufällige Regel aus der Produktion. Dies geschieht so lange, bis die mittlere Partition
erreicht wurde. Bei jeder erzeugten Partition wird die Regel auf einen Stack gelegt, den sogenannten
Symmetry-Stack. Auch hier werden die neuen Daten immer ganz oben auf dem Speicher platziert (Push)
und es wird immer der oberste Datensatz vom Speicher geladen (Pop), wie bei einem normalen Stack.
Wurde die linke Seite der Subdivisionen zufällig ermittelt, wird die rechte Seite durch die Regeln auf
dem Symmetry-Stack bestimmt. Das heißt, jede Zelle, die sich rechts von der Mitte befindet, wählt ihre
Regeln nicht selbst aus, sondern holt sich die Regel von Symmetry-Stack. Dadurch wird auf der rechten
Hälfte eine Spiegelung erreicht. Zusätzlich wird während des Prozesses ständig ein Status verändert.
Dieser Status kann über die vordefinierte Konstante SYM abgefragt werden. SYM erhält den Wert 0,
falls eine Zelle der linken Hälfte erzeugt wird. Den Wert 1, wenn eine Zelle der rechten Hälfte generiert
wird und eine 2, falls eine ungerade Anzahl an Zellen existiert und die mittlere Zelle generiert wird.
Die Abb. 5.5.8 bildet eine neue Facade-Grammar ab. Die Grammatik führt eine horizontale Unterteilung
in 7 gleiche große Partitionen aus, siehe Abb. 5.5.9. Durch Übergabe einer 1 an das letzte Argument
der Part-Funktion wird eine symmetrische Unterteilung eingeleitet. Die ersten drei Zellen erhalten eine
zufällige Regel aus der Produktion Tile. Jede der ausgewählten Regeln wird auf den Symmetry-Stack
gelegt, so lange, bis die Mitte erreicht wird. Die Zelle der Mitte erhält ebenfalls eine zufällige Regel, legt
diese allerdings nicht auf den Stack. Sobald die erste Zelle der rechten Hälften erzeugt wird, wählt diese
nicht eine zufällige Regel aus, sondern holt sich die Regel vom Symmetry-Stack und löscht sie danach.
Das Resultat dieser Vorgehensweise
ist in Abb. 5.5.9 zu erkennen, dabei
Main -> Part("Tile", 7, "X", 0, 1);
bildet die Zeichnung eine von vielen
Tile -> A | B | C;
möglichen Lösungen ab.
Die Variable B verdeutlicht zusätzlich
A -> .../*Blue*/;
den Einsatz der vordefinierten Konstante SYM. Die Konstante wird innerB [1, 1, 1] {SYM == 0, SYM == 2, SYM == 1} ->
.../*Green*/ | .../*Red*/ | .../*Green*/;
halb der Bedingungen eingesetzt und
sorgt dafür, dass je nach Status eine
C -> .../*Orange*/;
andere Regel ausgewählt wird. Aus
diesem Grund wird die mittlere Zelle
Abb. 5.5.8 Symmetrie Grammatik
rot dargestellt, während die beiden äußeren Zellen von B, in grün dargestellt
werden.
Abb. 5.5.9 Symmetrie Ergebnis
78
5.6 Umwelt
Wie Pflanzen erhalten auch Gebäude Einfluss durch ihre lokale sowie globale Umwelt, beziehungsweise
werden Gebäude in den meisten Fällen schon während des Entwurfs der Umgebung angepasst und
dementsprechend gebaut. Zum Beispiel werden die Türen eines Gebäudes häufig in die Nähe der Straße
gelegt. Oder, je dichter die Population innerhalb eines Gebietes ist, desto mehr Wohnraum wird benötigt.
Dies führt zu größeren und höheren Wohnhäusern. Aber auch kleine Details können die Informationen
der Umgebung verwenden. So könnte eine Wand von Efeu bedeckt sein, wenn diese sich in der Nähe
eines Waldes befinden. Grenzt die Wand allerdings an eine Straße, so zieren stattdessen Blumenkästen
die Fenster.
In Gegensatz zu den in Kapitel 3.6 Umgebungssensitive und offene Lindenmayer-Systeme erklärten umweltsensitiven L-Systemen werden hier keine speziellen Anfrage-Module benötigt, stattdessen kann die
Umwelt über normale Funktionen Anfragen beantworten.
Im Laufe dieses Kapitels wird die Funktionsweise sowie Abfrage der globalen und lokalen Eigenschaften erklärt und anhand praktischer Beispiele verdeutlicht.
5.6.1 Globale Umwelt
Die globalen Eigenschaften beschreiben die nicht an einen lokalen Ort gebundenen Eigenschaften der
Umwelt, wie bereits in Kapitel 3.6 Umgebungssensitive und offene Lindenmayer-Systeme aufgeführt.
Es wurden drei Eigenschaften der globalen Umwelt implementiert, zu diesen zählen die Temperatur, der
Niederschlag und die Bevölkerungsdichte.
(1) Temperatur
Diese Eigenschaft bestimmt die minimale, maximale und durchschnittliche
Temperatur der Region.
Die Eigenschaft beschreibt den minimalen, maximalen und mittleren Nieder(2) Niederschlag
schlag innerhalb der Region.
(3) Populationsdichte Die Eigenschaft bestimmt die durchschnittliche Bevölkerungsdichte je Quadratkilometer.
Um eine Vorstellung davon zu erhalten, in welchen Größenverhältnissen sich die Werte dieser Eigenschaften bewegen, folgen ein paar realistische Werte [Bro882]: Im Bereich Frankfurt beträgt die mittlere
Niederschlagsmenge 55 mm im Monat Mai und die mittlere tägliche Temperatur 14,5° C (über das gesamte Jahr). Die Bevölkerungsdichte in Mainz liegt bei 182 Einwohnern je km2.
Die Populationsdichte kann beispielsweise die Größe eines Hauses und dessen Anzahl an Stockwerke
beeinflussen. Der maximale Niederschlag bestimmt dagegen, ob die Gebäude eine Regenrinne an der
Traufe erhalten.
Die Abfrage innerhalb der Grammatik erfolgt über die Funktion GEnv("Property"). Das einzige Übergabeargument ist eine Zeichenkette, die angibt welche globale Eigenschaft abgerufen werden soll.
Mögliche Werte für das Argument sind "MinTemperature", "MaxTemperature", "AvgTemperature",
"MinRainfall", "MaxRainfall", "AvgRainfall" und "PopulationDensity". Wird z.B. "AvgRainfall" als
Argument übergeben, liefert die Funktion den Wert für die mittlere Niederschlagsmenge zurück. Dies
wäre zum Beispiel der oben erwähnte Wert von 55 mm.
Die Umsetzung und Anfrage ist demnach sehr einfach, verständlich und erfolgt über eine einzige
Funktion. Diese kann innerhalb der Grammatik beliebig eingesetzt werden, z.B. als Teil einer Bedingung,
als Faktor einer Regel-Wahrscheinlichkeit, usw. Die Eigenschaften lassen sich sehr leicht in das System
integrieren und könnten noch um zusätzliche Eigenschaften ausgebaut werden, beispielsweise, um
die relative Luftfeuchtigkeit, die mittlere Windgeschwindigkeit, die tägliche Sonnenscheindauer oder
ähnliche Eigenschaften.
79
5.6.2 Lokale Umwelt
Die lokale Umwelt spiegelt die meist
physischen an einen Ort gebundenen
Eigenschaften der Umgebung wieder. Zum
Beispiel die in der Nähe eines Gebäudes
verlaufenden Straßen oder Flüsse. Aber
auch beispielsweise die Position der anderen
Gebäude, wodurch ermittelt werden kann,
ob das Gebäude vollständig von anderen
Gebäuden umzingelt ist und sich deshalb in
einem Wohnblock befindet.
Die eigentliche Realisierung der lokalen
Umgebung wurde mit Hilfe einer Rasterung
erreicht, wodurch eine schnelle Analyse der
Umgebung erzielt werden kann. Folglich wird
ein Raster über die Umgebung gelegt. Diese
wird entsprechend dem Raster unterteilt und
ordnet jedem Feld1 eine Information bzw.
einen Typ zu.
In Abbildung 5.6.1 ist eine Landschaft aus
dem Spiel Anno 1701 zu sehen. Wird über
diese Landschaft ein Umgebungsraster
gelegt, entsteht das Beispielmuster aus Abb.
5.6.2. Die verschiedenen Farben der Kacheln
stellen jeweils einen anderen Umgebungstyp
dar, die unterschiedlichen Typen werden im
Kapitel 5.6.2.1 Typen erklärt. Im Gegensatz
zu den globalen Eigenschaften ist die
Abfrage der lokalen Eigenschaften nicht
mehr so einfach. Um eine Information über
die naheliegende Umgebung zu erhalten,
muss die lokale Umgebung (Raster)
abgetastet werden. Zu diesem Zweck wurden
verschiedene Abtast-Algorithmen eingeführt.
Die verschiedenen Algorithmen werden in
Kapitel 5.6.2.2 Abtastung beschrieben und
die Funktionen zur Abfrage schließlich in
Kapitel 5.6.2.3 Anfrage-Funktionen.
1
im fortlaufenden auch Kachel genannt.
80
Abb. 5.6.1 Umgebung
Abb. 5.6.2 Umgebungsraster
5.6.2.1 Umgebungstypen
Wie bereits beschrieben wurde, wird die Umgebung in Kacheln aufgeteilt, und jeder Kachel wird ein
Umgebungstyp zugewiesen. Dieser Typ wird durch die Merkmale innerhalb des Bereichs der Kachel
bestimmt. Befindet sich beispielsweise ein Baum innerhalb einer Kachel, so wird dieser der Typ Flora
zugewiesen. Zurzeit existieren sechs verschiedene Umgebungstypen: Wasser, Flora, Gebirge, Straßen,
Gebäude und freie Flächen.
(1) Freie Fläche Die Kachel weist keinerlei besondere Merkmale auf, d.h. keine der darauf folgenden Typen kann dieser Fläche zugewiesen werden.
Innerhalb der Kachel befinden sich Bäume, Sträucher oder ähnliche Pflanzen.
(2) Flora
Große Steine, Felsen oder Teile eines Gebirges füllen den größten Teil der Kachel aus.
(3) Gebirge
Die Kachel liegt zum größten Teil im Wasser. Dies können Teile des Meers, eines
(4) Wasser
Flusses, eines Teichs oder Ähnliches sein.
Feldwege, gepflasterte Straßen oder sonstige Pfade füllen die Kachel aus und bil(5) Straßen
den damit das Merkmal dieser Kachel.
Innerhalb der Kachel befinden sich Teile eines Gebäudes, dies können Wände oder
(6) Gebäude
sonstige Details sein.
Erneut wird auf die Abbildung 5.6.2 zurückgegriffen. Innerhalb der Abbildung werden bereits alle
vorhandenen Umgebungstypen dargestellt. Die dunkelgrünen Kacheln stellen dabei freie Bereiche
dar, die hellgrünen Kacheln stehen für Flora, die gelben für ein Gebirge, die blauen für Wasser, die
hellgrauen Kacheln weisen Straßen auf und zu guter letzt die roten Felder, die das Vorkommen an
Gebäuden kennzeichnen.
5.6.2.2 Abtastung
Bei einer Anfrage an die lokale Umwelt kann die Umgebung durch verschiedene Verfahren analysiert
werden. Möchte eine Grammatik zum Beispiel die Anzahl der nah verlaufenden Straßen erhalten, so
könnte die Umwelt um einen Punkt gleichmäßig in alle Richtungen abgetastet werden. Durch diese
Methode würde die Grammatik Informationen über die komplette, nahliegende Umgebung erhalten.
Dies wäre nicht sinnvoll, wenn beispielsweise eine einzelne Wand, Auskunft darüber erhalten möchte,
ob sie in der Nähe einer Straße liegt. Aus diesem Grund wurden vier verschiedene Abtast-Methoden
eingeführt. Eine ist die bereits erwähnte Abtastung um einen Punkt herum, eine weitere die Abtastung
entlang einer Wand/Fläche, die Dritte bzgl. einer Ecke und als Viertes, die Abtastung der Umwelt
von einem Punkt ausgehend in eine beliebige gerade Richtung. Die jeweilige Analyse wird dadurch
unterschieden, welche Startinformation für die Abtastung zu Verfügung steht. Dies ist entweder ein
einzelner Punkt, eine Fläche, eine Ecke oder ein Punkt mit einer Geraden.
Bei allen vier Abtast-Methoden werden beliebig viele Kacheln des Rasters durchlaufen. Für jede Kachel, die während des Abtastens durchlaufen wird, wird ein passender Zähler um eins inkrementiert.
D.h. für jeden Umgebungstyp existiert ein Zähler, welcher vor dem Abtasten mit null initialisiert wird
und nach dem Abtasten Auskunft darüber gibt, wie viele Kacheln des Typs sich in der Nähe befinden.
Der direkte Wert des Zählers liefert eine absolute Information über die Umgebung, zum Beispiel, dass
5 Kacheln des Typs Gebirge gescannt wurden. Wird der Zähler durch die Anzahl aller durchlaufenden
Kacheln dividiert, erhält man eine relative Information der Umgebung. Zum Beispiel, dass 50 % der
abgetasteten Umgebung von einem Gebirge belegt wird.
81
5.6.2.2.1 Punkt-Abtastung
Die einfachste Variante, die Umgebung zu scannen ist, alle um einen Punkt liegende Kacheln abzufragen.
Dabei werden die Kacheln des eigenen Gebäudes ignoriert, da die Informationen über die eigenen
Bereiche nicht sinnvoll wären. Schließlich will das Gebäude die Umgebung analysieren und nicht sich
selbst.
Abbildung 5.6.3 (a) zeigt die Iso-Sicht(Draufsicht) eines Gebäudes samt Umgebungsraster. Die roten
Kacheln innerhalb der Abbildung verdeutlichen den Bereich des Gebäudes. Der Ausgangspunkt für die
Abtastung wird durch den grünen Punkt dargestellt.
Da die roten Kacheln beim Abtasten der Umgebung ignoriert werden, wird mit der ersten Kachel außerhalb des roten Bereichs begonnen. Das System läuft alle Felder rings um das Gebäude ab und zählt
jeweils die Umgebungstypen, siehe Abb. 5.6.3 (b). Wurden alle Felder gezählt, werden die Werte entweder absolut oder relativ zurückgegeben. D.h. entweder wird direkt der absolute Wert verwendet, beispielsweise das 4 Straßen-Kacheln gezählt wurden. Oder aber, die Zähler der jeweiligen Typen werden
durch die Anzahl aller gelesenen Felder dividiert, dadurch liegen alle Werte zwischen 0 und 1. Wurden
z.B. 4 Kacheln von Typ Straße gezählt und insgesamt 16 Felder durchlaufen, ergibt dies einen relativen
Wert von 0.25. Das bedeutet, dass fünfundzwanzig Prozent der Umwelt durch Straßen belegt werden.
Nach einer Iteration muss der Vorgang nicht unbedingt beendet werden, es können noch weitere Stufen
durchlaufen werden. Dazu werden alle Kacheln der nächsten Stufe gezählt, wie in Abb. 5.6.3 (c) zu sehen
ist. Soll der absolute Wert berechnet werden, können die Zähler für die jeweiligen Umgebungstypen
einfach erhöht werden. Soll der relative Wert berechnet werden, erhalten alle weiteren Kacheln eine
Gewichtung. Die Gewichtung entspricht der reziproken Nummer der Iteration, d.h. in der ersten Iteration
(s. Abb. 5.6.3 (a)) erhalten alle Kacheln eine Gewichtung von 1, in der zweiten Iteration (s. Abb. 5.6.3
(b)) erhalten die Kacheln eine Gewichtung von ½, usw. Normiert werden die Kacheln durch die Division
mit der Summe aller Kacheln. Es gilt demnach, je weiter eine Kachel entfernt ist, desto schwächer wird
deren Gewichtung. Dadurch üben naheliegende Kacheln einen größeren Einfluss auf das Gebäude aus,
als weit entfernte Kacheln.
Abb. 5.6.3 (a) Iso-Sicht der Umgebung, (b) erste Iteration der Punkt-Abtastung und
(c) zweite Iteration der Punkt-Abtastung
5.6.2.2.2 Flächen-Abtastung
Eine weitere Methode, die Abtastung der Umgebung durchzuführen, ist die Abtastung bzgl. einer
Fläche. Dabei wird jeweils ein Strahl von den beiden äußeren Kanten der Fläche losgeschickt. Beide
Strahlen laufen in die Richtung der Flächen-Normale, wobei auch hier die Kacheln des Gebäudes
ignoriert werden. Damit bilden die beiden ersten, von den Strahlen getroffenen Kacheln (außerhalb des
Gebäudebereichs) einen Start- und Endpunkt. Anstatt nun alle Kacheln außerhalb des Gebäudebereichs
zu zählen, werden nur die Felder zwischen dem Start- und Endpunkt gezählt, siehe Abb. 5.6.4 (b). Wie
82
bei der Punkt-Abtastung können die Umgebungsinformation absolut oder relativ berechnet werden.
Außerdem können weitere Iterationen ausgeführt werden, in dem die Strahlen bis zu den nächsten
Kacheln weitergeschickt werden. Die so neu ermittelten Kacheln dienen wieder als Start- und Endpunkt,
siehe Abb. 5.6.4 (c). Ebenfalls wie bei der Punkt-Abtastung werden die Kacheln bei jeder weiteren
Iteration geringer gewichtet, falls eine relative Anfrage an die Umgebung gestellt wird.
Wie die Abbildungen aus 5.6.4 verdeutlichen, werden nur die Kacheln abgetastet, die sich vor der Wand
befinden. Eine Fläche erhält dadurch keine für sie unwichtigen Informationen von Kacheln, die sich
hinter der Fläche befinden.
Abb. 5.6.4 (a) Iso-Sicht der Umgebung, (b) erste Iteration der Flächen-Abtastung und
(c) zweite Iteration der Flächen-Abtastung
5.6.2.2.3 Kanten-Abtastung
Die Kanten- bzw. Ecken-Abtastung funktioniert ähnlich wie die Flächenabtastung, nur diesmal werden
zwei Strahlen von einem Punkt ausgehend verschickt. Die Abb. 5.6.5 (a) zeigt eine Ecke, die durch einen grünen Punkt dargestellt wird. Für diese Ecke soll nun eine Abtastung der Umgebung durchgeführt
werden. Wie bei der Flächenabtastung werden zwei Strahlen verschickt. Diese starten beide aus einem
gemeinsamen Punkt, der dem Startpunkt der Kante bzw. Ecke entspricht. Die beiden Strahlen sind
durch die Normalen der mit der Ecke verbundenen Flächen gegeben. Auch hier bilden die beiden ersten
Kacheln, die von den Strahlen getroffen werden, einen Start- und Endfeld. Die Umgebungstypen aller
Felder zwischen den beiden Kacheln werden gezählt und deren Ergebnis absolut oder relativ zurückgegeben, wie in Abb. 5.6.5 (b) gezeigt wird. Wie schon bei der Punkt- und Flächen-Abtastung können
weitere Iterationen durchgeführt werden, siehe Abb. 5.6.5 (c).
Abb. 5.6.5 (a) Iso-Sicht der Umgebung, (b) erste Iteration der Kanten-Abtastung und
(c) zweite Iteration der Kanten-Abtastung
83
5.6.2.2.4 Punkt-Gerade-Abtastung
Die letzte Variante zum Abtasten der lokalen Umgebung wird vom einen Punkt aus gestartet und verschickt einen Strahl in eine beliebige Richtung. Das erste Feld außerhalb des Gebäudebereichs, das vom
Strahl getroffen wird, erhöht den Zähler des jeweiligen Umgebungstyps. Bei jeder Iteration wird nur ein
Feld gelesen und deshalb jeweils nur ein Zähler inkrementiert. Ansonsten gelten alle üblichen Regeln
für absolute bzw. relative Informationen, wie sie bereits bei den vorherigen Abtast-Methoden erklärt
wurden.
Mit Hilfe dieser Methode können einzelne Objekte Anfragen an die Umwelt stellen. Zum Beispiel
könnte ein Fenster über diese Abfrage herausfinden, ob sich ein Baum, ein Gebäude oder Ähnliches
direkt vor ihm befindet.
Abb. 5.6.6 (a) Iso-Sicht der Umgebung, (b) erste Iteration der Punkt-Gerade-Abtastung und
(c) zweite Iteration der Punkt-Gerade-Abtastung
5.6.2.3 Anfrage-Funktionen
Dieses Unterkapitel beschreibt, wie die im vorherigen Kapitel erklärten Abtast-Methoden innerhalb
der Grammatik aufgerufen werden können. Dazu wurden drei Funktionen implementiert: Env, EnvP
und EnvPN. Alle drei Funktionen führen jeweils eine Abtastung der Umgebung durch und liefern als
Rückgabe den absoluten oder relativen Wert eines Umgebungstypen-Zählers. Die Rückgabewerte
können dann zum Beispiel die Größe eines Objektes verändern, die Wahrscheinlichkeit einer Regel
beeinflussen etc.
Im Gegensatz zu den umweltsensitiven L-Systemen aus Kapitel 3.6 Umgebungssensitive und offene
Lindenmayer-Systeme werden keine speziellen Anfrage-Module benötigt. Da Funktionen in dem neuen
System beliebige Rückgabewerte erzeugen können, müssen keine undefinierten Parameter durch ein
spezielles Anfrage-Modul beschrieben werden.
Die Funktion Env("EnvironmentType", ScanLevels, Absolute) ist die erste der drei lokalen Umgebungsfunktionen. Die Argumente der Funktion werden durch die folgende Tabelle erklärt.
"EnvironmentType"
84
Durch die Zeichenkette wird bestimmt, nach welchem Typ die Umgebung
gescannt werden soll. Genauer gesagt, welcher Zähler den Rückgabewert
bildet. Zulässig sind die englischen Begriffe der in Kapitel 5.6.2.1 aufgelisteten
Umgebungstypen, zu diesen zählen "Empty", "Nature", "Street", "Building",
"Water" und "Mountain".
ScanLevels
Absolute
Das Argument bestimmt die Anzahl der Iterationen, die beim Abtasten der
Umgebung ausgeführt werden, und damit die Distanz, bis zu welcher das
Umgebungsraster abgetastet wird.
Durch das Argument wird festgelegt, ob die Funktion den relativen oder
absoluten Wert des Zählers zurückgibt. Wird eine 0 übergeben, werden die
Zähler relativ berechnet, entsprechend der Regel aus Kapitel 5.6.2.2.1 PunktAbtastung. Ansonsten werden die Werte absolut ermittelt und zurückgegeben.
Als Rückgabe liefert die Funktion den relativen bzw. absoluten Zähler des angeforderten Umgebungstyps.
Offen bleibt die Frage, welche Abtast-Methode von der Funktion verwendet wird. Die Art der Methode
ist abhängig von der Grammatik, welche die Funktion ausführt. Handelt es sich um eine Mass-Grammar,
so wird eine Punkt-Abtastung durchgeführt. Bei einer Facade-Grammar wird eine Flächen-Abtastung
verwendet und bei einer Border-Grammar eine Kanten-Abtastung.
Der Ausgangspunkt für die Punkt-Abtastung wird durch den Mittelpunkt des Gebäudes bestimmt. Bei
einer Flächenabtastung sind die beiden Startpunkte die äußeren Punkte der Fassade und die beiden
Strahlen die Normalen der Fassade. Bei einer Border-Grammar entspricht der Startpunkt für die Abtastung dem Ursprung der Border-Grammar. Die beiden Strahlen werden durch die Normalen der benachbarten Fassaden bestimmt.
Die Funktion bleibt völlig unbeeinflusst von der aktuellen Transformation. Das heißt, die Funktion liefert immer das gleiche Ergebnis zurück, egal, wann sie innerhalb der Grammatik aufgerufen wird.
Eine weitere Möglichkeit, Anfragen an die Umgebung zu stellen, wird durch die Funktion
EnvP("EnvironmentType", ScanLevels, Absolute) ermöglicht. Die Argumente der Funktion besitzen
die gleiche Bedeutung wie die der bereits beschriebenen Env-Funktion. Allerdings führt die Funktion
immer eine Punkt-Abtastung (siehe Kapitel 5.6.2.2.1 Punkt-Abtastung) aus, unabhängig davon ob sie
innerhalb eine Mass-, Facade- oder Border-Grammar aufgerufen wird.
Im Gegensatz zu Env-Funktion wird diese Funktion durch die Transformations-Sequenz beeinflusst.
Genauer gesagt, der Ausgangspunkt für die Punkt-Abtastung wird durch die Verschiebung des aktuellen
Transformations-Zustands bestimmt, oder anders gesagt durch den Ursprung des aktuellen Koordinatensystems.
Die dritte Anfrage-Funktion ist die EnvPN("EnvironmentType", ScanLevels, Absolute) Funktion. Auch
hier besitzen die Argumente die gleiche Bedeutung wie die der Env-Funktion. D.h. "EnvironmentType"
bestimmt den Rückgabe-Zähler, ScanLevels die Anzahl der Iterationen und Absolute definiert, ob ein
relativer oder absoluter Wert zurückgegeben wird.
Die EnvPN-Funktion verwendet immer eine Punkt-Gerade-Abtastung (siehe Kapitel 5.6.2.2.4 PunktGerade-Abtastung), dabei wird der Ausgangspunkt durch den Ursprung des aktuellen Koordinatensystems
bestimmt und die Gerade durch die inverse z-Achse des aktuellen Koordinatensystems.
85
86
6. Resultate
Im vorherigen Kapitel 5 Konzept wurde das konzep­
tionierte und realisierte System beschrieben, mit dessen
Hilfe Regeln (Grammatiken) für die verschiedenen Gebäudetypen formuliert werden können. Aus diesen Regeln kann das System dann beliebig viele Variationen
des Typs erzeugen. In diesem Kapitel werden schließlich ein paar Anwendungsbeispiele erläutert und dargestellt.
Die Abbildung 6.1 verdeutlicht zum einen ein Mansarddach und zum anderen ein spitz zulaufendes Regeldach. Die Dachkonstruktionen wurden jeweils durch
das Straight-Skeleton erzeugt und die Form nachträglich durch eine Profile-Grammar verändert. Aus den
Beispiel ist bereits ersichtlich, dass jede der typischen
Dachformen (siehe Kapitel 2.2.2 Dachformen) über das
System konstruiert werden kann.
Das Bauwerk aus Abb. 6.2 und Abb. 6.3 soll hauptsächlich
den Einsatz der Facade- und Border-Grammars zeigen.
Wie üblich bei solchen Bauwerken, besteht das unterste
Stockwerk aus einer Stein- und die oberen Stockwerke
aus einer Holzkonstruktion, bei denen die einzelnen
Stockwerke etagenweise herausragen. Über die in
Kapitel 5.5 Subdivision und Symmetrie beschriebenen
Funktionen wurde die Fassade in einzelne Zellen
unterteilt, in denen ein zufälliges und symmetrisches
Fachwerkmuster eingebaut wird. Falls ein Fenster erzeugt
wird, erhält dieses jeweils einen linken und rechten,
zufällig ausgerichteten, Fensterladen. Außerdem erhält
das Dach einen Schornstein in der Nähe des Firsts und
entlang der Traufe mehrere Holzbalken, die unter dem
Dach hervortreten.
Der kleine Nebentrakt besteht lediglich aus einer
Balkenkonstruktion. Die Balken wurden mit Hilfe
einer Border- und Facade-Grammar realisiert. Da dem
Primitiv keine Profile-Grammar zugewiesen wird,
werden keine Wände für das Primitiv erzeugt, und es
sind deshalb ausschließlich die Balken sichtbar.
Zusätzlich besteht die Möglichkeit, dass Efeu eine der
unteren Wände bedeckt. Realisiert wurde der Efeu
mit der Hilfe eines einzigen Moduls, welches drei
Regeln und jeweils eine passende Bedingung enthält.
Die Bedingungen sorgen dafür, dass der Efeu nicht
den Bereich der Wand verlässt und um ein eventuell
vorhandenes Fenster herum wächst. Die drei Regeln
bestimmen die Fortpflanzung des Efeus. Dabei wächst
der Efeu entweder in eine Richtung weiter, erzeugt eine
Verzweigung oder hört ganz auf zu wachsen.
Abb. 6.1 Dachkonstruktionen
Abb. 6.2 Fachwerkhaus
Abb. 6.3 Fachwerk-Fassade
87
Der Gebäudetyp aus Abbildung 6.4 und 6.5 verdeutlicht den Entwurf von modernen Hochhäusern, unter
verstärkter Berücksichtigung der Umwelt. Beispielsweise passen die einzelnen Häuser ihre Größe entsprechend den umliegenden Gebäuden an. D.h. Gebäude, die in den Außenbezirken liegen, sind kleiner
als Gebäude, die sich mitten in einem Ballungsgebiet befinden. Weiterhin werden Balkone niemals an
Wänden erzeugt, die direkt neben einem anderen Haus liegen. Das Gleiche gilt für Fenster, allerdings
in etwas abgeschwächter Form. Das heißt, Fenster dürfen zwar mit geringer Wahrscheinlichkeit an
Wänden platziert werden, die direkt an ein anderes Gebäude grenzen, aber wenn sie dies tun, sind sie
schmaler als die üblichen Fenster des Gebäudes.
Weiterhin können eine große Anzahl an verschiedenen Masse-Modellen erzeugt werden, u. a. die üblichen
I-, H-, U-, T- und L-Formen, bei denen der Haupttrakt und die Nebentrakte eine zufällige Größe erhalten.
Auch hier besitzen die untersten Stockwerke eine andere Fassade als die darüber liegenden Stockwerke.
Außerdem unterscheiden sich die Fassaden aufgrund der Umgebung, zum Beispiel erhalten Fassaden des
untersten Stockwerks Schaufenster, wenn sie an eine Straße grenzen (siehe Abb. 6.5). Solche Fassaden
erhalten ebenfalls höchstwahrscheinlich die Eingangstür des Gebäudes, welche wiederum eine Treppe
erhalten kann, usw.
Obwohl Walmdächer vorhanden sind, stellen diese eine Seltenheit dar und treten häufiger in den Außenbezirken auf. Die meisten Gebäude besitzen Flachdächer, auf denen eventuell ein Treppenhaus angebracht wird.
In Abbildung 6.7 wird der implementierte Editor dargestellt. Über den Editor können die unterschiedlichen Gebäudetypen angelegt, die Gruppen verwaltet, die lokale Umgebung verändert und sonstige
Einstellungen vorgenommen werden. Außerdem können die verschiedenen Grammatiken in einem
Fenster editiert werden, und es werden entsprechende Informationen, Warnungen und Fehlermeldungen
über ein Ausgabefenster angezeigt.
Abb. 6.4 Virtuelle Stadt
88
Abb. 6.5 Modernes Gebäude
Abb. 6.6 Fachwerkhaus
Abb. 6.7 Editor
89
90
7. Schlussbemerkungen
7.1 Fazit
Im Großen und Ganzen erweist sich der Einsatz von Grammatiken bzw. stark ausgebauten Linden­mayerSystemen als geeignetes Mittel, um Regeln für Bauwerke aufzustellen. Die eingeführten Änderungen
an der Definition und der Syntax, die automatische Anpassung der Wahrscheinlichkeiten und weitere
Anpassungen (siehe Kapitel 5.1 Regelbasierte System) ermöglichen die Aufstellung von übersichtlichen
Grammatiken und sorgen für gezielte Transformationen der einzelnen Gebäudeteile. Durch den Vorteil
der Substitution von Grammatiken können mit wenig Regeln rekursive Konstruktionen wie Stockwerke,
Treppenstufen und Ähnliches formuliert werden.
Ebenfalls als sehr effektiv erweisen sich die implementierten Subdivision-Verfahren (siehe Kapitel 5.5
Subdivision und Symmetrie), mit deren Hilfe sich schnell und verständlich Fassaden anfertigen lassen.
Durch eine geringe Anzahl an Regeln kann die Fassade zerlegt werden und innerhalb der einzelnen Teile
können zufällige und evtl. symmetrisch angeordnete Strukturen wie Fenster, Türen, Fachwerkmuster
und vieles mehr generiert werden. Durch diese Unterteilungen erhalten die Fassaden geordnete Strukturen und es entstehen keine chaotischen Anordnungen.
Im Gegensatz zu den vorherigen Arbeiten lassen sich die einzelnen Bereiche des Gebäudes logisch
trennen und auf die verschiedenen konzeptionierten Grammatiken (siehe Kapitel 5.2 Grammatiken)
aufteilen. Diese Aufspaltung trägt stark zur Übersichtlichkeit und Verringerung der Komplexität bei,
woraus wiederum eine geringere Fehleranfälligkeit resultiert. Weiterhin können die einmal aufgestellten
Grammatiken so effektiv wiederverwendet werden: z.B. kann eine Facade-Grammar von jeder beliebigen Mass-Grammar aufgerufen werden und damit bei einer großen Anzahl von Gebäudetypen zum
Einsatz kommen.
Eine Schwachstelle der bisherigen Arbeiten war die Dachkonstruktion. Hier erweist sich das StraightSkeleton als mächtiges Mittel, und in Kombination mit einer Profile-Grammar können sehr komplexe,
vielfältige und so gut wie alle Dachformen gebildet werden, auf denen dann optimal Dachgauben und
sonstige Modelle platziert werden können.
Einer der wesentlichsten Vorteile des Systems liegt in der Möglichkeit, mit einfachen Methoden die
Gebäude an ihre lokale und globale Umgebung (siehe Kapitel 5.6 Umwelt) anzupassen. In den meisten
Fällen reichen ein oder zwei Aufrufe der vordefinierten Anfrage-Funktionen aus, um einen gezielten
Effekt zu erreichen. Solch ein Effekt könnte beispielsweise die Anpassung der Fenstergrößen oder deren
Vorkommenswahrscheinlichkeit sein.
Genauso effektiv wie simpel ist der Einsatz von Gruppen, über die Modelle oder Texturen schnell und
sinnvoll verwaltet und von den Grammatiken selektiert werden können. Sollen Objekte (z.B. Fenster) variieren, müssen keine speziellen Regeln innerhalb der Grammatiken eingebaut werden, sondern
­lediglich die verschiedenen Objekte einer Gruppe zugeordnet werden. Dadurch werden Regeln aus der
Grammatiken ausgelagert und die Komplexität der Grammatiken sinkt.
Trotz all der Verbesserungen müssen für komplexe Gebäude immer noch komplizierte Grammatiken
aufgestellt werden. Diese benötigen Zeit zur Formulierung und vor allem Verständnis über die
Funktionsweise von Grammatiken sowie deren Kommunikation. D.h. der Nutzer des Systems sollte
bereits Vorkenntnisse in der Programmierung oder besser noch in der theoretischen Informatik besitzen,
damit ein Verständnis der Funktionsweise von Grammatiken vorhanden ist. Zusätzlich ist selbst bei
entsprechenden Vorkenntnissen eine Einarbeitungszeit unvermeidbar. So wird beispielsweise zur
Erstellung der sehr abstrakten Profile-Grammars oder für Optimierungen innerhalb der Grammatiken
einiges an Erfahrungen benötigt.
Die Berechnungszeit eines Gebäudes ist stark von dessen Komplexität abhängig, d.h. von der Anzahl
der Regeln, Verschachtelungen, Struktur der Dachkonstruktion usw. Obwohl hier noch Verbesserungen
vorgenommen werden könnten, liegt sie in einem akzeptablen Bereich. Ebenfalls gut, aber durchaus
91
noch verbesserungsbedürftig ist die Performance beim Rendering. Durch einfache Methoden (z.B. Ausblenden von Objekten an einer Fassade, die der Betrachter nicht sehen kann) und modernen Verfahren
(Stichwort: Hardware Instancing) können bereits relativ gute Laufzeiten erreicht und mehrere hundert
Gebäude in Echtzeit dargestellt werden. Selbstverständlich wächst und sinkt die Performance abhängig
von der Komplexität der darzustellenden Gebäude.
Der Speicherverbrauch ist im Vergleich zu den bisherigen Arbeiten einer der großen Vorteile. Dadurch
das komplexe Objekte (wie Fenster, Türen, usw.) vorgefertigt geladen werden und deshalb nur einmal den Speicher belegen, Texturen wiederverwendet werden können und die Primitive auf Grund der
­CutOut-Modelle (siehe Kapitel 5.4.1.3 CutOut-Modell) keine komplexe Strukturen bilden müssen, wird
ein sehr geringer Speicherverbrauch erreicht. Dieser liegt ungefähr zwischen 10 und 200 kByte pro
Gebäude. Natürlich soll hier kein falscher Eindruck vermittelt werden, im schlechtesten Fall werden
für eintausend Gebäude rund 200 MByte benötigt, dies ist für ein Computerspiel oft nicht akzeptabel.
Dafür sind die Variationen sowie die Komplexität bei derartigen Gebäuden sehr hoch und die Gebäude
unterscheiden sich in allen Bereichen (Masse-Modell, Dachkonstruktion, Fassaden, etc).
Obwohl die Ergebnisse recht ansehnlich sind, kann nicht der Qualitätsstandard erreicht werden, der
­mittlerweile innerhalb der Videospiel-Branche üblich ist. Der größte Kritikpunkt liegt bei der momentan
sehr eingeschränkten Texturierung der Gebäude. Solange diese nicht verbessert wird, ohne dabei einen
zu hohen Speicherverbrauch zu erhalten, ist es nicht sinnvoll, komplette Gebäude durch das System
erstellen zu lassen. Dies gilt zu mindestens für den Einsatz in Computerspielen mit hohen Standards.
Da das System sehr flexibel ist, wäre es vorstellbar, die Gebäude vollständig aus vorgefertigten Modellen zusammenzubauen. Dadurch würde das Problem der Texturierung umgangen, es müsste allerdings
auf einen Großteil der Vielfalt verzichtet werden. So könnten ohne den Einsatz von sichtbaren Primitiven komplett vorgefertigte Stockwerke, Fenster, Türen und vieles mehr von dem System zufällig
zusammengesetzt werden. Trotz allem könnten die Gebäude die Vorteile des Systems nutzen und beispielsweise entsprechend auf ihre Umwelt reagieren.
7.2 Ausblick
Zum Schluss folgt eine kleine Beschreibung an Vorschlägen, wie das realisierte System noch verändert,
ausgebaut und verbessert werden könnte.
An erste Stelle steht hier eine Verbesserung des vorhandenen Editors. In dem Editor könnten weitere
Mittel eingesetzt werden, um die Formulierung der Grammatiken, die Verwaltung von Gruppen, die
Änderung von Einstellungen und vieles mehr zu erleichtern. Beispielsweise könnten die innerhalb einer
Grammatik definierten Konstanten über eine grafische Schnittstelle dargestellt und verändert werden.
Da solche Konstanten meistens die Anzahl der Stockwerke, die Größe der einzelnen Fachwerkmuster
und ähnliche Eigenschaften definieren, wäre es praktisch, wenn diese über Eingabefenster oder Regler
verändert werden könnten und sich damit die parametrische Kontrolle verbessert.
Zusätzlich wäre eine fünfte Grammatik vorstellbar, eine so genannte Group-Grammar. Einer Gruppe
könnte eine Group-Grammar zugewiesen werden und über deren Regeln die Rückgabe der Objekte
steuern. Falls nun eine Grammatik zufällige Objekte aus der Gruppe anfordert, entscheidet die Gruppe
anhand ihrer Regeln aus der Group-Grammar (dazu zählen u. a. die Wahrscheinlichkeiten, die Zufallsfunktionen und der Einfluss durch die Umgebung), welches der vorhandenen Objekte zurückgegeben
wird.
Ein weiterer Ausbau könnte vorsehen, dass neben vorgefertigten Modellen zusätzlich Partikeleffekte
geladen und platziert werden können. Dadurch könnte beispielsweise Rauch aus den Schornsteinen oder
einer Feuerstelle entspringen. Außerdem könnten die Effekte wie Modelle oder Texturen innerhalb von
Gruppen verwaltet werden.
Genauso wäre eventuell eine Gruppe für Grammatiken sinnvoll, zum Beispiel eine Gruppe, die mehrere
Facade-Grammars verwaltet. Anstatt nun einem Primitiv eine feste Facade-Grammar zuzuweisen,
könnte so zufällig eine Grammatik aus der Gruppe entnommen werden. Daraus würde eine erhöhte
92
Wiederverwendbarkeit und Vielfalt resultieren. Oder aber es könnte eine Grammatik ähnlich der ControlGrammar von [WWS+03] implementiert werden. Diese könnte über einfache Regeln den jeweiligen
Primitiven passende Grammatiken (z.B. Facade-Grammars) zuweisen.
Zur Optimierung der Berechnungszeiten könnten die von [EE98] oder [Obd] beschriebenen Verfahren
implementiert werden. Beide Arbeiten stellen Methoden vor, die die Berechnung des Straight-Skeletons
beschleunigen, zum Beispiel durch optimierte Listen bei der Split-Event-Berechnung. Weiterhin werden
eventuell entstehende Löcher innerhalb des Straight-Skeletons noch nicht berücksichtigt, d.h. bilden
mehrere Dach-Primitive einen Kreis, so dass in der Mitte ein oder mehrere Lücken entstehen, können
diese von dem bisherigen Algorithmus noch nicht erkannt werden.
Die Verbesserung der Performance könnte über eine Verringerung der Zeichenaufrufe (Draw Calls) erreicht werden. So könnten beispielsweise mehrere nahe aneinander stehende Gebäude zusammengefasst
und im Speicher optimiert abgelegt werden. Dadurch würden Häuserblöcke entstehen, die dann effizient
in einem Draw Call gezeichnet werden.
7.3 Zusammenfassung
Innerhalb der Arbeit wurde ein prozeduraler Ansatz zur Erzeugung von Gebäuden vorgestellt. Die Basis
des konzeptionierten Systems bilden mehrere Grammatiken, mit deren Hilfe unterschiedliche Gebäudetypen definiert werden können. Über diese Definition können dann beliebig viele Gebäude prozedural
erstellt werden. Damit die einzelnen Gebäudetypen möglichst übersichtlich, verständlich und schnell
formuliert werden können, wurden vier verschiedene Grammatik-Arten in das System integriert. Jede
dieser Arten besitzt eine andere Aufgabe und erstellt andere Bereiche des Gebäudes. Die Mass-Grammar erstellt das grundlegende Modell des Gebäudes, die Facade-Grammar die Objekte an den einzelnen
Fassaden und Dachflächen, die Border-Grammar die Objekte entlang der Kanten und die Profile-Grammar die Geometrie des Masse-Modells. Durch diese Aufspaltung werden die einzelnen Bereiche des
Gebäudes logisch getrennt und können bei anderen Gebäudetypen besser wiederverwendet werden.
Um das Gebäude zu erzeugen, können die Grammatiken entweder Primitive generieren oder
vorgefertigte Modelle laden. Primitive sind grundlegende Körper (Würfel, Zylinder, ...), denen weitere
Grammatiken zugeteilt werden können. Die zugewiesenen Grammatiken können dann an den einzelnen
Flächen und Kanten des Primitivs weitere Primtive oder Modelle platzieren. Damit solche Modelle
möglichst einfach verwaltet werden können, wurden Gruppen implementiert. Gruppen können beliebig
viele Objekte (Modelle oder Texturen) enthalten und geben ein zufälliges Objekt zurück, falls sie eine
Anforderung von einer Grammatik erhalten. Damit die einzelnen Grundflächen und Fassaden einfache
gestaltet werden können, wurden spezielle Subdivision-Verfahren in die Grammatiken eingebaut. Mit
Hilfe dieser Verfahren können die Primitive in Stockwerke oder sonstige Zellen unterteilt werden und
darin symmetrische Strukturen und Muster erzeugen.
Damit die Gebäude möglichst glaubwürdig erscheinen, müssen sie ihre lokale sowie globale Umwelt
berücksichtigen. Dazu wurden verschiedene Verfahren zur Analyse der Umgebung realisiert, die dann
innerhalb der einzelnen Grammatiken eingesetzt werden können, um die Eigenschaften der Gebäude
ihrer Umgebung anzupassen.
Beendet wird die Arbeit so, wie sie begonnen hat: mit einer Beschreibung der Selbstähnlichkeit und der
Fraktale. Diesmal von Lewis F. Richardson (1922) treffend in einem Gedicht verfasst.
Bigger swirls have smaller swirls,
That feed on their velocity,
And smaller swirls have smaller swirls,
And so on, to viscosity
93
8. Literaturverzeichnis
[Mül99]
Pascal Müller. Prozedurales Modellieren einer Stadt. Semesterarbeit ETH Zürich 1999
[Mül01]
Pascal Müller. Design und Implementation einer Preprocessing Pipeline zur Visualisierung
prozedural erzeugter Stadtmodelle. Diplomarbeit ETH Zürich 2001
[MP01]
Pascal Müller und Yoav I. H. Parish. Procedural Modeling of Cities. In Proceedings of ACM
SIGGRAPH 2001, S. 301-308
[MWH+06]
Pascal Müller, Peter Wonka, Simon Haegler, Andreas Ulmer und Luc Van Gool. Procedural
Modeling of Buildings. In Proceedings of ACM SIGGRAPH 2006, S. 614 - 623
[MVU+05]
P. Müller, T. Vereenooghe, A. Ulmer und L. Van Gool. Automatic reconstruction of Roman
housing architecture. International Workshop on Recording, Modeling and Visualization of
Cultural Heritage, Balkema Publishers 2005, S. 287-297
[WWS+03]
Peter Wonka, Michael Wimmer, François Sillion und William Ribarsky. Instant Architecture. In
Proceedings of ACM SIGGRAPH 2003, S. 669 - 677
[DHM+98]
Oliver Deussen, Patrick Hanrahan, Matt Pharr, Bernd Lintermann, Randomír Mĕch und
Przemyslaw Prusinkiewicz. Realistic Modeling and Rendering of Plant Ecosystems. In Proceedings
of SIGGRAPH 98, S. 275-286
[AS82]
Hal Abelsson und Andrea diSessa. Turtle geometry. MIT-Press Cambridge 1982
[Deu03]
Oliver Deussen. Computer generierte Pflanzen. Technik und Design digitaler Pflanzenwelten.
Springer-Verlag Heidelberg 2003. ISBN 3-540-43606-5
[EBE+03]
David S. Ebert, F. Kenton Musgrave, Darwyn Peachy, Ken Perlin, Steven Worley. Texturing &
Modeling A Procedural Approach. Morgen Kaufmann Publishers 2003. ISBN 1-55860-848-6
[Man82]
Benoît B. Mandelbrot. The Fractal Geometry of Nature. W. H. Freeman and Company 1982.
ISBN 0-7167-1186-9
[LP90]
P. Prusinkiewicz, A. Lindemayer. The Algorithmic Beauty of Plants. New York: Springer Verlag
1990. ISBN 0-387-94676-4
[Hol81]
S. R. Holtzman. Using Generative Grammars for Music Composition. Computer Music Journal
1981, 5(1):51-64
[Pru86]
P. Prusinkiewicz. Score Generation with L-Systems. Proc. Intl. Computer Music Conf 1986,
S. 455-457
[WS05]
Peter Worth und Susan Stepney. Growing Music: musical interpretations of L-Systems.
EvoWorkshops 2005, S. 545-550
[Smi84]
A. R. Smith. Plants, fractals, and formal languages. Computer Graphics. In Proceedings of ACM
SIGGRAPH 84, 18(3):1–10
94
[Lor02]
Wolfgang E. Lorenz. Fractal and Fractal Architecture. Technische Universität Wien 2002
[Han]
Michael Hansmeyer. Algorithms in Architecture. http://www.mh-portfolio.com/
[Gar85]
G. Y. Gardner. Visual Simulation of Clouds. In Proceedings of SIGGRAPH 85, S. 297–304
[FSJ01]
Ronald Fedkiw, Jos Stamy und Henrik Wann Jensenz. Visual Simulation of Smoke. Stanford
2001
[FKM+06]
Alfred R. Fuller, Hari Krishnan, Karim Mahrous, Bernd Hamann und Kenneth I. Joy. Real-time
Procedural Volumetric Fire. 2006
[MP96]
R. Měch und P. Prusinkiewicz. Visual Model of Plants Interacting with Their Environment. In:
Proceedings of SIGGRAPH 1996, S.397 – 410
[MPJ95]
R. Měch, P. Prusinkiewicz und P. James. Synthetic Topiary. In Proceedings of SIGGRAPH 1995
S.351 – 358
[HH74]
P. Hogeweg und B.Hesper. A model study on biomorphological description. Pattern Recognition
1974, S. 165-179
[BFH+80]
Wolfgang Brennecke, Heiko Folkerts, Friedrich Haferland und Franz Hart. Dachatlas Geneigte
Dächer. Institut für internationale Architektur Dokumentation München 1980
[Pre99]
Prehl, Hagen. Hölzerne Dachkonstruktionen Berechnung, Konstruktion, Tafeln, Beispiele. Werner
Verlag GmbH & Co Düsseldorf 1999
[War00]
Otto Warth. Die Konstruktion in Holz. Th. Schäfer Druckerei GmbH 1900
[Bro88]
F.A. Brockhaus GmbH Mannheim 1988. Brockhaus Enzyklopädie Fünfter Band COT-DR, 19.
Auflage, S.74 – 77
[Bro882]
F.A. Brockhaus GmbH Mannheim 1988. Brockhaus Enzyklopädie Vierter Band BRO-COS, 19.
Auflage, S.153, 158
[LD03]
Robert G. Laycock, A. M. Day. Automatically Generating Roof Models from Building Footprints.
In WSCG 2003, S 81-84. ISBN 80-903100-2-8
[LD032]
Robert G. Laycock und A. M. Day. Automatically Generating Large Urban Environments based
on the Footprint Data of Buildings. Proceedings of ACM Symposium on Solid and Physical
Modeling 2003, S. 346-351
[Aic+95]
Oswin Aichholzer, Franz Aurenhammer, David Alberts und Bernd Gärtner. A novel type of
skeleton for polygons. J. Universal Computer Science 1995, S. 752-761
[DEC03]
M. Dikaiakou, A. Efthymiou und Y. Chrysanthou. Modelling the Walled City of Nicosia. In D.
Arnold, A. Chalmers, and F. Niccolucci, VAST 2003, S. 57-65
95
[EE98]
David Eppstein und Jeff Erickson. Raising Roofs, Crashing Cycles, and Playing Pool: Applications
of a Data Structure for Finding Pairwise Interactions. In Proceedings of the 14th Annual ACM
Symposium on Computational Geometry 1998, S. 58-67
[AA96]
Oswin Aichholzer und Franz Aurenhammer. Straight skeletons for general polygonal figures in
the plane, In Proceedings 2nd Annual International Conference. Computing and Combinatorics,
S. 117-126. Lecture Notes in Computer Science 1090, Springer, 1996
[Gör04]
Robert Görke. Ein schneller Konstruktionsalgorithmus für eine Quickest-Path-Map bezüglich der
City-Metrik. Diplomarbeit Universität Karlsruhe 2004
[Bre00]
Claus Brenner. Towards fully automatic generation of city models. International Archives of
Photogrammetry and Remote Sensing, Volume 33, S. 85-92
[Obd]
Štěpán Obdržálek. The Angular bisector network Implementation and the CGAL library
[Jag04]
Robert Carl Jagnow. Stereological Techniques for Synthesizing Solid Textures from Images of
Aggregate Materials. Massachusetts Institute of Technology 2004
[1]
http://de.wikipedia.org/wiki/Dach
[2]
http://de.wikipedia.org/wiki/Dachausmittlung
[3]
http://en.wikipedia.org/wiki/Fractal
[4]
http://gumuz.looze.net/wordpress/index.php/archives/2006/03/30/python-conways-game-of-Life
[5]
http://de.wikipedia.org/wiki/Zellul%C3%A4rer_Automat
[6]
http://en.wikipedia.org/wiki/Cellular_automaton
[7]
http://de.wikipedia.org/wiki/Conways_Spiel_des_Lebens
96
Anhang A
Die nachfolgenden Funktionen können von allen vier Grammatik-Arten (Mass-, Facade-, Border- und
Profile-Grammar) aufgerufen werden.
cos(x)
Berechnet den Kosinus von x
sin(x)
tan(x)
Berechnet den Sinus von x
Berechnet den Tangens von x
acos(x)
Berechnet den Arkuskosinus von x
asin(x)
atan(x)
Berechnet den Arkussinus von x
Berechnet den Arkustangens von x
pow(x, y)
Liefert xy zurück
sqr(x)
min(x, y)
Berechnet die Quadratwurzel von x
Liefert das Minimum von x und y zurück
max(x, y)
floor(x)
ceil(x)
abs(x)
rand(x, y)
Liefert das Maximum von x und y zurück
Rundet x auf den nächsten ganzzahligen Wert ab
Rundet x auf den nächsten ganzzahligen Wert auf
Berechnet den Absolutbetrag von x
Liefert eine zufällige reelle Zahl zwischen x und y zurück
rani(x, y)
Liefert eine zufällige ganze Zahl zwischen x und y zurück
ranb()
Liefert zufällig eine 0 (false) oder 1 (true) zurück
noise(x, y, f)
Berechnet einen zweidimensionalen Perlin-Noise an der Stelle (x, y). Vorher
werden x und y mit f multipliziert
Gibt die einzelnen Argumente im Ausgabefenster aus. Als Argumente dürfen
beliebig viele Zahlen oder Zeichenketten übergeben werden
Trace(s0, s1, ...)
AutoPP(b)
Aktiviert oder deaktiviert das automatische Push und Pop vor bzw. nach der
Substitution einer Variablen, siehe Kapitel 5.1.8 Verzweigungen
String(x)
Konvertiert eine Zahl in eine Zeichenkette
For("Production", i)
Ruft i-mal die Produktion auf
If(i, a, b)
VCount("Variable")
Wenn i ungleich 0 (true) ist, wird a zurückgegeben, andernfalls (false) wird b
zurückgegeben
Selektiert das i-te Argument und liefert dies zurück. Es dürfen beliebig
viele Argumente an die Funktion übergeben werden, egal ob Zahlen oder
Zeichenketten
Liefert die Anzahl der bisherigen Substitutionen einer Variablen zurück
GCount("Group")
Liefert die Anzahl der Gruppenaufrufe zurück
Switch(i, a, b, ...)
Führt ein Anfrage an die globale Umgebung durch, siehe Kapitel 5.6.2.3 AnfrageFunktionen
Env("EnvironmentType",
Führt ein Anfrage an die lokale Umgebung durch, siehe Kapitel 5.6.2.3 AnfrageScanLevels, Absolute)
Funktionen
EnvP("EnvironmentType",
Führt ein Anfrage an die lokale Umgebung durch, siehe Kapitel 5.6.2.3 AnfrageScanLevels, Absolute)
Funktionen
EnvPN("EnvironmentType", Führt ein Anfrage an die lokale Umgebung durch, siehe Kapitel 5.6.2.3 AnfrageScanLevels, Absolute)
Funktionen
R(x, y, z)
Führt eine zusätzliche Rotation auf die aktuelle Transformation aus
GEnv("EnvironmentType")
S(x, y, z)
Ersetzt die Skalierung der aktuellen Transformation
97
T(x, y, z)
Führt eine zusätzliche Translation auf die aktuelle Transformation aus
TR(x ,y, z)
R()
Führt eine zusätzliche Translation auf die aktuelle Transformation aus, bzgl. der
aktuellen Ausrichtung
Setzt die aktuelle Rotation zurück
S()
Setzt die aktuelle Skalierung zurück
T()
Setzt die aktuelle Translation zurück
RX(x)
RY(y)
Führt eine zusätzliche Rotation um die x-Achse aus
Führt eine zusätzliche Rotation um die y-Achse aus
RZ(z)
Führt eine zusätzliche Rotation um die z-Achse aus
SX(x)
Ersetzt die aktuelle Skalierung entlang der x-Achse
SY(y)
Ersetzt die aktuelle Skalierung entlang der y-Achse
SZ(z)
Ersetzt die aktuelle Skalierung entlang der z-Achse
TX(x)
Führt eine zusätzliche Translation entlang der x-Achse aus
TY(y)
Führt eine zusätzliche Translation entlang der y-Achse aus
TZ(z)
Führt eine zusätzliche Translation entlang der z-Achse aus
Anhang B
Die nachfolgenden Funktionen dürfen ausschließlich von einer Profile-Grammar aufgerufen werden.
In("Register")
PointV()
PointH()
TexCoord(u, v)
TextureGroup("GroupIndex")
Reset()
98
Liest das Register aus und gibt den übergebenen Wert zurück, siehe Kapitel 5.2.5
Kommunikation
Erzeugt einen neuen vertikalen Punkt und verbindet diesen mit dem vorherigen
Punkt
Erzeugt einen neuen horizontalen Punkt und verbindet diesen mit dem vorherigen
Punkt
Setzt den Faktor für die Texturkoordinaten, siehe Kapitel 5.3.1.3 Texturierung
Lädt ein ausgewählte oder zufällige Textur aus einer Textur-Gruppe und setzt
diese als aktuelle Textur, siehe Kapitel 5.2.4.2 Texturierung
Löscht die aktuelle Textur, siehe Kapitel 5.2.4.2 Texturierung
Anhang C
Die nachfolgenden Funktionen dürfen ausschließlich von einer Mass-, Facade- oder Border-Grammar
aufgerufen werden.
Disp(x, y)
ranq()
Out(x, "Register")
In("Register")
ModelGroup("Name:Index", UndoRotate,
IntersectSetting)
Box("Profile", "Facade", "Border")
HalfBox("Profile", "Facade", "Border")
Cylinder("Profile", "Facade", "Border")
HalfCylinder("Profile", "Facade", "Border")
Wall("Profile", "Facade", "Border")
RoofBox("Profile", "Facade", "Border",
Slope, AboveWall, GableWeighting,
ConnectRoof)
RoofHalfBox("Profile", "Facade", "Border",
Slope, AboveWall, GableWeighting,
ConnectRoof)
RoofCylinder("Profile", "Facade", "Border",
Slope, AboveWall, GableWeighting,
ConnectRoof)
RoofHalfCylinder("Profile", "Facade",
"Border", Slope, AboveWall,
GableWeighting, ConnectRoof)
Prim("Type", "Profile", "Facade", "Border")
Roof("Type", "Profile", "Facade", "Border",
Slope, AboveWall, GableWeighting,
ConnectRoof)
Liefert den Displacement-Wert (erzeugt durch die ProfileGrammar) an der Stelle (x, y) zurück
Setzt die aktuelle Verschiebung auf einem zufälligen
Punkt innerhalb des Rechtecks, welches durch die aktuelle
Transformations-Sequenz definiert wird
Legt ein Ausgaberegister an und weist diesem den Wert x zu.
Sobald ein Primitiv oder Dach-Primitiv erzeugt wird, werden
alle bisherigen Register an die Grammatiken des Primitiv‘s
weitergeleitet, siehe Kapitel 5.2.5 Kommunikation
Liest das Register aus und gibt den übergebenen Wert zurück, siehe
Kapitel 5.2.5 Kommunikation
Lädt ein ausgewähltes oder zufälliges Model aus einer ModellGruppe, siehe Kapitel 5.4.1.1 Funktionen
Erstellt einen Würfel bzgl. der aktuellen Transformations-Sequenz
und führt die zugeteilten Grammatiken aus, siehe Kapitel 5.3.1.4
Funktionen
Erstellt einen Halb-Würfel bzgl. der aktuellen TransformationsSequenz und führt die zugeteilten Grammatiken aus, siehe Kapitel
5.3.1.4 Funktionen
Erstellt einen Zylinder bzgl. der aktuellen TransformationsSequenz und führt die zugeteilten Grammatiken aus, siehe Kapitel
5.3.1.4 Funktionen
Erstellt einen Halb-Zylinder bzgl. der aktuellen TransformationsSequenz und führt die zugeteilten Grammatiken aus, siehe Kapitel
5.3.1.4 Funktionen
Erstellt eine Wand bzgl. der aktuellen Transformations-Sequenz
und führt die zugeteilten Grammatiken aus, siehe Kapitel 5.3.1.4
Funktionen
Erstellt das Dach für einen Würfel bzgl. der aktuellen
Transformations-Sequenz und führt die zugeteilten Grammatiken
aus, siehe Kapitel 5.3.2.6 Funktionen
Erstellt das Dach für einen Halb-Würfel bzgl. der aktuellen
Transformations-Sequenz und führt die zugeteilten Grammatiken
aus, siehe Kapitel 5.3.2.6 Funktionen
Erstellt das Dach für einen Zylinder bzgl. der aktuellen
Transformations-Sequenz und führt die zugeteilten Grammatiken
aus, siehe Kapitel 5.3.2.6 Funktionen
Erstellt das Dach für einen Halb-Zylinder bzgl. der aktuellen
Transformations-Sequenz und führt die zugeteilten Grammatiken
aus, siehe Kapitel 5.3.2.6 Funktionen
Allgemeine Funktion zum Erstellen von Primitiven, siehe Kapitel
5.3.1.4 Funktionen
Allgemeine Funktion zum Erstellen von Dach-Primitiven, siehe
Kapitel 5.3.2.6 Funktionen
99
Anhang D
Die nachfolgenden vordefinierten Konstanten können von allen Grammatik-Arten (Mass-, Facade-,
Border- und Profile Grammar) verwendet werden.
WIDTH
TYPE
R.x
Enthält entweder die Breite des Grundstücks (Mass-Grammar), die Breite der Fassade
(Facade-Grammar, Profile-Grammar) oder die Länge der Kante (Border-Grammar)
Enthält die Länge des Grundstücks (Mass-Grammar), die Höhe der Fassade (FacadeGrammar, Profile-Grammar) oder den Wert 0 bei einer Kante (Border-Grammar)
Beschreibt den aktuellen Typ der Fassade bzw. Kante
Enthält den aktuellen Rotations-Winkel um die x-Achse
R.y
R.z
S.x
S.y
S.z
T.x
T.y
T.z
TRUE
FALSE
PI
Enthält den aktuellen Rotations-Winkel um die y-Achse
Enthält den aktuellen Rotations-Winkel um die z-Achse
Enthält die aktuelle Skalierung bzgl. der x-Achse
Enthält die aktuelle Skalierung bzgl. der y-Achse
Enthält die aktuelle Skalierung bzgl. der z-Achse
Enthält die aktuelle Verschiebung entlang der x-Achse
Enthält die aktuelle Verschiebung entlang der y-Achse
Enthält die aktuelle Verschiebung entlang der z-Achse
Enthält die Zahl 1
Enthält die Zahl 0
Enthält die Zahl Pi
HEIGHT
Anhang E
Die nachfolgenden vordefinierten Konstanten können nur von einer Mass-, Facade- oder BorderGrammar verwendet werden.
SYM
SNR
Enthält den aktuellen Symmetrie-Status, siehe Kapitel 5.5.2
Gibt die Nummer der aktuellen Fläche bzw. Kante an
Anhang F
Die nachfolgenden vordefinierten Konstanten können nur von einer Profile-Grammar verwendet werden.
PTYPE
VERTICAL
HORIZONTAL
BOTH
100
Enthält den aktuellen Profil-Typ, demzufolge ob ein horizontales oder vertikales Profil
erstellt werden soll
Kann in Verbindung mit PTYPE eingesetzt werden
Kann in Verbindung mit PTYPE eingesetzt werden
Kann in Verbindung mit PTYPE eingesetzt werden
Herunterladen