Fehler beim Darstellen einer Textur

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Fehler beim Darstellen einer Textur

    Hallo liebe Leute

    Ich habe ein kleines Problem und komme nicht dahinter, woran das liegen könnte.
    Ich wollte gerne in OpenGL ein NSString als Texture darstellen. Dieser wird mit

    Quellcode

    1. [NSString drawAtPoint: withAttributes:]

    in ein NSImage gezeichnet, welches ich später in eine Texture reinpacke.

    Hier ist mein Codebeispiel (vereinfacht):

    Quellcode

    1. NSMutableDictionary *attribs = [[NSMutableDictionary alloc] init];
    2. [attribs setObject:[NSFont fontWithName:@"Helvetica" size:16.0] forKey:NSFontAttributeName];
    3. NSSize textSize = [m_Title sizeWithAttributes:attribs];
    4. NSImage *image = [[NSImage alloc] initWithSize:textSize];
    5. [image lockFocus];
    6. [m_Title drawAtPoint:NSZeroPoint withAttributes:attribs]; //hier ist der NSString zum darstellen
    7. [image unlockFocus];
    8. glGenTextures(1, &m_TitleTexture);
    9. NSData *imageData = [image TIFFRepresentation];
    10. glBindTexture(GL_TEXTURE_2D, m_TitleTexture);
    11. glTexImage2D(GL_TEXTURE_2D, 0, 4, [image size].width, [image size].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, [imageData bytes]);
    12. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    13. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    14. [image release];
    15. [attribs release];
    Alles anzeigen


    Später wird das alles in einer anderen Methode gezeichnet und funktioniert soweit gut (siehe Screenshot 1).
    Nun wenn ich jetzt aber beim Font die Größe von 16 auf 17 ändere, dann wird der Text in der Texture verzerrt dargestellt (siehe Screenshot 2).

    Beim Zeichnen der Texturen wird nichts geändert. Habe auch die das NSImage als Datei auf platte gepackt, und dort sieht der Text korrekt aus.

    Weiß jemand von euch, was hier schief läuft? Hatte jemand schon mal ähnliche Probleme damit?
    Mir fällt hier aber noch auf, dass in den Screenshots die letzten Buchstaben links in der Texture gezeichnet werden. Könnte es vielleicht ein Hinweis darauf sein?

    Vielen Dank im Vorraus.
  • zerm schrieb:

    Das sieht aus, als würde die Zeilenlänge nicht passen. Die Bildbreite muss ein vielfaches von 4 sein, oder GL_UNPACK_ALIGNMENT muss auf 1 gestellt werden.
    Wie bzw. wo muss ich den diesen Parameter setzen. Bin (wie meisten so) ziemlich neu in OpenGL und muss noch all diese Zusatzdinger kennen lernen...

    wolf_10de schrieb:

    Ah ok, wie groß ist denn die Textur ??

    Ist das die Texture2D von Apple ?
    Die Textur-Größe wird immer angepasst, abhängig vom ViewPort, da das Fenster "resizable" ist (App ist nicht fürs iOS). Spielt hier die Größe der Textur eigentlich eine Rolle? Wird das nicht anschließend einfach skaliert? Oder verstehe ich deine Frage nicht richtig...
    Nein, es ist nicht die Apple-Klasse. Habe da was eigenes erstellt.
  • glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

    Genauer: Die Anzahl an Bytes, die Du auf die Graphikkarte lädts (bzw. erstmal auf den OpenGL Server) muss durch 4 teilbar sein.
    Üblicherweise arbeiten wir auf 32-Bit Worten (oder 64/128), was in der Regel der kleinsten Einheit entspricht, die wir direkt in den Speicher schreiben oder daraus lesen können. Auf vielen Architekturen ist das auch die einzig effiziente Möglichkeit, Daten zu adressieren. Den x86 Prozessoren ist das zwar inzwischen oft egal, aber auf dem PPC war beispielsweise sehr ineffizient, davon abzuweichen. Es hat aber auch rechentechnische Vorteile.

    Nehmen wir an, Du hast eine RGB Textur, mit ein Byte pro Kanal. Dann sieht ein 3 Pixel breites Bild so aus:
    R G B R | G B R G | B <- erste Zeile zuende
    Das heisst, die zweite Zeile fängt jedesmal an einer ungraden Stelle in einem Datenwort an. Das macht man üblicherweise so nicht, darum geht OpenGL standardmässig davon aus, dass man die Zeilen soweit mit Nullen aufgefüllt hat, dass die nächste Zeile wieder auf einem vielfachen von 4 anfängt.
    Wenn man GL_UNPACK_ALIGNMENT, wie oben beschrieben, auf 1 setzt, kümmert sich OpenGL explizit darum, was bei vielen (und grossen) Texturen aber mit Geschwindigkeitseinbussen verbunden sein kann.
    C++

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von zerm ()

  • zerm schrieb:

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    So meinte ich das jetzt nicht :D
    Muss ich den Parameter beim Befüllen der Texture mit den Bilddaten (vor dem "glTexImage2D()") oder beim Zeichnen (vor dem "glDrawArrays()") setzen. Oder evtl. auch wo anders, weil beide Varianten bis jetzt kein Erfolg gebracht haben.
  • Nobik schrieb:

    zerm schrieb:

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    So meinte ich das jetzt nicht :D
    Muss ich den Parameter beim Befüllen der Texture mit den Bilddaten (vor dem "glTexImage2D()") oder beim Zeichnen (vor dem "glDrawArrays()") setzen. Oder evtl. auch wo anders, weil beide Varianten bis jetzt kein Erfolg gebracht haben.

    Einmal setzen vor dem entsprechendem Pixel-Transfer, also in Deinem Fall glTexImage2D. Gilt dann für alle UNPACK Operationen (also etwa auch glSubTexImage*, glDrawPixels, ...)
    C++
  • Was zu lustigen und unvorhersehbaren Ergebnissen führen kann: die Größe des Images entspricht nicht den gültigen Texture-Formaten.

    Laut Spezifikation müssen Texturen quadratisch sein mit einer Seitenlänge in Pixeln, die auf Potenzen von 2 beschränkt sind. Also 16x16, 64x64 oder 256x256 etc. Die größtmögliche Textur hängt von der Implementierung ab. Bei krummen Größen wird OpenGL vermutlich das Pixel-Bitmap falsch interpretieren, also nicht korrekt in Zeilen und Spalten zerlegen, was dann zu den Verzerrungen führt. Wundere dich also eher darüber, dass es mit 16 Punkt geklappt hat, das dürfte eher Zufall sein.

    "Next we need to resize the image so that the image dimensions are a power of 2. Remember that in order to use an image as a texture the image needs to be 128x128, 256x256, etc. "
    Gute Quelle zum Nachschlagen: nehe.gamedev.net/data/lessons/lesson.asp?lesson=23

    Das sind zugegebenermassen Einschränkungen, die oft sinnlos RAM verschwenden. In einem QpenGL Tutorial Buch von Addison-Wesley habe ich auch den Hinweis gefunden, dass ein Vielfaches von 2 ausreicht anstelle der 2er Potenz und dass die Texture nicht quadratisch sein muss. Ein paar Seiten widerspricht sich das Buch da aber wieder. Dafür weist es auf gluScaleImage() hin, damit man die Texture entsprechend skalieren kann.
  • ssb schrieb:

    Was zu lustigen und unvorhersehbaren Ergebnissen führen kann: die Größe des Images entspricht nicht den gültigen Texture-Formaten.

    Laut Spezifikation müssen Texturen quadratisch sein mit einer Seitenlänge in Pixeln, die auf Potenzen von 2 beschränkt sind. Also 16x16, 64x64 oder 256x256 etc. Die größtmögliche Textur hängt von der Implementierung ab. Bei krummen Größen wird OpenGL vermutlich das Pixel-Bitmap falsch interpretieren, also nicht korrekt in Zeilen und Spalten zerlegen, was dann zu den Verzerrungen führt. Wundere dich also eher darüber, dass es mit 16 Punkt geklappt hat, das dürfte eher Zufall sein.

    "Next we need to resize the image so that the image dimensions are a power of 2. Remember that in order to use an image as a texture the image needs to be 128x128, 256x256, etc. "
    Gute Quelle zum Nachschlagen: nehe.gamedev.net/data/lessons/lesson.asp?lesson=23

    Das sind zugegebenermassen Einschränkungen, die oft sinnlos RAM verschwenden. In einem QpenGL Tutorial Buch von Addison-Wesley habe ich auch den Hinweis gefunden, dass ein Vielfaches von 2 ausreicht anstelle der 2er Potenz und dass die Texture nicht quadratisch sein muss. Ein paar Seiten widerspricht sich das Buch da aber wieder. Dafür weist es auf gluScaleImage() hin, damit man die Texture entsprechend skalieren kann.

    Deshalb meine Frage wie groß die texture ist. Sie muss Power of 2 sein, nicht unbedingt quadratisch
    also 512x32 oder 16x256, usw...
  • ssb schrieb:

    Laut Spezifikation müssen Texturen quadratisch sein mit einer Seitenlänge in Pixeln, die auf Potenzen von 2 beschränkt sind.

    Wir haben seit gefühlten zehn Jahren GL_ARB_texture_non_power_of_two, also keine Beschränkung auf Power-of-two Texturen. Eventuell aber nicht auf ES 1.0 (iPhone ältere Generation), bin ich mir aber nicht sicher.

    Ausserdem sollte es einen Fehler geben:
    GL_INVALID_VALUE is generated if non-power-of-two textures are not supported and the width or height cannot be represented as 2 k + 2 ⁡ border for some integer value of k.

    Und jeder prüft natürlich regelmässig auf GL Errors, oder?

    Edit GL_ARB_texture_non_power_of_two ist 8 Jahre alt ;) Da hat sogar Apple inzwischen mitgezogen :P
    C++
  • zerm schrieb:

    ssb schrieb:

    Laut Spezifikation müssen Texturen quadratisch sein mit einer Seitenlänge in Pixeln, die auf Potenzen von 2 beschränkt sind.

    Wir haben seit gefühlten zehn Jahren GL_ARB_texture_non_power_of_two, also keine Beschränkung auf Power-of-two Texturen. Eventuell aber nicht auf ES 1.0 (iPhone ältere Generation), bin ich mir aber nicht sicher.

    Ausserdem sollte es einen Fehler geben:
    GL_INVALID_VALUE is generated if non-power-of-two textures are not supported and the width or height cannot be represented as 2 k + 2 ⁡ border for some integer value of k.

    Und jeder prüft natürlich regelmässig auf GL Errors, oder?

    Edit GL_ARB_texture_non_power_of_two ist 8 Jahre alt ;) Da hat sogar Apple inzwischen mitgezogen :P

    nicht bei ES
  • wolf_10de schrieb:

    Deshalb meine Frage wie groß die texture ist. Sie muss Power of 2 sein, nicht unbedingt quadratisch
    also 512x32 oder 16x256, usw...
    Das ist korrekt, in dem Fall geht es nun wieder.

    @ssb
    Wenn du mir noch sagen kannst, ob ich es irgendwie abstellen kann, dass die letzten Buchstaben meiner Schrift bzw. meiner Grafik nicht mehr im linken Bereich der Textur auftreten (siehe Screenshots).
    Oder soll ich da das NSImage generell größer initialisieren und anschließend den NSString zentriert zeichnen?
  • Nobik schrieb:

    wolf_10de schrieb:

    Deshalb meine Frage wie groß die texture ist. Sie muss Power of 2 sein, nicht unbedingt quadratisch
    also 512x32 oder 16x256, usw...
    Das ist korrekt, in dem Fall geht es nun wieder.

    @ssb
    Wenn du mir noch sagen kannst, ob ich es irgendwie abstellen kann, dass die letzten Buchstaben meiner Schrift bzw. meiner Grafik nicht mehr im linken Bereich der Textur auftreten (siehe Screenshots).
    Oder soll ich da das NSImage generell größer initialisieren und anschließend den NSString zentriert zeichnen?

    Das sind die UV-Koordinaten oder hast du eine Texturewiederholung GL_REPEAT eingestellt?
  • Nobik schrieb:

    @ssb
    Wenn du mir noch sagen kannst, ob ich es irgendwie abstellen kann, dass die letzten Buchstaben meiner Schrift bzw. meiner Grafik nicht mehr im linken Bereich der Textur auftreten (siehe Screenshots).
    Oder soll ich da das NSImage generell größer initialisieren und anschließend den NSString zentriert zeichnen?

    Ich bin zwar nicht ssb, trotzdem: Entweder lädst Du die Textur schon rewrappt hoch (sprich mit einem Offset). Oder Du stellst sie gewrappt dar. Einfach den Texturparameter von GL_REPEAT auf GL_CLAMP stellen.
    Multigrad - 360°-Produktfotografie für den Mac