Texturen – Inhalt Inhaltsverzeichnis 1. Einleitung ......................................................................... 2 1.1 Vorwort ........................................................................ 2 1.2 Was sind Texturen ......................................................... 2 2. Texturverarbeitung in der Hardware ................................ 3 2.1 Point Sampling .............................................................. 3 2.2 Bilineares Filtern ............................................................ 4 2.3 MIP-Mapping ................................................................. 4 2.4 Trilineares Filtern ........................................................... 4 2.5 Multi-Texturing .............................................................. 5 2.6 Texturkompression ........................................................ 6 3. Texturen in Java 3D ......................................................... 7 3.1 Einleitendes Beispiel....................................................... 7 3.2 Texturoptionen ............................................................. 10 3.3 Texturattribute ............................................................. 12 3.4 Automatsiche Texturkoordinatenberechnung .................... 14 3.5 MIP-Maps .................................................................... 16 4. Programmbeispiele ........................................................ 17 5. Literaturverzeichnis ....................................................... 19 1 Texturen – Einleitung 1. Einleitung 1.1 Vorwort Diese Ausarbeitung entstand im Rahmen der LVA Seminar Java 3D bei Herrn Prof. Dr. Heinzel an der FH Fulda im WS 2002/2003. Voraussetzung für das Verständnis ist grundlegende Kenntnisse in der Grafikprogrammierung und der objektorientierten Programmierung. Des weiteren empfehle ich die Dokumentation der Java 3D API als Referenz zum Querlesen, da es den Rahmen dieser Ausarbeitung sprengen würde, alle Details zu den vorgestellten Objekten, Methoden und Attributen mit aufzunehmen. Auch das Grundprinzip der Szenegraphen in Java 3D erleichtert das Verständnis dieser Ausarbeitung. 1.2 Was sind Texturen? Eine Textur ist eine zweidimensionale Grafik, die durch ein Bitmapformat oder durch eine Schraffur, ein Raster oder ein Muster definiert ist. Die Textur kann Oberflächenmerkmale verschiedenster Art eines Körpers spezifizieren, Materialeigenschaften. Diese vom bloßen Texturen Aussehen lassen sich bis auf hin zu definierte Flächen(z. B. Polygone) in einem zwei- oder dreidimensionalen Raum „legen“. Diesen Vorgang nennt man Textur-Mapping, wobei hier zwischen diversen, mehr oder weniger komplexen Mapping-Verfahren unterschieden wird. Der Zweck des „Texturing“ liegt in einer realistischen Darstellung von Objekten in zwei- oder dreidimensionalen Szenen, die dennoch relativ effizient von der Hardware verarbeitet werden können. 2 Texturen in der Hardware 2. Texturverarbeitung in der Hardware Da die Entwicklung bei 3D Grafikchips zügig voranschreitet und jeder Hersteller seine eigenen, zusätzlichen 3D-Funktionen in die Chips implementiert, werden im folgenden Abschnitt nur einige grundlegende Funktionen hinsichtlich Texturierung beschrieben. Des Weiteren wird auch nicht auf Spezialfunktionen von Grafikkarten für den High-EndBereich eingegangen. Auch lassen sich die meisten Funktionen in Software-Texturing-Verfahren verwirklichen. Der Anteil eines Grafikchips bei der Texturverarbeitung lässt sich zunächst einfach deuten: Er liest die Texturen aus dem Grafik-, Hauptoder Festplattenspeicher und legt sie auf die als Polygonnetz angelieferten Objekte. Dann folgt noch ein Tiefenvergleich bei mehreren sich überschneidenden Objekten, um nur die Pixel auf dem Bildschirm auszugeben, die tatsächlich sichtbar in der 3D-Welt erscheinen. Ganz so einfach funktioniert das jedoch nicht, wenn man bedenkt, dass sich ein 3D-Objekt vom Betrachter entfernen bzw. nähern oder drehen kann. 2.1 Point Sampling Das Point Sampling ist eine sehr einfache Methode der Texturierung. Hierbei wird ein Bezug zwischen der Textur und dem Polygon hergestellt. Der Farbwert des Texels (Textur-Element), dessen Position der des Pixels des Polygons am Nächsten liegt, wird verwendet. Ein Problem entsteht bei einer Differenz der Anzahl Texel und Pixel. Aus großer Nähe überdeckt ein Texel gleich mehrere Pixel, dies führt zu einer sehr groben Darstellung der Textur. Aus großer Distanz bleibt für ein Texel kein ganzes Pixel mehr übrig, man muss ein Texel auswählen. Dies führt unter Umständen zu einem Farbchaos, bei dem der Betrachter keine sinnvolle Oberflächendarstellung mehr deuten kann. 3 Texturen in der Hardware Pixel Texel mappin mappin g g Textur Polygon Textur Abb. 1 2.2 Bilineares Filtern Beim bilinearen Filtern oder auch bilinearen Textur-Mapping werden vier Texel interpoliert auf ein Pixel abgebildet. Dadurch verwischen sowohl grob dargestellte Texturen bei großer Nähe, als auch bunt flimmernde Texturen bei großer Distanz zu einem gewissen Grad. 2.3 MIP-Mapping Für MIP-Mapping stellt man jede Textur in verschiedenen Auflösungsstufen zur Verfügung. So kommt je nach Distanz zwischen Betrachter und Objekt eine höher oder niedriger aufgelöste Version der Textur zur Anwendung. 2.4 Trilineares Filtern Das trilineare Filtern von Texturen ist eine Erweiterung des MIPMapping, das eine qualitativ hochwertige Darstellung von Texturen ermöglicht. Falls sich ein Pixel zu nicht zu einer Auflösungsstufe zuordnen lässt, wird zwischen zwei MIP-Maps gemittelt. Dazu werden für ein Pixel die zwei MIP-Map-Werte durch bilineares Filtern ermittelt und zwischen den daraus resultierenden Farbwerten wird durch eine weitere Interpolation die Pixelfarbe bestimmt. 4 Texturen in der Hardware 2.5 Multi-Texturing Die Möglichkeit, auf ein Polygon mehr als eine Textur zu legen, nennt man Multi-Texturing. Eine Anwendung von Multi-Texturing ist zum Beispiel die ursprüngliche Simulation Textur, Hell/Dunkel-Muster beliebiger beispielsweise (Lighting-Map) Lichtverteilungen. eine gelegt. Mauer, Das Auf wird Ergebnis eine nun ein ist ein statischer Lichteffekt, der jedoch durch Variation der Lighting-Map dynamisch gestaltet werden kann. Abb. 2 Weitere Anwendungsgebiete von Multi-Texturing sind das Bump- Mapping (Simulation von Prägestrukturen) und das Enviroment-Mapping (Simulation von Reflexionen auf glatten und metallischen Oberflächen). Auch die Kombination beider Verfahren ist möglich. 5 Texturen in der Hardware 2.6 Texturkompression Um den Speicherplatz und die Datenbandbreite möglichst gering zu halten, sind in Texturkompression, den oder heutigen besser Grafikchips gesagt Verfahren zur Texturdekompression, implementiert. Dadurch können mehr oder höher aufgelöste Texturen verwendet werden. Die Texturen müssen allerdings der Software komprimiert beiliegen. Sie werden komprimiert in den Grafikspeicher transferiert und erst bei dem Zugriff ohne Geschwindigkeitsverlust dekomprimiert. 6 Texturen in Java 3D 3. Texturen in Java 3D Im folgenden Abschnitt möchte ich die Möglichkeiten der Verwendung von Texturen in Java 3D zeigen. Zu Beginn wird die Entwicklung eines einfachen Beispiels an Hand eines Rezeptes dargestellt, um die prinzipielle Vorgehensweise der Texturierung zu veranschaulichen. Im Anschluss daran gehe ich auf die Details der Java Texture API ein. 3.1 Einleitendes Beispiel Um eine Textur überhaupt in Java 3D verwenden zu können, muss sie in einem lesbaren Dateiformat und Auflösung vorliegen. Unterstützte Dateiformate sind zum Beispiel JPEG und GIF, weitere Formate sind der Sun-Website zu entnehmen. Die Auflösung in Pixel muss in der Breite sowie der Höhe einer Zweierpotenz entsprechen, also 2n x 2m Pixel. Dies liegt in dem binären Zahlenraum der Rechnersysteme begründet und ermöglicht effizientes Rendering. Ist die Textur in richtigem Format und richtiger Auflösung vorhanden, wird sie mittels TexturLoader aus der Datei geladen. Dazu wird zunächst ein TexturLoader-Objekt benötigt, dem bei der Instanzierung der Dateinamen der Textur und ein Observer-Objekt übergeben wird. TextureLoader loader = new TextureLoader(“brick.jpg”, this); ImageComponent2D image = loader.getImage(); Das Observer-Objekt überwacht den Ladevorgang der Grafik. Hierfür wird das Applet (this) verwendet, in dem das Objekt dargestellt wird. Ein ImageComponent2D-Objekt dient als Behälter für die Grafik. 7 Texturen in Java 3D Im nächsten Schritt übergibt man das ImageComponent2D-Objekt an ein Textur-Objekt. Bei der Instanzzierung des Texture2D-Objekts werden vier Parameter übergeben. Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA, image.getWidth(), image.getHeight()); Der erste Parameter gibt MIP-Map-Modus an. Es gibt 2 Konstanten, BASE_LEVEL für Standardtexturierung mit einer Textur in fixer Auflösung und MULTI_LEVEL_MIPMAP für die Verwendung von einer Textur in mehreren Auflösungen (siehe Abschnitt MIP-Mapping). Der zweite Parameter bestimmt die Genauigkeit des Farbwertes jedes Texels und wie das Pixel, das den Texelwert bekommt, dargestellt wird. Es werden sechs verschiedene Modi unterschieden (siehe TexturOptionen). Der dritte und vierte Parameter bestimmt Breite und Höhe der Textur. Appearance appear = new Appearance(); appear.setTexture(texture); Mit der Instanzzierung eines Appearance-Objekts und der Übergabe des Texture-Objekt an das Appearance-Objekt wird die Darstellung in der Szene möglich. Zum Schluss müssen die Texturkoordinaten gesetzt werden. Dazu muss man wissen, dass die logischen Texturkoordinaten die Höhe und Breite 1.0 besitzen. Diese werden den Vertex-Koordinaten des Polygons zugeordnet. Die folgende Abbildung verdeutlicht diese Zuordnung, das eigentliche Mapping. 8 Texturen in Java 3D tc(1.0, 0.0) tc(1.0, 1.0) tc(0.0, 0.0) tc(0.0, 1.0) Abb. 3 Das Code-Fragment für die Zuweisung der Koordinaten sieht folgendermaßen aus. /* Array für Geometriepunkte anlegen, um die Eckpunkte * des Rechtecks * festzulegen und Index der Eckpunkte erzeugen */ Point3f p = new Point3f(-1.0f, 1.0f, 0.0f); plane.setCoordinate(0, p); p.set(-1.0f, -1.0f, 0.0f); plane.setCoordinate(1, p); p.set(1.0f, -1.0f, 0.0f); plane.setCoordinate(2, p); p.set(1.0f, 1.0f, 0.0f); plane.setCoordinate(3, p); /* Mapping: Array für Texturkoordinaten anlegen und auf * Rechteck legen */ Point2f q = new Point2f( 0.0f, 1.0f); plane.setTextureCoordinate(0, q); q.set(0.0f, 0.0f); plane.setTextureCoordinate(1, q); q.set(1.0f, 0.0f); plane.setTextureCoordinate(2, q); 9 Texturen in Java 3D Der Szenengraph für dieses Beispiel würde folgendermaßen aussehen: BG Simple Universe S Appearance Texture Abb. 4 Nach diesem grundlegenden Beispiel sollen nun weitere Funktionen der Java Texture API erläutert werden. Der vollständige Quellcode dieses Beispiels „TexturTest“ liegt auf der beiliegenden CD vor. 3.2 Texturoptionen Die Option Boundary-Mode stellt eine sehr wichtige Funktion bei der Texturierung von großen, homogenen Flächen dar. Sie bestimmt, wie eine Textur auf ein Polygon gelegt wird, wenn die Textur nur eine kleinen Teil des Polygons abdeckt. Es gibt zwei Modi, die mit folgenden Konstanten initiiert werden: - WRAP -> Die Textur wird wie zum Beispiel Fliesen ohne Fugen aneinander gelegt, bis das Polygon vollständig bedeckt ist - CLAMP -> Das Polygon wird jenseits der Textur mit den Farben der Randpixel der Textur gefärbt 10 Texturen in Java 3D Die Konstanten müssen für x- und y-Richtung, bzw. z-Richtung gesetzt werden. Die geschieht mit den Methoden - void setBoundaryModeS (int boundaryModeS) - void setBoundaryModeT (int boundaryModeT) - void setBoundaryModeR (int boundaryModeR). Mit der Option Boundary-Color kann der Programmierer Einfluss die Farbe jenseits der Textur nehmen, wenn der Boundary-Mode auf CLAMP gesetzt ist und die Textur kleiner als das Polygon ausfällt. Die Methoden lauten: - void setBoundaryColor (Color4f boundaryColor) void setBoundaryColor (float r, float g, float b, float a) Die Filterung legt die Art und Weise fest, wie die Texel auf die Pixel des Polygons abgebildet werden. Da in den seltensten Fällen eine direkte Abbildung eines Texels auf ein Pixel möglich ist (siehe Abb. 1), kann der Programmierer zwischen verschiedenen Abbildungsverfahren wählen. Java 3D unterscheidet zum einen den Fall, dass das abzubildende Texel größer als das Pixel ist (Magnification Filter) und zum anderen, dass das abzubildende Texel kleiner als das Pixel ist (Mignification Filter). Die Filter werden mit den Methoden - void setMagFilter (int magFilter) void setMinFilter (int minFilter) gesetzt. 11 Texturen in Java 3D Die Konstanten lauten - BASE_LEVEL_POINT -> Die Farbe des nächstliegenden Texels wird verwendet (vgl. Kapitel 2.1 Point Sampling) - BASE_LEVEL_LINEAR -> Der Farbwert der vier nächstliegenden Texel wird interpoliert und als Pixelfarbe gesetzt (vgl. Kapitel 2.2 Bilienar Filtern) - MULTI_LEVEL_POINT -> Der Farbwert des nächstliegenden Texels in der nächstliegenden MIP-Map wird verwendet. - MULTI_LEVEL_LINEAR -> Nur bei MIP-Mapping; der Farbwert der vier nächstliegenden Texel wird von den zwei nächstgelegenen MIP-Maps ermittelt. Anschließend erhält der Pixelwert den zwischen den MIP-MapTexeln interpolierten Wert (vgl. Kapitel 2.4 Trilineares Filtern) Das Format bestimmt die Genauigkeit des Farbwertes jedes Texels. Eine Aufstellung der Konstanten, die bei der Instanzzierung des TexturObjekts angegeben werden, zeigt die folgende Tabelle: 3.3 Texturattribute Texturattribute haben den Vorteil, dass sie Änderungen an der Optik von Texturen durchführen, diese Attribute jedoch in einem separaten Objekt (TextureAttribute) definiert werden. Der Programmierer kann somit eine Textur laden, aber unterschiedlich Darstellen durch verändern der TextureAttributes. 12 Texturen in Java 3D Abb. 5 Der Konstruktor, um alle Attribute eines TexturAttribute-Objekts zu setzen benötigt vier Parameter. - TextureAttributes (int textureMode, Transform3D transform, Color4f textureBlendColor, int perspCorrectionMode) Mit dem Attribut textureMode beeinflusst der Programmierer die Farbdarstellung des texturierten Objekts. Die Standardeinstellung ist REPLACE, d. h. die Pixelfarbe = Texelfarbe. Die Tabelle zeigt alle möglichen Modi: Die Methode void setTextureMode (int textureMode) ändert die Konstante textureMode. Das Attribut textureBlendColor wirkt sich nur dann auf die Darstellung aus, wenn der Texture-Mode setTextureBlendColor (Color4f BLEND gesetzt textureBlendColor) ist. Mit manipuliert void der Anwender die Texturdarstellung. 13 Texturen in Java 3D Wenn eine Textur auf ein Polygon gemappt wird, das schräg zum Betrachter erscheint, führt Java 3D eine Korrektur der Perspektive vor. Dies wird standardmäßig aufwendig, aber mit guter Qualität durchgeführt (Konstante NICEST). Wünscht man schnelleres Rendering zu lasten der Qualität, setzt man das Attribut mit der Methode void setPerspectiveCorrectionMode (int mode) auf FASTEST. Das letzte Attribut beeinflusst die Textur an sich. Mit der Methode void setTextureTransform (Transform3D transform) kann der Programmierer zur Laufzeit die Textur verschieben, rotieren und skalieren, in dem er ein Transform3D-Objekt mit den gewünschten Transformationen an das TextureAttribute übergibt. 3.4 Automatische Texturkoordinatenberechnung Gerade bei sehr komplexen Szenen mit mehreren Polygonen muss der Programmierer viel Aufwand betreiben, um die Texturkoordinaten auf die Polygonkoordinaten zu transferieren (vlg. 3.1 Einleitendes Beispiel). Um diese „Schreibarbeit“ zu verringern, wurde die Klasse TexCoordGeneration in der Java 3D API implementiert. Die Instanzzierung der TexCoordGeneration Klasse kann parameterlos (Standardwerte werden verwendet) oder mit Angabe von Generierungsformat und Texturformat erfolgen. - TexCoordGeneration () - TexCoordGeneration (int genMode, int format) 14 Texturen in Java 3D Die Anbindung an den Szenengraph wird in Abbildung 6 dargestellt. Abb. 6 Der Parameter format bestimmt, ob die Textur eine 2D- oder 3D-Textur ist (Standardwert ist 2D-Textur). Interessanter ist der Parameter genMode, der die folgenden drei Variationen kennt: - OBJECT_LINEAR -> Die Textur, die auf das Polygon gelegt wird, bewegt sich mit dem Objekt (statische Texturkoordinaten) - EYE_LINEAR -> Das Objekt, auf dem die Textur liegt, wird unter der Textur gedreht (variable Texturkoordinaten) - SPHERE_MAP -> Die Texturkoordinaten werden dynamisch aus der Oberflächennormalen und der Betrachtungsrichtung berechnet (dynamische Texturkoordinaten) Für eine ausführliche Beschreibung der Methoden und Attribute verweise ich auf das Sun Programmierreferenz zur Java 3D API. 15 Texturen in Java 3D 3.5 MIP-Maps Java 3D unterstützt das bereits in Kapitel 2.3 erwähnte Multiple-LevelTexturing (MIP-Mapping). Dahinter steckt ein Verfahren, das eine Textur von beispielsweise 128 x 128 Pixel Auflösung in der Größe so lange geviertelt wird (Länge und Breite werden halbiert), bis die Textur in der Auflösung 1 x 1 Pixel vorliegt. Alle zwischendurch erzeugten Texturen werden gespeichert, so dass Texturen in den Größen 128 x 128, 64 x 64, ..., 1 x 1 vorliegen. Je nach der Distanz des Betrachters zum texturierten Objekt in der Szene wird ein höher oder niedriger aufgelöste Textur verwendet. Die unterschiedlichen Auflösungsstufen der Textur können in einer kleinen Schleife erstellt werden. while (imageWidth > 1 || imageHeight > 1){ imageLevel++; if (imageWidth > 1) imageWidth /= 2; if (imageHeight > 1) imageHeight /= 2; image = loader.getScaledImage(imageWidth, imageHeight); texture.setImage(imageLevel, image); } Zu beachten ist hierbei, dass bei der Instanzzierung des TextureObjekts der erste Parameter den MIP-Map-Modus initialisiert. Texture2D texture = new Texture2D(Texture.MULTI_LEVEL_MIPMAP, Texture.RGB, imageWidth, imageHeight); Weiterhin sind die Texturoptionen (vgl. Kapitel 3.2) hinsichtlich Filtereinstellungen für den Minification-Filter auf MULTI_LEVEL_POINT oder MULTI_LEVEL_LINEAR anzupassen. 16 Beispiele 4. Beispiele Ein gutes Beispiel für die Wirkung der verschiedenen Optionen und Attribute auf eine Textur ist eine Art Tutorial von Henry A. Sowizral und David R. Nadeau. In dieser Sammlung von Klassen befindet sich die Datei ExTexture.java, die einen 3D-Würfel in einer Szene darstellt. Über diverse Menüpunkte lassen sich Attribute und Optionen interaktiv verändern. Mit der Maus kann der Benutzer den Würfel in der Szene drehen, zoomen, usw.. Diese Sammlung von Klassen befindet sich unter der Internetadresse http://www.sdsc.edu/~nadeau/Courve/Siggraph99 Aufmerksam wurde ich auf dieses Beispiel durch meinen Mitstudent Stefan Dubois. 17 Beispiele Jicasso – Visuelle Java 3D Programmierung Das Tool Jicasso von Colin Mummery ermöglicht die visuelle Erstellung von 3D Objekten in einer Szene. Der Benutzer kann diverse graphische Primitive einer Szene hinzufügen und anschließen Licht, Textur, Hintergrund usw. modifizieren. Einschränkungen macht das Tool bezüglich des generierten Quelltextes. Die (hier getestete) Shareware-Variante erzeugt lediglich BinärcodeDateien, so dass ich über die Qualität des erzeugten Quellcodes keine Aussage machen kann. Das Tool liegt in einer Betaversion der CD bei, im Internet findet man es unter der Adresse http://www.cellspark.com/jicasso.html 18 Literarturverzeichnis 5. Literaturverzeichnis: - M. Bertuch – Polygonfabriken – Artikel aus C’T 8/2000, S.202f, Heise-Verlag - F. Angulanza, M. Mayr, C. Osterrieder – Texturen in Java 3D – Vortrag vom 02.07.2002, Quelle: http://www.cosy.sbg.ac.at/graphics_I/ps_pdf_ppt/angulanza_e t_al.pdf - S. P. Häuser – Definition und Darstellung von Texturen – Studienarbeit vom 23.07.1997, Quelle: http://www.ncstrl.informatik.uni-stuttgart.de/Dienst/UI/2.0/De scribe/medoc.ustuttgart_fi/STUD-1628 - Java 3D Tutorial v 1.5 von SUN, Quelle: http://developer.java.sun.com/developer/onlinetraining 19