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

Aktuelle Zeit: Do Mär 28, 2024 20:35

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



Ein neues Thema erstellen Auf das Thema antworten  [ 11 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Mi Jun 20, 2018 09:58 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Hallo zusammen,
ich möchte meine gerenderten Ergebnisse nun speichern.

Nachdem ich über einen Framebuffer meine "gerenderten Werke" auf einer Textur habe, möchte ich diese nun weiterverarbeiten.

Bitte direkt runter zu Edit5 springen!


Info: Um zu verhindern, dass jetzt durch diese Frambuffer-Aktion Wechselwirkungen/Probleme auftreten, arbeite ich hier bei diesem konkreten Problem für den Forenbeitrag einfach "nur" mit einer von Festplatte geladenen Graphik.


Ich habe ganz stupide die Funktionen von TglBitmap2D (z.B. SavePNG) verwenden wollen, allerdings erhalte ich die Meldung:
Zitat:
SavePng - the given format isn't supported by this function.

Ursache ist, dass das InternalFormat des TglBitmap2D "ifEmpty" ist. Das kann ich mir partout nicht erklären, weil ich ja genau diese Textur dauernd fehlerfrei rendere. Nach dem Laden der Datei von Festplatte ist das Format garantiert immer "ifBGRA8"; ich weiß nicht, wann/weshalb die Textur ihr Format verliert...

Unabhängig davon würde ich eh am Liebsten die Textur einfach (incl. Alpha!) wieder auf ein TBitmap32 zurückladen. Das Laden aller Bilder findet über AssignFromBitmap32 statt, ich bräuchte also genau das Gegenteil davon:
Code:
  1. function TTextur.AssignFromBitmap32(const aBitmap: TBitmap32): Boolean;
  2. var
  3.   pSource: PColor32Array;
  4.   pData, pTempData: PByte;
  5.   Row, RowSize, TempWidth, TempHeight: Integer;
  6.   IntFormat: TglBitmapInternalFormat;
  7. begin
  8.   Result := False;
  9.  
  10.   if not Assigned(aBitmap) then begin
  11.     Log('TTextur.AssignFromBitmap32.BitmapEmpty', M, '', ws_SEVERITY_UNASSIGNED_WHERE_REQUESTED);
  12.     Exit;
  13.   end;
  14.  
  15.   pData := NIL;
  16.   try
  17.     IntFormat := ifBGRA8;
  18.     TempWidth  := aBitmap.Width;
  19.     TempHeight := aBitmap.Height;
  20.     RowSize := trunc(FormatGetSize(IntFormat) * TempWidth);
  21.     GetMem(pData, TempHeight * RowSize);
  22.  
  23.     pTempData := pData;
  24.     for Row := 0 to TempHeight -1 do begin
  25.       pSource := aBitmap.Scanline[Row];
  26.       if Assigned(pSource) then begin
  27.         Move(pSource^, pTempData^, RowSize);
  28.         Inc(pTempData, RowSize);
  29.       end;
  30.     end;
  31.     SetDataPointer(pData, IntFormat, TempWidth, TempHeight);
  32.  
  33.     FTexturWidth := aBitmap.Width;
  34.     FTexturHeight := aBitmap.Height;
  35.  
  36.     Result := true;
  37.     FValid := True;
  38.   except
  39.     on E: SysUtils.Exception do begin
  40.       if Assigned(pData) then begin
  41.         FreeMem(pData);
  42.       end;
  43.       Log('TTextur.AssignFromBitmap32', M, E.Message, ws_SEVERITY_EXCEPTION);
  44.     end;
  45.   end;
  46. end;
  47.  


Ich habe den Code soweit verstanden, dass nach dem Laden der Arbeitsspeicherbereich "pData" die Pixeldaten enthält, und die Textur diese nun nach "SetDataPointer" als direkte Datenquelle verwendet. Beim Auslesen der Textur müsste ich nun aber so einen Befehl verwenden wie "GetDataPointer", den es allerdings nicht gibt.

Wäre jemand so lieb, und würde mir die Prozedur von "Laden aus Bitmap32" umschreiben nach "Schreibe in Bitmap32"? Oder zumindest ein paar Befehle, wie ich das rüberbekomme.

Alternativ: Falls jemand die Ursache weiß, warum meine imo gültige Textur auf einmal das InternalFormat ifEmpty hat und wie ich das beheben kann, würde ich natürlich auch einfach SavePNG verwenden...

Danke im Voraus!

Edit1:
Code:
  1.     _Bitmap := TBitmap32.Create;
  2.  
  3.  
  4.     TempWidth  := TexturWidthPowerOf2;
  5.     TempHeight := TexturHeightPowerOf2;
  6.     _Bitmap.SetSize(TexturWidthPowerOf2, TexturHeightPowerOf2);
  7.  
  8.     for Row := 0 to TempHeight -1 do begin
  9.       pSource := Self.Scanline[Row];
  10.       pTarget := _Bitmap.ScanLine[Row];
  11.       if Assigned(pSource) then begin
  12.         Move(pSource^, pTarget^, RowSize);
  13.       end;
  14.     end;
  15.  
  16.     _Bitmap.SaveToFile('c:\temp\pngtest.png');
  17.  

Sieht eigentlich nett aus, aber pSource, also Self.Scanline[Row] ist immer NIL. Vielleicht verliere ich wirklich die Textur irgendwo?


Edit2:
Ok, direkt beim Laden setzt GenTexture das InternalFormat auf ifEmpty zurück, da FreeDataAfterGenTexture aktiv ist; ist ja auch irgenwo verständlich. D.h. wahrscheinlich ist die Textur nun im Graphikkartenspeicher, und nicht mehr im normalen RAM.
FreeDataAfterGenTexture auf "False" zu setzen würde zwar meine Demo hier zum Laufen bringen, aber in der Praxis lasse ich die Textur ja über einen FrameBuffer erzeugen: damit sind ja nicht Daten im Objekt vorhanden und ich bin genauso nass wie vorher. Ich muss also wissen, wie ich die Daten der Textur wieder lesbar aus der Graphikkarte raushole?

Edit3: GetDataFromTexture - war ja auch zu einfach.
Code:
  1.   ms := TMemoryStream.Create;
  2.   ms.Position := 0;
  3.  
  4.   ConvertTo(ifBGRA8);
  5.   Self.SavePNG(ms);
  6.   ms.Position := 0;
  7.  
  8.   png := TPngImage.Create;
  9.   png.LoadFromStream(ms);
  10.  
  11.   FreeAndNil(ms);
  12.  
  13.   png.SaveToFile('c:\temp\musterpng.png');
  14.  

Das hier funktioniert schon mal. Zur Not kann ich mir das PNG-Objekt an TBitmap32 zuweisen.

Edit4:
Code:
  1.    GetDataFromTexture;
  2.     _Bitmap := TBitmap32.Create;
  3.  
  4.  
  5.     TempWidth  := TexturWidthPowerOf2;
  6.     TempHeight := TexturHeightPowerOf2;
  7.     _Bitmap.SetSize(TexturWidthPowerOf2, TexturHeightPowerOf2);
  8.  
  9.     IntFormat := ifBGRA8;
  10.     RowSize := trunc(FormatGetSize(IntFormat) * TempWidth);
  11.     for Row := 0 to TempHeight -1 do begin
  12.       pSource := Self.Scanline[Row];
  13.       pTarget := _Bitmap.ScanLine[Row];
  14.       if Assigned(pSource) then begin
  15.         Move(pSource^, pTarget^, RowSize);
  16.       end;
  17.     end;
  18.  
  19.     FreeData;
  20.     _Bitmap.SaveToFile('c:\temp\pngtest.png');
  21.  


Edit5: Problem wieder offen.

Die folgende Prozedur verwende ich nun zum Speichern der Textur (direkt abgeleitet von TglBitmap2D):
Code:
  1. procedure TglBitmap2dNachfahre.Save;
  2. var
  3.   bmp32: TBitmap32;
  4.   pSource, pTarget: PColor32Array;
  5.   Row, RowSize, TempWidth, TempHeight: Integer;
  6.   IntFormat: TglBitmapInternalFormat;
  7.   ms: TMemoryStream;
  8.   png: TPngImage;
  9. begin
  10.   TempWidth  := 512;
  11.   TempHeight := 512;
  12.  
  13.   // Verfahren 1
  14.   GetDataFromTexture;
  15.   bmp32 := TBitmap32.Create;
  16.  
  17.   bmp32.SetSize(TempWidth, TempHeight);
  18.   bmp32.ResetAlpha(255);
  19.  
  20.   IntFormat := ifBGRA8;
  21.   RowSize := trunc(FormatGetSize(IntFormat) * TempWidth);
  22.   for Row := 0 to TempHeight -1 do begin
  23.     pSource := Self.Scanline[Row];
  24.     pTarget := bmp32.ScanLine[Row];
  25.     if Assigned(pSource) then begin
  26.       Move(pSource^, pTarget^, RowSize);
  27.     end;
  28.   end;
  29.  
  30.   FreeData;
  31.   bmp32.SaveToFile('c:\temp\bmp32.png');
  32.  
  33.  
  34.   // Verfahren 2
  35.   GetDataFromTexture;
  36.   ms := TMemoryStream.Create;
  37.   ms.Position := 0;
  38.  
  39.   ConvertTo(ifBGRA8);
  40.   SavePNG(ms);
  41.   ms.Position := 0;
  42.  
  43.   png := TPngImage.Create;
  44.   png.LoadFromStream(ms);
  45.   png.SaveToFile('c:\temp\SavePNG.png');
  46.  
  47.   FreeAndNil(png);
  48.   FreeAndNil(ms);
  49.   FreeData;
  50. end;
  51.  


Mit einer Textur, in die ich vorher ein Bild geladen habe, funktioniert das auch einwandfrei. Nur wenn ich vom FrameBuffer kopiere kann ich zwar die (kopierte) Textur einwandfrei rendern, aber die abgespeicherte Datei besteht zu 100% aus transparenten Pixeln. Was mache ich falsch?

Code:
  1.   procedure CheckFBO;
  2.   var
  3.     error: GlEnum;
  4.   begin
  5.     error := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  6.     case error of
  7.       GL_FRAMEBUFFER_COMPLETE_EXT:
  8.         Exit;
  9.       GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
  10.         raise Exception.Create('Incomplete attachment');
  11.       GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
  12.         raise Exception.Create('Missing attachment');
  13.       GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
  14.         raise Exception.Create('Incomplete dimensions');
  15.       GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
  16.         raise Exception.Create('Incomplete formats');
  17.       GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
  18.         raise Exception.Create('Incomplete draw buffer');
  19.       GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
  20.         raise Exception.Create('Incomplete read buffer');
  21.       GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  22.         raise Exception.Create('Framebufferobjects unsupported');
  23.     end;
  24.   end;
  25.  
  26. procedure Bla.Render;
  27. var
  28.   tmpTextur: TglBitmap2dNachfahre;
  29. begin
  30.   glGenFramebuffersEXT(1, @fbo);
  31.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
  32.   glGenRenderbuffersEXT(1, @depthbuffer);
  33.   glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
  34.   glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 512, 512);
  35.   glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer);
  36.  
  37.   tmpTextur := TglBitmap2dNachfahre.Create(glBitmapPosition(512, 512), ifRGBA8);
  38.   tmpTextur.GenTexture;
  39.   tmpTextur.Bind;
  40.  
  41.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  42.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  43.   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
  44.   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tmpTextur.ID, 0);
  45.  
  46.   CheckFBO;
  47.  
  48.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
  49.   glPushAttrib(GL_VIEWPORT_BIT);
  50.  
  51.   // Meine tatsächlichen Rendervorgänge
  52.   Background.Render;
  53.   // ...
  54.  
  55.   glPopAttrib;
  56.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  57.  
  58.   glMatrixMode(GL_TEXTURE);
  59.   glEnable(GL_TEXTURE_2D);
  60.   tmpTextur.Bind;
  61.   glColor4f(1, 1, 1, 1);
  62.  
  63.   glBegin(GL_QUADS);
  64.     glTexCoord2f(0, 0);
  65.     glVertex3f(0, 0, 0);
  66.  
  67.     glTexCoord2f(0, 1);
  68.     glVertex3f(0, 512, 0);
  69.  
  70.     glTexCoord2f(1, 1);
  71.     glVertex3f(512, 512, 0);
  72.  
  73.     glTexCoord2f(1, 0);
  74.     glVertex3f(512, 0, 0);
  75.   glEnd;
  76.  
  77. //  if blsave then begin
  78.     tmpTextur.Save;
  79. //    blsave := False;
  80. //  end;
  81.  
  82.   glBindTexture(GL_TEXTURE_2D, 0);
  83.  
  84.   FreeAndNil(tmpTextur);
  85.   glDeleteFramebuffersEXT(1, @fbo);
  86.   glDeleteRenderbuffersEXT(1, @depthbuffer);
  87. end;
  88.  


