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