Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Mär 28, 2024 18:34

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 3 Beiträge ] 
Autor Nachricht
BeitragVerfasst: So Jul 08, 2018 15:01 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Hallo!

Ich tue mich immer noch sehr schwer mit den verschiedenen Blend Modi, vielleicht aber auch weil ich immer irgendwelche "Sonderfälle" habe:

Siehe Anhang.
Ich befinde mich im glOrtho-Modus. Alles in 2D, damit nichts verzerrt, sondern Alles pixelgenau dargestellt wird.

Entsprechend Tutorial 7 ( https://wiki.delphigl.com/index.php/Tutorial_Lektion_7 ) rendere ich zuerst das Hintergrundbild. Dies kann zwar nach Benutzereinstellung teilweise transparent sein (entweder wegen Alpha < 100% oder weil PNG-Bild mit Teiltransparenz). Hier in diesem konkreten Beispiel nehmen wir aber an, dass es zu 100% deckend dargestellt wird.

Nun wird mit glVertex2i(x, y) eine halbtransparente, weiße Box drübergelegt.

Vielleicht nicht ganz unwichtiger Hinweis: Ich zeichne in einen FrameBuffer, was vielleicht zusätzliche Probleme mit sich bringt, und Diese hier überhaupt erst erzeugt:

Statt dass das dunkelblaue Hintergrundbild ein wenig aufgehellt wird, wird dieses nun selbst an den betroffenen Pixelstellen 50% transparent. Damit habe ich nun genau die Situation vom Tutorial ("Der ahnungslose Programmierer wird dann mit großen Augen vor dem Fenster stehen und sich wundern, wieso er durch die hintere Wand des Hauses ins Freie sehen kann."), obwohl ich jedoch zuerst die hintere Wand gezeichnet habe.

Ich denke, ich kenne die Ursache des Problems: Da im 2D-Modus (von mir) alles auf die Z-Ebene "0" gezeichnet wird, hat eben der Zeichenvorgang "Recht", der zuletzt gezeichnet hat. Wenn ich zuerst den betroffenen Bereich deckend zeichne (Wolken / Dunkelblau), und dann die kleinere halbtransparente Box drüberzeichne, wird in diesem Bereich (leider?) nicht einfach nur die Farbe des kleinen Bereichs halbtransparent dazuaddiert, sondern auch der komplette Alphawert der Z-Ebene 0 auf 50% gesetzt.

Ich arbeite bisher mit
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Vermutlich gibt es zwei korrekte Lösungswege:
1) Arbeiten mit "Tiefe", also Z Korrdinate --> glVertex3i . Hintergrundbild mit Z-Koordinate wirklich "hinter" der kleineren Box zeichnen, damit sollte es dann auch keine Probleme geben, wenn das Hintergrundbild mit Alpha nur 90% deckend ist...(?) Problem: Ich muss nun nachträglich überall in meinen Programmen die Z-Ebene einführen, was erheblicher aufwand wäre...

2) Arbeiten mit anderem BlenModus/BlendFunc (Welchem?)
Im Tutorial sind ja zahlreiche Möglichkeiten erleutert, die man einfach nur Auswählen muss. Leider weiß ich nicht, was ich auswählen möchte. Wenn ich z.B. DST-Alpha behalten möchte, wird dann die kleine Box gar nicht mehr geblendet sonder zu 100% decken draufgeklatscht oder wie? (Leider setzen meine einzelnen Objekt jeweils mehrmals glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) damit, nach meiner damaligen Meinung, auch alles richtig gezeichnet wird (ist ja ansonsten auch der Fall); damit kann ich nicht "mal eben" in einen anderen Blendmodus wechseln und auch wirklich Resultate sehen.

glBlend kann ich auch für das Hintergrundbild nicht pauschal ausschalten, da ja im richtigen Betrieb auch das Hintergrundbild halbtransparent sein kann (es liegt dann noch ein anderes Hintergrundbild hintendran...).