Zuletzt geändert von berens am Do Jun 21, 2018 20:13, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Jun 20, 2018 16:15 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Da du schon einen Framepuffer auf deine Textur hast, sollte es mit folgendem Code aus meinem Tutorial klappen.
Getestet mit Lazarus und Linux.
Code:
  1. procedure TForm1.ButtonTexturSaveClick(Sender: TObject);
  2. var
  3.   Picture: TPicture;
  4. begin
  5.   Picture := TPicture.Create;
  6.   with Picture.Bitmap do begin
  7.     PixelFormat := pf32bit;  // 32-Bit erzwingen
  8.     Width := TexturSize;
  9.     Height := TexturSize;
  10.     glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
  11.     glReadPixels(0, 0, TexturSize, TexturSize, GL_RGBA, GL_UNSIGNED_BYTE, RawImage.Data);
  12.   end;
  13.   Picture.SaveToFile('textur.png');
  14.   Picture.Free;
  15. end;

Die kompletten Sourcen sind hier erhätlich: https://wiki.delphigl.com/index.php/Laz ... ramepuffer

Das ganze EXT-Zeugs kannst du dir sparen, ausser du hast einen Uralt-PC.

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 10:58 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

du hast noch ein sehr alte Version der glBitmap. Die neue von der Community überarbeitet Variante hat eine DownloadData Methode, mit der du die Daten aus einer Textur wieder in den RAM laden und dann in einem beliebigen Format speichern kannst.

