Ich bin gerade dabei, ein bisschen mit 2D-OpenGL zu experimentieren (also mit glOrtho) und habe dabei einige Fragen zu Texturen. Als Texturenloader benutze ich die Textures.pas und die Texturen sind als Targas gespeichert.
1) Ich würde gerne im Stil eines Bildbetrachters meine Bilder laden und danach wieder abspeichern können. Dabei ergibt sich aber das Problem, dass ich noch keine Möglichkeit gefunden habe, die Texturen in ein array of byte oder irgendeine Form von Stream zu überführen. Jetzt hatte ich mir schon überlegt, eventuell als Notlösung ein array of array of byte zu benutzen, um die Dateien zu speichern, und dann beim Laden jeweils kurzzeitig eine temporäre Datei zu erzeugen, die ich dann auslesen kann. Leider sind die Dateien seit dem Laden aber schreibgeschützt (Werden die nicht in den Speicher geladen?). Kann man vielleicht auf eine andere Weise (möglichst ohne temporäre Datei ) Texturen in Streams überführen, bzw. aus einer Variablen laden?
2) Eine Frage, die auf das Nicht-Vorhanden-Sein von Texturen anspielt: Kann ich eigentlich auch einfarbige Objekte erzeugen, die lediglich eine einfarbige (aber durchaus definierte) Füllung besitzen? Das würde sich besonders bei Linien anbieten...
3) Ein sehr merkwürdiger Fehler bereitet mir Kopfzerbrechen: Ich will 50x50 Pixel (entspricht Ausgabegröße) große Quads zeichnen und weise ihnen als Textur ein 50x50 Pixel großes Targa zu. Das Ergebnis ist sehr verpixelt und besteht aus ca. 5x5 Pixel großen Klötzchen verschiedenster Farben. Weise ich meinen Quads hingegen eine 1000x1000 Pixel Textur zu, ist alles bestens. Ins besondere, da die Texturen (zu Testzwecken) einfarbig sind, kann ich das irgendwie nicht verstehen. - Und auf Dauer würde ich eigentlich doch lieber die kleinen Texturen verwenden .
Vielen Dank schonmal für alle Antworten und bis bald,
Ogridi
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Irgendwie schreit das Thema gerade zu nach mir.
Ich räume mal das Feld von hinten hin auf.
3. Das sind in der Regel keine gültigen Texturen und, dass du da überhaupt Texturen siehst darüber solltest du dich freuen. Normal muss die Höhe und Breite einer Textur eine Potenz von 2 sein. Also 1, 2, 4, 8, 16, 32, 64, 128 usw. Nach Möglichkeit solltest du dich auch an diese Größen halten. Dann empfielt es sich auch nicht zu kleine Texturen zu benutzen. Das Texturen wechseln verbraucht Zeit und wenn du die Möglichkeit hast in eine 512x52 große Textur viele deiner kleinen Textuern zu packen, dann solltest du das tun. Aber je nachdem was du vor hast ist das kein ausschlaggebender Punkt.
2. Ja. Mit glColor kannst du die Farbe deiner Primitive (Punkt, Linie, Dreieck, Viereck) beeinflussen. Ob darauf eine Textur dargestellt wird oder nicht ist nebensächlich. Sollte eine Textur dargestellt werden wird dessen Farbe mit der gesetzten Farbe multipliziert. Dabei werden aber die Farbwerte auf einen Bereich von 0 bis 1 normalisiert. Also 255 entspricht dann 1 und 255 * 255 wäre 1*1 und das wäre 1. Nur um der verwirrung etwas vorweg zu nehmen.
1. Als erstes tu mir, dir und uns allen einen gefallen und lege niemals Texturdaten in einem Array of array of Byte ab. Danke. Die Zugriffe auf einzelne Pixel mögen sicht zwar so recht einfach gestalten aber im Nachhinein wirst du mit einer unsäglichen Geschwindigkeit bestraft werden. Wenn dann nimm dir einen Speicherblock Höhe*Breite*Farbtiefe und lege dort deine Daten ab. Wenn du magst kannst du dir Pointer auf den Anfang einer Zeile berechnen und diese in einem array ablegen. Damit hast du alle Möglichkeiten die man benötigt und ein wenig kompfortabel ist es auch noch. Geschwindigkeitstechnisch ist das kaum zu überbieten.
Zum Textenloader: Die Texture.pas ist leider nur eine ziemlich beschränkter OneWay loader ohne Einfluss auf das was passiert. Soll bedeiten. Du hast eine Methode LoadTexture und bekommst einen Cardinal zurück. Das wars. Das ist für deinen Fall natürlich nicht wirklich brauchbar. Als Alternative kann ich dir meinen Loader anbieten. Der ist in der Lage aus Streams zu lesen und hält die Texturdaten so lange sie benötigt werden oder du sie haben möchtest. In der Wiki Dokumentation findest du auch reichlich Beispiele. Aber bitte nutz nur die Object orientierten. Mit den anderen bist du genau da wo du mir der Textures auch wärst. Abspeicher kannst du die Texturen leider noch nicht aber in der nächsten Version ist das definitiv schon drin. Momentan bleibt dir leider nur der Weg die Textur als ein Bitmap zurückgeben zu lassen und dieses dann abzuspeichern. In der nächsten Version hast du dann auch die Möglichkeit besser auf die Daten eines Bildes zuzugreifen. Denke mal, dass ich im Laufe der nächsten Woche(n) die neue Version freigeben kann. Will aber nichts versprechen. Zeit ist ein bisschen arg knapp.
Danke erstmal für die ausführliche (und ebenso schnelle) Antwort. Ich bin schon die ganze Zeit dabei, die Tipps einigermaßen umzusetzen .
Was ich jedoch noch nicht so ganz verstehen kann, ist, dass ich mit glColor3f nur dann ein vernünftiges Ergebnis bekomme, wenn ich vorher als Textur '0' einbinde (glBindTexture(GL_TEXTURE_2D, 0)). Ansonsten zeigt er (1, 1, 1) als komisches Gelb an und so ähnlich. Außerdem dachte ich, dass man mit glClear(GL_COLOR_BUFFER_BIT) die aktuelle Farbe zurücksetzen kann, was aber auch nicht funktioniert. (-> Alle danach gezeichneten Quads werden - wie du gesagt hast - mit der zunächst angegebenen Farbe überzeichnet.)
Und bei der Gelegenheit: Wie bekomme ich eigentlich aus der Farbe meiner Form (clBtnFace) die RGB-Anteile? Das konnte ich bislang auch noch nicht lösen...
Ansonsten auch thx für die Bemühungen mit deinem Loader. Es ist irgendwie schon toll, dass du eine Speicherfunktion genau dann implementieren willst, wenn ich sie brauche .
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ogridi hat geschrieben:
Ansonsten auch thx für die Bemühungen mit deinem Loader. Es ist irgendwie schon toll, dass du eine Speicherfunktion genau dann implementieren willst, wenn ich sie brauche .
Das täuscht. Du brauchst sie erst dann wenn ich sie implementiert habe.
Jetzt kommt wieder der Hinweis mit der StateMashine. OpenGL speichert die Einstellungen so lange bist du ihm etwas anderes sagt. Darunter zählt Farbe, Texture, Normalen, etc. Einfach alles.
Sobald du eine Textur aktiviert (glEnable(Target) und glBindTexture ) hast wird diese so lange benutzt wie sie aktiv ist. Wenn du keine Texturkoordinaten angegeben hast wird entweder 0, 0 oder die letzte gültige benutzt. Bin mir da gerade nicht so sicher. Um deine Textur nicht mehr zu benutzen solltest du glDisable(GL_TEXTURE_2D) aufrufen. Damit teilst du opengl mit, dass du diese Textur nicht mehr benutzen willst. Dann wird die zu letzt gesetzte Farbe benutzt. Und wenn du irgendwann etwas gelb haben willst und dann wieder etwas weiß oder texturiert dann musst du wieder glColor mit den entsprechenden Parametern aufrufen.
glClear(GL_COLOR_BUFFER_BIT) löscht nur den Speicherbereich in dem OpenGL die Farbinformationen ablegt. Framebuffer genannt. Der wird genutzt um deinen Bildschirminhalt darzustellen.
clBtnFace: Mit der Methode ColorToRGB kannst du einen wert wie clBtnFace in einen RGB Wert umwandeln. Um diesen dann zu zerlegen kannst du die Methoden GetRValue, GetBValue, GetGValue aufrufen die liefern dir den entsprechenden RGB Werte zurück. Diese kannst du dann mit glColor3ub setzen oder mit / 255 in einen Fließkommawert umrechnen.
Ich hab jetzt mal angefangen, deinen Loader zu implementieren. Als Test-Targas hab ich a) meine alten Photo-Paint (die mit dem alten Loader einwandfrei liefen) und b) neue, mit Gimp erstellte Bilder genommen (64x64 Pixel).
Code:
for x :=0to MapMeta.XLength-1do
for y :=0to MapMeta.YLength-1do
Tex[x][y]:=(x + y)mod4;
SetLength(TexData,4);
TexData[0]:= TglBitmap2D.Create('tex\4.tga');
TexData[1]:= TglBitmap2D.Create('tex\4.tga');
TexData[2]:= TglBitmap2D.Create('tex\4.tga');
TexData[3]:= TglBitmap2D.Create('tex\4.tga');
TexData[0].GenTexture();
TexData[1].GenTexture();
TexData[2].GenTexture();
TexData[3].GenTexture();
TexData ist eine Auflistung von Texturen, Tex ein Array, dem die Indices von TexData (und somit die Texturen) zugewiesen werden. Nach dieser Anweisungsgruppe erzeugt OpenGL bereits einen 'invalid operation'-Fehler. Ab dann läuft aber wieder alles einwandfrei. Er zeigt die Texturen super an usw. Was mache ich falsch?
Danach zeichne ich ein Quad und es ist strahlend weiß (im Gegensatz zur Form). Dieses Problem hatte ich schon vorher mit GetRValue & Co. Haste dazu vielleicht auch noch ne Idee?
So. Heute hatte ich immerhin noch mal Gelegenheit, mir das ganze in Ruhe anzusehen. Den Fehler mit der Farbe hab ich gefunden (durch 256 teilen), aber weshalb dieser 'invalid operation' Fehler ausgelöst wird, ist mir schleierhaft.
Wie gesagt: Die Texturen und der übrige Code sind die gleichen wie vorher, der Fehler wird in den Zeilen 10-13 jeweils einmal ausgelöst und das Endbild ist hervorragend.
Ich habe auch noch mal in dem Wiki nachgeschaut. Da steht immerhin, dass der Fehler keine Auswirkungen haben sollte (was ja auch zutrifft). Außerdem könnte es an einer alten OpenGL-Version liegen. Ich benutze aber schon den 2.0-Header.
Den Fehler einfach einmal auszulesen und so praktisch zu anullieren widerstrebt mir aber irgendwie. Lässt sich das nicht doch noch irgendwie beheben?
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Genau entweder du macht / 256 oder machst glColor3ub. Dann kannst du es direkt übergeben.
Zu der Invalid Operation. Das ist eine sehr gute Frage. Gehe mal bitte dorthin und zieh dir das Toll und erstelle damit mal einen bericht den du mir zukommen lässt. Also mal hier anhängen oder so. Dann schaue ich mal. Kann sein, dass ich eine extension vorraussetze die aber bei dir nicht existiert.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Okay. Danke für den Bericht und entschuldige, dass es ein bisschen gedauert hat. Ich hatte am Wochenende leider nicht sinnvoll Zeit.
So spontan kann ich nicht erkennen, dass da irgendetwas schief liegt. Teste mal bitte vor dem Erstellen der Texturen ob es einen Fehler gab und nachdem du eine erstellt hast. Ich möchte mal bitte den Fehler genau eingrenzen können. Habe nämlich momentan keine Ahnung wo es sein könnte. Nur bei einer "Invalid Operation" hat er irgendeine Einstellung nicht genommen. Welche auch immer.
Evtl hilft es ja auch, wenn du deinen Treiber mal updatest. Wenn ich das richtig gesehen haben benutzt einen 71.24. Wenn sich die Buildnummer als Treibernummer umsetzen lässt. Aber OpenGL 1.5 müsste da hinkommen. Wobei deine Karte eigentlich auch Problemlos 2.0 machen müsste.
Und da noch ne kleine Anmerkung. es ist egal ob du den OpenGL 2.0 Header benutzt. Es kann auch sein, dass die darunter liegende Karte nur OpenGL 1.1 kann. Nur in dem 2.0er header sollten die Konstanten alles halbwegs stimmen.
Ich hab hier noch mal eine sehr stark zusammengeschrumpfte Version von dem Projekt angehängt. Der Fehler tritt hier noch auf und zwar genau in der Zeile GenTexture(). Ich habe das Projekt jetzt auch schon an drei verschiedenen Rechnern ausprobiert und mit Texturen von drei verschiedenen Programmen; das Ergebnis ist leider immer das gleiche .
Naja, vielleicht ist es ja doch ein ganz einfacher Fehler im Ansatz und du kannst ihn mir in fünf Minuten eröffnen . Auf alle Fälle nochmal vielen Dank für deine Hilfe.
Ogridi
PS: Welche Funktion hat jetzt eigentlich die Header-Datei, bzw. das SDK?
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2068
Programmiersprache: C++
Erste Messagebox: "No Error"
Zweite Messagebox: "No Error"
Könnte es sein, dass die PCs alle Grafikkarten vom selben Hersteller haben?
Sowas vermute ich da spontan.
Der Header stellt dir die entsprechenden Funktionen bereit.
Diese befinden sich in der opengl.dll bzw. der dll auf die der Treiber umleitet.
Ansonsten müsstest du diese immer selber angeben und mit ?external? auf die DLL verweisen.
So einfach ist es in der Praxis leider nicht, da die DLL nicht alle Funktionen aufweisen muss.
Daher sind es im Header Pointer auf die entsprechenden Funktionen, die nach einem Aufruf von InitOpenGL auf die entsprechende Bereiche in der DLL gesetzt werden (falls vorhanden).
Das SDK ist eine Headersammlung und enthält noch Beispiele und Tutorials.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ja das ist ein bisschen Problematisch. Ich bekomme auch keinen Fehler. Denke i0n0s hat wie ich auch eine ATI Karte. Leider habe ich nirgendswo eine NVidia Karte um das mal ausprobieren zu können. Du würdest mir einen riesen gefallen tun, wenn du dich mal durch die glBitmap wühlen würdest und versuchst heraus zu finden wo der Fehler tatsächlich auftritt. Ich helfe dir auch beim Zurrecht finden. Versprochen.
Ändere mal die glBitmap bitt wie folgt ab. Beginnend ab Zeile 2236.
Zwei von den Test-PCs benutzen übrigens NVidia-Grafikkarten, der dritte hat wohl einen Intel-Grafikchip auf der Platine. Hab aber mittlerweile auch jemanden gefunden, bei dem der Fehler nicht auftritt ^^ .
Ich hoffe mal, das hilft dir weiter.
@i0n0s: Danke erstmal. Das heißt dann also, dass diese ganze riesen Header-Datei mit ihren 27k Zeilen praktisch nur zum Weiterleiten der Anweisungen gedacht ist? Wie groß ist denn dann erst die richtige OpenGL.dll?
Ansich sollte der Befehl den belegten Speicher durch die erzeugte Textur zurückgeben. Weshalb er hier nen Fehler ausgibt verstehe ich nicht. Aber sollte nicht kritisch sein.
Ogridi hat geschrieben:
@i0n0s: Danke erstmal. Das heißt dann also, dass diese ganze riesen Header-Datei mit ihren 27k Zeilen praktisch nur zum Weiterleiten der Anweisungen gedacht ist? Wie groß ist denn dann erst die richtige OpenGL.dll?
Die OpenGL32.dll ist 800 KB "gross", aber die kann auch nur OpenGL 1.4.
Die OpenGL.dll von meinem Treiber ist 6 oder 5 MB (je nachdem welche es ist ) gross.
Aber du hast recht, die Weiterleitung ist die Aufgabe des Headers.
Aber der Grund für die Grosse (und für den Respekt vor der Unit) ist, dass sie mit jeder OpenGL-DLL funktioniert, egal was für Funktionen enthalten sind bzw. fehlen.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Japp. Genau das macht der Fehler. Allerdings ermittelt er nur die Größe des ersten Levels. Also die MipMaping Ebenen hängen da nicht mit drinne. Ich finde das aber doof, dass die das nicht könne. Ich denke mal, dann kommt da auch keine sinnvolle Größe zurück, oder? Also Size dürfte leer sein. Hmmm. Muss ich mal schauen eigentlich kann man das auch weglassen.
Mitglieder in diesem Forum: 0 Mitglieder und 8 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.