Ich denke, auch laut Artikel https://wiki.delphigl.com/index.php/glBlendFunc ist der Blendmodus zwar richtig, aber das Problem besteht mit dem Tiefenpuffer (der ja nur eine Ebene hat).

Falls ich auf mehrere Z-Ebenen umstellen soll, wie mache ich das am unproblematischsten für den kompletten Code?
glDepthFunc(GL_ALWAYS), und bei glVertext3i die Z-Koordinate immer entsprechend ändern so, wie ich bisher "von Hinten nach Vorne" gezeichnet habe?

Wobei mir die WikiSeite für den Teifentest ( https://wiki.delphigl.com/index.php/Tiefentest ) auch da wieder einen Riegel vorschieben will:
Zitat:
Sobald Transparenz verwendet wird, kann der Tiefentest zumindest für diese Teile nicht mehr benutzt werden. Dies würde zu Fehlern führen, da das transparente Fragment ggfs. das durchscheinende, jedoch erst später an die Grafik-Pipeline gesendete und somit vom Tiefentest verworfene Fragment dahinter völlig verbirgt. Wenn man Transparente Fragmente nicht in den Tiefenbuffer schreibt, so können diese Fragmente von anderen, eigentlich weiter hinten liegenden, Fragmenten komplett überschrieben werden.
Aus diesem Grund sollten Transparente Objekte nach allen anderen Objekten an OpenGL geschickt werden und diese möglichst von hinten nach vorne sortiert sein. Das Sortieren kann durch einen Alpha Wert im Framebuffer umgangen werden, jedoch ist dieser nur selten in Hardware vorhanden, wodurch in den weit langsameren Softwaremodus gewechselt wird.


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Zuletzt geändert von berens am Mo Jul 09, 2018 13:16, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jul 08, 2018 22:08 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Sobald Transparenz verwendet wird, kann der Tiefentest zumindest für diese Teile nicht mehr benutzt werden. Dies würde zu Fehlern führen, da das transparente Fragment ggfs. das durchscheinende, jedoch erst später an die Grafik-Pipeline gesendete und somit vom Tiefentest verworfene Fragment dahinter völlig verbirgt. Wenn man Transparente Fragmente nicht in den Tiefenbuffer schreibt, so können diese Fragmente von anderen, eigentlich weiter hinten liegenden, Fragmenten komplett überschrieben werden.
Ich denke, damit hast du den Nagel auf den Kopf getroffen.
Wen man Alpha-Blending verwendet, ist es sehr wichtig, in welcher Reihenfolge gezeichnet wird. Man muss die Objekte/Meshes sortieren.

Siehe hier:
https://wiki.delphigl.com/index.php/Laz ... st_wichtig
https://wiki.delphigl.com/index.php/Laz ... a_Blending

Dies ist zwar OpenGL 3.3, aber dies spielt keine Rolle.

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jul 09, 2018 10:55 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Edit siehe unten, ich will nicht dauernd Beiträge "spammen" ;)


Also das Problem hängt definitiv mit dem Framebuffer zusammen!

Das möchte ich machen (ein kleines, halbtransparentes, rotes Rechteck auf einem blauen undurchsichtigem) im glOrto-Modus entsprechend Dimensdimensionen des Fensters, bzw. FBO.

Dateianhang:
2018-07-09 11_52_48-OhneFrameBuffer.png

Dateianhang:
2018-07-09 11_52_48-MitFrameBuffer.png


Vielleicht habe ich in der Framebufferunit ein Fehler/Problem mit dem Tiefenpuffer?