Informationen gibts hier oder hier.

Gruß Bergmann89.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 11:06 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Hallo Mathias, danke für die Antwort und den verweis auf das andere Tutorial, ich hatte meine Beispiele von https://wiki.delphigl.com/index.php/Tutorial_Framebufferobject.

Ich habe leider den Spezialfall, dass Hintergrundbereiche im Framebuffer transparent bleiben müssen (also auch später in der gespeicherten PNG-Datei), und mit Deiner Methode gehen leider die "Partielle-Transparenz"-Informationen (Alpha-Scanline) verloren - soweit ich das sehen konnte(?). Auch mit rumbastelei habe ich es damit nicht hinbekommen.

Bei meinem Problem konnte ich feststellen, dass ich wohl nochmal (durch die Zeile aus dem Tutorial) "prozedural" eine andere Textur gebunden habe, als die, die ich vorher mit tmpTextur.Bind gebunden hatte: Deshalb lief der Renderdurchlauf ins Leere -oder zumindest nicht auf die Textur, die ich später tatsächlich rendere. Soweit ich mich erinnere muss man aus dem o.g. Beispiel nur die Zeile
Code:
  1. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);

auskommentieren, dann ist gut.

Nach sehr vielen Hin- und Her habe ich jetzt auch das Ergebnis so wie ich es haben will, aber der Aufwand ist aktuell noch viel zu groß, vielleicht kann mir nochmal kurz jemand einen Tip geben:

1) Ich render Zweidimensional im glOrtho-Modus. Diesen muss ich für den Framebuffer ändern (auf die Größe des FBO). Kann man die Abmessungen von glOrtho auch irgendwie mit glPushAttrib or so zwischenspeichern, oder zumindest über einen Befehl die Größe des aktuellen glOrtho-Bereichs auslesen?

2) Im Framebuffer wird -trotz imo korrekten ViewPorts/glOrtho- "auf dem Kopf" gerendert, so dass ich nun meine "normalen" Texturen habe, und die zur Laufzeit erstellten, die nun leider auf dem Kopf stehen. Was muss ich wie ändern, dass im FBO richtig herum gerendert wird, oder wie kann ich die Textur einfach und schnell auf den Kopf stellen/spiegeln (nicht erst beim Rendern!)

FrameBuffer für meine 2d-Ansprüche, Objektorientiert:
Code:
  1. type
  2.   TglFrameBuffer = class(TComponent)
  3.   private
  4.     FFBO: GluInt;
  5.     FTextur: TglBitmap2dNachfahre;
  6.     FWidth, FHeight: Integer;
  7.     FTexturWidth, FTexturHeight: Integer;
  8.     procedure CheckFBO;
  9.   public
  10.     property FBO: GLuint read FFBO;
  11.     property Width: integer read FWidth;
  12.     property Height: integer read FHeight;
  13.     property TexturWidth: integer read FTexturWidth;
  14.     property TexturHeight: integer read FTexturHeight;
  15.     property Textur: TglBitmap2dNachfahre read FTextur;
  16.  
  17.     procedure Bind;
  18.     procedure UnBind;
  19.  
  20.     constructor Create(_Owner: TComponent; _Width, _Height: integer); reintroduce;
  21.     destructor Destroy; override;
  22.   end;
  23.  
  24.  
  25. implementation
  26.  
  27. uses
  28. ...
  29. , glBitmap
  30. ;
  31.  
  32. { TglFrameBuffer }
  33.  
  34. constructor TglFrameBuffer.Create(_Owner: TComponent; _Width, _Height: integer);
  35. begin
  36.   inherited Create(_Owner);
  37.  
  38.   if _Width  < 1 then _Width  := 1;
  39.   if _Height < 1 then _Height := 1;
  40.   FWidth  := _Width;
  41.   FHeight := _Height;
  42.   FTexturWidth  := HAL1_PowerOf2(_Width);
  43.   FTexturHeight := HAL1_PowerOf2(_Height);
  44.  
  45.   glGenFramebuffersEXT(1, @FFBO);
  46.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FFBO);
  47.   glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, TexturWidth, TexturHeight);
  48.  
  49.   FTextur := TglBitmap2dNachfahre.Create(glBitmapPosition(TexturWidth, TexturHeight), ifBGRA8);
  50.   FTextur.GenTexture;
  51.   FTextur.Bind;
  52.  
  53.   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, FTextur.ID, 0);
  54.   CheckFBO;
  55. end;
  56.  
  57. destructor TglFrameBuffer.Destroy;
  58. begin
  59.   glDeleteFramebuffersEXT(1, @FFBO);
  60.   FreeAndNil(FTextur);
  61.  
  62.   inherited;
  63. end;
  64.  
  65. procedure TglFrameBuffer.Bind;
  66. begin
  67.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FFBO);
  68.  
  69.   glPushAttrib(GL_VIEWPORT_BIT);
  70.  
  71.   glViewPort(0, 0, TexturWidth, TexturHeight);
  72.   glMatrixMode(GL_PROJECTION);
  73.   glLoadIdentity();
  74.  
  75.   glOrtho(0, TexturWidth, TexturHeight, 0, 0, 1000);
  76.   glMatrixMode(GL_MODELVIEW);
  77.   glLoadIdentity;
  78.  
  79.   glClearColor(0,0,0,0);
  80.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  81. end;
  82.  
  83. procedure TglFrameBuffer.UnBind;
  84. begin
  85.   glPopAttrib;
  86.   glMatrixMode(GL_PROJECTION);
  87.   glLoadIdentity();
  88.  
  89.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  90. end;
  91.  
  92. procedure TglFrameBuffer.CheckFBO;
  93. var
  94.   error: GlEnum;
  95. begin
  96.   error := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  97.   case error of
  98.     GL_FRAMEBUFFER_COMPLETE_EXT:
  99.       Exit;
  100.     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
  101.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete attachment', ws_SEVERITY_EXCEPTION);
  102.     GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
  103.       Log('TglFrameBuffer.CheckFBO', M, 'Missing attachment', ws_SEVERITY_EXCEPTION);
  104.     GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
  105.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete dimensions', ws_SEVERITY_EXCEPTION);
  106.     GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
  107.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete formats', ws_SEVERITY_EXCEPTION);
  108.     GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
  109.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete draw buffer', ws_SEVERITY_EXCEPTION);
  110.     GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
  111.       Log('TglFrameBuffer.CheckFBO', M, 'Incomplete read buffer', ws_SEVERITY_EXCEPTION);
  112.     GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  113.       Log('TglFrameBuffer.CheckFBO', M, 'Framebufferobjects unsupported', ws_SEVERITY_EXCEPTION);
  114.   end;
  115. end;
  116.  


