OpenGL Texture Mapping - Farbverfälschung?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Christian
Beiträge: 73
Registriert: 31.08.2004 16:02

OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Christian »

Hi,

ich beschäftige mich derzeit mit OpenGL und bin nun beim Texture Mapping angekommen. Zum Einstieg habe ich mich daran gemacht, einfach nur ein zur Laufzeit erzeugtes, quadratisches Image als Textur auf ein OpenGL-Quad zu legen. Dabei ist mir aufgefallen, dass zwischen dem Bild und der Textur leichte Farbunterschiede bestehen. Da meine Grafikarte nur sperrlich auf 3D ausgelegt ist, bin ich mir nun nicht sicher, ob es an ihr oder an meiner möglicherweise falschen Handhabung von OpenGL-Befehlen liegt. Hier mal ein Beispielcode:

Code: Alles auswählen

; ; - OpenGL-Include
; XIncludeFile "OpenGL.pbi"

; - verwendete OpenGL-Konstanten und -Funktionen
#GL_TEXTURE_2D = $0DE1
#GL_TEXTURE_MAG_FILTER = $2800
#GL_TEXTURE_MIN_FILTER = $2801
#GL_NEAREST = $2600
#GL_LINEAR = $2601
#GL_RGB8 = $8051
#GL_RGBA8 = $8058
#GL_RGBA = $1908
#GL_RGB = $1907
#GL_UNSIGNED_BYTE = $1401
#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_MODELVIEW = $1700
#GL_PROJECTION = $1701
#GL_VERTEX_ARRAY = $8074
#GL_TEXTURE_COORD_ARRAY = $8078
#GL_DOUBLE = $140A
#GL_FLOAT = $1406
#GL_TRIANGLE_STRIP = $0005

Import "Opengl32.lib"
   glEnable_(a.l) As "_glEnable@4"
   glGenTextures_(a.l,b.l) As "_glGenTextures@8"
   glBindTexture_(a.l,b.l) As "_glBindTexture@8"
   glTexImage2D_(a.l,b.l,c.l,d.l,e.l,f.l,g.l,h.l,i.l) As "_glTexImage2D@36"
   glClear_(a.l) As "_glClear@4"
   glClearColor_(a.f,b.f,c.f,d.f) As "_glClearColor@16"
   glMatrixMode_(a.l) As "_glMatrixMode@4"
   glLoadIdentity_() As "_glLoadIdentity@0"
   glOrtho_(a.d,b.d,c.d,d.d,e.d,f.d) As "_glOrtho@48"
   glTranslatef_(a.f,b.f,c.f) As "_glTranslatef@12"
   glEnableClientState_(a.l) As "_glEnableClientState@4"
   glVertexPointer_(a.l,b.l,c.l,d.l) As "_glVertexPointer@16"
   glTexCoordPointer_(a.l,b.l,c.l,d.l) As "_glTexCoordPointer@16"
   glDrawArrays_(a.l,b.l,c.l) As "_glDrawArrays@12"
   glDisableClientState_(a.l) As "_glDisableClientState@4"
EndImport





EnableExplicit