Das geht:
Code:
  1.  
  2.   glColor4f(0, 0, 1, 1);
  3.   glBegin(GL_QUADS);
  4.     glVertex3i( 10,  10, -10);
  5.     glVertex3i( 10, 500, -10);
  6.     glVertex3i(500, 500, -10);
  7.     glVertex3i(500,  10, -10);
  8.   glEnd;
  9.  
  10.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  11.   glEnable(GL_BLEND);
  12.  
  13.   glColor4f(1, 0, 0, 0.5);
  14.   glBegin(GL_QUADS);
  15.     glVertex3i( 50,  50, -5);
  16.     glVertex3i( 50, 450, -5);
  17.     glVertex3i(450, 450, -5);
  18.     glVertex3i(450,  50, -5);
  19.   glEnd;
  20.  
  21.   glDisable(GL_BLEND);
  22.  


Das geht nicht:
Code:
  1.  
  2.   fb := TglFrameBuffer.Create(Self, PositionUserDesigned.Width, PositionUserDesigned.Height);
  3.   fb.Bind;
  4.   glClearColor(1, 1, 1, 1);
  5.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  6.  
  7.   glColor4f(0, 0, 1, 1);
  8.   glBegin(GL_QUADS);
  9.     glVertex3i( 10,  10, -10);
  10.     glVertex3i( 10, 500, -10);
  11.     glVertex3i(500, 500, -10);
  12.     glVertex3i(500,  10, -10);
  13.   glEnd;
  14.  
  15.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  16.   glEnable(GL_BLEND);
  17.  
  18.   glColor4f(1, 0, 0, 0.5);
  19.   glBegin(GL_QUADS);
  20.     glVertex3i( 50,  50, -5);
  21.     glVertex3i( 50, 450, -5);
  22.     glVertex3i(450, 450, -5);
  23.     glVertex3i(450,  50, -5);
  24.   glEnd;
  25.  
  26.   glDisable(GL_BLEND);
  27.   fb.Unbind;
  28.  
  29.   // bis hierher alles wie oben; es wird jedoch statt auf den Bildschirm ein den Framebuffer gezeichnet.
  30.  
  31.   // Jetzt den Frambuffer als "Textur" laden und darstellen:
  32.   glMatrixMode(GL_TEXTURE);
  33.   glEnable(GL_TEXTURE_2D);
  34.   glEnable(gl_Blend);
  35.  
  36.   FB.Textur.Bind;
  37.  
  38.   glColor4f(1, 1, 1, 1);
  39.   glBegin(GL_QUADS);
  40.     glTexCoord2f(0, 0);
  41.     glVertex3f(0, 0, 0);
  42.  
  43.     glTexCoord2f(0, fb.Height/fb.TexturHeight);
  44.     glVertex3f(0, fb.Height, 0);
  45.  
  46.     glTexCoord2f(fb.Width/fb.TexturWidth, fb.Height/fb.TexturHeight);
  47.     glVertex3f(fb.Width, fb.Height, 0);
  48.  
  49.     glTexCoord2f(fb.Width/fb.TexturWidth, 0);
  50.     glVertex3f(fb.Width, 0, 0);
  51.   glEnd;
  52.  