Ablauf im Programm:
Code:
  1.  
  2. var
  3.   fb: TglFrameBuffer;
  4.  
  5.   fb := TglFrameBuffer.Create(Self, PositionUserDesigned.Width, PositionUserDesigned.Height);
  6.   fb.Bind;
  7.   // Meine regulären Zeichenvorgänge
  8.   Background.Render;
  9.   ...
  10.   if blSave then begin
  11.     fb.Textur.Save;
  12.     blSave := False;
  13.   end;
  14.  
  15.   fb.UnBind;
  16.  
  17.   // Bäh: Hier muss ich aktuell noch manuell glOrtho wieder zurücksetzen. Statische Werte für die Demo:
  18.   glOrtho(0, 660, 500, 0, 0, 1000);
  19.   glMatrixMode(GL_MODELVIEW);
  20.   glLoadIdentity;
  21.  
  22.   glMatrixMode(GL_TEXTURE);
  23.   glEnable(GL_TEXTURE_2D);
  24.   FB.Textur.Bind;
  25.   glColor4f(1, 1, 1, 1);
  26.  
  27.   // Textur auf dem Kopf darstellen, wobei TexturGröße (PowerOf2)> Objektgröße
  28.    glBegin(GL_QUADS);
  29.     glTexCoord2f(0, 1-(fb.Height/fb.TexturHeight));
  30.     glVertex3f(0, fb.Height, 0);
  31.  
  32.     glTexCoord2f((fb.Width/fb.TexturWidth), 1-(fb.Height/fb.TexturHeight));
  33.     glVertex3f(fb.Width, fb.Height, 0);
  34.  
  35.     glTexCoord2f((fb.Width/fb.TexturWidth), 1);
  36.     glVertex3f(fb.Width, 0, 0);
  37.  
  38.     glTexCoord2f(0, 1);
  39.     glVertex3f(0, 0, 0);
  40.   glEnd;
  41.  