; - Beispiel - Verfälschung der Texturfarben
If OpenWindow(0, 0, 0, 800, 600, "OpenGL Texturbeispiel - Farbverfälschung", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    ; - Variablen definieren
    Define hWnd.l, Width.l, Height.l, hDC.l, hRC.l
    Define PixelFormat.PIXELFORMATDESCRIPTOR, iPixelFormat.l
    Define TextureID.l, ImageID.l
    Define TerminateProgram.b

    hWnd                   = WindowID(0)
    Width                  = WindowWidth(0)
    Height                 = WindowHeight(0)
    hDC                    = GetDC_(hWnd)

    ; - Pixelformat des DC
    PixelFormat\nSize      = SizeOf(PIXELFORMATDESCRIPTOR)
    PixelFormat\nVersion   = 1
    PixelFormat\dwFlags    = #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW
    PixelFormat\iPixelType = #PFD_TYPE_RGBA
    PixelFormat\cColorBits = 32
    PixelFormat\cDepthBits = 16
    PixelFormat\iLayerType = #PFD_MAIN_PLANE
    iPixelFormat           = ChoosePixelFormat_(hDC, PixelFormat)

    ; - dieses PixelFormat dann dem DC zuweisen
    SetPixelFormat_(hDC, iPixelFormat, PixelFormat)

    ; - OpenGL-RenderContext
    hRC = wglCreateContext_(hDC)
    wglMakeCurrent_(hDC, hRC)

    ; - (2D-)Texturen in OpenGL aktivieren
    glEnable_(#GL_TEXTURE_2D)

    ; - Farbtiefe des Bildes festlegen
    #Color_Depth = 24

    ; - Bild zeichnen, dass als Textur verwendet werden wird
    ImageID = CreateImage(#PB_Any, 512, 512, #Color_Depth)
    If StartDrawing(ImageOutput(ImageID)) <> 0

        Box(0, 0, ImageWidth(ImageID), ImageHeight(ImageID), RGB(200, 200, 200))
        Box(20, 20, ImageWidth(ImageID) - 40, ImageHeight(ImageID) - 40, RGB(255, 255, 255))
        Box((ImageWidth(ImageID) - 100) / 2, (ImageHeight(ImageID) - 100) / 2, 100, 100, RGB(100, 100, 240))

        StopDrawing()

    EndIf

    ; - Texturnamen generieren
    glGenTextures_(1, @TextureID)
    If glBindTexture_(#GL_TEXTURE_2D, TextureID)

        ; - Variablen definieren
        Define ImageDC.l
        Define ImageBufferSize.l, *ImageBuffer, bmi.BITMAPINFO

        ImageDC = StartDrawing(ImageOutput(ImageID))
        If ImageDC <> 0

            ; - Speicherbereich reservieren
            ImageBufferSize             = ImageWidth(ImageID) * ImageHeight(ImageID) * #Color_Depth / 8
            *ImageBuffer                = AllocateMemory(ImageBufferSize)

            ; - Headerdaten festlegen
            bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
            bmi\bmiHeader\biWidth       = ImageWidth(ImageID)
            bmi\bmiHeader\biHeight      = ImageHeight(ImageID)
            bmi\bmiHeader\biPlanes      = 1
            bmi\bmiHeader\biBitCount    = #Color_Depth
            bmi\bmiHeader\biCompression = #BI_RGB

            ; - Bilddaten aus dem Speicher erfassen 
            GetDIBits_(ImageDC, ImageID(ImageID), 0, ImageHeight(ImageID), *ImageBuffer, bmi, #DIB_RGB_COLORS)

            StopDrawing()



            ; - Struktur-BGRA
            Structure BGRA
             b.c
             g.c
             r.c
             a.c
            EndStructure

            ; - Pointer auf den aktuellen Pixel/Farbwert
            Define *Pixel.BGRA, i.l

            ; - Farben liegen im BGRA vor -> für glTexImage2D_() wird aber RGBA benötigt
            For i = 0 To ImageBufferSize - 1 Step #Color_Depth / 8

              ; - Farbwert auslesen
              *Pixel = *ImageBuffer + i

              ; - B- und R-Wert vertauschen
              Swap *Pixel\b, *Pixel\r

            Next i

        EndIf

        ; - wenn die Farb-Tiefe 24 Bit beträgt
        If #Color_Depth = 24

            ; - aus den obigen Bitmap-Daten eine OpenGL-Textur erstellen
            glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGB8, ImageWidth(ImageID), ImageHeight(ImageID), 0, #GL_RGB, #GL_UNSIGNED_BYTE, *ImageBuffer)

        ; - sonst, wenn sie 32 Bit beträgt
        ElseIf #Color_Depth = 32

            ; - aus den obigen Bitmap-Daten eine OpenGL-Textur erstellen
            glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGBA8, ImageWidth(ImageID), ImageHeight(ImageID), 0, #GL_RGBA, #GL_UNSIGNED_BYTE, *ImageBuffer)

        EndIf

        ; - Texturfilter setzen
        glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)

        ; - Vertex- und Texel-Array definieren
        Dim Vertex.f(11)
        Dim Texel.f(7)

        ; - Vertex-Array für QUAD
        Vertex(0) = 0                    :   Vertex(1) = ImageHeight(ImageID) :  Vertex(2) = -1
        Vertex(3) = ImageWidth(ImageID)  :   Vertex(4) = ImageHeight(ImageID) :  Vertex(5) = -1
        Vertex(6) = 0                    :   Vertex(7) =                   0  :  Vertex(8) = -1
        Vertex(9) = ImageWidth(ImageID)  :  Vertex(10) =                   0  : Vertex(11) = -1

        ; - Texel-Array
        Texel(0)  =  0.0  :  Texel(1) = 1.0
        Texel(2)  =  1.0  :  Texel(3) = 1.0
        Texel(4)  =  0.0  :  Texel(5) = 0.0
        Texel(6)  =  1.0  :  Texel(7) = 0.0

    EndIf



    Repeat

      Repeat
        Define EventID.l = WaitWindowEvent(10)
        Select EventID
          Case #PB_Event_CloseWindow
            TerminateProgram = #True
        EndSelect
      Until (EventID = 0 Or TerminateProgram = #True)



      ; - Buffer leeren
      glClearColor_(200/255, 200/255, 200/255, 1)
      glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)



      ; - Projektionsmatrix auswählen
      glMatrixMode_(#GL_PROJECTION)
      glLoadIdentity_()

      ; - orthogonale Projektion verwenden
      glOrtho_(0, Width, 0, Height, 1.0, 1000.0)

      ; - ModelView auswählen
      glMatrixMode_(#GL_MODELVIEW)
      glLoadIdentity_()

      ; - in das lokale Koordinatensystem des Bildes übergehen
      glTranslatef_((Width - ImageWidth(ImageID)) / 2, (Height - ImageHeight(ImageID)) / 2, 0)

      ; - OpenGL mitteilen, dass Koordinaten-Arrays für Vertices und Texturen verwendet werden
      glEnableClientState_(#GL_VERTEX_ARRAY)
      glEnableClientState_(#GL_TEXTURE_COORD_ARRAY)

      ; - OpenGL-Quad rendern, welches das Sprite repräsentiert
      glBindTexture_(#GL_TEXTURE_2D, TextureID)
      glVertexPointer_(3, #GL_FLOAT, 0, @Vertex(0))
      glTexCoordPointer_(2, #GL_FLOAT, 0, @Texel(0))
      glDrawArrays_(#GL_TRIANGLE_STRIP, 0, 4)

      ; - OpenGL mitteilen, dass die Koordinaten-Arrays für Vertices und Texturen nicht mehr benötigt werden
      glDisableClientState_(#GL_VERTEX_ARRAY)
      glDisableClientState_(#GL_TEXTURE_COORD_ARRAY)    



      ; - Front- und Back-Buffer vertauschen
      SwapBuffers_(hDC)

    Until TerminateProgram = #True

    ; - Textur löschen
    glDeleteTextures_(1, @TextureID);

    ; - RenderContext löschen
    wglMakeCurrent_(#Null, #Null)
    wglDeleteContext_(hRC)
    ReleaseDC_(hWnd, hDC)

EndIf

End
Auf das Bild zeichne ich einfach 3 ineinander geschachtelte Quadrate mit den Farben:

RGB(200, 200, 200)
RGB(255, 255, 255)
RGB(100, 100, 240)

Mache ich aber vom obigen, laufenden Programm einen Screenshot und lese die Farbwerte aus, dann sind diese 3 Quadrate (leicht) anders gefärbt, nämlich mit:

RGB(204, 204, 204)
RGB(255, 255, 255) -> (weiß und schwarz werden korrekt dargestellt)
RGB(102, 102, 255)

Wäre schön, wenn jemand den obigen Code mal testen könnte und mal schauen würde, ob bei ihm diese Farbverfäschung auch auftaucht. Falls das bei euch auch auftritt: Was mache ich oben falsch? Der Knackpunkt scheint mir der glTexImage2D_() Befehl zu sein, aber da entdecke ich keinen Fehler ...

Vielen Dank!

Grüße,
Christian
Zuletzt geändert von Christian am 13.03.2010 02:16, insgesamt 3-mal geändert.
Benutzeravatar
Josh
Beiträge: 1028
Registriert: 04.08.2009 17:24

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Josh »

dass der screenshot was anderes zeigt als der ursprüngliche bildschirm, kommt mir komisch vor. wenn leicht andere farben als von deinem programm vorgegeben angezeigt werden, dann würde ich tippen, dass du deine grafikkarte nicht auf truecolor eingestellt hast.
Christian
Beiträge: 73
Registriert: 31.08.2004 16:02

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Christian »

Nein, richtig konfiguriert ist meine Hardware schon.
Dieses Problem tritt ja nur in der Textur auf - alles andere funktioniert. Insbesondere wird im obigen Beispiel auch die Farbe, die ich mit glClearColor_() für den Hintergrund einstelle, korrekt dargestellt. Es sind nur die Farben der Textur verfälscht.

Hast du den obigen Code mal ausprobiert?
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Kaeru Gaman »

die werte 204 und 102 lassen darauf schließen, dass die Texture mit einer anderen Bit-Tiefe vorliegt.
keine Ahnung wo man das bei openGL angibt, aber sieht so aus als ob das eben keine 32bit Texture ist, zumindest im Speicher.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von DarkDragon »

Bei mir zeigt es ein weißes Quadrat an, der Quelltext ist einfach nicht sauber.
Btw.: "glBindTexture_(#GL_TEXTURE_2D, @TextureID)" das @ muss weg. Aber das hilft auch nicht.
OpenGL und DirectX sind beides keine pixelkorrekten Renderer. Gerade bei mobilen und Onboardgrafikkarten ist das so.
Bei ATI Grafikkarten werden alle Farbwerte einer Textur intern als 16bit Fließkommazahl standardmäßig gespeichert. Bei nVidia standardmäßig mit 32bit. Das einzige was da hilft ist manuell auf 16 oder 32bit umstellen, aber von diesen Texturen sollte man nicht zuviele im Speicher haben bzw. darstellen.

P.S.: Double-Vertex/TexturecoordArrays sind schlecht fürs Karma ;-) . Das wurde damals als OpenGL 3.0 rauskam schon infrage gestellt ob man das weiterführen soll. Die Grafikkarten verarbeiten nicht mehr als 32bit Fließkommawerte.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Christian
Beiträge: 73
Registriert: 31.08.2004 16:02

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Christian »

Kaeru Gaman hat geschrieben:die werte 204 und 102 lassen darauf schließen, dass die Texture mit einer anderen Bit-Tiefe vorliegt.
keine Ahnung wo man das bei openGL angibt, aber sieht so aus als ob das eben keine 32bit Texture ist, zumindest im Speicher.
Danke, das war der entscheidende Hinweis!

Nach ein bisschen Suche bin ich nun endlich auf den zu dieser Überlegung passenden Link gestoßen:

http://www.opengl.org/resources/code/sa ... ode51.html

glTexImage2D_() kann im dritten Parameter mit den in dieser Liste aufgeführten #GL_* Konstanten aufgerufen werden, der die OpenGL-Implementation (soweit möglich) dazu zwingt die Textur in einem bestimmten Farbformat zu speichern. Ich habe obiges Beispiel mal entsprechend angepasst.


@Dark Dragon:

Danke dir für den Hinweis zum "@" bei glBlindTexture_() und den Double-Vertext/TextureCoordArrays!
Nachdem ich meine Farbtiefe am Rechner während der Fehlersuche mal von 32 Bit auf 24 Bit runtergesetzt hatte, um einen 24-Bit DeviceContext nutzen zu können, wurde bei mir auch nur ein weißes Quadrat angezeigt.
Ich habe dann mal die folgende Zeile hinzugefügt, um die Textur-Filterung einzustellen:

Code: Alles auswählen

   ; - Texturfilter setzen
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)
Damit wird nun im 24-Bit Modus alles korrekt dargestellt. (unabhängig davon, ob ich nun #GL_NEAREST oder #GL_LINEAR nutze) Allerdings ist mir absolut unklar, warum der Filter aktiviert werden muss, damit es funktioniert. Hast du da eine Erklärung? (Und funktioniert es bei dir jetzt überhaupt auch?)

(Habe den Quellcode im Ausgangsposting mal dahingehend angepasst!)
OpenGL und DirectX sind beides keine pixelkorrekten Renderer. Gerade bei mobilen und Onboardgrafikkarten ist das so.
Was darf ich mir unter einem (nicht) pixelkorrekten Renderer vorstellen? (Google kannte es nicht! :roll: )

Grüße,
Christian
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von DarkDragon »

Christian hat geschrieben:

Code: Alles auswählen

   ; - Texturfilter setzen
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)
Damit wird nun im 24-Bit Modus alles korrekt dargestellt. (unabhängig davon, ob ich nun #GL_NEAREST oder #GL_LINEAR nutze) Allerdings ist mir absolut unklar, warum der Filter aktiviert werden muss, damit es funktioniert. Hast du da eine Erklärung? (Und funktioniert es bei dir jetzt überhaupt auch?)
Es sollte #GL_TEXTURE_MIN_FILTER und #GL_TEXTURE_MAG_FILTER gesetzt werden. Das eine beschreibt was passiert wenn die Textur zu klein ist und das andere wenn sie zu groß ist für die Darstellung auf dem Bildschirm. Ohne diese Informationen geht es nicht (Dann meint es nichts anzeigen zu müssen wenn die Textur zu klein bzw zu groß für die Anzeige ist).
Christian hat geschrieben:
OpenGL und DirectX sind beides keine pixelkorrekten Renderer. Gerade bei mobilen und Onboardgrafikkarten ist das so.
Was darf ich mir unter einem (nicht) pixelkorrekten Renderer vorstellen? (Google kannte es nicht! :roll: )

Grüße,
Christian
Naja das wirst du spätestens bei Blending merken: Blendingeffekte sehen auf unterschiedlichen Systemen immer unterschiedlich aus, außer man macht es selbst.

Versuch mal das hier noch alles bei der Initialisierung (Wie hier vorgeschlagen):

Code: Alles auswählen

    glDisable_(#GL_BLEND)
    glDisable_(#GL_DITHER)
    glDisable_(#GL_FOG)
    glDisable_(#GL_LIGHTING)
    glDisable_(#GL_TEXTURE_1D)
    glDisable_(#GL_TEXTURE_3D)
    glShadeModel_(#GL_FLAT)
    glColor3f_(1.0, 1.0, 1.0)
Aber du wirst mit solch kleineren Verfälschungen früher oder später leben müssen.

[EDIT]
Hier findest du z.B. weitere Farbverfälschungen: http://www.purebasic.fr/german/viewtopi ... endingMode (Ist zwar DirectX, aber dasselbe gilt auch für OpenGL)
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Christian
Beiträge: 73
Registriert: 31.08.2004 16:02

Re: OpenGL Texture Mapping - Farbverfälschung?

Beitrag von Christian »

Es sollte #GL_TEXTURE_MIN_FILTER und #GL_TEXTURE_MAG_FILTER gesetzt werden. Das eine beschreibt was passiert wenn die Textur zu klein ist und das andere wenn sie zu groß ist für die Darstellung auf dem Bildschirm. Ohne diese Informationen geht es nicht (Dann meint es nichts anzeigen zu müssen wenn die Textur zu klein bzw zu groß für die Anzeige ist).
Ah ja, danke - das macht Sinn. Ich war der Auffassung in den letzten Tagen mal gelesen zu haben, dass #GL_TEXTURE_MAG/MIN_FILTER bereits bei der OpenGL-Initialisierung einen Startwert besitzen. Deswegen dachte ich, dass ich die nicht unbedingt setzen muss. Habe gerade nochmal deswegen gegooglet und dazu den Hinweis gefunden, dass OpenGL Texturen standardmäßig als MipMaps interpretiert - da bei meiner Textur aber nur ein Detaillevel von 0 vorliegt, passiert genau das, was du geschrieben hast. OpenGL weiß nicht, wie es das darstellen soll.
DarkDragon hat geschrieben:Versuch mal das hier noch alles bei der Initialisierung (Wie hier vorgeschlagen):

Code: Alles auswählen

 glDisable_(#GL_BLEND)
glDisable_(#GL_DITHER)
glDisable_(#GL_FOG)
glDisable_(#GL_LIGHTING)
glDisable_(#GL_TEXTURE_1D)
glDisable_(#GL_TEXTURE_3D)
glShadeModel_(#GL_FLAT)
glColor3f_(1.0, 1.0, 1.0)
Darauf war ich während meiner Recherche auch schon gestoßen - allerding hatte das nichts gebracht. Das bezieht sich offenbar wirklich nur auf die untexturierten Primitiven, denen einen exakte Farbe zugewiesen werden soll. Sieht man auch daran, dass die Texturen alle deaktiviert werden. (ursprünglich in deinem Link #GL_TEXTURE_2D ja auch)

Letztendlich ist meine Farbverfälschung jetzt aber erstmal weg, indem ich das Interne Texturformat richtig konfiguriere.
Und mit Farbverfälschungen muss ich sicher irgendwann leben, da hast du Recht. Geht ja schon dann los, wenn ich das texturierte Quad irgendwie ein bisschen drehe oder in die z-Richtung neige. Aber da ist es teilweise ja auch gewünscht. Bin jetzt aber zumindest erstmal zufrieden, dass es in Originalgröße korrekt dargestellt wird! Das war mir erstmal wichtig ...
DarkDragon hat geschrieben: [EDIT]
Hier findest du z.B. weitere Farbverfälschungen: http://www.purebasic.fr/german/viewtopi ... endingMode (Ist zwar DirectX, aber dasselbe gilt auch für OpenGL)
Interessant. Das werde ich im Hinterkopf behalten, wenn ich mich mit Blending beschäftige.

Vielen Dank für eure Postings, hat mir neben der Lösung meines Problems gleich noch den ein oder anderen wertvollen Tipp eingebracht. :)

Grüße,
Christian
Antworten