Und hier die Framebuffer Unit:
Code:
  1.  
  2. unit HAL1_GRAPHICS_glFrameBuffer;
  3.  
  4. interface
  5.  
  6. {$REGION 'uses 1.1'}
  7. uses
  8.   , dglOpenGL
  9.  
  10.  
  11. type
  12.   TVektor = record
  13.             X,Y,Z,W : glFloat
  14.   end;
  15.   TMatrix = array[(mat_XAchse,mat_YAchse,mat_ZAchse,mat_Position)] of TVektor;
  16.  
  17. type
  18.   TglFrameBuffer = class(TComponent)
  19.   private
  20.     FFBO: GluInt;
  21.     depthbuffer: GLuint;
  22.     FTextur: TTextur;
  23.     FWidth, FHeight: Integer;
  24.     FTexturWidth, FTexturHeight: Integer;
  25.     FOriginalMatrix: TMatrix;
  26.     procedure CheckFBO;
  27.   public
  28.     property FBO: GLuint read FFBO;
  29.     property Width: integer read FWidth;
  30.     property Height: integer read FHeight;
  31.     property TexturWidth: integer read FTexturWidth;
  32.     property TexturHeight: integer read FTexturHeight;
  33.     property Textur: TTextur read FTextur;
  34.  
  35.     procedure Bind;
  36.     procedure UnBind;
  37.  
  38.     constructor Create(_Owner: TComponent; _Width, _Height: integer); reintroduce;
  39.     destructor Destroy; override;
  40.   end;
  41.  
  42.  
  43. implementation
  44.  
  45. uses
  46.  
  47. , glBitmap
  48. ;
  49.  
  50.  
  51.  
  52. { TglFrameBuffer }
  53.  
  54. constructor TglFrameBuffer.Create(_Owner: TComponent; _Width, _Height: integer);
  55. begin
  56.   inherited Create(_Owner);
  57.  
  58.   if _Width  < 1 then _Width  := 1;
  59.   if _Height < 1 then _Height := 1;
  60.   FWidth  := _Width;
  61.   FHeight := _Height;
  62.   FTexturWidth  := HAL1_PowerOf2(_Width);
  63.   FTexturHeight := HAL1_PowerOf2(_Height);
  64.  
  65.   glGenFramebuffersEXT(1, @FFBO);
  66.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FFBO);
  67.   glGenRenderbuffersEXT(1, @depthbuffer);       //
  68.   glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);//
  69.   glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, TexturWidth, TexturHeight);
  70.   glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer);
  71.  
  72.   //  FTextur := TTextur.Create(glBitmapPosition(TexturWidth, TexturHeight), ifBGRA8);
  73.   FTextur := TTextur.CreateNew(TexturWidth, TexturHeight);
  74.   FTextur.GenTexture;
  75.   FTextur.Bind;
  76.  
  77.   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, FTextur.ID, 0);
  78.   CheckFBO;
  79. end;
  80.  
  81. destructor TglFrameBuffer.Destroy;
  82. begin
  83.   glDeleteFramebuffersEXT(1, @FFBO);
  84.   glDeleteRenderbuffersEXT(1, @depthbuffer);
  85.   FreeAndNil(FTextur);
  86.  
  87.   inherited;
  88. end;
  89.  
  90. procedure TglFrameBuffer.Bind;
  91. begin
  92.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FFBO);
  93.  
  94.   glGetFloatv(GL_PROJECTION_MATRIX, @FOriginalMatrix);
  95.  
  96.   glPushAttrib(GL_VIEWPORT_BIT);
  97.  
  98.   glViewPort(0, 0, TexturWidth, TexturHeight);
  99.   glMatrixMode(GL_PROJECTION);
  100.   glLoadIdentity();
  101.  
  102.   glOrtho(0, TexturWidth, TexturHeight, 0, 0, 1000);
  103. //  glOrtho(0, TexturWidth, 0, -TexturHeight, 0, 1000);
  104.   glMatrixMode(GL_MODELVIEW);
  105.   glLoadIdentity;
  106.  
  107.   glClearColor(0,0,0,0);
  108.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  109. end;
  110.  
  111. procedure TglFrameBuffer.UnBind;
  112. begin
  113.   Textur.FlipV;
  114.  
  115.   glPopAttrib;
  116.  
  117.   glLoadMatrixf(@FOriginalMatrix);
  118. //  glMatrixMode(GL_MODELVIEW);
  119. //  glLoadIdentity;
  120.  
  121.  
  122.   glMatrixMode(GL_PROJECTION);
  123.   glLoadIdentity();
  124.  
  125.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  126. end;
  127.  
  128. procedure TglFrameBuffer.CheckFBO;
  129. var
  130.   error: GlEnum;
  131. begin
  132.   error := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  133.   case error of
  134.     GL_FRAMEBUFFER_COMPLETE_EXT:
  135.       Exit;
  136.     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
  137.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete attachment', ws_SEVERITY_EXCEPTION);
  138.     GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
  139.       Log('TglFrameBuffer.CheckFBO', M, 'Missing attachment', ws_SEVERITY_EXCEPTION);
  140.     GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
  141.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete dimensions', ws_SEVERITY_EXCEPTION);
  142.     GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
  143.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete formats', ws_SEVERITY_EXCEPTION);
  144.     GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
  145.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete draw buffer', ws_SEVERITY_EXCEPTION);
  146.     GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
  147.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete read buffer', ws_SEVERITY_EXCEPTION);
  148.     GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  149.       Log('TglFrameBuffer.CheckFBO', M, 'Framebufferobjects unsupported', ws_SEVERITY_EXCEPTION);
  150.   end;
  151. end;
  152.  
  153. end.