Zuletzt geändert von berens am Do Jun 21, 2018 17:16, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 17:09 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Ich habe leider den Spezialfall, dass Hintergrundbereiche im Framebuffer transparent bleiben müssen (also auch später in der gespeicherten PNG-Datei), und mit Deiner Methode gehen leider die "Partielle-Transparenz"-Informationen (Alpha-Scanline) verloren - soweit ich das sehen konnte(?). Auch mit rumbastelei habe ich es damit nicht hinbekommen.

Eine blöde Frage, hast du Alphablending aktiviert ?
Code:
  1.   glEnable(GL_BLEND);                                  // Alphablending an
  2.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);   // Sortierung der Primitiven von hinten nach vorne.


Zitat:
Im Framebuffer wird -trotz imo korrekten ViewPorts/glOrtho- "auf dem Kopf" gerendert, so dass ich nun meine "normalen" Texturen habe, und die zur Laufzeit erstellten, die nun leider auf dem Kopf stehen. Was muss ich wie ändern, dass im FBO richtig herum gerendert wird, oder wie kann ich die Textur einfach und schnell auf den Kopf stellen/spiegeln (nicht erst beim Rendern!)

Ich kenne das Problem, daher habe ich einfach Zeile für Zeile in die Bitmap kopiert.
Siehe hier: https://wiki.delphigl.com/index.php/Laz ... _speichern

Vielleicht hilft dir auch folgendes weiter.
Code:
  1. glMatrixMode(GL_TEXTURE);
  2. glScalef(1.0, -1.0, 1.0); 


Zitat:
Kann man die Abmessungen von glOrtho auch irgendwie mit glPushAttrib or so zwischenspeichern, oder zumindest über einen Befehl die Größe des aktuellen glOrtho-Bereichs auslesen?
Ja dies sollte gehen, ich weis nur nicht mehr wie der Befehl heisst, man kann die Matrix speichern und laden.

PS:Kannst du bitte die Code-Tags für Pascal verwenden.
Code:
  1. (code=pascal)Writeln('Hello World');(/code)

Die () einfch durch [] ersetzen.

_________________
OpenGL


Zuletzt geändert von mathias am Do Jun 21, 2018 21:16, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 17:19 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Ja dies sollte gehen, ich weis nur nicht mehr wie der Befehl heisst, man kann die Matrix speichern und laden.

Ich habe mich wohl geirrt, es gibt nur einen Befehl um eine Matrix zu laden.
Code:
  1. var
  2.   MyMatrix:array[0..15]of GLfloat;
  3. begin
  4.   glLoadMatrixf(@MyMatrix); // Matrix laden
  5.   glSaveMatrixf(@MyMatrix); // Gibt es leider nicht

Ausser mein Google ist kaputt. :mrgreen:
Dies ist ein Vorteil von OpenGL 3.3, da hat man vollen Zugriff auf die Matrix, da man alle selbst macht.

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 20:12 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Zunächst mal: Vielen Dank für die Rückmeldungen und Ideen!

@Bergmann89: Update werde ich zeitnah in einer ruhigen Minuten testen und installieren.

@mathias:
Zitat:
Eine blöde Frage, hast du Alphablending aktiviert ?

Die Frage ist zwar generell berechtigt, aber hier glaube ich nicht zutreffend. Zu Erinnerung: Nehmen wir an, ich will eine farbige Kreisfläche auf eine quadratische Textur zeichnen, will ich ja nur den Kreishaben, nicht den freien Bereich bis in die Ecken des Quadrads. Soweit klar. Wenn ich die Textur als PNG auf Festplatte speichere (PNG unterstützt ja partielle Transparenz) und in einem Graphikprogramm lade, werden die freien Flächen (also die Ecken, "das, was nicht Kreis ist") je nach Graphikprogramm z.B. mit einem dezenten Schachbrettmuster hinterlegt um zu zeigen: Dieser Bereich ist durchsichtig.

Das von dir beschriebene Verfahren lässt sich mit Delphi 2010 leider nicht verwenden, da ich hier auf "RawImage" bzw. "RawImage.Data" nicht zugreifen kann; das gibt es hier nicht.

Bei dem im Tutorial verlinkten zweiten Verfahren, glaube ich, werden wirklich 1:1 die Pixel "vom Bildschirm" gelesen, oder vom Framebuffer die Farbe, die für glClearColor verwendet wurde. Korrigiere mich, wenn ich falsch liege.

Das "auf den Kopf stellen" der Textur erledige ich nun bei FrameBuffer.Unbind automatisch durch die TglBitmap2d.FlipVertical. Tolle Sache, aber dran denken: Ohne Daten keine Texturbearbeitung! Also:

Code:
  1. procedure TglBitmap2dNachfahre.FlipV;
  2. begin
  3.   GetDataFromTexture; // Daten laden
  4.   FlipVert; // Vertikal spiegeln
  5.   GenTexture; // Daten "speichern"
  6.   FreeData; // Speicher freigeben, passiert mit GenTexture (je nach Einstellung) ggf. automatisch
  7. end;


Der Tip mit glScalef(1.0, -1.0, 0.0) war das, was ich ursprünglich die ganze Zeit im Hinterkopf hatte, aber nicht abrufen konnte. Ich meine, es war mal in irgend einem Einsteigertutorial genannt. Leider stellt es im laufenden Betrieb die komplette Scene auf den Kopf, so dass ich in jeden Renderdurchlauf das Bild rumgedreht bekomme. Ich meine zwar eigentlich, den Befehl nur innerhalb der Arbeiten mit dem Framebuffer verwendet zu haben, und danach -testweise mit dem selben Befehl, testweise mit glScalef(1.0, 1.0, 0.0)- wieder für Ordnung gesorgt zu haben, aber ich konnte kein Befriedigendes Ergebnis erziehlen. Wie gesagt, Textur spiegeln hat sich ja bereits erledigt, also da keine Energie mehr reinstecken.

Das mit glOrtho ist halt noch ein ziemlich krasser Knackpunkt für mich. Entweder muss ich allen meinen glObjekten eine Callback-Möglichkeit geben, um den Orthomodus wieder korrekt setzen zu lassen, oder jemand hat noch einen umwerfenden Tip. Mit Matrizen kenne ich mich zu wenig aus, und ich weiß auch nicht, ob alle PCs, die jünger als 5 Jahre sind wirklich OpenGL 3.3 können. Deshalb mache ich es lieber umständlicher, aber dafür kompatibel.

Nochmals vielen Dank an alle Antworter!


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 21, 2018 21:20 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Mit Matrizen kenne ich mich zu wenig aus, und ich weiß auch nicht, ob alle PCs, die jünger als 5 Jahre sind wirklich OpenGL 3.3 können.

Es könnte auch OpenGL 2.0 reichen, die Manuelle Behandlung von Matrizen wird meistens verwendet, wen man auch mit Shader arbeitet.

Zitat:
Das von dir beschriebene Verfahren lässt sich mit Delphi 2010 leider nicht verwenden, da ich hier auf "RawImage" bzw. "RawImage.Data" nicht zugreifen kann; das gibt es hier nicht.
Gibt es bei Delphi keine Möglichkeit direkt auf die Raw-Daten der Bitmap zu zugreifen ?

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 22, 2018 01:41 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 03, 2002 22:12
Beiträge: 2105
Wohnort: Vancouver, Canada
Programmiersprache: C++, Python
glOrtho erzeugt eine parallele projektionsmatrix und multipliziert diese mit der aktuellen matrix. Wenn du die aktuelle matrix speichern moechtest kannst du das mit glGet machen:

Code:
  1. float matrix[16];
  2. glGetFloatv(GL_PROJECTION_MATRIX, matrix);
  3. glOrtho(....);
  4. [...]
  5. glLoadMatrix(matrix);

Ist C++, aber denke das prinzip wird verstaendlich. Habe leider Delphi seit ewigkeiten nichtmehr genutzt und erinnere mich kaum daran wie die syntax ist.

Siehe: https://www.khronos.org/registry/OpenGL ... /glGet.xml

Zu deinem problem der auf dem kopf stehenden Bilder: Natuerlich funktioniert die flipVertical() funktion, allerdings vermute ich (ich hab sie nicht angeschaut) das diese das Bild im RAM flipt. Funktioniert, ist aber langsam und prinzipiell ueberfluessig. Du kannst einfach den top und bottom parameter in der glOrtho funktion austauschen - damit drehst du sozusagen deinen Viewport auf den kopf und damit die Textur.

Siehe: https://www.khronos.org/registry/OpenGL ... lOrtho.xml


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 22, 2018 08:31 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 69
Danke, Aya.

Mit Matrizen habe ich bisher noch nicht unabhängig von Codebeispielen gearbeitet. Ich habe mit Hilfe von https://wiki.delphigl.com/index.php/glLoadMatrix das wie folgt umsetzen können:

