Entwicklung eines interaktiven Malprogramms mit

Transcrição

Entwicklung eines interaktiven Malprogramms mit
Fachbereich 4: Informatik
Entwicklung eines interaktiven
Malprogramms mit Ansteuerung
eines 5-DOF Grafiktabletts und einer
Marker Simulation mit QT
Bachelorarbeit
zur Erlangung des Grades eines Bachelor of Science (B.Sc.)
im Studiengang Computervisualistik
vorgelegt von
Jessica Orth
Erstgutachter:
Prof. Dr.-Ing. Stefan Müller
(Institut für Computervisualistik, AG Computergraphik)
Zweitgutachter:
Dipl.-Inform. Diana Röttger
(Institut für Computervisualistik, AG Computergrafik)
Koblenz, im November 2012
Erklärung
Ich versichere, dass ich die vorliegende Arbeit selbständig verfasst und keine anderen als die angegebenen Quellen und Hilfsmittel benutzt habe.
Ja
Nein
Mit der Einstellung der Arbeit in die Bibliothek bin ich einverstanden.
Der Veröffentlichung dieser Arbeit im Internet stimme ich zu.
.................................................................................
(Ort, Datum)
(Unterschrift)
Zusammenfassung
In dieser Arbeit gehe ich der Frage auf den Grund, welche Werkzeugeigenschaften in der Malerei von Bedeutung sind, und warum Malprogramme nur vergleichsweise zögerlich von Künstlern angenommen werden. Ich
zeige die Vorzüge und mögliche Umsetzungen computergestützter Kunst
auf und stelle kommerzielle, sowie wissenschaftliche Arbeiten zum Thema
Nonphotorealistic Rendering, Mal- und Zeichensimulation vor. Außerdem
stelle ich mein eigenes Mal- und Illustrationsprogramm mit Zeichentablettanbindungvor, und zeige die Entwicklung des Programms mit dem QTGUI-Framework in den einzelnen Entwicklungsstufen.
In this work I want to point out what kind of characteristics and features are relevant for painting, and why painters are just hesitantly adopting
paint programs for computers. I show the advantages of computer assisted art and present commercial and scientific works that deal with nonphotorealistic rendering, painting and drawing simulation. Additionally I
present my own paint- and illustration program in connection with a drawing tablet and show step-by-step the stages of development, using the
QT-GUI-Framework.
Inhaltsverzeichnis
1
2
3
Einleitung
1.1 Anforderungen an Mal- und Illustrationsprogramme . . . .
1.2 Motivation - Vorzüge der computergestützten Zeichnung und
Malerei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Entwicklung eines eigenen Malprogramms
2.1 Das QT Framework . . . . . . . . . . . . . . .
2.2 Ein Programmrahmen mit ersten Funktionen
2.3 Anforderungen und Konzept . . . . . . . . .
2.4 Das Ebenenfenster . . . . . . . . . . . . . . .
2.5 Das Werkzeugfenster . . . . . . . . . . . . . .
2.6 Anbindung des Grafiktabletts . . . . . . . . .
2.7 Undo, Redo und Zoom . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Mal- und Zeichensimulation
3.1 Bisherige Projekte zur interaktiven Simulation von Mal- und
Zeichenmedien . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Nähere Betrachtung eines Simulationsansatzes: Wasserfarbensimulation . . . . . . . . . . . . . . . . . . .
3.2 Kubelka und Munk Theorie . . . . . . . . . . . . . . . . . . .
3
3
9
11
11
13
18
19
21
24
30
31
31
34
37
4
Entscheidung und Implementierung eines komplexeren Werkzeuges mit Papiersimulation
40
4.1 Eigenschaften von Filzstiften oder Copic Markern . . . . . . 41
4.2 Implementierung des Filzstift Werkzeugs . . . . . . . . . . . 42
5
Bewertung
47
6
Ausblick
49
1
1
Einleitung
Die Malerei ist eine Kunst, die die Menschen seit Jahrtausenden fasziniert.
Zu den frühesten kulturellen Leistungen der Menschheit zählt die Höhlenmalerei: Die ältesten Malereien wurden in der Höhle von Coliboaia in
Rumänien gefunden. Sie sind zwischen 23.000 und 35.000 Jahren alt und
gelten damit als die ältesten, bisher entdeckten Malereien [Sch11]. Auch
heute noch sind Zeichnung und Malerei ein wichtiger Teil der modernen
Kultur. Sie sind Mittel zum Ausdruck von Gedanken und Kritik, Humor
und Satire, ermöglichen die Weitergabe von Visionen und Gedankenanstößen, von erdachten Welten, Geschöpfen, und Geschichten.
Es ist einfach, ein Bild zu malen, selbst für ein Kleinkind ohne jede Vorerfahrung. Und doch dauert es Jahre, die Kunst zu meistern und zu perfektionieren.
Welche sind nun die technischen Eigenschaften der Malerei und welche
dieser Eigenschaften werden am Computer umgesetzt? Welche können überhaupt am Rechner verwirklicht werden und wo stößt die Simulation an ihre Grenzen? Warum sind andere Kunstformen wie die Musik bereits zum
Großteil, oder sogar vollständig digitalisiert? Auch das Verfassen von literarischen Texten geschieht heute fast immer am PC. In der Malerei jedoch
hat sich auch heute nur in wenigen Teilbereichen, wie Fotobearbeitung und
Hyperrealismus in Form von Airbrush ähnlichen Techniken der Computer
als Werkzeug durchgesetzt.
"Jeder Mensch ist ein Künstler."(Joseph Beuys)
1.1
Anforderungen an Mal- und Illustrationsprogramme
Computer haben im Laufe der Zeit und der technischen Entwicklung die
Arbeit vieler Menschen vereinfacht und beschleunigt. Wohl niemand, der
einen Computer besitzt, würde sich die Arbeit machen, heute noch einen
Roman mit der Hand zu schreiben und auch Animationen und Filme werden schon längst nicht mehr Bild für Bild mit der Hand gezeichnet und
koloriert. Auch ein Großteil der Musik wird heute elektronisch produziert
und verbreitet. Digitale Malerei hat sich allerdings bei den meisten Künstlern nicht durchgesetzt. Warum ist das so? Bietet die computergestützte
Arbeit in anderen Bereichen Vorteile, die es in der Malerei nicht gibt? Oder
ist der Stand der Technik einfach noch nicht so weit, die wesentlichen Eigenschaften umzusetzen?
Ein Teil der Antwort scheint naheliegend: Künstler empfinden die Malprogramme auf Computern oft als kalt, sie fühlen sich distanziert von den
2
Werkzeugen, die sie nicht wirklich berühren können. Auch sind Computerprogramme zu genau und steril [Coc91]. Gemälde, die am Computer
entstanden sind, wirken oft unorganisch.
Es gibt drei eng miteinander verbunden Aspekte der realen Malerei, die
von den Entwicklern solcher Computerprogramme oft übersehen werden:
Prozess, Zufall und Komplexität [Bax04].
Der Prozess ist es für den Künstler, der im Mittelpunkt des Schaffens steht,
nicht das Endergebnis. Dies wird von Ingenieuren oft übersehen, da es
für sie das Endprodukt ist, das im Vordergrund steht. Der Künstler hingegen hat oft kein genaues Endprodukt vor Augen. Für ihn sind nur die
Dinge klar, die das Gemälde ausmachen, die Stimmung, die Farbgebung,
die Gefühle oder der Gedanke, der vermittelt werden soll. Ob ein Baum
einen Zentimeter weiter links steht, oder eine Wolke mehr oder weniger
am Himmel schwebt, spielt keine Rolle. Das Gemälde entsteht in einem
dynamischen Schaffensprozess, einzelne Entscheidungen werden während
des Prozesses getroffen, nicht vorher, und manche Entscheidungen trifft
auch der Zufall für den Künstler. Das Gemälde entsteht in einem Prozess
von Einflussnahme und Betrachtung des Ergebnisses. Es ist ein Kreislauf,
der von Aktion und Reaktion und auch dem Zufall lebt. Ein guter Künstler kann zwar nahezu genau voraussagen, wie ein Pinselstrich aussehen
wird, aber eben nur nahezu. Im realen Leben wird kein Künstler es schaffen, zweimal genau den selben Pinselstrich zu erzeugen und manchmal
kann die Wirkung eines Farbtupfers sogar die gesamte Wirkung des Bildes
verändern und in eine andere Richtung führen, als vom Künstler erwartet.
Der berühmte Fernsehkünstler Bob Ross sagte in seiner Fernsehsendung
The Joy of Painting oft ’We don’t make mistakes here, just have happy little accidents’. Seine Sendung dreht sich um den Schaffensprozess und wer
sie ansieht, versteht, welchen Stellenwert der Prozess für den Künstler hat.
Pablo Picasso breitete den Schaffensprozess sogar auf mehrere Bilder aus.
Er hatte eine Idee, malte ein Bild, malte ein weiteres, das vom ersten abstrahierte und dann ein weiteres, das wiederum von diesem abstrahierte,
um in eine bestimmte Richtung zu kommen. So erstellte er ganze Bilderreihen, an deren Ende oft Werke standen, die sich heute aufgrund ihrer
damaligen Neuartigkeit und ihres hohen Wiedererkennungswertes großer
Berühmtheit erfreuen. Von ihm stammt das Zitat ’I start with an idea and
then it becomes something else’. Abbildung 1 zeigt ein Bild, in dem Picasso
das Gemälde eines Stieres entwickelt, indem er es immer weiter von der
Realität abstrahiert.
Dennoch ist es wichtig, dass der Zufall in der Bedienung der Werkzeuge nur eine untergeordnete Rolle spielt und das Ergebnis der Erwartung
eines erfahrenen Künstlers weitestgehend entspricht. In einigen Mal- und
Bildbearbeitungsprogrammen gibt es zwar Funktionen, die den Zufall miteinbeziehen, diese sind jedoch in realen Werkzeugen nicht zu finden und
3
Abbildung 1: Pablo Picasso: Der Stier, 1945/46.
nur schwer zu kontrollieren. Ein Beispiel für solche Funktionen sind das
Zittern (jittering) im Strich oder in der Kontur des Striches oder eine zufällige Mischung zweier vom Benutzer gewählter Farben.
Dies ist natürlich nicht die Art von Zufall, die man sich beim Malen oder
zeichnen wünscht, sondern entspricht eher dem Effekt den ein Erdbeben
oder eine sehr zittrige Hand hervorrufen würde. Zufällige Mischung zweier Farben gibt es wohl bei keinem realen Werkzeug. Die Effekte, die Pinselborstenbewegungen, verlaufende Farbe oder die Mikrostrukturen des Papieres hervorrufen sind zwar nicht zu 100 Prozent vorhersehbar, aber doch
gut abzuschätzen.
Die nächste wichtige Anforderung an ein gutes Malprogramm ist die Komplexität der Simulation, die sehr schwer in allen Punkten umzusetzen ist,
und an der die meisten Programme an ihre Grenzen stoßen. Verschiedene
Pinsel und Farben können eine beeindruckende Spannbreite an Effekten
und Eindrücken erzeugen. Dies ist ein wichtiger Bestandteil dessen, was
uns an der Malerei fasziniert, was die Malerei so vielseitig, und den Schaffensprozess so wichtig macht. Ohne die Komplexität wären die Möglichkeiten der Malerei nicht so umfangreich und diese Kunst nicht so schwer zu
4
meistern. Auch der Zufall würde eine entsprechend kleinere Rolle spielen.
Wenn die Komplexität des Systems zu gering wird, spielt der Zufall irgendwann keine Rolle mehr. Dies ist zum Beispiel bei dem bekannten Malprogramm ’Paint’ von Microsoft der Fall. Hier ist die Komplexität sehr stark
vereinfacht, die einzigen Parameter für den Pinsel sind der RGB-Farbwert
und die Strichstärke, wobei man nur aus 4 verschiedenen Größen wählen,
und die Strichstärke auch nicht innerhalb eines Striches verändern kann.
Hier dürfte es schwer sein, beim Malen auf große Überraschungen zu stoßen.
In der Komplexität der Malerei liegt eine große Herausforderung an die
Computergrafik. Seit mehreren Jahrzehnten versuchen Forscher in verschiedenen Ländern, Programme und Algorithmen zu entwickeln, die annähernd die Komplexität einiger Malwerkzeuge simulieren können ([Str86],
[GK91], [Coc91]). Doch erst in den letzten Jahren wurde die Computertechnik weit genug entwickelt, um solche Systeme interaktiv und echtzeitfähig
umsetzen zu können ([CAS+ 97], [BSL01], [CT04]). Die Hard- und Software
für diese Systeme ist allerdings oft noch relativ teuer, vor allem verglichen
mit realen Malwerkzeugen und in kommerziellen Malprogrammen sind
solche Ansätze ebenfalls weitestgehend noch nicht zu finden.
Eine Ausnahme bildet das Programm Painter von Corel bei dessen Entwicklung auch Künstler mitgewirkt haben. Painter 12 ist zurzeit das führende kommerzielle Programm für computersimulierte Malerei und es enthält sehr viele Werkzeuge, die reale Pendants möglichst gut imitieren sollen, was jedoch meistens nicht realitätsgetreu funktioniert. Zwar lassen sich
mit Corel Painter einige Effekte realer Werkzeuge nachstellen, jedoch werden lange nicht alle dieser Effekte simuliert und einige Eigenschaften, wie
z.B. die Farbmischung auch falsch dargestellt. Einige Effekte lassen sich
zwar imitieren, allerdings anders, als es in der Realität der Fall wäre, was
nicht intuitiv für den Künstler ist. Das Ölfarbenwerkzeug kann beispielsweise grob die Form eines trockenen Pinsels simulieren und auch Farben
verwischen, wenn man jedoch auch den Duktus imitieren möchte, muss
mit einem zweiten Werkzeug namens Impasto nachgeholfen werden. Anschließend fehlen allerdings immer noch einige der zahlreichen Eigenschaften realer Ölfarben, wie eine realitätsgetreue Pinselsimulation und Aufnahme und Abgabe von Öl und Farbe, Farbaustausch zwischen einzelnen Pinselborsten, Verlaufen und Trocknen der Farbe etc. In kommerziellen Programmen wird meist versucht, möglichst viele Werkzeuge einzubinden,
die dann aber nur halbherzig umgesetzt werden. Wissenschaftliche Ansätze konzentrieren sich meist auf ein einziges Werkzeug und versuchen, dieses möglichst genau zu analysieren und zu simulieren.
Ein weiterer Vorreiter der kommerziellen Malprogramme ist ArtRage. Das
Programm bietet weniger verschiedene Werkzeuge, die dafür aber, meiner Meinung nach, teilweise besser umgesetzt sind. ArtRage bietet kein
Impasto-Verhalten für Pinsel, aber einen Airbrush mit Neigungsabfrage
5
eines Tablettstiftes und Filz- und Wachsstift Simulation mit realistischer
wirkendem Mischungsverhalten. Alle Werkzeuge reagieren auf den Zeichenstiftdruck, nur der Airbrush auf die Neigung. Beide Programme bieten
verschiedene Maluntergründe, die wie Leinwände oder verschiedene Papierbögen aussehen, allerdings liegt hier kein Papiermodell darunter. Die
Untergründe sind Schablonen, die sich beispielsweise auf den Bleistift auswirken, sie bieten aber keinen Farbfluss nach Ende der Benutzereingabe.
In Corel Painter kann außerdem zwar die Papierfarbe eingestellt werden,
die Papierstruktur ist jedoch nicht sichtbar und wirkt sich nur auf wenige Werkzeuge, wie Wachsmaler oder Pastelkreide recht unspektakulär aus.
Eine Schwachstelle liegt in beiden Programmen bei manchen Werkzeugen
noch in Strichführungen mit zu engen Kurven. Bei den Pinselwerkzeugen
beispielsweise wirken diese abgerissen. ArtRage ist wesentlich übersichtlicher und einfacher zu benutzen als Corel Painter. Es beschränkt sich auf
Mal- und Zeichenfunktionalität wärend Corel Painter noch viele zusätzliche Funktionen bietet, worunter jedoch die Intuitivität und Übersichtlichkeit leidet.
Abbildung 2: Corel Painter - Acryl und Wachsstifte/Pastelkreide mit GUI
Abbildung 2 zeigt die Benutzeroberfläche von Corel Painter. Sie wirkt
ein bisschen unübersichtlich und grau. Links auf der Grafik sind die verschiedenen Stile des Acrylfarbenwerkzeuges dargestellt, rechts die Stile des
Werkzeuges "Kreide und Wachsstifte", das auch noch im Fenster "Painter
Werkzeugeäusgewählt ist, sodass die einzelnen Stile angezeigt werden. In
der Grafik habe ich mit grüner Umrandung noch einmal das Papier eingefügt, das ich ausgewählt habe.
6
Abbildung 3: ArtRage GUI - Werkzeuge auf Untergrund Essential Canvas
Die Oberfläche von ArtRage ist einfacher und freundlicher gehalten.
Für die einzelnen Werkzeuge gibt es weniger Einstellungen, und die Werkzeugsimulationen sind teilweise realistischer und trotz weniger Einstellungsmöglichkeiten vielseitiger als bei Corel Painter.
Abbildung 4 zeigt noch einmal vier Werkzeuge, die von ArtRage zur
Verfügung gestellt werden. Drei der Werkzeuge sind auch in Abbildung 3
zu sehen, allerdings auf einem anderen Untergrund. Die Werkzeuge wirken auf den beiden Untergründen teilweise sehr unterschiedlich. In Corel
Painter wird durch verschiedene Untergründe lediglich eine Art Muster in
die Werkzeugspuren eingefügt (s. Abbildung 2).
Sowohl mit Corel Painter als auch mit ArtRage können realistisch aussehende Ergebnisse erzielt werden, doch das Verhalten der Farbe ist noch
nicht korrekt umgesetzt, die Farbe fließt nicht realistisch und einige Eigenschaften der Werkzeuge werden nicht simuliert. Außerdem lassen sich die
Effekte, vor allem mit Corel Painter eher umständlich erreichen und nicht
intuitiv wie mit den realen Werkzeugen.
Idealerweise sollen Malprogramme nicht nur echte Effekte möglichst
realitätsnah simulieren, sondern dem Nutzer auch ermöglichen, diese Effekte intuitiv und ohne besonders viele Einstellungen und lange Einarbeitungszeit zu erreichen.
Das heißt, die virtuellen Werkzeuge sollten sich nach Möglichkeit so verhalten, wie es die entsprechenden realen Werkzeuge auch tun würden und
diese Effekte sollten sich ebenso erzeugen lassen, wie es in der Realität der
7
Abbildung 4: ArtRage - Werkzeuge auf Untergrund Basic Canvas
Fall wäre. Dies vereinfacht Künstlern den Einstieg in die Arbeit mit dem
Programm und verbessert den Eindruck der Simulation.
Bei den gängigen Malprogrammen gibt es hunderte von Einstellungsmöglichkeiten und Zustände (States), in denen sich einzelne Werkzeuge befinden können. Dies dient zwar der Komplexität, ist jedoch nicht besonders
intuitiv und führt zu einer langen Einarbeitungsphase, die viele Künstler
abschreckt, weil sie den Umgang mit den Werkzeugen noch einmal ganz
neu lernen müssen.
1.2
Motivation - Vorzüge der computergestützten Zeichnung und
Malerei
Die computergestützte Malerei hat auf den ersten Blick viele Nachteile. Die
Distanziertheit des Benutzers von den Werkzeugen und Materialien und
die zu geringe Komplexität in ihrem Verhalten wurden bereits angesprochen. Dies scheint für viele Künstler bereits die Arbeit mit digitalen Malprogrammen zu disqualifizieren. Jedoch hat die digitale Malerei auch einige, nicht zu verachtende Vorteile, die ich nun vorstellen möchte.
Einige Vorteile computergestützter Malerei sind offensichtlich: Ein virtuelles Malsystem kann dazu in der Lage sein, eine Vielzahl von Medien
und Werkzeugen zu simulieren. Es ist also für den Anwender ohne großen
Aufwand oder Anschaffungskosten möglich, verschiedene Werkzeuge und
Medien auszuprobieren. Auch sind solche Systeme recht mobil, ein Laptop
oder Tablet-PC lässt sich leicht transportieren und ermöglicht die Malerei
8
auch an Orten, an denen sie normalerweise nicht möglich gewesen wäre
(zB im Zug/Flugzeug, in Arbeitspausen oder spontan unterwegs). Außerdem entstehen bei der virtuellen Malerei keine giftigen Dämpfe von Lösungsmitteln, wie es bei der Ölmalerei der Fall ist, wodurch die Malerei
mit Ölfarben nur in größeren, gut gelüfteten Räumen gefahrlos möglich
ist. Auch die Gefahr, Kleidung oder andere Textilien oder Gegenstände mit
kaum wieder löslicher Acryl- und Ölfarbe zu ruinieren ist bei der virtuellen Malerei nicht gegeben. So können sich auch Kinder gefahrlos an solcher
Malerei versuchen und beliebig oft neu beginnen oder herumprobieren ohne sich und ihre Umgebung dabei zu bemalen oder teure Materialien zu
verschwenden.
Auch die Undo- bzw. Redo-Funktion von Computersystem kann vielen
Künstlern, vor allem aber Anfängern von großem Nutzen sein. Ein kleiner Ausrutscher kann so das Bild nicht mehr unwiederbringlich zerstören.
Zwar ist es für einen geübten Künstler oft nicht schwierig, einen Ausrutscher zu korrigieren, aber gerade für Anfänger sind solche Funktionen eine
große Unterstützung, die auch Ängste oder Hemmungen nimmt, da sich jeder Pinselstrich leicht rückgängig machen oder wiederherstellen lässt.
Bei der Malerei mit einem virtuellen Computersystem lässt sich außerdem Einfluss auf die Physik nehmen, was ungeahnte Möglichkeiten hervorbringt. Durch physikalische Veränderungen werden ganz neue Stile und
Techniken möglich. So ist es zum Beispiel möglich, das System so zu verändern, dass die Farbe nicht mehr nach unten, sondern in die Mitte der
Leinwand läuft, der Künstler kann die Geschwindigkeit des Trocknungsprozesses selbst einstellen oder eine Soforttrocknung veranlassen oder bereits getrocknete Schichten und Bildteile wieder nass werden lassen. Der
Benutzer kann Effekte und Filter über sein Bild legen oder einzelne Farbtöne global für das gesamte Bild verändern, auch wenn die betroffenen Farbschichten unter anderen Farbschichten liegen. Einige Bildformate wie das
GIF-Format lassen auch Animationen zu. Hier verschwimmen in den virtuellen Bildern die Grenzen zwischen Bild und Video.
Ein weiterer großer Vorteil der virtuellen Kunst ist die Möglichkeit, auf einfache und schnelle Weise einzelne Objekte zu kopieren und erneut im selben oder in einem anderen Bild einzufügen. Dies ist zum Beispiel in Animationsfilmen wichtig, in der Hintergründe sehr detailliert dargestellt, und
ganze Massen von Kreaturen glaubhaft und sehr realistisch dargestellt werden. Hier können die Figuren nicht nur einfach kopiert, sondern aus verschiedenen Blickwinkeln und in verschiedenen Posen gerendert werden.
Einzelne Figuren und Objekte, Räume und Bewegungen können also wiederverwendet werden. Dies ist natürlich nicht nur bei Bildbestandteilen
der Fall, sondern auch bei kompletten Werken: Ein Künstler kann ein digitales Bild in kurzer Zeit und mit wenig Aufwand in der ganzen Welt verbreiten, er kann beliebig viele Kopien erstellen und diese über das Internet
an jeden beliebigen Ort verschicken oder von überall aus zugänglich ma9
chen. Dies ist vor allem für politische und gesellschaftskritische Werke, die
nicht für kommerzielle Zwecke geschaffen wurden, ein großer Vorteil. Für
kommerzielle Zwecke kann dies natürlich auch ein Nachteil sein, da nicht
nur der Künstler das Bild beliebig vervielfältigen kann, sondern jeder, der
das Bild sieht, so wie auch jeder, der ein Musikstück abspielt, dieses mitschneiden und kopieren kann. Computergestützte Kunst eignet sich also
vor allem für nicht kommerzielle Aktionskunst, die möglichst viele Menschen erreichen soll.
Ein weiterer, auf den ersten Blick gravierend wirkender Nachteil der Computermalerei ist der fehlende Pinselduktus sowohl in der virtuellen als
auch in der gedruckten Form der Bilder. Es gibt kein Relief in den Bildern, keinen daraus resultierenden Schattenwurf, wie wir es von realen
Ölgemälden gewohnt sind. Die Bilder sind flach und glatt. Doch auch dies
ist den bisher nicht ausreichenden technischen Möglichkeiten geschuldet
und wird wahrscheinlich, wie auch mangelnde Komplexität der Malsysteme, bald der Vergangenheit angehören. Erste Ansätze zum Bau von 3DDruckern gibt es bereits seit den 1980er Jahren. Heute sind die Systeme
auch für Privatkunden bezahlbar.
Auf der Seite http://www.3d-druck-vergleich.de wird mit Preisen
ab 689 Euro für ein 3D-Drucker-Kit geworben (Stand 20.01.2012), fertige
Systeme gibt es ab ca 1500 Euro. Die meisten 3D-Drucker erstellen Objekte aus Kunststoff, auf der Cebit 2011 stellte das irische Unternehmen
Mcor Technologies aber einen 3D-Drucker vor, der Objekte aus normalem
Druckerpapier herstellt. Auf Youtube findet sich ein Video dieses Verfahrens: http://www.youtube.com/watch?v=V2EVkmR3jbM.
Hiermit wäre es leicht möglich, auch dreidimensionale Gemälde mit Pinselduktus auszudrucken. Auch in virtuellen Bildern lässt sich ein Pinselduktus simulieren. Dazu ist es allerdings nötig, dass sich entweder das Bild
vom Betrachter drehen und neigen lässt oder dass die Position der Lichtquelle im Raum verschiebbar ist, damit verschiedene Schattenwürfe dargestellt werden können. Ein Gemälde wäre dann sowohl in seiner virtuellen,
als auch in seiner gedruckten Version ein 3D Objekt. Der Aufwand hierfür
wird immer geringer, da die Hardware günstiger und die Rechenleistung
und der Speicherplatz der Computer und auch die Datenübertragungsrate
des Internets immer größer wird.
2
2.1
Entwicklung eines eigenen Malprogramms
Das QT Framework
Für mein eigenes Malprogramm habe ich das GUI Framework QT verwendet. QT ist ein sehr umfangreiches, aber dennoch benutzerfreundliches und
10
intuitives Framework für plattformunabhängige Entwicklung grafischer
Oberflächen und bietet sich dadurch für die Entwicklung aktueller Software an. Der Einstieg in QT fällt vergleichsweise leicht. Das Framework ist
sehr gut dokumentiert und es gibt zahlreiche Bücher, aber auch Tutorials
und Internetforen. QT bietet eigene Klassen zum Zeichnen von Raster- und
Vektorgrafiken, aber auch der Widgets, aus denen eine QT-Oberfläche aufgebaut ist. Objekte, deren Klasse von QPaintDevice abgeleitet ist, abstrahieren von einem zweidimensionalen Objekt, in das gezeichnet werden kann.
Zum Zeichnen wird ein Objekt der Klasse QPainter verwendet, mit dessen
Hilfe in QPaintDevices oder auf andere Widgets gezeichnet werden kann.
QPainter bietet optimiertes Zeichnen auf niedriger Systemebene und stellt
viele vorgefertigte Funktionen zum Zeichnen von Primitiven und Figuren
zur Verfügung. Hierzu zählen zum Beispiel Linien, Rechtecke, Kreise, aber
auch Schriftzüge, Splines oder Tortendiagramme, sowie Optionen zur Veränderung der Strichbreite, -farbe, oder Deckkraft, und außerdem verschiedene Kompositionsmodi, mit deren Hilfe Ziel- und Quellfarben auf unterschiedliche Weise miteinander verknüpft werden können. Da mein Malprogramm ein rasterbasiertes Malprogramm werden sollte, um Zugriff auf
jeden einzelnen Pixel zu erhalten, habe ich als Bildklasse die von QPaintDevice abgeleitete Klasse QImage gewählt, die hardwareunabhängige Datenverarbeitung und direkten Pixelzugriff bietet.
Für das Hauptfenster eines Programms bietet QT die Klasse QMainWindow,
um die herum eine Applikation aufgebaut werden kann. Das QMainWindow stellt eine Menüleiste zur Verfügung, zu der einzelne Menüs hinzugefügt werden können. Die Menüs beinhalten QActions, die auch in Gruppen zusammengefasst werden können. QT bietet eine Erweiterung des C++
Sprachstandards durch einen Meta-Object-Compiler (MOC). Der MOC liest
alle zum Programm gehörigen Header Dateien und erstellt für jede Klassendeklaration, die das Makro Q_Object enthält, eine C++ Quelldatei mit
Metaobjektprogrammcode. Unter anderem enthält dieser Metaobjektprogrammcode den C++ Code, für den Signals and Slots Mechanismus von
QT, außerdem Laufzeittypinformationen und das Dynamic Property System.
Die Signals and Slots Funktionalität ist charakteristisch für QT. Sie erlaubt
dem Programmierer auf einfache und intuitive Weise, die Aktionen des
Endbenutzers mit selbstgeschriebenen Funktionen zu verknüpfen. Klickt
der Benutzer beispielsweise einen Button, so wird das Signal clicked() des
Button-Objekts ausgelöst. Mit der statischen Funktion connect der QObject
Klasse kann jedes Signal mit einem Slot verbunden werden. Slots sind hierbei Funktionen, die wie normale C++ Funktionen implementiert und aufgerufen werden.
Der einzige Unterschied zwischen normalen C++-Funktionen und QT-Slots
ist, dass Slots mit QT-Signalen verbunden werden können. Ein Signal kann
mit beliebig vielen Slots verbunden sein und umgekehrt. Außerdem kann
11
ein Signal auch mit einem anderen Signal verbunden werden, sodass das
zweite Signal sofort ausgesandt wird, wenn das erste versendet wurde. Zu
beachten ist hierbei, dass die Signatur eines Signals der des mit ihm verbundenen Slots entsprechen muss. Dadurch wird die Typsicherheit des Signals and Slots Mechanismus gewährt.
Codebeispiel 1:
QAction* newAction = new QAction(tr("&New"), this);
connect( newAction, SIGNAL(triggered()),
this, SLOT(newDocument()) );
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(newAction);
Im Codebeispiel 1 wird ein Zeiger auf eine neue QAction erzeugt. Die
Aktion bekommt als erstes Argument einen String übergeben. Dies ist der
Text, der im Menü für die Aktion angezeigt wird. Das zweite Argument
ist das Parent-Object für die Aktion. Wird der Quellcode in einem QMainWindow Ojekt verwendet, ist also das MainWindow das Vaterobjekt der
Aktion. Anschließend wird mit der statischen connect-Funktion das Signal
triggered() des QAction-Zeigers mit dem Slot newDocument() des MainWindows verbunden. Ein File-Menü wird erzeugt und die Aktion hinzugefügt. Die Signatur des Signals entspricht der des Slots: beide Argumentlisten sind leer. Die Verbindung funktioniert nur, wenn der Slot newDocument() zuvor als Slot deklariert wurde. Slots werden wie Funktionen als
public oder private deklariert, nur dass das Schlüsselwort slot zum Schlüsselwort public bzw. private hinzugefügt wird. Ist der Slot nicht deklariert,
wird weder ein Kompiler- noch ein Laufzeitfehler ausgelöst. Wird das Signal gesendet, passiert nichts. Die Funktion tr(QString) dient der Übersetzung des Programms in verschiedene Sprachen.
Das Hauptfenster des Programms besitzt nun eine Menüleiste,
die mit Menüs und Aktionen bestückt werden kann.
2.2
Ein Programmrahmen mit ersten Funktionen
Für ein erstes, einfaches Malprogramm muss noch die Mausposition abgefragt werden. QT bietet viele Eventfunktionen, um Benutzeraktionen und
-eingaben abzufragen. Für Mausabfragen steht die Funktion QMouseEvent
der Klasse QWidget bereit, die von der Klasse QInputEvent erbt, die wiederum von der Klasse QEvent erbt. Die Funktion QMouseEvent wird immer aufgerufen, wenn die Computermaus zur Programmlaufzeit bewegt
wird. Durch die Mausbewegung soll der Benutzer zunächst einfache Linien auf ein Bild der Klasse QImage malen können. Hierfür habe ich die
12
Klasse QPaintArea angelegt, die von der Klasse QWidget abgeleitet ist, sodass ich die QWidget-Funktionen verwenden kann. Die QPaintArea Klasse bekommt ein QImage namens m_Image als privates Klassenmitglied
und die QMouseEvent Funktionen QMouseMoveEvent, QMouseClickEvent und QMouseReleaseEvent werden überschrieben. Im Folgenden werden alle Mitgliedsvariablen mit m_... bezeichnet. Wenn nicht anders beschrieben, handelt es sich um ein Mitglied der Klasse, von der aktuell die
Rede ist.
Jede der Mausfunktionen bekommt nun als Argument einen Zeiger auf ein
QMouseEvent Objekt übergeben, das die nötigen Informationen über die
Mauseingabe beinhaltet (Mausposition, gedrückte Mausbuttons, Eventtyp
und Keyboardmodifiers). Mit QPainter wird nun auf das QImage gezeichnet. Hierfür wird ein Objekt der QPainter-Klasse angelegt, wobei es als Argument im Konstruktor das QImage erhält, die Zeicheneinstellungen mit
den QPainter-Funktionen festgelegt, und dann die drawLine-Funktion des
QPainters aufgerufen, die als Argumente zwei Punkte der Klasse QPoint
erhält.
Codebeispiel 2:
QPainter painter(&m_Image);
if(m_Button == 1)
{
//left button pressed, painting with left color
painter.setPen(QPen(m_ToolColorLeft, m_StrokeWidth,
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
}
else if(m_Button == 2)
{
//right button pressed, painting with right color
painter.setPen(QPen(m_ToolColorRight, m_StrokeWidth,
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
}
painter.drawLine(m_LastPoint, endPoint);
int rad = (m_StrokeWidth / 2) + 2;
update(QRect(m_LastPoint, endPoint).normalized()
.adjusted(-rad, -rad, +rad, +rad));
m_LastPoint = endPoint;
13
Strichfarbe, -breite und -aussehen werden mit der Klasse QPen festgelegt. Das QPen-Objekt bekommt die Eigenschaften im Konstruktor übergeben und wird dann an den Painter weitergereicht. In der Funktion MousePressEvent wird abgefragt, ob der Benutzer die rechte oder die linke
Maustaste gedrückt hat, und die Membervariable der PaintArea entsprechend auf 1 bzw. 2 gesetzt. Dies wird in der MouseMoveEvent-Funktion
abgefragt, und die Stiftfarbe entsprechend angepasst. Für die drawLine Funktion werden die aktuelle Mausposition (endPoint) und die Mausposition
des letzten MouseMoveEvent-Aufrufs (mLastPoint) übergeben. Anschließend muss noch die update-Funktion aufgerufen werden, die ein Rechteck
übergeben bekommt, das neu gezeichnet werden soll. Die update-Funktion
ruft die QWidget-Funktion paintEvent auf, in der das Neuzeichnen implementiert wird. Diese Funktion habe ich ebenfalls überschrieben, um selbst
zu bestimmen, wie ein Objekt der Klasse PaintArea neu gezeichnet werden
soll. Das MainWindow bekommt einen PaintArea-Zeiger als Mitgliedsvariable, sodass die Funktionen der Klasse vom Mainwindow aufgerufen und
vom Benutzer ausgelöst werden können.
Nun ist der erste, kleine Schritt geschafft. Es kann ein Linienzug in zwei
verschiedenen Farben gezeichnet werden. Als nächstes soll der Benutzer
die Stiftfarbe selbst bestimmen können. Ich habe dazu eine neue, ebenfalls
von QWidget abgeleitete Klasse erstellt, in der erst einmal die Stifteigenschaften, und später auch die anderen Werkzeuge ausgewählt und deren
Eigenschaften festgelegt werden sollen. Die Klasse nenne ich SettingsWindow und das MainWindow erhält ebenfalls einen Zeiger auf eine Instanz
dieser Klasse. Im Konstruktor wird dem SettingsWindow als Parent das
MainWindow übergeben. Außerdem wird die Toolbar des MainWindows
durch ein View-Menü erweitert, und eine QAction verbinde ich mit einem
Slot, der das SettingsWindow wieder anzeigt, wenn es zuvor geschlossen
wurde.
Als erstes soll über das SettingsWindow die Strichfarbe des einfachen Stiftwerkzeugs geändert werden können. Der Stiftstrich hat jeweils unterschiedliche Farben für Bewegung mit gedrückter linker und rechter Maustaste. Beide Farben sollten vom Benutzer geändert werden können. Also bekommt das SettingsWindow zwei Buttons vom Typ QButton, die an einem
QLayout ausgerichtet werden. Das Aussehen von QButtons kann mit Stylesheets verändert werden. Ich passe die Farbe der Buttons an die jeweilig
aktive Farbe an.
Codebeispiel 3:
m_LeftColor = new QPushButton(tr(""));
m_LeftColor->setStyleSheet("QPushButton
{ background-color: blue; }");
m_RightColor = new QPushButton(tr(""));
14
m_RightColor->setStyleSheet("QPushButton
{ background-color: yellow; }");
connect(
parent,
connect(
parent,
mLeftColor, SIGNAL( clicked() ),
SLOT( setToolColorLeft() ) );
mRightColor, SIGNAL( clicked() ),
SLOT( setToolColorRight() ) );
Klickt der Benutzer nun auf einen der beiden Buttons, wird die entsprechende Funktion setToolColorLeft() bzw. setToolColorRight() des Vater-Widgets, also des MainWindows aufgerufen, die ein QColorDialog-Fenster öffnet, sodass der Benutzer eine RGB-Farbe auswählen kann. Die ausgewählte Farbe wird dann vom MainWindow an PaintArea und SettingsWindow
weitergegeben. In PaintArea wird die Strichfarbe eingestellt und in SettingsWindow die Button-Farbe angepasst.
Codebeispiel 4:
void MainWindow::setToolColorLeft()
{
// open qColor dialog with the actual
left bzw. right color as default value
QColor newColor = QColorDialog::
getColor(mPaintArea->getToolColorLeft());
if(newColor.isValid())
{
m_PaintArea->setToolColorLeft(newColor);
m_SettingsWindow->setLeftButtonColor(newColor);
}
}
Die Setter-Funktion setToolColorLeft(QColor) schreibt die neue Farbe
in die Variablen m_ToolColorLeft und die Setter-Funktion setLeftButtonColor(QColor) passt die Farbe des Buttons an. Die PaintArea- und SettingsWindow-Klasse haben keinen direkten Zugriff aufeinander. Sie kommunizieren immer über das MainWindow miteinander. Die Strichdicke kann auf
die gleiche Art eingestellt werden, wie die Strichfarbe, nur dass wir zur Eingabe keinen Button, sondern einen QSlider benutzen. So kann eine große
Auswahl an möglichen Pixelzahlen für die Strichbreite eingestellt werden.
Zusätzlich gibt es noch die QSpinBox, mit deren Hilfe eine Zahl aus einem
Zahlenintervall genauer ausgewählt werden kann, entweder, indem eine
Zahl in das kleine Zahlenfeld getippt wird, oder mit den kleinen Pfeilen
neben dem Fenster. Der QSlider wird mit der QSpinBox verbunden und
umgekehrt, sodass beide Objekte immer den selben Wert anzeigen, und
die Strichbreite über beide Eingabeobjekte verändert werden kann.
15
Abbildung 5: QSlider und QSpinBox Kombination
Für die Deckkraft des Stiftwerkzeugs wiederhole ich das ganze; auch
sie soll mit einer Kombination aus QSlider und QSpinBox verändert werden können. Über das MainWindow werden die Daten an PaintArea gesendet und an den QPainter übergeben. Hierfür stehen die Funktionen setStrokeWidth(int) und setOpacity(float) bereit. Bei der Deckkraft gibt es allerdings
noch ein Problem: der Stiftstrich besteht aus vielen kurzen, geraden Linien.
Wenn die Deckkraft nicht vollständig opak eingestellt ist, überlappen die
Striche an den Anfangs- und Endpunkten, sodass der gezeichnete Linienzug gepunktet aussieht (s. Abbildung 6).
Abbildung 6: Anfangs- und Endpunkte des Striches überlappen
Zu der Lösung dieses Problems komme ich später. An dieser Stelle habe
ich zunächst das Gesamtkonzept des Programms geplant und die Anforderungen aufgestellt.
16
2.3
Anforderungen und Konzept
Um mir über die Bedienung und die Funktionen des Programms genauer
klar zu werden, habe ich erst einmal einen Entwurf der fertigen Oberfläche gezeichnet, so wie ich sie mir zu diesem Zeitpunkt vorgestellt habe (s.
Abbildung 7). Die Oberfläche sollte einfach und übersichtlich strukturiert
sein. Das MainWindow, die PaintArea und das SettingsWindow mit seinen
drei bisher implementierten Einstellungsmöglichkeiten hatte ich bereits.
Eine Ebenenfunktionalität sollte in jedem guten Mal- und Illustrationsprogramm enthalten sein. Also brauchte ich ein Ebenenfenster, in dem die einzelnen Bildebenen angelegt und verwaltet werden können. Das SettingsWindow sollte nicht nur die Stiftoptionen, sondern auch weitere Werkzeuge und deren Optionen enthalten und in ToolWindow umbenannt werden.
Abbildung 7: GUI Entwurf
Die Werkzeuge im ToolWindow sollten zunächst einfache, geometrischer Formen zeichnen, und zwar Linien, Ellipsen, Rechtecke und Splines.
Außerdem sollte das Stiftwerkzeug durch ein Radiergummiwerkzeug ergänzt werden, und das ToolWindow dynamischer gestaltet werden, sodass
in der oberen Hälfte des Fensters das Werkzeug ausgewählt werden, und in
der unteren Hälfte die jeweiligen Einstellungen zum ausgewählten Werkzeug verändert werden können.
Im Ebenenfenster (Layers-Window) sollte eine Liste der aktuell vorhande17
nen Ebenen angezeigt werden. Der Benutzer soll neue Ebenen anlegen,
Ebenen auswählen, die jeweils ausgewählte Ebene löschen, sichtbar oder
unsichtbar machen und nach oben oder unten verschieben können. Die
Ebenen liegen übereinander, sodass der Inhalt einer Ebene den aller darunter liegenden Ebenen verdeckt. Außerdem soll der Benutzer Deckkraft
und Mixing-Mode der ausgewählten Ebene einstellen können.
Natürlich soll es auch möglich sein, ein neues Bild anzulegen, Bilder zu öffnen, zu speichern und zu drucken. Außerdem soll eine Undo-Funktion für
jede Ebene implementiert werden und gelöschte Ebenen sollen wieder aus
dem Papierkorb zurückgeholt werden können. Auch eine Zoomfunktion
ist wünschenswert. Später sollte optional ein komplexeres Werkzeug implementiert werden, das die Eigenschaften des realen Pendants möglichst
gut simuliert.
2.4
Das Ebenenfenster
Das Ebenenfenster ist ebenfalls eine von QWidget abgeleitete Klasse. Es bekommt den Namen LayersWindow und wird ebenfalls Mitglied von MainWindow. In der Skizze enthält es eine Liste von Ebenen, in der man scrollen
und einzelne Elemente auswählen kann. Dies lässt sich sehr gut mit dem
QWidget QListWidget umsetzen. QListWidget ist ein Kontainer für QListWidgetItems. Es stellt die Items in Listenform dar, und funktioniert ansonsten ähnlich, wie ein normaler C++-Vektor, nur dass QListWidget für den
Benutzer visualisiert wird und die einzelnen Items angeklickt werden können. Sind zu viele Items in der Liste, wird eine Scrollbar hinzugefügt.
Ich erzeuge einen Zeiger auf ein QListWidget, den ich m_LayerList nenne,
und übergebe als Vaterobjekt das Ebenenfenster. m_LayerList ist Klassenmitglied von LayersWindow. Mit der Funktion setSelectionMode() kann
man einstellen, wie sich das QListWidget beim Klicken der einzelnen, in
ihm enthaltenen, Widgets verhalten soll.
Ich wähle QAbstractItemView::SingleSelection, denn es soll immer nur eine
Ebene zur selben Zeit ausgewählt werden können. Außerdem kann sich jedes Item jeweils in einem von drei States befinden: checked, unchecked und
indeterminate. Mit der Funktion setStyleSheet() kann ein kleines Icon festgelegt werden, das den jeweiligen State anzeigt. Ich wähle ein kleines Auge,
das ich gezeichnet habe, da der Benutzer dies von anderen Mal- und Zeichenprogrammen gewohnt ist.
Codebeispiel 5:
mLayerList->setStyleSheet("
QListWidget::indicator:checked {
image: url(images/layerIcons/layer_visible.png);
18
}
QListWidget::indicator:unchecked {
image: url(images/layerIcons/layer_invis.png);
}
QListWidget::indicator:indeterminate {
image: url(images/layerIcons/layer_indet.png);
}
");
Nun erstelle ich zwei Verbindungen mit dem connect-Makro, eines für
das Ereignis, dass ein Widget in m_LayerList ausgewählt wurde (itemClicked(QListWidgetItem*)), und eine für das Verändern des Widgets (itemChanged(QListWidgetItem*)). Wenn eine Ebene angeklickt wird, so wird
das Ereignis über das MainWindow an PaintArea weitergeleitet. Dort muss
die Funktion dann implementiert werden. Außerdem speichere ich mir
einen Zeiger in LayersWindow, der auf das aktuell ausgewählte Item zeigt.
Wenn itemChanged() aufgerufen wurde, frage ich den State des Items ab,
und leite dies ebenfalls an PaintArea weiter.
In der PaintArea müssen diese Funktionen nun implementiert werden. Hierfür habe ich eine neue Klasse namens Layer angelegt, dessen privates Mitglied ein QImage ist. Außerdem speichert es alle Einstellungen, die der
Benutzer für die Ebene festlegen kann, also Deckkraft, MixingMode und
Sichtbarkeit. Später kommen noch einige weitere Informationen und Einstellungsmöglichkeiten hinzu. Die Objekte der Klasse Layer verwalte ich in
einem Standard-C++-Vektor. In der Methode PaintEvent der Klasse PaintArea wird, wie gesagt, festgelegt, wie das Bild, bzw. jetzt die Bilder gezeichnet werden sollen. Ich laufe zum Zeichnen über den Vektor und zeichne die Bilder aller Ebenen, die als sichtbar gekennzeichnet wurden, mit der
jeweilig eingestellten Deckkraft und dem jeweilig eingestellten MixingMode. Hierbei ist darauf zu achten, dass die Ebenen, deren Repräsentanten
im Ebenenfenster weiter unten liegen, zuerst gezeichnet werden, damit sie
von den darüber liegenden Ebenen verdeckt werden.
Da die Reihenfolge der Ebenen, wie sie übereinander gestapelt sind,
wichtig für das gerenderte Bild sind, soll der Benutzer nun auch die Reihenfolge verändern können. Ich füge einen Up- und einen Down- Button
hinzu, wie ich es in der Skizze eingezeichnet habe. Genau wie die anderen
Einstellungen wird das Klicken dieser Buttons über das MainWindow an
PaintArea weitergereicht, und die ausgewählte Ebene wird mit der darüberbzw. darunterliegenden Ebene getauscht. Dies darf natürlich nur passieren,
wenn es nicht die oberste Ebene war, die nach oben verschoben, bzw. die
unterste Ebene, die nach unten verschoben werden soll. In diesem Fall geschieht nichts, außer dass eine Nachricht in der Statusbar des MainWindow
angezeigt wird, der der Benutzer entnehmen kann, dass die von ihm aus19
Abbildung 8: Ebenenfenster - Ellipsen auf Ebenen mit verschiedenen Mixing Modi
geführte Aktion nicht ausgeführt werden kann. Nun füge ich noch einen
Knopf zum Löschen der ausgewählten Ebene hinzu, sodass die aktive Ebene einfach aus dem Vektor in PaintArea und der Liste in LayersWindow
entfernt wird, sobald der Knopf gedrückt wird.
Das Problem mit den Überlappenden Teilstrichen eines Linienzuges
konnte mithilfe einer Extraebene gelöst werden, in der gezeichnet wird. Sobald die Maustaste losgelassen wird, wird der Inhalt der Extraebene über
die aktive Ebene gerendert.
Mit dem Button NewFoil kann eine neue Ebene hinzugefügt werden, die
auf den Ebenenstapel als oberste Ebene abgelegt wird. Später soll mit dem
Button NewPaper noch eine komplexere Ebene angelegt werden können,
die ein Blatt Papier simuliert. Die Normalen Ebenen sollen Folien simulieren, wie man sie z.B. von einem Overheadprojektor kennt.
2.5
Das Werkzeugfenster
Widmen wir uns nun aber zuerst noch einmal dem ToolWindow, denn das
komplexere Werkzeug soll erst später implementiert werden. In der Skizze
sieht man, wie das ToolWindow im weiteren Verlauf der Entwicklung aussehen soll. Es soll nicht mehr nur Einstellungsmöglichkeiten für das Stiftwerkzeug beinhalten, sondern es sollen auch andere Werkzeuge in diesem
20
Fenster ausgewählt und die entsprechenden Optionen angezeigt und eingestellt werden können. Wählt der Benutzer ein anderes Werkzeug aus, so
sollen im unteren Teil des Fensters nur die Optionen angezeigt werden,
die der Benutzer für das ausgewählte Werkzeug sinnvoll verändern kann.
Ein Radiergummi beispielsweise hat keine Farbe, deshalb ist es sinnlos,
das Layout für die Farbeinstellungen anzuzeigen, wenn das Radiergummiwerkzeug ausgewählt wurde.
Ich habe das SettingsWindow in ToolWindow umbenannt und einen QSplitter hinzugefügt. Ein Splitter ist in GUI-Bibliotheken ein Trenner, der ein
Fenster in zwei Unterfenster trennt, die jeweils wie ein normales Fenster benutzt werden können. Einem Splitterobjekt muss im Kontruktor die
Ausrichtung, zusätzlich zum Vaterfenster übergeben werden. Qt::Vertical
bedeutet hierbei, dass die beiden Fenster, die getrennt werden sollen, vertikal zueinander ausgerichtet sind, der SplitterHandle (die "Linie", die der
Benutzer anklicken und verschieben kann, um die beiden Fenster zu skalieren), ist also horizontal ausgerichtet. Zu dem Splitter füge ich zwei neue
Widgets hinzu, eins für die Werkzeugbuttons und eins für die Optionen.
Das Widget für die Werkzeugbuttons bekommt ein QGridLayout, sodass die
einzelnen ToolButtons rasterförmig ausgerichtet werden können. Das Widget für die Einstellungen bekommt ein QVBoxLayout, in dem die einzelnen
Groupboxen für die Einstellungen (Z.B. die beiden Buttons für die Farbeinstellungen, oder die QSlider- und QSpinBox-Kombination für Deckkraft
und Linienstärke), übereinander angeordnet werden.
An dieser Stelle habe ich die vier geplanten Werkzeuge zum Zeichnen von
Primitiven (Gerade Linien, Rechtecke, Ellipsen) und Splines implementiert,
und für jedes Werkzeug ein Icon erstellt. Klickt der Benutzer auf einen der
Buttons, werden alle anderen Buttons deaktiviert und die entsprechenden
GroupBoxes für die Einstellungen des ausgewählten Werkzeugs angezeigt.
Anschließend übergebe ich eine Ziffer an das MainWindow, das dieses wiederum an die PaintArea weiterleitet, woraufhin der Werkzeugstatus geändert wird. Die PaintArea befindet sich nun im entsprechenden Modus des
ausgewählten Werkzeuges, und zeichnet für die Benutzereingaben andere
Figuren, als zuvor.
Um eine Vorschau für den Benutzer anzuzeigen, sodass er, wenn beispielsweise eine Ellipse gezeichnet wird, sieht, wie die Ellipse aussehen würde,
wenn er nun den Mausbutton loslassen würde, ohne dass die Ellipse aber
gleich endgültig in das Bild gezeichnet wird, habe ich die Extraebene benutzt, die ich zur Vermeidung der überlappenden Linienstücke angelegt
habe. Wenn der Benutzer mit der linken Maustaste in die PaintArea klickt,
und das Ellipsenwerkzeug ausgewählt hat, ist der erste Punkt der Ellipse
damit festgelegt. Nun kann die Maus mit gedrückter linker Maustaste bewegt werden, wobei jedes Mal ein MouseMoveEvent ausgelöst wird. Bei
jedem MouseMoveEvent wird nun eine neue Ellipse in die Vorschauebene
gezeichnet und die PaintArea in der entsprechenden Bounding-Box neu21
gezeichnet. Lässt der Benutzer nun die linke Maustaste los, wird das Vorschaubild gelöscht, es ist dann transparent und zeigt nichts an. Die fertige
Ellipse wird in der ausgewählten Ebene mit den passenden Einstellungen
für das Ellipsenwerkzeug und der entsprechenden Ebene gezeichnet.
Abbildung 9: Tool Window
Als die vier einfachen Werkzeuge fertig waren, habe ich noch ein abstraktes Werkzeug hinzugefügt, das einen Splinezug zeichnet. Der Benutzer zeichnet einen Linienzug, der im Vorschaubild angezeigt wird. Wenn er
loslässt, wird ein abstrakter Linienzug aus einer Kette von Splines gezeichnet. Wird der Linienzug im Vorschaubild hierbei schneller gezeichnet, so
befinden sich die Einzelnen Punkte des Linienzuges weiter auseinander,
und der abstrakte Spline sieht etwas wilder und expressiver aus. Zeichnet
der Benutzer die Linie langsamer, so befinden sich die einzelnen Kontrollpunkte näher zusammen und der Splinezug ähnelt der ursprünglichen Linie etwas mehr. Dies ist ein gutes Beispiel für den Zufall, von dem ich im
Abschnitt Anforderungen an Mal- und Illustrationsprogramme Section 1.1
gesprochen habe. Natürlich handelt es sich weder in der Realität, noch in
der Simulation um einen echten Zufall. Für den Benutzer aber, der in beiden Fällen nicht eindeutig das Aussehen des Striches vorhersagen kann,
kommt eine gewisse Zufallskomponente hinzu, die das Bild weniger steif
und kalt wirken lässt. Wie bereits erwähnt, darf diese Zufallskomponente
weder zu groß noch zu klein sein. Der Benutzer soll das Ergebnis einer Ein22
gabe gut abschätzen können, es jedoch nicht genau kennen.
Abbildung 10: Abstract Lines Tool - Example
2.6
Anbindung des Grafiktabletts
Das Grafiktablett dient der Benutzereingabe genau wie die Maus, es kann
allerdings mehr Eingabedaten an das Programm weitergeben. Während
die Maus nur die Position und die gedrückten Mausbuttons an das Programm übertragen kann, dienen verschiedene Grafiktabletts zur Eingabe
von bis zu 6 Freiheitsgraden. Ein Grafiktablett der günstigsten Preiskategorie besitzt nur 3 DOF (Degrees of Freedom), die X- und Y-Position der
Stiftspitze auf dem Tablett, sowie den Druck, den der Benutzer gerade auf
den Stift ausübt. Günstige Grafiktabletts können auch nicht besonders viele Druckstufen messen. Grafiktabletts mittlerer Preisklasse können wesentlich mehr Druckstufen messen. Zusätzlich zu den Daten, die ein günstiges Tablett liefert, messen sie außerdem die Schrägstellung (X- und Y-Tilt)
des Stiftes (5-DOF). Teure Tablets können als letzten Freiheitsgrad noch die
Drehung um die Stiftachse messen, und die Stiftposition im dreidimensionalen Raum damit eindeutig bestimmen (6-DOF).
In der vorliegenden Arbeit verwende ich ein 5-DOF Tablett. Der Benutzer
soll die Daten, die das Tablett liefert, auf verschiedene Einstellungen des
ausgewählten Werkzeuges abbilden können.
Normalerweise kann jedes Grafiktablett direkt angeschlossen, und als Maus
verwendet werden. Das heißt, die X- und Y-Position wird sofort von dem
Tablett an den Computer übertragen und als Mauseingabe interpretiert.
Möchte man nun auch die anderen Daten, die das Tablett liefert, abfragen,
23
benötigt man eine Bibliothek, die der Anbieter des Tabletts oft selbst zur
Verfügung stellt. Mein Grafiktablett ist von der Firma Wacom, die ebenfalls eine freie Bibliothek für Entwickler anbietet. Leider ist diese Bibliothek nur für die Microsoft Foundation Classes geeignet, das Microsoft GUIFramework. QT hat allerdings seine eigene Tablet-Klasse, mit der nicht nur
die Tablettdaten von Wacom, sondern auch der meisten anderen Tabletts
einer entsprechenden Tablettklasse angebunden werden können. QT kann
beispielsweise die Daten eines sogenannten Stylus abfragen, dies ist gerade
ein Tablett mit 5 Freiheitsgraden. Normalerweise sollten alle Programme,
die für einen Stylus geschrieben sind, mit Tabletts, die 5-DOF bereitstellen,
uneingeschränkt funktionieren, egal von welchem Hersteller das Tablett
ist.
Als erstes muss nun der Applikationstyp geändert werden. Bisher habe
ich in meiner main-Methode eine QApplication erstellt, die die Kommandozeilenargumente übergeben bekommt, dann eine Instanz des MainWindows erstellt, die wiederum in ihrem Konstruktor alle weiteren Klassen des
Programms initialisiert, das MainWindow angezeigt und anschließend die
QApplication mit der exec()-Funktion ausgeführt.
Codebeispiels 6:
#include "mainwindow.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Anstelle von QApplication verwende ich jetzt eine Applikation vom
Typ TabletApplication, die ebenfalls die Kommandozeilenargumente erhält.
Für eine TabletApplication muss nun aber noch ein Zeiger auf ein Objekt
der Klasse übergeben werden, in das gezeichnet werden soll. In meinem
Fall ist das PaintArea. Mit der Funktion setCanvas() der Applikation, übergebe ich einen Zeiger auf ein PaintArea Objekt, das ich zuvor instantiiert
habe. Dann lege ich wieder ein Objekt von MainWindow an, und übergebe hier ebenfalls den Zeiger auf Paintarea, denn hier soll ja ein Zeiger auf
PaintArea als Mitglied gespeichert werden. Als letztes wird die neue Applikation wieder ausgeführt, wie zuvor. Die main-Methode soll übrigens
den selben Rückgabewert haben, wie die Applikation ( app.exec(); ).
Codebeispiel 7:
24
#include "mainwindow.h"
#include "tabletapp.h"
int main(int argc, char *argv[])
{
TabletApplication app(argc, argv);
PaintArea* paintArea = new PaintArea;
app.setCanvas(paintArea);
MainWindow mainWindow(paintArea);
mainWindow.show();
return app.exec();
}
Die Klasse TabletApplication habe ich selbst angelegt, sie erbt von QApplication und fängt QEvents auf, die an die Application gesendet werden.
Erhält sie ein QEvent, das anzeigt, dass der Stift den messbaren Bereich
über dem Tablett erreicht hat, oder diesen wieder verlassen hat, ruft TabletApplication eine Setter-Funktion von PaintArea auf, sodass PaintArea immer richtig auf das entsprechende Eingabegerät reagieren, oder eine Fehlermeldung ausgeben kann, sofern keine Implementierung für ein Gerät
vorhanden ist. TabletApplication reicht nun alle eingehenden TabletEvents
an seinen Zeichenbereich, also PaintArea weiter, wo sie verarbeitet für das
Zeichnen verwenden können.
In PaintArea muss ich die Funktion anlegen, die von TabletApplication aufgerufen wird, und an die die QTabletEvents gesendet werden. Die Signatur
dieser Funktion lautet:
void tabletEvent(QTabletEvent* evt)
Wenn nun ein QTabletEvent die PaintArea über diese Funktion erreicht,
und außerdem eine gültige Ebene ausgewählt ist, die zudem als sichtbar
gekennzeichnet wurde (in unsichtbare Ebenen kann nicht gezeichnet werden), so wird das Event verarbeitet. Die ankommenden Events können
vom Typ QEvent::TabletPress, QEvent::TabletRelease oder QEvent::TabletMove
sein. Außerdem enthalten die Events alle Daten, die das Grafiktablett zu
dem Zeitpunkt, zu dem das Event ausgelöst wurde, zur Verfügung gestellt
hat, normalerweise sind das X-, Y-Position, X-, Y-Tilt und Pressure. Außerdem kann der Typ des Events abgefragt werden. So kann beispielsweise
getestet werden, ob der Benutzer zur Eingabe die Stiftspitze oder den Radiergummi verwendet hat.
Bei den bisher implementierten Werkzeugen soll auf die QEvents TabletPress und TabletRelease genauso reagiert werden, wie auf ein Mausevent.
Hierzu rufe ich einfach die zuvor implementierten Mausfunktionen auf
25
und reiche das TabletEvent an diese weiter, wobei es allerdings gecastet
werden muss:
Codebeispiel 8:
mousePressEvent( (QMouseEvent*) evt );
bzw.
mouseReleaseEvent( (QMouseEvent*) evt );
Außerdem merke ich mir zuvor noch in einer boolschen Mitgliedsvariable von PaintArea (m_DeviceDown), ob als letztes ein TabletPress oder
ein TabletRelease Event kam, der Benutzer also gerade zeichnet, oder nicht.
Dann fange ich die TabletMove-Events ab. Wenn der Stift sich bewegt ist es
wichtig zu wissen, ob der Stift gerade auf dem Tablett ist, oder sich nur in
dem Bereich darüber befindet, in dem zwar die Stiftposition getrackt wird,
und der Cursor entsprechend bewegt werden kann, aber nicht gezeichnet
werden soll.
In m_Tool ist das aktuell ausgewählte Werkzeug gespeichert. Zeichnet der
Benutzer mit dem hinteren Stiftende, soll das aktuelle Werkzeug kurzzeitig auf das Radiergummiwerkzeug umgestellt werden. Auch das Stiftende
mit dem Radiergummi ist Druckempfindlich, sodass die Radiergummigröße während des Zeichnens ständig an den ausgeübten Druck angepasst
werden kann.
Codebeispiel 9:
if(m_DeviceDown){
if(evt->pointerType() == QTabletEvent::Eraser)
{
//set tool to eraser
m_Tool = 1;
}
if(m_PressureWidth)
{ //der Druck wird momentan auf die Strichstärke gemappt
m_StrokeWidthTablet = m_StrokeWidth * evt->pressure();
}
if(m_PressureColor)
{
//der Druck wird momentan auf die Strichfarbe gemappt
m_TabletPenColor.setRed(
m_ToolColorFG.red() * (1.0 - evt->pressure())
+ m_ToolColorBG.red() * evt->pressure() );
m_TabletPenColor.setGreen(
m_ToolColorFG.green() * (1.0 - evt->pressure())
26
+ m_ToolColorBG.green() * evt->pressure() );
m_TabletPenColor.setBlue(
m_ToolColorFG.blue() * (1.0 - evt->pressure())
+ m_ToolColorBG.blue() * evt->pressure() );
}
if(m_TiltWidth){
//Der Gesamttilt wird momentan auf die Strichstärke gemappt
if( (abs(evt->xTilt())) > (abs(evt->yTilt())) )
{
m_StrokeWidthTablet = m_StrokeWidth * abs(evt->xTilt())/30;
}
else
{
m_StrokeWidthTablet = m_StrokeWidth * abs(evt->yTilt())/30;
}
}
if(m_TiltColor){
//Der Gesamttilt wird momentan auf die Strichfarbe gemappt
if( (abs(evt->xTilt())) > (abs(evt->yTilt())) )
{
m_TabletPenColor.setRed( m_ToolColorFG.red()
* (1.0 - float(abs(evt->xTilt())/60.0))
+ m_ToolColorBG.red() *
float(abs(evt->xTilt())/60.0) );
m_TabletPenColor.setGreen( m_ToolColorFG.green()
* (1.0 - float(abs(evt->xTilt())/60.0))
+ m_ToolColorBG.green() * float(abs(evt->xTilt())/60.0) );
m_TabletPenColor.setBlue( m_ToolColorFG.blue()
* (1.0 - float(abs(evt->xTilt())/60.0))
+ m_ToolColorBG.blue() * float(abs(evt->xTilt())/60.0) );
}
else
{
m_TabletPenColor.setRed( m_ToolColorFG.red()
* (1.0 - float(abs(evt->yTilt())/60.0))
+ m_ToolColorBG.red() * float(abs(evt->yTilt())/60.0) );
m_TabletPenColor.setGreen( m_ToolColorFG.green()
* (1.0 - float(abs(evt->yTilt())/60.0))
+ m_ToolColorBG.green() * float(abs(evt->yTilt())/60.0) );
m_TabletPenColor.setBlue( m_ToolColorFG.blue()
* (1.0 - float(abs(evt->yTilt())/60.0))
+ m_ToolColorBG.blue() * float(abs(evt->yTilt())/60.0) );
}
27
}
Das Radiergumiwerkzeug wird allerdings im ToolWindow nicht als aktuelles Werkzeug eingestellt, dies würde den Benutzer nur verwirren. Wenn
er das Stiftwerkzeug mit dem Tabletstift benutzt, ist der Radierummi im
Stiftwerkzeug vorhanden. Der Druck wird im Radiergummimodus immer
nur auf die Radiergummigröße gemappt. Wenn der Benutzer einstellt, dass
der Druck auf die Farbe gemappt wird, spielt dies für den Radiergummi keine Rolle, da er keine Farbe besitzt. Für das Stiftwerkzeug allerdings
kann der Benutzer in den Optionen für das Stiftwerkezeug im Werkzeugfenster einstellen, wie Stiftdruck und Schrägstellung sich auf Farbe und
Linienstärke auswirken sollen.
Im ToolWindow muss es nun noch ein kleines Menü in den Stiftoptionen geben, so dass der Benutzer über kleine Checkboxen einstellen kann,
wie das Stiftwerkzeug auf Zeichenstiftdruck und -schrägstellung reagiert.
Klickt der Benutzer eine Checkbox an, wird die Box mit einem kleinen
Häkchen als aktiviert gekennzeichnet und ein Slot, der wieder über das
connect-Makro mit dem Checkbox-Signal stateChanged verbunden wurde,
wird aufgerufen. In dieser Slotfunktion wird wieder über das MainWindow an PaintArea kommuniziert, dass die Checkbox aktiviert oder deaktiviert wurde. Anschließend werden die boolschen Mitgliedsvariablen von
PaintArea angepasst, die die ausgewählten Optionen speichern. m_TiltColor
gibt zum Beispiel an, dass die Schrägstellung des Zeichenstiftes auf die
Stiftfarbe abgebildet werden soll.
Abbildung 11: Tablet Menü - Tablet Druck wird auf Farbe und Strichbreite gemappt
28
2.7
Undo, Redo und Zoom
Abbildung 12: Die Werkzeugleiste mit ToolButtons für Undo / Redo, Zoom und
andere Aktionen
Die Undo-Funktion kann in einem Malprogramm auf verschiedene Weisen umgesetzt werden. Die einzige Bedingung ist, dass die n letzten Benutzereingaben rückgängig gemacht werden können. Hierbei kann das gesamte Protokoll der letzten Eingaben gespeichert, und auch Eingaben an
beliebiger Stelle des Protokolls gelöscht werden. Ich habe mich dafür entschieden, die Undo-Funktion ebenenbasiert zu implementieren. Es wird
nicht das gesamte Protokoll gespeichert und die Eingaben können nur in
der umgekehrten Reihenfolge rückgängig gemacht werden. Allerdings werden immer nur die Eingaben der aktuell ausgewählten Ebene zurückgenommen. So können auch verschiedene Eingaben zurückgenommen werden, die vor der letzten Eingabe verarbeitet wurden. Wenn beispielsweise auf Ebene 1 etwas mit blauer Farbe gezeichnet wird, und anschließend
auf Ebene 2 mit gelber Farbe, dann kann anschließend Ebene 1 ausgewählt,
und die Undo-Funktion ausgelöst werden, sodass die Zeichnungen mit der
blauen Farbe gelöscht werden, diejenigen mit gelber Farbe aber nicht, obwohl sie danach gezeichnet wurden.
Umgesetzt habe ich dies mit einem C++-Standard-Stack von Bildausschnitten, der eine benutzerdefinierte Größe hat. Der Benutzer kann beim Erstellen einer neuen Ebene die Stapelgröße des Undo-Stacks für diese Ebene
angeben. Bei jeder Benutzereingabe, also jeder Zeichnung eines neuen Linienzuges mit dem Stiftwerkzeug oder eines Primitives mit dem Rechteck, Ellipsen- oder einem sonstigen Werkzeug, wird der ursprüngliche Bildausschnitt in der Bounding-Box der neuen Eingabe auf dem Stack abgelegt. Beim Auslösen der Undo-Funktion, wird der oberste Bildausschnitt
der aktiven Ebene vom Undo-Stapel der Ebene genommen und an der entsprechenden Stelle über das Bild gezeichnet. Für die Redo-Funktion wird
zuvor noch der Bildausschnitt, der von der Undo-Funktion überschrieben
wird, auf einem zweiten Stapel, dem Redo-Stapel abgelegt. Wird die RedoFunktion ausgelöst, wird der oberste Bildausschnitt vom Redo-Stack heruntergenommen und über den entsprechenden Bildausschnitt gezeichnet,
der wiederum auf dem Undo-Stack abgelegt wird.
Die Zoomfunktion wird über die Toolbar des Mainwindows ausgelöst. Es
gibt jeweils fünf Verkleinerungs- und Vergrößerungsstufen. Wird die ZoomIn oder Zoom-Out Funktion ausgelöst, so wird ein Signal an den entsprechenden Slot gesendet, der die Größe der PaintArea anpasst, und den Zoom29
befehl an die Paintarea weiterreicht, um auch die Größe des angezeigten
Bildes anzupassen. Die Skalierungsfunktion ist in QT, sowie in OpenGL
bereits implementiert. Allerdings müssen die Koordinaten für die Mausund Stifteingabe auf die neue Größe neu gemappt werden.
3
Mal- und Zeichensimulation
An dieser Stelle habe ich die Wahl des Werkzeugs getroffen, das im Programm simuliert werden soll. Da ich ein Grafiktablett mit fünf Freiheitsgraden verwende, die Drehung um die Stiftachse also nicht berücksichtigt wird, möchte ich ein Werkzeug simulieren, das achsensymmetrisch ist.
Hierfür habe ich mich zunächst mit vorangegangen Arbeiten zur Simulation künstlerischer Medien beschäftigt.
3.1
Bisherige Projekte zur interaktiven Simulation von Mal- und
Zeichenmedien
In diesem Kapitel stelle ich in der Vergangenheit entstandene Projekte vor,
in denen verschiedene Werkzeuge und Medien simuliert wurden. Ich beschränke mich hierbei auf interaktive Methoden, also Projekte, in denen
einzelne Striche vom Benutzer erzeugt und anschließend vom System simuliert werden. Es gibt weitere Projekte, in denen Kunstfilter beschrieben
und implementiert wurden, die aus fertigen Rastergrafiken neue zweidimensionale Bilder erzeugen, die realen Zeichnungen, Skizzen oder Gemälden ähneln. Außerdem gibt es Arbeiten, in denen aus 3D-Modellen solche
zweidimensionalen Grafiken in verschiedenen Stilen erzeugt werden.
Einer der ersten der versuchte, den Mal- und Zeichenstrichen ein organischeres Aussehen zu verleihen, war John Peter Lewis, der 1984 am Massachusetts Institute of Technology ein Programm entwickelte, das zwar kein
spezielles Werkzeug simulierte, mit dem aber doch wesentlich organischer
wirkende Bilder erzeugt werden konnten als dies bisher der Fall gewesen
war [Jew84]. Zuvor waren alle Malprogramme einfacher Natur, der ’Pinsel’
war eine Art Stempel, der einfache Quadrate in den Framebuffer rendert,
und die ’Palette’ eine einfache Liste von RGB-Farben. Lewis entwickelte
ein System, das mit Hilfe der Fast-Fourier-Transformation beliebige Texturen generiert, und so die organische Struktur realer Zeichenuntergründe
annähert.
1986 stellte Steve Strassman in seiner Arbeit "Hairy Brushesëines der ersten Modelle für die Simulation eines speziellen Werkzeuges, nämlich eines Pinsels mit Borstensimulation für Tinte (Sumi-e), vor [Str86]. Strassman modelliert den Pinsel als eindimensionales Array von Pinselborsten,
wobei jede Borste eigene Farbe bereitstellt und eine eigene Position, relativ
30
zum Pinsel besitzt. Während der Pinsel sich den Pinselpfad entlangbewegt,
wird in regelmäßigen Abständen der Zustand aller Pinselborsten aktualisiert (relative Position, Tintenfarbe und -menge ...) und anschließend das
Bild aktualisiert, das sich aus der Pinselbewegung ergibt. Das Programm
konnte Grauwertbilder generieren, die echten Sumi-e Bildern sehr ähneln,
allerdings war das System nicht Echtzeitfähig, da die Rechenleistung zu
dieser Zeit hierfür viel zu gering war. Der Benutzer musste also für jeden
Kontrollpunkt jedes Pinselstriches manuell alle Daten eingeben. Das Rendern eines Pinselstriches dauerte, je nach Komplexität und Qualität des Antialiasings ein bis zwei Minuten.
Abbildung 13: Shrimp and Leaf - sume-e painting
Abbildung 14 zeigt ein Beispielbild, das Strassmans Programm mit 17
Pinselstrichen erzeugt hat, wobei jeder Pinselstrich mit Hilfe von jeweils
zwischen drei und acht Kontrollpunkten generiert wurde. Das Bild wurde
mit Antialiasing versehen, es hat eine Farbtiefe von acht Bit und eine Originalauflösung von 640 x 480 Pixeln.
Zwei Jahre später entwickelte ein Team um Teresa W. Bleser [TWBM88]
ein Modell für die Simulation von Zeichenkohle. Grundlage hierfür war
eine Matrix von Bitmaps, wobei abhängig von Druck und Schrägstellung
des Zeichenstiftes jeweils das passendste Bitmap ausgewählt und gerendert wurde.
Seit der Veröffentlichung von Strassmans Arbeit, wurde das japanische Sumie (auch Suiboku-ga) ein beliebtes Thema für Nonphotorealistic Rendering
und eine ganze Reihe weiterer Arbeiten hierzu folgten ([GK91], [TKH95],
[ZST+ 99], [Lee91], [Lee01], [SN99], [SN00], [WI00], [YJYC02], [YJYL03], [CT02],
[CT04], [JSYO02], [SXP03], [SXP03]).
Für die Tintenausbreitung wurden in den Arbeiten verschiedene Ansätze
gewählt. [ZST+ 99]] entwickelten einen Algorithmus, der auf einem Gitter
automatisierter Zellen beruht. [SXP03] verwendeten partielle Differential-
31
gleichungen . [GK91] stellten eine Methode vor, die später noch öfter aufgegriffen wurde. Sie modellierten das Papier als ein Gewebe von Papierfasern und berechneten den Tintenaustausch zwischen benachbarten Zellen
anhand der Anzahl von Papierfasern die sie jeweils verbindet.
Ein recht berühmtes Model für ein Malprogramm stellte Tunde Cockshott
in seinen Arbeiten von 1991 und 1992 vor [Coc91], [TCE92]. Cockshott, als
Künstler unzufrieden mit den damaligen Simulationsprogrammen für Malerei, beschäftigte sich später selbst mit Computergrafik und entwarf sein
Modell "Wet & Sticky", das ebenfalls auf einem 2D-Gitter von selbstständigen Automaten besteht, die mit ihren Nachbarn Farbpartikel austauschen,
doch er stellte neue Regeln auf, nach denen der Farbaustausch stattfindet.
Farbe fließt in seinem Modell von höher gelegenen zu niedriger gelegenen
Nachbarzellen und wird auch von der Gravitation und der Oberflächenspannung beeinflusst. Sein Fokus lag vor allem auf der Farbsimulation ohne weiteren Einfluss des Benutzers, sodass sich die Farbe vermischt und
fließt, wenn der Strich getan und die Eingabe beendet ist. Diese Berechnungen waren für ein Echtzeitsystem mit damaliger Rechengeschwindigkeit
sehr komplex, weshalb das Modell auch keine zusätzliche Pinselsimulation bieten konnte.
David Small stellte 1991 eine Arbeit zur Simulation von Wasserfarben vor,
welche ebenfalls auf dem Prinzip der automatisierten Papierzellen beruht,
die jeweils mit ihren direkten Nachbarn interagieren [Sma91]. Eine generelle Arbeit zum Thema Cellulare Automata wurde 1987 von Kristian Lindgren
veröffentlicht [LN90]. Curtis et. al stellten 1997 ein weiteres Modell zur Simulation von Wasserfarben vor [CAS+ 97]. In der Arbeit werden die Eigenschaften von Wasserfarbe auf Papier analysiert und die einzelnen Effekte so
genau wie möglich nachempfunden, wobei Wert auf die Echtzeitfähigkeit
des Systems gelegt, und ein Mittelweg zwischen realistischer Simulation
und Performanz gesucht wird. Wie auch Cockshot versuchen Curtis et. al
gerade so viele physikalische Eigenschaften zu simulieren, dass ein plausibles Verhalten des Mediums bei vertretbaren Kosten erreicht wird. 2004
veröffentlichte Tom van Laerhoven und sein Team eine Arbeit, in der das
System von Curtis et. al neu implementiert und die Rechengeschwindigkeit
erhöht wurde, indem das Papier in Kacheln unterteilt und die Berechnungen für diese auf Clustering Processing Einheiten verteilt wurden.
Eine ähnliche Methode wie das Team um Bleser von 1988 verwendeten
Mark Alan Zimmer und John Derry 1998 zur dynamischen Generierung
von Strichen verschiedener Medien wie Pinselstriche, Bleistift, Zeichenkohle und andere. Die einzelnen Striche wurden ebenfalls abhängig von
Schrägstellung und Druck des Eingabestiftes unter Berechnung weiterer
physikalischer Eigenschaften aus einer Menge von vorgegeben Mustern erzeugt [Zim98].
Dave Rudolf und seine Kollegen am Department of Computer Science University of Saskatchewan stellten in den Jahren 2003 und 2004 Arbeiten zur
32
Simulation von Wachskreide vor. Der Benutzer gibt einzelne Striche vor,
aus denen anschließend ein Wachskreidebild erzeugt wird [DRN03], [DRN04].
William Baxter veröffentlicht seit 2001 regelmäßig Arbeiten zum Thema
non-photorealistic Rendering (NPR). 2001 entwickelten Baxter, Vincent Scheib,
Ming C. Lin und Dinesh Manochaunter eine Arbeit mit dem Namen "DAB:
Interactive Haptic Painting with 3D Virtual Brushes". DAB ist der Name
des Systems, das sie zu der Arbeit entwickelten, eine Kombination aus
komplexem Pinsel- und Farbmodell, gekoppelt an ein Phantom Device zur
Ausgabe von haptischen Rückmeldungen [BSL01]. 2004 veröffentlichten
Baxter, Wendt und Lin ein weiteres System namens IMPaSTo, welches es
den Benutzern ermöglichte, virtuelle, pastose Gemälde, ähnlich Öl- oder
Acrylgemälden mit sehr realistisch wirkendem Pinselduktus zu schaffen
[BWL04]. 2004 erschienen auch separate Arbeiten zu den verwendeten Pinselund Farbmodellen und der haptischen Interaktion mit fluiden Medien [BL04],
[BLL04]. 2010 veröffentlichte das Team von Nelson Chu, William Baxter, LiYi Wei und Naga Govindaraju für die Microsoft Research eine Arbeit zur
detaillierten Simulation von viskosen Fluiden wie Öl- oder Acryfarben auf
Leinwand in Kombination mit 3D Pinseln [CBWG10].
3.1.1
Nähere Betrachtung eines Simulationsansatzes: Wasserfarbensimulation
In [CAS+ 97] wird ein Modell zur Simulation von Wasserfarben auf Papier
vorgestellt. Das Papier wird hierbei durch drei Schichten repräsentiert. Die
oberste Schicht ist die shallow-water-Schicht. Auf dieser Schicht kann sich
das Wasser frei bewegen, wobei es die Wasserfarbpigmente mit sich trägt.
Die zweite Schicht ist die pigment-deposition Schicht, auf der sich die unbewegten Pigmente befinden. Mit der Zeit wandern die Pigmente langsam
von der shallow-water Schicht zur pigment-deposition Schicht. Sie können
aber auch wieder in die shallow-water-Schicht zurück gelangen. Die dritte
Schicht ist die capillary Schicht, die die Kapillargefäße des Papiers simuliert.
Hier wird die Bewegung des bereits vom Papier absorbierten Wassers in
den Papierfasern simuliert. Außerdem werden einige weitere Hilfs-Arrays
benutzt, die bestimmte Eigenschaften des Papiers diskretisiert abspeichern:
• Die wet-arrea-Maske, eine bool-Maske, in der gespeichert wird, welche Bereiche des Papiers schon mit Wasser in Berührung gekommen
sind und welche nicht. Diese Information ist für den Kapillareffekt
wichtig.
• Eine Maske für die Flussgeschwindigkeit des Wassers in der x- und
y-Richtung.
• Eine Maske für den Wasserdruck an jeder Stelle des Papiers
33
• In einer weiteren Maske sind die Konzentrationen der einzelnen Farbpigmente an jeder Stelle des Papiers gespeichert
• Eine Gradientenkarte, in der die Höhenwerte der rauen Papieroberfläche abgespeichert sind
• Die fluid-capacity Maske speichert für jede Zelle die Maximale Kapazität an Farbe
• Und eine letzte Maske, in der die physikalischen Eigenschaften der
Wasserfarbmischung, wie die Viskosität und Reibungswiderstand abgespeichert werden.
Alle Masken werden für jeden Zeitschritt aktualisiert. Die Werte in den
einzelnen Masken beeinflussen sich gegenseitig und hängen voneinander
ab. Die Durchlässigkeit der einzelnen Schichten ist z.B. von der Viskosität,
der Dichte und den Van-der-Waals-Kräften abhängig.
Die Simulation von Curtis et. al generiert zunächst ein virtuelles Papier. In der Hauptschleife werden in festen Zeitabständen die Masken aktualisiert und der Transfer zwischen den Schichten berechnet. Zuerst wird
das Höhenfeld per Pseudo-Zufallsmechanismus erzeugt, und die Werte auf
den Bereich von 0 bis 1 gemappt. Solche Pseudo-Zufallsmechanismen werden z.B. in [Per85] oder [Wor96] vorgestellt. Aus den Gradienten des Höhenfeldes lassen sich anschließend die x- und y-Flussrichtungen des Wassers berechnen. Auch die maximale Aufnahmefähigkeit des Papiers an jeder Stelle wird aus dem Höhenfeld berechnet als c = h ∗ (cmax − cmin) +
cmin.
Die Hauptschleife des Programms berechnet für jeden Zeitschritt die Bewegung des Wassers und der Pigmente innerhalb der einzelnen Schichten.
Danach folgt die Berechnung des Pigmenttransfers, wobei aus der Konzentration der Pigmente in der pigment-deposition und shallow-water-Schicht
und der wet-arrea-Maske berechnet wird, wie viele Pigmente von der shallow-water-Schicht zur pigment-deposition Schicht übertragen werden sollen und umgekehrt. Als Letztes wird für jeden Zeitschritt noch die Wirkung
der Kapillarkräfte simuliert, indem die wet-arrea-Maske entsprechend der
Wasserkonzentration in den nassen Zellen vergrößert, und Wasser von jeder Zelle an ihre Nachbarzellen übertragen wird, sofern deren Wasserkonzentration um einen bestimmten Schwellwert niedriger ist, als die eigene.
Die Simulation der Kapillarkräfte ermöglicht außerdem einen Effekt, der
typisch für Wasserfarben ist, und als Backrun-Effekt bezeichnet wird. Dieser Effekt tritt auf, wenn Wasser in eine teilweise getrocknete, und teilweise noch feuchte Region zurückfließt. Abbildung 15 c) zeigt den BackrunEffekt. Die Abbildung stammt von Curtis et. al. Abbildung 15 b) zeigt den
Edge-Darkening-Effekt. Dieser Effekt entsteht, wenn der Pinsel nass ist und
34
auf eine trockene Stelle des Papiers gemalt wird. Das Wasser neigt dann dazu, in Richtung der Ränder des Striches zu fließen. Dabei trägt es Pigmente
mit sich, sodass die Ränder des Striches dunkler werden. Dieser Effekt wird
simuliert, indem der Wasserdruck an den Rändern der wet-arrea-Maske
verringert wird.
Abbildung 14: Curtis et. al: Typische Effekte von Wasserfarben
Der Körnungseffekt, der in Abbildung 15 d) zu sehen ist, wird zwar
durch das Papier, bzw. durch die Höhenmaske des Papiers beeinflusst, er
entsteht aber hauptsächlich durch die Eigenschaften der einzelnen Pigmente. Die Dichte der Pigmente unterscheidet sich, und Pigmente mit einer
höheren Dichte setzen sich schneller auf dem Papier ab, sie werden also
schneller von der shallow-water-Schicht zur pigment-deposition-Schicht
übertragen. Außerdem hat jedes Pigment eine unterschiedlich starke Neigung dazu, sich am Papier festzusetzen. Pigmente, die stärker am Papier
festhalten, neigen weniger dazu, wieder in die obere shallow-water-Schicht
zurück zu wechseln. So entsteht der granulation-Effekt.
Der flow-Effekt in 15 e) entsteht bei realen Wasserfarben, wenn nass auf
nass gemalt wird. In der Simulation entsteht er, indem die Flussrichtungen
in der shallow-water-Schicht berechnet, und die Pigmente entsprechend
bewegt werden. Wenn die wet-area-Maske an der Stelle des Pixels jedoch
den Wert false hat, wird die Flussrichtung auf null gesetzt, sodass der flowEffekt nur bei einem nass in nass Pinselstrich entsteht.
Ein weiterer, für die Simulation von Wasserfarben wichtiger Effekt ist der
Dry-Brush-Effekt, der in Abbildung 15 a) dargestellt ist. Er tritt auf, wenn
der Pinsel relativ trocken ist, und nur noch Farbe an die Stellen des Papiers
überträgt, die einen hohen Wert in der Höhenmaske aufweisen. Dieser Effekt ist leicht umzusetzen, indem aus der wet-arrea-Maske alle Pixel auf
false gesetzt werden, die einen bestimmten Höhenwert unterschreiten. Der
Höhenwert ist abhängig von der Nässe des Pinsels.
Der letzte Effekt, der lasierende Effekt in 14 f), wird durch das KubelkaMunk-Modell, welches Curtis et. al verwenden, erzeugt.
35
Abbildung 15: Simulation der typischen Wasserfarbeffekte durch das System von
Curtis et. al
3.2
Kubelka und Munk Theorie
Farben werden in der Computergrafik im RGB-Farbraum dargestellt. Die
Informationen für den Rot-, Grün- und Blaukanal werden als Zahlen zwischen 0 und 255 abgespeichert, benötigen also jeweils 1 Byte. Das RGBFarbmodell ist ein additives Farbmodell, eine Farbe wird durch Erhöhung
einer einzelnen Komponente immer heller. Additive Farbmischmodelle sind
sinnvoll für die Mischung von Licht, aber nicht für die Mischung verschiedenfarbiger Pigmente. Hier ist ein subtraktives Farbmischverfahren wünschenswert.
Der CMYK-Farbraum ist ein subtraktiver Farbraum, der für den Vierfarbendruck verwendet wird. Ein Farbton wird durch die subtraktive Mischung der drei Grundtöne Cyan, Magenta und Gelb dargestellt, welche
jedoch nur in der Theorie zu allen Farben gemischt werden können. In der
Praxis ergibt die Mischung aller drei Farben zu gleichen Teilen mit voller Sättigung ein dunkles Braun. Deshalb kommt ein K-Komponente (K
steht für Key) hinzu, an der die anderen Farben ausgerichtet werden und
die den prozentualen Schwarzanteil repräsentiert. Das CMY oder CMYKFarbmodell wird zum Beispiel von [Sma91] verwendet.
Aber auch das CMY(K)-Farbmodell ist für die Simulation der Mischung
von Pigmenten nicht gut geeignet, denn es bezieht nur die Absorbtion der
zu mischenden Farben zur Berechnung Mischfarbe mit ein, die Streuung
wird nicht beachtet [HM92].
Das Kubelka und Munk Modell (siehe [Kok07] und [Kub48]) beschreibt
sowohl die Absorbtions- als auch die Streuungseigenschaften von pigmentierten Systemen und wird auch von Farbherstellern zur Berechnung der
Pigmentkonzentrationen genutzt. Der Grundgedanke des Kubelka-MunkModells ist, dass eine dünne Farbschicht, auf die Licht fällt, einen Teil des
Lichtes absorbiert und einen anderen Teil streut. Die Menge des absorbierten und reflektieren Lichtes ist allerdings nicht ganz einfach zu bestimmen.
Das Licht fällt durch die oberste, zuletzt aufgetragene Farbschicht, wobei
bereits ein Teil des Lichtes absorbiert, ein Teil reflektiert und der restliche
Teil durchgelassen wird. Von der darunterliegenden Farbschicht wieder
wiederum ein Teil des auftreffenden, zuvor durchgelassenen Lichtes absorbiert, ein Teil durchgelassen, und ein Teil reflektiert, der daraufhin wieder
36
auf die darüber liegende Farbschicht trifft, wo sich das Spiel wiederholt.
Mathematisch kann der absolute Lichtanteil, der von einer Farbschicht mit
bekannter Dicke absorbiert bzw. zurückgeworfen wird, mit den Gleichungen von Kubelka und Munk berechnet werden. Die Herleitung der Formeln wird in [KM31] beschrieben.
Aus den Streuungs- und Absorbtionseigenschaften S und K einer Pigmentlösung, die übrigens für verschiedene Schichtdicken als konstant angenommen werden, kann nun die konkrete Menge an reflektiertem Licht
R und durchgelassenem Licht T (Transmission) berechnet werden. R und T
hängen von der Dicke der Farbschicht ab.
Sei x die Dicke einer Farbschicht mit bekannten S- und K-Werten, dann
ist die Reflektion R und die Transmission T der Farbschicht definiert als
bSx
c
b
T =
c
R = sinh
(1)
(2)
mit c = asinhbSx + bcoshbSx.
Für das Verfahren müssen der Absorptionskoeffizient K und der Streuungskoeffizient S realer Pigmentlösungen mit einem Spektralradiometer
gemessen werden. Abbildung 17 zeigt ein modernes Spektralradiometer.
Abbildung 16: Spektralradiometer ’Orion’ der Firma IARD sensing solutions
Die Messung erfolgt wie in Abbildung 18 dargestellt, wobei die Messungen mit sehr hoher Präzision durchgeführt werden müssen. Es werden verschieden dicke Farbschichten auf weißem und schwarzem Untergrund aufgetragen. Die Dicke der Farbschicht und die Farbe des Unter37
grundes sind hierbei bekannt. Aus den Messergebnissen werden die Sund K-Koeffizienten für eine sehr dünne Farbschicht berechnet. Hieraus
lassen sich Absorption- und Streuungs-Koeffizienten für entsprechend dickere Farbschichten berechnen. Auch die Koeffizienten für gemischte Farben oder übereinander aufgetragene Farbschichten unterschiedlicher Dicke können berechnet werden [Kub54].
Abbildung 17: Beispielaufbau Spektralradiometer
Die Reflextanz der Farbschicht hängt vom Spektrum des Lichtes ab, mit
dem die Farbschicht beleuchtet wird. für jede Wellenlänge ergeben sich unterschiedliche Werte für die S- und K-Koeffizienten der Farbschicht. Es werden deshalb nur für eine bestimmte Anzahl einzelner Wellenlängen die Sund K-Koeffizienten gemessen.
Allerdings muss die Messung für jede Pigmentlösung und jede Beleuchtungswellenlänge nur einmal erfolgen, sodass bereits vorhandene Werte
übernommen werden können. Hierbei ist jedoch darauf zu achten, dass
verschiedene Messwerte aus der selben Quelle, also aus der selben Messung stammen, da die Werte nicht absolut sind.
Curtis et. al haben in ihrer Ausarbeitung den Benutzer frei Farben definieren lassen, indem er das Aussehen der Farbe über weißen und schwarzem Grund bestimmen konnte. Hieraus können, durch Umkehren der Ausgangsgleichungen die S und K Koeffizienten der benutzerdefinierten Farbe
berechnet werden:
S=
1
b2 − (a − Rw )(a − 1)
· coth−1 (
)
b
b(1 − Rw )
K = S(a − 1)
√
w +1
mit a = 21 (Rw + Rb −R
), b = a2 − 1.
Rb
38
(3)
(4)
Rw steht hierbei für die RGB-Farbwerte über weißen Grund, und Rb für
die RGB-Farbe auf schwarzem Grund. Abbildung 19 zeigt eine Auswahl an
Farben über schwarzem und weißem Untergrund und die dazugehörigen
S- und K-Koeffizienten jeweils für den Rot-, Grün- und Blauanteil der Farbe. Durch Verändern der Werte für Rw und Rb kann der Benutzer eigene
Pigmente kreieren. ρ steht für die Pigmentdichte in der jeweilig simulierten Pigmetnlösung, ω für die zwischen-molekularen Anziehungskräfte, die
Van-der-Waals-Kräfte und γ für die Körnung der Farbet. Auch diese Werte
könnten vom Benutzer für eine Pigmentlösung festgelegt werden.
Abbildung 18: Eine Auswahl gängiger Pigmente aus der Malerei, simuliert mit
dem System von Curtis et. al
4
Entscheidung und Implementierung eines komplexeren Werkzeuges mit Papiersimulation
Da ich ein Grafiktablett mit 5 Freiheitsgraden verwende, wollte ich ein
Werkzeug simulieren, das achsensymmetrisch ist, sodass der fehlende sechste Freiheitsgrad die Simulation nicht beeinträchtigt. Zur Auswahl standen
unter anderem ein Airbrush, Filzstifte, Kugelschreiber, Wachsmalkreide,
Kohle, Blei- und Bundstifte. Wachsmalkreide, Kohle, Blei- und Buntstifte
sind allerdings nur eingeschränkt achsensymmetrisch, denn beim Malen
oder Zeichnen wird das Werkzeug normalerweise durch den Abrieb abge39
schrägt.
Letztendlich fiel die Wahl auf die Simulation eines Filzstiftes, dessen Haupteigenschaft die gleichmäßige Verteilung und Ausbreitung der Tinte, sowie
eine realistische Farbmischung und die Form des Striches oder einzelner
Punkte sind, welche sich sowohl durch den Stiftdruck, als auch durch die
Neigungsrichtung und -stärke ergibt.
Als Vorbild für die Simulation stand der Markertyp ciao mit der Super Brush
Spitze der Firma Copic, der besonders gut für Illustration, Produkt- und
Mediendesign geeignet ist.
Abbildung 19: Copic Marker ciao, Super Brush Spitze
4.1
Eigenschaften von Filzstiften oder Copic Markern
Realistisch wirkende Filzstifte sollten folgende Eigenschaften besitzen:
• Die Strichstärke und -form passt sich dynamisch während des Zeichnens an die Schrägstellung des Stiftes an. Hierbei ist nicht nur die
Neigungsstärke, sondern auch die Neigungsrichtung relativ zur Strichrichtung wichtig.
• Selbstverdeckung: innerhalb eines Striches ohne Absetzen verdeckt
der Strich sich selbst, wenn er sich selbst kreuzt.
• Die Menge der abgegebenen Tinte passt sich innerhalb eines Striches
an die aktuelle Geschwindigkeit an, mit der der Stift über das Papier
bewegt wird. Auch Druck und Neigung bzw. die Kontaktfläche des
simulierten Markers haben Einfluss auf die Deckkraft der Farbe.
• Die Farbe breitet sich realistisch auf dem Papier aus. Die Ausbreitung findet auch nach Absetzen des Stiftes statt und hängt von der
jeweiligen Beschaffenheit des Papieres und der bereits im Papier vorhandenen Tinte ab.
• Die Farbe trocknet mit der Zeit und beeinflusst die neu aufgetragene
Tinte dann nicht mehr oder nur noch sehr schwach.
40
• Die Mischung der einzelnen Farbpigmente soll möglichst realistisch
wirken und nach einem subtraktiven Farbmischverfahren berechnet
werden.
4.2
Implementierung des Filzstift Werkzeugs
Das Filzstiftwerkzeug wird als neues Werkzeug zum Tool Window hinzugefügt. Außerdem habe ich die zweite Art von Ebenen an dieser Stelle
implementiert, die eine Schicht Papier simulieren sollen. Die Papiersimulation ist, wie in der Auflistung der Filzstifteigenschaften gezeigt wurde, für
die Filzstiftsimulation wichtig.
Um ein realistisches Aussehen des Papieres zu erhalten, habe ich ein reales
Blatt Zeichenpapier dünn mit einem hellen Bleistift eingefärbt, um die Erhebungen und das Aussehen der Papierfasern besser Sichtbar zu machen.
Dann habe ich das Papier mit hoher Auflösung eingescannt. Aus dem eingescannten Bild habe ich ein QBrush Objekt angelegt, und das Bild in passender Größe auf einen neu angelegten Simulationslayer zeichnen lassen.
Aus diesem Bild habe ich eine Höhenmap erstellt, indem ich die schwachen
Grautöne des Originalbildes auf die Werte von 0 bis 255 gemappt habe, wie
in Curtis et. al beschrieben. Die Höhenmap beeinflusst später die Ausbreitung der Tinte im Papier.
Für die Ausbreitung habe ich im Simulationslayer ein zweidimensionales Gitter von Papierzellen angelegt. Hierfür habe ich eine Papierzellenklasse geschrieben, die jeweils eine einzelne Papierzelle darstellt. Jede Papierzelle im Gitter kennt ihre eigene ’Höhe’ oder Dicke und ihre Tintenfasskraft, die von der Höhe, also dem Volumen der Zelle abhängt. Außerdem
kennt sie die Farbmenge, die sie bereits enthält und ihre 8 direkten Nachbarzellen.
Um den ersten Punkt der Filzstifteigenschaften zu erfüllen, habe ich
beim Aufsetzen des Stiftes an der entsprechenden Stelle eine Linie anstelle
eines Punktes zeichnen lassen. Der Punkt, an dem der Stift aufgesetzt wurde, befindet sich in der Mitte der Linie. Die Linie zeigt in die selbe Richtung,
wie der Zeichenstift, wenn man von oben darauf schauen würde, und die
Länge der Linie wird von der Neigungsstärke des Stiftes bestimmt.
Wird der Stift bewegt, werden in stetigen Zeitabständen die Stiftdaten an
das Programm gesendet. Bei jedem eintreffenden Zeitsignal wird eine solche Linie gezeichnet und, sofern es nicht das erste Signal des Striches ist,
ein Polygon zwischen den vier Punkten der letzten und der aktuellen Linie
gezeichnet. So ergibt sich für jeden Stiftstrich ein Quadstrip, der Stiftdicke
und Neigungsstärke sowie die Neigungsrichtung abbildet.
Im Gegensatz zu den einfachen Linienzügen des normalen Stiftwerkezuges überlappen die Polygonzüge eines Striches nicht und die Deckkraft
41
Abbildung 20: Ein Ausschnitt der Papiertextur, links die Visualisierung, rechts die
Höhenmap
der einzelnen viereckigen Polygone kann innerhalb eines Striches variieren. Die Polygone des selben Striches können sich gegenseitig überlagern.
Wie man in Abbildung 21 sieht, sind die einzelnen Vierecke unterschiedlich
groß. Da in gleichmäßigen Zeitabständen Signale vom Grafiktablett ausgesendet werden, kann der Stift einen größeren Weg zwischen zwei Signalen
zurücklegen, wenn er schneller bewegt wird. Dadurch werden die Polygone größer, wenn sich der Stift schneller über das Tablett bewegt. Bei einem
Copic Marker wird der Strich lasierender, also weniger deckend, je schneller er über das Blatt bewegt wird. Um diesen Effekt zu simulieren, soll
die Deckkraft der Polygone von deren Flächeninhalt abhängen. Je größer
der Flächeninhalt eines Vierecks, umso geringer seine Deckkraft. Die Farbe
kann der Benutzer wie beim einfachen Stiftwerkzeug einstellen. Auch der
Zeichenstiftdruck wirkt sich auf die Deckkraft aus. Wie bei einem realen
Copic Marker oder Filzstift erhöht ein höherer Zeichenstiftdruck die Deckkraft des aktuellen Polygons (s. Abbildung 22).
Der Benutzer kann mit dem Filzstiftwerkzeug sowohl auf der Folienebene als auch auf der Papierebene malen. Ist eine Papierebene aktiv,
soll nun auch die Papiersimulation in die Filzstiftsimulation miteinbezogen werden, also die letzten vier Punkte der Filzstifteigenschaften simuliert
42
Abbildung 21: Polygonzüge mit dem Filzstiftwerkzeug
werden. Punkt 3 wurde bisher nur halb umgesetzt. Die Zeichengeschwindigkeit und der Druck wirken sich bisher auf die Deckkraft des Stiftes aus,
aber eine Tintenabgabe ist bisher wird bisher nicht simuliert und damit
auch nicht die Menge der abgegebenen Tinte beeinflusst.
Wird also nun eine Papierebene angelegt und ausgewählt, soll eine Tintenabgabe simuliert werden. Hierfür werden die Filzstiftstriche des Benutzers
zunächst auf einem Bild vom Typ QImage namens AddedColorImage gezeichnet. Bei jedem gezeichneten Polygon des Polygonzuges werden werden die Papierzellen der Papierebene in der Bounding-Box um das Polygon herum aktualisiert. Hierbei wird der Polygonzug, so wie er in Abbildung 22 vom Benutzer gezeichnet werden kann, Polygon für Polygon aus
dem Bild, in das der Benutzer zeichnet, herausgelöscht und auf ein weiteres
Bild, das ich InkImage genannt habe, übertragen. Jede einzelne Papierzelle
besitzt nun einen Zeiger auf die RGBA-Werte dieses InkImages. Beim Aktualisieren der Papierzellen in der Bounding-Box (pro Pixel des AddedColorImages und des InkImages gibt es ein Papierzellenobjekt) wird die Farbe aus AddedColorImage in InkImage übertragen, sodass die Papierzelle
43
Abbildung 22: Die Polygonzüge des Filzstiftwerkzeuges mit an Zeichengeschwindigkeit und -druck angepasster Deckkraft
direkten Zugriff auf die Farbe hat. Das InkImage ist alles, was der Benutzer sieht. Wird beim Aktualisieren der Zelle die Tintenkapazität der Zelle
überschritten, was passiert wenn in InkImage mehr Farbe abgelegt werden
soll, als die Zelle fassen kann, läuft die Zelle über. Wenn die Zelle überläuft, merkt sich die Zelle, wie viel Farbe überlaufen soll. Diese Farbe wird
nicht in InkImage geschrieben, sondern auf die 8 Nachbarzellen verteilt,
wobei die Verteilung auf die Nachbarzellen von deren Höhe relativ zur aktuellen Zelle und deren übrige Tintenfasskraft abhängt. Da der Benutzer
nur das Zeichnen in das AddedColorImage auslöst und der Rest automatisch geschieht, findet die Simulation auch noch statt, wenn der Benutzer
zu zeichnen aufgehört hat. Außerdem ist diese Funktion relativ effizient,
da nicht alle Pixel des Bildes angesprochen werden, sondern nur diejenigen
in der Bounding-Box des Polygons und durch die selbstständige Ausbreitung über die Papierzellen kann sich die Tinte auch über die Bounding-Box
hinweg ausbreiten. Damit die Tintenausbreitung konvergiert und die Tinte
nicht in einer Endlosschleife in der Mitte der überlaufenden Regionen hin
44
und her schwappt muss bei jedem Tintenüberlauf ein sehr kleiner Teil der
Tinte verloren gehen. Der verschwindende Teil sollte so gering sein, dass
der Benutzer es nicht bemerkt, aber groß genug um eine größere Anzahl
von Überläufen zwischen dem selben Zellenpaar oder innerhalb einer Zellengruppe zu vermeiden.
Um Eigenschaft Nummer 6 zu erfüllen, habe ich mich an dem Kubelka
und Munk Farbmodell versucht. Wie wir gesehen haben, definiert sich eine Farbe im Kubelka-Munk-Modell durch das Aussehen einer Farbschicht
der Dicke x über einem weißen und einem schwarzen Untergrund. Hierbei
ist zu beachten, dass für die Werte jedes Farbkanals f, in meinem Fall rot,
grün und blau, für beide Farbvektoren Rw und Rb gilt 0 < f < 1. Da die
Farbkanäle hier eine Farbtiefe von 8 Bit haben und somit die Werte [0,255]
annehmen können gilt damit natürlich 0 < f < 255. Eine weitere Bedingung ist, dass für jeden Farbkanal gilt Rb < Rw .
Mit Hilfe der Gleichungen (3) und (4) können aus den Farbwerten Rw und
Rb die S- und K-Koeffizienten für die K&M Farbe berechnet werden. Der
Benutzer kann das Aussehen der Farbe über schwarzem und weißem Untergrund auswählen und die Berechnungen werden ausgeführt. Anschließend werden die R- und T-Werte wie in den Gleichungen (1) und (2) beschrieben für jeden Farbkanal der neu definierten Farbe berechnet.
Jede Papierebene besitzt ein QImage für die R- und ein QImage für die TWerte. Wenn der Benutzer mit dem Filzstiftwerkzeug auf der Papierebene
malt, werden die Polygonzüge mit den jeweiligen RGB-Werten für T und
R in das Transmission- bzw. Reflektions-Bild gezeichnet. Die Papierzellen
in der Bouding-Box werden aktualisiert und die neuen R- und T-Werte für
die Mischfarbe berechnet. Dabei werden R- und T-Werte rekursiv aus den
neu hinzugekommenen R- und T-Werten und den R- und T-Werten der Farbe, die bereits in der Zelle ist, berechnet. Hierfür werden folgende Formeln
verwendet:
T12 R2
(5)
1 − R1 R2
T1 T2
T =
(6)
1 − R1 R2
Die so berechneten R-Werte werden mit den Werten der Farbkanäle aus
der hinzukommenden Farbe multipliziert, und die T-Werte mit den Farbwerten, die zuvor in der Zelle vorhanden waren. Hieraus ergibt sich die
neue Farbe in der Zelle.
Abbildung 23 zeigt die Farbmischung in meinem Malprogramm mit
dem Kubelka-Munk-Modell bei ausgewähltem Filzstifttool auf einer Papierebene. Im Programm sind 12 Farben vorgegeben, der Benutzer kann
aber eigene Farben definieren, indem er die Stiftfarbe auf weißem und
schwarzem Grund auswählt.
R = R1 +
45
Abbildung 23: Filzstiftwerkzeug mit Kubelka und Munk Farmodell
Abbildung 24 zeigt den noch einmal Aufbau meines Programms und
die Zusammenhänge der beschriebenen Klassen anhand eines Klassendiagramms.
5
Bewertung
Von den sechs genannten Eigenschaften von Filzstiften und Copic Markern
konnten einige in der Simulation umgesetzt werden. Punkt 1 wurde vollständig umgesetzt, allerdings wäre es optimal, wenn die Strichdicke bei einer Stiftbewegung in Richtung der Stiftneigung etwas dicker wäre. Durch
ein optimales Verlaufen der Tinte könnte dies erreicht werden. Punkt 2,
die Selbstverdeckung innerhalb eines Markerstriches, wurde umgesetzt.
Auch Punkt 3, die Anpassung der abgegebenen Tintenmenge an die Bewegungsgeschwindigkeit, Druckstärke und Kontaktfläche des Stiftes konnte
gut umgesetzt werden. Hier würde ebenfalls eine optimale Ausbreitung
der Tinte den Effekt verbessern, da die Tinte dann realistisch ineinander
verlaufen, und die schwankende Tintenmenge im Strich sanftere Farbübergänge bilden würde.
Die Tintenausbreitung funktioniert zwar, allerdings breitet sich die Tinte
nur wenig aus. Durch die Verteilung der überlaufenden Tinte auf die acht
Nachbarzellen, die wiederum die Tinte beim Überlaufen an ihre acht Nachbarzellen verteilen, kommt beim Überlaufen einer Zelle bei ihrer übernächs-
46
Abbildung 24: UML Diagramm meines Programms
1
ten Nachbarzelle nur noch 64
der übergelaufenen Farbe an. Die Trocknung
der Farbe wurde mit einem weiteren QImage für die Papierebenen umgesetzt (DryedInkImage). In regelmäßigen Zeitabständen wird die Farbe aus
dem InkImage in das DryedInkImage übertragen, sodass sich die Farbe nur
noch auf die Farbmischung mit dem Kubelka und Munk Model auswirkt,
aber nicht mehr zu der Farbe zählt, die die Zelle fassen kann, und sich damit auch nicht mehr auf die Farbausbreitung auswirkt.
Die Mischung der einzelnen Farbpigmente wirkt realistisch und es wurde mit dem K&M Modell ein subtraktives Farbmodell implementiert, das
eine intuitive Farbmischung und benutzerdefinierte Farben mit individuellen Transmissions- und Reflektionseigenschaften ermöglicht. Der Benutzer
kann mit einem Dialog die Farbwirkung seiner eigenen Farbe über weißem
und schwarzem Grund wählen oder eine von 12 Pigmentlösungen wählen,
die sich normalerweise auch in gängigen Markerkästen befinden.
Das Bild in Abbildung 25 habe ich mit dem Malprogramm, das in dieser
Arbeit vorgestellt wurde, gemalt. Gras und Baum habe ich mit dem Filzstift Werkzeug auf eine Papierebene gemalt. Man sieht die Papierporen und
Unebenheiten im Hintergrund unter dem Blau des Himmels. Die Eule im
Vordergrund, den Himmel, den Mond und Teile der Blätter des Baumes
habe ich mit dem Copic Marker Werkzeug auf darüber liegenden Folien
gemalt. Die unterschiedliche Farbmischung der Markerstriche auf der Folie und der Papierebene ist deutlich sichtbar. Auf der Folienebene wirken
die übereinander aufgetragenen Striche sehr viel lasierender.
47
Abbildung 25: Eule in der Dämmerung mit ScratchUp
6
Ausblick
Um die Eigenschaften des virtuellen Markers noch realistischer zu gestalten, sollte die Tintenausbreitung in den Papierebenen verbessert werden.
Die Tinte sollte sich schneller ausbreiten, sodass der Effekt deutlicher sichtbar ist. Idealerweise sollte der Benutzer die Flüssigkeit im Marker einstellen können, sodass er die Stärke der Tintenausbreitung beeinflussen kann.
Auch ein Konturenstift wäre schön, der die Ausbreitung der Markertinte
aufhält und ein Überlaufen über die Konturen verhindert.
Ein individuelleres Trocknungsverfahren würde die Simulation verbessern,
in dem pro Zelle die Tinte nach einer gewissen Zeit trocknet. Dieses Verfahren war allerdings zu teuer, da hier jede Papierzelle einen Timer bekommen
oder in regelmäßigen Abständen über jede Zelle des gesamten Bildes gelaufen werden musste. Dies könnte mit einer geordneten Liste gelöst wer-
48
den, in der die Zellkoordinaten in Gruppen nach ihrer Trocknungszeit geordnet werden. Sobald die früheste Trocknungszeit erreicht wurde, würde
die dryInk()-Funktion aller Zellen in der Gruppe aufgerufen und damit die
Farbe in den entsprechenden Zellen trocknen. Es wäre auch schön, wenn
der Benutzer das Bild sofort trocknen könnte.
Dies sind Punkte, an denen in Zukunft gearbeitet werden kann, um die
Marker-Simulation zu verbessern.
Literatur
[Bax04]
B AXTER, William V.: Physically-based Modeling Techniques for Interactive Digital Painting. Chapel Hill, North Carolina, University of North Carolinal at Chapel Hill, Ph.D. Thesis, 2004
[BL04]
B AXTER, William V. ; L IN, Ming C.: A Versatile Interactive 3D Brush Model. http://gamma.cs.unc.edu/brush.
Version: 2004
[BLL04]
B AXTER, William V. ; L IU, Yuanxin ; L IN, Ming C.: A Viscous
Paint Model for Interactive Applications. http://gamma.cs.
unc.edu/viscous. Version: July 2004
[BSL01]
B AXTER, William V. ; S CHEIB, Vincent ; L IN, Ming C. ; F IUME,
Eugene (Hrsg.): dAb: Interactive Haptic Painting With 3D Virtual
Brushes. http://gamma.cs.unc.edu/dab. Version: 2001
[BWL04]
B AXTER, William V. ; W ENDT, Jeremy ; L IN, Ming C.: IMPaSTo: A Realistic Model for Paint. http://gamma.cs.unc.edu/
impasto. Version: June 2004
[CAS+ 97]
C URTIS, Cassidy J. ; A NDERSON, Sean E. ; S EIMS, Joshua E. ;
FL EISCHER, Kurt W. ; S ALESIN, David H.: Computer-Generated
Watercolor. 1997
[CBWG10] C HU, Nelson ; B AXTER, William ; W EI, Li-Yi ; G OVINDAR AJU , Naga:
Detail-Preserving Paint Modeling for 3D Brushes.
http://research.microsoft.com/apps/pubs/
default.aspx?id=121930. Version: 2010
[Coc91]
C OCKSHOTT, T.: Wet and Sticky: A novel model for computer based painting, University of Glasgow, Glasgow, Scotland, Ph.D.
Thesis, 1991
[CT02]
C HU, N. S. ; TAI, C. L.: An efficient brush model for physicallybased 3D painting. 2002
49
[CT04]
C HU, N. S. ; TAI, C. L.: Real-time painting with an expressive virtual chinese brush. 2004
[DRN03]
D. R UDOLF, D. M. ; N EUFELD, E.: Simulating wax crayons. 2003
[DRN04]
D. R UDOLF, D. M. ; N EUFELD, E.: A bidirectional deposition model
of wax crayons. 2004
[GK91]
G UO, Q. ; K UNII, T.: Diffuse paintings of sumie. 1991
[HM92]
H AASE, Chet S. ; M AYER, Gary W.: Modeling pigmented materials
for realistic image synthesis. 1992
[Jew84]
J EWIS, J. P.: Texture synthesis for digital painting. 1984
[JSYO02]
J.-S. Y EH, T.-Y L. ; O UHYOUNG, M.: On the effects of haptic display in brush and ink simulation for chinese painting and calligraphy. 2002
[KM31]
K UBELKA, P. ; M UNK, F.: The Kubelka-Munk Theory of Reflectance.
1931
[Kok07]
K OKHANOVSKY, A. A.: Physical interpretation and accuracy of the
Kubelka-Munk theory. 2007
[Kub48]
K UBELKA, P.: New Contributions to the Optics of Intensely LightScattering Materials. Part I. 1948
[Kub54]
K UBELKA, Paul: New Contributions to the Optics of Intensely
Light-Scattering Materials. Part II: Nonhomogeneous Layers. 1954
[Lee91]
L EE, J.: Simulating oriental black-ink painting. 1991
[Lee01]
L EE, J.: Diffusion rendering of black ink paintings using new paper
and ink models. 2001
[LN90]
L INDGREN, K. ; N ORDAHL, Mats G.: Cellular Automata. 1990
[Per85]
P ERLIN, Ken: An image synthesizer. July 1985
[Sch11]
S CHOLZ, Monique: Hoehle von Coliboaia (Rumaenien): Aelteste
Hoehlenmalereien Mitteleuropas entdeckt. http://www.h-age.
net. Version: 04. Januar 2011
[Sma91]
S MALL, D.: Simulating watercolor by modeling diffusion, pigment,
and paper fibers. 1991
[SN99]
S AITO, S. ; N AKAJIMA, M.: 3D physically based brush model for
painting. 1999
50
[SN00]
S AITO, S. ; N AKAJIMA, M.: Physically based 3D brush model for
interactive painting. 2000
[Str86]
S TRASSMANN, Steve: Hairy Brushes. 1986
[SXP03]
S. X U, F. T. F. Lau L. F. Lau ; PAN, Y.: Advanced design for a
realistic virtual brush. 2003
[TCE92]
T. C OCKSHOTT, J. P. ; E NGLAND, D.: Modelling the texture of
paint. 1992
[TKH95]
T. K UNII, G. N. ; H AYASHI, T.: A diffusion model for computer
animation of diffuse ink painting. 1995
[TWBM88] T. W. B LESER, J. L. S. ; M C G EE, J. P.: Charcoal sketching: returning
control to the artist. 1988
[WI00]
W ONG, H. ; I P, H.: Virtual brush: A model-based synthesis of chinese calligraphy. 2000
[Wor96]
W ORLEY, Steven P.: A cellular texturing basis function. 1996
[YJYC02]
Y. J. Y U, Y. B. L. D. H. Lee L. D. H. Lee ; C HO, H. G.: A model
based technique for realistic oriental painting. 2002
[YJYL03]
Y. J. Y U, H. G. C. Y. B. Lee L. Y. B. Lee ; L EE, D. H.: Interactive
rendering technique for realistic oriental painting. 2003
[Zim98]
Z IMMER, M. A.: Digital mark-making method. 1998
[ZST+ 99]
Z HANG, Q. ; S ATO, Y. ; TAKAHASHI, J. ; M URAOKA, K. ; C HIBA,
N.: Simple cellular automaton-based simulation of ink behaviour and
its application to suibokuga-like 3D rendering of trees. 1999
51

Documentos relacionados