Autor |
Beitrag |
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Sa 06.09.08 11:31
Hi,
ich möchte eine Szene in OpenGL als Bild speichern. Indem ich hier etwas rumgespielt habe (4x so große Fläche, nur ein Viertel aufm Bildschirm rendern), konnte ich ber "Druck"-Taste 4 Screenshots erstellen und diese zusammenfügen.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| glViewport(0, 0, VPanel.ClientWidth, VPanel.ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluPerspective(45.0, VPanel.ClientWidth/VPanel.ClientHeight, NearClipping, FarClipping);
glMatrixMode(GL_MODELVIEW); glLoadIdentity; |
Ja, das ist Mist, ich weiß  Vor allem weil es nicht mit mehr als doeppelte Auflösung geht. Gibt es da nicht eine vernünftige Art, sowas zu machen?
Danke, Xion
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Sa 06.09.08 17:39
Ja, indem man sich einen Textur-Puffer anlegt und in diesen Rendert und dann diesen in ein Bitmap. Beispiele gibt's bei DelphiGL ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
toenne
      
Beiträge: 51
|
Verfasst: So 07.09.08 01:53
Vielleicht hilfts: www.delphigl.com/for...viewtopic.php?t=7772
Das überflüssige Zeugs mit dem leeren Bitmap in das dann der Snapshot kopiert wird kannst du ja weglassen  .
Gruss
Toenne
|
|
Xion 
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: So 07.09.08 10:44
@toenne: bei deinem Code raucht bei mir irgendwie die Grafikkarte ab oO
@BenBE: irgendwie find ich nix. ich find nie was bei DelhpiGL, kA, ich glaube ich bediene die Suche falsch
ich habs mal so gemacht ( von hier )
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure SnapShot; var ATarget: TBitmap; begin ATarget:=TBitmap.Create; ATarget.PixelFormat := pfDevice; ATarget.Width := Screen.Width; ATarget.Height := Screen.Height; BitBlt(ATarget.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY); ATarget.SaveToFile('test.bmp'); end; |
Das Problem ist aber, dass ich damit ja nicht über die Bildschirmgröße rauskomme. Ich hätte es eigentlich gerne so groß, dass man es drucken kann (also ca. 3*3-fache Bildschirmgröße)
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: So 07.09.08 12:45
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
toenne
      
Beiträge: 51
|
Verfasst: So 07.09.08 15:35
Zitat: | @toenne: bei deinem Code raucht bei mir irgendwie die Grafikkarte ab oO |
Hast du ihn doch komplett kopiert oder wie?
Du brauchst doch nur...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| glGetIntegerv(GL_VIEWPORT, @Viewport); Rohbild := TBitmap.Create; try Rohbild.Width := Viewport[2]; Rohbild.Height := Viewport[3]; Rohbild.PixelFormat := pf24bit; for i := 0 to Viewport[3] - 1 do glReadPixels(0, Viewport[3] - i, Viewport[2], 1, GL_BGR, GL_UNSIGNED_BYTE, Rohbild.ScanLine[i]); |
...und schon hast du eine Kopie in 'Rohbild'. Der ganze andere Krempel ist für dich irrelevant.
Aber wie ich dich jetzt verstehe willst du gar nicht den Bildschirminhalt kopieren sondern die ganze Szene? Hmm, was über die Bildschirmgrenzen hinausgeht wird doch gar nicht gerendert denke ich?
Gruss
Toenne
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: So 07.09.08 16:18
Ich denke, er will eine Kopie eines Viewports haben, der größer als der Bildschirm ist ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Mo 08.09.08 11:18
Xion: Ich denke du hast 2 Möglichkeiten.
1) Wie es BenBE schon so vorgeschlagen hatte. Du erzeugst einen offscreen buffer und renderst dort dein Bild hinein. Das Problem ist aber Aufgrund des Formates den ein OffScreen Buffer (32Bit RGBA + Tiefenbuffer etc) hat steigt der Speicherverbrauch um ein vielfaches an. Und dessen Größe ist irgendwoe auch begrenzt. Oben drein kommt hinzu, dass du recht hohe Hardwareanforderungen hast. Aber mit einem FrameBuffer Object wäre es möglich einen solchen Buffer zu erstellen. Da der seine Daten in einer Textur ablegt wäre es ziemlich einfach die Daten abzufragen.
2) Du musst deine Szene X mal Rendern und immer die passenden Teile des Bildes kopieren und dir daraus ein großes Bild zusammen basteln. Es gab vor ewigen Zeiten auf delphi3d.net mal ein Demo dazu aber leider ist die Seite seit geraumer Zeit offline. Ich weiß es mittlerweile nicht mehr genau was der dort gemacht hatte deswegen kann ich nur einen eigenen Vorschlag machen. Allerdings habe ich keine Ahnung ob das immer so funktioniert.
Du kannst einen Viewport setzen der entsprechend groß ist. Allerdings der Framebuffer bekommt die maximal Größe des Fensters. Bei glViewport setzt du normal ClientHeight/ClientWidth. Wenn du aber deine gewünschte Größe einsetzt, dann wird das Bild entsprechend Groß gezeichnet. Du kannst bei X und Y dann aber entsprechende Werte setzen um den Viewport zu verschieben und einen anderen Teil in den Framebuffer zu verschieben. Der Einfachheit halber solltet du zu Begin erst mal mit einer Größe von 512x512 arbeiten. Beispiel:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| glViewport(0, 0, 8192, 8192);
glViewport(512, 0, 8192, 8192);
glViewport(1024, 0, 8192, 8192);
usw. |
Das müsstest du so häufig machen bist du alle Teile kopiert hast. Kopieren musst du dann Zeilenweise. Dazu solltest du dich mal in dem Screenshot Artikel im Wiki von DGL umschauen. Also prinzipiel mit glReadPixel. Du solltest glReadBuffer auf GL_BACK stellen und SwapBuffers nicht ausführen wärend du die Teile generierst. Dann wird aus dem nicht sichtbaren Backbuffer gelesen und niemand bekommt diese temporären Bilder zu sehen. Aber je nach Größe der Szene kann es dauern, da du im Falle von 8192x8192 die gesammte Szene 256 Mal zeichnen musst. Du kannst aber auch größere Stücke als 512x512 nehmen. Könnte nur beim Zusammenbauen etwas komplizierter/verwirrender werden.
Ich weiß allerdings nicht ob es zu einem Problem führen kann, wenn der Viewport zu groß wird. Mitunter können einige Karten nur einen Viewport von 4096x4096 Pixel. Ich weiß nicht ob sich das auf die maximale Anzeigegröße bezieht oder wirklich auf Width und Height bei glViewport. Die größe kannst du wie folgt abfragen.
Delphi-Quelltext 1: 2: 3: 4:
| var VP: array[0..1] of Integer; begin glGetIntegerv(GL_MAX_VIEWPORT_DIMS, @VP); |
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Xion 
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Fr 12.09.08 14:53
wow, danke, ich hab momentan nicht so viel Zeit.
Also ich habs nach methode 2 schonmal probiert, hab sie jetzt auch einigermaßen zum laufen bekommen (bin am notebook fast verzweifelt, scheinbar kann es nicht mehr als 2x2 Bildschirme berechnen). Leider ist es nicht ganz einwandfrei, Size=2 funktioniert prima, Size=3 ist unten etwas abgeschnitten und Size=4 ist verzerrt oO
Hier mal der Code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| procedure TOpenGLWorks.SnapShot(Redraw: TTickProc; GameTimer: TGameTimer); var ATarget: Graphics.TBitmap; X,Y,W,H: integer; Size: integer; begin Size:=3; W:=VPanel.ClientWidth; H:=VPanel.ClientHeight;
glViewport( 0, 0, W*Size, H*Size ); Redraw(0);
ATarget:=Graphics.TBitmap.Create; ATarget.PixelFormat := pfDevice; ATarget.Width := W*Size; ATarget.Height := H*Size; GameTimer.Enabled:=False; for X:= 0 to (Size-1) do for Y:= 0 to (Size-1) do begin glViewport( -X*W, -Y*H, W*Size, H*Size ); Redraw(0); glViewport( -X*W, -Y*H, W*Size, H*Size ); Redraw(0); BitBlt(ATarget.Canvas.Handle, X*W, ( (Size-1)-Y)*H, W,H, DC, 0, 0, SRCCOPY); end; ATarget.SaveToFile('test.bmp');
glViewport( 0, 0, W, H ); Redraw(0); GameTimer.Enabled:=True; end; |
Zudem verstehe ich nicht, warum ich 2x die Szene rendern muss, um ein anständiges Bild zu bekommen (sonst kommt jeder Block doppelt)
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
Xion 
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Sa 13.09.08 12:54
das hier ist durch den obigen Code entstanden...das Ergebnis ist mir unerklärlich (das rausgeschnittene Eck).
Originalgröße: 4428x3328
Anmerkung: er scheint irgendwo nicht lange genug zu warten, bis er es als Screenshot ausliest. Ich denke mal das ist die differenz zwischen dem fertigen rendern und dem tatsächlichen anzeigen auf dem Bildschirm. Ich habs mal mit glReadPixels versucht, funktioniert aber leider so nicht:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| procedure TOpenGLWorks.SnapShot(Redraw: TTickProc; GameTimer: TGameTimer; Size: integer); var ATarget, SubTarget: Graphics.TBitmap; X,Y,W,H: integer; DestRect,TargetRect: TRect; begin
W:=VPanel.ClientWidth; H:=VPanel.ClientHeight;
glViewport( 0, 0, W*Size, H*Size ); Redraw(0);
DestRect.Left:=0; DestRect.Top:=0; DestRect.Right:=W; DestRect.Bottom:=H;
ATarget:=Graphics.TBitmap.Create; ATarget.PixelFormat := pfDevice; ATarget.Width := W*Size; ATarget.Height := H*Size;
SubTarget:=Graphics.TBitmap.Create; SubTarget.PixelFormat := pfDevice; SubTarget.Width := W; SubTarget.Height := H;
GameTimer.Enabled:=False; for X:= 0 to (Size-1) do for Y:= 0 to (Size-1) do begin glViewport( -X*W, -Y*H, W*Size, H*Size ); Redraw(0); glReadPixels( X*W, Y*H, W, H, GL_RGB, GL_BITMAP, @SubTarget );
TargetRect.Left:=X*W; TargetRect.Top:=Y*H; TargetRect.Right:=W+X*W; TargetRect.Bottom:=H+Y*H;
ATarget.Canvas.CopyRect(TargetRect,SubTarget.Canvas,DestRect); end; ATarget.SaveToFile('test.bmp');
glViewport( 0, 0, W, H ); Redraw(0); GameTimer.Enabled:=True; end; |
Einloggen, um Attachments anzusehen!
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
toenne
      
Beiträge: 51
|
Verfasst: Mo 15.09.08 20:53
Willkommen im Club: www.delphigl.com/for...ic.php?p=65288#65288
Ich habs mittlerweile aufgegeben mir über das zweifache Rendern den Kopf zu zerbrechen...ist halt so, Hauptsache es funktioniert...
Gruss
Toenne
|
|
|