Code:
  1.  
  2.   TVektor = record
  3.             X,Y,Z,W : glFloat
  4.   end;
  5.   TMatrix = array[(mat_XAchse,mat_YAchse,mat_ZAchse,mat_Position)] of TVektor;
  6.  
  7. type
  8.   TglFrameBuffer = class(TComponent)
  9.   private
  10.     FOriginalMatrix: TMatrix;
  11.    ...
  12.  
  13. procedure TglFrameBuffer.Bind;
  14. begin
  15.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FFBO);
  16.  
  17.   glGetFloatv(GL_PROJECTION_MATRIX, @FOriginalMatrix);
  18.  
  19.   glPushAttrib(GL_VIEWPORT_BIT);
  20.  
  21.   glViewPort(0, 0, TexturWidth, TexturHeight);
  22.   glMatrixMode(GL_PROJECTION);
  23.   glLoadIdentity();
  24.  
  25.   glOrtho(0, TexturWidth, TexturHeight, 0, 0, 1000);
  26.   glMatrixMode(GL_MODELVIEW);
  27.   glLoadIdentity;
  28.  
  29.   glClearColor(0,0,0,0);
  30.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  31. end;
  32.  
  33. procedure TglFrameBuffer.UnBind;
  34. begin
  35.   Textur.FlipV;
  36.  
  37.   glPopAttrib;
  38.  
  39.   glLoadMatrixf(@FOriginalMatrix);
  40.  
  41.   glMatrixMode(GL_PROJECTION);
  42.   glLoadIdentity();
  43.  
  44.   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  45. end;
  46.  


Wie ist denn der korrekte Datentyp aus der dglOpenGL, so dass ich den TMatrix-Typ jetzt nicht nochmal neu deklarieren muss?

Ich hatte FOriginalMatrix mal mit dem Typ TVector4f und TMatrix4f aus der dglOpenGL.pas versucht, da diese zumindest dem Namen nach (TMatrix4f) und vom Datentyp her (TGLVectorf4 = array[0..3] of GLfloat) für diesen Zweck vorgesehen sein sollten. Dies hat auch generell funktioniert, aber das Programm ist nach einigen Sekunden mit Speicherverletzung abgestürzt, also hat er wohl beim Speichern der Matrix wohingeschrieben, wo es eigentlich nicht vorgesehen war(?).

Ist der Code nun soweit richtig? Mit puren Pointern kenne ich mich nicht so aus, wann nun das @ davor soll, und wann nicht etc. Muss FOriginalMatrix irgendwie initialisiert oder freigegeben werden?

---

Der Tip mit glOrtho auf den Kopf stellen ist gut, aber irgendwie ist dann nichts mehr zu sehen. Ich gehe davon aus, dass meine anderen Komponenten die ich rendern lasse dann irgendwo "OffScreen" landen, weil nun doch der Ursprung anders ist, bzw. nun das Render im Uhrzeigersinn oder so erfolgen müsste, oder ich Culling an/aus machen müsste? Da meine mit dem Framebuffer erzeugte Textur nur ca. 1x / Stunde aktualisiert wird, nehme ich den Mehraufwand durch das spiegeln im RAM erst Mal hin. :)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Jun 22, 2018 17:11 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Gibt es sogar in deutsch.

https://wiki.delphigl.com/index.php/glG ... IEW_MATRIX

Ich habe dies gerade probiert, somit kann man Matrizen laden und speichern.
Dies ist aber recht verwirrend, glLoadFloatf und glLoadMatrix.
Code:
  1.   glMatrixMode(GL_MODELVIEW);
  2.   glLoadIdentity();
  3.   glGetFloatv(GL_MODELVIEW_MATRIX, @m);
  4.   glRotatef(5.0, 0.0, 0.0, 1.0); // Wird ingnoriert
  5.   m.Scale(0.2); // Wird ausgeführt.
  6.   glLoadMatrixf(@m);
  7.  

TMatrix ist hier deklariert: https://github.com/sechshelme/Lazarus-O ... matrix.pas und https://github.com/sechshelme/Lazarus-O ... vector.pas

Etwas merkwürdige Deklaration, vor allem das mit der Array, aber es wird kompiliert.
Code:
  1.   TVektor = record
  2.             X,Y,Z,W : glFloat
  3.   end;
  4.   TMatrix = array[(mat_XAchse,mat_YAchse,mat_ZAchse,mat_Position)] of TVektor;

Für deinen Fall, da du keine Manipulationen machst, würde ich es einfach so deklarieren.
Code:
  1.  
  2. type
  3.   TMatrix = Array[0..15] of glFloat;
  4. // oder
  5.   TMatrix = Array[0..3, 0..3] of glFloat;
  6. // oder
  7.   TMatrix = Array[0..3] of TVector4f;

TVector3f ist bei dglOpenGL.pas dabei.

_________________
OpenGL


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 25 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.102s | 17 Queries | GZIP : On ]