Edit 1:
Zunächste mal wieder vielen Dank an @mathias für den bisherigen Tip.

Die Erkenntnis, dass das Problem definitiv mit FrameBufferObject (FBO) und Alpha-Werten zu tun hat, lieferte mit nun auch seeehr viele Ergebnisse zum selben Thema hier im Forum.

Die Eigentliche Lösung kam von @Bergmann89 - ich folge ihm mit der Erfahrungssammlung in OpenGL was Probleme etc. an geht sehr direkt nach, bin halt nur ein paar Jahre hinten dran ;)

Im Beitrag https://delphigl.com/forum/viewtopic.php?f=2&t=9178&hilit=fbo+alpha schildert er das identische Problem, und freundlicherweise auch die Lösung, so wie ich sie anwenden kann.

Wie bereits festgestellt, überschreiben die zuletzt gerenderten Objekte -auch wenn Sie näher am Betrachter liegen- den Alpha-Wert des dahinterliegenden Objektes - wenn in eine Framebufferobject (FBO) gezeichnet wird! (Wie gesagt, beim normalen rendern geht alles.) Stellen wir uns den FBO einfach als normale Textur oder PNG-Datei mit Transparenz vor, so ist nun das Bild an Stellen teilweise oder komplett durchsichtig, wo eigentlich nur ein Objekt hätte draufgeblendet werden sollen.

Die Lösung lässt sich nun auch bei mir einfach anwenden: Der Hintergrund des Framebuffers muss nun nochmal seinen kompletten Alpha-Wert neu zeichnen. Nur Alpha, nicht das Bild (Freche Kopie aus dem verlinkten Thread):
Code:
  1. glColorMask(False, False, False, True);
  2. glColor4f(1,1,1,1);
  3. glDisable(GL_TEXTURE_2D);
  4. glBegin(GL_QUADS);
  5.   glVertex2f(        0,        0);
  6.   glVertex2f(W(Button),        0);
  7.   glVertex2f(W(Button), H(Button));
  8.   glVertex2f(        0, H(Button));
  9. glEnd;
  10. glEnable(GL_TEXTURE_2D);
  11. glColorMask(True, True, True, True);


Mein Pendant ist:
Code:
  1. glEnable(GL_BLEND);
  2. glColorMask(False, False, False, True);
  3. glColor4f(1,1,1,1);
  4. Background.Render;
  5. glColorMask(True, True, True, True);
  6.  


Somit kann nun das Hintergrundbild immernoch problemlos Transparent sein ("Farbverlauf" von Deckend zu Transparent, PNG mit teilweiser Transparenz, ...) es wird (für mich: ebenso überraschender wie erfreulicher Weise) korrekt dargestellt. Da die Elemente im Vordergrund schon vorher gerendert und geblendet waren (die kleinen Boxen und bei mir der Text etc.) hat das drüberzeichnen eines "anderen" Alphawertes nun keine Auswirkungen mehr, die das Ergebnis verfälschen würden.

Wieder was gelernt, danke für Lesen und Antworten!


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 3 Beiträge ] 
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 23 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.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.095s | 17 Queries | GZIP : On ]